Documentation
¶
Overview ¶
Package devfixture seeds and resets the deterministic development fixture (REQ-065) through the formal public Connect service seams. It never touches the database directly during seeding — every entity is created via the orchestrator, auth, webhook, and trust services — so the runner works against any deployment that exposes those APIs.
The seed is organized as nine committed phases (identity, routing, accounts, trust, bundle, values, enrollment, install, verify). Progress is persisted atomically to data/dev-seed-progress.json; a re-run verifies canonical consistency (entity existence + stable logical keys, never server-generated mutable fields) of already-committed phases and resumes from the first non-committed phase. When every phase is committed the run reports "fixture up-to-date" and issues no write RPCs (AC-065-03).
Reset (dev-reset-data) rebuilds the databases SDK-only: it rolls every migration down to the baseline and back up to the latest schema, then re-seeds all nine phases. On failure the progress file is marked "partial": true (the shell layer owns pg_restore recovery).
Index ¶
Constants ¶
const ( DefaultFixtureVersion = "v2" DefaultDataDir = "data" DefaultChartDir = "deploy/fixtures/chart" DefaultTrustEnv = "staging" // orchestrator --target-env in the dev kustomize DefaultInstallTimeout = 15 * time.Minute DefaultInstallPoll = 3 * time.Second // AC-065-28 defaults (DEV_TIMEOUT_OPERATOR / DEV_TIMEOUT_SEED_RETRIES): // operator-online wait and phase-write retry count with 1s/2s/4s backoff. DefaultOperatorOnlineTimeout = 180 * time.Second DefaultSeedRetries = 3 )
Defaults for seed runtime knobs.
Variables ¶
var ErrFixtureConflict = errors.New("fixture_conflict")
ErrFixtureConflict reports canonical drift of an already-committed phase: an entity is missing or its stable logical key no longer matches the seed contract.
Functions ¶
This section is empty.
Types ¶
type AuthClient ¶
type AuthClient interface {
GetInitStatus(context.Context, *connect.Request[authv1.GetInitStatusRequest]) (*connect.Response[authv1.GetInitStatusResponse], error)
Initialize(context.Context, *connect.Request[authv1.InitializeRequest]) (*connect.Response[authv1.InitializeResponse], error)
Login(context.Context, *connect.Request[authv1.LoginRequest]) (*connect.Response[authv1.LoginResponse], error)
CreateLocalUser(context.Context, *connect.Request[authv1.CreateLocalUserRequest]) (*connect.Response[authv1.CreateLocalUserResponse], error)
GetLocalUser(context.Context, *connect.Request[authv1.GetLocalUserRequest]) (*connect.Response[authv1.GetLocalUserResponse], error)
}
AuthClient is the auth service seam (accounts phase + login preamble).
type BindingClient ¶
type BindingClient interface {
ListBindings(context.Context, *connect.Request[authv1.ListBindingsRequest]) (*connect.Response[authv1.ListBindingsResponse], error)
CreateBinding(context.Context, *connect.Request[authv1.CreateBindingRequest]) (*connect.Response[authv1.CreateBindingResponse], error)
}
BindingClient is the org-customer binding seam (identity phase).
type BundleClient ¶
type BundleClient interface {
GetBundle(context.Context, *connect.Request[orchestratorv1.GetBundleRequest]) (*connect.Response[orchestratorv1.GetBundleResponse], error)
ListBundles(context.Context, *connect.Request[orchestratorv1.ListBundlesRequest]) (*connect.Response[orchestratorv1.ListBundlesResponse], error)
}
BundleClient is the orchestrator bundle service seam (verify phase).
type ClusterRef ¶
ClusterRef is the manifest entry for one seeded cluster.
type Config ¶
type Config struct {
Mode Mode
OrchestratorURL string
WebhookURL string
AuthURL string
// WebhookAPIKey is the CI ingress key the fixture presents to
// WebhookService/SubmitReleaseBundle (REQ-011 §562, TASK-102). The webhook
// ingress is authenticated, so a missing key fails the seed with a clear
// error instead of an opaque 401.
WebhookAPIKey string
DataDir string
AdminUser string
AdminPassword string // optional override; falls back to credentials file
DeployerUser string
DeployerPassword string // optional override; falls back to credentials file
ReaderPassword string // optional override; generated in local mode
// E2ERunnerPassword is the e2e-runner (release_admin) password
// (REQ-066 下游义务, 批次4 D1/D3); optional override, generated in local
// mode, env-injected as E2E_RUNNER_PASSWORD in ci mode.
E2ERunnerPassword string
TrustEnvironment string
TrustRootPrivateKey string // CI mode: PEM-encoded Ed25519 private key
FixtureVersion string
ChartDir string
InstallTimeout time.Duration
InstallPollPeriod time.Duration
// OperatorOnlineTimeout bounds the operator-session-online wait during
// verify (AC-065-18/28); SeedRetries bounds phase-write retries with
// 1s/2s/4s exponential backoff (AC-065-19/28). Zero falls back to the
// package defaults.
OperatorOnlineTimeout time.Duration
SeedRetries int
// StopAfterPhase ends the run cleanly once the named phase has been
// committed (no error, no partial marker). The lifecycle module uses
// `enrollment` to split the seed: it generates the tokens first,
// deploys/injects them into the customer agent clusters, then re-runs
// devseed to resume from the install phase (progress/resume contract).
StopAfterPhase string
Logger *slog.Logger
Now func() time.Time // test hook; defaults to time.Now
// DatabaseDSN opens the PostgreSQL schema for Reset. ReleaseNotifierDSN
// is optional and skipped when empty.
DatabaseDSN string
ReleaseNotifierDSN string
// MigrationsFactory opens the schema-migration seam used by Reset.
// Tests inject a fake; production uses NewPostgresMigrations.
MigrationsFactory func(dsn string) (Migrations, error)
}
Config carries every knob for the seed runner. Zero values fall back to defaults; secrets left empty are resolved from data/dev-credentials.env (local mode, reuse-or-generate) or fail in CI mode.
type CustomerRef ¶
CustomerRef is the manifest entry for one seeded customer.
type DefinitionRef ¶
type DefinitionRef struct {
ID string `json:"id"`
ValuesRevisionID string `json:"values_revision_id"`
BundleID string `json:"bundle_id"`
}
DefinitionRef is the manifest entry for one seeded release definition.
type Manifest ¶
type Manifest struct {
FixtureVersion string `json:"fixture_version"`
GeneratedAt string `json:"generated_at"`
Customers map[string]CustomerRef `json:"customers"`
Clusters map[string]ClusterRef `json:"clusters"`
Routes map[string]RouteRef `json:"routes"`
Operators map[string]OperatorRef `json:"operators"`
Definitions map[string]DefinitionRef `json:"definitions"`
Bundle BundleRef `json:"bundle"`
}
Manifest is the runtime identity manifest written to data/dev-fixture.json (REQ-065): stable logical keys mapping to the server-generated identifiers that later stages (REQ-066) reference.
type Migrations ¶
type Migrations interface {
// DownAll rolls every applied migration down to the baseline.
DownAll(ctx context.Context) error
// Up applies all pending migrations.
Up(ctx context.Context) error
// Close releases the database handle.
Close() error
}
Migrations is the schema-migration seam used by Reset. Production uses postgresMigrations; tests inject a fake to exercise the reset state machine without a live PostgreSQL instance.
func NewPostgresMigrations ¶
func NewPostgresMigrations(dsn string) (Migrations, error)
NewPostgresMigrations opens the PostgreSQL database at dsn and returns the migration seam backed by internal/postgres RunMigrations/RunMigrationsDown over the embedded migration FS (SDK-only — no pg_dump/pg_restore/kubectl here; the shell layer owns those).
type OperatorRef ¶
OperatorRef is the manifest entry for one seeded cluster's operator agent.
The operator id is minted by the orchestrator when the agent enrolls, so it cannot be derived from a logical key; the manifest publishes the id observed ONLINE during the enrollment wait. The REQ-066 control-plane stage needs it because GetActiveOperatorSession selects a session by operator id (AC-066-17).
type OrchestratorClient ¶
type OrchestratorClient interface {
// identity
ListCustomers(context.Context, *connect.Request[orchestratorv1.ListCustomersRequest]) (*connect.Response[orchestratorv1.ListCustomersResponse], error)
CreateCustomer(context.Context, *connect.Request[orchestratorv1.CreateCustomerRequest]) (*connect.Response[orchestratorv1.CreateCustomerResponse], error)
GetCluster(context.Context, *connect.Request[orchestratorv1.GetClusterRequest]) (*connect.Response[orchestratorv1.GetClusterResponse], error)
CreateCluster(context.Context, *connect.Request[orchestratorv1.CreateClusterRequest]) (*connect.Response[orchestratorv1.CreateClusterResponse], error)
// routing
ConfigureClusterRoute(context.Context, *connect.Request[orchestratorv1.ConfigureClusterRouteRequest]) (*connect.Response[orchestratorv1.ConfigureClusterRouteResponse], error)
GetClusterRoutes(context.Context, *connect.Request[orchestratorv1.GetClusterRoutesRequest]) (*connect.Response[orchestratorv1.GetClusterRoutesResponse], error)
// values
ListReleaseDefinitions(context.Context, *connect.Request[orchestratorv1.ListReleaseDefinitionsRequest]) (*connect.Response[orchestratorv1.ListReleaseDefinitionsResponse], error)
CreateReleaseDefinition(context.Context, *connect.Request[orchestratorv1.CreateReleaseDefinitionRequest]) (*connect.Response[orchestratorv1.CreateReleaseDefinitionResponse], error)
CreateValuesRevision(context.Context, *connect.Request[orchestratorv1.CreateValuesRevisionRequest]) (*connect.Response[orchestratorv1.CreateValuesRevisionResponse], error)
ListValuesRevisions(context.Context, *connect.Request[orchestratorv1.ListValuesRevisionsRequest]) (*connect.Response[orchestratorv1.ListValuesRevisionsResponse], error)
SubmitValuesRevision(context.Context, *connect.Request[orchestratorv1.SubmitValuesRevisionRequest]) (*connect.Response[orchestratorv1.ValuesRevisionDecisionResponse], error)
ApproveValuesRevision(context.Context, *connect.Request[orchestratorv1.ApproveValuesRevisionRequest]) (*connect.Response[orchestratorv1.ValuesRevisionDecisionResponse], error)
// enrollment
CreateEnrollmentToken(context.Context, *connect.Request[orchestratorv1.CreateEnrollmentTokenRequest]) (*connect.Response[orchestratorv1.CreateEnrollmentTokenResponse], error)
// operator session online check (AC-065-18)
ListOperators(context.Context, *connect.Request[orchestratorv1.ListOperatorsRequest]) (*connect.Response[orchestratorv1.ListOperatorsResponse], error)
// install
CreateOperation(context.Context, *connect.Request[orchestratorv1.CreateOperationRequest]) (*connect.Response[orchestratorv1.CreateOperationResponse], error)
GetOperation(context.Context, *connect.Request[orchestratorv1.GetOperationRequest]) (*connect.Response[orchestratorv1.GetOperationResponse], error)
}
OrchestratorClient is the orchestrator seam covering every entity the seed creates. Methods are grouped by phase in the code comments.
type RouteRef ¶
RouteRef is the manifest entry for one seeded artifact route.
Routes are cluster-scoped: the public ClusterRoute surface carries no release-definition identity, so a route is never attributed to a definition. The manifest publishes them because the REQ-066 identity expectation asserts a route count (AC-066-29) and no other input source exposes one.
type TrustClient ¶
type TrustClient interface {
GetTrustPolicy(context.Context, *connect.Request[trustv1.GetTrustPolicyRequest]) (*connect.Response[trustv1.GetTrustPolicyResponse], error)
CreateTrustRoot(context.Context, *connect.Request[trustv1.CreateTrustRootRequest]) (*connect.Response[trustv1.CreateTrustRootResponse], error)
}
TrustClient is the trust service seam (trust phase).
type WebhookClient ¶
type WebhookClient interface {
SubmitReleaseBundle(context.Context, *connect.Request[webhookv1.SubmitReleaseBundleRequest]) (*connect.Response[webhookv1.SubmitReleaseBundleResponse], error)
}
WebhookClient is the webhook service seam (bundle phase).