Skip to content

ci(dev-lead): guard the caller↔reusable permission contract (prevents startup_failure) - #455

Merged
don-petry merged 11 commits into
mainfrom
ci/dev-lead-permission-contract
Jun 7, 2026
Merged

don-petry merged 11 commits into
mainfrom
ci/dev-lead-permission-contract

Conversation

@don-petry

Copy link
Copy Markdown
Collaborator

Why

A reusable workflow's jobs can only use GITHUB_TOKEN permissions the caller grants at jobs.<id>.permissions. If a reusable job requests more, every consumer fails at startup (startup_failure) — no runtime error, the run is just invalid.

This is exactly petry-projects/.github#402: #435 added statuses: read to the reusable's job permissions but never to the caller template, so every @main consumer broke (.github was 15/15 startup_failure). Nothing caught it.

What

tests/dev-lead/integration/test_caller_permissions.py computes the union (max level per scope) of all reusable job permissions and asserts the published caller template (petry-projects/.github → standards/workflows/dev-lead.yml) grants ≥ each scope. Wired as a new caller-permissions job in test-dev-lead.yml.

Because it checks the reusable's PR against the published template, it enforces the safe ordering: the caller grant must merge first, then the reusable may request it. A future permissions: addition to the reusable fails this check until the template is updated — converting a silent org-wide outage into a red check on the PR that causes it.

Verification

  • Negative: a tampered reusable requesting packages: write is flagged, naming the exact scope + file to fix.
  • Positive: currently reports statuses: read MISSING — because the live template on .github@main doesn't have it yet.

⚠️ Merge ordering

This job stays red until petry-projects/.github#403 merges (which adds statuses: read to the template). That red is the contract gap it correctly detects. Merge #403 first, then this goes green.

Refs petry-projects/.github#402

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings June 7, 2026 03:03
@don-petry
don-petry requested a review from a team as a code owner June 7, 2026 03:03
@coderabbitai

coderabbitai Bot commented Jun 7, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

@don-petry, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 6 minutes and 34 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: ee4e68a7-dcef-4afc-aa26-8d0d1d8f49c1

📥 Commits

Reviewing files that changed from the base of the PR and between d4debee and 680720a.

📒 Files selected for processing (3)
  • .github/workflows/test-dev-lead.yml
  • tests/dev-lead/integration/.gitignore
  • tests/dev-lead/integration/test_caller_permissions.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/dev-lead-permission-contract

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a new integration test script, test_caller_permissions.py, which validates the GITHUB_TOKEN permission contract between a caller workflow and a reusable workflow by comparing local configurations against fetched templates. The review feedback highlights several robust error-handling improvements, specifically addressing potential AttributeError crashes if the YAML parser returns None for empty files, and handling cases where GitHub Actions permissions are defined as strings (such as write-all or read-all) rather than dictionaries.

Comment thread tests/dev-lead/integration/test_caller_permissions.py
Comment thread tests/dev-lead/integration/test_caller_permissions.py Outdated
Comment thread tests/dev-lead/integration/test_caller_permissions.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an integration guard to prevent org-wide startup_failure outages caused by permission drift between the dev-lead reusable workflow (requested permissions) and the published caller stub template (granted jobs.<id>.permissions).

Changes:

  • Introduces tests/dev-lead/integration/test_caller_permissions.py to compute required permission maxima from the reusable and compare them against the published caller template in petry-projects/.github.
  • Wires the new check into CI via a caller-permissions job in .github/workflows/test-dev-lead.yml.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
tests/dev-lead/integration/test_caller_permissions.py New integration test that validates the caller↔reusable GITHUB_TOKEN permission contract against the published template.
.github/workflows/test-dev-lead.yml Adds a CI job to install PyYAML and run the new permission-contract validation script.

Comment thread tests/dev-lead/integration/test_caller_permissions.py Outdated
Comment thread tests/dev-lead/integration/test_caller_permissions.py
Comment thread tests/dev-lead/integration/test_caller_permissions.py Outdated
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (applied)

Changes committed and pushed.

@don-petry
don-petry enabled auto-merge (squash) June 7, 2026 03:07

@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: df8ffea5c4

ℹ️ 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/dev-lead/integration/test_caller_permissions.py Outdated
Comment thread tests/dev-lead/integration/test_caller_permissions.py Outdated
Comment thread tests/dev-lead/integration/test_caller_permissions.py Outdated
Comment thread tests/dev-lead/integration/test_caller_permissions.py Outdated
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (applied)

Changes committed and pushed.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 7, 2026

@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: f602078d1a

ℹ️ 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/dev-lead/integration/test_caller_permissions.py
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — fix-reviews (applied)

Changes committed and pushed.

@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


P2 Badge Remove generated Python bytecode

This adds generated __pycache__ artifacts alongside the new source test. Because these .pyc files are CPython-version-specific outputs from running/importing the test, future local or CI runs with a different interpreter or after editing the test can leave tracked bytecode churn unrelated to the actual contract check; please remove the cache files from the commit and keep only the Python source.

ℹ️ 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".

@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (applied)

Changes committed and pushed.

@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (applied)

Changes committed and pushed.

@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — fix-bot-comment (no-changes)

Agent reasoning
Issues addressed: 0
Files changed: none
Skipped (informational): Quality Gate passed — 0 new issues, 0 security hotspots reported by SonarCloud
```

Copy link
Copy Markdown
Collaborator Author

@dev-lead Please action the unresolved Codex review comments on this PR. (Automated re-trigger sweep — #445 now trusts chatgpt-codex-connector[bot].)


Generated by Claude Code

@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — on-mention (no-changes)

Engine ran but made no changes.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 7, 2026
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — rate-limited (intent: fix-reviews)

PR: #455
The retry cron will re-attempt automatically. Rate limit resets at: 2026-06-07T05:29:52Z

@don-petry

Copy link
Copy Markdown
Collaborator Author

Auto-rebase failed — merge conflict — this branch has conflicts with main that must be resolved.

Claude will attempt to resolve this automatically. If it cannot, a follow-up comment will explain what needs manual attention.

To resolve manually instead:

git fetch origin
git merge origin/main
# resolve conflicts, then:
git add .
git commit
git push

claude and others added 6 commits June 7, 2026 05:20
A reusable workflow job can only use token permissions the caller grants at
jobs.<id>.permissions; if a job requests more, every consumer fails at startup
(startup_failure) with no runtime error. #435 added statuses:read to the
reusable but not the caller template, breaking every @main consumer (.github
15/15) — petry-projects/.github#402.

Add test_caller_permissions.py: parse the union of all reusable job permissions
and assert the published caller template (petry-projects/.github
standards/workflows/dev-lead.yml) grants >= each scope. Wire it as a new
test-dev-lead job. This fails the build at the PR that edits the reusable —
forcing the template grant to land first (the safe ordering).

Verified: catches a tampered reusable requesting packages:write; the negative
message names the exact scope and file to fix.

NOTE: this job stays red until the template gains statuses:read
(petry-projects/.github#403) — that's the contract gap it correctly detects.

Refs petry-projects/.github#402

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (no-changes)

No changes were needed for this PR.

@don-petry
don-petry disabled auto-merge June 7, 2026 17:22
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (no-changes)

No changes were needed for this PR.

@don-petry
don-petry enabled auto-merge (squash) June 7, 2026 17:23
@don-petry
don-petry disabled auto-merge June 7, 2026 22:12
@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (no-changes)

No changes were needed for this PR.

@don-petry
don-petry enabled auto-merge (squash) June 7, 2026 22:13
@don-petry

Copy link
Copy Markdown
Collaborator Author

@donpetry-bot review

@don-petry
don-petry disabled auto-merge June 7, 2026 22:52
@sonarqubecloud

sonarqubecloud Bot commented Jun 7, 2026

Copy link
Copy Markdown

@donpetry-bot

Copy link
Copy Markdown
Contributor

@don-petry I'm on it — starting a fresh review now. Results will appear in a few minutes.

@don-petry

Copy link
Copy Markdown
Collaborator Author

Dev-Lead — review-changes (no-changes)

No changes were needed for this PR.

@don-petry
don-petry enabled auto-merge (squash) June 7, 2026 22:53
@don-petry

Copy link
Copy Markdown
Collaborator Author

@donpetry-bot review

@donpetry-bot

Copy link
Copy Markdown
Contributor

@don-petry I'm on it — starting a fresh review now. Results will appear in a few minutes.

@donpetry-bot donpetry-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Automated review — APPROVED ✓

Risk: LOW
Reviewed commit: 680720a4a5dec2263fee4c079a5edb81098581c5
Review mode: triage-approved (single reviewer)

Summary

Confirming the triage tier's LOW-risk assessment. This PR adds a CI guard test that computes the union (max level per scope) of permissions requested by every job in dev-lead-reusable.yml and asserts the published caller template (petry-projects/.github → standards/workflows/dev-lead.yml) grants ≥ each scope. It correctly enforces the safe ordering: the caller grant must merge first, then the reusable may request it — converting a previously silent org-wide startup_failure (the petry-projects/.github#402 incident) into a red check on the PR that causes it.

The implementation is careful about edge cases: it handles the write-all / read-all string shorthands with a wildcard "*" key on both sides, falls back to workflow-level permissions when a job omits its own block, and emits specific, actionable failure messages naming the exact scope, file, and job key to fix.

Linked issue analysis

No closing-issue link, but the PR body references petry-projects/.github#402 (the incident this guards against) and #403 (the template-side fix that must merge first). The PR body explicitly flags the merge-ordering expectation. Scope matches the stated intent.

Findings

  • Test-only addition — no production runtime code changed. Only files touched are a new test (tests/dev-lead/integration/test_caller_permissions.py), a new CI job in .github/workflows/test-dev-lead.yml, and a local .gitignore for __pycache__.
  • Pinned action SHA — actions/checkout is pinned by SHA (df4cb1c… / v6.0.3), consistent with repo convention.
  • Minimal job permissions — the new caller-permissions job declares only contents: read. The remote template is fetched from the public petry-projects/.github repo via github.token, which is appropriate.
  • Prior bot feedback incorporated — earlier review iterations addressed Gemini/Copilot/Codex notes on None-yaml defensiveness, string-shorthand permission handling, and the __pycache__/ ignore. CodeRabbit's latest review is APPROVED.
  • No transient deps in the test — pip install pyyaml is installed at job runtime (unpinned), which is acceptable for an ephemeral test environment. Not a blocker.

CI status

All checks SUCCESS: CodeQL, SonarCloud, CodeRabbit, agent-shield, gitleaks, gh-aw-compile, validate-agent-profiles, Agent Security Scan, unit-tests, ShellCheck, bats, Lint, Analyze (actions), dependency-audit (skipped where N/A). No unresolved review threads or unanswered human-reviewer questions.


Reviewed automatically by the PR-review agent (single-reviewer mode: opus 4.7). Reply if you need a human review.

@don-petry
don-petry merged commit 8991594 into main Jun 7, 2026
26 checks passed
@don-petry
don-petry deleted the ci/dev-lead-permission-contract branch June 7, 2026 23:00
don-petry added a commit to petry-projects/.github that referenced this pull request Jun 11, 2026
The dispatch job in dev-lead-reusable.yml already requests statuses: read
(added in #435), but the caller stub template was never
updated to grant it. This caused every @main consumer to fail at startup
(startup_failure). Syncing the template unblocks the new caller-permissions
CI guard being added in petry-projects/.github-private#455.
don-petry added a commit that referenced this pull request Jun 12, 2026
… startup_failure) (#455)

* ci(dev-lead): guard the caller<->reusable permission contract

A reusable workflow job can only use token permissions the caller grants at
jobs.<id>.permissions; if a job requests more, every consumer fails at startup
(startup_failure) with no runtime error. #435 added statuses:read to the
reusable but not the caller template, breaking every @main consumer (.github
15/15) — petry-projects/.github#402.

Add test_caller_permissions.py: parse the union of all reusable job permissions
and assert the published caller template (petry-projects/.github
standards/workflows/dev-lead.yml) grants >= each scope. Wire it as a new
test-dev-lead job. This fails the build at the PR that edits the reusable —
forcing the template grant to land first (the safe ordering).

Verified: catches a tampered reusable requesting packages:write; the negative
message names the exact scope and file to fix.

NOTE: this job stays red until the template gains statuses:read
(petry-projects/.github#403) — that's the contract gap it correctly detects.

Refs petry-projects/.github#402

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: apply manual instructions [skip ci-relay]

* chore: apply manual instructions [skip ci-relay]

* fix(reviews): address review comments [skip ci-relay]

* chore: apply manual instructions [skip ci-relay]

* chore: apply manual instructions [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <noreply@anthropic.com>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.com>
don-petry added a commit that referenced this pull request Jun 14, 2026
… startup_failure) (#455)

* ci(dev-lead): guard the caller<->reusable permission contract

A reusable workflow job can only use token permissions the caller grants at
jobs.<id>.permissions; if a job requests more, every consumer fails at startup
(startup_failure) with no runtime error. #435 added statuses:read to the
reusable but not the caller template, breaking every @main consumer (.github
15/15) — petry-projects/.github#402.

Add test_caller_permissions.py: parse the union of all reusable job permissions
and assert the published caller template (petry-projects/.github
standards/workflows/dev-lead.yml) grants >= each scope. Wire it as a new
test-dev-lead job. This fails the build at the PR that edits the reusable —
forcing the template grant to land first (the safe ordering).

Verified: catches a tampered reusable requesting packages:write; the negative
message names the exact scope and file to fix.

NOTE: this job stays red until the template gains statuses:read
(petry-projects/.github#403) — that's the contract gap it correctly detects.

Refs petry-projects/.github#402

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: apply manual instructions [skip ci-relay]

* chore: apply manual instructions [skip ci-relay]

* fix(reviews): address review comments [skip ci-relay]

* chore: apply manual instructions [skip ci-relay]

* chore: apply manual instructions [skip ci-relay]

---------

Co-authored-by: Claude Code Bot <noreply@anthropic.com>
Co-authored-by: donpetry-bot <281750570+donpetry-bot@users.noreply.github.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.

4 participants