Add unkin-agent Gitea identity with write but no merge
ci/woodpecker/pr/plan Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful

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
This commit is contained in:
2026-08-08 22:37:52 +10:00
parent 4be9899e8e
commit 4953142200
45 changed files with 118 additions and 0 deletions
@@ -4,6 +4,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "master"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
# Whitelist-push: the owner can push main directly (needed for the initial
# push and the fork's maintenance workflow); everyone else must open a PR.
enable_push: true
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -4,6 +4,8 @@ default_branch: "main"
default_delete_branch_after_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -4,6 +4,8 @@ default_branch: "main"
default_delete_branch_after_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -3,6 +3,8 @@ private: false
default_delete_branch_after_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,4 +5,6 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -10,6 +10,8 @@ allow_rebase_explicit: false
allow_squash_merge: true
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/pre-commit"
@@ -5,6 +5,8 @@ default_delete_branch_after_merge: true
default_merge_style: "squash"
branch_protection:
- rule_name: "main"
merge_whitelist_teams:
- "Owners"
enable_push: false
status_check_contexts:
- "ci/woodpecker/pr/build"
@@ -0,0 +1,14 @@
# Grants the unkin-agent bot Write across every unkin repository so Ben's AI
# coding agents can push benvin/* branches and open pull requests. Write is the
# minimum Gitea permission that allows pushing branches + creating PRs.
#
# Merge stays reserved for Ben: branch protection on every default branch sets a
# merge whitelist of the Owners team only, so members of this team can push and
# open PRs but cannot merge or approve. Keep this team out of every merge and
# approval whitelist.
description: "AI coding agents -- push branches + open PRs, never merge"
permission: write
include_all_repositories: true
can_create_repos: false
members:
- unkin-agent
@@ -0,0 +1,18 @@
# Shared identity used by Ben's AI coding agents to submit work (branches, pull
# requests, issues, comments) as a distinct, attributable, least-privilege
# account instead of Ben's own login. Auth is via ephemeral API tokens minted by
# the vault-plugin-secrets-gitea engine (gitea/creds/unkin-agent) -- no token or
# usable password lives in this repo's state beyond the generated placeholder.
#
# Write access comes from the "agents" team (team/agents.yaml); merge is blocked
# by branch protection (merge whitelist = Owners only), so the agent can open and
# comment on PRs/issues but never merge or approve.
email: unkin-agent@unkin.net
full_name: "Unkin Agent"
description: "shared identity for automated AI coding agents -- write, never merge"
# Conservative bot posture: not a site admin, cannot create orgs or repos,
# profile visible only to signed-in users.
visibility: limited
admin: false
allow_create_organization: false
max_repo_creation: 0