feat: apply-repo-settings action (in-workflow rulesets sync) - #23
Merged
Merged
Conversation
An ephemeral alternative to the repository-settings GitHub App (https://github.com/repository-settings/app). The upstream app is a Probot webhook server — adapting it for one-shot in-workflow runs is more invasive than building a minimal applier from scratch. Why a fresh implementation: this action covers the two sections we actually use today (`repository:` config and `rulesets:`) in ~170 lines of bash + `gh api`. Other sections (labels/collaborators/teams/ environments/legacy-branches) aren't implemented — they have separate sync mechanisms in nsheaps/.github already. Contents: action.yml composite action interface (app-id + private-key required; owner/repo/settings-file/dry-run/ sections all optional with sensible defaults). Outputs a JSON summary of changes. action.sh the applier: - PATCH /repos/{owner}/{repo} with .repository - For each ruleset: list existing, diff against desired, POST/PUT as needed. Never deletes rulesets that aren't in the YAML. docs/setup.html static HTML helper that builds a GitHub App manifest with the exact permissions this action needs (administration:write + contents:read + metadata:read), submits to github.com/.../apps/new, then exchanges the returned code for credentials via the manifest conversion endpoint. Accordion sections cover hosting choices and a manual-setup walkthrough. README.md inputs/outputs reference + example workflow that triggers on workflow_dispatch / repository_dispatch / push to settings.yml on main. Permissions intentionally narrow: this app needs Administration:write to manage rulesets and repo config, plus Contents:read to read the settings file. No Issues/PR/Workflow write — labels are managed by sync-labels today. Reuses the existing actions/create-github-app-token pin (29824e69f54612133e76f7eaac726eef6c875baf, v2) used by github-app-auth elsewhere in this repo.
Triggered by: 374f864 Workflow run: https://github.com/nsheaps/github-actions/actions/runs/26590895624
Extends the apply-repo-settings setup helper into a reusable page that
can register any GitHub App via the manifest flow, then deploys it to
GitHub Pages so the hosted redirect URL is stable.
Changes:
- pages/index.html (moved from .github/actions/apply-repo-settings/
docs/setup.html and substantially restructured):
* App preset dropdown driven by a single PRESETS registry. Adding
a new app = one entry in the registry; no other code changes.
* apply-repo-settings is the seed preset; manifest permissions,
secret names, and post-creation next-steps move into the entry.
* Generic ?qparam=value form prefill — any input/select/textarea
with a `name` matching a query param gets prefilled at load.
Supports text/url/select/textarea/checkbox+radio. Field hints
under each label name the qparam.
* Round-trip state preserved via `&state=preset=...` on the
manifest submit, with sessionStorage + ?preset fallback on
return, so the right preset's secret names / next-steps render
after the GitHub redirect-back.
* Redirect URL defaults to the current page (sans code/state).
* New "How do query-param prefills work?" accordion documents
the mechanism; hosting + manual-setup accordions retained.
- .github/workflows/pages.yaml: deploys pages/ via the standard
actions/configure-pages + upload-pages-artifact + deploy-pages
trio. Triggers on push to main with paths in pages/ or this
workflow, plus workflow_dispatch. concurrency: pages, serial.
One-time enablement still required at repo Settings → Pages
(Source: GitHub Actions) — noted in the workflow comment.
- .github/actions/apply-repo-settings/README.md:
* "Setting up the GitHub App" section now points at the hosted
page with the preset preselected:
https://nsheaps.github.io/github-actions/?preset=apply-repo-settings
* Cross-references pages/index.html + the deploy workflow.
Validation: JS parses clean via `node --check`. Preset block contains
the documented permissions and secret names. (Headless browser smoke
test not run — chromium not installed in this environment.)
Triggered by: 3d6b641 Workflow run: https://github.com/nsheaps/github-actions/actions/runs/26593382819
Contributor
There was a problem hiding this comment.
Review: Correctness 92% | Security 88% | Simplicity 90%
Scope: 4 files added (action.sh, action.yml, pages/index.html, .github/workflows/pages.yaml). 2 chore-format auto-commits. Draft ✅
CI: Format ✅ Security ✅
action.sh — shell correctness
set -euo pipefail✅ — proper shell safety- Required env var guards
${VAR:?required}✅ want_section()correctly uses[[ ",$SECTIONS," == *",$target,"* ]]— handles edge cases ✅yq -o=json '.repository // {}'— correct null/empty handling ✅gh api --paginatefor listing existing rulesets — handles repos with many rulesets ✅- Ruleset comparison normalizes both sides with
jq -S '.'(sorted keys) and extracts only the diffable fields (name, target, enforcement, conditions, rules, bypass_actors) — correct approach for idempotency ✅ - Non-destructive: never deletes rulesets absent from YAML — documented and intentional ✅
- Summary generation with
${CREATED[@]:-}+jq -s 'map(select(length>0))'correctly produces[]for empty arrays ✅ create-github-app-tokenpinned to SHA (29824e69f54612133e76f7eaac726eef6c875baf) ✅
action.yml
SETTINGS_FILE: ${{ inputs.settings-file }}passed as env var and quoted in action.sh — not injection-prone ✅GH_TOKENscoped only to the apply step ✅
pages/index.html
- Client-side manifest flow is GitHub's documented approach — correct ✅
&state=preset=...roundtrip is safe — preset name only, no credentials ✅- JS parses clean per commit message ✅
Follow-ups:
- P2:
action.ymlinstallsyqfromhttps://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64—latestis a moving target. Pin to a specific version (e.g.v4.44.3) to avoid silent breaking changes on new releases. - P2: PR has no labels applied.
Reviewed by henry-nsheaps[bot] · nsheaps/github-actions#23
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.github/actions/apply-repo-settings/— an ephemeral, in-workflow alternative to therepository-settingsGitHub App.repository:config +rulesets:. Other sections (labels/collaborators/teams/environments/legacybranches) are out of scope — they have separate sync mechanisms innsheaps/.github.gh api. Non-destructive: never deletes rulesets that aren't in the YAML.docs/setup.html— a single-file GitHub App manifest helper that builds the app with exactly the permissions this action needs (administration:write,contents:read,metadata:read) and exchanges the manifest code for credentials client-side. Five accordion sections cover hosting (GH Pages recipe), troubleshooting, manual setup, and key rotation.Why a fresh impl, not a fork of the upstream app
The upstream is a Probot webhook server — adapting it to one-shot in-workflow runs is more invasive than rewriting the subset we need. README documents the choice.
Test plan
action.yml+action.shlint clean (existingmise run checkcoversbash -n).docs/setup.htmlrenders + the manifest submit flow ends at?code=on a return.nsheaps/.github(see consumer PR in nsheaps/.github).Consumer
nsheaps/.github PR for the workflow. Land this one first; that one pins
@main.