Test how the pruner reads a build that compiled nothing - #29
Merged
Merged
Conversation
…suite in CI The prune phase reads a failed build as a needed directory. Two patterns decide what a build's outcome means: a Gradle build that compiled nothing (NO-SOURCE) counts as a failure even with exit code zero, and failing tests alone do not count as a missing directory. Without the first, the pruner would hide the source directory it just tested and write a policy that fails a correct submission. Nothing tested either pattern. prune_sandbox.sh now checks both through a bwrap that builds no sandbox: it records which paths each attempt hides and runs the build directly, so the checks measure classification rather than containment and need no user namespace. Each rule is checked in both directions, the control runs disabling it, and every check reads the pruner's own build logs, so a broken stand-in fails the checks instead of passing them. The Test workflow now runs the suite. Its Bubblewrap checks skip there, and say so, because the runner has no bubblewrap.
Merged
12 of 14 tasks
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
Before a sandbox policy is written, the prune phase decides from each test run whether a hidden directory was needed. Two rules keep it from misreading a build that compiled nothing, or one whose tests simply fail. Nothing tested either rule. Both are now tested in both directions, and the test suite for the real pruner runs in CI.
Linked issues
Closes #16. Item 4 was done in #27; this finishes item 3.
1. Problem
The prune phase hides a directory, runs the exercise's build, and reads a failed run as "this directory was needed". Gradle reports a build that compiled nothing (
NO-SOURCE) with exit code zero. Without a rule reading that line as a failure, the pruner would conclude that the source directory it just hid was unnecessary and write a policy that keeps it hidden, so a correct submission would fail. A second rule stops ordinary failing tests from being read as a missing directory. The two patterns invar/tmp/pruning/detect_minimal_fs.shwere the whole defence and nothing exercised them.tests/prune_sandbox.sh, the suite that runs the real pruner, also ran in no workflow.2. Improvement from the user's perspective
No Improvement from the user's perspective
3. Improvement from the maintainer's perspective
Changing either rule, or how the pruner reads a build's outcome, now fails a check instead of quietly producing a policy that is too tight or cannot be generated. The checks need no Bubblewrap: a stand-in
bwrapbuilds no sandbox, records which paths each run would hide and runs the build directly, so they test how outcomes are classified, not what a sandbox contains. Each check reads the pruner's build logs, so a stand-in that breaks fails the checks rather than passing them. They run in theTestworkflow on every pull request; the suite's Bubblewrap checks skip there, visibly, because the runner has no bubblewrap.4. Testing manual
Prerequisites
Steps
docker run --rm -v "$PWD:/repo:ro" ubuntu:26.04 bash -c 'apt-get update -qq && apt-get install -y -qq python3 >/dev/null && cp -a /repo /w && bash /w/tests/prune_sandbox.sh'docker run --rm -v "$PWD:/repo:ro" ubuntu:26.04 bash -c 'apt-get update -qq && apt-get install -y -qq python3 >/dev/null && cp -a /repo /w && sed -i "s/There were failing tests|//" /w/var/tmp/pruning/detect_minimal_fs.sh && bash /w/tests/prune_sandbox.sh'docker run --rm -v "$PWD:/repo:ro" ubuntu:26.04 bash -c 'apt-get update -qq && apt-get install -y -qq python3 >/dev/null && cp -a /repo /w && sed -i "s/^UNIGNORABLE_SUCCESS_PATTERNS=.*/UNIGNORABLE_SUCCESS_PATTERNS=a^/" /w/var/tmp/pruning/detect_minimal_fs.sh && bash /w/tests/prune_sandbox.sh'--security-opt seccomp=unconfined --security-opt systempaths=unconfined, astests/prune_sandbox.shand Make the pruner safe to run against code it did not write #22 describe. Neither is--privileged.Expected result
oklines between the two--targetchecks and the Bubblewrap skip, and7 passed, 0 failed, 1 skipped.FAIL failing tests alone do not make a directory needed, and6 passed, 1 failed, 1 skipped.FAILon both checks about a build that compiles nothing, and5 passed, 2 failed, 1 skipped.15 passed, 0 failed, 0 skipped.Negative case (what must still be rejected)
A build that compiles nothing, whether it exits zero or not, keeps the directory it reads as
rrather than hidden. Two control runs show each rule is load-bearing: with the NO-SOURCE pattern disabled the same fixture recordsn, and with the failing-tests pattern disabled the pruner stops after its first attempt, whose log shows the build ran and printed its failing tests.Layers exercised
No layer-specific behaviour changed
5. Test case coverage regarding this PR
tests/prune_sandbox.sh, Ubuntu 26.04 container, root, no bubblewrap, as in CItarget/neededasr. Hidden: failing tests alone leavetarget/unneededasn. Controls: the NO-SOURCE rule disabled recordsn; the failing-tests rule disabled stops the prune after one attempt in which the build ran. The Bubblewrap group skips because nothing provides it.tests/prune_sandbox.sh, Ubuntu 26.04 container, non-root, bubblewrap, the two--security-optflags abovetests/prune_sandbox.shwith the NO-SOURCE pattern removedtests/prune_sandbox.shwith the failing-tests pattern removedtests/prune_sandbox.shwith the stand-inbwrapbroken so that it refuses every runAll runs used kernel 7.0 on arm64 under Docker Desktop.
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