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.
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:
- 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
bootapi-images builds the AlmaLinux node rootfs tarballs that bootapi's
image-based provisioning (liveimg) unpacks, and on a v* tag publishes
almalinux9-node-<ver>.tar.zst to the artifactapi rootfs-images local repo. Split
out of bootapi-templates so that repo stays templates-only.
Modeled on the bootapi-templates entry: public, squash, delete-branch-after-merge,
main protection requiring the pre-commit + lint Woodpecker checks and benvin
approval.
Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
bootapi-templates holds the live kickstart/iPXE templates and the distro catalog
that bootapi pulls via git-sync (every ~3m, like argocd), so template/OS changes
ship without rebuilding bootapi. Its CI validates that every template parses and
renders for every catalog distro (via 'bootapi validate') plus shellcheck on the
%post snippets.
Modeled on the bootapi repo entry: public, squash, delete-branch-after-merge,
main protection requiring the pre-commit + validate Woodpecker checks and benvin
approval.
Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
bootapi is a Go service replacing Cobbler's PXE/kickstart side: it renders
kickstart files and iPXE boot scripts from NetBox data and serves them to
PXE-booting hosts. The ENC half already moved to encapi; bootapi covers the
provisioning/boot half.
Adds config/git.unkin.net/unkin/repository/bootapi.yaml modeled on encapi:
public repo, squash merges, delete-branch-after-merge, main branch protection
requiring the pre-commit/test/build Woodpecker checks and benvin approval.
Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
Registers the logarchiver Gitea repo: a k8s Go service that archives
raw logs from NATS JetStream to S3 as zstd-compressed, GPG-encrypted,
indexed objects, plus a CLI to search and retrieve them. It replaces the
Vector archiver leg of the centralized logging stack (argocd-apps #296)
with zstd compression, OpenPGP encryption keyed from the Vault GPG
secrets engine, and a ClickHouse-backed searchable index.
- Add config/git.unkin.net/unkin/repository/logarchiver.yaml modeled on
the existing Go-service repos (encapi, cephrgw-operator): public repo,
main default branch, squash merges, branch protection requiring the
woodpecker pre-commit/test/build PR checks with benvin approval.
Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
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
Create the Gitea repositories for the new vault-plugin-secrets-gitea
secrets engine and its companion terraform-provider-giteavaultsecret,
mirroring the rancher pair's settings.
- add config/git.unkin.net/unkin/repository/vault-plugin-secrets-gitea.yaml
- add config/git.unkin.net/unkin/repository/terraform-provider-giteavaultsecret.yaml
Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
terragrunt-enc will be the single source of truth for encapi ENC data
(statuses, roles, node classifications), managed via Terraform/Terragrunt,
superseding Cobbler classification for Puppet.
- Add config/git.unkin.net/unkin/repository/terragrunt-enc.yaml (public,
default_branch main, delete-branch-after-merge, squash merges).
- Protect main: block direct pushes, require the two Woodpecker PR status
checks (pre-commit, plan), and whitelist benvin for approvals.
The cephrgw-operator provisions Ceph RGW (S3) buckets and access keys from
Kubernetes CRDs via the Ceph manager dashboard API, and needs a Gitea repo
to host its code and run Woodpecker CI.
- Add config/git.unkin.net/unkin/repository/cephrgw-operator.yaml with the
standard public-repo settings (squash merge, delete branch on merge) and
main branch protection requiring the pre-commit/test/build PR checks.
Add branch protection to the openbao fork repository so main is protected: only
the owner may push directly and other changes must land via a pull request that
passes the fork build pipeline.
- Add branch_protection for main (whitelist-push to the owner; require the
ci/woodpecker/pr/build status check on PRs); set squash as the default merge
RFC2136 dynamic-DNS updater daemon (Go) that replaces the puppet dns-update
shell script. Squash merge, protected main with woodpecker build/test/pre-commit
status checks.
Create the Gitea repository for the private OpenBao fork so its integration
branch (main) can be pushed and hosted on git.unkin.net.
- Add config/git.unkin.net/unkin/repository/openbao.yaml (private, default branch
main, delete branch after merge)
The Terraform provider for the gpg secrets engine needs a Gitea repo to hold
its source and run its Woodpecker PR/release pipelines.
- Add config/git.unkin.net/unkin/repository/terraform-provider-gpgvaultsecret.yaml
(public, main default branch, squash-only, main branch protection gated on the
pre-commit/build/test PR checks), mirroring the sibling
terraform-provider-litellmvaultsecret repo.
passv (a Vault-backed drop-in for pass) needs a Gitea repo to hold its source
and run its Woodpecker PR/release pipelines.
- Add config/git.unkin.net/unkin/repository/passv.yaml (public, main default
branch, squash-only, main branch protection gated on the pre-commit/build/test
PR checks), mirroring the sibling vault-plugin-secrets-gpg repo.
Creates the two Gitea repositories backing the new Rancher token secrets engine:
a Vault/OpenBao plugin and its Terraform provider.
- Add config/git.unkin.net/unkin/repository/vault-plugin-secrets-rancher.yaml
(squash-only, main protected on pre-commit/build/test).
- Add config/git.unkin.net/unkin/repository/terraform-provider-ranchervaultsecret.yaml
(same protection profile as the litellm provider repo).
Provision the terraform-rancher Gitea repo, which will manage Rancher's
Authentik OIDC auth (keycloakoidc AuthConfig) via the rancher2 provider,
mirroring the terraform-authentik pattern.
The GPG/OpenPGP secrets engine needs a Gitea repo to hold its source and run
its Woodpecker PR/release pipelines.
- Add config/git.unkin.net/unkin/repository/vault-plugin-secrets-gpg.yaml
(public, main default branch, squash-only, main branch protection gated on
the pre-commit/build/test PR checks), mirroring the sibling
vault-plugin-secrets-bind-tsig repo.
Register a new public repo to host benvin-utils, a monorepo of small
single-purpose CLI tools (first tool: podgap) that share a common Go library.
- Add config/git.unkin.net/unkin/repository/benvin-utils.yaml (main default branch, delete branch after merge)
Declares the repo for a HashiCorp Vault / OpenBao secrets engine that
manages BIND TSIG keys via the bind-operator (static rotation + dynamic
creds). Mirrors the vault-plugin-secrets-litellm repo config.
Adds the Gitea repository that manages the Docker container build for the
jellyfin-ha (HA transcoding) Jellyfin fork.
- Create unkin/jellyfin-ha (public, squash merges, delete branch on merge)
- Protect main; require the ci/woodpecker/pr/build check and docker-team approval