feat: add composite actions, enhanced governance, and GitHub Issue reports#7
feat: add composite actions, enhanced governance, and GitHub Issue reports#7
Conversation
…ports - Add composite actions: security-scan, sync-settings, update-pre-commit - Replace SMTP email with GitHub Issues for drift reporting - Add label sync, default branch check, vulnerability alerts, metadata checks - Enhance README with detailed purpose for every enforced setting - Add baseline schema validation to quality checks - Refactor workflows to use composite actions
📝 WalkthroughWalkthroughAdds three composite GitHub Actions and refactors workflows to use them; extends baseline with vulnerability_alerts and labels; enhances the sync script with label, vulnerability, default-branch and metadata checks; updates CI/workflow behaviors and adds extensive docs, runbooks, and CLAUDE skills. Changes
Sequence Diagram(s)sequenceDiagram
participant Workflow as "Workflow"
participant Composite as "sync-settings Action"
participant Script as "sync-repo-settings.sh"
participant GitHub as "GitHub API"
participant IssueMgr as "Issue Manager"
Workflow->>Composite: invoke(mode, github_token)
Composite->>Script: run sync (dry-run/apply)
Script->>GitHub: list repos / fetch repo state
GitHub-->>Script: repo list & current state
Script->>Script: compute effective config (baseline + overrides)
Script->>Script: detect drift (labels, vuln alerts, branch, metadata, etc.)
alt apply mode
Script->>GitHub: PATCH/PUT to apply fixes
GitHub-->>Script: apply responses
end
Script-->>Composite: emit report + outputs
Composite-->>Workflow: return report, outputs
Workflow->>IssueMgr: if drift -> close old issues, create new drift issue
IssueMgr->>GitHub: create/close issue(s)
Workflow->>GitHub: upload artifact & update job summary
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Pull request overview
This PR adds composite actions, replaces SMTP email delivery with GitHub Issues for drift reporting, and enhances the sync script with several new checks (vulnerability alerts, label standardization, default branch validation, and repository metadata checks). The baseline JSON is extended with vulnerability_alerts and labels sections, workflows are refactored to use composite actions, and a baseline schema validation step is added to quality checks. The README is comprehensively rewritten to document every enforced setting.
Changes:
- Add 3 composite actions (
security-scan,sync-settings,update-pre-commit-composite) and refactor all workflows to use them; replace SMTP email delivery with GitHub Issue creation/closure for drift and new-repo reporting - Extend
sync-repo-settings.shwith new functions:sync_vulnerability_alerts,sync_labels,check_default_branch,check_repo_metadata; add correspondingvulnerability_alertsandlabelssections toconfig/baseline.json - Rewrite
README.mdwith detailed documentation of every enforced setting, add baseline JSON schema validation toquality-checks.yml, and updateCLAUDE.mdwith composite action and sync details
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
scripts/sync-repo-settings.sh |
Adds 4 new functions for vuln alerts, labels, default branch, and metadata checks; integrates them into main loop |
config/baseline.json |
Adds vulnerability_alerts under security and a new labels array with 6 standard labels |
README.md |
Complete rewrite with detailed settings tables, architecture diagram, and composite action documentation |
CLAUDE.md |
Updates overview to mention composite actions, GitHub Issues, and details on sync script enforcement |
.secrets.baseline |
Updated timestamp only |
.github/workflows/sync-settings.yml |
Refactored to use sync-settings composite action; adds GitHub Issue creation/closure for drift and new repos |
.github/workflows/security.yml |
Refactored to use security-scan composite action; adds actions: read permission |
.github/workflows/quality-checks.yml |
Adds baseline JSON schema validation step |
.github/workflows/update-pre-commit-hooks.yml |
Refactored to use update-pre-commit-composite action |
.github/actions/sync-settings/action.yml |
New composite action wrapping sync script and report parsing |
.github/actions/security-scan/action.yml |
New composite action wrapping Semgrep and Trivy scans |
.github/actions/update-pre-commit-composite/action.yml |
New composite action wrapping pre-commit autoupdate and PR creation |
scripts/sync-repo-settings.sh
Outdated
| echo "$effective" | jq -c '.labels[]' 2>/dev/null | while read -r label_json; do | ||
| local name color description | ||
| name=$(echo "$label_json" | jq -r '.name') | ||
| color=$(echo "$label_json" | jq -r '.color') | ||
| description=$(echo "$label_json" | jq -r '.description') | ||
|
|
||
| if ! echo "$current_labels" | grep -qx "$name"; then | ||
| changes="${changes}- Label missing: \`$name\`\n" | ||
| if [ "$MODE" = "--apply" ]; then | ||
| gh api -X POST "repos/$OWNER/$repo/labels" \ | ||
| -f name="$name" -f color="$color" -f description="$description" \ | ||
| > /dev/null 2>&1 || log "WARN: Could not create label $name for $repo" | ||
| fi | ||
| fi | ||
| done | ||
| echo -e "$changes" |
There was a problem hiding this comment.
The while read loop runs in a subshell because it's on the right side of a pipe (jq ... | while read). Any modifications to the changes variable inside the loop are lost when the subshell exits, so echo -e "$changes" on line 343 will always output an empty string. This means label drift is never reported.
Use process substitution instead of a pipe to keep the loop in the current shell, e.g., while read -r label_json; do ... done < <(echo "$effective" | jq -c '.labels[]' 2>/dev/null). This matches the pattern used elsewhere in the script where variables are accumulated.
| run: | | ||
| ./scripts/sync-repo-settings.sh "${{ inputs.mode }}" |
There was a problem hiding this comment.
${{ inputs.mode }} is directly interpolated into the run: shell command, which is a script injection risk. Although the current caller constrains this input to a choice type with fixed values, the composite action itself doesn't validate the input. If reused by another workflow that passes untrusted input, this could allow arbitrary command execution.
Pass the input via an environment variable instead (e.g., env: MODE: ${{ inputs.mode }}), and reference it as "$MODE" in the script. This follows the recommended GitHub Actions security practice of never using ${{ }} expressions directly in run: blocks.
| # Check for missing description and topics | ||
| check_repo_metadata() { | ||
| local repo="$1" | ||
| local changes="" | ||
|
|
||
| local current | ||
| current=$(gh api "repos/$OWNER/$repo" 2>/dev/null) || return | ||
|
|
||
| local description | ||
| description=$(echo "$current" | jq -r '.description // ""') | ||
| if [ -z "$description" ] || [ "$description" = "null" ]; then | ||
| changes="${changes}- **Missing repository description**\n" | ||
| fi | ||
|
|
||
| local topics | ||
| topics=$(echo "$current" | jq -r '.topics | length') | ||
| if [ "$topics" = "0" ]; then | ||
| changes="${changes}- **No repository topics configured**\n" | ||
| fi | ||
|
|
||
| if [ -n "$changes" ]; then | ||
| log "WARN: metadata gaps for $repo" | ||
| else | ||
| log "OK: metadata for $repo" | ||
| fi | ||
| echo -e "$changes" | ||
| } |
There was a problem hiding this comment.
check_default_branch, sync_repo_settings, sync_security, sync_vulnerability_alerts, and check_repo_metadata each independently call gh api "repos/$OWNER/$repo", resulting in at least 4-5 API calls to the same endpoint per repository per sync run. With the GitHub API rate limit of 5,000 requests/hour for authenticated users, this could become a problem as the number of repositories grows.
Consider fetching the repo data once at the start of the per-repo loop in main() and passing it to each function, or caching the result in a temporary variable.
scripts/sync-repo-settings.sh
Outdated
| color=$(echo "$label_json" | jq -r '.color') | ||
| description=$(echo "$label_json" | jq -r '.description') | ||
|
|
||
| if ! echo "$current_labels" | grep -qx "$name"; then |
There was a problem hiding this comment.
grep -qx "$name" interprets $name as a regex pattern. If a label name ever contains regex metacharacters (e.g., ., +, *), this check could produce false matches or miss real matches. Consider using grep -qxF "$name" to treat the name as a fixed string.
There was a problem hiding this comment.
Actionable comments posted: 8
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/quality-checks.yml:
- Around line 82-96: The current "Validate baseline schema" shell block only
checks top-level section presence; update it to validate required nested keys
and label fields using jq so missing subkeys fail CI. Replace or extend the loop
that iterates sections (repo_settings, security, branch_protection, labels,
required_files) with explicit jq checks such as verifying
.security.vulnerability_alerts exists and is an object, and that .labels is an
array with every element containing .color and .description (e.g. fail if any
.labels[] | select(.color==null or .description==null) is found); ensure ERRORS
increments and the script exits non‑zero with a clear message when any nested
validation fails.
In @.github/workflows/sync-settings.yml:
- Around line 62-95: Change the "Create or update drift issue" flow to create
the new issue before closing old ones and only retire older "settings-drift"
issues if the gh issue create command (in the step named "Create or update drift
issue") succeeds; use the gh issue create output (or check its exit status) to
conditionally run the close loop that calls gh issue close, and ensure the
"Close drift issue if compliant" step still only runs when
steps.sync.outputs.has_drift == 'false'. Also add a workflow-level concurrency
key (e.g., concurrency: group: settings-drift-sync-${{ github.ref }} or a static
group) to serialize runs and avoid races between overlapping executions.
- Around line 18-20: Remove the unused ambient write permission by deleting the
"issues: write" entry from the permissions block (leave "contents: read"
intact); this ensures the workflow only requests least-privilege scopes since
the workflow uses secrets.ORG_SETTINGS_PAT for mutating calls rather than
GITHUB_TOKEN.
- Around line 117-119: The gh repo list invocation that populates NEW_REPOS
currently uses a hard cap (--limit 200) which can omit repos; update the command
used to set NEW_REPOS (the gh repo list ... --jq ... assignment) by removing the
--limit 200 flag entirely (or replace it with --limit 1000 if you want a
practical upper bound) so all non-archived repositories created after $WEEK_AGO
are returned.
In `@scripts/sync-repo-settings.sh`:
- Around line 347-358: The check_default_branch function currently hardcodes
"main" as the expected branch; update it to call get_effective_settings "$repo"
and read the expected branch from the resulting .branch_protection.branch value
(e.g., store it in a variable like expected_branch), then use that variable
instead of the literal "main" for both the comparison that sets changes and the
gh api -X PATCH default_branch payload (respecting MODE). Also adjust the
warning/log text to reference expected_branch and ensure you handle the case
when .branch_protection.branch is empty by falling back to a sensible default or
skipping the patch.
- Around line 334-340: The script only checks for presence of a label name via
current_labels/grep and never verifies color/description, so update logic should
compare existing label attributes and patch mismatches: when iterating each
desired label (variables name, color, description) fetch the existing label data
(using gh api repos/$OWNER/$repo/labels/$name or from the current_labels JSON),
parse its color and description, and if either differs then treat it as a change
and, when MODE="--apply", call gh api -X PATCH "repos/$OWNER/$repo/labels/$name"
with -f color and -f description to update the label; keep the existing create
branch if label missing, and reuse log for warnings (log function) when PATCH
fails.
- Around line 145-148: The current check uses want_alerts=$(echo "$effective" |
jq -r '.security.vulnerability_alerts // false') and returns whenever
want_alerts != "true", which skips explicit false overrides; change the logic so
the script only returns when the vulnerability_alerts field is absent/unset, not
when it's explicitly false. Use jq to detect presence (e.g., extract a sentinel
like null when the key is missing or use has("vulnerability_alerts") on
.security) and then: if the field is missing return, otherwise continue and
handle "true" vs "false" values from want_alerts; update the conditional around
the early return (the block using want_alerts, effective, and the return)
accordingly.
- Around line 328-343: The problem is the piped while loop reading jq output
runs in a subshell so updates to the shared variable "changes" are lost; to fix
it, initialize changes before the loop and replace the piped construct with a
same-shell loop (e.g., use process substitution: while read -r label_json; do
... done < <(echo "$effective" | jq -c '.labels[]' 2>/dev/null) or a
here-string) so modifications to "changes" persist, keeping the existing logic
that uses "name", "color", "description", "current_labels", "MODE" and the gh
api call unchanged. Ensure "changes" is declared/initialized in the parent shell
scope before the loop so echo -e "$changes" later prints the collected changes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 86c5a0b7-4895-475a-8e4d-0be533841e06
📒 Files selected for processing (12)
.github/actions/security-scan/action.yml.github/actions/sync-settings/action.yml.github/actions/update-pre-commit-composite/action.yml.github/workflows/quality-checks.yml.github/workflows/security.yml.github/workflows/sync-settings.yml.github/workflows/update-pre-commit-hooks.yml.secrets.baselineCLAUDE.mdREADME.mdconfig/baseline.jsonscripts/sync-repo-settings.sh
| - name: Validate baseline schema | ||
| run: | | ||
| ERRORS=0 | ||
| for section in repo_settings security branch_protection labels required_files; do | ||
| if ! jq -e ".$section" config/baseline.json > /dev/null 2>&1; then | ||
| echo "ERROR: Missing section '$section' in baseline.json" | ||
| ERRORS=$((ERRORS + 1)) | ||
| else | ||
| echo "OK: section '$section' present" | ||
| fi | ||
| done | ||
| if [ "$ERRORS" -gt 0 ]; then | ||
| echo "ERROR: baseline.json schema validation failed" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
This only checks section presence, not the baseline schema.
Lines 85-91 will still pass if security.vulnerability_alerts is missing or if a label entry omits color/description. That leaves the new baseline contract effectively unvalidated.
Suggested jq-based validation
- name: Validate baseline schema
run: |
- ERRORS=0
- for section in repo_settings security branch_protection labels required_files; do
- if ! jq -e ".$section" config/baseline.json > /dev/null 2>&1; then
- echo "ERROR: Missing section '$section' in baseline.json"
- ERRORS=$((ERRORS + 1))
- else
- echo "OK: section '$section' present"
- fi
- done
- if [ "$ERRORS" -gt 0 ]; then
- echo "ERROR: baseline.json schema validation failed"
- exit 1
- fi
+ jq -e '
+ (.repo_settings | type == "object") and
+ (.security | type == "object") and
+ (.security.vulnerability_alerts | type == "boolean") and
+ (.branch_protection | type == "object") and
+ (.required_files | type == "array") and
+ (.labels | type == "array") and
+ ([.labels[] | (.name | type == "string")
+ and (.color | type == "string" and test("^[0-9A-Fa-f]{6}$"))
+ and (.description | type == "string")] | all)
+ ' config/baseline.json >/dev/null || {
+ echo "ERROR: baseline.json schema validation failed"
+ exit 1
+ }As per coding guidelines, "Confirm the JSON structure aligns with the baseline schema validated by quality checks (Validate baseline schema step) and used by per-repo drift/metadata checks."
📝 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.
| - name: Validate baseline schema | |
| run: | | |
| ERRORS=0 | |
| for section in repo_settings security branch_protection labels required_files; do | |
| if ! jq -e ".$section" config/baseline.json > /dev/null 2>&1; then | |
| echo "ERROR: Missing section '$section' in baseline.json" | |
| ERRORS=$((ERRORS + 1)) | |
| else | |
| echo "OK: section '$section' present" | |
| fi | |
| done | |
| if [ "$ERRORS" -gt 0 ]; then | |
| echo "ERROR: baseline.json schema validation failed" | |
| exit 1 | |
| fi | |
| - name: Validate baseline schema | |
| run: | | |
| jq -e ' | |
| (.repo_settings | type == "object") and | |
| (.security | type == "object") and | |
| (.security.vulnerability_alerts | type == "boolean") and | |
| (.branch_protection | type == "object") and | |
| (.required_files | type == "array") and | |
| (.labels | type == "array") and | |
| ([.labels[] | (.name | type == "string") | |
| and (.color | type == "string" and test("^[0-9A-Fa-f]{6}$")) | |
| and (.description | type == "string")] | all) | |
| ' config/baseline.json >/dev/null || { | |
| echo "ERROR: baseline.json schema validation failed" | |
| exit 1 | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In @.github/workflows/quality-checks.yml around lines 82 - 96, The current
"Validate baseline schema" shell block only checks top-level section presence;
update it to validate required nested keys and label fields using jq so missing
subkeys fail CI. Replace or extend the loop that iterates sections
(repo_settings, security, branch_protection, labels, required_files) with
explicit jq checks such as verifying .security.vulnerability_alerts exists and
is an object, and that .labels is an array with every element containing .color
and .description (e.g. fail if any .labels[] | select(.color==null or
.description==null) is found); ensure ERRORS increments and the script exits
non‑zero with a clear message when any nested validation fails.
scripts/sync-repo-settings.sh
Outdated
| if ! echo "$current_labels" | grep -qx "$name"; then | ||
| changes="${changes}- Label missing: \`$name\`\n" | ||
| if [ "$MODE" = "--apply" ]; then | ||
| gh api -X POST "repos/$OWNER/$repo/labels" \ | ||
| -f name="$name" -f color="$color" -f description="$description" \ | ||
| > /dev/null 2>&1 || log "WARN: Could not create label $name for $repo" | ||
| fi |
There was a problem hiding this comment.
Existing labels are never standardized.
This only checks whether the label name exists. If bug is already present with the wrong color or description, it is treated as compliant and never patched, so the new baseline cannot actually standardize labels.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@scripts/sync-repo-settings.sh` around lines 334 - 340, The script only checks
for presence of a label name via current_labels/grep and never verifies
color/description, so update logic should compare existing label attributes and
patch mismatches: when iterating each desired label (variables name, color,
description) fetch the existing label data (using gh api
repos/$OWNER/$repo/labels/$name or from the current_labels JSON), parse its
color and description, and if either differs then treat it as a change and, when
MODE="--apply", call gh api -X PATCH "repos/$OWNER/$repo/labels/$name" with -f
color and -f description to update the label; keep the existing create branch if
label missing, and reuse log for warnings (log function) when PATCH fails.
- Add docs/architecture.md with system context and component overview - Add docs/runbooks/ with 4 operational procedures (exclude repo, add setting, handle drift, onboard repo) - Add 3 Claude Code skills: /audit, /add-repo-override, /exclude-repo - Update README and CLAUDE.md with new structure
… sync The PUT endpoint replaces all branch protection. Without this fix, repos without an explicit override in overrides.json would have their status check contexts wiped to an empty array. Now the script reads the current contexts from the repo and carries them forward.
Review fixes (CodeRabbit + Copilot): - Fix sync_labels subshell scoping: use process substitution instead of piped while loop so changes variable propagates correctly - Use grep -qxF instead of grep -qx to avoid regex interpretation - Read default branch from config instead of hardcoding "main" - Handle explicit false overrides for vulnerability_alerts - Remove unused issues: write permission from workflow - Create drift issue before closing old ones to prevent gap - Add concurrency group to prevent parallel sync runs - Raise repo list limit from 200 to 1000 - Add label field structure validation to baseline schema check Dependabot bumps absorbed: - actions/checkout v4.2.2 -> v6.0.2 - actions/setup-python v5.6.0 -> v6.2.0 - actions/upload-artifact v4.6.2 -> v7.0.0 - github/codeql-action v3.28.18 -> v4.32.6 - peter-evans/create-pull-request v7.0.8 -> v8.1.0 Lint fixes: - Fix MD032 (blanks around lists) in skill SKILL.md - Fix MD029 (ordered list prefix) in audit SKILL.md - Fix MD041 (first line heading) in copilot-instructions and PR template - Fix MD034 (bare URLs) in CONTRIBUTING.md and SECURITY.md - Remove unused drift_count variable (shellcheck SC2034)
- markdownlint-cli2-action: update SHA to match v22.0.0 tag - action-yamllint: update SHA to match v3.1.1 tag - trivy-action: update from v0.31.0 to v0.35.0 with correct SHA - zizmor: update from v1.5.0 to v1.23.1, use find for binary extraction
- Use env var instead of inline ${{ inputs.mode }} in sync-settings
composite action to prevent shell injection (Semgrep finding)
- Add if: always() to Trivy step so it runs regardless of Semgrep
result, preventing missing SARIF upload
- Set zizmor secrets-outside-env to info level (acceptable for
single-admin personal account without GitHub Environments)
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
.github/actions/security-scan/action.yml (1)
13-16: Consider uploading Semgrep SARIF results.Semgrep SAST results are not uploaded to GitHub Security. If Semgrep is configured to output SARIF (it can with additional options), you could upload those results alongside Trivy for consolidated security findings in the GitHub Security tab.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/actions/security-scan/action.yml around lines 13 - 16, Update the "Run Semgrep SAST" step (uses: semgrep/semgrep-action@713efdd...) to output SARIF (e.g., enable SARIF/format and write to a known file path) and add a follow-up step (e.g., "Upload Semgrep SARIF") that uses the GitHub SARIF uploader (github/codeql-action/upload-sarif@v2 or equivalent) to upload the produced SARIF file; ensure the uploader step references the same SARIF file path so Semgrep results appear in the GitHub Security tab.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/sync-settings.yml:
- Around line 90-99: The gh issue create step can fail and the script will still
proceed to close existing drift issues; fix this by capturing the output/exit
status of the create command (replace the bare `gh issue create --title "$TITLE"
--body "$BODY" --label "settings-drift"` with a form that assigns its
output/JSON to a variable and checks its exit code), ensure you extract the new
issue number into LATEST only if creation succeeded, log an error and exit
non-zero if creation failed, and only run the subsequent gh issue list / while
loop when LATEST is valid; reference the `gh issue create` invocation, the
`LATEST` assignment, and the closing loop to implement these checks.
In `@zizmor.yml`:
- Line 6: The rule entry "secrets-outside-env" in zizmor.yml is using an
unsupported bare value ("info"); update the configuration to use only allowed
per-rule options. Replace the line with a valid mapping such as
"secrets-outside-env: {}" or "secrets-outside-env: { disable: false }" (or
remove the line entirely) so the "secrets-outside-env" rule uses a supported
config shape instead of the invalid string.
---
Nitpick comments:
In @.github/actions/security-scan/action.yml:
- Around line 13-16: Update the "Run Semgrep SAST" step (uses:
semgrep/semgrep-action@713efdd...) to output SARIF (e.g., enable SARIF/format
and write to a known file path) and add a follow-up step (e.g., "Upload Semgrep
SARIF") that uses the GitHub SARIF uploader
(github/codeql-action/upload-sarif@v2 or equivalent) to upload the produced
SARIF file; ensure the uploader step references the same SARIF file path so
Semgrep results appear in the GitHub Security tab.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b892857f-0467-4896-a971-d47da98fd372
📒 Files selected for processing (26)
.claude/skills/add-repo-override/SKILL.md.claude/skills/audit/SKILL.md.claude/skills/exclude-repo/SKILL.md.github/PULL_REQUEST_TEMPLATE.md.github/actions/security-scan/action.yml.github/actions/sync-settings/action.yml.github/actions/update-pre-commit-composite/action.yml.github/copilot-instructions.md.github/workflows/quality-checks.yml.github/workflows/security.yml.github/workflows/sync-settings.yml.github/workflows/update-pre-commit-hooks.yml.secrets.baselineCLAUDE.mdCONTRIBUTING.mdREADME.mdSECURITY.mddocs/architecture.mddocs/runbooks/README.mddocs/runbooks/add-setting.mddocs/runbooks/exclude-repo.mddocs/runbooks/handle-drift.mddocs/runbooks/onboard-repo.mdscripts/generate-report.shscripts/sync-repo-settings.shzizmor.yml
💤 Files with no reviewable changes (1)
- scripts/generate-report.sh
✅ Files skipped from review due to trivial changes (7)
- .github/copilot-instructions.md
- .claude/skills/audit/SKILL.md
- docs/runbooks/onboard-repo.md
- docs/runbooks/add-setting.md
- docs/runbooks/README.md
- docs/runbooks/handle-drift.md
- SECURITY.md
🚧 Files skipped from review as they are similar to previous changes (2)
- .github/actions/sync-settings/action.yml
- .secrets.baseline
Use ignore directive with specific workflow files instead of unsupported severity level string. These workflows use secrets without GitHub Environments, which is acceptable for a single-admin personal account.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@zizmor.yml`:
- Around line 7-9: The ignore entries currently suppress all findings for the
entire workflows by listing "sync-settings.yml" and
"update-pre-commit-hooks.yml"; update these to line-specific ignores by
replacing those entries with filename:line (e.g., "sync-settings.yml:40" and
"update-pre-commit-hooks.yml:25") so only the known acceptable lines are ignored
while preserving checks for other lines; locate the "ignore:" block in
zizmor.yml and change the two list items accordingly.
zizmor.yml
Outdated
| ignore: | ||
| - sync-settings.yml | ||
| - update-pre-commit-hooks.yml |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect the exact lines that currently reference secrets in the ignored workflows,
# so the file-wide ignores can be replaced with line-scoped ignores.
fd '^(sync-settings|update-pre-commit-hooks)\.yml$' .github/workflows -x sh -c '
file="$1"
echo "== $file =="
rg -n -C2 "\$\{\{\s*secrets\." "$file" || true
' sh {}Repository: gamaware/github-org-settings
Length of output: 165
🏁 Script executed:
cat -n .github/workflows/sync-settings.ymlRepository: gamaware/github-org-settings
Length of output: 7095
🏁 Script executed:
cat -n .github/workflows/update-pre-commit-hooks.ymlRepository: gamaware/github-org-settings
Length of output: 797
🌐 Web query:
zizmor rules.secrets-outside-env.ignore syntax line column documentation
💡 Result:
zizmor lets you ignore the secrets-outside-env audit either inline (comment) or via config (zizmor.yml).
1) Inline ignore comment
Put a YAML comment in the span that triggers the finding:
# zizmor: ignore[secrets-outside-env]You can also add a trailing explanation, and you can ignore multiple audits with commas. The comment must be a real YAML comment (not inside a string/block literal). [1]
2) zizmor.yml config: rules.secrets-outside-env.ignore
Use:
rules:
secrets-outside-env:
ignore:
- workflow.yml # ignore entire file
- workflow.yml:123 # ignore line 123 (any column)
- workflow.yml:123:45 # ignore line 123, column 45The ignore entry format is:
filename.yml[:line[:column]]
line and column are optional and 1-based. [1][2]
Scope these ignores to specific lines, not entire workflows.
The current ignores suppress all secrets-outside-env findings in these workflow files, both present and future. Use line-specific ignores instead:
ignore:
- sync-settings.yml:40
- update-pre-commit-hooks.yml:25This targets only the specific lines passing secrets to composite actions (which is acceptable), while preserving visibility into any other potential issues in these workflows.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@zizmor.yml` around lines 7 - 9, The ignore entries currently suppress all
findings for the entire workflows by listing "sync-settings.yml" and
"update-pre-commit-hooks.yml"; update these to line-specific ignores by
replacing those entries with filename:line (e.g., "sync-settings.yml:40" and
"update-pre-commit-hooks.yml:25") so only the known acceptable lines are ignored
while preserving checks for other lines; locate the "ignore:" block in
zizmor.yml and change the two list items accordingly.
…eation - Scope zizmor secrets-outside-env ignore to line-level where practical (update-pre-commit-hooks.yml:25), file-level for sync-settings.yml (5 secret usages make line-level unmaintainable) - Add error handling for gh issue create in drift detection step to prevent closing existing issues when creation fails
There was a problem hiding this comment.
🧹 Nitpick comments (1)
.github/workflows/sync-settings.yml (1)
157-166: Consider deduplicating new-repo issues to avoid noise.Unlike the drift issue logic which closes superseded issues, this step creates a new issue on each run when new repos exist. If the workflow triggers multiple times within the 7-day window (e.g., manual dispatches), it may create duplicate issues for the same repositories.
Consider either:
- Closing previous
new-repoissues before creating a new one (similar to drift logic)- Checking if a recent
new-repoissue already exists before creating♻️ Optional: Add deduplication similar to drift issues
- name: Create issue for new repos if: steps.newrepos.outputs.has_new == 'true' env: GH_TOKEN: ${{ secrets.ORG_SETTINGS_PAT }} run: | BODY=$(cat reports/new-repos.md) - gh issue create \ + if ! gh issue create \ --title "chore: new repositories discovered — $(date '+%Y-%m-%d')" \ --body "$BODY" \ - --label "new-repo" + --label "new-repo"; then + echo "::error::Failed to create new-repo issue" + exit 1 + fi + + # Close previous new-repo issues + LATEST=$(gh issue list --label "new-repo" --state open --json number --jq '.[0].number') + gh issue list --label "new-repo" --state open --json number --jq '.[].number' | while read -r num; do + if [ "$num" != "$LATEST" ]; then + gh issue close "$num" --comment "Superseded by new discovery run." + fi + done🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/sync-settings.yml around lines 157 - 166, The "Create issue for new repos" step currently always runs when steps.newrepos.outputs.has_new == 'true' and calls gh issue create with label "new-repo", causing duplicates; modify that step to first query existing open issues labeled "new-repo" (using gh issue list --label "new-repo" --state open --json createdAt,body,number or equivalent) and either (a) skip creating a new issue if a recent one (e.g., within 7 days) exists that covers the same repos, or (b) close/mark as superseded any prior "new-repo" issues (gh issue close <number>) before running gh issue create; keep the conditional on steps.newrepos.outputs.has_new and the GH_TOKEN env intact and ensure the check/close logic runs in the same step before the gh issue create command.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In @.github/workflows/sync-settings.yml:
- Around line 157-166: The "Create issue for new repos" step currently always
runs when steps.newrepos.outputs.has_new == 'true' and calls gh issue create
with label "new-repo", causing duplicates; modify that step to first query
existing open issues labeled "new-repo" (using gh issue list --label "new-repo"
--state open --json createdAt,body,number or equivalent) and either (a) skip
creating a new issue if a recent one (e.g., within 7 days) exists that covers
the same repos, or (b) close/mark as superseded any prior "new-repo" issues (gh
issue close <number>) before running gh issue create; keep the conditional on
steps.newrepos.outputs.has_new and the GH_TOKEN env intact and ensure the
check/close logic runs in the same step before the gh issue create command.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 05a7924a-b119-46b3-8940-caec878c945e
📒 Files selected for processing (2)
.github/workflows/sync-settings.ymlzizmor.yml
Summary
security-scan,sync-settings,update-pre-commit-composite) matching the pattern fromsystem-design-coursesettings-driftlabel, new repos usenew-repolabel. GitHub sends email notifications nativelyvulnerability_alertsandlabelssections toconfig/baseline.jsonTest plan
./scripts/sync-repo-settings.sh --dry-runlocally to verify all checks--dry-runto validate CISummary by CodeRabbit
New Features
Documentation