Skip to content
38 changes: 37 additions & 1 deletion .github/workflows/claude-code-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ jobs:
issues: write
actions: read
checks: read
administration: write

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Checking Claude workflow permission scopes..."
for f in .github/workflows/claude-code-reusable.yml .github/workflows/claude.yml standards/workflows/claude.yml; do
  if [ -f "$f" ]; then
    echo
    echo "=== $f ==="
    rg -n -C2 "permissions:|administration:" "$f" || true
  fi
done

echo
echo "Expected:"
echo "- administration: write present in reusable workflow job"
echo "- administration: write ALSO present in caller/template workflow job permissions"

Repository: petry-projects/.github

Length of output: 2068


administration: write on line 69 will not be effective unless the caller workflow also grants it.

The reusable workflow declares administration: write, but the caller (.github/workflows/claude.yml) still only grants contents: write, id-token: write, and related scopes. GitHub Actions enforces the intersection of caller-granted and callee-requested permissions, so any admin-scoped operations in claude-code will be constrained.

Update .github/workflows/claude.yml to include administration: write in the permissions section of the claude-code job.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/claude-code-reusable.yml at line 69, The reusable workflow
requests administration: write but the caller job doesn't grant it; update the
caller workflow (.github/workflows/claude.yml) to add administration: write to
the permissions block for the claude-code job so the intersection of permissions
includes admin scope; locate the claude-code job in claude.yml and add the
administration: write permission alongside the existing contents: write and
id-token: write entries to ensure admin-scoped operations in claude-code can
execute.

steps:
Comment on lines 66 to 73

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

Adding administration: write here will only affect the job-scoped GITHUB_TOKEN. In this job the action later receives github_token: ${{ secrets.GH_PAT_WORKFLOWS }} (a separate PAT), so unless that PAT is guaranteed to be present and to have equivalent admin capabilities, the new permission may not actually enable label/ruleset/discussions changes. Consider having the action default to ${{ secrets.GH_PAT_WORKFLOWS || github.token }} (or documenting that the PAT must include admin-level scopes) so the permission grant is effective.

Copilot uses AI. Check for mistakes.
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Expand All @@ -83,10 +84,45 @@ jobs:
actions: read
checks: read
claude_args: |
--allowedTools "Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr comment:*),Bash(gh issue comment:*),Bash(gh run view:*),Bash(gh run watch:*),Edit,Write"
--allowedTools "Bash(gh pr create:*),Bash(gh pr view:*),Bash(gh pr comment:*),Bash(gh issue comment:*),Bash(gh run view:*),Bash(gh run watch:*),Bash(gh api:*),Bash(gh label create:*),Edit,Write"
prompt: |
Implement a fix for issue #${{ github.event.issue.number }}.

**Standards-conformance rules — read these before writing any code:**

- **For workflow files** (`.github/workflows/*.yml`): if a template
exists in `petry-projects/.github/standards/workflows/` for what
you're adding, **copy it verbatim** rather than writing from
scratch. Available templates: `agent-shield.yml`, `claude.yml`,
`dependabot-automerge.yml`, `dependabot-rebase.yml`,
`dependency-audit.yml`, `feature-ideation.yml`. Fetch via:
`gh api repos/petry-projects/.github/contents/standards/workflows/<file>.yml --jq '.content' | base64 -d`

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

The new prompt suggests fetching workflow templates via the contents API and piping through base64 -d, but base64 isn't included in --allowedTools (only gh api is). Either allow Bash(base64:*) (and likely redirection) or change the suggested fetch command to use gh api -H "Accept: application/vnd.github.raw" ... > .github/workflows/<file>.yml so it works with the current tool allowlist.

Suggested change
`gh api repos/petry-projects/.github/contents/standards/workflows/<file>.yml --jq '.content' | base64 -d`
`gh api -H "Accept: application/vnd.github.raw" repos/petry-projects/.github/contents/standards/workflows/<file>.yml > .github/workflows/<file>.yml`

Copilot uses AI. Check for mistakes.
Adapt only when the file genuinely needs repo-specific content.
Comment on lines +100 to +105

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

Similarly, this prompt lists claude.yml as one of the standards/workflows/ templates to copy verbatim, but standards/workflows/claude.yml is not currently a thin caller (it runs the Claude action directly). That makes the instruction ambiguous for repos trying to follow the new “template-first” rule; align the prompt with the actual template, or update the template to match the reusable-workflow delegation model.

Suggested change
you're adding, **copy it verbatim** rather than writing from
scratch. Available templates: `agent-shield.yml`, `claude.yml`,
`dependabot-automerge.yml`, `dependabot-rebase.yml`,
`dependency-audit.yml`, `feature-ideation.yml`. Fetch via:
`gh api repos/petry-projects/.github/contents/standards/workflows/<file>.yml --jq '.content' | base64 -d`
Adapt only when the file genuinely needs repo-specific content.
you're adding, use that template instead of writing from scratch.
Available templates: `agent-shield.yml`, `claude.yml`,
`dependabot-automerge.yml`, `dependabot-rebase.yml`,
`dependency-audit.yml`, `feature-ideation.yml`. Fetch via:
`gh api repos/petry-projects/.github/contents/standards/workflows/<file>.yml --jq '.content' | base64 -d`
For `claude.yml`, copy the standard thin caller template and keep
it delegating to the reusable Claude workflow rather than running
the Claude action inline. Adapt templates only when the file
genuinely needs repo-specific content.

Copilot uses AI. Check for mistakes.

- **For org standards** (labels, settings, rulesets, CODEOWNERS):
read `petry-projects/.github/standards/` first via `gh api`.
Match colors, names, and structure exactly. The full standards
tree is at `petry-projects/.github/tree/main/standards/`.

- **For SHA pinning** (Action Pinning Policy in
`standards/ci-standards.md`): never guess or fabricate SHAs.
Always look them up:
* Tags: `gh api repos/{owner}/{repo}/git/refs/tags/{tag} --jq '.object.sha'`
* Branches: `gh api repos/{owner}/{repo}/branches/{branch} --jq '.commit.sha'`
If the lookup fails, do not pin — open the PR with the action
still using its tag and clearly explain the blocker in the PR
body so a human can complete the fix.

- **For CodeQL** (`codeql.yml`): all ecosystems present in the repo
MUST be configured as CodeQL languages. Repos with
`.github/workflows/*.yml` files MUST scan the `actions`
ecosystem. Use a matrix strategy for multi-language repos.

- **Do not skip the work** if previous comments say "blocked": the
prior infrastructure issues that produced those comments may
have been resolved. Attempt the fix; if you hit a *new* error,
report the actual error message rather than referring to history.

After implementing:
1. Create a pull request with a clear title and description. Include "Closes #${{ github.event.issue.number }}" in the PR body.
2. Self-review your own PR — look for bugs, style issues, missed edge cases, and test gaps. If you find problems, push fixes.
Expand Down
18 changes: 18 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@

---

## Organization Standards

The full set of org standards lives at
**[`petry-projects/.github/tree/main/standards/`](https://github.com/petry-projects/.github/tree/main/standards)**.
Read the relevant standard *before* making changes that touch CI, repo settings, agent configuration, or labels.

| Topic | Standard | What it covers |
|-------|----------|----------------|
| **CI/CD workflows** | [`standards/ci-standards.md`](https://github.com/petry-projects/.github/blob/main/standards/ci-standards.md) | Required workflows, action pinning, permissions, job naming, tech-stack patterns |
| **Workflow templates** | [`standards/workflows/`](https://github.com/petry-projects/.github/tree/main/standards/workflows) | Copy-paste-ready templates: `agent-shield.yml`, `claude.yml`, `dependabot-automerge.yml`, `dependabot-rebase.yml`, `dependency-audit.yml`, `feature-ideation.yml` |
| **Agent configuration** | [`standards/agent-standards.md`](https://github.com/petry-projects/.github/blob/main/standards/agent-standards.md) | CLAUDE.md / AGENTS.md / SKILL.md required structure, frontmatter rules, cross-references |
| **Repo settings + labels** | [`standards/github-settings.md`](https://github.com/petry-projects/.github/blob/main/standards/github-settings.md) | Required settings, label set with exact colors, code-quality ruleset, branch protection |
| **Dependabot config** | [`standards/dependabot-policy.md`](https://github.com/petry-projects/.github/blob/main/standards/dependabot-policy.md) and [`standards/dependabot/`](https://github.com/petry-projects/.github/tree/main/standards/dependabot) | Per-ecosystem dependabot.yml templates and policy |

**When fixing a compliance finding, the rule is: read the standard, then copy the template — do not generate from scratch.** Anything generated from scratch is, by definition, drift from the standard. If a needed standard or template is missing, file an issue against `petry-projects/.github` rather than diverging silently.

Check failure on line 24 in AGENTS.md

View workflow job for this annotation

GitHub Actions / Lint

Line length

AGENTS.md:24:201 MD013/line-length Line length [Expected: 200; Actual: 324] https://github.com/DavidAnson/markdownlint/blob/v0.40.0/doc/md013.md
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

---

## Project Context

- **Assume brownfield.** When exploring a repo, check for existing source code before assuming it is greenfield.
Expand Down
69 changes: 68 additions & 1 deletion standards/ci-standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,39 @@ repository must implement.

---

## Using Templates from `standards/workflows/`

> **Rule:** When fixing a compliance finding by adding a workflow file, **copy
> the template from [`standards/workflows/`](workflows/) verbatim.** Do not
> generate the file from scratch, even if the change seems trivial. The
> templates are the source of truth — anything generated from scratch is, by
> definition, drift.

Available templates:

| Template | Purpose |
|----------|---------|
| [`agent-shield.yml`](workflows/agent-shield.yml) | Deep agent-config security scan via `ecc-agentshield` |
| [`claude.yml`](workflows/claude.yml) | Thin caller delegating to the org-level reusable Claude Code workflow |
| [`dependabot-automerge.yml`](workflows/dependabot-automerge.yml) | Auto-approve and squash-merge eligible Dependabot PRs |
| [`dependabot-rebase.yml`](workflows/dependabot-rebase.yml) | Rebase Dependabot PRs on demand |
| [`dependency-audit.yml`](workflows/dependency-audit.yml) | Multi-ecosystem audit (npm, pnpm, gomod, cargo, pip) |
| [`feature-ideation.yml`](workflows/feature-ideation.yml) | BMAD Method ideation pipeline (BMAD-enabled repos only) |
Comment on lines +19 to +26

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

claude.yml is described here as a “thin caller delegating to the org-level reusable Claude Code workflow”, but the actual standards/workflows/claude.yml file currently contains the full workflow (it runs anthropics/claude-code-action directly rather than uses: .../claude-code-reusable.yml). This mismatch will confuse consumers and undermines the new “copy templates verbatim” rule; either update the template to match the thin-caller model or adjust this description to match reality.

Copilot uses AI. Check for mistakes.

**Adapt only when the template genuinely requires repo-specific content** (e.g., a
project name in a comment, a different cron schedule for a known reason). Anything
beyond surface adaptation indicates either a missing template or a missing standard
— file an issue against `petry-projects/.github` rather than diverging silently.

**Fetching a template programmatically** (e.g., from a Claude Code automation run):

```bash
gh api repos/petry-projects/.github/contents/standards/workflows/<file>.yml \
--jq '.content' | base64 -d > .github/workflows/<file>.yml
```

---

## Required Workflows

Every repository MUST have these 7 workflows. Reusable templates for Dependabot
Expand Down Expand Up @@ -544,6 +577,31 @@ version for human readability.
Dependabot keeps pinned SHAs up to date via the `github-actions` ecosystem
entry in `dependabot.yml`.

### Looking Up the Correct SHA

> **Never guess or fabricate a SHA.** A SHA that doesn't exist in the upstream
> repo will fail at runtime — and worse, may "pass CI" if the job that uses it
> is conditionally skipped, leaving a latent failure waiting to bite the next
> developer.

Use the GitHub API to resolve a tag or branch to its current commit SHA:

```bash
# For a tag (e.g., v6.0.2)
gh api repos/actions/checkout/git/refs/tags/v6.0.2 --jq '.object.sha'

# For a branch (e.g., stable)
gh api repos/dtolnay/rust-toolchain/branches/stable --jq '.commit.sha'

# Verify a SHA exists in the upstream repo before pinning
gh api repos/actions/checkout/commits/de0fac2e4500dabe0009e67214ff5f5447ce83dd --jq '.sha'
```

**If the lookup fails or the network is unavailable, do not pin.** Leave the
action with its tag reference and document the blocker in the PR body so a
human can complete the fix. A correct unpinned reference is better than an
incorrect pinned one.

> **Note on examples in this document:** The "Workflow Patterns by Tech Stack"
> section uses tag references (e.g., `@v4`) for readability since those are
> illustrative patterns, not copy-paste templates. The "Required Workflows"
Expand Down Expand Up @@ -576,10 +634,19 @@ For single-job workflows, top-level least-privilege permissions are acceptable
|----------|------------|
| CI (build/test) | `contents: read` |
| SonarCloud | `contents: read`, `pull-requests: read` |
| Claude Code | `contents: write`, `id-token: write`, `pull-requests: write`, `issues: write`, `actions: read`, `checks: read` |
| Claude Code | `contents: write`, `id-token: write`, `pull-requests: write`, `issues: write`, `actions: read`, `checks: read`, `administration: write` |
| CodeQL | `actions: read`, `security-events: write`, `contents: read` |
| Dependabot auto-merge | `contents: read`, `pull-requests: read` (+ app token for merge) |

> **Note on Claude Code `administration: write`:** Required so the
> `claude-issue` job can autonomously create labels, repository rulesets, and
> enable settings like Discussions. Without it, compliance fixes that touch
> repo-level configuration (Discussions, code-quality ruleset, missing
> labels) require manual human action. The grant only takes effect on the
> `claude-issue` job in the reusable workflow — repo-level callers don't
> need to set it themselves because they use `secrets: inherit` and inherit
> the called workflow's permission shape via the intersection rule.

Copilot AI Apr 8, 2026

Copy link

Choose a reason for hiding this comment

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

This note describes the reusable-workflow permissions model incorrectly. For workflow_call, the called workflow’s GITHUB_TOKEN permissions are the intersection of (a) the caller job’s permissions and (b) the called workflow job’s permissions — so adding administration: write only in the reusable workflow will NOT take effect unless caller workflows also grant administration: write on the uses: job. secrets: inherit does not impact token permissions. Recommend updating the note and ensuring the standards/workflows/claude.yml template (and this repo’s .github/workflows/claude.yml) include administration: write when the automation job needs it.

Suggested change
> labels) require manual human action. The grant only takes effect on the
> `claude-issue` job in the reusable workflow — repo-level callers don't
> need to set it themselves because they use `secrets: inherit` and inherit
> the called workflow's permission shape via the intersection rule.
> labels) require manual human action. For reusable workflows invoked via
> `workflow_call`, the effective `GITHUB_TOKEN` permissions are the
> intersection of the caller job's `permissions` and the called workflow
> job's `permissions`, so adding `administration: write` only in the reusable
> workflow is not sufficient. Caller workflows must also grant
> `administration: write` on the `uses:` job when this automation needs
> repo-level administration access. `secrets: inherit` passes secrets only
> and does not affect token permissions.

Copilot uses AI. Check for mistakes.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

---

## Organization-Level Secrets for Standard CI
Expand Down
Loading