Skip to content

Commit d83bc29

Browse files
committed
feat: add architecture docs, runbooks, and Claude Code skills
- 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
1 parent b239275 commit d83bc29

11 files changed

Lines changed: 384 additions & 5 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
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+
- `my-repo branch_protection.required_status_checks.contexts '["Build","Test"]'`
17+
- `my-repo repo_settings.has_wiki true`
18+
19+
## Steps
20+
21+
1. Read the current `config/overrides.json`
22+
2. Parse `$ARGUMENTS` to extract repo name, setting path, and value
23+
3. Add or update the override for the specified repo
24+
4. Validate the resulting JSON with `jq empty`
25+
5. Show the diff of what changed
26+
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+
2. 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

CLAUDE.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ a baseline, apply corrections, and report drift via GitHub Issues.
1414
- `.github/workflows/` — CI/CD and scheduled sync workflows
1515
- `.github/actions/` — Composite actions (security-scan, sync-settings,
1616
update-pre-commit-composite)
17+
- `.claude/skills/` — Reusable skills (`/audit`, `/add-repo-override`,
18+
`/exclude-repo`)
19+
- `docs/architecture.md` — System architecture overview
1720
- `docs/adr/` — Architecture Decision Records
21+
- `docs/runbooks/` — Operational procedures (exclude repo, add setting,
22+
handle drift, onboard repo)
1823

1924
## Git Workflow
2025

@@ -73,6 +78,12 @@ commit hooks — see `.pre-commit-config.yaml` for the full list.
7378
- `.github/actions/update-pre-commit-composite/` — reusable
7479
pre-commit autoupdate + PR creation
7580

81+
## Claude Code Skills
82+
83+
- `/audit` — run a dry-run settings check across all repos
84+
- `/add-repo-override` — add a per-repo exception to overrides.json
85+
- `/exclude-repo` — exclude a repository from governance
86+
7687
## Code Review
7788

7889
- CodeRabbit auto-review via `.coderabbit.yaml`

README.md

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,15 @@ corrected in `--apply` mode.
145145
github-org-settings/
146146
├── .claude/
147147
│ ├── settings.json # Claude Code hooks config
148-
│ └── hooks/
149-
│ └── post-edit.sh # Auto-format on edit
148+
│ ├── hooks/
149+
│ │ └── post-edit.sh # Auto-format on edit
150+
│ └── skills/
151+
│ ├── audit/ # /audit — dry-run settings check
152+
│ │ └── SKILL.md
153+
│ ├── add-repo-override/ # /add-repo-override — add exception
154+
│ │ └── SKILL.md
155+
│ └── exclude-repo/ # /exclude-repo — exclude a repo
156+
│ └── SKILL.md
150157
├── .github/
151158
│ ├── actions/
152159
│ │ ├── security-scan/ # Composite: Semgrep + Trivy
@@ -173,10 +180,17 @@ github-org-settings/
173180
│ ├── baseline.json # Settings enforced on all repos
174181
│ └── overrides.json # Per-repo exceptions
175182
├── docs/
176-
│ └── adr/
183+
│ ├── architecture.md # System architecture overview
184+
│ ├── adr/
185+
│ │ ├── README.md
186+
│ │ ├── 001-settings-governance.md
187+
│ │ └── 002-sync-architecture.md
188+
│ └── runbooks/
177189
│ ├── README.md
178-
│ ├── 001-settings-governance.md
179-
│ └── 002-sync-architecture.md
190+
│ ├── add-setting.md # How to add a new setting
191+
│ ├── exclude-repo.md # How to exclude a repo
192+
│ ├── handle-drift.md # How to respond to drift
193+
│ └── onboard-repo.md # How to onboard a new repo
180194
├── .coderabbit.yaml # CodeRabbit auto-review config
181195
├── .gitignore
182196
├── .markdownlint.yaml

docs/architecture.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Architecture Overview
2+
3+
## System Context
4+
5+
This repository is the single source of truth for GitHub repository
6+
settings across all `gamaware` repositories. It acts as a control
7+
plane that reads a desired state from JSON configuration and
8+
reconciles it against the actual state via the GitHub API.
9+
10+
```text
11+
+---------------------+ +------------------+
12+
| config/ | | GitHub API |
13+
| baseline.json |------>| (repos, branches,|
14+
| overrides.json | | labels, security|
15+
+---------------------+ +------------------+
16+
| ^
17+
v |
18+
+---------------------+ |
19+
| scripts/ | |
20+
| sync-repo-settings |---------------+
21+
| generate-report |
22+
+---------------------+
23+
|
24+
v
25+
+---------------------+
26+
| GitHub Issues |
27+
| Job Summaries |
28+
| Artifacts (90 days) |
29+
+---------------------+
30+
```
31+
32+
## Components
33+
34+
### Configuration Layer (`config/`)
35+
36+
- `baseline.json` — settings enforced on every repository
37+
- `overrides.json` — per-repo exceptions (status checks, exclusions)
38+
39+
The effective configuration for a repo is the baseline deep-merged
40+
with its overrides. If no override exists, the baseline is used
41+
as-is.
42+
43+
### Sync Engine (`scripts/`)
44+
45+
`sync-repo-settings.sh` is the core reconciliation loop:
46+
47+
1. **Discovery**`gh repo list` finds all non-archived repos
48+
2. **Comparison** — for each repo, current state is fetched via API
49+
and compared field-by-field against the effective config
50+
3. **Remediation** — in `--apply` mode, PATCH/PUT calls correct drift
51+
4. **Reporting** — a markdown report is generated with per-repo diffs
52+
53+
The script handles 7 categories independently:
54+
55+
| Category | API Endpoint | Method |
56+
| --- | --- | --- |
57+
| Repo settings | `repos/{owner}/{repo}` | PATCH |
58+
| Security | `repos/{owner}/{repo}` | PATCH |
59+
| Vulnerability alerts | `repos/{owner}/{repo}/vulnerability-alerts` | PUT |
60+
| Branch protection | `repos/{owner}/{repo}/branches/main/protection` | PUT |
61+
| Labels | `repos/{owner}/{repo}/labels` | POST |
62+
| Default branch | `repos/{owner}/{repo}` | PATCH |
63+
| Metadata | (advisory only) ||
64+
65+
### Composite Actions (`.github/actions/`)
66+
67+
Reusable building blocks consumed by workflows:
68+
69+
- `security-scan/` — Semgrep SAST + Trivy SCA with SARIF upload
70+
- `sync-settings/` — wraps the sync script with structured outputs
71+
- `update-pre-commit-composite/` — autoupdates hooks and creates PR
72+
73+
### Workflows (`.github/workflows/`)
74+
75+
| Workflow | Schedule | Purpose |
76+
| --- | --- | --- |
77+
| `sync-settings.yml` | Weekly Sunday 00:00 UTC | Settings enforcement |
78+
| `quality-checks.yml` | PR + push | Linting and validation |
79+
| `security.yml` | PR + push | SAST + SCA |
80+
| `update-pre-commit-hooks.yml` | Weekly Sunday 00:00 UTC | Hook version updates |
81+
82+
### Reporting
83+
84+
Drift is communicated through three channels:
85+
86+
1. **GitHub Issues** — auto-created with `settings-drift` label when
87+
drift is found, auto-closed when all repos are compliant
88+
2. **Job Summaries** — visible in the Actions run page
89+
3. **Artifacts** — full markdown report stored for 90 days
90+
91+
## Security Model
92+
93+
- The `ORG_SETTINGS_PAT` secret provides API access with `repo` and
94+
`admin:org` scopes
95+
- Workflows use least-privilege `permissions` blocks
96+
- All third-party actions are pinned to SHA commits
97+
- Secret scanning and push protection are enforced on this repo too
98+
99+
## Design Decisions
100+
101+
Detailed rationale is documented in Architecture Decision Records:
102+
103+
- [ADR 001: Settings Governance](adr/001-settings-governance.md)
104+
- [ADR 002: Sync Architecture](adr/002-sync-architecture.md)

docs/runbooks/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Runbooks
2+
3+
Operational procedures for managing GitHub organization settings.
4+
5+
| Runbook | Purpose |
6+
| --- | --- |
7+
| [Exclude a Repository](exclude-repo.md) | Stop syncing settings to a repo |
8+
| [Add a New Setting](add-setting.md) | Enforce a new setting across all repos |
9+
| [Handle Drift](handle-drift.md) | Respond to drift detection issues |
10+
| [Onboard New Repository](onboard-repo.md) | Prepare a new repo for governance |

docs/runbooks/add-setting.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Add a New Setting
2+
3+
Enforce a new GitHub setting across all repositories.
4+
5+
## Steps
6+
7+
1. Identify the GitHub API field name for the setting. Check the
8+
[GitHub REST API docs](https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#update-a-repository)
9+
10+
2. Add the field to the appropriate section in `config/baseline.json`:
11+
- `repo_settings` — repository-level toggles
12+
- `security` — security features
13+
- `branch_protection` — branch protection rules
14+
- `labels` — standard labels
15+
- `required_files` — files that must exist
16+
17+
3. Update `scripts/sync-repo-settings.sh` if the new setting requires
18+
a different API endpoint or comparison logic
19+
20+
4. Update `README.md` to document the new setting and its purpose
21+
22+
5. Test locally:
23+
24+
```bash
25+
./scripts/sync-repo-settings.sh --dry-run
26+
```
27+
28+
6. Create a PR. Review the dry-run output to confirm the expected
29+
changes
30+
31+
7. After merge, the next weekly run will apply the setting. For
32+
immediate application, trigger manually:
33+
34+
```bash
35+
gh workflow run sync-settings.yml -f mode="--apply"
36+
```
37+
38+
## Per-Repo Exceptions
39+
40+
If a repo legitimately needs a different value, add an override in
41+
`config/overrides.json` under the repo name.

docs/runbooks/exclude-repo.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Exclude a Repository
2+
3+
Stop syncing settings to a specific repository.
4+
5+
## When to Use
6+
7+
- Third-party forks that must keep upstream settings
8+
- Temporary repos that will be deleted soon
9+
- Repos with fundamentally different governance needs
10+
11+
## Steps
12+
13+
1. Open `config/overrides.json`
14+
2. Add the repo name to the `excluded` array:
15+
16+
```json
17+
{
18+
"excluded": ["repo-to-exclude"]
19+
}
20+
```
21+
22+
3. Create a PR with the change
23+
4. After merge, the next sync run will skip this repo
24+
25+
## Reverting
26+
27+
Remove the repo name from the `excluded` array and merge the PR.
28+
The next sync run will pick it up again.

docs/runbooks/handle-drift.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Handle Drift Detection
2+
3+
Respond to a `settings-drift` issue created by the sync workflow.
4+
5+
## Triage
6+
7+
1. Open the linked workflow run from the issue body
8+
2. Review the Job Summary to see which repos drifted and what changed
9+
3. Download the report artifact for full details
10+
11+
## Common Causes
12+
13+
| Cause | Action |
14+
| --- | --- |
15+
| Manual settings change via GitHub UI | Let the next `--apply` run fix it |
16+
| New repo created without governance | The sync will apply baseline settings |
17+
| Legitimate exception needed | Add an override in `config/overrides.json` |
18+
| PAT expired or lacks scopes | Rotate the `ORG_SETTINGS_PAT` secret |
19+
20+
## Manual Fix
21+
22+
If you need to fix drift immediately without waiting for the
23+
weekly run:
24+
25+
```bash
26+
gh workflow run sync-settings.yml -f mode="--apply"
27+
```
28+
29+
Or locally:
30+
31+
```bash
32+
./scripts/sync-repo-settings.sh --apply
33+
```
34+
35+
## Issue Lifecycle
36+
37+
- The workflow auto-creates a new issue each time drift is found
38+
- Previous drift issues are auto-closed with a superseded comment
39+
- When all repos are compliant, open drift issues are auto-closed
40+
with a compliant comment

0 commit comments

Comments
 (0)