Manage Gitea users; add teabot personality bot accounts
ci/woodpecker/pr/plan Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful

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
This commit is contained in:
2026-07-27 17:22:19 +10:00
parent ee08fd5585
commit fd82876f5f
10 changed files with 198 additions and 0 deletions
@@ -0,0 +1,37 @@
# The gitea_user resource requires a password argument. These accounts
# authenticate via API tokens (issued out-of-band by the
# vault-plugin-secrets-gitea engine, or a static KV entry initially), so the
# password is never used interactively. It is generated here so nothing
# sensitive is hardcoded, and kept only in state.
resource "random_password" "this" {
length = 32
special = true
override_special = "!@#%^&*()-_=+"
}
resource "gitea_user" "this" {
username = var.username
login_name = coalesce(var.login_name, var.username)
email = var.email
password = random_password.this.result
full_name = var.full_name
description = var.description
visibility = var.visibility
admin = var.admin
restricted = var.restricted
active = var.active
allow_create_organization = var.allow_create_organization
max_repo_creation = var.max_repo_creation
must_change_password = var.must_change_password
# Do not e-mail the (possibly unmonitored) bot address on creation.
send_notification = false
lifecycle {
# The provider cannot read the password back from the API; ignore it so the
# account never shows perpetual drift once created.
ignore_changes = [password]
}
}
@@ -0,0 +1,13 @@
terraform {
required_version = ">= 1.10"
required_providers {
gitea = {
source = "go-gitea/gitea"
version = "0.7.0"
}
random = {
source = "hashicorp/random"
version = ">= 3.5"
}
}
}
@@ -0,0 +1,69 @@
variable "username" {
description = "Username of the Gitea account (immutable; changing it recreates the user)"
type = string
}
variable "login_name" {
description = "Login name, may differ from username. Defaults to the username."
type = string
default = null
}
variable "email" {
description = "E-Mail address of the user"
type = string
}
variable "full_name" {
description = "Display / full name of the user"
type = string
default = ""
}
variable "description" {
description = "Profile description of the user"
type = string
default = ""
}
variable "visibility" {
description = "Profile visibility: public, limited or private"
type = string
default = "limited"
}
variable "admin" {
description = "Whether the user is a site administrator"
type = bool
default = false
}
variable "restricted" {
description = "Restricted users can only access repositories/orgs they are explicitly added to"
type = bool
default = false
}
variable "active" {
description = "Whether the account is active"
type = bool
default = true
}
variable "allow_create_organization" {
description = "Whether the user may create organisations"
type = bool
default = false
}
variable "max_repo_creation" {
description = "Maximum number of repositories the user may create (0 disallows creation)"
type = number
default = 0
}
variable "must_change_password" {
description = "Force a password change on first login"
type = bool
default = false
}