Repository navigation
fix(periodic-report): reject native, UNC and escaped Windows private paths in the run core - #6362
JasonBuildAI wants to merge 2 commits into
Conversation
…paths in the run core The run-request core is the gate for the periodic-report capability, and its private-path rule recognized only the POSIX spelling of the private roots. The same path written the way a Windows host or a serialized string spells it (C:\Users\<name>\..., \\server\Users\<name>\..., the rooted \Users\<name>\..., and the escaped C:\\Users\\<name>\\...) was accepted into the run identity and echoed in the composed packet while the POSIX spelling was refused, contrary to the protocol's documented "rejects ... private paths" contract. Match a separator run at every junction of the same private roots, the class the boundary scan (loopx-project#6161) and the public-safe-outbound scanner (loopx-project#6223) already reject. Paths outside the private roots, and URLs, stay acceptable; the native, UNC, rooted and escaped spellings plus the CLI refusal path are pinned by tests. Closes loopx-project#6358 Signed-off-by: JasonBuildAI <jasonbuildai@gmail.com>
…#6362 Signed-off-by: JasonBuildAI <jasonbuildai@gmail.com>
…r runs An independent review of the first commit measured the leading separator-run quantifier retrying every start position inside a long non-root run, and the raw-value scan runs before field length validation, so a request carrying tens of kilobytes of separators stalled compose-run (32,768 backslashes: 9.1 s through the builder). A single leading separator is acceptance-identical (the engine can start at the last separator of a run; 200,000-case fuzz: 0 verdict differences and 0 loosening) and scans linearly (65,536 separators: 0.0013 s). A bounded regression test pins it, and the Windows spellings of the inner var/folders and private/tmp junctions get explicit cases. Signed-off-by: JasonBuildAI <jasonbuildai@gmail.com>
|
This pull request has merge conflicts with Choose the remote for the base repository, not an out-of-date fork. git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEADFor a same-repository clone whose Keep the DCO |
|
Closing as superseded: #6363 (merged at 09:26Z, closes #6358) already landed this fix on Verified before closing:
The only difference is where the explanatory comment sits (above the assignment here, inside the
No action requested. If something specific from this branch should be kept (for example its separate wall-clock bounded test), say so and I can open a small follow-up against current |
Goal And Delivered Outcome
Outcome basis / optional anchor: [Bug]: periodic-report run core rejects POSIX private paths but not the native Windows spelling #6358;
docs/reference/protocols/periodic-report-v0.md("The core rejects raw content, messages, logs, transcripts, credentials, secret fields, and private paths."); same spelling class as merged fix(contract): block native, mixed and escaped Windows private paths in the boundary scan #6161 and fix(capability): detect native and escaped Windows private paths in public-safe-outbound #6223.Goal/source and gap: the periodic-report run-request core (
loopx/capabilities/periodic_report/core.py) refused the POSIX spelling of a private path but accepted the same path spelled the way a Windows host or a serialized string writes it: native drive (C:\Users\<name>\...), UNC (\\server\Users\<name>\...), rooted native (\Users\<name>\...) and the escaped form (C:\\Users\\<name>\\...,\\\\server\\Users\\<name>\\...). A Windows operator's private reference was accepted into the run and echoed in the composed packet while its POSIX spelling was refused, so the documented "core rejects ... private paths" contract held only for one spelling.Observable before → after, with the validation row that proves it: before,
build_periodic_report_runreturned aperiodic_report_v0packet for the native drive spelling andloopx periodic-report compose-runexited 0 with"ok": true; after, every native, UNC, rooted and escaped spelling of the same private roots raises "contains a private path or credential-like value" and the CLI exits 1 withperiodic_report_error_v0. Proven by the probe matrix and theregression_parity/real_entrypointrows.Issue/task and intended base: Closes [Bug]: periodic-report run core rejects POSIX private paths but not the native Windows spelling #6358. Base:
main.Author Declaration
Implemented against
docs/reference/protocols/periodic-report-v0.mdat b0b2acf; successor context from merged fix(contract): block native, mixed and escaped Windows private paths in the boundary scan #6161 / fix(capability): detect native and escaped Windows private paths in public-safe-outbound #6223 (same spelling class, adjacent owners).loopx/capabilities/periodic_report/core.py(_LOCAL_PATH_SURFACE_PATTERN,_reject_raw_keys)tests/capabilities/test_periodic_report.py::test_private_path_spelling_variants_are_rejectedloopx/capabilities/periodic_report/cli.py(compose-run)...::test_periodic_report_cli_refuses_native_windows_private_path...::test_public_windows_paths_and_urls_stay_accepted...::test_long_separator_run_stays_boundedhttps://URLs and clean tokens already accepted), then re-ran the same probe after the change (0 mismatches). An independent review of the first head measured that the initial leading separator-run quantifier could rescan long non-root runs quadratically (32,768 backslashes: 9.1 s through the builder, and the raw-value scan runs before field length validation); the lead is now a single separator, acceptance-identical (a 200,000-case fuzz over separator/root-heavy strings shows 0 verdict differences between the two lead forms and 0 loosening against the pre-change rule) and linear (65,536 separators: 0.0013 s; the same request now fails the length check in 0.016 s), pinned by a bounded regression test. Also ran the changed test file, the periodic-report family with a baseline/head failure-set comparison, CI-scope ruff, mypy, the semantic inventory advisory,loopx check, andloopx canary premerge. Deliberately left out: the other POSIX-only copies of this pattern (loopx/chat_action_store.py,loopx/registry.py) and a migration ontoloopx/public_safe_text.py, because the shared owner's lookbehind deliberately drops spellings this surface refuses today (x/Users/...,//Users/...) and its drive arm refuses paths outside the private roots; consolidation is owned by [Architecture]: two modules both claim to own "private-looking text" #5136, not by this fix.Scope And Continuation
Validation
staticpassedpython -m ruff check tests loopx/canary loopx/control_plane loopx/domain_packs loopx/presentation(CI scope): all checks passed;python -m ruff check loopx/capabilities/periodic_report/core.py tests/capabilities/test_periodic_report.py: all checks passedunitpassedpython -m pytest -q tests/capabilities/test_periodic_report.py: 29 passed (includes the four new tests); adjacent subset (_adapters,_profile,_audience,_triggers,_bindings, CLI capability chain): 72 passedregression_paritypassedregression_paritypassedModuleNotFoundError: No module named 'tzdata'on this Windows checkout without thetzdatawheel); baseline vs head run of the five failing files gives byte-identical sortedFAILEDsets (80 vs 80) and identical pass counts (34), so no verdict changedreal_entrypointpassed"ok": true; after: exit 1,periodic_report_error_v0with "contains a private path or credential-like value"; POSIX control case refused in both runsmanualpassedloopx check --scan-path <both changed files>: public boundary scan clean, errors 0, warnings 0;loopx canary premerge --from-git-diff: passed, merge gate passed, self-merge not authorized;python scripts/generate_semantic_inventory.py --changed-from HEAD: no supported new vocabulary carriers;python -m mypy: one pre-existing Windows-onlyos.WNOHANGerror in the untouchedloopx/control_plane/effect_runtime.py, changed files are outside the checked list\\?\prefixes and drive-relativeC:Users\...spellings, which ordinary hosts do not produce, and the same-pattern copies listed above.Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
Boundary Checklist
.loopx/,.codex/goals/, and liveACTIVE_GOAL_STATE.md).none.Signed-off-bytrailer (git commit -s).