Documentation
¶
Overview ¶
Package tenant enumerates the accounts this fleet may serve.
It sits outside both the GARM reconciler and the GitHub App bootstrapper because it is a fleet-wide fact that each of them must read the same way: an App registered for an account the reconciler would refuse is a deployment that fails after the one irreversible step in the whole flow.
Index ¶
Constants ¶
const DefaultID = "example"
DefaultID is the account the fleet ran on before it could serve more than one, and stays the default so an operator who passes no tenant gets the behaviour that is already deployed.
const DefaultRegistryPath = "/etc/gha-fleet/tenant-registry.yaml"
Variables ¶
This section is empty.
Functions ¶
func AccountURLPrefixes ¶
func AccountURLPrefixes() map[string]struct{}
AccountURLPrefixes is the set of account prefixes whose every repository the fleet may build a runner for. It holds only tenants that declared they serve a whole account, because an organization entity receives jobs from repositories the registry never names one by one -- which is otherwise a create refused per retry, after every other layer has already said yes.
func IDs ¶
func IDs() []string
TenantIDs lists the selectable tenants for help text and error messages.
func RepositoryURLs ¶
func RepositoryURLs() map[string]struct{}
RepositoryURLs is the closed set of exact repository URLs the fleet may build a runner for. The provider asserts a boundary rather than trusting whatever GARM hands it, and before multi-tenancy that boundary was a single constant. Deriving it here keeps the boundary closed and code-reviewed while making it exactly as wide as the registry above, so onboarding a tenant is one place.
Types ¶
type Registry ¶
type Registry struct {
SchemaVersion int `json:"schema_version" yaml:"schema_version"`
DefaultID string `json:"default_tenant" yaml:"default_tenant"`
Tenants []Tenant `json:"tenants" yaml:"tenants"`
}
Registry is the runtime-owned account boundary shared by GARM reconciliation and GitHub App bootstrap/verification. The public repository ships a synthetic example file; production identities are loaded from the estate.
func ExampleRegistry ¶
func ExampleRegistry() Registry
type Tenant ¶
type Tenant struct {
// ID selects the tenant on the command line. It is not an identity and is
// never compared against anything GitHub or GARM returns.
ID string `json:"id" yaml:"id"`
// Owner is the account that owns the App, receives its installation, and
// backs the organization entity.
Owner string `json:"owner" yaml:"owner"`
// Repository is the exact repository the repository entity serves, in
// `owner/name` form. It always belongs to Owner.
Repository string `json:"repository" yaml:"repository"`
// ManagedRepositories is the closed set that may receive a repository-
// scoped Scale Set from this tenant's App credential. Organization-scoped
// serving remains available when ServesWholeAccount is true, but an exact
// repository entity needs this reviewed identity before GARM mutation.
ManagedRepositories []string `json:"managed_repositories" yaml:"managed_repositories"`
// AppSlug is the slug the verified installation metadata must carry.
AppSlug string `json:"app_slug" yaml:"app_slug"`
// CredentialName is the GARM credential this tenant's entities bind to.
// Distinct per tenant so one GARM can hold both without either entity
// silently adopting the other's credential.
CredentialName string `json:"credential_name" yaml:"credential_name"`
// HomepageURL is the exact homepage the App manifest must declare.
HomepageURL string `json:"homepage_url" yaml:"homepage_url"`
// ServesWholeAccount widens this tenant's provider boundary from the one
// repository above to every repository Owner holds. Set it only for a
// tenant whose scale sets hang from an organization entity, because that
// is the entity that receives jobs from repositories Repository does not
// name. Leaving it false keeps the tightest boundary the fleet can state.
//
// It is declared rather than inferred: the provider is the layer that
// does not trust what GARM hands it, so how wide it may be is an
// onboarding decision with a review attached, not a runtime observation.
ServesWholeAccount bool `json:"serves_whole_account" yaml:"serves_whole_account"`
// ScaleSetRepositories binds repository-scoped product lanes to one exact
// reviewed repository. Public source declares only the class name; private
// runtime configuration supplies the production repository identity.
ScaleSetRepositories map[string]string `json:"scale_set_repositories,omitempty" yaml:"scale_set_repositories,omitempty"`
}
Tenant is one account this fleet may serve.
Runtime deployments load a strict reviewed registry. The compiled rows below are synthetic public examples only; operational CLI commands require the private registry path and pass the selected immutable row into their engine. Every identity check compares against that selected tenant and fails closed.
One tenant is one GitHub App. The App stays private and owned by the account it serves, so GitHub itself still permits exactly one installation, on that account, covering only its repositories. Multi-tenancy repeats that control per account rather than relaxing it: two private Apps, each locked to its own owner, is not the same thing as one App reachable by two owners.
func ByID ¶
TenantByID returns the tenant an operator selected, or refuses. An unknown id is a refusal rather than a fallback to the default: silently serving the wrong account is the failure this whole file exists to prevent.
func WithRepository ¶
WithRepository selects one reviewed repository entity without widening the tenant or accepting an arbitrary same-owner path. An empty repository keeps the tenant's historical primary entity.