diff --git a/.github/workflows/trusted-uv-materializer-quality-ci.yml b/.github/workflows/trusted-uv-materializer-quality-ci.yml index ea78c30cc7..5edb0dda18 100644 --- a/.github/workflows/trusted-uv-materializer-quality-ci.yml +++ b/.github/workflows/trusted-uv-materializer-quality-ci.yml @@ -2,16 +2,15 @@ name: Trusted uv Materializer Quality CI on: pull_request: + branches: [main] paths: - ".github/workflows/trusted-uv-materializer-quality-ci.yml" - "scripts/ci/materialize_base_python_requirements.py" - - "scripts/ci/verify_release_maturin_tool_assets.py" - "tests/conftest.py" - "tests/test_materialize*.py" - "tests/test_trusted_uv*.py" - "tests/test_uv*.py" - "tests/test_repository_branch_coverage_*.py" - - "tests/test_verify_release_maturin_tool_assets.py" - "requirements-opencode-review-ci.txt" - "requirements-noema-document-ci.txt" - "requirements-opencode-review-ci-hashes.txt" @@ -22,13 +21,11 @@ on: paths: - ".github/workflows/trusted-uv-materializer-quality-ci.yml" - "scripts/ci/materialize_base_python_requirements.py" - - "scripts/ci/verify_release_maturin_tool_assets.py" - "tests/conftest.py" - "tests/test_materialize*.py" - "tests/test_trusted_uv*.py" - "tests/test_uv*.py" - "tests/test_repository_branch_coverage_*.py" - - "tests/test_verify_release_maturin_tool_assets.py" - "requirements-opencode-review-ci.txt" - "requirements-noema-document-ci.txt" - "requirements-opencode-review-ci-hashes.txt" diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e8dfc577..7977c970bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,52 @@ -### Maturin download failures close every transport response - -- Refactor the bounded Maturin asset downloader so successful and rejected - responses share one unconditional close path while `HTTPError` keeps its own - explicit close path. A new regression exercises a non-200 response and an - opener-raised HTTP error. This removes an impossible optional-response branch - without changing hosts, redirects, byte limits, hashes, or fail-closed error - mapping; the focused suite is 17 passed with 100% statement and branch - coverage. The trusted full-suite workflow now also tracks the verifier source - and its focused test, so a future lifecycle change cannot omit the repository - coverage gate that detected this regression. The pull-request trigger admits - stacked canonical-owner bases as well as `main`; the protected-branch push - trigger remains restricted to `main`. +### OpenCode invalid-token wrappers remain fail-closed + +- Treat a balanced object or array whose first token is invalid JSON as one + outer evidence container instead of skipping its opener and promoting a + nested exact-run control. RED commit + `b5a0507b8ee4ec70cc5fca751f34df98719f219b` binds `undefined`, arbitrary + unquoted array tokens, and unquoted object keys; GREEN commit + `443c29aa6f56735f7fcf0ee6a550b6bad5f7e2f8` preserves the proven prose + delimiter recovery while keeping balanced malformed wrappers fail-closed. + The production normalizer remains executable (`100755`). + +### OpenCode mixed-output framing preserves later controls + +- Ignore prose `{` or `[` delimiters whose next non-whitespace token cannot + start the corresponding JSON container. This preserves a later complete + exact-run control after diagnostics such as `Diagnostic: [pending` without + weakening the existing fail-closed rule for malformed outer objects or + arrays. RED commit `42099a359cdfb8126ea4e3d9118c60f6d98af1fa` + records the lost-control case; GREEN commit + `07baba20259c9061fbb647963f09745a9ca6931b` restores the framing boundary. + Fresh exact-head hosted Checks and a qualifying independent approval remain + required before ordinary merge. + +### OpenCode embedded JSON evidence is outermost and linear-time + +- Parse prose-wrapped JSON by scanning each outermost object or array once, + with string and escape awareness, instead of retrying `raw_decode` at every + nested `{`. A malformed outer container can no longer promote a nested + exact-run control object into top-level approval evidence, and adversarial + nested prefixes no longer cause quadratic decoding work. RED commit + `d05f67f6c5f164309d3cbf15f4858c5fa3d176cd` preserves the malformed-object + exploit; GREEN commit `86f52f320e8eb5ac56efdf9a3e2552b20bf409de` + replaces the retry loop, and `1a00c73a752b45d9d2a808d9bc96baae51ea8402` + extends the same invariant to malformed array nesting. Fresh exact-head + hosted Checks and a qualifying independent approval remain required before + ordinary merge. + +### OpenCode evidence labels require standalone identity boundaries + +- Reject a purported verification label when it is only the suffix of an + identifier-like token such as `uncoverage:`. The OpenCode normalizer now + applies the same boundary rule while selecting the last admissible label and + while finding the next label that terminates its section. RED commit + `af06cf9c87de4ac76db575d087a170746d6ab83d` proves that a forged suffix could + override an earlier fail-closed coverage statement; GREEN commit + `4d49b8307706ab8d4565cca8b0d9728bcdad2a35` preserves repeated labels, + Markdown decoration, and the distinct `docstring coverage:` label while + rejecting the identity-confused form. Fresh exact-head hosted Checks and a + qualifying independent approval remain required before ordinary merge. ### Shared Strix lock advances beyond the PyJWT recursion DoS diff --git a/docs/doctoring/maturin-download-response-lifecycle-20261001.md b/docs/doctoring/maturin-download-response-lifecycle-20261001.md deleted file mode 100644 index b6765daae8..0000000000 --- a/docs/doctoring/maturin-download-response-lifecycle-20261001.md +++ /dev/null @@ -1,44 +0,0 @@ -# Maturin download response-lifecycle RCA - -## Incident - -Trusted uv Materializer run `36811202519`, job `110206427182`, checked out -`.github#1653@5cd141ec2c33b631d164af936cd1c9de70e4c9a4`. All 5,314 tests passed, -but the complete repository gate reported 99% coverage. The only incomplete -owner was `scripts/ci/verify_release_maturin_tool_assets.py`: five statements -and two branches in its non-200 and `HTTPError` response paths. - -## Root cause and boundary - -The bounded downloader belongs to the central `.github#2530` successor, not -the #1653 label-taxonomy delta. Its nullable `response` finalizer encoded a -false branch that cannot fall through: when `opener.open()` raises, control -re-raises from the `HTTPError` handler before the code following the finalizer. -That made honest 100% branch evidence impossible even though successful -responses were closed. The Trusted uv workflow path filter also omitted this -verifier and its tests, so fixing the canonical owner would not itself request -the complete gate that originally exposed the defect downstream. After the -path repair, owner head `8cf2ea5f73976d47b2267fb52ac28284323404b7` -still produced no gate because the workflow admitted only PRs whose base was -`main`, while #2530 is correctly stacked on canonical owner #2531. - -## Repair - -The downloader now closes every returned response in one unconditional nested -`finally` block. An opener-raised `HTTPError` remains independently closed by -its handler. Tests assert closure for both an HTTP 503 response and an HTTP 502 -exception. A workflow contract now requires both verifier paths in pull-request -and protected-branch triggers, and a separate contract admits stacked PR bases -while the push trigger remains restricted to protected `main`. The repair does -not change admitted hosts, the one-hop redirect -contract, credentials, request timeout, byte bounds, digests, or error mapping. - -## Evidence and remaining gates - -- Hosted RED: 5,314 passed, 5 skipped, 40 subtests; 18,775 statements with 5 - missing, 7,652 branches with 2 partial; total 99%. -- Local owner GREEN: 17 focused tests; 107/107 statements and 34/34 branches; - `git diff --check` clean. -- Required before acceptance: complete exact-head hosted suite, security and - CodeQL verdicts, qualifying independent approval, ordinary owner integration, - then ordinary merge-forward into #1653 and fresh consumer Checks. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index b4882cee5a..2367002926 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,11 +1,5 @@ # Product and Technical Gap Baseline -## 2026-10-01 Maturin response-lifecycle coverage closure - -| Gap | Exact evidence | Action | Status | -|---|---|---|---| -| `.github#1653@5cd141ec2c33b631d164af936cd1c9de70e4c9a4` passed all 5,314 tests but failed the complete branch gate because the canonical Maturin downloader left five error-path statements and two branches unexecuted; the owner workflow omitted both verifier paths and stacked PR bases | Trusted uv Materializer run `36811202519`, job `110206427182`; `verify_release_maturin_tool_assets.py` 95%, missing lines 104 and 106-112 plus branch 114→116; no owner run at #2530 predecessor `8cf2ea5f73976d47b2267fb52ac28284323404b7` because its base was #2531 rather than `main` | Repair canonical successor `.github#2530`: exercise non-200 and opener-raised `HTTPError` closure, replace the impossible nullable-response finalizer with one unconditional response-owned close scope, add source/test and stacked-PR trigger contracts to the complete gate while retaining protected-main push scope, preserve all network and fail-closed boundaries, then ordinary-merge the accepted owner head into #1653 | **Proposed / hosted RED reproduced; focused verifier coverage GREEN locally; path and stacked-admission contracts RED→GREEN; exact-head hosted full-suite, security, CodeQL, and independent approval required** | - ## 2026-10-01 bounded Maturin release downloader SAST closure | Gap | Exact evidence | Action | Status | @@ -3725,3 +3719,125 @@ verdict-shape acceptance, and qualifying independent approval. **Gap / failure scene.** The v2 handler names a run with `head/base/required-run/producer-source`, but its required-workflow fallback looked up only `head/base/required-run`. When authenticated status publication is unavailable, a completed clean handler job could not be found and a rerun ended false RED. Omitting the producer source would also allow a regenerated live merge revision to reuse predecessor evidence. **Action / evidence.** Correct the fallback lookup to include the live merge source and retain fail-closed base, head, required-run, workflow-path, job-name, GHAS-identity, and SARIF checks. The test-first repair reproduced two failures, then passed 96 focused workflow-contract tests; the new edge case rejects a stale merge-source title. Ruff E9/F/I on the changed dispatch-contract file and `git diff --check` pass. Fresh hosted Checks and a qualifying independent approval are still required on the unchanged executable delta before merge. + +## 2026-10-01 OpenCode evidence-label identity boundary + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; fresh exact-head +hosted Checks and a qualifying independent approval remain mandatory. + +**Context Map / owner.** The central `.github` review-control bounded context +owns OpenCode response normalization and approval-evidence admission. OpenCode +is the untrusted evidence producer; repository review workflows consume only +the normalizer's fail-closed verdict contract. + +**Gap / RCA.** The optimized last-label search used an unconstrained +`rfind("coverage:")`. A response could state that real coverage evidence was +not measured, then append `uncoverage: ... 100%`; the suffix beginning inside +`uncoverage:` was accepted as a newer `coverage:` label. The false label could +therefore replace the genuine fail-closed section and make +`mentions_full_coverage` return true. The same missing identity boundary also +affected forward searches for the next section label. + +**RED → GREEN / action.** RED +`af06cf9c87de4ac76db575d087a170746d6ab83d` adds the durable suffix-forgery +case. GREEN `4d49b8307706ab8d4565cca8b0d9728bcdad2a35` rejects label occurrences whose +preceding character is alphanumeric, underscore, or hyphen in both backward +selection and forward section termination. It retains decorated Markdown +labels, repeated legitimate labels, and the separate `docstring coverage:` +rule. Local direct behavior cases, Python compilation, and `git diff --check` +are GREEN; the local environment has no pytest installation, so no full-suite +claim is made. Completion still requires hosted exact-head tests, terminal +required Checks, no unresolved actionable thread, qualifying independent +approval, and ordinary protected integration. + +## 2026-10-01 OpenCode outermost JSON evidence boundary + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; executable repair +and local focused verification are GREEN, while fresh exact-head hosted Checks +and a qualifying independent approval remain mandatory. + +**Context Map / owner.** The central `.github` review-control bounded context +owns OpenCode response normalization and exact-run evidence admission. The +model response is untrusted input; downstream required-review workflows may +consume only top-level controls accepted by this owner contract. + +**Gap / RCA.** Exact-head Strix run +[36794394865](https://github.com/ContextualWisdomLab/.github/actions/runs/36794394865) +reported repeated JSON decoding in `iter_json_objects`. Direct reproduction +confirmed two effects from the same retry-at-every-`{` loop: a malformed outer +object could promote its valid nested exact-run control into top-level evidence, +and doubling an unclosed nested prefix increased processing time by roughly +four times. The first effect is an identity-boundary false admission; the +second permits model-controlled quadratic work. + +**RED → GREEN / action.** RED +`d05f67f6c5f164309d3cbf15f4858c5fa3d176cd` records the malformed-object +promotion. GREEN `86f52f320e8eb5ac56efdf9a3e2552b20bf409de` +tracks one outermost container at a time, handles quoted strings and escapes, +and decodes only a completed outermost span. Follow-up test commit +`1a00c73a752b45d9d2a808d9bc96baae51ea8402` binds the same rule to malformed +array nesting. The existing embedded-object cases and both new adversarial +cases pass; Python compilation and `git diff --check` are GREEN. A direct +3,200-level measurement completed in 0.001236 seconds, while the prior +1,600-level case required 0.065367 seconds. These are local diagnostic values, +not a hosted performance claim. Pytest is unavailable in the local runner, so +the complete suite remains an exact-head hosted acceptance requirement. + + +## 2026-10-01 OpenCode mixed-output JSON framing boundary + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; executable +RED→GREEN complete, fresh exact-head hosted Checks and a qualifying independent +approval remain mandatory. + +**Context Map / owner.** The central `.github` review-control bounded context +owns mixed-output framing and exact-run evidence admission. OpenCode output is +untrusted: prose delimiters must not block a later complete top-level control, +while actual malformed outer containers must continue to suppress nested +controls. + +**Gap / RCA.** CodeRabbit review on prior exact head +`2ee8ddad072fe59bbe33c99994fa1e8c9cb5387c` showed that +`Diagnostic: [pending` was treated as an unclosed JSON array and hid a later +valid control. Direct reproduction showed the same regression for +`Diagnostic: {pending`. The outermost single-pass repair had dropped the +predecessor's candidate-start grammar gate. + +**RED → GREEN / action.** RED +`42099a359cdfb8126ea4e3d9118c60f6d98af1fa` binds both prose delimiters. +GREEN `07baba20259c9061fbb647963f09745a9ca6931b` admits an object start only +before `"` or `}`, and an array start only before a JSON value starter. +Existing malformed object/array nested-control cases remain fail-closed. +Direct focused cases 8/8, Python compilation, and `git diff --check` are GREEN; +pytest is unavailable locally, so the full hosted suite remains required. + + +## 2026-10-01 balanced invalid-token wrapper evidence boundary + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; executable +RED→GREEN is published, while fresh exact-head hosted Checks and a qualifying +independent approval remain mandatory. + +**Context Map / owner.** The central `.github` review-control bounded context +owns OpenCode mixed-output normalization and exact-run evidence admission. +OpenCode model output is untrusted. A nested control inside any balanced outer +container—including a syntactically invalid one—must never acquire top-level +identity. + +**Gap / RCA.** The candidate-start allowlist skipped balanced wrappers whose +first token was invalid JSON. Inputs such as `[undefined, {control}]`, +`[unquoted_token, {control}]`, and `{unquoted_key: {control}}` therefore +promoted the nested exact-run control. The earlier `NaN`/`Infinity` repair +covered Python JSON extensions but not the general invalid-token boundary. + +**RED → GREEN / action.** RED +`b5a0507b8ee4ec70cc5fca751f34df98719f219b` reproduces all three promotions. +GREEN `443c29aa6f56735f7fcf0ee6a550b6bad5f7e2f8` treats an invalid starter as a +malformed outer container when its token reaches a structural separator before +another opener; the proven unclosed prose-delimiter recovery remains intact. +Focused parser verification is 118/118 GREEN. Full repository verification +reached 5,318 passed, 7 skipped, and 40 subtests; its sole failure was the +published-commit ancestry test because the isolated `git archive` intentionally +has no `.git` directory. Warnings-fatal compilation and diff whitespace checks +are GREEN. Exact Git tree `dccb57a152c21600305c0eabac06cb29de2e0cf7` +preserves source mode `100755`. diff --git a/scripts/ci/opencode_review_normalize_output.py b/scripts/ci/opencode_review_normalize_output.py index 7ad4c2b431..5335875eb3 100755 --- a/scripts/ci/opencode_review_normalize_output.py +++ b/scripts/ci/opencode_review_normalize_output.py @@ -953,23 +953,25 @@ def mentions_verification_posture(reason: str, summary: str) -> bool: def label_section(text: str, label: str) -> str: - """Return text after a verification label until the next known label.""" - # ⚡ Bolt: Fast path starts using native find, avoiding nested O(N) regex evaluation - starts: list[int] = [] - index = text.find(label) + """Return text after the last admissible label until the next known label.""" + index = text.rfind(label) while index != -1: - if label == "coverage:" and text[max(0, index - 10) : index] == "docstring ": - index = text.find(label, index + len(label)) + if ( + (index > 0 and (text[index - 1].isalnum() or text[index - 1] in "_-")) + or ( + label == "coverage:" + and text[max(0, index - 10) : index] == "docstring " + ) + ): + index = text.rfind(label, 0, index) continue - starts.append(index) - index = text.find(label, index + len(label)) + break - if not starts: + if index == -1: return "" - start = starts[-1] + len(label) + start = index + len(label) end = len(text) - # ⚡ Bolt: Dynamically shrink the search window to prevent O(N) redundant scanning overhead for candidate in APPROVAL_VERIFICATION_LABELS: if candidate == label: continue @@ -977,8 +979,11 @@ def label_section(text: str, label: str) -> str: idx = text.find(candidate, start, end) while idx != -1: if ( - candidate == "coverage:" - and text[max(0, idx - 10) : idx] == "docstring " + (idx > 0 and (text[idx - 1].isalnum() or text[idx - 1] in "_-")) + or ( + candidate == "coverage:" + and text[max(0, idx - 10) : idx] == "docstring " + ) ): idx = text.find(candidate, idx + len(candidate), end) continue @@ -1443,7 +1448,6 @@ def reject(reason: str) -> None: def iter_json_objects(text: str) -> list[Any]: """Extract top-level JSON values without promoting nested control objects.""" - decoder = json.JSONDecoder() values: list[Any] = [] try: @@ -1453,26 +1457,59 @@ def iter_json_objects(text: str) -> list[Any]: # OpenCode exports may contain prose around the JSON control object. pass - index = 0 - while True: - index = text.find("{", index) - if index == -1: - break - next_index = index + 1 - while next_index < len(text) and text[next_index] in " \t\r\n": - next_index += 1 - if next_index < len(text) and text[next_index] not in {'"', "}"}: - index += 1 + start_index: int | None = None + container_stack: list[str] = [] + in_string = False + escaped = False + for index, character in enumerate(text): + if start_index is None: + if character not in "{[": + continue + next_index = index + 1 + while next_index < len(text) and text[next_index] in " \t\r\n": + next_index += 1 + if next_index == len(text): + continue + next_character = text[next_index] + valid_object_start = character == "{" and next_character in {'"', "}"} + valid_array_start = character == "[" and ( + next_character in '\"{[-0123456789]' + or any( + text.startswith(literal, next_index) + for literal in ("true", "false", "null", "NaN", "Infinity") + ) + ) + if not valid_object_start and not valid_array_start: + token_end = next_index + while token_end < len(text) and text[token_end] not in ",:]}{[": + token_end += 1 + if token_end == len(text) or text[token_end] in "{[": + continue + start_index = index + container_stack.append("}" if character == "{" else "]") continue - try: - value, new_index = decoder.raw_decode(text, index) - values.append(value) - # ⚡ Bolt: Advance index to avoid O(N^2) redundant parsing of nested JSON blocks - index = new_index + + if in_string: + if escaped: + escaped = False + elif character == "\\": + escaped = True + elif character == '"': + in_string = False continue - except json.JSONDecodeError: - pass - index += 1 + + if character == '"': + in_string = True + elif character in "{[": + container_stack.append("}" if character == "{" else "]") + elif container_stack and character == container_stack[-1]: + container_stack.pop() + if not container_stack: + try: + values.append(json.loads(text[start_index : index + 1])) + except json.JSONDecodeError: + pass + start_index = None return values diff --git a/scripts/ci/verify_release_maturin_tool_assets.py b/scripts/ci/verify_release_maturin_tool_assets.py index a59507ac83..b91e1b7469 100644 --- a/scripts/ci/verify_release_maturin_tool_assets.py +++ b/scripts/ci/verify_release_maturin_tool_assets.py @@ -97,16 +97,12 @@ def _download(filename: str) -> bytes: opener = urllib.request.build_opener( urllib.request.ProxyHandler({}), _ExactReleaseRedirect() ) + response = None try: response = opener.open(request, timeout=60) - try: - if response.status != 200: - raise ValueError( - f"maturin release download returned HTTP {response.status}" - ) - raw = response.read(MAX_ASSET_BYTES + 1) - finally: - response.close() + if response.status != 200: + raise ValueError(f"maturin release download returned HTTP {response.status}") + raw = response.read(MAX_ASSET_BYTES + 1) except urllib.error.HTTPError as error: try: raise ValueError( @@ -114,6 +110,9 @@ def _download(filename: str) -> bytes: ) from error finally: error.close() + finally: + if response is not None: + response.close() if len(raw) > MAX_ASSET_BYTES: raise ValueError("maturin release asset exceeds inspection limit") return raw diff --git a/tests/test_opencode_review_normalize_output.py b/tests/test_opencode_review_normalize_output.py index a24c541743..c9bb1e0a76 100644 --- a/tests/test_opencode_review_normalize_output.py +++ b/tests/test_opencode_review_normalize_output.py @@ -1367,6 +1367,29 @@ def test_material_changed_file_scope_rejects_false_documentation_typo_reason( assert check_structural_approval(path) == 4 +def test_label_section_uses_last_non_docstring_coverage_label() -> None: + """Ignore embedded docstring labels while selecting the last test label.""" + combined = ( + "coverage: stale evidence " + "docstring coverage: 100% documentation evidence " + "coverage: 100% current evidence " + "performance: measured" + ) + + assert norm.label_section(combined, "coverage:") == " 100% current evidence " + + +def test_coverage_label_rejects_identifier_suffix_override() -> None: + """Do not let an identifier suffix override failed coverage evidence.""" + combined = ( + "coverage: coverage execution evidence not measured\n" + "uncoverage: coverage execution evidence 100%\n" + "docstring coverage: coverage execution evidence 100%" + ) + + assert not norm.mentions_full_coverage(combined, "") + + def test_label_and_full_coverage_detection(tmp_path, monkeypatch): combined = FULL_SUMMARY.casefold() assert "100%" in norm.label_section(combined, "coverage:") @@ -1375,6 +1398,19 @@ def test_label_and_full_coverage_detection(tmp_path, monkeypatch): "performance: FAST docstring coverage: 100% something else coverage: 100%" ) assert norm.label_section(text_coverage, "performance:") == " FAST " + assert ( + norm.label_section( + "coverage: stale\ncoverage: current\nperformance: measured", "coverage:" + ) + == " current\n" + ) + assert ( + norm.label_section( + "coverage: direct\ndocstring coverage: docs\nperformance: measured", + "coverage:", + ) + == " direct\n" + ) assert norm.mentions_full_coverage("", FULL_SUMMARY) no_source_summary = FULL_SUMMARY.replace( "coverage execution evidence proves 100% test coverage", @@ -2482,6 +2518,80 @@ def test_iter_json_objects_extracts_raw_and_embedded_json(): assert norm.iter_json_objects("no json here") == [] +def test_iter_json_objects_skips_non_json_prose_delimiters(): + """Unclosed prose delimiters cannot hide a later complete control object.""" + control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + encoded_control = json.dumps(control) + + assert norm.iter_json_objects("Diagnostic: [pending\n" + encoded_control) == [ + control + ] + assert norm.iter_json_objects("Diagnostic: {pending\n" + encoded_control) == [ + control + ] + + +def test_iter_json_objects_does_not_promote_control_nested_in_malformed_outer(): + """A malformed outer container cannot promote nested control evidence.""" + nested_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + malformed_object = '{"outer":' * 2_000 + json.dumps(nested_control) + " trailing" + malformed_array = "[" * 2_000 + json.dumps(nested_control) + " trailing" + + assert norm.iter_json_objects(malformed_object) == [] + assert norm.iter_json_objects(malformed_array) == [] + + +@pytest.mark.parametrize("non_finite_value", ["NaN", "Infinity"]) +def test_iter_json_objects_does_not_promote_control_from_non_finite_array( + non_finite_value, +): + """Python JSON extensions cannot expose nested control evidence.""" + nested_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = f"review prose [{non_finite_value}, {json.dumps(nested_control)}]" + + values = norm.iter_json_objects(text) + + assert len(values) == 1 + assert isinstance(values[0], list) + assert values[0][1] == nested_control + + +@pytest.mark.parametrize( + "malformed_outer", + [ + "[undefined, ]", + "[unquoted_token, ]", + "{unquoted_key: }", + ], +) +def test_iter_json_objects_does_not_promote_control_from_invalid_outer_token( + malformed_outer, +): + """A balanced invalid outer token cannot expose nested control evidence.""" + nested_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = "review prose " + malformed_outer.replace( + "", json.dumps(nested_control) + ) + + assert norm.iter_json_objects(text) == [] + + @pytest.mark.parametrize("approve_first", [True, False]) def test_main_rejects_conflicting_current_run_controls_without_rewriting( tmp_path, capsys, approve_first diff --git a/tests/test_trusted_uv_materializer_quality_workflow_contract.py b/tests/test_trusted_uv_materializer_quality_workflow_contract.py index ed4ad55681..d1992cdbb6 100644 --- a/tests/test_trusted_uv_materializer_quality_workflow_contract.py +++ b/tests/test_trusted_uv_materializer_quality_workflow_contract.py @@ -29,13 +29,11 @@ def test_quality_workflow_runs_for_every_materializer_surface() -> None: required_paths = ( '".github/workflows/trusted-uv-materializer-quality-ci.yml"', '"scripts/ci/materialize_base_python_requirements.py"', - '"scripts/ci/verify_release_maturin_tool_assets.py"', '"tests/conftest.py"', '"tests/test_materialize*.py"', '"tests/test_trusted_uv*.py"', '"tests/test_uv*.py"', '"tests/test_repository_branch_coverage_*.py"', - '"tests/test_verify_release_maturin_tool_assets.py"', '"requirements-opencode-review-ci-hashes.txt"', '"requirements-opencode-review-ci.txt"', '"requirements-noema-document-ci.txt"', @@ -46,16 +44,6 @@ def test_quality_workflow_runs_for_every_materializer_surface() -> None: assert workflow.count(required_path) == 2 -def test_quality_workflow_admits_stacked_pull_requests() -> None: - """A non-default canonical owner base must not suppress exact-head evidence.""" - - pull_request_trigger = _workflow_text().split(" pull_request:\n", 1)[1].split( - " push:\n", 1 - )[0] - - assert "branches:" not in pull_request_trigger - - def test_quality_workflow_pins_actions_and_uses_read_only_permissions() -> None: """Quality evidence executes from the exact PR head with least privilege.""" diff --git a/tests/test_verify_release_maturin_tool_assets.py b/tests/test_verify_release_maturin_tool_assets.py index 6aa84a0827..e9c80e91f0 100644 --- a/tests/test_verify_release_maturin_tool_assets.py +++ b/tests/test_verify_release_maturin_tool_assets.py @@ -6,7 +6,6 @@ import runpy import sys import tarfile -import urllib.error import urllib.request import zipfile from pathlib import Path @@ -177,52 +176,6 @@ def build_opener(proxy_handler, redirect_handler): verifier._download("maturin-x86_64-pc-windows-msvc.zip") -def test_maturin_download_closes_unsuccessful_responses_and_http_errors(monkeypatch): - """Every rejected transport response releases its underlying connection.""" - closed = [] - - class Response: - status = 503 - - def close(self): - closed.append("response") - - class ResponseOpener: - def open(self, _request, timeout): - assert timeout == 60 - return Response() - - monkeypatch.setattr( - verifier.urllib.request, - "build_opener", - lambda _proxy, _redirect: ResponseOpener(), - ) - with pytest.raises(ValueError, match="HTTP 503"): - verifier._download("maturin-x86_64-pc-windows-msvc.zip") - assert closed == ["response"] - - transport_error = urllib.error.HTTPError( - "https://github.com/asset", 502, "Bad Gateway", {}, io.BytesIO() - ) - monkeypatch.setattr( - transport_error, "close", lambda: closed.append("http-error") - ) - - class ErrorOpener: - def open(self, _request, timeout): - assert timeout == 60 - raise transport_error - - monkeypatch.setattr( - verifier.urllib.request, - "build_opener", - lambda _proxy, _redirect: ErrorOpener(), - ) - with pytest.raises(ValueError, match="HTTP 502"): - verifier._download("maturin-x86_64-pc-windows-msvc.zip") - assert closed == ["response", "http-error"] - - def test_maturin_download_rejects_unlisted_name_before_network(monkeypatch): """Caller-controlled paths and URLs never reach the network transport.""" monkeypatch.setattr(