foundation/bootstrap/components/credentials.ts

51 lines
2.1 KiB
TypeScript
Raw Normal View History

// 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<string>;
forgejoDbUser: string; // "forgejo" (deterministic)
forgejoDbPassword: pulumi.Output<string>;
}
/** 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<string> {
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"),
},
};
}