Skip to content

yaml: missing "cleanup" rule — shell-embedded teardown verbs (rm -rf <path>, docker rm/down, kill) inside run:/script: blocks uncaptured #2647

Closed

Description

@squid-protocol

yaml.py's cleanup rule is None. GitLab's after_script: is correctly excluded (already lands in func_start as an executable-logic anchor, confirmed by existing test coverage — no change needed there; a dedicated cleanup rule over it would double-count, same rejection shape as jcl's DISP=(...,DELETE) in #2610). But ordinary shell-level resource teardown embedded in run:/script: content — rm -rf <non-root-path>, docker rm/docker stop, docker-compose down/docker compose down, bare kill <pid> — matches no current rule: high_risk_execution's rm -rf is deliberately root-only (asserted in test_yaml_strict.py L63/193), io only catches install verbs, panics_and_aborts's kill only catches the signal-numbered form. yaml's own philosophy (per corpus notes) is that shell embedded in run:/script: counts like code (branch/io/high_risk_execution all reach into it), so teardown verbs there being invisible is an inconsistency, not a design choice.

Fix shape (illustrative): re.compile(r"\brm[ \t]+-rf?[ \t]+(?!/(?:[ \t]|$))\S{1,200}\b|\bdocker(?:-compose)?[ \t]+(?:rm|stop|down)\b|\bkill[ \t]+(?!-[0-9])\S{1,64}\b", re.I) — needs ReDoS/boundary review and overlap re-check against panics_and_aborts/high_risk_execution before landing.

Found by the #1096/#2560 rosetta n/a review sweep.

Activity

  1. added
    enhancementNew feature, sensor, or structural signature
    core-engineModifications to the central physics and parsing engine
    on Sep 2, 2026
  2. squid-protocol commented on Sep 4, 2026

    @squid-protocol
    OwnerAuthor

    Already shipped — closing as done. The rule landed in #2681 ("Rosetta batch 3 wave 2 — doc-comment pairing, rule over-claims, three None rules"), which only listed closes #2672, so this stayed open.

    yaml.py's cleanup is no longer None, and the shipped shape is this issue's proposal with one improvement:

    "cleanup": re.compile(
        r"\brm[ \t]+-rf?[ \t]+(?!/(?:[^A-Za-z]|$))\S{1,200}\b"
        r"|\bdocker(?:[ \t]+compose|-compose)?[ \t]+(?:rm|stop|down)\b"
        r"|\bkill[ \t]+(?!-[0-9])\S{1,64}\b",
        re.M | re.I,
    ),

    Two deltas from the illustrative shape here, both tightening it: the docker alternative also accepts the space form docker compose down (the proposal only had docker-compose), and the rm -rf root guard is (?!/(?:[^A-Za-z]|$)) rather than (?!/(?:[ \t]|$)), so rm -rf / followed by anything non-alphabetic is still left to high_risk_execution instead of leaking into cleanup.

    Verified end to end against engine main (538ef8a):

    • Overlap re-check, which this issue asked for, is settled in the rule's own comment: after_script: stays with func_start (no double-count), and the rule keys off the shell verb rather than the block keyword, so teardown inside run:/script: double-counts with branch/io exactly the way this language's documented philosophy already has shell-in-yaml behave. high_risk_execution's root-only rm -rf / and panics_and_aborts' signal-numbered kill -9 are both preserved — test_yaml_strict.py L63/193 still assert them, and the simple-case table pins run: rm -rf /tmp/build-cache positive against run: rm -rf / negative.
    • Corpus pairing: keyword-rosetta's c.yml plants run: 'rm -rf /tmp/build-artifact' and run: 'docker compose down'. verify_language.py yaml → PASS, 76 assertions across 4 files.
    • Band: the cleanup cell is yaml=2 against a corpus median of 2 — +0%, green. No new red cell manufactured.
    • 122 yaml tests pass, including the ReDoS sweep.

    Same caveat as #2646, and it matters more here because the alternation is broader: no real-world file in the golden master exercises this rule. language-crucible's yaml corpus is 8 Ansible task files with no CI workflow, compose file or teardown verb in them, so a regression in this alternation would not be caught by crucible-audit. Filed as squid-protocol/language-crucible#23.

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

    core-engineModifications to the central physics and parsing engineenhancementNew feature, sensor, or structural signature

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions