Goal
Apply required_signatures Repository Ruleset to every active workflow-having repo in JacobPEvans + dryvist so that no automated commit can land unsigned, ever.
This is Layer 3 of the 8-PR "eliminate unsigned automated commits" initiative. The other layers fix the existing offenders (PR #1) and add CI/hook/audit backstops (PRs #5, #6, #7). This layer is the iron rule — once active, GitHub itself rejects unsigned pushes at the API level.
Why this is an issue and not a PR
Repository Rulesets aren't stored in code (no terraform module, no YAML files). They're a GitHub-managed resource configured via the REST API at repos/{owner}/{repo}/rulesets. Each command below is idempotent — re-running has no effect if the rule already exists.
Auth required
The current gh auth PAT lacks administration:write scope (fine-grained PAT, no admin permission). To execute the commands below, use either:
- A classic PAT with
admin:repo_hook + repo scopes: gh auth login --scopes admin:repo_hook,admin:org,repo,workflow,write:org
- A fine-grained PAT with "Repository administration: Read and write" on the target repos
- An installation token from the JacobPEvans-github-actions[bot] App (verify the App has the
Administration: Write permission first; if not, grant via Settings → Developer settings → GitHub Apps → JacobPEvans-github-actions → Permissions)
What needs to change
1. JacobPEvans/JacobPEvans output branch extension
Depends on PR #26 (snake/3d-contrib fix) being merged first. Without that, applying the rule retroactively rejects every future snake.yml/3d-contrib.yml run.
gh api repos/JacobPEvans/JacobPEvans/rulesets/11490473 --method PUT --input - <<'EOF'
{"conditions": {"ref_name": {"include": ["~DEFAULT_BRANCH", "refs/heads/output"], "exclude": []}}}
EOF
2. JacobPEvans repos with rulesets MISSING required_signatures (PATCH each)
| Repo |
Ruleset ID |
Current rules |
| cc-edge-claude-code-otel |
13538560 |
deletion, non_fast_forward, pull_request |
| cc-edge-copilot-otel |
14126034 |
deletion, non_fast_forward, pull_request |
| cc-edge-vscode-io |
14126036 |
deletion, non_fast_forward, pull_request |
| cc-stream-github-copilot-rest-io |
14126037 |
deletion, non_fast_forward, pull_request |
For each:
for entry in "cc-edge-claude-code-otel:13538560" "cc-edge-copilot-otel:14126034" "cc-edge-vscode-io:14126036" "cc-stream-github-copilot-rest-io:14126037"; do
repo="${entry%%:*}"; rid="${entry##*:}"
current=$(gh api "repos/JacobPEvans/$repo/rulesets/$rid")
new_rules=$(echo "$current" | jq '.rules + [{"type":"required_signatures"}]')
gh api --method PUT "repos/JacobPEvans/$repo/rulesets/$rid" --input - <<EOF2
{"rules": $new_rules}
EOF2
done
3. JacobPEvans active workflow-having repos with NO rulesets (POST canonical)
These are repos that have workflow files but no ruleset at all — they're at risk of accepting unsigned commits if a future workflow adds git commit:
agentics (13 workflows — fork of githubnext/agentics, drives gh-aw)
agent-os (2 workflows — fork)
Skipping claude-code-automated (archived) and personal/obsidian/notes repos without workflows (they have no automation risk and the user may commit from web/mobile editors).
For each:
for repo in agentics agent-os; do
gh api repos/JacobPEvans/$repo/rulesets --method POST --input - <<EOF2
{
"name": "main",
"target": "branch",
"enforcement": "active",
"conditions": {"ref_name": {"include": ["~DEFAULT_BRANCH"], "exclude": []}},
"rules": [
{"type": "deletion"},
{"type": "non_fast_forward"},
{"type": "required_signatures"}
]
}
EOF2
done
(Keeping the rule set minimal — deletion, non_fast_forward, required_signatures — since these are upstream forks where we don't want to enforce our own PR-review patterns.)
4. dryvist org-level → fallback to per-repo
gh api orgs/dryvist/rulesets returned 404 on probe (likely Free-tier limitation, possibly token permission). For all 9 dryvist public repos, POST the canonical ruleset:
for repo in nix-pxe-bootstrap homelab-schemas nix-ai-server ansible-proxmox-cluster ansible-server-apps tofu-proxmox-cluster .github cc-edge-pack-template cc-edge-claude-code-io; do
gh api repos/dryvist/$repo/rulesets --method POST --input - <<EOF2
{
"name": "main",
"target": "branch",
"enforcement": "active",
"conditions": {"ref_name": {"include": ["~DEFAULT_BRANCH"], "exclude": []}},
"rules": [
{"type": "deletion"},
{"type": "non_fast_forward"},
{"type": "required_signatures"},
{"type": "pull_request", "parameters": {"allowed_merge_methods": ["squash","rebase"], "dismiss_stale_reviews_on_push": false, "require_code_owner_review": false, "require_last_push_approval": false, "required_approving_review_count": 0, "required_review_thread_resolution": true, "required_reviewers": []}}
]
}
EOF2
done
After this, re-probe org rulesets — if org-level becomes available at any point, migrate the per-repo rulesets to org-level for unified management.
Verification after running all commands
for org in JacobPEvans dryvist; do
echo "=== $org ==="
for repo in $(gh repo list "$org" --limit 100 --json name --jq '.[].name'); do
sig_present=$(gh api "repos/$org/$repo/rulesets" --jq '[.[].id]' 2>/dev/null \
| jq -r '.[]' | xargs -I{} gh api "repos/$org/$repo/rulesets/{}" --jq '.rules[].type' 2>/dev/null \
| grep -c required_signatures || true)
workflows=$(gh api "repos/$org/$repo/contents/.github/workflows" --jq 'length' 2>/dev/null || echo 0)
if [ "${sig_present:-0}" = "0" ] && [ "${workflows:-0}" -gt "0" ]; then
echo " STILL MISSING required_signatures (has $workflows workflows): $repo"
fi
done
done
Expected: empty output. Any line means a repo's automated commits could still land unsigned.
Explicitly out of scope
Tracking
Close this issue once the verification command above produces empty output AND the PR #1 sub-step is complete.
Goal
Apply
required_signaturesRepository Ruleset to every active workflow-having repo in JacobPEvans + dryvist so that no automated commit can land unsigned, ever.This is Layer 3 of the 8-PR "eliminate unsigned automated commits" initiative. The other layers fix the existing offenders (PR #1) and add CI/hook/audit backstops (PRs #5, #6, #7). This layer is the iron rule — once active, GitHub itself rejects unsigned pushes at the API level.
Why this is an issue and not a PR
Repository Rulesets aren't stored in code (no terraform module, no YAML files). They're a GitHub-managed resource configured via the REST API at
repos/{owner}/{repo}/rulesets. Each command below is idempotent — re-running has no effect if the rule already exists.Auth required
The current
gh authPAT lacksadministration:writescope (fine-grained PAT, no admin permission). To execute the commands below, use either:admin:repo_hook+reposcopes:gh auth login --scopes admin:repo_hook,admin:org,repo,workflow,write:orgAdministration: Writepermission first; if not, grant via Settings → Developer settings → GitHub Apps → JacobPEvans-github-actions → Permissions)What needs to change
1. JacobPEvans/JacobPEvans output branch extension
Depends on PR #26 (snake/3d-contrib fix) being merged first. Without that, applying the rule retroactively rejects every future snake.yml/3d-contrib.yml run.
2. JacobPEvans repos with rulesets MISSING
required_signatures(PATCH each)For each:
3. JacobPEvans active workflow-having repos with NO rulesets (POST canonical)
These are repos that have workflow files but no ruleset at all — they're at risk of accepting unsigned commits if a future workflow adds
git commit:agentics(13 workflows — fork of githubnext/agentics, drives gh-aw)agent-os(2 workflows — fork)Skipping
claude-code-automated(archived) and personal/obsidian/notes repos without workflows (they have no automation risk and the user may commit from web/mobile editors).For each:
(Keeping the rule set minimal —
deletion,non_fast_forward,required_signatures— since these are upstream forks where we don't want to enforce our own PR-review patterns.)4. dryvist org-level → fallback to per-repo
gh api orgs/dryvist/rulesetsreturned 404 on probe (likely Free-tier limitation, possibly token permission). For all 9 dryvist public repos, POST the canonical ruleset:After this, re-probe org rulesets — if org-level becomes available at any point, migrate the per-repo rulesets to org-level for unified management.
Verification after running all commands
Expected: empty output. Any line means a repo's automated commits could still land unsigned.
Explicitly out of scope
Tracking
Close this issue once the verification command above produces empty output AND the PR #1 sub-step is complete.