# agent-guard CI - Linux/macOS full matrix plus focused Windows Core checks. # # The full suite remains on Linux/macOS. The Windows job pins the Core shapes # that need real ntpath/filesystem behavior without pretending that every # POSIX fixture or harness is portable. Zero third-party dependencies. name: CI on: push: branches: [main] pull_request: workflow_dispatch: concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: test: name: ${{ matrix.os }} / Py${{ matrix.python-version }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Unit, CLI, recovery, policy and conformance suites run: | set -o pipefail python -m unittest discover tests -v 2>&1 | tee test-output.txt - name: Upload test log if: always() uses: actions/upload-artifact@v4 with: name: test-log-${{ matrix.os }}-py${{ matrix.python-version }} path: test-output.txt if-no-files-found: error - name: Integration smoke - hard boundary holds end-to-end shell: bash run: | set -e d="$(mktemp -d)" git -C "$d" init -q printf 'node_modules/\n' > "$d/.gitignore" cd "$d" # workspace root must be refused with exit code 2 even under --enforce python3 "$GITHUB_WORKSPACE/skills/delete-guard/scripts/check.py" \ --enforce -- 'rm -rf .' && { echo 'guard failed to block'; exit 1; } \ || test $? -eq 2 echo 'hard boundary verified' dsh-adapter-smoke: name: DSH adapter runtime smoke runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "22.23.2" - uses: actions/setup-python@v5 with: python-version: "3.11" - name: Import and initialize adapter with mocked host services run: npm run test:dsh dsh-native-lab: name: DSH native Lab capture / Node22 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: "22.23.2" - uses: actions/setup-python@v5 with: python-version: "3.11" - name: Native session decoder and capture regressions (no model) run: python -m unittest -v tests.test_dsh_native_session tests.test_dsh_profiles tests.test_dsh_guard_lab tests.test_dsh_read_redaction windows-core-rc: name: Windows Core RC gate / Py3.13 runs-on: windows-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.13" - name: Dialect mismatch, path normalization and safe recovery checks shell: pwsh run: | python -m unittest -v ` tests.test_dialects ` tests.test_delete.SafeDeleteCLI.test_relocate_then_restore_roundtrip ` tests.test_delete.WindowsVerbNoDialect ` tests.test_delete.CheckCLI.test_cmd_dialect_cannot_turn_rm_root_delete_into_noop ` tests.test_exfil_sanitize.FormatPreservation.test_native_windows_user_path_uses_exact_bytes_and_sanitizes ` *> windows-core-test-output.txt $testExit = $LASTEXITCODE Get-Content windows-core-test-output.txt if ($testExit -ne 0) { exit $testExit } - name: Upload Windows Core test log if: always() uses: actions/upload-artifact@v4 with: name: windows-core-py3.13-test-log path: windows-core-test-output.txt if-no-files-found: error