repospawner opens repo-creation PRs against terraform-git and needs no other
access, so give it its own identity and a per-repo team instead of adding it to
the org-wide agents team.
- add config/git.unkin.net/user/repospawner.yaml (limited visibility, not admin,
no org/repo creation), mirroring the unkin-agent bot posture
- add config/git.unkin.net/unkin/team/repospawner.yaml granting write on the
terraform-git repository only (include_all_repositories false)
Why: AI coding agents currently push and open PRs as Ben's own account
using Ben's token, so their work is unattributable and carries Ben's full
owner privileges. A dedicated least-privilege identity separates agent work
from Ben's and keeps merge a human decision.
How:
- add the unkin-agent bot user (non-admin, no org/repo creation, limited
visibility); it authenticates via ephemeral vault-plugin-secrets-gitea
tokens, not a stored password
- add the agents team granting Write on all unkin repositories, the minimum
needed to push branches and open PRs; unkin-agent is its only member
- add merge_whitelist_teams Owners to every default-branch protection rule
that lacked a merge whitelist, so Write no longer implies merge and only
Owners (Ben) can merge across the estate
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
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