Add a runner capability probe for the CI that depends on it - #17
Merged
Merged
Conversation
added 2 commits
September 9, 2026 22:12
Two planned jobs depend on the machine rather than on this repository: running the Landlock acceptance suites inside an ordinary container, and running the pruner, which needs Bubblewrap and therefore unprivileged user namespaces. Neither can be read out of the source, and a runner image can withdraw either without notice, so the question is asked in one place and asked the same way every time. The probe walks the whole Landlock path rather than reading the version: it proves both fixture files are readable to begin with, applies a ruleset, and then proves the permitted file is still readable and the forbidden one is not. The opening baseline is what makes the answer trustworthy, since a file some other mechanism had already made unreadable would otherwise look exactly like Landlock working. It requires ABI 4, which is what the helper itself demands for the network rules the acceptance suite exercises with --connect-tcp. The Bubblewrap assertion runs a real script in a production-shaped sandbox rather than bwrap /bin/true, since the namespaces, the tmpfs root and the bound work directory are the parts that fail on a restricted host. It refuses to answer as root, which is exempt from the very restriction being measured. Verdicts are three-valued. A capability this repository does not yet use being absent is a fact to record, so it leaves the dispatch green; a probe that could not reach a verdict is not a fact about anything, and fails the run instead. The workflow is manual on purpose. It is a diagnostic, not a gate.
main moved its jobs to ubuntu-26.04 while this branch was open, so the probe was left asking its questions of a different machine from the one the rest of CI uses, which is the one thing a capability probe must not do. The container it starts follows for the same reason.
MarkusPaulsen
force-pushed
the
chore/runner-capability-probe
branch
from
September 9, 2026 20:13
04213aa to
b1adb01
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a manual workflow that reports what a GitHub runner can actually do, before the CI that depends on the answer is written. Two planned jobs turn on the machine rather than on this repository: running the Landlock acceptance suites inside an ordinary container, and running the prune phase, which needs Bubblewrap. Neither answer can be read out of the source, and a runner image can withdraw either without notice.
Linked issues
No linked issues.
1. Problem
Nothing here can say whether a GitHub runner enforces a Landlock policy inside an ordinary container, or whether Bubblewrap can build a sandbox on it at all. Both are properties of the machine rather than of the code, and each decides whether a planned job is worth writing: the first governs the Landlock acceptance suites, the second the prune phase that discovers which paths a language environment needs.
Two parts of Phobos are involved, and they use different mechanisms for the same job. The run phase confines a submission with Landlock. The prune phase uses Bubblewrap, which needs unprivileged user namespaces, restricted by default on Ubuntu since 24.04 and so measured on the
ubuntu-26.04runner, not assumed.Writing either job first and finding out afterwards means writing a job that may have to be thrown away, or worse, one that passes for a reason nobody checked. Nothing is broken today. This is the gap that has to be closed before the rest of the CI is worth writing.
2. Improvement from the user's perspective
No Improvement from the user's perspective.
3. Improvement from the maintainer's perspective
One dispatch answers both capability questions, with the kernel, the Landlock version, the AppArmor settings and the Bubblewrap version recorded beside the answer, so a later CI failure can be compared against a known-good survey instead of being re-diagnosed from scratch. Because the probe stays in the repository, the same question can be asked again whenever GitHub changes the runner image.
The survey also reports one finding about this repository rather than the machine: the prune phase asks Bubblewrap for
--unshare-utc, which Bubblewrap has never had. The option is--unshare-uts. That is reported and not asserted, because it is a defect here and not a property of the runner.4. Testing manual
Prerequisites
--privileged,--cap-addor--security-opt.Steps
Not reproducible from a run. This adds a workflow and the scripts it calls, so no submission executes differently. A reviewer verifies it in three ways instead.
.sh,gcc -Wall -Wextra -Werror -fanalyzerand cppcheck over every.c, actionlint over the new workflow, and yamllint over the repository.docker run --rm -v "$PWD:/mnt:ro" ubuntu:26.04 bash -c 'apt-get update -qq >/dev/null && apt-get install -y -qq gcc libc6-dev bubblewrap >/dev/null && cp -r /mnt/tests /t && bash /t/runner-capability-probe.sh --report'libc6-devis named because 26.04 no longer pulls it in withgcc. Without it the probe stops atfatal error: errno.h, and the whole Landlock half of the survey goes unanswered while the Bubblewrap half still reports, which is easy to read past.--reportwith--assert-landlock.workflow_dispatchfor a workflow that is already on the default branch, which is why this change comes before the CI that uses it.Expected result
rejected: --unshare-utc is not an option, --unshare-uts is.okfor the ABI, for the fixture baseline, for the applied ruleset, for the permitted read, for the refused read and for the host as a whole, and thenverdict: indeterminate, the probe could not answer, exit 3. That is the right answer from inside a container: there is no Docker daemon in it, so the container half cannot be asked, and an unanswered half must never be reported as available. On a GitHub runner both halves are answered and the verdict isavailable.available,unavailableorindeterminate.Negative case (what must still be rejected)
The probe must never report a capability as present when it is not, so both false-positive paths are checked directly.
bwraponPATHthat runsecho sandboxed-build-ran; exit 73and run--assert-bwrap: it must printFAIL ... (exit 73)andverdict: unavailable.chmod 000the fixture's forbidden file before the probe runs and the probe must exit indeterminate withthe forbidden file is unreadable before any restriction, not report enforcement.--assert-bwrapas root must refuse to answer, because root is exempt from the restriction being measured.One check cannot be made in an ordinary container. Proving that the Bubblewrap invocation is well formed needs a host where user namespaces are permitted, so that one was run once under
--privileged, purely to confirm the sandbox assembles and the script inside it runs. Every other result above was produced without any security flag.Layers exercised
No layer-specific behaviour changed.
5. Test case coverage regarding this PR
No behaviour covered by the suites changed.
Breaking changes and migration
No breaking changes or migration.
Checklist
--privileged,--cap-addor--security-opt, or the manual says why that was not possible.Review progress