Documentation
¶
Overview ¶
Package app is the assembly point: it reads configuration from the environment, picks the Postgres or SQLite repositories, builds the domain services and HTTP handlers, registers the routes behind the auth, token scope, rate limit and audit middleware, and owns the server's lifecycle.
Most of what lives here is wiring rather than logic, and the wiring is the hazard — several of the connections it makes fail at runtime rather than at compile time. A domain that is not registered with the reconciler still serves writes; a route class not handled in middleware.go still answers. CONTRIBUTING.md enumerates those sites under "Adding a config domain".
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewRouter ¶
func NewRouter( h *servicesettings.Handler, fh *flagsconfig.Handler, lh *localization.Handler, sec *security, health http.HandlerFunc, inventory http.Handler, auditLog http.Handler, ) *http.ServeMux
NewRouter registers the API. Every write goes through sec.guard, which declares how that route's target environment is found so a token can only reach the environments its scope names; every read goes through sec.read, which declares how that route's response is narrowed to the same scope. The probe and scrape routes are the only open ones.
Types ¶
type App ¶
type App struct {
// contains filtered or unexported fields
}
func (*App) Close ¶
Close releases what NewApp opened, for a caller that never reached Run — a test, or a startup that failed after the app was built. Run does its own ordered shutdown instead, because there the listener has to stop and the reconciler has to be told before the database can go.
func (*App) Handler ¶
Handler is the middleware chain and router exactly as the server serves them. It exists for internal/pgintegration: this package's own end-to-end tests all run on SQLite, and the behaviour that differs between the two — the scope lookup's bind syntax, the audit columns' declared widths — is therefore reachable only from a test outside this package, which cannot build the unexported security type NewRouter takes. Nothing in the binary calls it.
type Config ¶
type Config struct {
// DBDriver selects the storage backend: "postgres" (production, the source
// of truth) or "sqlite" (local test stack only — see internal/database/sqlite.go).
DBDriver string
DBConnString string
ServerPort string
// Connection pool bounds. A zero field takes the database package's own
// default; they are read here so every tunable an operator sets is visible
// in one place rather than in whichever package happens to consume it.
DBMaxOpenConns int
DBMaxIdleConns int
DBConnMaxLifetime time.Duration
DBConnMaxIdleTime time.Duration
// Messaging / JetStream
NATSURL string
NATSCreds string // optional path to a .creds file
PublishEnabled bool
NATSReplicas int // KV bucket replicas: 1 dev, 3 prod cluster
// Reconciler
ReconcileInterval time.Duration
// Security
//
// AdminTokens is the named-token configuration (see parseAdminTokens):
// ADMIN_TOKENS=alice:*:s3cr3t,ci-dev:1|2:another-secret
// AdminToken is the single shared token form, for a deployment that does
// not need per-environment scopes; it is recorded as the "shared"
// full-scope actor.
AdminTokens string
AdminToken string
// WriteRateLimit bounds writes per caller per minute; <= 0 disables it.
WriteRateLimit int
// TLS: when both are set the admin API serves HTTPS, otherwise plain HTTP
// with a startup warning.
TLSCertFile string
TLSKeyFile string
// Observability. LogFormat "json" emits ECS documents for Elasticsearch;
// "text" is the readable local-development shape.
LogLevel string
LogFormat string
ServiceName string
ServiceVersion string
}
func LoadConfig ¶
func LoadConfig() *Config
func (*Config) LogOptions ¶
func (c *Config) LogOptions() obs.LogOptions
LogOptions is the logging configuration in the form the obs package wants.
type Inventory ¶
type Inventory struct {
Flags []InventoryFlag `json:"flags"`
ServiceSettings []InventoryServiceSettings `json:"serviceSettings"`
Localization []InventoryLoc `json:"localization"`
}
Inventory lists the editable rows with their primary keys. Admin tools need this because the IDs an update targets are data, not something a caller can know up front. Read-only, and it reuses the reconciler's list queries rather than adding new ones.
Each of the three collections is paged independently by the same ?limit and ?offset, so a caller walks all three together; the reconcile queries return every row and the page is taken here, which is why the limit matters — the response is the whole configuration estate otherwise.
Taking the page here also means ?limit bounds only the response, never the read: ListAllForReconcile has no LIMIT and no WHERE, so every request scans all three tables and materialises every document whatever page it was asked for. The read guard meters this route per credential for that reason (middleware.go), which bounds how often that happens but not what one call costs. Closing it properly needs the listers to take a limit, an offset and the caller's scope so the database does the paging — that is a change to the three repository packages, not to this handler.
type InventoryFlag ¶
type InventoryLoc ¶
type InventoryServiceSettings ¶
type InventoryServiceSettings struct {
ID int64 `json:"id"`
MicroserviceID int64 `json:"microserviceId"`
EnvironmentID int64 `json:"environmentId"`
SettingsJSON json.RawMessage `json:"settingsJson"`
}