Skip to content

Commit bbf3450

Browse files
committed
Harden sandbox validation and scanners
1 parent 0753fe8 commit bbf3450

49 files changed

Lines changed: 404 additions & 254 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2828
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
2929
with:
30-
go-version: "1.25"
30+
go-version: "1.25.10"
3131
cache-dependency-path: services/${{ matrix.service }}/go.sum
3232

3333
- name: Build
@@ -268,7 +268,7 @@ jobs:
268268
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
269269
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
270270
with:
271-
go-version: "1.25"
271+
go-version: "1.25.10"
272272

273273
- name: Install cosign (signing & attestation)
274274
run: |
@@ -457,7 +457,7 @@ jobs:
457457

458458
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
459459
with:
460-
go-version: "1.25"
460+
go-version: "1.25.10"
461461

462462
- name: Install Python dependencies
463463
run: pip install -r requirements-ci.txt
@@ -487,7 +487,7 @@ jobs:
487487

488488
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
489489
with:
490-
go-version: "1.25"
490+
go-version: "1.25.10"
491491

492492
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
493493
with:
@@ -509,7 +509,7 @@ jobs:
509509

510510
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
511511
with:
512-
go-version: "1.25"
512+
go-version: "1.25.10"
513513

514514
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
515515
with:
@@ -820,7 +820,7 @@ jobs:
820820

821821
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
822822
with:
823-
go-version: "1.25"
823+
go-version: "1.25.10"
824824

825825
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
826826
with:
@@ -861,9 +861,11 @@ jobs:
861861
run: python -m pytest tests/test_m5_acceptance.py -v --tb=short
862862

863863
- name: Release gate summary
864+
env:
865+
REF_NAME: ${{ github.ref_name }}
864866
run: |
865867
{
866868
echo "## Release Gate: PASSED"
867-
echo "Branch: ${{ github.ref_name }}"
869+
echo "Branch: ${REF_NAME}"
868870
echo "All hardened checks passed for release branch."
869871
} >> "$GITHUB_STEP_SUMMARY"

.github/workflows/release.yml

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -86,24 +86,30 @@ jobs:
8686
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
8787
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
8888
with:
89-
go-version: "1.25"
89+
go-version: "1.25.10"
9090
cache-dependency-path: services/${{ matrix.service }}/go.sum
9191

9292
- name: Build (linux/amd64)
9393
working-directory: services/${{ matrix.service }}
94+
env:
95+
SERVICE: ${{ matrix.service }}
96+
VERSION: ${{ github.ref_name }}
9497
run: |
9598
mkdir -p ../../dist
9699
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
97-
go build -ldflags="-s -w -X main.version=${{ github.ref_name }}" \
98-
-o ../../dist/${{ matrix.service }}-linux-amd64 .
100+
go build -ldflags="-s -w -X main.version=${VERSION}" \
101+
-o "../../dist/${SERVICE}-linux-amd64" .
99102
100103
- name: Build (linux/arm64)
101104
working-directory: services/${{ matrix.service }}
105+
env:
106+
SERVICE: ${{ matrix.service }}
107+
VERSION: ${{ github.ref_name }}
102108
run: |
103109
mkdir -p ../../dist
104110
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 \
105-
go build -ldflags="-s -w -X main.version=${{ github.ref_name }}" \
106-
-o ../../dist/${{ matrix.service }}-linux-arm64 .
111+
go build -ldflags="-s -w -X main.version=${VERSION}" \
112+
-o "../../dist/${SERVICE}-linux-arm64" .
107113
108114
- name: Generate SBOM (Syft)
109115
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
@@ -208,6 +214,8 @@ jobs:
208214
done
209215
210216
- name: Generate sandbox OpenVEX document
217+
env:
218+
DOCUMENT_ID: https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/custom-python.vex.json
211219
run: |
212220
mkdir -p dist
213221
python3 scripts/security/generate_custom_python_vex.py \
@@ -216,7 +224,7 @@ jobs:
216224
--image secai-sandbox-search-mediator:latest \
217225
--image secai-sandbox-diffusion:latest \
218226
--include-unicode-locale-glibc \
219-
--document-id "https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}/custom-python.vex.json" \
227+
--document-id "${DOCUMENT_ID}" \
220228
--output dist/custom-python.vex.json
221229
222230
- name: Upload OpenVEX artifact
@@ -302,12 +310,14 @@ jobs:
302310
sudo apt-get install -y podman xz-utils
303311
304312
- name: Build portable USB image
313+
env:
314+
VERSION: ${{ github.ref_name }}
305315
run: |
306316
mkdir -p dist
307317
sudo bash scripts/build-usb-image.sh \
308318
--image-ref "ghcr.io/secai-hub/secai_os:latest" \
309319
--output-dir ./dist \
310-
--version "${{ github.ref_name }}"
320+
--version "${VERSION}"
311321
312322
- name: Install cosign
313323
run: |
@@ -361,18 +371,19 @@ jobs:
361371
chmod +x /usr/local/bin/cosign
362372
363373
- name: Sign VM artifacts
374+
env:
375+
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
376+
VERSION: ${{ github.ref_name }}
364377
run: |
365378
mkdir -p dist
366-
cp output/secai-os.qcow2 "dist/secai-os-${{ github.ref_name }}.qcow2"
367-
cp output/secai-os.ova "dist/secai-os-${{ github.ref_name }}.ova"
368-
for f in dist/secai-os-${{ github.ref_name }}.qcow2 dist/secai-os-${{ github.ref_name }}.ova; do
379+
cp output/secai-os.qcow2 "dist/secai-os-${VERSION}.qcow2"
380+
cp output/secai-os.ova "dist/secai-os-${VERSION}.ova"
381+
for f in "dist/secai-os-${VERSION}.qcow2" "dist/secai-os-${VERSION}.ova"; do
369382
cosign sign-blob --yes \
370383
--key env://COSIGN_PRIVATE_KEY \
371384
--output-signature "${f}.sig" \
372385
"$f"
373386
done
374-
env:
375-
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
376387
377388
- name: Upload VM artifacts
378389
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
@@ -409,9 +420,10 @@ jobs:
409420
install -m 0644 scripts/release/secai-os-run-docker.ps1 dist/secai-os-run-docker.ps1
410421
411422
- name: Record release image digest
423+
env:
424+
IMAGE_REF: ghcr.io/${{ github.repository }}
425+
TAG: ${{ github.ref_name }}
412426
run: |
413-
IMAGE_REF="ghcr.io/${{ github.repository }}"
414-
TAG="${{ github.ref_name }}"
415427
DIGEST=$(skopeo inspect "docker://${IMAGE_REF}:${TAG}" 2>/dev/null | jq -r '.Digest' || echo "")
416428
if [ -n "$DIGEST" ] && [ "$DIGEST" != "null" ]; then
417429
echo "${DIGEST}" > dist/IMAGE_DIGEST
@@ -428,6 +440,12 @@ jobs:
428440
fi
429441
430442
- name: Generate release manifest
443+
env:
444+
COMMIT_SHA: ${{ github.sha }}
445+
IMAGE_REF: ghcr.io/${{ github.repository }}
446+
TAG: ${{ github.ref_name }}
447+
WORKFLOW_REF: ${{ github.workflow_ref }}
448+
WORKFLOW_RUN: ${{ github.run_id }}
431449
run: |
432450
cd dist
433451
@@ -482,8 +500,8 @@ jobs:
482500
# Build manifest JSON
483501
jq -n \
484502
--arg schema_version "1" \
485-
--arg tag "${{ github.ref_name }}" \
486-
--arg image_ref "ghcr.io/${{ github.repository }}" \
503+
--arg tag "${TAG}" \
504+
--arg image_ref "${IMAGE_REF}" \
487505
--arg image_digest "$IMAGE_DIGEST" \
488506
--arg image_ref_pinned "$IMAGE_REF_PINNED" \
489507
--argjson binaries "$BINARIES_JSON" \
@@ -493,9 +511,9 @@ jobs:
493511
--arg provenance_type "https://slsa.dev/provenance/v1" \
494512
--arg checksum_file "SHA256SUMS" \
495513
--arg signature_file "SHA256SUMS.sig" \
496-
--arg commit_sha "${{ github.sha }}" \
497-
--arg workflow_run "${{ github.run_id }}" \
498-
--arg workflow_ref "${{ github.workflow_ref }}" \
514+
--arg commit_sha "${COMMIT_SHA}" \
515+
--arg workflow_run "${WORKFLOW_RUN}" \
516+
--arg workflow_ref "${WORKFLOW_REF}" \
499517
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
500518
'{
501519
schema_version: $schema_version,
@@ -571,18 +589,20 @@ jobs:
571589
subject-path: "dist/*-linux-*"
572590

573591
- name: Attest SBOMs
592+
env:
593+
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
594+
IMAGE_REF: ghcr.io/${{ github.repository }}
595+
TAG: ${{ github.ref_name }}
574596
run: |
575597
for sbom in dist/*-sbom.cdx.json; do
576598
service=$(basename "$sbom" -sbom.cdx.json)
577-
image_ref="ghcr.io/${{ github.repository }}:${{ github.ref_name }}-${service}"
599+
image_ref="${IMAGE_REF}:${TAG}-${service}"
578600
cosign attest --yes --type cyclonedx \
579601
--predicate "$sbom" \
580602
--key env://COSIGN_PRIVATE_KEY \
581603
"$image_ref" || \
582604
echo "WARN: cosign attest skipped for ${service} (no matching image)"
583605
done
584-
env:
585-
COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }}
586606
587607
- name: Create GitHub Release (binaries + SBOMs + checksums)
588608
if: ${{ !inputs.dry_run }}

.github/workflows/vm-boot-smoke.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,18 @@ jobs:
4141
id: image
4242
env:
4343
GH_TOKEN: ${{ github.token }}
44+
IMAGE_DIGEST_INPUT: ${{ inputs.image_digest }}
45+
REF_NAME: ${{ github.ref_name }}
46+
REPOSITORY: ${{ github.repository }}
4447
run: |
45-
if [ -n "${{ inputs.image_digest }}" ]; then
46-
DIGEST="${{ inputs.image_digest }}"
48+
if [ -n "${IMAGE_DIGEST_INPUT}" ]; then
49+
DIGEST="${IMAGE_DIGEST_INPUT}"
4750
else
4851
echo "Fetching IMAGE_DIGEST artifact from latest build workflow run..."
49-
RUN_ID=$(gh api "repos/${{ github.repository }}/actions/workflows/build.yml/runs?branch=${{ github.ref_name }}&status=success&per_page=1" \
52+
RUN_ID=$(gh api "repos/${REPOSITORY}/actions/workflows/build.yml/runs?branch=${REF_NAME}&status=success&per_page=1" \
5053
--jq '.workflow_runs[0].id' 2>/dev/null || echo "")
5154
if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then
52-
echo "ERROR: No successful build.yml run found for ref ${{ github.ref_name }}"
55+
echo "ERROR: No successful build.yml run found for ref ${REF_NAME}"
5356
exit 1
5457
fi
5558
echo "Using build run: ${RUN_ID}"

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,8 @@ All CI jobs are defined in [`.github/workflows/ci.yml`](.github/workflows/ci.yml
315315

316316
| Job | Workflow Link | What It Proves |
317317
|-----|--------------|---------------|
318-
| `go-build-and-test` | [View job](https://github.com/SecAI-Hub/SecAI_OS/actions/workflows/ci.yml) | 428 Go tests across 9 services with `-race` (build, test, vet) |
319-
| `python-test` | [View job](https://github.com/SecAI-Hub/SecAI_OS/actions/workflows/ci.yml) | 1,136 Python tests (unit/integration + adversarial/acceptance), ruff lint, bandit security scan (enforced on HIGH/HIGH), mypy type checking |
318+
| `go-build-and-test` | [View job](https://github.com/SecAI-Hub/SecAI_OS/actions/workflows/ci.yml) | 429 Go tests across 9 services with `-race` (build, test, vet) |
319+
| `python-test` | [View job](https://github.com/SecAI-Hub/SecAI_OS/actions/workflows/ci.yml) | 1,154 Python tests (unit/integration + adversarial/acceptance), ruff lint, bandit security scan (enforced on HIGH/HIGH), mypy type checking |
320320
| `appsec-lint` | [View job](https://github.com/SecAI-Hub/SecAI_OS/actions/workflows/ci.yml) | Hadolint for container build files and Semgrep project security rules |
321321
| `security-regression` | [View job](https://github.com/SecAI-Hub/SecAI_OS/actions/workflows/ci.yml) | Adversarial test suite: prompt injection, policy bypass, containment, recovery |
322322
| `supply-chain-verify` | [View job](https://github.com/SecAI-Hub/SecAI_OS/actions/workflows/ci.yml) | SBOM generation via Syft, cosign availability, provenance keywords in release/build workflows |
@@ -338,7 +338,7 @@ All CI jobs are defined in [`.github/workflows/ci.yml`](.github/workflows/ci.yml
338338
| [API Reference](docs/api.md) | HTTP API for all services |
339339
| [Policy Schema](docs/policy-schema.md) | Full policy.yaml schema reference |
340340
| [Security Status](docs/security-status.md) | Implementation status of all 54 milestones |
341-
| [Test Matrix](docs/test-matrix.md) | Test coverage: 1,564 tests across Go and Python (see [test-counts.json](docs/test-counts.json)) |
341+
| [Test Matrix](docs/test-matrix.md) | Test coverage: 1,583 tests across Go and Python (see [test-counts.json](docs/test-counts.json)) |
342342
| [Compatibility Matrix](docs/compatibility-matrix.md) | GPU, VM, and hardware support |
343343
| [Security Test Matrix](docs/security-test-matrix.md) | Security feature test coverage |
344344
| [FAQ](docs/faq.md) | Common questions |
@@ -456,13 +456,13 @@ Privacy: Tor-routed, PII stripped, injection detection, privacy-preserving query
456456
## Running Tests
457457

458458
```bash
459-
# Go tests (428 total across 9 services)
459+
# Go tests (429 total across 9 services)
460460
for svc in airlock registry tool-firewall gpu-integrity-watch mcp-firewall \
461461
policy-engine runtime-attestor integrity-monitor incident-recorder; do
462462
(cd services/$svc && go test -v -race ./...)
463463
done
464464

465-
# Python tests (1,136 total)
465+
# Python tests (1,154 total)
466466
python -m pip install -r requirements-ci.txt
467467
PYTHONPATH=services python -m pytest tests/ -v
468468

@@ -564,7 +564,7 @@ services/
564564
search-mediator/ Python -- Tor-routed web search (:8485)
565565
ui/ Python/Flask -- Web UI (:8480)
566566
common/ Python -- Shared utilities (audit, auth, mlock)
567-
tests/ 1,136 Python tests, 428 Go tests (1,564 total)
567+
tests/ 1,154 Python tests, 429 Go tests (1,583 total)
568568
docs/ Architecture, API, threat model, install guides
569569
schemas/ OpenAPI spec, JSON Schema for config files
570570
examples/ Task-oriented walkthroughs

deploy/sandbox/compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ services:
195195
- "9050"
196196
tmpfs:
197197
- /tmp:rw,noexec,nosuid,nodev,size=64m
198-
- /var/lib/tor:rw,nosuid,nodev,size=32m,uid=100,gid=101
198+
- /var/lib/tor:rw,nosuid,nodev,size=128m,uid=100,gid=101
199199
healthcheck:
200200
test: ["CMD-SHELL", "nc -z 127.0.0.1 9050 || exit 1"]
201201
interval: 15s

deploy/sandbox/searxng/Containerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM docker.io/searxng/searxng@sha256:37c616a774b90fb5df9239eb143f1b11866ddf7b830cd1ebcca6ba11b38cc2bf
1+
FROM docker.io/searxng/searxng@sha256:e37c25170d9f5947b16713af33e0ab41f0e6e6e73685e19c30fc6bb63562f801
22

33
USER root
44

deploy/sandbox/tor/Containerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM docker.io/library/alpine:3.22@sha256:310c62b5e7ca5b08167e4384c68db0fd2905dd9c7493756d356e893909057601
1+
FROM docker.io/library/alpine:3.23@sha256:5b10f432ef3da1b8d4c7eb6c487f2f5a8f096bc91145e68878dd4a5019afde11
22

33
RUN apk add --no-cache tor
44

docs/install/dev.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This guide covers running SecAI OS services locally for development and testing,
66

77
## Prerequisites
88

9-
- **Go 1.25+** for building Go services
9+
- **Go 1.25.10+** for building Go services
1010
- **Python 3.12 recommended** for running Python services. CI and lockfiles use Python 3.12; package metadata still allows Python 3.11 where scanner compatibility requires it.
1111
- **pip** for Python dependency management
1212
- **git** for version control

0 commit comments

Comments
 (0)