Skip to content

fix(contract): reject reversed finding line ranges - #561

Open
sylvesterkaczmarek wants to merge 2 commits into
openai:mainfrom
sylvesterkaczmarek:fix/contract-location-line-ranges
Open

fix(contract): reject reversed finding line ranges#561
sylvesterkaczmarek wants to merge 2 commits into
openai:mainfrom
sylvesterkaczmarek:fix/contract-location-line-ranges

Conversation

@sylvesterkaczmarek

Copy link
Copy Markdown

Summary

Require canonical finding locations loaded by the TypeScript SDK to satisfy endLine >= startLine, matching the existing Python finalizer invariant.

Fixes #560.

Reproduction / evidence

Current upstream main at 37bf87a692fc72d41f7312cc48808d699d204fba has asymmetric canonical validation:

  • the bundled Python finalizer rejects an ordinary location whose endLine is before startLine;
  • the JSON schema checks only that both values are positive integers;
  • validateCanonicalContract() in the TypeScript loader validates the location path but does not compare the line numbers.

A copy of the real bundled completed-scan fixture can therefore be changed to startLine: 41, endLine: 40, resealed by updating the findings.json digest in scan-manifest.json, and still load through loadContract() on current main.

Root cause

The relational line-range invariant is enforced during Python finalization but was not mirrored in the TypeScript canonical-validation pass. The existing JSON Schema cannot express this sibling-value comparison by itself.

Fix

After validating each ordinary finding location path, reject a defined endLine that is less than its startLine.

The check is intentionally limited to the existing producer invariant and does not alter valid single-line or forward multi-line locations.

Tests / validation

Added contract-location-line-ranges.test.ts. It copies the real bundled examples/completed-scan fixture, mutates the first location, rewrites findings.json, recomputes the sealed artifact digest, and calls the real loadContract().

The regression verifies:

  • startLine: 41, endLine: 40 is rejected;
  • startLine: 41, endLine: 44 remains valid.

The branch is based directly on current upstream main at 37bf87a692fc72d41f7312cc48808d699d204fba and is not behind it. Production diff: 8 additions, 0 deletions.

Full repository tests cannot be run in this execution environment because the repository cannot be cloned here. Pushed-head CI remains the authoritative full-suite validation.

Risk

Low. This only makes the TypeScript loader reject a canonical location that the bundled producer already rejects.

@github-actions github-actions Bot added the bug Something isn't working label Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypeScript contract loader accepts reversed finding line ranges

1 participant