Skip to content

Commit 74ee2cc

Browse files
authored
feat: add composite actions, enhanced governance, and GitHub Issue reports (#7)
## Summary - Add 3 composite actions (`security-scan`, `sync-settings`, `update-pre-commit-composite`) matching the pattern from `system-design-course` - Replace SMTP email delivery with GitHub Issues — drift creates/closes issues with `settings-drift` label, new repos use `new-repo` label. GitHub sends email notifications natively - Enhance sync script with: label standardization, default branch validation, Dependabot vulnerability alerts, repository metadata checks (description/topics) - Add `vulnerability_alerts` and `labels` sections to `config/baseline.json` - Refactor all 4 workflows to use composite actions - Add baseline JSON schema validation to quality checks - Comprehensive README documenting the purpose of every enforced setting ## Test plan - [ ] Run `./scripts/sync-repo-settings.sh --dry-run` locally to verify all checks - [ ] Trigger workflow manually with `--dry-run` to validate CI - [ ] Verify composite actions are referenced correctly - [ ] Confirm JSON schema validation catches missing sections - [ ] Verify GitHub Issue creation/closure logic <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Consolidated security scan combining static analysis and vulnerability scanning with SARIF upload * Repository settings sync with drift detection, issue-based reporting, new-repo discovery, and optional remediation * Automated pre-commit hook update workflow * Enforcement additions: vulnerability alerts, standard labels, default-branch checks, and repository metadata validations * **Documentation** * Expanded docs, runbooks, onboarding guides, and user-facing skill/reference pages; updated README and contribution/security guidance <!-- end of auto-generated comment: release notes by coderabbit.ai -->
1 parent c464a06 commit 74ee2cc

27 files changed

Lines changed: 1135 additions & 188 deletions
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
name: add-repo-override
3+
description: Add a per-repo settings override to overrides.json
4+
user-invocable: true
5+
---
6+
7+
# Add Repository Override
8+
9+
Add a per-repo exception to `config/overrides.json`.
10+
11+
## Arguments
12+
13+
`$ARGUMENTS` should be in the format: `<repo-name> <setting-path> <value>`
14+
15+
Examples:
16+
17+
- `my-repo branch_protection.required_status_checks.contexts '["Build","Test"]'`
18+
- `my-repo repo_settings.has_wiki true`
19+
20+
## Steps
21+
22+
1. Read the current `config/overrides.json`
23+
2. Parse `$ARGUMENTS` to extract repo name, setting path, and value
24+
3. Add or update the override for the specified repo
25+
4. Validate the resulting JSON with `jq empty`
26+
5. Show the diff of what changed
27+
6. Remind the user to create a PR for the change

.claude/skills/audit/SKILL.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
name: audit
3+
description: Run a dry-run settings audit across all repositories
4+
user-invocable: true
5+
disable-model-invocation: true
6+
---
7+
8+
# Audit Repository Settings
9+
10+
Run a dry-run sync to check for drift without applying changes.
11+
12+
## Steps
13+
14+
1. Run the sync script in dry-run mode:
15+
16+
```bash
17+
./scripts/sync-repo-settings.sh --dry-run
18+
```
19+
20+
1. Display the report:
21+
22+
```bash
23+
cat reports/sync-report.md
24+
```
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
name: exclude-repo
3+
description: Exclude a repository from settings governance
4+
user-invocable: true
5+
---
6+
7+
# Exclude Repository
8+
9+
Add a repository to the exclusion list in `config/overrides.json`.
10+
11+
## Arguments
12+
13+
`$ARGUMENTS` should be the repository name to exclude.
14+
15+
## Steps
16+
17+
1. Read the current `config/overrides.json`
18+
2. Add `$ARGUMENTS` to the `excluded` array (if not already present)
19+
3. Validate the resulting JSON with `jq empty`
20+
4. Show the updated exclusion list
21+
5. Remind the user to create a PR for the change

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Pull Request
2+
13
## What changed
24

35
<!-- Brief description of the change -->
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Security Scan
2+
description: Run SAST and SCA security scans
3+
4+
inputs:
5+
scan-path:
6+
description: Path to scan
7+
required: false
8+
default: "."
9+
10+
runs:
11+
using: composite
12+
steps:
13+
- name: Run Semgrep SAST
14+
uses: semgrep/semgrep-action@713efdd345f3035192eaa63f56867b88e63e4e5d # v1.0.0
15+
with:
16+
config: auto
17+
18+
- name: Run Trivy vulnerability scanner
19+
if: always()
20+
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
21+
with:
22+
scan-type: fs
23+
scan-ref: ${{ inputs.scan-path }}
24+
format: sarif
25+
output: trivy-results.sarif
26+
27+
- name: Upload Trivy results to GitHub Security
28+
uses: github/codeql-action/upload-sarif@0d579ffd059c29b07949a3cce3983f0780820c98 # v4.32.6
29+
if: always()
30+
with:
31+
sarif_file: trivy-results.sarif
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Sync Repository Settings
2+
description: Compare and apply GitHub settings across all repos against a baseline
3+
4+
inputs:
5+
mode:
6+
description: "Run mode: --dry-run or --apply"
7+
required: true
8+
default: "--dry-run"
9+
github_token:
10+
description: PAT with repo and admin scopes
11+
required: true
12+
13+
outputs:
14+
report_file:
15+
description: Path to the generated report
16+
value: ${{ steps.sync.outputs.report_file }}
17+
total_repos:
18+
description: Number of repos scanned
19+
value: ${{ steps.parse.outputs.total_repos }}
20+
compliant:
21+
description: Number of compliant repos
22+
value: ${{ steps.parse.outputs.compliant }}
23+
drift:
24+
description: Number of repos with drift
25+
value: ${{ steps.parse.outputs.drift }}
26+
has_drift:
27+
description: Whether any drift was detected
28+
value: ${{ steps.parse.outputs.has_drift }}
29+
30+
runs:
31+
using: composite
32+
steps:
33+
- name: Run settings sync
34+
id: sync
35+
shell: bash
36+
env:
37+
GH_TOKEN: ${{ inputs.github_token }}
38+
REPORT_FILE: reports/sync-report.md
39+
SYNC_MODE: ${{ inputs.mode }}
40+
run: |
41+
./scripts/sync-repo-settings.sh "$SYNC_MODE"
42+
echo "report_file=reports/sync-report.md" >> "$GITHUB_OUTPUT"
43+
44+
- name: Parse report
45+
id: parse
46+
shell: bash
47+
run: ./scripts/generate-report.sh reports/sync-report.md
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Update Pre-commit Hooks Composite Action
2+
description: Updates pre-commit hook versions and creates a PR
3+
4+
inputs:
5+
github_token:
6+
description: GitHub token for creating PRs
7+
required: true
8+
9+
runs:
10+
using: composite
11+
steps:
12+
- name: Set up Python
13+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
14+
with:
15+
python-version: "3.x"
16+
17+
- name: Install pre-commit
18+
shell: bash
19+
run: pip install pre-commit
20+
21+
- name: Update hooks
22+
shell: bash
23+
run: pre-commit autoupdate
24+
25+
- name: Create Pull Request
26+
uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
27+
with:
28+
token: ${{ inputs.github_token }}
29+
commit-message: "chore: update pre-commit hook versions"
30+
title: "chore: update pre-commit hook versions"
31+
body: |
32+
Automated update of pre-commit hook versions.
33+
34+
Review the changes to `.pre-commit-config.yaml` and merge if CI passes.
35+
branch: chore/update-pre-commit-hooks
36+
delete-branch: true

.github/copilot-instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Review priorities for this repository:
1+
# Review Priorities
22

33
1. Shell script quality: shellcheck and shellharden compliance, proper
44
quoting, error handling (set -euo pipefail), no hardcoded tokens

.github/workflows/quality-checks.yml

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,24 @@ jobs:
1515
runs-on: ubuntu-latest
1616
steps:
1717
- name: Checkout
18-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
18+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
19+
with:
20+
persist-credentials: false
1921

2022
- name: Lint markdown
21-
uses: DavidAnson/markdownlint-cli2-action@db4c2f7b1e4a6de4660458dd8d547f94deaac667 # v22.0.0
23+
uses: DavidAnson/markdownlint-cli2-action@07035fd053f7be764496c0f8d8f9f41f98305101 # v22.0.0
2224

2325
yaml-lint:
2426
name: YAML Validation
2527
runs-on: ubuntu-latest
2628
steps:
2729
- name: Checkout
28-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
30+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
31+
with:
32+
persist-credentials: false
2933

3034
- name: Lint YAML
31-
uses: ibiqlik/action-yamllint@2576f72e4b4e5aef56e60fc8a24fa17e25be1fef # v3.1.1
35+
uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c # v3.1.1
3236
with:
3337
config_file: .yamllint.yml
3438

@@ -37,7 +41,9 @@ jobs:
3741
runs-on: ubuntu-latest
3842
steps:
3943
- name: Checkout
40-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
44+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
45+
with:
46+
persist-credentials: false
4147

4248
- name: Run ShellCheck
4349
uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # v2.0.0
@@ -47,7 +53,9 @@ jobs:
4753
runs-on: ubuntu-latest
4854
steps:
4955
- name: Checkout
50-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
56+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
57+
with:
58+
persist-credentials: false
5159

5260
- name: Check required files
5361
run: |
@@ -79,20 +87,44 @@ jobs:
7987
fi
8088
done
8189
90+
- name: Validate baseline schema
91+
run: |
92+
ERRORS=0
93+
for section in repo_settings security branch_protection labels required_files; do
94+
if ! jq -e ".$section" config/baseline.json > /dev/null 2>&1; then
95+
echo "ERROR: Missing section '$section' in baseline.json"
96+
ERRORS=$((ERRORS + 1))
97+
else
98+
echo "OK: section '$section' present"
99+
fi
100+
done
101+
# Validate label structure
102+
LABEL_ERRORS=$(jq '[.labels[] | select(.name == null or .color == null or .description == null)] | length' config/baseline.json)
103+
if [ "$LABEL_ERRORS" -gt 0 ]; then
104+
echo "ERROR: $LABEL_ERRORS labels missing required fields (name, color, description)"
105+
ERRORS=$((ERRORS + LABEL_ERRORS))
106+
fi
107+
if [ "$ERRORS" -gt 0 ]; then
108+
echo "ERROR: baseline.json schema validation failed"
109+
exit 1
110+
fi
111+
82112
actions-security:
83113
name: Actions Security
84114
runs-on: ubuntu-latest
85115
steps:
86116
- name: Checkout
87-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
117+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
118+
with:
119+
persist-credentials: false
88120

89121
- name: Install zizmor
90122
run: |
91-
ZIZMOR_VERSION="1.5.0"
123+
ZIZMOR_VERSION="1.23.1"
92124
curl -sL "https://github.com/woodruffw/zizmor/releases/download/v${ZIZMOR_VERSION}/zizmor-x86_64-unknown-linux-gnu.tar.gz" -o /tmp/zizmor.tar.gz
93125
mkdir -p /tmp/zizmor-extract
94126
tar -xzf /tmp/zizmor.tar.gz -C /tmp/zizmor-extract
95-
sudo mv /tmp/zizmor-extract/zizmor /usr/local/bin/zizmor
127+
find /tmp/zizmor-extract -name zizmor -type f -exec sudo mv {} /usr/local/bin/zizmor \;
96128
chmod +x /usr/local/bin/zizmor
97129
98130
- name: Run zizmor

.github/workflows/security.yml

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,19 @@ on:
99
permissions:
1010
contents: read
1111
security-events: write
12+
actions: read
1213

1314
jobs:
1415
security-scan:
1516
name: Security Scan
1617
runs-on: ubuntu-latest
1718
steps:
1819
- name: Checkout
19-
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
20-
21-
- name: Run Semgrep
22-
uses: returntocorp/semgrep-action@713efdd345f3035192eaa63f56867b88e63e4e5d # v1.0.0
23-
with:
24-
config: auto
25-
26-
- name: Run Trivy
27-
uses: aquasecurity/trivy-action@18f2510ee396bbf400402947e7f3b01483832965 # v0.31.0
20+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2821
with:
29-
scan-type: fs
30-
format: sarif
31-
output: trivy-results.sarif
22+
persist-credentials: false
3223

33-
- name: Upload Trivy SARIF
34-
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
35-
if: always()
24+
- name: Run Security Scan
25+
uses: ./.github/actions/security-scan
3626
with:
37-
sarif_file: trivy-results.sarif
27+
scan-path: "."

0 commit comments

Comments
 (0)