Repository navigation
test: split test_denied_commands_security.py by behaviour (1 of 2) - #21858
Conversation
test/test_denied_commands_security.py was 11,435 lines, more than five times the 2,000-line cap. This first of two PRs moves the contiguous run from TestDenyMatchingIsQuoteNormalized through TestHostsFileWarmUp into five topic files: quoting, cost, ssh_self, own_host and hosts_file. The module autouse fixture, the packet-less probe socket, the captured real functions and the guarded literals move to the non-test denied_commands_security_helpers.py, which every file imports by name. The original keeps its header, everything before that class and the new recursive-force rm floor tests at its end (6,549 lines); the second PR moves the rest. TestSandboxEscapeSshSelf was 1,806 lines, so it is cut into two topic classes: TestSandboxEscapeSshSelf keeps how the floor reads an ssh-family command line, and TestSandboxEscapeSshSelfOwnHost takes which hosts count as this machine. Both carry _RULE and the class autouse _pin_own_host_cache, so every test runs under the same pin. Every test moves with an identical AST; only docstrings, comments and own-line markers change. The collected tests, their fixtures and their markers are identical before and after. The security-conductor corpus gains one test row per new file, so the deny fence's assertions stay in it, and its size band admits them. The wait-discipline row follows its two waits, and one docstring cite names the file that now polls the own-host warm task set.
Sensitive change review
|
Sensitive Change ReviewSensitive files changed:
|
UX Review (Opus 5.5) — ⏭️ skippedRevision |
Design Review (Opus 5.5) — ✅ PASSDesign-level review of Design-Verdict: PASS Before merge, check that [DESIGN-REVIEWED] e36a1b7 Description read[DESCRIPTION-READ] c76563d4dcdc8909668d0c748eefefbd216db43ab7f19b37c759ce68e1dda95c That sha256 names everything this verdict read: the PR description, plus the 1 evidence file(s) the workflow collected from it and handed this review. It covers that evidence because the media strip replaces every attachment URL with the same placeholder, so an edit swapping one attachment for another would leave the description's captured text identical while what this review judged changed. Recompute it with |
First Principles Review (Opus 5.5) — 🟡 CONCERNSPremise-level review of First-Principles-Verdict: CONCERNS Splitting Not justified as shipped
What this change shipsInventory (6 items) — 5 justifiedIntent: bring an 11,435-line deny-fence test file toward the 2,000-line cap without changing any test. This is an ADDITION (a refactor that only moves code).
[FIRST-PRINCIPLES-REVIEWED] e36a1b7 Description read[DESCRIPTION-READ] 31ff4e88c66bd5d794b6c89a759fdfcb339685c95cfe0fac3244db6dd957732d That sha256 names the PR description this verdict read. Recompute it with |
Opus 5.5 Review — ✅ no blocking findingsReviewed Verdict parsed from the review's SHA-scoped output markers for commit False positive or not applicable? A repository writer can comment: |
GPT 6.1 Review — ✅ no blocking findingsGPT 6.1 completed its review of This comment is updated in place on each push. Review detailsNo findings. False positive or not applicable? A repository writer can comment: |
Security Scope Review -- ✅ PASSWhich legitimate operations does Verdict basis: adjudicated, zero confirmed regressions. Security scope review -- adjudicated candidates
No candidate flipped from allowed to refused. Scope-Verdict: PASS TIGHTENING: none -- this diff doesn't make any guard stricter. The only non-test file it changes is the corpus, which gets six new ADJUDICATED: 9 candidates written; the harness returned no confirmed newly-refused rows. PLATFORM COVERAGE: Rows cover posix, windows and any. The diff adds no new path, separator, interpreter or environment-variable logic to any guard. The candidates check that the maintainers' daily commands on the moved test files still pass the gate in both host spellings:
These rows are aimed at the new file names that contain gate-sensitive words ( [SCOPE-REVIEWED] e36a1b7 |
|
|
mbriones98
left a comment
There was a problem hiding this comment.
Checks green and readiness passed at e36a1b7; no behavior change.
Problem / Motivation
Goal: Bring
test/test_denied_commands_security.py(11,435 lines) under the 2,000-line cap by behaviour under test, in two PRs, without changing a single test; this first PR moves its last 4,800 lines.The file is more than five times the size the line-cap campaign allows. A file that large is hard to navigate and review, and each PR that adds a deny-gate test to it pushes it further past the cap.
Why it matters
The maintainers' rule is that no hand-written file may exceed 2,000 lines. This file breaks it today, and every new deny-gate test makes the split bigger. Splitting it by behaviour gives each topic a file of its own that can grow, and makes a deny family's tests findable by file name.
Not a goal
What changed (motivation → approach → change)
The original keeps its header and every class before
TestDenyMatchingIsQuoteNormalized; the contiguous run from that class throughTestHostsFileWarmUpmoves into five topic files.TestRecursiveForceRmFloor, which main appended after it, stays in the original until PR 2. The module autouse fixture, the packet-less probe socket, the two captured real functions and the guarded-literal block (_K..Q,_rule_pattern,_denied_by) move to a non-testdenied_commands_security_helpers.py, which every file imports by name. A recipe tool did the move from BASE, so it re-runs after a rebase instead of being hand-merged.TestSandboxEscapeSshSelfwas 1,806 lines, more than the 1,600 a file may hold, so it is cut into two topic classes.TestSandboxEscapeSshSelfkeeps its name, its docstring and every test of how the floor reads an ssh-family command line;TestSandboxEscapeSshSelfOwnHosttakes the tests of which hosts count as this machine. Both carry the class constant_RULEand the class autouse fixture_pin_own_host_cache, so every test still runs under the same pin.test_denied_commands_security.py_quoting_cost_ssh_selfTestSandboxEscapeSshSelf: the rule on both tiers, its note, destinations through quoting, options,user@, globs and expansions_own_hostTestSandboxEscapeSshSelfOwnHost(interface seed, netlink publish, resolver worker and warm-up, DNS-alias verdicts, dotless names) andTestHostAddressesPlatformReaders_hosts_filedenied_commands_security_helpers.py_own_address_probe_stays_local,_PacketlessProbeSocket,_REAL_RESOLVED_HOST_VERDICT,_REAL_SCHEDULE_HOSTS_WARM, the guarded literals,_rule_pattern,_denied_byThe helpers module is under 150 lines because it holds only the module autouse fixture every file must import and the helpers two or more files read.
Glue, the only lines whose AST or comments change:
pytestmarkcomment takes the family wording, since no test left in it patchesctypes.CDLL.pytestmark = pytest.mark.usefixtures("fresh_darwin_libc_handles"), so each test keeps the fixture set it had;_own_host(which patchesctypes.CDLL) keeps the BASE comment, the others say every test of the family resets the caches.TestSandboxEscapeSshSelfOwnHosthas a new class docstring; inTestSandboxEscapeSshSelf's copy of_pin_own_host_cache, the three comments that said "the ... tests below" nameTestSandboxEscapeSshSelfOwnHostinstead (comments only, AST identical).TestDeniedReasonNotes' docstring and one comment in it, which pointed at a_denied_by"above" and "every id-based assertion in this file"; one quoting docstring that pointed at "the asymmetry this file already documents" now namesTestNameAsDataIsNotAnInvocation.# nosemgrep:/# flake-ok:comments sit above the moved semgrep and timing sites (listed under Move audit).golden-paths.json) gains onekind: testrow per new part file, with the same surface, platform and reason as the original's row plus "(part of the split test_denied_commands_security.py)". The original row stays, since the original still holds deny-fence assertions. That puts the corpus at 64 rows (69 after PR 2), soTestTheShippedCorpusIsALiveGate's size band moves its ceiling from 60 to 70, with one sentence on why. The band still rejects a stub or an unreviewed dump.test/wait_discipline_baseline.txt: the row's two waits are the gateway-startup polls now in_own_host, so the row moves there (2 → 2).test/test_dashboard_server_composition_contract.py:432: the docstring naming the module that polls_OWN_HOST_WARM_TASKSnow namestest_denied_commands_security_own_host.Backwards compatibility
Compatible: test-only move. Every collected test keeps its name and parameters; the one class split shows as a new class name for the tests it took (
TestSandboxEscapeSshSelfOwnHost::<same test>). Every test sees the same fixtures and markers. No test file imports from the origin, and no production code, import path, patch target or CLI changes.Removes nothing: every test, fixture and helper still exists, moved with an identical AST. The corpus only gains rows.
Tests
No test was added or rewritten. These proofs show the move lost nothing:
pytest --collect-onlyat BASE vs HEAD (original + 5 parts)(class, name, params)multiset is identical withTestSandboxEscapeSshSelfOwnHostmapped back toTestSandboxEscapeSshSelfpytest --fixtures-per-testat BASE vs HEADitem.iter_markers()) at BASE vs HEAD-n0, HEAD at-n 3, and HEAD's 1,371 node ids at-n0in a seeded shuffled order (seed 20261017)run_scoped_tests.plan: 10 files) + every corpus gateleaf_test_scope.corpus_gates()derives (543 files) + every test that scans the tree throughsource_corpus+ every reader ofgolden-paths.json+ the wait-discipline, darwin-libc and line-cap ratchets,-n 3(604 files, at an earlier base)test/test_flake_pattern_ratchet.py(-n0, against the merge-base)--baseline-commit <BASE>) over the changed.pyfiles--disable-nosemexactly the 5 moved BASE findings, each marked in its new home, plus the kept one in the original_own_hostwithout the libc reset request each turn their guard redscripts/local-gate.py --base <BASE> --dry-run: backend related set 10 test files (7 in the diff, 3 referencing a changed file), all inside the run above; frontend 372 files, all from the cross-surface set (nowebsite/file changes).Move audit
Every other test function, method and helper moved with an identical AST. Both copies of
_pin_own_host_cacheare AST-identical to BASE (their comments name the sibling class where BASE said "this class's" or "below").git diff BASE...HEADis 535,637 bytes.Moved sites with an own-line marker (the bodies are unchanged):
kirocrew.test-autouse-shared-monkeypatch(marker between decorator anddef):_own_address_probe_stays_local(helpers), both copies of_pin_own_host_cache(_ssh_self,_own_host),TestHostsFileWarmUp._isolate(_hosts_file).kirocrew.test-bare-monkeypatch-undo: the per-targetmonkeypatch.undo()intest_view_construction_never_raises(_quoting).kirocrew.test-stdlib-clock-rebound+# flake-ok:: the frozen_argv_floor.time.monotonicintest_negative_dns_verdict_is_revalidated_after_ttl(_own_host); the rule is newer than the code, so the move is its first sight of it.# flake-ok:only: the 1 s wall-clock ceilings in_quotingand_cost, the two bounded 10 ms startup polls and the 0.5 s ceiling against a 5 s hold in_own_host, and the 10 ms step of_poll_untilin_own_host.No credential-shaped literal, PEM header, internal host or internal ticket id is on any added line; the only home path is the
/home/xplaceholder of the empty-word tests.Diff alignment (L36): for every changed file,
git diff BASE -- <file>andgit diff --minimal BASE -- <file>add and delete the same lines; the original is 22/4908 (docstring, import and comment glue only).Logger names (L25): no new module defines a logger.
Path-list edits (L14)
src/kiro_crew/builtin_skills/security-conductor/golden-paths.json: fivekind: testrows, one per part file (test/test_denied_commands_security_{quoting,cost,ssh_self,own_host,hosts_file}.py), surface "S1 bash classifier fence", platformany, the original row's reason plus "(part of the split test_denied_commands_security.py)". The corpus goes from 59 to 64 rows; PR 2 adds five more (69).test/test_security_conductor_verify_fix.py:1047: the corpus size band's ceiling 60 → 70, so it admits 64 now and 69 after PR 2; the comment gains one sentence on why. A test row takes one pytest selector, so the rows cannot be folded together.test/wait_discipline_baseline.txt:2 test_denied_commands_security.py→2 test_denied_commands_security_own_host.py.Citations
test/test_dashboard_server_composition_contract.py:432: the module that polls_OWN_HOST_WARM_TASKS→test_denied_commands_security_own_host.TestCatalogstays), the count-assertion and pin-style references intest_cli_commands_coverage_agent_security.pyandtest_spawn_admission_verdict_census.py,test_denied_rule_seam.py's_CATASTROPHICpointer andsecurity/denied_rules.py's ReDoS-tests pointer (both classes stay in PR 1), anddocs/system-specs/modules/security.md'sTestSelfProtectionFloorIsAdditivepointer (stays in PR 1); class-name citations of moved classes keep resolving because the class names are unchanged.CI path references
None: no workflow filter, explicit file list,
AUTOSDE.yamlglob or sensitive-change glob names this file.Manual verification
N/A: unit coverage is sufficient. This is a test-only move, and the collected-test multiset plus the run of every moved test prove it.
Related Issues
Part of #20192
Follow-up: #20383 (pre-existing shapes moved verbatim; de-flake there)
Checklist
feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert: ...)