Skip to content

feat(repo-settings): port per-repo settings module from .github-tofu#7

Merged
JacobPEvans-personal merged 1 commit into
mainfrom
feat/port-repo-settings
Jun 1, 2026
Merged

feat(repo-settings): port per-repo settings module from .github-tofu#7
JacobPEvans-personal merged 1 commit into
mainfrom
feat/port-repo-settings

Conversation

@JacobPEvans-personal
Copy link
Copy Markdown
Member

What

Mines the "gold" from .github-tofu before it is retired: ports its per-repo
settings module
into this canonical governance repo. .github-tofu was a
same-day scaffold that duplicated the org-level ruleset (it collided on org
ruleset id 15555419, already owned here). Consolidating its useful half here
lets .github-tofu be archived/deleted without losing the repo-settings
baseline.

Ports only the repository-settings half of the source nix-repo module:

  • squash + rebase merges only (no merge commit)
  • auto-merge on, delete branch on merge
  • web commit signoff required, wiki off
  • Dependabot vulnerability alerts + automatic security updates
  • secret scanning + push protection on public repos only (see Cost impact)

The source module's per-repo all ruleset (signed commits) is intentionally
not ported
— the org-level rulesets in rulesets.tf already enforce signed
commits, linear history, and Conventional Commits on every repo. Porting the
per-repo ruleset would duplicate org-level coverage.

How it matches this repo's conventions

  • Single org-scoped provider, no aliases. The source split modules per
    owner (nix_repo_jpe / nix_repo_dryvist) via aliased providers. All seven
    nix-* repos now resolve to the org (verified live), so they are managed by
    the one providers.tf provider — no aliases, no per-repo owner.
  • No identity in config/*.yml. Per AGENTS.md ("no account logins in
    config/*.yml"), the per-repo owner field from the source is dropped; the
    owner comes from the provider. config/repos.yml carries only the repo name
    (the governance subject), visibility, description, and topics.
  • Inventory in config/, decoded via yamldecode(file(...)) into a local
    in the new topical file repos.tf. Settings logic lives in
    modules/repo-settings/.
  • Native import {} blocks (for_each over the inventory) replace the
    source's scripts/import.sh, so a first apply RECONCILES the existing repos
    instead of trying to recreate them (which prevent_destroy would block).
  • Release-please / renovate / markdownlint hygiene untouched.

Cost impact

Free. Secret scanning + secret-scanning push protection are enabled on
public repos only — free on public repos. The security_and_analysis block
is emitted via a dynamic block gated on visibility == "public", so the
config can never silently enable paid GitHub Advanced Security (Secret
Protection) on a private repo; private repos are excluded from the block
entirely. All other managed settings (merge methods, auto-merge, branch
deletion, wiki, web-commit signoff, Dependabot alerts + security updates) are
free on public and private repos. No Actions/Packages capacity is allocated.

This corrects a latent cost bug in the source module, which hardcoded
visibility = "public" and enabled secret scanning unconditionally — that
would have charged GHAS the moment a private repo entered the inventory.

Scope (first increment)

Inventory is the same nix- family* .github-tofu/data/repos.yaml covered,
resolved to live visibility (all currently public):

Repo Visibility
nix-ai public
nix-darwin public
nix-home public
nix-devenv public
nix-claude-code public
nix-pxe-bootstrap public
nix-ai-server public

Follow-up: expand the inventory to every non-archived org repo (~38), per
the Phase 1 plan in the tracking issue. Intentionally out of scope here to keep
this increment reviewable.

Validation (local, no backend)

  • tofu fmt -check -recursive — clean
  • tofu init -backend=false — success
  • tofu validateSuccess! The configuration is valid.
  • tflint --recursive (root + module, with the repo's pre-commit --only
    set) — exit 0, no findings
  • pre-commit (fmt, validate, tflint, checkov, tofu test) — all pass

tofu plan / apply were not run — they require the ORG_ADMIN token tier
and the S3 backend.

Checkov suppressions (documented, per-resource)

Two Checkov GIT checks are skipped on github_repository.this with inline
justifications (visible in the diff), because both are false positives for this
governance model — not bypasses of real failures:

  • CKV_GIT_1 ("repository is Private") — these repos are intentionally public;
    the org cost policy depends on it (public = free secret scanning).
  • CKV2_GIT_1 ("branch protection associated") — branch protection is provided
    at the org level via github_organization_ruleset in rulesets.tf, which
    Checkov does not associate with the per-repo resource.

CI (ci-gate.yml) does not run Checkov; these annotations are for the local
pre-commit hook and reviewer transparency.

Operator must review tofu plan before apply

This is the first config in the repo that touches existing repos' settings
(not just org rulesets). On first apply the import {} blocks adopt each repo
plus its two Dependabot sub-resources into state, then reconcile settings. The
plan diff WILL show changes to live repos (merge methods, wiki, signoff,
Dependabot, secret scanning). Inspect the full tofu plan and confirm every
diff is intended before applying.
Apply requires the ORG_ADMIN token tier.

Refs: #6

🤖 Generated with Claude Code

Consolidates GitHub governance into this canonical repo so the same-day
.github-tofu scaffold — which duplicated the org ruleset (collided on id
15555419) — can be retired before it ever applies.

Ports only the repository-settings half of .github-tofu's nix-repo module:
squash + rebase merges (no merge commit), auto-merge on, delete branch on
merge, web commit signoff required, wiki off, Dependabot vulnerability alerts
+ security updates. The source module's per-repo rulesets are intentionally
dropped — the org-level rulesets here already enforce signed commits, linear
history, and Conventional Commits on every repo, so porting them would
duplicate org-level coverage.

Adapted to this repo's conventions: single org-scoped provider (no per-owner
aliases — all seven nix-* repos now resolve to the org), no account login in
config/*.yml (owner comes from the provider), inventory in config/repos.yml
decoded via yamldecode, settings module under modules/repo-settings/.

Secret scanning + push protection are scoped to PUBLIC repos only via a
dynamic security_and_analysis block gated on visibility == public, so an apply
never silently enables paid GitHub Advanced Security on a private repo. The
source module hardcoded visibility=public and enabled these unconditionally.

First apply reconciles existing repos via native Terraform import blocks
(for_each over the inventory) instead of .github-tofu's import.sh.

Cost impact: free. Secret scanning + push protection enabled on public repos
only (free); private repos excluded from the security_and_analysis block, so
no GHAS charge. All other settings are free on public and private repos. No
Actions/Packages capacity allocated.

Refs: #6
Assisted-by: Claude:claude-opus-4-8
@JacobPEvans-personal JacobPEvans-personal marked this pull request as ready for review June 1, 2026 17:54
@JacobPEvans-personal JacobPEvans-personal merged commit fcebc00 into main Jun 1, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant