fix(apply): lint reads the same artifact shape apply consumes (A3)#2
Merged
Conversation
`generate` emits a service-policy artifact in one of two shapes — a bare spec, or a full XC
create body `{metadata, spec}`. `apply_from_scan` handles both and says so in a comment; the
linter did not. It read `spec["rule_list"]` straight off the artifact, which on a wrapped one
is None because rule_list sits a level deeper, so it saw zero rules and reported
⚠ lint deny-unauth-x402-scenario-control: no DENY rule — refine will correct at apply
for a policy whose rules[0].spec.action is "DENY". In a 12-policy crAPI/x402 run, 6 policies
were wrapped and all 6 drew the false positive — noise that trains an operator to ignore the
one warning that matters.
Adds `artifact_spec()` — the same unwrap rule apply_from_scan uses — and applies it in
lint_service_policy, so the two cannot drift apart again. Re-linting the artifacts from a real
run: 6 flagged -> 0.
Deliberately NOT applied to lint_api_schema: its consumer (console `_dispatch_action`) uploads
the artifact to XC's object store verbatim without unwrapping, so a wrapped api_schema really
would be broken and the linter's complaint there is a true positive. Every api_schema artifact
on disk is bare today; unwrapping in the linter would only hide a future breakage.
Regression tests cover both directions — a wrapped policy with a DENY lints clean, and a
wrapped policy that has no DENY, or an ALLOW before the DENY, is still caught. 190 pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Fixes a false positive in the pre-apply policy linter. Spotted from real scan output:
That policy has a DENY. The linter just couldn't see it.
Cause
generateemits a service-policy artifact in one of two shapes — a bare spec, or a full XCcreate body
{metadata, spec}.apply_from_scanhandles both, and says so:lint_service_policydidn't. It readspec["rule_list"]straight off the artifact, which on awrapped one is
None—rule_listsits a level deeper — so it saw zero rules and returned["no DENY rule"].In a 12-policy crAPI/x402 run, 6 policies were wrapped and all 6 drew the false positive:
deny-unauth-x402-scenario-controlcontainsrules[0].spec.action == "DENY"followed by anALLOW — exactly the shape the linter exists to approve. The cost isn't cosmetic: noise at a
50% false-positive rate trains an operator to skim past the one warning that matters.
Fix
Adds
artifact_spec()— the same unwrap ruleapply_from_scanuses — and applies it inlint_service_policy, so the two can't drift apart again. Re-linting the artifacts from a realrun: 6 flagged → 0.
Scope
Deliberately not applied to
lint_api_schema. Its consumer (console/app.py_dispatch_action) uploads the artifact to XC's object store verbatim, without unwrapping —so a wrapped api_schema genuinely would be broken and the linter's complaint there is a true
positive. Every api_schema artifact on disk is bare today; unwrapping in the linter would only
hide a future breakage. Noted rather than papered over.
Verification
wrapped policy with no DENY, or with an ALLOW before the DENY, is still caught — the fix
must not blunt the linter.
ruffclean.service_policy.*.jsonartifact on disk: 0 flagged.Note
Pre-existing, from
d751aa1(the original A3 linter) — not introduced by #1. Whether #1'sswitch to a full scan transcript is why it became noticeable is unclear: with ~10 findings the
lint lines may or may not have fallen inside the old 40-line window.
🤖 Generated with Claude Code