This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Repositories

Shared organization, repository, and access configuration

This project owns the organization and repository catalog consumed by GitHub, GitLab, and Forgejo. Named organization administrators and developers belong in this catalog. Root configuration owns the schema version and defaults. Each organization owns orgs/<organization>/org.json and one orgs/<organization>/repos/<repository>.json file per repository. Vault continues to own Forgejo login identities and service-specific access.

First-party means owned by us, regardless of forge. Our repositories retain their chosen names across GitHub, GitLab, and Forgejo: alwaldend/src stays alwaldend/src, including when copied or synchronized between those forges.

Forks and mirrors of external repositories must belong to an organization in the catalog. Their names use the original upstream hostname in reverse order, followed by its full owner and repository path, in lowercase with punctuation replaced by underscores. For example, https://gitlab.com/fdroid/fdroiddata becomes alwaldend/com_gitlab_fdroid_fdroiddata. Copies on another forge keep that name; they do not add a prefix for our intermediate copy. This naming rule also applies to external repositories imported once for later syncing.

The Terraform module owns this derivation. A forge key opts a repository into that consumer. GitLab import_from refers to the corresponding catalog source; fork_from identifies a GitLab upstream. External origins belong in the repository’s upstream_url. Forge-specific overrides preserve settings such as Pages sites and repository descriptions during adoption.

Consumers retain their own providers, state, and Vault authentication. They adopt existing remote resources by import and preserve managed resource addresses or declare explicit moves. Named developers can read repositories, write feature branches, and open pull or merge requests; protected default branches restrict pushes and merges to administrators and any separately owned existing service grants. Catalog GitHub repositories permit merge commits only: the shared defaults disable squash merges and rebase merges, and a catalog precondition rejects any repository record that enables them. Merging therefore keeps the reviewed feature commit as a parent of the default-branch commit instead of replacing it. GitLab and Forgejo merge methods are not owned here. Dedicated per-project landing repositories are retired: the main site publishes every project landing at /projects/<name>/, so the catalog carries no landing repository. The apex site repository keeps the Pages configuration that serves it.

Catalog targets are repository-internal infrastructure inputs. They are not production build dependencies or published artifacts.

GitLab receives one-time repository imports and the configured upstream fork. The user will arrange ongoing synchronization separately; the decision and adoption evidence live in OpenSpec.

1 -

repository-catalog Specification

Define shared organization, repository identity, naming, and named access configuration for the GitHub, GitLab, and Forgejo infrastructure consumers.

The repository catalog SHALL store shared defaults and schema version at its root, one configuration file per organization, and one configuration file per repository beneath its organization. Those records SHALL own the configured organizations, repositories, named administrators, and named developers. Each forge consumer SHALL use that catalog for its selected repositories and named roles, preserving forge-specific settings without maintaining another copy of the inventory. Authentication and service-specific grants SHALL remain with their existing owners.

  • WHEN an organization assigns named administrators and developers and selects repositories for multiple forges
  • THEN each selected consumer uses the same catalog assignments and repository identities
  • AND forge-specific settings and service identities remain with their declared owners

First-party repository names SHALL remain the same across forges, including when copied or synchronized. External forks and mirrors SHALL belong to a catalog organization and use a name derived from the original upstream’s reversed hostname followed by its full owner and repository path, in lowercase with punctuation replaced by underscores. Cross-forge copies of external repositories SHALL retain that name rather than naming the intermediate copy as their upstream.

  • WHEN the first-party alwaldend/src repository is copied from GitHub to GitLab or Forgejo
  • THEN its destination remains alwaldend/src
  • WHEN https://gitlab.com/fdroid/fdroiddata is forked into alwaldend
  • THEN its organization-owned name is alwaldend/com_gitlab_fdroid_fdroiddata
  • AND subsequent copies on another forge retain that name

Consumers SHALL grant catalog administrators administrative access and catalog developers repository reads, feature-branch writes, and pull or merge request creation. Catalog developers SHALL NOT receive direct push or merge access to protected default branches through their named roles or overlapping retained grants. Existing service-specific permissions SHALL be preserved and distinguished from named developer assignments.

  • WHEN a catalog developer accesses a selected repository
  • THEN the developer can read its contents, create a feature branch, and open a pull or merge request
  • AND the developer cannot push or merge to its protected default branch

Consumers SHALL adopt existing remote resources through imports and preserve their remote identities. Existing managed resource addresses SHALL remain stable or use explicit state-preserving moves. Existing GitHub repository settings and Pages configuration SHALL remain intact, and default branches SHALL remain unchanged. No deletion or replacement SHALL execute without separate user approval for its concrete scope.

  • WHEN a catalog repository already exists remotely or in Terraform state
  • THEN its import or state move preserves the existing remote repository ID and contents
  • AND the reviewed plan does not recreate it to resolve a name collision
  • WHEN any reviewed plan proposes a deletion or replacement
  • THEN execution of that operation stops pending the user’s explicit approval for the identified operation and scope

GitLab SHALL receive a one-time Git import of every catalog-selected GitHub repository and an organization-owned fork of the selected F-Droid metadata upstream. Imports SHALL preserve the source default branch, and the fork SHALL retain its upstream fork relationship. This change SHALL configure no ongoing synchronization.

  • WHEN the GitHub default-branch migration completes and the initial GitLab imports and fork finish
  • THEN every selected GitHub repository has its intended GitLab copy and source default branch
  • AND the metadata repository retains its F-Droid upstream fork identity
  • AND later upstream changes are not promised to synchronize

GitLab default-branch access SHALL be established through group defaults before new repositories are populated. Existing automatically created protections SHALL be verified and imported before standalone protection management is applied. Adoption SHALL preserve the existing protections; provider limitations SHALL be reported rather than bypassed by unprotecting or recreating them.

  • WHEN an imported GitLab repository has an existing default-branch rule
  • THEN Terraform adopts that rule by import before applying permitted in-place access changes
  • AND adoption does not invoke unprotect-and-recreate behavior

2 - Repository catalog module

This provider-free Terraform module reads the catalog files, merges forge defaults, and projects organization-owned repository names and settings for each consumer. It creates no resources and uses no credentials.

Fork and mirror names follow the catalog naming contract. Output keys retain the organization and catalog key, independently of the derived destination name. The consumers retain their existing state addresses where resources were already managed.

The catalog test runs without network access or provider initialization:

bazel_agent bazel test //infra/repos/tf:tf_tests.catalog_test