12 Commits

Author SHA1 Message Date
unkinben cad35f8d9b repository: stop migration_mirror_interval planning an update every run
ci/woodpecker/pr/plan Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Why:
- The go-gitea/gitea provider schema defaults migration_mirror_interval to
  "8h0m0s", but on read it writes repo.MirrorInterval straight back into state,
  and Gitea returns an empty MirrorInterval for non-mirror repositories.
- So the stored value ("") never matches the schema default ("8h0m0s"), and tofu
  plans an in-place update of every gitea_repository on every run even with no
  config change, keeping terraform-git plans perpetually dirty.
- migration_mirror_interval is the only migration_* field read back from the API;
  the rest are write-only migration options, so no sibling field churns.

Change:
- Add a targeted ignore_changes on migration_mirror_interval at the repository
  module so the provider default no longer fights Gitea's empty value, making
  every repository idempotent. It is a migration-only knob with no drift to track
  for these non-mirror repos.
2026-08-11 21:14:24 +10:00
unkinben df118383da team: stop spurious edits that fail Gitea 1.26 permission validation
ci/woodpecker/pr/plan Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Why:
- The go-gitea/gitea provider's SDK (v0.25.1, already shipped in provider
  0.8.1 on main) rejects a team permission of `none` on every EditTeam with
  "permission mode invalid"; it only accepts read/write/admin/owner
  client-side. The same check exists in the older 0.21.0 SDK, so the provider
  version is not the lever here.
- The team module's `units` (server returns an unordered space-separated
  string that never matches the provider's comma-ordered default) and
  `repositories` (provider sorts state; `include_all_repositories` populates
  every repo) drift on representation alone, so every apply plans an in-place
  update for every team.
- Each update calls EditTeam, which replays the stored `permission=none` kept
  by `ignore_changes` and fails, blocking apply for every non-owner team
  (docker/terraform/rpmbuild/puppet/pybuild/forgebot/agents) and the whole
  terraform-git apply, including the unkin-agent rollout.

Change:
- Add `units` and `repositories` to the team `ignore_changes` so provider
  representation churn no longer triggers an EditTeam call.
- Preserve each team's current on-server permission and repository membership
  (no access change).
2026-08-09 12:31:19 +10:00
unkinben a43267532a Import pre-existing Gitea branch protections
ci/woodpecker/pr/plan Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Why:
- tofu apply fails with "Branch protection already exist" because the nine
  repos protected in #60 already have live branch protection in Gitea that is
  absent from Terraform state, so Terraform tries to create rules that already
  exist and Gitea rejects them.
- The pinned go-gitea/gitea provider 0.7.0 defines no importer for
  gitea_repository_branch_protection, so the existing rules cannot be adopted
  on that version.

How:
- Bump the gitea provider from 0.7.0 to 0.8.1, which adds an importer for
  gitea_repository_branch_protection (id format <org>/<repo>/<rule_name>).
- Add import blocks adopting the nine existing branch protections into state
  instead of recreating them.
2026-08-09 11:45:26 +10:00
unkinben bd7bef9f99 user: add gitea-vault-admin site-admin bot and one-time Vault KV seeding
ci/woodpecker/pr/plan Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Why: the vault-plugin-secrets-gitea engine needs a purpose-built Gitea
site-admin credential to mint and delete per-user tokens. Provision that
account and its Vault seed here so the credential is generated once and never
exposed. Ben asked that the password be written to Vault exactly once and
never updated afterwards.

Change:
- Add config/git.unkin.net/user/gitea-vault-admin.yaml: a local site-admin bot
  (admin: true, limited visibility, no org/repo creation).
- Extend the user module with an optional vault_seed_path/vault_seed_mount: when
  set, write the account's generated password to Vault KV as admin_username and
  admin_password via vault_kv_secret_v2, with lifecycle ignore_changes on
  data_json so the write is create-only and never churns (random_password
  already never regenerates). This keeps the seed stable and prevents a re-apply
  from overwriting a password later rotated out-of-band by rotate-root.
- Add the hashicorp/vault provider (module plus root generate block); it reads
  VAULT_ADDR and VAULT_TOKEN already exported by the Makefile k8s login.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-27 19:26:24 +10:00
unkinben fd82876f5f Manage Gitea users; add teabot personality bot accounts
ci/woodpecker/pr/plan Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Add a data-driven 'user' config kind so Gitea accounts are declared as
config/git.unkin.net/user/<name>.yaml, mirroring the existing repository
and team kinds. Wire the yaml into a new modules/user submodule that
creates a gitea_user (provider go-gitea/gitea 0.7.0, already pinned).

The provider's user resource requires a password; generate a per-user
random_password so nothing sensitive is hardcoded and only a placeholder
lives in state (tokens come later from vault-plugin-secrets-gitea).

Provision teabot's implementer and reviewer personality accounts with a
conservative posture: not site admins, no org creation, no repo creation,
limited profile visibility.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-27 17:22:19 +10:00
unkinben 85583a02ad Remove woodpecker module and fix branch protection dependency
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
- Remove woodpecker_repository module and provider (repos managed outside TF)
- Add removed block with destroy=false to drop state without destroying
- Add module.team to branch_protection depends_on to prevent race condition
- Add lifecycle ignore_changes for team permission (provider bug: API returns
  "none" but rejects it on write)
2026-06-12 22:26:19 +10:00
unkinben bd60fb3669 Add forgebot and forgebot-skills repos with branch protection
- forgebot: branch protection on main with pre-commit, test, build CI checks
- forgebot-skills: branch protection on main with validate CI check
- Both repos enabled for Woodpecker CI
2026-06-12 00:32:57 +10:00
unkinben dc9f3cd595 fix: remove unused deploy_key variable and duplicate required_providers
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/plan Pipeline was successful
2026-06-11 23:30:23 +10:00
unkinben 883faee35c style: tofu fmt alignment
ci/woodpecker/pr/pre-commit Pipeline failed
ci/woodpecker/pr/plan Pipeline failed
2026-06-11 23:28:02 +10:00
unkinben 6203e4d0e2 fix: add terraform.tf for pre-commit validation
ci/woodpecker/pr/pre-commit Pipeline failed
ci/woodpecker/pr/plan Pipeline failed
Required for tofu-validate and tflint to work standalone
without the terragrunt-generated backend.tf.
2026-06-11 23:25:32 +10:00
unkinben 1b127941f8 feat: add terraform-git
ci/woodpecker/pr/pre-commit Pipeline failed
ci/woodpecker/pr/plan Pipeline was successful
- add new repo
- change write -> none
2026-06-11 23:23:29 +10:00
unkinben c87b3ac471 feat: initial terraform-git project
Manage Gitea resources via Terraform/Terragrunt with YAML-driven config.

Resources managed:
- Organisation (unkin)
- 28 repositories with settings
- 6 teams with members
- 13 branch protection rules
- 9 Woodpecker CI repo activations
- Deploy key module (ready, no keys yet)

Config structure: config/<service>/<org>/<type>/<object>.yaml
Consul backend for state, Vault for auth tokens.
2026-06-10 23:45:41 +10:00