Skip to content

Stop the structure gate from importing untracked sibling modules #49

Description

@ckrough

Follow-up to #41 (PR #48), which narrowed Stage C discovery to tracked paths. Discovery is narrowed; the execution context is not.

Problem

scripts/gates/structure.sh runs each suite as ( cd "$dir" && python3 -m unittest "$mod" ). python3 -m puts the current working directory at the front of sys.path, so every .py file in the suite directory is importable, tracked or not. A name shadowing a stdlib module, or any module the tracked suite imports, is imported before the real one.

Confirmed empirically during the #41 security review: a tracked plug/skills/demo/scripts/test_demo.py containing import json, plus an untracked plug/skills/demo/scripts/json.py whose first module-level statement writes a sentinel. The untracked file executed, the gate printed PASS python suite and exited 0, and no refusal fired, because the file never matched the test_*.py glob.

The tracked-path control constrains which files are named for execution. It does not constrain what those files import.

Why this is worth fixing

Same threat model as #41: the gate is the test binding in .daedalus/config.json, so an implementer subagent writing <plugin>/skills/<skill>/scripts/os.py into a worktree gets it executed on the next gate run, unstaged and unreviewed. This vector is easier than the one #41 closed, since the payload needs no test_ prefix.

Acceptance Criteria

  • An untracked .py sibling of a tracked suite that shadows a stdlib or imported module does not execute when the gate runs.
  • A gate self-test covers it, asserting a module-level sentinel is never written (the pattern case_untracked_python_refused established in Stop the structure gate from executing untracked test files #41).
  • The tracked suite still runs and still imports its own legitimate helpers.
  • The Discovery rule header paragraph in structure.sh describes the execution-context control alongside the discovery control.

Notes

Candidates: python3 -P (3.11+), python3 -I, PYTHONSAFEPATH=1, an explicit PYTHONPATH with an isolated interpreter, or executing from a clean checkout of the index (git archive / git worktree). The last also closes the related gap that --cached selects paths while the interpreter reads working-tree content, so unstaged edits to a tracked suite still execute.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions