An open API service indexing awesome lists of open source software.

https://github.com/nolte/terraform-github-bootstrap

Bootstrap the nolte GitHub org via Terraform: org settings, teams, branch protection rulesets.
https://github.com/nolte/terraform-github-bootstrap

bootstrap github iac nolte terraform

Last synced: 11 days ago
JSON representation

Bootstrap the nolte GitHub org via Terraform: org settings, teams, branch protection rulesets.

Awesome Lists containing this project

README

          

# terraform-github-bootstrap

> Manage the [`nolte`](https://github.com/nolte) GitHub account as Terraform: repository inventory and repository rulesets.

## Purpose

This repository owns parts of the [`nolte`](https://github.com/nolte) GitHub configuration as code, using the [`integrations/github`](https://registry.terraform.io/providers/integrations/github/latest/docs) Terraform provider.

> **`nolte` is a personal user account on GitHub, not an organisation.** Organisation-only concerns (org settings, teams, organisation-wide rulesets) are therefore out of scope here. If `nolte` is migrated to an organisation later, those concerns can be added in a separate root module without disturbing the current code.

It is a deliberate complement to [`nolte/gh-plumbing`](https://github.com/nolte/gh-plumbing):

| Concern | Source of truth |
|---|---|
| Repository **inventory** (which repos exist, description, topics, visibility, has_issues / has_wiki / …) | **this repo** (Terraform `github_repository`) |
| Per-repo **repository rulesets** (modern branch protection) | **this repo** (Terraform `github_repository_ruleset`) |
| Per-repo settings, labels, merge strategy, classic branch protection | [`gh-plumbing`](https://github.com/nolte/gh-plumbing) (Probot Settings App via `_extends`) |
| Reusable workflows, Boring-Cyborg / Stale / Release-Drafter commons, Renovate preset | [`gh-plumbing`](https://github.com/nolte/gh-plumbing) |

To keep both systems from fighting, the `github_repository` resource here `ignore_changes` on every field Probot owns (merge strategies, `delete_branch_on_merge`, auto-merge).

## Getting started

```sh
# Install pinned tool versions (see .tool-versions).
task -l # discover available targets
task tf:fmt # format
task tf:validate # validate every root module
task tf:plan # plan against the live account (requires GITHUB_TOKEN with `repo` scope)
task tf:apply # apply (human-gated)
```

`terraform.tfvars` lives next to the root module and is git-ignored — copy `terraform.example.tfvars` and adjust. **Adopt every existing repo via `terraform import github_repository.managed[""] ` before the first apply**, otherwise Terraform will try to create a duplicate.

State backend is currently **local** (`terraform.tfstate` next to the module). When a remote backend is adopted, update the module and migrate state explicitly.

## Structure

```
terraform/
repos/ # repository inventory + per-repo rulesets
portfolio-app/ # wrapper around gh-plumbing//terraform/portfolio-app
# provisions per-repo PORTFOLIO_APP_ID + PORTFOLIO_APP_PRIVATE_KEY
docs/ # MkDocs source (English)
.github/ # Probot configs + reusable-workflow consumers
scripts/ # operator helpers (gopass → TF_VAR_* env loaders)
```

### portfolio-app credentials

The portfolio-app module needs a GitHub App that is **registered manually** — there is no GitHub API for App creation or private-key generation. Five manual steps before the first `task tf:apply:portfolio-app`:

1. **Register the App** at . Permissions and webhook settings are documented at [`docs/en/portfolio-app.md`](docs/en/portfolio-app.md) and in the [upstream setup guide](https://github.com/nolte/gh-plumbing/blob/develop/docs/en/portfolio-app/setup.md).
2. **Generate a private key** (`.pem`) on the App's settings page.
3. **Note the numeric App ID** (visible on the App's settings page).
4. **Install the App** in every consumer repository (default: `terraform-github-bootstrap`, `gh-plumbing`, `claude-shared`).
5. **Persist credentials in gopass** and let Terraform read them via `TF_VAR_*`:

```sh
GP=internet/github.com/nolte/apps/nolte-portfolio-app
gopass insert "$GP/appid" # numeric App ID
gopass insert "$GP/slug" # e.g. nolte-portfolio-app
gopass insert -m "$GP/private_key" < downloaded.pem
shred -u downloaded.pem

# Each session before plan/apply:
source scripts/portfolio-app-env.sh
task tf:plan:portfolio-app
```

`scripts/portfolio-app-env.sh` exports `TF_VAR_app_id`, `TF_VAR_app_private_key`, and `GITHUB_TOKEN`; nothing touches tfvars or the repo. Full operator runbook at [`docs/en/portfolio-app.md`](docs/en/portfolio-app.md).

> **Spec note.** `spec/project/project-structure/` does not currently list `terraform/` as a sanctioned top-level source tree (only `src/`, `custom_components/`, `.claude-plugin/`, `playbooks/`+`roles/`). This repository uses `terraform/` as a conscious extension — analogous to the Ansible exception. Tracked under `spec/source-layout-extension.md` once the spec amendment lands upstream.

## Related repositories

- [`nolte/gh-plumbing`](https://github.com/nolte/gh-plumbing) — per-repo Probot Settings, reusable workflows, Renovate preset.
- [`nolte/claude-shared`](https://github.com/nolte/claude-shared) — Claude Code plugin used to scaffold this repository.

## Status

Bootstrap / pre-MVP. Local state, no CI gate on `tf:plan` yet. Repository inventory starts with this bootstrap repo itself (dogfood) and is meant to grow one `terraform import` at a time.

## License

To be added. See open question in `spec/`.