// components/credentials.ts // // CONTRACT_002 single owner of credential GENERATION + Vault distribution. // // Generation (`generateCredentials`) is pure @pulumi/random — no Vault, no // network — so it can be created in Phase 3 and consumed by the data-plane // components (postgres.ts needs its password at container boot). Distribution // (`writeCredentialsToVault`, T06) is the half that depends on Vault being // unsealed (Gate A); it writes every value to the KV paths in CONTRACT_002 §2.3. // Splitting the two halves resolves the ordering tension between "Postgres up in // Phase 3" and "secrets in Vault in Phase 5" without giving up single ownership. // // camelCase keys, no exceptions (CONTRACT_002 §2.2): the Vault write JSON-encodes // these objects, so the key names ARE the camelCase Vault keys downstream reads. import * as pulumi from "@pulumi/pulumi"; import { RandomPassword } from "@pulumi/random"; import { DeployCtx } from "../lib/context"; /** `foundation/postgres/service-credentials` (CONTRACT_002 §2.3). */ export interface PostgresCredentials { superUser: string; // "postgres" — image default superuser (deterministic) superPassword: pulumi.Output; forgejoDbUser: string; // "forgejo" (deterministic) forgejoDbPassword: pulumi.Output; } /** Everything generateCredentials() produces; grows as Wave-2 tasks land. */ export interface FoundationCredentials { postgres: PostgresCredentials; } /** * High-entropy alphanumeric secret. special:false keeps values safe to drop into * connection strings / app.ini / psql literals without escaping (len 28 ≈ 166 bits). */ function secret(name: string, length = 28): pulumi.Output { return new RandomPassword(name, { length, special: false }).result; } /** Generate all egg credentials (pure; no dependencies). CONTRACT_002 writer. */ export function generateCredentials(ctx: DeployCtx): FoundationCredentials { return { postgres: { superUser: "postgres", superPassword: secret("postgres-super-password"), forgejoDbUser: "forgejo", forgejoDbPassword: secret("forgejo-db-password"), }, }; }