mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #396] [MERGED] feat(cursor-review): optional direct-Anthropic review cells via a pinned Claude Code CLI over a read-only PR checkout #397
Labels
No labels
cursor-review-catalog-drift
groom
groom
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/github-workflows#397
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/github-workflows/pull/396
Author: @mattmillerai
Created: 10/9/2026
Status: ✅ Merged
Merged: 10/9/2026
Merged by: @mattmillerai
Base:
main← Head:matt/be-19913-anthropic-direct-cells📝 Commits (7)
ce872cdfeat(cursor-review): optional direct-Anthropic review cells via a pinned Claude Code CLI over a read-only PR checkout (BE-19913)f82d7b9fix(cursor-review): harden the direct-Anthropic cells per review49bec95fix(cursor-review): load no PR-authored Claude config in the direct-Anthropic cellse2a926cfix(cursor-review): deny /proc and /sys to the direct-Anthropic agent independently of --restricted1290970fix(cursor-review): keep Grep and Glob in the direct-Anthropic cells by dropping --bare (BE-19913)e2ebf0ffeat(cursor-review): record each direct-Anthropic cell's token usage as an artifact (BE-19913)7b0f72bfix(cursor-review): make usage recording best-effort and refuse malformed counts (BE-19913)📊 Changes
10 files changed (+1119 additions, -43 deletions)
View changed files
📝
.github/cursor-review/README.md(+5 -1)📝
.github/cursor-review/aggregate-panel.py(+53 -14)📝
.github/cursor-review/package.json(+3 -2)📝
.github/cursor-review/tests/test_aggregate_panel.py(+122 -0)📝
.github/cursor-review/tests/test_workflow_job_isolation.py(+66 -0)📝
.github/cursor-review/tests/test_workflow_panel_integrity.py(+162 -15)📝
.github/cursor-review/tests/test_workflow_ref_guard_parity.py(+1 -1)📝
.github/workflow-pins/tests/test_check_workflow_pins.py(+3 -2)📝
.github/workflows/cursor-review.yml(+700 -8)📝
docs/callers/cursor-review.md(+4 -0)📄 Description
Adds an opt-in pair of direct-Anthropic review cells to
cursor-review.yml. It mirrorsreview-openai-directstep for step, with one deliberate difference: the agent also reads a read-only PR checkout. Diff-only cells miss every finding that needs a file outside the diff.What changed
anthropic_direct_model(default'', same plain-id check asopenai_direct_model; refused with a warning when it equalsopenai_direct_model, whose artifact name it would collide with),anthropic_direct_effort(defaultxhigh; anything outsidelow|medium|high|xhigh|maxwarns and falls back toxhigh), andanthropic_direct_replaces_cursor_anthropic(defaulttrue).ANTHROPIC_API_KEY, documented likeOPENAI_API_KEY.gateresolvesanthropic_key_present, sopreflight(which followsruns_on) never references the secret.preflight/Define panel models:anthropic_direct,anthropic_direct_countsand a validatedanthropic_direct_effort.claude-. This runs after the OpenAI drop, so the empty-panel::error::sees both drops.judge_modelis never touched.grep -xmatched line by line, so a multi-line value got through on one clean line. This also fixes the existingopenai_direct_modelcheck.review-anthropic-direct(ubuntu-latest,contents: read, 2-entry matrix):workflows_refguard.Checkout PR repostep: same pinned action SHA asreview,ref: pull_request.head.sha(the reviewed diff's RIGHT side, not the merge ref),path: _pr,fetch-depth: 1,persist-credentials: false. Following steps runfind _pr -type l -deleteand remove PR-authored Claude config (rm -rf _pr/.claude _pr/.mcp.json _pr/CLAUDE.local.md), the counterpart of the Cursor cells'rm -rf .cursor.pr-diffand ledger downloads, then the key check.package.jsonpin, using the same exact-versionjqcheck as the Codex install, plus aVerifystep. That step checks the version and also fails by name ifclaude --helpstops listing any confinement flag the cell relies on (--restricted,--disallowedTools,--permission-prompts,--setting-sources, …).Build prompt.claude -p --bare --restricted --setting-sources "" --tools "Read,Grep,Glob" --strict-mcp-config --disallowedTools "Read(//proc/**),Read(//sys/**)" …with the sharedreview-output-mcp.pyas the only MCP server, run in_pr. Everypython3in that step (and the MCP server it spawns) runs with-I, so a PR-plantedjson.pyin the cwd cannot shadow the stdlib. Its key,CLAUDE_CONFIG_DIRandCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1are set in that one step's env. The result JSON goes to/tmp/claude-result.jsonand is never echoed. The key is in that process's env, so/proc/self/environis denied by explicit rules that do not depend on--restricted.Report cell outcome, thefindings-direct-<type>-<model>upload, andFail the leg when the cell did not submit.aggregate-panel.pycounts direct cells per lab:--direct-*flags stay the OpenAI ones.--anthropic-direct-model/-counts/-resultflags cover Anthropic."@anthropic-ai/claude-code": "2.1.286"in.github/cursor-review/package.json, whose description now names both CLIs..github/cursor-review/README.mdanddocs/callers/cursor-review.md. They include the zero-data-retention note for private repos and the Read/Grep/Glob-only,--restricteddescription.Follow-ups from review (
1290970,e2ebf0f,7b0f72b)Dropped
--bare. On the pinned 2.1.286 binary,--baresilently removes Grep and Glob from--tools "Read,Grep,Glob". The agent was left with Read only, so it could open files it already knew about but never search the checkout, which is the reason it gets a checkout at all. Everything--barewould skip is already off:--setting-sources ""and a freshCLAUDE_CONFIG_DIRload no settings, hooks, plugins or CLAUDE.md instructions.--strict-mcp-configadmits only the submission server.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1stops telemetry.The verify step no longer requires
--bare, and a new test pins its absence.Token usage artifact. New
Record token usageandUpload usage artifactsteps: each cell uploadsusage-direct-<review_type>-<model>, kept 30 days.measured=falsewhen the cell left no result, e.g. after a timeout.findings-*, soconsolidatenever reads it as a cell, and its upload is best-effort.RecordTokenUsageTestcover these behaviours.Usage recording hardened (CodeRabbit).
Record token usageiscontinue-on-error, like its upload. A present but malformed count or model id makes the recordmeasured: falserather than a zero a cost report would trust.The
consolidateneeds:comment now reads correctly for two direct jobs.Tests
test_aggregate_panel.pygets a newPerLabTest. It covers:test_workflow_panel_integrity.py:DirectCellsGateWhenTheyReplaceTestis now parameterised per lab, andAnthropicDirectCellsGateWhenTheyReplaceTestexecutes preflight → aggregate → leg check for the new job. I checked the sabotage cases by hand. Each of these one-line edits makes the twin fail:--anthropic-direct-counts falseanthropic_direct_counts=truechanged tofalseexit 1changed totrueANTHROPIC_DIRECT_MODELEXPECTED_GUARDS12→13, and the workflow-pins self-check 23→24.test_workflow_job_isolation.py: new assertion thatANTHROPIC_API_KEYis referenced only bygateandreview-anthropic-direct, and that the latter is onubuntu-latest. Another asserts that theclaudeinvocation carries--bare,--restrictedand--setting-sources "", and that the job removes_pr/.claudeand_pr/.mcp.json. A third pins the/proc+/sysdeny rule,--permission-prompts noneand the verify step's flag check. Removing the deny rule fails it.check_workflow_pins.py,check_agents_md.py --root .andcheck-org-repo-literals.shall pass.actionlint: diffed againstmain's copy of the file, there is no new kind of finding. The only additions are one more instance each of the existing guard-step warnings (job.workflow_shaunknown to actionlint, and SC2018/SC2019 info), because the guard is a byte-identical copy.Judgment calls
anthropic_direct_modelunset, behaviour is unchanged: the job is skipped, the new aggregate flags default to off/skipped, and every existing test passes unmodified apart from the two guard counts.Residual
Exercised on Linux, not yet on a GitHub runner. The job's own step scripts, taken verbatim from the workflow, ran in a
node:22-bookwormcontainer with the pinned 2.1.286 binary and a real key.Verify Claude Code CLI versionpassed, including the version parse and every flag.status=okwith no permission denials.measured=true.The first live run should still check that both cells report
status=ok.Confinement probes on that Linux setup:
/procwere refused with both layers, with--restrictedalone, and with the deny rules alone. All three succeeded with neither, so the probe is real.CLAUDE.mdinstructing a one-word reply was ignored under--setting-sources "".CLI pin. 2.1.295's changelog fixes "
--toolsand--restrictednot applying to built-in tools that register after launch". In these 2.1.286 runs the agent was offered only Glob, Grep and Read, plus the submission tools under MCP. Take Dependabot's bump past 2.1.295 once it clears the cooldown.The judge (
Consolidate panel) stays on Cursor. Moving it, retrying direct cells on transient API errors, and supporting more than one direct Anthropic model are all out of scope.Provenance
check_workflow_pins.py,check-org-repo-literals.shandcheck_agents_md.py --root ..actionlintwas diffed againstmainbefore the review-fix commits and has not been re-run since.--setting-sources "", and dropping the/procdeny rule.claude -p. With--restrictedalone, and with the deny rules alone, file-tool reads of/procand/syswere refused.🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.