Repository navigation
test: split test_denied_commands_security.py by behaviour (2 of 2) - #21968
Conversation
Sensitive change review
|
Sensitive Change ReviewSensitive files changed:
|
UX Review (Opus 5.5) — ⏭️ skippedRevision |
First Principles Review (Opus 5.5) — ✅ PASSPremise-level review of First-Principles-Verdict: PASS Confirm that the five new What this change shipsInventory (6 items) — 6 justifiedIntent: bring
[FIRST-PRINCIPLES-REVIEWED] fe1c174 Description read[DESCRIPTION-READ] bb5f5d4ba83812f06bb7a202753e3bfb0812171eb23082a09e99678663d7e7b3 That sha256 names the PR description this verdict read. Recompute it with |
Design Review (Opus 5.5) — ✅ PASSDesign-level review of Design-Verdict: PASS Nothing to check. [DESIGN-REVIEWED] fe1c174 Description read[DESCRIPTION-READ] fa88395f3f9092bf3166b474a22f1d1db160dd807353f6f645d351e628d014ba 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 |
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 change is a test-file split, not a stricter rule. The patch changes no file under ADJUDICATED: 14 candidates, 0 confirmed newly-refused. The harness returned no confirmed rows. The candidates target the area whose tests moved: local pytest runs of the new PLATFORM COVERAGE: The diff makes no new assumption about paths, separators, argv shape, interpreter, executable name or environment variables, because no matcher changes. I still wrote spellings for two platforms:
There are no [SCOPE-REVIEWED] fe1c174 |
8529a0c to
dae53e9
Compare
test/test_denied_commands_security.py was still 6,549 lines after the first PR of this series. This second PR moves everything after TestIsDeniedReDoSResistance into five new topic files (rows, mentions, kill, mint and stdin) and puts the remaining cost classes at the top of the existing cost part. The original keeps its header, the catalog, the resolver, the dual-tier matching and the ReDoS budget, at 1,560 lines, so its line-cap baseline row goes. Every test moves with an identical AST; only module docstrings 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, as in the first PR, and two citations name the files that now hold _CATASTROPHIC and TestSelfProtectionFloorIsAdditive.
dae53e9 to
fe1c174
Compare
|
Problem / Motivation
Goal: Finish bringing
test/test_denied_commands_security.pyunder the 2,000-line cap by behaviour under test, without changing a single test; this second PR moves the 4,990 lines the first PR left.After the first PR of this series (#21858) the file is still 6,549 lines, more than three times the cap the line-cap campaign enforces, and every deny-gate test added to it pushes it further past.
Why it matters
The maintainers' rule is that no hand-written file may exceed 2,000 lines. This PR finishes the split, so the file leaves the line-cap baseline and each deny family's tests can be found by file name and grow in a file of their own.
Not a goal
_costgains classes, inserted above its own.What changed (motivation → approach → change)
The original keeps its header and every class up to
TestIsDeniedReDoSResistance: the catalog and its count pin, flag interposition, row scoping, the resolver, dual-tier matching, gap splitting, user-pattern semantics and the ReDoS budget. Everything after it moves, by the same recipe as the first PR, into five new topic files, and the remaining cost classes go into the existing_costpart above its first class, in their BASE order. The shared helpers already live indenied_commands_security_helpers.py, so it does not change.test_denied_commands_security.py_rowsreverse-shell-nc, the dev-mode confirm flag, the recursive-forcermfloor_mentions_kill_mint_stdin_costGlue, the only lines whose AST or comments change:
_cost's docstring is rewritten to cover what it now holds. Every new file copiespytestmark = pytest.mark.usefixtures("fresh_darwin_libc_handles")with the family wording, so each test keeps the fixture set it had.# nosemgrep:/# flake-ok:comments sit above the moved semgrep and timing sites (listed under Move audit).golden-paths.json) gains onekind: testrow per new file, as in the first PR, which takes it from 64 to 69 rows (the size band's ceiling is 70 since test: split test_denied_commands_security.py by behaviour (1 of 2) #21858)..github/file-line-cap-baseline.txtis deleted, because the file is now under the cap.test_denied_rule_seam.py(_CATASTROPHIC, in_cost) anddocs/system-specs/modules/security.md(TestSelfProtectionFloorIsAdditive, in_rows).Backwards compatibility
Compatible: test-only move. Every collected test keeps its class, name and parameters (the multiset is identical before and after), and 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 over the whole family (original + every part)(class, name, params)multiset is identicalpytest --fixtures-per-testat BASE vs HEADitem.iter_markers()) at BASE vs HEAD-n0) and HEAD's 1,371 node ids at-n0in a seeded shuffled orderrun_scoped_tests.plan: 39 files) + every reader ofgolden-paths.json+ the wait-discipline, darwin-libc and line-cap ratchets,-n 3(44 files)test/test_flake_pattern_ratchet.py(-n0, against the merge-base)--baseline-commit <BASE>) over the changed.pyfiles--disable-nosemexactly the one moved BASE finding, marked in its new homeverify_test_split.pyMove audit
Every test function, method and helper moved with an identical AST;
verify_test_split.pyfinds every BASE unit unchanged at HEAD.git diff BASE...HEADis 530,923 bytes.Moved sites with an own-line marker (the bodies are unchanged):
kirocrew.test-autouse-shared-monkeypatch(marker between decorator anddef):TestReverseShellNcIsCommandTokenAnchored._remote_rsync_targets_are_not_this_host(_rows).# flake-ok:only: the three 5 s ReDoS-budget ceilings ofTestUserRegexReDoSGateand the 0.5 s backstop ofTestSelfModuleIndexIsLinear(_cost), and the 0.2 s backstop ofTestPythonStdinDetectorStepsOverOutputRedirects(_stdin).No credential-shaped literal, PEM header, internal host, home path or internal ticket id is on any added line.
Diff alignment (L36): for every changed file,
git diff BASE -- <file>andgit diff --minimal BASE -- <file>add and delete the same lines: the original 1/4990,_cost874/3 (its docstring and imports), every new file, the row edits and the citations match too.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 new part file (test/test_denied_commands_security_{rows,mentions,kill,mint,stdin}.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 64 to 69 rows, inside the band's ceiling of 70..github/file-line-cap-baseline.txt: the row11203 test/test_denied_commands_security.pyis deleted (the file is 1,560 lines).Citations
test/test_denied_rule_seam.py:123:_CATASTROPHICand the ReDoS budget →test_denied_commands_security_cost.py.docs/system-specs/modules/security.md:test_denied_commands_security.py::TestSelfProtectionFloorIsAdditive→test_denied_commands_security_rows.py::TestSelfProtectionFloorIsAdditive.TestCatalogstays), the count-assertion and pin-style references intest_cli_commands_coverage_agent_security.pyandtest_spawn_admission_verdict_census.py,security/denied_rules.py's pointer to the ReDoS tests (TestIsDeniedReDoSResistancestays); class-name citations 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: ...)