Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/settings-drift.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Settings drift

on:
schedule:
- cron: "0 6 * * 1"
workflow_dispatch:

permissions:
contents: read

defaults:
run:
shell: bash

jobs:
drift:
name: Settings drift
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24

- name: List the repositories to check
id: repos
run: echo "names=$(node -p "Object.keys(require('./settings/repos.json')).map((name) => name.split('/')[1]).join(',')")" >> "$GITHUB_OUTPUT"

- name: Create a read-only token
id: token
uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0
with:
client-id: ${{ vars.SETTINGS_APP_CLIENT_ID }}
private-key: ${{ secrets.SETTINGS_APP_PRIVATE_KEY }}
owner: BSStudio
repositories: ${{ steps.repos.outputs.names }}
permission-administration: read

- name: Compare settings with the baseline
env:
GH_TOKEN: ${{ steps.token.outputs.token }}
run: node scripts/apply-settings.mjs --dry-run
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ node scripts/apply-settings.mjs # fix them in ever
node scripts/apply-settings.mjs --dry-run BSStudio/backstage # one repo
```

Settings must not drift unnoticed: `.github/workflows/settings-drift.yml` runs the dry run every Monday morning and fails when anything differs. It reads the repos with a token from the read-only "BSStudio settings check" GitHub App (Administration: read), which is installed on the repos in `settings/repos.json`; a repo added to that file needs the App installed too. Fixing drift stays a local run of the script. GitHub turns scheduled workflows off after 60 days without activity in the repo and emails about it; Renovate's monthly PRs normally keep it active.

A named repo must be listed in `settings/repos.json`. A run writes only what differs, then reads the repo again and reports anything GitHub did not take. Run it as an admin of the listed repos: without admin rights GitHub leaves some settings out of its answers (they show as `missing`) and refuses the writes. A failed call is reported with the `gh` command that failed.

Security features (secret scanning, push protection, Dependabot alerts, CodeQL default setup, private vulnerability reporting) come from the organisation's "GitHub recommended" code security configuration, which is the default for new public repos. The script checks that it is attached and never attaches it.
Expand Down
Loading