Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions standards/agent-standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ Every repository MUST have:
| `CLAUDE.md` | Project-level instructions for Claude Code | error if missing |
| `AGENTS.md` | Development standards for AI agents | error if missing |

## Compliance Exemptions — Files Agents Must Not Modify

The following files are structurally immutable. Agents must not open PRs that
modify them. No compliance finding will ever require a change to these files;
if an existing agent-created PR touches them, close it without merging.

**Canonical source:** [`standards/workflow-exemptions.json`](workflow-exemptions.json)

| File | Reason |
|------|--------|
| `.github/workflows/claude.yml` | Anthropic OIDC invariant — any diff from the default branch causes `401 Workflow validation failed`; Claude Code cannot run on that PR |
| `.github/workflows/agent-shield.yml` | Security boundary — agents are not permitted to weaken security scanning; changes require explicit human review |

These files must be adopted verbatim from `standards/workflows/` and updated
only by merging a standards PR from `petry-projects/.github`, which propagates
to all repos via the `@v1` tag bump.

Comment on lines +17 to +33

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

LGTM — exemption section is well-scoped.

Clear rationale per file, and the "adopt verbatim / updated only via standards PR" instruction lines up with the Tier 1 stub contract in ci-standards.md. The LanguageTool "GitHub" capitalization hints on lines 25/26/29 are false positives — these are literal path/repo identifiers.

Minor suggestion: consider adding a machine-readable signal (e.g., a known list consumed by scripts/compliance-audit.sh) so the exemption is enforced at PR-open time rather than relying on agents reading this doc. Otherwise an agent that skips the doc will still attempt a compliance PR against claude.yml.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~25-~25: The official name of this software platform is spelled with a capital “H”.
Context: ... | File | Reason | |------|--------| | .github/workflows/claude.yml | Anthropic OIDC ...

(GITHUB)


[uncategorized] ~26-~26: The official name of this software platform is spelled with a capital “H”.
Context: ...; Claude Code cannot run on that PR | | .github/workflows/agent-shield.yml | Security ...

(GITHUB)


[uncategorized] ~29-~29: The official name of this software platform is spelled with a capital “H”.
Context: ...ted only by merging a standards PR from petry-projects/.github, which propagates to all repos via the...

(GITHUB)

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

In `@standards/agent-standards.md` around lines 17 - 31, Add a machine-readable
exemption list and wire it into the existing compliance check so agents can’t
open PRs that modify those immutable workflow files: create a small JSON or YAML
file (e.g., a single-key list containing ".github/workflows/claude.yml" and
".github/workflows/agent-shield.yml" and any future entries) and update
scripts/compliance-audit.sh to read that file and reject PRs touching any listed
paths; also add a one-line reference in agent-standards.md next to the exemption
table pointing to this machine-readable source (and mention that the canonical
source of truth is the standards/workflows/ adoption process) so humans and
automation reference the same list.

### CLAUDE.md Requirements

- MUST reference `AGENTS.md` for development standards
Expand Down
42 changes: 42 additions & 0 deletions standards/ci-standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,24 @@ Each repo needs a `sonar-project.properties` file at root with project key and o
AI-assisted code review on PRs and issue automation via Claude Code Action.
A copy-paste ready template is available at [`standards/workflows/claude.yml`](workflows/claude.yml).

> **OIDC security constraint — `claude.yml` is immutable on PR branches.**
> Anthropic's token endpoint validates that `.github/workflows/claude.yml` on
> a PR branch is byte-for-byte identical to the same file on the default branch.
> Any diff — including SHA-pinning the `uses:` line, adding a trigger, or
> changing a comment — causes the OIDC token exchange to fail:
>
> ```text
> App token exchange failed: 401 Unauthorized — Workflow validation failed.
> The workflow file must exist and have identical content to the version
> on the repository's default branch.
> ```
>
> Claude Code will not run on that PR. Agents must not open PRs that modify
> `.github/workflows/claude.yml`. The caller stub template now includes a
> `paths-ignore` guard that prevents this workflow from triggering on PRs that
> only change this file. See also [Action Pinning Policy](#action-pinning-policy)
> for the reusable workflow ref exemption.
>
> **All three jobs require a checkout step.** The `claude` job (PR reviews), the
> `claude-issue` job (issue automation), and the `claude-ci-fix` job (CI failure
> response) each need `actions/checkout` **before** the `claude-code-action` step.
Expand Down Expand Up @@ -737,6 +755,30 @@ incorrect pinned one.
> example to a repository, always look up the current SHA for each action and
> pin to it with a version comment.

### Exception: Internal Reusable Workflow References

Calls to `petry-projects/.github` reusable workflows use tag references
(`@v1`, `@main`) — **not SHA pins** — and are exempt from this policy.

```yaml
# CORRECT — tag ref for internal reusable workflow
uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@v1

# WRONG — do not SHA-pin internal reusable workflow refs
uses: petry-projects/.github/.github/workflows/claude-code-reusable.yml@ee22b427cbce9ecadcf2b436acb57c3adf0cb63d
```

**Why:** Pinning the `uses:` line in a Tier 1 caller stub creates a diff from
the default branch. Anthropic's OIDC token endpoint validates that
`.github/workflows/claude.yml` on a PR branch is identical to the default
branch — any diff causes `401 Workflow validation failed` and Claude Code
cannot run on that PR.

The `@v1` tag on `petry-projects/.github` is managed deliberately (bumped only
on backward-compatible releases) and is not subject to tag-force-push risk
because the org controls the tag. **Do not open compliance PRs to pin these
references.**

Comment on lines +758 to +781

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
rg -nP -C3 'check_action_pinning|unpinned-actions' scripts/compliance-audit.sh

Repository: petry-projects/.github

Length of output: 998


🏁 Script executed:

sed -n '186,250p' scripts/compliance-audit.sh

Repository: petry-projects/.github

Length of output: 2532


🏁 Script executed:

rg -n 'petry-projects.*\.github' scripts/compliance-audit.sh | head -20

Repository: petry-projects/.github

Length of output: 2479


🏁 Script executed:

rg -n '@v1|@main' scripts/compliance-audit.sh | grep -i 'filter\|exempt\|exclude'

Repository: petry-projects/.github

Length of output: 48


🏁 Script executed:

sed -n '756,779p' standards/ci-standards.md

Repository: petry-projects/.github

Length of output: 1137


Add whitelist for petry-projects/.github reusable workflow tag refs to check_action_pinning().

The check_action_pinning() function currently lacks a filter to exempt petry-projects/.github/** reusable workflows tagged with @v1 or @main. Without this whitelist, the audit will flag these exempted refs as unpinned and create compliance PRs attempting to pin them to SHA, defeating the purpose of the exemption documented in ci-standards.md (lines 756–779). Update the grep filter to exclude petry-projects/.github/**@(v1|main) patterns.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~758-~758: The official name of this software platform is spelled with a capital “H”.
Context: ... Reusable Workflow References Calls to petry-projects/.github reusable workflows use tag references ...

(GITHUB)


[uncategorized] ~770-~770: The official name of this software platform is spelled with a capital “H”.
Context: ...ic's OIDC token endpoint validates that .github/workflows/claude.yml on a PR branch is...

(GITHUB)


[uncategorized] ~775-~775: The official name of this software platform is spelled with a capital “H”.
Context: ...annot run on that PR. The @v1 tag on petry-projects/.github is managed deliberately (bumped only o...

(GITHUB)

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

In `@standards/ci-standards.md` around lines 756 - 779, The check_action_pinning()
audit currently flags tag refs for internal reusable workflows; update its
grep/filter logic so it explicitly excludes petry-projects/.github
reusable-workflow tag refs (e.g. patterns matching
petry-projects/.github/**@(v1|main)); modify the filter used in
check_action_pinning() to add a negative match or whitelist for
petry-projects/.github/**@(v1|main) so those tag refs are skipped and not
reported or used to create compliance PRs.

---

## Permissions Policy
Expand Down
15 changes: 15 additions & 0 deletions standards/workflow-exemptions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"immutable_files": [
{
"path": ".github/workflows/claude.yml",
"reason": "OIDC invariant — any diff causes 401 Workflow validation failed",
"requires_human_review": true
},
{
"path": ".github/workflows/agent-shield.yml",
"reason": "Security boundary — agents cannot weaken security scanning",
"requires_human_review": true
}
]
}

2 changes: 1 addition & 1 deletion standards/workflows/auto-rebase.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ jobs:
contents: write # update-branch via GITHUB_TOKEN (may touch .github/workflows/)
pull-requests: write # post comments on PRs
uses: petry-projects/.github/.github/workflows/auto-rebase-reusable.yml@v1
secrets: inherit
secrets: inherit
19 changes: 19 additions & 0 deletions standards/workflows/claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@
# or `secrets: inherit`. These are required for the reusable to work.
# • If you need different behaviour, open a PR against the reusable in the
# central repo. The change will propagate everywhere on next run.
#
# WHY THIS FILE IS IMMUTABLE (agents: read before opening any PR here):
# Anthropic's OIDC token endpoint validates that this file on a PR branch
# is byte-for-byte identical to the file on the default branch. Any diff —
# even a whitespace or comment change — causes the token exchange to fail:
# "401 Unauthorized — Workflow validation failed"
# Claude Code will not run on that PR. Do not open compliance PRs against
# this file. Do not SHA-pin the `uses:` line — internal reusable workflow
# refs are exempt from the Action Pinning Policy (ci-standards.md
# §Action Pinning Policy). The @v1 tag is the correct, stable reference.
#
# NARROW GUARD: The paths-ignore setting (lines 38-39) under pull_request

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 | 🟡 Minor

Stale line reference in NARROW GUARD comment.

The comment says paths-ignore setting (lines 38-39) but the actual paths-ignore block is at lines 45-46 in this file. Either remove the line numbers (recommended — they will drift again on any future edit and any change here invalidates the OIDC byte-for-byte invariant for downstream repos until @v1 is bumped) or correct them.

📝 Proposed fix
-#   NARROW GUARD: The paths-ignore setting (lines 38-39) under pull_request
-#   prevents the workflow from triggering only when the PR's entire changeset
-#   is limited to claude.yml alone. PRs that modify claude.yml *plus other
-#   files* will still trigger the workflow and hit the 401 error at token
-#   exchange. Other triggers (issue_comment, pull_request_review_comment,
-#   issues, check_run) are unaffected by paths-ignore and run as configured.
+#   NARROW GUARD: The paths-ignore setting under `pull_request` (below)
+#   prevents the workflow from triggering only when the PR's entire changeset
+#   is limited to claude.yml alone. PRs that modify claude.yml *plus other
+#   files* will still trigger the workflow and hit the 401 error at token
+#   exchange. Other triggers (issue_comment, pull_request_review_comment,
+#   issues, check_run) are unaffected by paths-ignore and run as configured.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# NARROW GUARD: The paths-ignore setting (lines 38-39) under pull_request
# NARROW GUARD: The paths-ignore setting under `pull_request` (below)
# prevents the workflow from triggering only when the PR's entire changeset
# is limited to claude.yml alone. PRs that modify claude.yml *plus other
# files* will still trigger the workflow and hit the 401 error at token
# exchange. Other triggers (issue_comment, pull_request_review_comment,
# issues, check_run) are unaffected by paths-ignore and run as configured.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@standards/workflows/claude.yml` at line 25, The "NARROW GUARD" comment
referencing "paths-ignore setting (lines 38-39)" is stale; update the NARROW
GUARD comment that references the paths-ignore block so it no longer contains
hard-coded line numbers (recommended) or correct the numbers to match the
current position of the paths-ignore block; edit the comment text in the
claude.yml NARROW GUARD section to either remove the "(lines ...)" portion or
replace it with a stable description pointing to the "paths-ignore" block so
future edits won't drift.

# prevents the workflow from triggering only when the PR's entire changeset
# is limited to claude.yml alone. PRs that modify claude.yml *plus other
# files* will still trigger the workflow and hit the 401 error at token
# exchange. Other triggers (issue_comment, pull_request_review_comment,
# issues, check_run) are unaffected by paths-ignore and run as configured.
Comment on lines +25 to +30

Copilot AI Apr 25, 2026

Copy link

Choose a reason for hiding this comment

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

The header comment calls out specific line numbers for the paths-ignore block ("lines 38-39"), but those line numbers are already out of date. To avoid future drift/misleading guidance, consider removing the line-number reference and instead point to the on.pull_request.paths-ignore section (or update the reference).

Suggested change
# NARROW GUARD: The paths-ignore setting (lines 38-39) under pull_request
# prevents the workflow from triggering only when the PR's entire changeset
# is limited to claude.yml alone. PRs that modify claude.yml *plus other
# files* will still trigger the workflow and hit the 401 error at token
# exchange. Other triggers (issue_comment, pull_request_review_comment,
# issues, check_run) are unaffected by paths-ignore and run as configured.
# NARROW GUARD: The on.pull_request.paths-ignore setting prevents the
# workflow from triggering only when the PR's entire changeset is limited
# to claude.yml alone. PRs that modify claude.yml *plus other files* will
# still trigger the workflow and hit the 401 error at token exchange.
# Other triggers (issue_comment, pull_request_review_comment, issues,
# check_run) are unaffected by paths-ignore and run as configured.

Copilot uses AI. Check for mistakes.
# ─────────────────────────────────────────────────────────────────────────────
#
# Claude Code — thin caller that delegates to the org-level reusable workflow.
Expand All @@ -25,6 +42,8 @@ on:
pull_request:
branches: [main]
types: [opened, reopened, synchronize]
paths-ignore:
- '.github/workflows/claude.yml' # OIDC invariant — see header above
issue_comment:
types: [created]
pull_request_review_comment:
Expand Down
Loading