chore(probe): cross-repo GITHUB_TOKEN read probe (throwaway, do not merge) - #271
chore(probe): cross-repo GITHUB_TOKEN read probe (throwaway, do not merge)#271kyle-sexton wants to merge 1 commit into
Conversation
|
Claude finished @kyle-sexton's task in 1m 41s —— View job Code Review
Security & CLAUDE.md AlignmentThe probe is well-aligned with the repo's security ground rules:
One subtle positive: for fork PRs, GitHub provides a read-only, secrets-stripped Probe DesignThe discriminator logic is sound. ARM C (private repo) is the correct falsifiability test — a 200 on ARM B alone is confounded by world-readable public data, and the PR description correctly identifies this. The Findings1. ARM E intermediate calls don't capture rate-limit headers Lines 80–97 (and mirror at 141–157): the two intermediate curl calls that resolve If it matters, wrapping them with a lightweight version of 2. Line 34 (and L96): omitting 3. Code duplication between jobs The two jobs are identical except for the 4. Line 82: if the API returns an error body (e.g., a 404 JSON), SummaryProbe design is solid and all security-relevant constraints from CLAUDE.md are respected. The only actionable item is finding #1 (missing header capture for ARM E's intermediate calls) if the rate-limit bucket question is load-bearing. Everything else is cosmetic. Ready to run as-is for the Phase 0 empirical check. |
|
Claude finished @kyle-sexton's task in 2m 4s —— View job Security Review —
|
| Check | Result |
|---|---|
| Trigger | pull_request only — no pull_request_target or workflow_run ✓ |
github context in run: |
None — no script-injection surface ✓ |
| Token handling | Passed as env var; never echoed; no set -x ✓ |
| Permissions | {} top-level; per-job {} and actions+checks: read only ✓ |
| No checkout | No actions/checkout, no untrusted code in workspace ✓ |
No external uses: |
No action pins to audit — pure run: shell ✓ |
| Temp file cleanup | rm -f "$hdrs" "$body" in every probe call ✓ |
| ARM C (private repo) | Expected 404 — no exfiltration path ✓ |
| Log hygiene | Error bodies capped at 200 bytes; no token echo ✓ |
|
Probe complete; results recorded on #238 (#238 (comment)). Verdict: DESIGN LIVES. GITHUB_TOKEN -> public cross-repo = 200 (even with Closing unmerged and deleting the branch as planned. This comment was written by an AI agent (adversarial-verification lane, on the operator's behalf). |
Summary
Throwaway Phase 0 probe for #238. Settles empirically whether a workflow
GITHUB_TOKENcan read ANOTHER repository's Actions/Checks data when that repository is public.GitHub's docs never join the two axes. The installation-token side says the token is "limited to the repository that contains your workflow" and "cannot be granted access to repositories that the installation was not granted access to"; each target endpoint says it "can be used without authentication ... if only public resources are requested". Nothing states the evaluation order, so #238's ratified receiver-side polling architecture rests on an unverified premise. If the answer is 404, the poller needs a GitHub App or PAT, breaking the zero-new-secrets constraint that already excluded event-driven dispatch — which would send #238 back to design rather than to a build tweak.
This probe does not admit #238 for work. That item stays human-gated; this only informs the operator's decision.
Six arms, two permission postures (
{}andactions+checks: read). A bare 200 is confounded — public Actions data is world-readable — so the private-repo arm is the discriminator:claude-code-plugins(baseline)GITHUB_TOKENto publicclaude-code-plugins(the question)GITHUB_TOKENto publicstandards(second target; rate-limit bucket test)GITHUB_TOKENto PRIVATEmedley(discriminator)GITHUB_TOKENto ownci-workflows(sanity)Also captures
x-ratelimit-limit/remaining/resourceandx-accepted-github-permissionson every call, to settle whether the 1,000 req/hr bucket is keyed to the workflow's repo or to each target repo.Reads only. No writes, no secrets beyond the ambient token, and the token value is never echoed.
Test plan
The workflow IS the test. Read the two jobs' logs and compare arm B against arm C:
Related
Refs #238. Follows the throwaway-probe shape of #270 (
pull_request-triggered,permissions: {}, closed unmerged, branch deleted).Do not merge. This PR is closed and the branch deleted once the logs are captured.
This PR was opened by an AI agent (adversarial-verification lane, on the operator's behalf).