Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 3 additions & 5 deletions std/capsicum/test_capsicum_portability.ae
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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
Expand Down
32 changes: 16 additions & 16 deletions tests/freebsd/README.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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.
7 changes: 3 additions & 4 deletions tests/freebsd/capsicum_enforce.ae
Original file line number Diff line number Diff line change
@@ -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
Expand Down
7 changes: 4 additions & 3 deletions tests/freebsd/casper_delegation.ae
Original file line number Diff line number Diff line change
@@ -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.
//
Expand Down
19 changes: 9 additions & 10 deletions tests/freebsd/nightly.sh
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
#!/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
# CLI) authenticated for issue filing. If `gh` is absent the script still
# 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
Expand All @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions tests/freebsd/rights_limit_stdlib_fd.ae
Original file line number Diff line number Diff line change
@@ -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
Expand Down
5 changes: 2 additions & 3 deletions tests/freebsd/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down