Skip to content

sandbox: the compressor family is enumerated by name, so its unlisted twins keep the hole (pigz, lz4, lzop, …) #1420

Description

@argszero

What is still open

PR #1418 names the compressor family to the write-target walk (gzip, gunzip, bzip2, bunzip2,
xz, unxz, lzma, unlzma, zstd, unzstd), with a read-form gate so -c/--stdout/-t/-l
and the -dc cluster stay allowed. That is the family enumerated by name, so every compressor
whose name is not on that list keeps exactly the hole the PR closes: an empty target list, and the
loop that judges targets never runs.

Two rows measured at #1418's own head (78e2c4d1), through the real predicate, workdir=/workspace:

$ python -c "from emrg.tools.bash_tool import _check_sandbox, _extract_write_targets; ..."
lz4 /outside/emrg/f                     targets=[]  read-only=ALLOW  workspace-write=ALLOW
lz4 /outside/emrg/f /outside/emrg/f.lz4 targets=[]  read-only=ALLOW  workspace-write=ALLOW
pigz /outside/emrg/f                    targets=[]  read-only=ALLOW  workspace-write=ALLOW
zstd /outside/emrg/f                    targets=['/outside/emrg/f']  read-only=BLOCK  workspace-write=BLOCK   <- the family #1418 added, for contrast

Why this is not the same residual as the tar / curl family

lz4 is not hypothetical here: it is installed on this host (/opt/homebrew/bin/lz4), so it is
reachable from a sandboxed bash call. The second row is the sharper half — an explicit positional
destination
outside the workspace is named by nothing, which is the destination-last shape rsync
had before #1419 rather than the option-value shape tar/curl have.

Ground truth measured first (the discipline this class keeps needing)

The verdict alone is not evidence that a verb needs the write treatment, so the semantics were
measured in a scratch directory before this issue was written:

$ cd $(mktemp -d) && printf 'hello compressors\n' > f && lz4 f && ls
Compressed filename will be : f.lz4
f  f.lz4          # rc=0; f still present, f.lz4 created

So lz4 is not a gzip-style in-place rewriter: its default form derives a new path beside the
operand. That is a write the walk cannot see in the same direction as the gzip -k row #1418
blocks (a second file appears), not the same as gzip -S.c (which the PR documents as a named limit).
It also means the first question for this issue is not "which verbs join the set" but what each
verb's default form does
, per verb:

verb default form shape
pigz, pbzip2, pixz, plzip, lbzip2 in-place twin of the gzip/bzip2/xz CLI same as the family #1418 added
lz4 derives a sibling path (ff.lz4), keeps the operand write, operand unnamed; the derived path is not nameable without a per-verb rule
lzop, brotli, lzip to be measured

pigz is listed first because it is the exact twin of gzip (pigz ff.gz, operand removed;
pigz -d/unpigz decompress), so it should need no new mechanism — only a name in the set and a row
in the read-form table.

What this issue asks for

  1. Ground truth per verb first (the lz4 measurement above is the template), because the two
    families differ: an in-place twin can join _COMPRESSOR_VERBS and inherit the read gate, while a
    sibling-deriving verb needs to name its operand or its derived path, and a verb whose default form
    is a read must not be swept in at all.
  2. At least pigz/unpigz — the same shape as the family already fixed, one name and one row.
  3. If a verb's semantics cannot be settled cheaply, pin it as a measured hole in
    tests/test_bash_tool_option_destinations.py::UNCOVERED_WRITERS (the list that exists exactly for
    this), so the next reader finds it stated rather than inferred.
  4. A test row per verb added, in the two directions emrg: the compressors rewrite their operand, so the sandbox names it #1418 already establishes: the write form names
    its operand and is refused at both tiers, and the read form (-c, -t, -l, -dc) names nothing
    and stays allowed. No test may start, stop or restart a daemon, and the protected path may only be
    an input to a pure predicate.

Nothing here is a defect in #1418's own claim: the PR covers the verbs it names, and the verbs it
covers were verified independently (every write form for them went ALLOW → BLOCK at both tiers, every
read form stayed ALLOW). This is the boundary of the enumeration, filed so it is stated rather than
rediscovered.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions