Skip to content

tests: document why the insecure fixtures use Path.chmod (CodeQL negative result) - #80

Merged
sumitake merged 4 commits into
mainfrom
dev/claude/codeql-test-fixture-filter
Jul 30, 2026
Merged

tests: document why the insecure fixtures use Path.chmod (CodeQL negative result)#80
sumitake merged 4 commits into
mainfrom
dev/claude/codeql-test-fixture-filter

Conversation

@sumitake

@sumitake sumitake commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Summary

Follow-up to #77, and a negative result. The two deliberately-insecure test fixtures there set their modes through Path.chmod rather than os.chmod, which resolved CodeQL's py/overly-permissive-file alerts. An independent reviewer called that a scanner workaround rather than convention alignment, and was right: the two calls are behaviourally identical, so the choice communicated nothing and depended on which sink CodeQL happens to model.

This PR set out to replace the workaround with an honest inline suppression. That does not work here, and the PR now records why.

What was tested, and what it showed

Reverting to os.chmod with inline # codeql[py/overly-permissive-file] annotations re-fired both alerts on the annotated lines (tests/test_claude_transcript_model.py:171 and :204, run 0017b3f). GitHub code scanning does not honour inline CodeQL suppression comments in this configuration.

The other candidate does not work either, for a different reason. A CodeQL config filter cannot be path-scoped: query-filters match query metadata and apply repository-wide, so excluding the query would unscan production code, and paths-ignore scopes files but drops every query for that path. There is no "exclude this query only under tests/".

What changed

Path.chmod stays, and the reason is now written at the call site: what the fixture is, why the permissive mode is the input under test, both mechanisms that were tried and why each failed, and an instruction not to tidy it back to os.chmod without re-checking CodeQL. The second fixture points at that explanation rather than repeating it.

This does not make the code safer — it was never unsafe. It converts an unexplained workaround into a documented decision, which was the actual complaint, and stops the next engineer from rediscovering this the hard way.

Verification

  • python3 -m unittest discover -s tests -t . — 658 tests, OK
  • Behaviour unchanged: both fixtures still apply the permissive mode and still assert refusal/skip. Verified in host: observe the Claude host active model from its session transcript #77 by targeted mutation that neutralizing either mode fails its test.
  • The negative result above is itself CI-verified at 0017b3f.

Boundary declaration

  • No provider executor source, raw provider command, credential, private path, downloader, or post-install hook.
  • No native-runtime change.
  • No host-specific preset or provider-specific plugin.

Generated and release surfaces

Review and post-condition

Tier 2, cross-checked by Grok (xAI), two rounds, verdict PROCEED. The cross-check independently confirmed the config-filter reasoning and ranked inline suppression the correct narrow mechanism if honoured — the CI run above is what showed it is not, so the change landed as documentation instead.

Post-condition: CodeQL green on the final commit, with no alerts on the two fixture lines.

author: claude
standing_directives: document a deliberate workaround at its call site rather than leave it reading as arbitrary; re-consult the cross-check when the approach materially changes; no production scanning coverage reduced; generated-file parity; no raw provider command or credential in the public tree
tier: 2
cross_check: PROCEED-WITH-MODIFICATIONS (grok, xai family, architecture route, read-only) - the earlier PROCEED covered the suppression approach and was invalidated when CI disproved its premise, so the cross-check was RE-CONSULTED on the revised approach per the material-change rule. It endorsed documenting over closing, and raised two additive modifications, both integrated: the explanatory comment no longer contains a suppression-shaped token that a future parser could match or an audit miscount, and the config-filter claim is scoped to stock config with the heavier alternatives named
post_condition: CodeQL green with 'No new alerts' on the final commit; the inline-suppression experiment at 0017b3f re-fired both alerts on the annotated lines and that negative result is recorded in the PR body, the changelog, and at the call site
mcp_coverage_gap: NONE
contributor_rights: OWNER-AUTHORED
operator_reserved: no

Generated with Claude Code

…sink

The two negative-test fixtures were routed through Path.chmod because CodeQL
models os.chmod and not the Path method. That resolved the alerts without
expressing anything: the calls are behaviourally identical, and the choice
depends on a scanner implementation detail that can change, at which point CI
goes red on an unrelated PR and the reason has to be rediscovered.

Use os.chmod with an inline suppression and a stated rationale at each site. The
permissive mode is the input under test -- each assertion is that the resolver
REFUSES the artifact -- and no production path sets a permissive mode.

A CodeQL config filter was considered and rejected: query-filters match query
metadata repository-wide, so excluding this query would unscan production too,
and paths-ignore would drop every query across tests/ rather than this one. No
path-scoped query filter exists, so the inline mechanism is the narrowest
available.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread tests/test_claude_transcript_model.py Fixed
Comment thread tests/test_claude_transcript_model.py Fixed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ce9d41a4f8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/test_claude_transcript_model.py Outdated
Cross-check nit: a same-line reason makes the suppression auditable by grep,
rather than depending on a reader picking up the comment above it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread tests/test_claude_transcript_model.py Fixed
Comment thread tests/test_claude_transcript_model.py Fixed
@sumitake sumitake changed the title tests: state the insecure-fixture intent instead of sidestepping the CodeQL sink tests: document why the insecure fixtures use Path.chmod (CodeQL negative result) Jul 30, 2026
sumitake and others added 2 commits July 29, 2026 20:44
The inline-suppression experiment failed. Reverting to os.chmod with
`# codeql[py/overly-permissive-file]` annotations re-fired both alerts on the
annotated lines (run 0017b3f), so GitHub code scanning does not honour inline
CodeQL suppressions in this configuration.

A config filter is not available either, for a different reason: query-filters
match query metadata repository-wide, so excluding the query would unscan
production, and paths-ignore drops every query for the path rather than this one.

Keep Path.chmod and write the reason where it is used -- what the fixture is,
why the permissive mode is the input under test, both mechanisms tried and why
each failed, and not to tidy it back without re-checking CodeQL. This does not
make the code safer; it was never unsafe. It turns an unexplained workaround
into a documented decision, which was the actual complaint.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Cross-check re-consultation on the revised approach returned
PROCEED-WITH-MODIFICATIONS with two additive points, both integrated.

The comment explaining that inline suppressions do not work CONTAINED a
suppression-shaped token. That is inert today, but a future parser with looser
line or region rules could match it, and a suppression inventory or compliance
audit would count it as an active directive. Describe the rule id in prose
instead.

Scope the config-filter claim to stock CodeQL config and name the heavier
alternatives (split analysis jobs, custom packs, SARIF post-filtering) rather
than asserting path scoping is impossible outright.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sumitake
sumitake merged commit c2bd5da into main Jul 30, 2026
15 checks passed
@sumitake
sumitake deleted the dev/claude/codeql-test-fixture-filter branch July 30, 2026 03:52
sumitake added a commit that referenced this pull request Jul 30, 2026
PR #80 concluded that inline suppressions are not honoured here, but the run
behind it (0017b3f) used a TRAILING same-line comment, while CodeQL's documented
Python syntax is a standalone comment line before the alert. One placement was
tested and generalised to all -- caught by cross-family review of the learning
entry that recorded the conclusion.

This branch ran the documented placement (27b697a). It also fails: alerts fire
on the annotated lines 173 and 208 with the standalone comment correctly on 172
and 207. So #80's conclusion stands and now has evidence across two placements
rather than one, and no correcting follow-up to #80 is needed.

Keep the Path.chmod workaround and name both runs at the call site, so the next
reader does not spend a third cycle on a placement variant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
sumitake added a commit that referenced this pull request Jul 30, 2026
…ent (#82)

* test: re-run the CodeQL suppression experiment with documented placement

EXPERIMENT, not a conclusion. PR #80 concluded that inline CodeQL suppressions
are not honoured in this repository. That conclusion is unsupported: the run at
0017b3f placed the annotation as a TRAILING same-line comment, while CodeQL's
documented Python suppression syntax requires a standalone comment line before
the alert. One placement was tested and the result generalised to all
placements.

This tests the documented form. If CodeQL is green, the mechanism works, #80's
call-site documentation and changelog are wrong and need correcting, and the
Path.chmod call-shape dependency can be dropped for the honest os.chmod plus a
stated suppression. If CodeQL is red, the negative result finally has the
evidence #80 claimed, and this reverts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* tests: record that BOTH CodeQL suppression placements were tested

PR #80 concluded that inline suppressions are not honoured here, but the run
behind it (0017b3f) used a TRAILING same-line comment, while CodeQL's documented
Python syntax is a standalone comment line before the alert. One placement was
tested and generalised to all -- caught by cross-family review of the learning
entry that recorded the conclusion.

This branch ran the documented placement (27b697a). It also fails: alerts fire
on the annotated lines 173 and 208 with the standalone comment correctly on 172
and 207. So #80's conclusion stands and now has evidence across two placements
rather than one, and no correcting follow-up to #80 is needed.

Keep the Path.chmod workaround and name both runs at the call site, so the next
reader does not spend a third cycle on a placement variant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* tests: cite CodeQL check-run ids alongside the commits

Cross-check: the comment called 0017b3f and 27b697a 'runs', but they are commit
SHAs; the CodeQL check runs are 90773472337 and 90784725147. A reader following
the citation would have landed on a commit rather than the evidence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants