Repository navigation
Conversation
gadievron
requested review from
dgeyshis,
shahar-davidson and
sounil
as code owners
October 27, 2026 08:50
…ps the finding-ref anchors (#711) The Python CLI linkifies the model's #N finding references into <a href="#finding-N" class="finding-ref">#N</a> and both templates render the matching id="finding-N" anchors on the finding <details>, but the Go remediation policy allowed neither the class attribute nor any fragment href, so bluemonday dropped the WHOLE anchor — the operator got plain text and the .finding-ref rules styled nothing (PR #579's noted dead channel). The producer/consumer contract, agreed and allowed now — as narrowly as the old surface: the class attribute on <a> accepts EXACTLY the finding-ref value (any other class dies); the href pattern accepts the absolute http(s) links the policy always allowed plus the same-document #finding-N fragments ONLY. AllowRelativeURLs is required for a fragment to survive bluemonday's URL policy; the href VALUE PATTERN is what keeps that permission from admitting any other relative URL — page2.html, ../x, //evil.com all fail the pattern and die, and javascript: and every other scheme still die at the pattern too. Pinned: the anchor survives with href AND class (plus the referrer hardening); the hostile shapes die (the script URLs, the foreign classes, the non-fragment relatives, the protocol-relatives, the off-shaped fragments, the unknown schemes); the absolute http(s) links keep their noreferrer/target hardening; both templates carry the finding anchor ids. The Python producer half extracted to a module-level _linkify_finding_refs (behavior-preserving) and pinned: the exact shapes the Go patterns admit (a drifted producer shape would silently strip at the render boundary).
gadievron
force-pushed
the
fix/711-finding-ref-links
branch
from
October 27, 2026 09:49
21686d3 to
e372a2c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes #711 — #247-era producer/consumer disagreement: the Python CLI linkifies the model's
#Nfinding references into<a href="#finding-N" class="finding-ref">#N</a>(and the prompt explicitly asks the model for them), both templates render the matchingid="finding-N"anchors on the finding<details>— but the Go remediation policy allowed neither theclassattribute nor any fragment href, so bluemonday dropped the whole anchor. The operator got plain text; the.finding-refCSS styled nothing (PR #579's noted dead channel).The falsifier (authored at filing): "a rendered HTML report whose remediation section contains a working link to a finding anchor."
The fix — the contract agreed, as narrowly as the old surface
The consumer (the Go policy): the class attribute on
<a>accepts exactly thefinding-refvalue; the href accepts the finding fragments (#finding-N, digits, end-anchored) plus the pre-existing http(s) surface — the http(s) half of the pattern is deliberately prefix-shaped and case-insensitive, with a whitespace class matchingvalidURL'sTrimSpace, so bluemonday's own unchanged URL handling keeps owning the http(s) value exactly as before (an earlier fully-anchored pattern silently demoted uppercase schemes, whitespace-padded values, and apostrophe/quote/backtick-bearing URLs — real regressions, caught and closed in review with a 120-shape A/B:REGRESS=0, and the only newly accepted HREF VALUES in that corpus were the intended fragments — the full sanitized-output surface also gains three harmless class-related shapes the review rounds recorded (a class-only anchor with no href; duplicateclassattributes — the browser uses the first;rel="noreferrer"on the fragment links), all enumerated, none a breakout).AllowRelativeURLsis required for a fragment to survive — and the href value pattern is what keeps that permission from admitting anything else:page2.html,../x,//evil.com,#top, every off-shaped fragment, andjavascript:/every other scheme all die.The producer (the Python linkifier): extracted to the module-level
_linkify_finding_refs(behavior-preserving — the 14-shape A/B: 0 diffs) + the numeric-character-reference lookbehind (',’— Python's ownhtml.escapeoutput, the common model-emitted shape — no longer linkify into misdirecting live links, the review's catch).The drift pins
internal/report/finding_ref_test.go): the anchor survives with href AND class (plus therel="noreferrer"hardening); the hostile corpus dies (script URLs incl. entity-encoded, foreign classes, non-fragment relatives, protocol-relatives, off-shaped fragments, unknown schemes); the 8-shape old-surface regression corpus (uppercase, mixed-case, whitespace-padded, apostrophe/quote/backtick-bearing, unicode-whitespace-led http(s) URLs — each verified RED under the historical regressor pattern, 8/8); both templates' anchor idsCount-pinned (the reskin's two finding paths both carry them).tests/test_issue711_finding_ref_links.py): the exact contract shape; every-number linkification; the non-numeric shapes untouched; the entity lookbehind pin; the call-site pin (the handler routes through the module function — the C4 ledger's green row exposed that the suite's direct-call tests left the call site unpinned; a revert of the call-site hunk would leave them green while the report path regressed — pinned at the source now, verified load-bearing).Evidence (runs/711)
9143061f..e372a2c: 6 nodes / 2 witnesses (absence-red at base — the all-new Python file; thered_waiver{new-test-file}route, its per-file fact verified: the file is absent at base); the behavioral half is Go-side (the pytest executor cannot run Go) — its linkage evidence is the C4 ledger.C4-mutants.json; the mutant patches:_mutant_href.patch/_mutant_import.patchin this bundle): 4/4 prod hunks covered behaviorally — the twocli.pyhunks by hunk-reverts (failing=6 / failing=1 — the call-site row went green→behavioral when the pin landed; its kill is the call-site source pin, honestly a source pin not an end-to-end execution). The twotypes.gohunks are a compile-interdependent PAIR (each single revert is a Go compile error — an undefined/unusedregexpimport), so the revert route's confounding check refuses both seeds and the claim route refuses too ("a claim cannot ride on a compile error"); covered at PAIR level by prod-mutants in the pair's + ranges instead (the href-pattern mutant — in the policy-lines hunk's range — killed by 3 tests; theAllowRelativeURLs(false)mutant — in the policy hunk's behavioral range, the import hunk having no mutable behavioral content of its own — killed by 1). The pair-level attribution is stated as pair-level, not as two independent in-range demonstrations.21686d38; r6 the CI-catch round — the Report CSS reproducibility job failed on the bare word "relative" in the policy comment (the tailwind content list includes types.go: the extractor generated.relative{position:relative}into regen.css and cmp diverged — the The HTML report's pipeline step rows render four fields and drop two diagnostic classes — the discovery/skip counters and the unknown-price disclosure #700 comment-token hazard, met a second time); the isolating control executed (the pre-fix types.go swapped in alone adds exactly that rule), the reword to "non-absolute" landed, and the regen re-verified BYTE-IDENTICAL to vendor (sha256 equal; the pre-PR baseline also identical — nothing in the whole PR delta emits a utility); TERMINAL DRY ate372a2c.9143061f; the open PRs fix(rust): the macro-body call scan runs on a tree-sitter token-tree walk — both regexes and the byte budget retired to the differential oracle (#708) #871/chore(deps): update dependency marked to v18.1.2 #872/chore(deps): update dependency openai to v3.42.0 #873/fix(prompts): the Untrusted choke-point — prompt-untrusted content refuses raw interpolation, unwrapped only at the fence single home (#709) #874/fix(dynamic-test): the recorded build-egress ruling — the falsifier's second disjunct, the accepted state pinned so it cannot drift (#710) #875 disjoint), reconciliation (5 rows); the sixth round is the CI-catch discharge above.Parity
The legs' own terminal lines, pasted verbatim (the full logs in the bundle —
base-parity-full.log,head-parity-settled.log[the WARM run],head-parity-settled-cold.log,head-parity-go.log,collect-diff.txt):base (at
9143061f, the full core suite):head, warm (at the final head
e372a2c, the same suite — the standing trio identity-matched; the +7 passing over base = the 6-test Python producer suite + the 1 parametrizedno-hardcoded-pathsguard item; the skips identical (38 = 38):the go module (at the head):
head-parity-go.logendsEXIT:0— all packages ok.collect-diff: base 13,324 collected → head 13,331 —
+7 added / 0 removed, exactly the new producer suite's 6 tests + the parametrized guard item (collect-diff.txt).the cold-run disclosure: the head worktree's FIRST full run showed
3 failed, 13145 passed, 180 skipped— the +142 skips over base are the first-run provisioning class, fully decoded by the warm run above (38 = 38); the cold log retained ashead-parity-settled-cold.log.