The waitfordb CI is being split into three Woodpecker PR workflows
(pre-commit, test, build), each exposing its own status context. Require
all three on the main branch protection so a PR cannot merge until
pre-commit, test, and build all pass. Mirrors node-lookup.
Owners-only merge, benvin approval, and the required Woodpecker PR check.
Requires the repo to be activated in Woodpecker so ci/woodpecker/pr/build
reports before a PR can merge.
waitfordb is a small Go tool shipped as a container image, used as a Kubernetes
initContainer to block an app from starting until its database is ready. It
replaces the hand-written psql-in-a-shell init steps on the arrstack.
Creates the unkin/waitfordb Gitea repo (Go tool settings mirroring node-lookup:
public, squash merges, delete branch after merge). branch_protection is omitted
on creation to avoid requiring Woodpecker status checks that do not exist until
the first pipeline runs; it will be added in a follow-up PR once CI is green.
terraform-provider-arrstackvaultsecret is a bespoke Terraform provider that
configures the new arrstack Vault/OpenBao secrets engine (engine config +
roles) from terraform-vault, following the per-engine-provider convention
used by the gpg/litellm/rancher vault-secret providers. It needs a Gitea
repo to host its source before CI and releases can be wired up.
- add config/git.unkin.net/unkin/repository/terraform-provider-arrstackvaultsecret.yaml
- public repo, default branch main, delete-branch-after-merge, squash-only
- Owners-only merge with required pre-commit/build/test Woodpecker checks
vault-plugin-secrets-arrstack is a new Vault/OpenBao secrets engine that
dynamically mints arrproxy machine (per-user) API tokens, enabling
terraform-driven onboarding of *arr services. It needs a Gitea repo to
host its source before CI and releases can be wired up.
- add config/git.unkin.net/unkin/repository/vault-plugin-secrets-arrstack.yaml
- public repo, default branch main, delete-branch-after-merge, squash-only
- Owners-only merge with required pre-commit/build/test Woodpecker checks
Now that each fork's Woodpecker image build is green, lock down main:
Owners-only merge, PRs must pass the build check, and the owner may push
main directly for upstream-fix maintenance merges.
- add branch_protection(main) to sonarr/radarr/prowlarr.yaml
- required check: ci/woodpecker/pr/docker; merge whitelist: Owners; push whitelist: unkinben
Create the three arrstack source-fork repos (Postgres + stateless
multi-replica work). No branch protection yet so the initial upstream
mirror can be force-pushed; a follow-up PR adds protection + required
Woodpecker checks once CI exists.
Match the sibling Go service repo convention (node-lookup/encapi):
require the woodpecker pre-commit/test/build PR status checks,
squash merge style, and restrict merge/approval to Owners/benvin.
Match the vault-secrets-netbox naming convention: repo
terraform-provider-vault-secrets-ghp, provider source address
git.unkin.net/unkin/vault-secrets-ghp, resources ghp_secret_backend /
ghp_secret_role. Renames the repo (the only content was an unmerged scaffold PR,
which is re-pushed to the new repo).
P4 steps 5-6: a Vault/OpenBao secrets engine that mints scoped ghp access tokens
via ghp's admin API (authenticating with the static admin service token now
deployed), plus its Terraform provider. Mirrors the vault-plugin-secrets-gitea /
terraform-provider-giteavaultsecret pair.
Provision the Gitea repo for the autobackup-operator, a Kubernetes
operator that creates S3 buckets and backup schedules from
backups.unkin.net/* annotations on PVCs and CNPG clusters. Matches the
convention of sibling operator repos (private=false, squash merges,
main branch protection with pre-commit/test/build checks).
Why: the jellyfin-ha-src main branch is protected but merges are not gated
on CI, so a pull request can be merged while its Woodpecker build is red.
How: add the ci/woodpecker/pr/ci context to the main branch protection
rule. The gitea provider computes enable_status_check from a non-empty
context list, so this turns required status checks on and blocks merge
until that exact check passes.
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.
Now that the source fork is seeded on main with the pinned upstream tree and a
pristine upstream ref, enable branch protection on main: block direct pushes
and require an Owners approval so future changes land through reviewed pull
requests.
Add the jellyfin-ha-src Gitea repository that carries the HA source fork of
ZoltyMat/jellyfin-ha with local patches, replacing the direct upstream clone
in the build pipeline.
Declare the repository as public with a main default branch and
delete-branch-after-merge enabled. Leave branch protection unset so the
initial fork seed can push the pinned upstream tree and a pristine upstream
ref directly to main; protection is added in a follow-up change once the fork
is seeded.
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).
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.
Why:
- An audit for the new unkin-agent bot (org-wide write) found repos with
no branch_protection at all, so the agent (or anyone with write) could
push straight to their default branch.
- The rest of the estate protects default branches; these repos were the gap.
How:
- Add enable_push: false + approval_whitelist_teams: Owners on each active
repo's default branch, matching the estate's most common convention
(PR-only; Owners can still open and approve).
- Omit status checks on these repos as none run CI, so a required context
would permanently block merges.
- Leave the 8 archived repos untouched: they are read-only, nothing can push
to them, and branch-protection creation on archived repos is rejected.
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