This is the multi-page printable view of this section. Click here to print.
OpenSpec
- 1: Specifications
- 1.1: Infra forgejo
- 1.2: Owned dns
- 1.2.1: owned-dns Specification
1 - Specifications
1.1 - Infra forgejo
1.1.1 - Forgejo infrastructure specification
Purpose
Describe the Forgejo service owned by infra/forgejo, including Xen
Orchestra provisioning, Ansible service configuration, and Terraform account
and repository management. The tf_setup, ansible, and tf packages are
implementation stages of this owner. This baseline records source guarantees
and prerequisites; it does not verify live service health or restore earlier
Forgejo data.
Baseline revision: 550d7e79b1f5fdbc2b6017b75178471d6914082f.
Observed: 2026-09-08. Sources: owner README,
BUILD, and the implementation links below.
Requirements
Requirement: Scoped Xen Orchestra provisioning and disk checks
Setup SHALL provision Forgejo through Xen Orchestra in the
src_infra_dc1_forgejo1 resource set using the owner’s Vault AppRole and
packaged XO OIDC login flow. The VM SHALL declare 20 GiB boot, 40 GiB
Forgejo, and 5 GiB Traefik disks. Ansible SHALL verify the expected sizes
of xvdb and xvdc before applying the service roles that use them.
Sources: setup contract, setup BUILD, VM definition, and deployment playbook.
Scenario: Detect unexpected Xen disk attachments
- WHEN Ansible gathers disks that do not match the expected Forgejo and Traefik device names and sizes
- THEN its pre-task assertion fails before the service roles run
Requirement: Canonical service routing with legacy hostname support
Forgejo SHALL configure https://git.alwaldend.com/ as its canonical root
URL, bind its HTTP service to loopback port 3000, and enable the built-in
SSH service on port 3005. Traefik SHALL route the canonical hostname, the
inventory hostname, and forgejo.alwaldend.com to that HTTP service with
the Vault certificate resolver.
Sources: service variables, Forgejo configuration, and Traefik routing.
Scenario: Inspect support for existing Forgejo clients
- WHEN the Traefik routing template is rendered with the owner’s variables
- THEN the canonical and legacy hostnames resolve to the same configured loopback service
- AND generated Forgejo URLs use the canonical Git hostname
Requirement: Guarded Vault OIDC bootstrap
The deployment playbook SHALL create a missing vault OIDC authentication
source after configuring the Forgejo service. It SHALL preserve one existing
active OAuth2 source and reject multiple matches, an inactive source, or a
source of another type. Creation SHALL obtain client credentials from the
injected environment and suppress secret-bearing task output.
Source: deployment playbook.
Scenario: Preserve an existing active authentication source
- WHEN Forgejo reports exactly one active OAuth2 source named
vault - THEN the bootstrap accepts it and skips source creation
Scenario: Reject an ambiguous authentication source
- WHEN more than one
vaultsource is discovered, or its type or active state is incompatible - THEN the bootstrap assertion fails rather than selecting or replacing an arbitrary source
Requirement: Vault identities and service grants with catalog named roles
Service Terraform SHALL require a verified positive integer Vault OAuth
source ID, discover login users from the owning Vault group through at most
two nested group levels, and use entity UUIDs as external login names.
Managed accounts SHALL be protected from deletion. The shared repository
catalog SHALL own named organization administrator and developer assignments
and organization-owned repository identities. Catalog members and Vault
access-group members SHALL belong to the discovered login population.
Existing Vault service-administrator, package-writer, and automation-writer
grants SHALL be retained; the src automation writer group SHALL resolve to
exactly one user. A catalog developer SHALL NOT also receive administrator
access through the retained Vault groups.
Sources: service Terraform contract, users, access validation, and repository access. The shared catalog contract owns repository naming and named-role assignments; its adoption change records the source migration and pending verification.
Scenario: Reject unsupported group membership
- WHEN a login group extends beyond two nested levels, an access-group member is outside the login population, or the automation writer count is not one
- THEN the corresponding Terraform condition rejects the configuration
- AND Terraform does not silently omit the unsupported membership
Scenario: Resolve a catalog member through Vault
- WHEN a catalog administrator or developer is assigned organization access
- THEN that assignment uses the discovered account’s existing Vault entity UUID and verified OAuth source mapping
- AND the assignment does not create a password-based replacement account
Scenario: Retain service access while restricting a named developer
- WHEN shared named roles are adopted
- THEN existing Vault service administration, package-writing, and automation-writer grants remain configured
- AND the catalog developer receives feature-branch and pull-request access without a default-branch push or merge bypass
- AND an overlapping administrator grant for that developer fails validation
1.2 - Owned dns
1.2.1 - owned-dns Specification
Purpose
Define Forgejo DNS management through the owner’s tf_setup root,
including canonical declarations, scoped credentials, and offline source checks
before adopting live records.
Requirements
Requirement: Owner-local DNS configuration
The tf_setup root SHALL consume this owner’s canonical dnsconfig.json through
the shared DNS Terraform module, preserving declared record identities and views.
DNS resources SHALL default to disabled before adoption and SHALL remain enabled
by default after authorized adoption. Adoption SHALL bind existing provider records
to the owner’s state without adding, changing, replacing, or deleting DNS records.
Subsequent reconciliation of unchanged declarations SHALL preserve owned and
unrelated records.
Scenario: Inspect the preparatory configuration
- WHEN the checked-in root is evaluated with default inputs before adoption
- THEN it reads this owner’s declaration and disables managed DNS records
- AND the package contains the module and declaration inputs
Scenario: Inspect the adopted configuration
- WHEN the adopted root is evaluated with default inputs
- THEN it reads this owner’s declaration and enables managed DNS records
- AND the package contains the module and declaration inputs
Scenario: Adopt existing records
- WHEN the owner reviews the matched existing provider imports through
//infra/forgejo/tf_setup:dns.planand:dns.show, then applies that saved plan through:dns.apply - THEN the owner state binds each declared record to its existing provider identity
- AND the reviewed adoption plan proposes no record additions, changes, replacements, or deletions
Scenario: Reconcile unchanged declarations
- WHEN the adopted root plans unchanged declarations through
//infra/forgejo/tf_setup:dns.planand applies its reviewed saved plan through:dns.apply - THEN it makes no DNS resource changes
- AND owned records retain their declared values and views while unrelated records remain unchanged
Requirement: Scoped DNS execution and offline checks
The DNS wrapper SHALL select src_infra_dc1_forgejo1 through the repository AL
flow and keep secret values in injected variables. Dedicated DNS commands SHALL
select dns=1, retain the existing setup backend, and target module.dns without
starting unrelated service authentication. DNS apply SHALL consume only a
reviewed saved plan. Real DNS credentials and Vault policy grants SHALL be
prerequisites for operational Terraform calls. RouterOS DNS credentials SHALL be
isolated from unrelated RouterOS resources. The package SHALL expose a format
test that does not authenticate to Vault or contact DNS providers.
Scenario: Validate the Terraform source
- WHEN the package format test executes
- THEN it checks the packaged Terraform configuration without live credentials
- AND existing non-DNS authentication and backend paths remain unchanged
Scenario: Prepare an operational Terraform invocation
- WHEN the wrapper selects its Terraform stage labels
- THEN it selects DNS credential injection through the owner AppRole with
dns=1, the existing setup backend, and themodule.dnstarget - AND disabled DNS resources do not imply offline provider configuration