Neither repo has a test workflow, so the required ci/woodpecker/pr/test
context never reports and every PR stays permanently unmergeable.
- Remove ci/woodpecker/pr/test from status_check_contexts on both repos
- Keep ci/woodpecker/pr/build and ci/woodpecker/pr/pre-commit
Add a pull mirror of github.com/9p4/jellyfin-plugin-sso into the mirrors
organisation, syncing every 8h with issues, pull requests and release
migration disabled.
gitea_fork can only express the source repo and owning organisation, so any
other setting in a fork's yaml is silently dropped.
- validate fork_from entries carry no other repository attributes, naming the
offending config key and attributes
- note that gitea_fork has no archive_on_destroy
Express a fork as an optional fork_from key on the repository yaml, so a
forked repo is declared the same way as any other repo.
- add fork_from "<owner>/<repo>" to the repository module and object type
- create gitea_fork instead of gitea_repository when fork_from is set
- validate the source repo name matches the config file name, since a fork
inherits the source name
- move gitea_repository.this to index 0 for the count refactor
- index existing repository import targets to match
Host the Go rewrites of the certmanager and sshsignhost Vault signing
helpers.
- Add config/git.unkin.net/unkin/repository/puppet-vault-signers.yaml
- Protect main with Owners-only merge and the standard woodpecker checks
Defense in depth for the repo-creation bot: a restricted Gitea account can
only see repositories and organisations it is explicitly added to, so a
leaked repospawner token cannot enumerate or read the rest of the estate.
The repospawner team grant on terraform-git already covers everything the
bot does, so nothing it needs is lost.
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)
The terraform-nomad project is being decommissioned; mark it archived
in Gitea so it becomes read-only, consistent with other retired repos
in this config (e.g. rpmbuild-template).
PR plan pipelines were failing with "Error acquiring the state lock"
when they collided with a concurrent apply (or another plan) holding
the lock on the same Consul-backed state.
- plan: pass -lock=false to terragrunt plan; apply/apply-if-changes keep locking
Both repos do not need to be private, and their main branches should
only accept PRs whose Woodpecker pipeline passed.
- private: false for clickhouse-tools and logviewer
- require ci/woodpecker/pr/build status check on main for both
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
Scope grew beyond IPAM (devices, provisioning). Renaming the config file renames
the managed repo; the gitea provider archives the old terraform-ipam repo
(archive_on_destroy=true) and creates terraform-infra. terraform-ipam only holds an
auto-init README, so nothing is lost.
Claude-Session: https://claude.ai/code/session_01JUoARVdmhxKQHyyyp1pxeT
Provision the Gitea repo for a generic app-token Vault/OpenBao secrets
engine that issues short-lived signed JWTs for self-made services,
replacing per-app static bearer Secrets. Mirrors the existing plugin repo
entries (squash-only, main branch protection, PR CI checks).
Claude-Session: https://claude.ai/code/session_01JUoARVdmhxKQHyyyp1pxeT
Provision the repo for the new Kea DHCP Kubernetes operator that replaces
the ISC dhcpd PXE-boot VM.
- add config/git.unkin.net/unkin/repository/kea-operator.yaml
Claude-Session: https://claude.ai/code/session_01JUoARVdmhxKQHyyyp1pxeT
description:"Base container images for the estate, carrying internal CA trust and dnf/repo configuration, built as a matrix across the supported distros."
description:"Go toolchain builder container image, built on each supported container-base distro image, used by Woodpecker pipelines to compile Go projects."
description:"Build repo that compiles the tailscale/go-cache-plugin GOCACHEPROG S3 Go build cache from a pinned upstream module version and publishes static binaries as Gitea releases."
description:"Media copy/move tool: Go API + UI spawning per-file k8s Jobs from mediafs CephFS to media PVCs; doubles as a Ceph aggregate-bandwidth test"
description:"HashiCorp Vault / OpenBao secrets engine for ghp: mints ephemeral, scoped access tokens via the ghp admin API, authenticating as a static admin service token"
private:false
default_branch:"main"
default_delete_branch_after_merge:true
# Squash-only: the gitea provider has no "default merge style", so we restrict
description:"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."
# migration_mirror_interval defaults to "8h0m0s" but Gitea returns an empty MirrorInterval for non-mirror repos, so the read-back never matches and plans a spurious update every run; it is a migration-only knob with no drift to track here.
ignore_changes=[migration_mirror_interval]
}
}
moved{
from=gitea_repository.this
to=gitea_repository.this[0]
}
# gitea_fork has no archive_on_destroy, so removing a fork from the config deletes the repository instead of archiving it.
error_message="fork_from source repository must be named \"${var.name}\": a fork inherits the source name, so it cannot differ from the config file name."
# Gitea's SDK rejects the stored permission=none on any EditTeam call; units/repositories only churn on provider representation (unordered units string, sorted/include-all repos), so ignore them to avoid spurious edits that would fail.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.