mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-06 08:35:21 +08:00
Completes the handoff task for the Windows harness: the native test job ran with the MSYS-shared /tmp and the runner's inherited LocalAppData\Temp ACLs, which the daemon's strict private-filesystem checks reject by design. The test-windows job now creates a per-user root under the profile with an owner-stamped, protected current-SID DACL and routes TEMP/TMP (native form) and TMPDIR (POSIX form) through it before scripts/test.sh runs. The guards script already hardened its root DACL but ownership is never inherited on Windows: bundle copies created by the admin-group runner token can come out Administrators-owned, and the launcher's exe policy requires the exact current user as owner. Stamp the current SID on the staged bundle dir and both executables explicitly. Job topology, gates, and triggers are unchanged; the new step is a sub-second pwsh block in the existing test-windows job. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
213 lines
9.4 KiB
YAML
213 lines
9.4 KiB
YAML
# Reusable: unit + integration tests on all platforms
|
|
name: Test
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
skip_perf:
|
|
description: 'Skip incremental perf tests (phases 2-7)'
|
|
type: boolean
|
|
default: true
|
|
broad_platforms:
|
|
description: 'Test the broad platform matrix (older glibc + extra OS versions) instead of the core set'
|
|
type: boolean
|
|
default: false
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
# Emit the platform matrices as JSON. The CORE set is the default (fast,
|
|
# unchanged); the BROAD set adds extra free runners (older glibc /
|
|
# additional OS versions) for a wider "does it build everywhere" picture.
|
|
setup-matrix:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
outputs:
|
|
unix: ${{ steps.set.outputs.unix }}
|
|
windows: ${{ steps.set.outputs.windows }}
|
|
steps:
|
|
- name: Compute matrices
|
|
id: set
|
|
env:
|
|
BROAD: ${{ inputs.broad_platforms }}
|
|
run: |
|
|
CORE_UNIX='[
|
|
{"os":"ubuntu-latest","cc":"gcc","cxx":"g++"},
|
|
{"os":"ubuntu-24.04-arm","cc":"gcc","cxx":"g++"},
|
|
{"os":"macos-14","cc":"cc","cxx":"c++"},
|
|
{"os":"macos-15-intel","cc":"cc","cxx":"c++"}
|
|
]'
|
|
# Broad matrix legs are REQUIRED gates (no optional/continue-on-error
|
|
# escape hatches): the release dry run must be all-green, every platform.
|
|
BROAD_UNIX='[
|
|
{"os":"ubuntu-22.04","cc":"gcc","cxx":"g++"},
|
|
{"os":"ubuntu-22.04-arm","cc":"gcc","cxx":"g++"},
|
|
{"os":"macos-15","cc":"cc","cxx":"c++"}
|
|
]'
|
|
# Each Windows leg pins the msys2 environment + package arch to the
|
|
# RUNNER architecture so the build is native, never emulated:
|
|
# x86-64 runners -> CLANG64 (mingw-w64-clang-x86_64-*)
|
|
# ARM64 runner -> CLANGARM64 (mingw-w64-clang-aarch64-*)
|
|
# windows-11-arm previously used the x86-64 CLANG64 toolchain, so its
|
|
# binary ran under Windows-on-ARM x86-64 emulation and ASan's function
|
|
# interception crashed (interception_win: unhandled instruction). With
|
|
# the native ARM64 toolchain ASan instruments native ARM64 code, so it
|
|
# is a real (non-optional) gate, not a tolerated emulated-flake.
|
|
CORE_WIN='[{"os":"windows-latest","msystem":"CLANG64","pkg":"x86_64"}]'
|
|
BROAD_WIN='[{"os":"windows-2025","msystem":"CLANG64","pkg":"x86_64"},{"os":"windows-11-arm","msystem":"CLANGARM64","pkg":"aarch64"}]'
|
|
if [ "$BROAD" = "true" ]; then
|
|
UNIX=$(jq -cn --argjson a "$CORE_UNIX" --argjson b "$BROAD_UNIX" '$a + $b')
|
|
WIN=$(jq -cn --argjson a "$CORE_WIN" --argjson b "$BROAD_WIN" '$a + $b')
|
|
else
|
|
UNIX=$(jq -cn --argjson a "$CORE_UNIX" '$a')
|
|
WIN=$(jq -cn --argjson a "$CORE_WIN" '$a')
|
|
fi
|
|
echo "unix={\"include\":$UNIX}" >> "$GITHUB_OUTPUT"
|
|
echo "windows={\"include\":$WIN}" >> "$GITHUB_OUTPUT"
|
|
|
|
test-unix:
|
|
needs: setup-matrix
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJSON(needs.setup-matrix.outputs.unix) }}
|
|
runs-on: ${{ matrix.os }}
|
|
# Broad-only legs (extra OS versions) are informational: visible but
|
|
# non-blocking, so a flaky/less-common runner can't block a release.
|
|
continue-on-error: ${{ matrix.optional == true }}
|
|
timeout-minutes: 240
|
|
steps:
|
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
|
|
- name: Install deps (Ubuntu)
|
|
if: startsWith(matrix.os, 'ubuntu')
|
|
run: sudo apt-get update && sudo apt-get install -y zlib1g-dev
|
|
|
|
- name: Test
|
|
run: scripts/test.sh CC=${{ matrix.cc }} CXX=${{ matrix.cxx }}
|
|
env:
|
|
CBM_SKIP_PERF: ${{ inputs.skip_perf && '1' || '' }}
|
|
|
|
test-tsan:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 120
|
|
steps:
|
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
|
|
- name: Install deps (Ubuntu)
|
|
run: sudo apt-get update && sudo apt-get install -y clang zlib1g-dev
|
|
|
|
- name: ThreadSanitizer tests
|
|
run: make -f Makefile.cbm test-tsan CC=clang CXX=clang++
|
|
|
|
test-windows:
|
|
needs: setup-matrix
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJSON(needs.setup-matrix.outputs.windows) }}
|
|
runs-on: ${{ matrix.os }}
|
|
continue-on-error: ${{ matrix.optional == true }}
|
|
timeout-minutes: 240
|
|
steps:
|
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
|
|
- uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
|
|
with:
|
|
msystem: ${{ matrix.msystem }}
|
|
path-type: inherit
|
|
install: >-
|
|
mingw-w64-clang-${{ matrix.pkg }}-clang
|
|
mingw-w64-clang-${{ matrix.pkg }}-compiler-rt
|
|
mingw-w64-clang-${{ matrix.pkg }}-zlib
|
|
make
|
|
git
|
|
|
|
- name: Create protected per-user temp root
|
|
# The daemon suites fail closed on the MSYS-shared /tmp and on the
|
|
# runner's inherited LocalAppData\Temp ACLs. Give the whole harness a
|
|
# per-user root under the profile with an owner-stamped, protected
|
|
# current-SID DACL, matching the launcher/daemon trust policy.
|
|
shell: pwsh
|
|
run: |
|
|
$root = Join-Path $env:USERPROFILE ("cbm-ci-tmp-" + [guid]::NewGuid().ToString("N"))
|
|
New-Item -ItemType Directory -Path $root | Out-Null
|
|
$sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
$acl = [System.Security.AccessControl.DirectorySecurity]::new()
|
|
$acl.SetOwner($sid)
|
|
$acl.SetAccessRuleProtection($true, $false)
|
|
$rule = [System.Security.AccessControl.FileSystemAccessRule]::new(
|
|
$sid,
|
|
[System.Security.AccessControl.FileSystemRights]::FullControl,
|
|
([System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor
|
|
[System.Security.AccessControl.InheritanceFlags]::ObjectInherit),
|
|
[System.Security.AccessControl.PropagationFlags]::None,
|
|
[System.Security.AccessControl.AccessControlType]::Allow)
|
|
$acl.AddAccessRule($rule) | Out-Null
|
|
Set-Acl -LiteralPath $root -AclObject $acl
|
|
"CBM_CI_TEMP_ROOT=$root" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
|
|
- name: Test
|
|
shell: msys2 {0}
|
|
# AddressSanitizer is unavailable on native ARM64 Windows (LLVM ships no
|
|
# libclang_rt.asan for aarch64-w64-windows-gnu) and cannot intercept the
|
|
# system DLLs under x86-64 emulation either, so windows-11-arm runs the
|
|
# native ARM64 build with SANITIZE= (no sanitizer) — still a real
|
|
# functional gate. ASan/UBSan coverage comes from the other 9 legs,
|
|
# including native-ARM Linux/macOS. x86-64 Windows keeps full sanitizers.
|
|
run: |
|
|
# Native tests resolve temp via TEMP/TMP (cbm_tmpdir); shell tools use
|
|
# TMPDIR. Route both through the protected root created above so no
|
|
# fixture lands under a shared or ACL-inherited ancestry.
|
|
export TEMP="$(cygpath -m "$CBM_CI_TEMP_ROOT")"
|
|
export TMP="$TEMP"
|
|
export TMPDIR="$(cygpath -u "$CBM_CI_TEMP_ROOT")"
|
|
scripts/test.sh CC=clang CXX=clang++ ${{ matrix.os == 'windows-11-arm' && 'SANITIZE=' || '' }}
|
|
env:
|
|
CBM_SKIP_PERF: ${{ inputs.skip_perf && '1' || '' }}
|
|
|
|
# Windows product-surface regression guards. Distinct from test-windows above
|
|
# (the sanitizer C suite): these drive a real product binary + embedded HTTP UI
|
|
# over stdio / CLI / HTTP and fail if a Windows bug already fixed on main comes
|
|
# back -- non-ASCII repo paths dropping definitions (#636/#357, fixed by #700),
|
|
# the PreToolUse hook augmenter no-op on drive-letter cwd (#618, fixed by #619),
|
|
# the UI directory picker not enumerating drives (#548, roots field), and non-ASCII
|
|
# CLI arguments being mangled by the narrow-argv main() (#423/#20, fixed by the
|
|
# wide-argv entrypoint that reads GetCommandLineW).
|
|
test-windows-guards:
|
|
runs-on: windows-latest
|
|
timeout-minutes: 60
|
|
steps:
|
|
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
|
|
- uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
|
|
with:
|
|
msystem: CLANG64
|
|
path-type: inherit
|
|
install: >-
|
|
mingw-w64-clang-x86_64-clang
|
|
mingw-w64-clang-x86_64-zlib
|
|
make
|
|
git
|
|
|
|
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
with:
|
|
node-version: "22"
|
|
|
|
- name: Test npm wrapper failure handling
|
|
working-directory: pkg/npm
|
|
run: npm test
|
|
|
|
- name: Build product binary with embedded UI
|
|
shell: msys2 {0}
|
|
# --with-ui builds the frontend (npm) and embeds it, so the drive-picker
|
|
# guard's HTTP UI is available. Functional gate only (no sanitizers).
|
|
run: scripts/build.sh --with-ui CC=clang CXX=clang++
|
|
|
|
- name: Windows regression guards (#636/#357, #618, #548, #423/#20)
|
|
shell: pwsh
|
|
# -GuardsOnly runs the four green guards and gates on them. The runner sets
|
|
# CBM_INDEX_SUPERVISOR=0 for determinism, but the non-ASCII CLI guard drops that
|
|
# override so it exercises the real supervisor->worker spawn (where #423/#20's
|
|
# second half lives); the other guards test path/hook/drive fixes in-process.
|
|
run: ./scripts/test-windows.ps1 -GuardsOnly -Binary build/c/codebase-memory-mcp.exe
|