diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f4c687a76..a0d98c24f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -596,6 +596,8 @@ jobs: set -e gmake compiler ae stdlib gmake test + ./build/ae run std/capsicum/test_capsicum_portability.ae + sh tests/freebsd/run.sh # ============================================================ # contrib/host bridge check — syntax check of every host bridge diff --git a/std/capsicum/test_capsicum_portability.ae b/std/capsicum/test_capsicum_portability.ae index 04bb95236..7420bcbcd 100644 --- a/std/capsicum/test_capsicum_portability.ae +++ b/std/capsicum/test_capsicum_portability.ae @@ -1,5 +1,4 @@ -// std.capsicum / std.casper portability (#1584) — co-located, replacing -// tests/regression/test_capsicum_portability.ae. +// std.capsicum / std.casper portability (#1584), co-located with the module. // // Capsicum is FreeBSD-only, and that is exactly why this suite runs // EVERYWHERE rather than skipping. Two contracts, and both matter: @@ -16,9 +15,8 @@ // half everywhere and asserts something real on every leg. // // The kernel-enforcement behaviour itself (entering capability mode, -// rights narrowing, Casper delegation) needs a live FreeBSD box: that -// lives in tests/freebsd/ and the nightly harness, which the CI matrix -// has no runner for. +// rights narrowing, Casper delegation) needs a live FreeBSD box. Those +// tests live in tests/freebsd/ and run in the native FreeBSD CI job. import std.spec import std.capsicum diff --git a/tests/freebsd/README.md b/tests/freebsd/README.md index ab5dcc67d..d34faf6c3 100644 --- a/tests/freebsd/README.md +++ b/tests/freebsd/README.md @@ -1,14 +1,14 @@ # FreeBSD-only sandbox tests These exercise **real Capsicum / Casper enforcement** and can only pass on a -FreeBSD host with a Capsicum-enabled kernel. GitHub's CI matrix has **no -FreeBSD runner**, so they live here (outside `tests/regression/`) and are run -by `run.sh` / the nightly harness rather than the normal test suite. +FreeBSD host with a Capsicum-enabled kernel. They live here, outside the +portable regression suite, and are run by `run.sh` in the native FreeBSD CI +VM. The nightly harness can provide an independent scheduled run. -The portable side of the contract — graceful degrade off FreeBSD, the gate -`aeo`'s `require_capsicum()` / `prefer_capsicum()` depends on — **is** covered -by `tests/regression/test_capsicum_portability.ae`, which runs on every CI -platform. +The portable side of the contract - graceful degrade off FreeBSD, the gate +`aeo`'s `require_capsicum()` / `prefer_capsicum()` depends on - **is** covered +by `std/capsicum/test_capsicum_portability.ae`, which runs in the portable +suite and explicitly in the native FreeBSD CI job. ## Tests @@ -39,22 +39,22 @@ sh tests/freebsd/run.sh # uses ./build/ae; all-skip + exit 0 off FreeB AE=/path/to/ae sh tests/freebsd/run.sh ``` -## Nightly self-test (the CI stand-in) +## Optional nightly self-test -`nightly.sh` syncs the target branch, builds from clean, runs these tests + -the portable contract test + the `#668` seccomp clone-fence test, and **files -a GitHub issue on failure** (deduped by an issue-title marker; comments on the -existing issue rather than spamming new ones). Intended for a cron on the -GhostBSD build box. +`nightly.sh` provides an independent scheduled run. It syncs the target branch, +builds from clean, runs these tests plus the portable contract test, and +**files a GitHub issue on failure** (deduped by an issue-title marker; comments +on the existing issue rather than spamming new ones). It is intended for a cron +on the GhostBSD build box. ```sh # GhostBSD cron (03:17 nightly): -17 3 * * * cd $HOME/aether && BRANCH=feat/freebsd-sandbox-parity-v2 \ +17 3 * * * cd $HOME/aether && BRANCH=main \ sh tests/freebsd/nightly.sh >> $HOME/aether-nightly.log 2>&1 ``` `gh` must be authenticated on the host for issue filing; without it the script still runs the tests and just prints the report. `NO_ISSUE=1` forces a dry run. -When a real FreeBSD CI runner exists, fold `run.sh` into the matrix and retire -the nightly (or keep it as defence in depth). +The native FreeBSD CI job is the pull-request gate. Keep the nightly only when +an independent scheduled run is useful. diff --git a/tests/freebsd/capsicum_enforce.ae b/tests/freebsd/capsicum_enforce.ae index bf7fbc002..383303265 100644 --- a/tests/freebsd/capsicum_enforce.ae +++ b/tests/freebsd/capsicum_enforce.ae @@ -1,7 +1,6 @@ -// FreeBSD-only Capsicum enforcement test (run as a subprocess by the -// nightly harness / tests/freebsd/run.sh). NOT in the CI regression set — -// the CI matrix has no FreeBSD runner; the portable contract is covered by -// tests/regression/test_capsicum_portability.ae. +// FreeBSD-only Capsicum enforcement test (run as a subprocess by +// tests/freebsd/run.sh in the native FreeBSD CI job). The portable contract +// is covered by std/capsicum/test_capsicum_portability.ae. // // capsicum.enter() is IRREVERSIBLE and process-wide, so this whole program // is the unit: it asserts pre-state, enters capability mode, then asserts diff --git a/tests/freebsd/casper_delegation.ae b/tests/freebsd/casper_delegation.ae index df962c09c..2ff4bfd1e 100644 --- a/tests/freebsd/casper_delegation.ae +++ b/tests/freebsd/casper_delegation.ae @@ -1,7 +1,8 @@ -// FreeBSD-only Casper delegation test (run as a subprocess by the nightly -// harness). Proves the two-phase pattern that std.casper's docstring (and +// FreeBSD-only Casper delegation test (run as a subprocess by +// tests/freebsd/run.sh in the native FreeBSD CI job). Proves the two-phase +// pattern that std.casper's docstring (and // aeo's design) depend on: open the service channel BEFORE entering -// capability mode, then use it AFTER — a passwd lookup that would +// capability mode, then use it AFTER - a passwd lookup that would // otherwise be impossible in capability mode (no /etc/passwd access) // succeeds because Casper performs it on the other side of the boundary. // diff --git a/tests/freebsd/nightly.sh b/tests/freebsd/nightly.sh index 1c3e1c7d6..1cc002cb3 100755 --- a/tests/freebsd/nightly.sh +++ b/tests/freebsd/nightly.sh @@ -1,15 +1,14 @@ #!/bin/sh # tests/freebsd/nightly.sh — self-run nightly FreeBSD sandbox validation. # -# There is no FreeBSD runner in the GitHub CI matrix, so the Capsicum / -# Casper / audit enforcement paths can't be gated automatically. This -# script is the stand-in: run it on a cron on the GhostBSD build box -# (paul@192.168.0.57), it builds the target branch from a clean tree and -# runs the FreeBSD enforcement tests + the portable contract test. On -# failure it opens (or updates) a GitHub issue so the result feeds back. +# The native FreeBSD CI job gates the Capsicum / Casper enforcement paths. +# This script provides an optional independent scheduled run on the GhostBSD +# build box: it builds the target branch from a clean tree and runs the +# FreeBSD enforcement tests plus the portable contract test. On failure it +# opens (or updates) a GitHub issue so the result feeds back. # # Cron example (GhostBSD), 03:17 nightly: -# 17 3 * * * cd $HOME/aether && BRANCH=feat/freebsd-sandbox-parity-v2 \ +# 17 3 * * * cd $HOME/aether && BRANCH=main \ # sh tests/freebsd/nightly.sh >> $HOME/aether-nightly.log 2>&1 # # Requirements on the host: git, gmake, a C toolchain, and `gh` (GitHub @@ -17,12 +16,12 @@ # runs the tests and just prints the report (no issue filed). # # Env: -# BRANCH branch to test (default: feat/freebsd-sandbox-parity-v2) +# BRANCH branch to test (default: main) # REPO owner/name for issues (default: aether-lang-dev/aether) # NO_ISSUE=1 run tests, never file an issue (dry run) set -u -BRANCH="${BRANCH:-feat/freebsd-sandbox-parity-v2}" +BRANCH="${BRANCH:-main}" REPO="${REPO:-aether-lang-dev/aether}" ROOT=$(cd "$(dirname "$0")/../.." && pwd) cd "$ROOT" || exit 3 @@ -47,7 +46,7 @@ fail_report() { return fi title="$MARKER $BRANCH failed: $stage" - body=$(printf 'Nightly FreeBSD sandbox validation failed.\n\n- host: %s\n- branch: `%s`\n- commit: `%s`\n- stage: **%s**\n- when: %s\n\n```\n%s\n```\n\n_Filed automatically by tests/freebsd/nightly.sh (no FreeBSD CI runner yet)._' \ + body=$(printf 'Nightly FreeBSD sandbox validation failed.\n\n- host: %s\n- branch: `%s`\n- commit: `%s`\n- stage: **%s**\n- when: %s\n\n```\n%s\n```\n\n_Filed automatically by the optional tests/freebsd/nightly.sh run._' \ "$(uname -srm)" "$BRANCH" "$(git rev-parse --short HEAD 2>/dev/null)" "$stage" "$TS" "$(tail -120 "$LOG")") # Dedup: if an open issue with the same title exists, comment instead. existing=$(gh issue list --repo "$REPO" --state open --search "$title in:title" --json number --jq '.[0].number' 2>/dev/null) diff --git a/tests/freebsd/rights_limit_stdlib_fd.ae b/tests/freebsd/rights_limit_stdlib_fd.ae index 4c5feb081..7e8469acc 100644 --- a/tests/freebsd/rights_limit_stdlib_fd.ae +++ b/tests/freebsd/rights_limit_stdlib_fd.ae @@ -1,6 +1,6 @@ // FreeBSD-only: capsicum.rights_limit() on a descriptor obtained from a -// std.file handle via file.fd() (issue #1003). Run by tests/freebsd/run.sh; -// NOT in the CI regression set (no FreeBSD runner). +// std.file handle via file.fd() (issue #1003). Run by tests/freebsd/run.sh +// in the native FreeBSD CI job. // // Proves the fd accessor returns the real kernel descriptor: narrowing it // succeeds; after capsicum.enter() the narrowed, already-open handle still diff --git a/tests/freebsd/run.sh b/tests/freebsd/run.sh index 4d502e4a7..1709c6376 100755 --- a/tests/freebsd/run.sh +++ b/tests/freebsd/run.sh @@ -2,9 +2,8 @@ # tests/freebsd/run.sh — run the FreeBSD-only sandbox enforcement tests. # # These exercise REAL Capsicum/Casper behaviour and can only pass on a -# FreeBSD host with a Capsicum-enabled kernel; there is no FreeBSD runner -# in the CI matrix yet, so they live outside tests/regression/ and are -# driven by this script (locally / by the nightly harness). +# FreeBSD host with a Capsicum-enabled kernel. The native FreeBSD CI job +# and the optional nightly harness both drive this script. # # Each test .ae is a self-contained program: exit 0 = pass, 1 = fail, # 2 = skip (not FreeBSD). On a non-FreeBSD host every test skips and the