Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / cmd/provision-tenant/main.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 |
| Branch | master |
| Path or archive member | cmd/provision-tenant/main.go |
| Original SHA-256 | d32dfd0f7bb8fccf53fd5f8122acb2e55a72f696b582a56af13f184c691c9746 |
| Git blob SHA | 3e7f155e92d2ae8d5e4a58e1e4db9d06cc768b86 |
| Reading-copy SHA-256 | d32dfd0f7bb8fccf53fd5f8122acb2e55a72f696b582a56af13f184c691c9746 |
Every recorded occurrence
These 41 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / cmd/provision-tenant/main.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | w3-ai-staffing-recommendations | 43d56387270ef4da4cabd794d97ca6a49909bc7d | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ai-intelligence-layer | 5d5ddff70393a197c5f54a45280bb5dd42b24755 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws2-alias-relationship | e4dada4601c6eb101830f9d223a9655dfa120616 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | vendor-intelligence | fe9796a19c261951d3f2565206c0c1b5ac294465 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws6-retrieval | 6c56e29231ec05735927fa265c97d517499dfeaf | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws1-ontology-sync | b596f449a32a1016fbd403c36505cc00a1ac9ee6 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | w3-ai-staffing-recommendations | 43d56387270ef4da4cabd794d97ca6a49909bc7d | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws3-clearance | 4b8e7ce594c068621867f9c9deed0ec64ae6c553 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | phase2-eval-fairness | d361af254701975fe239927656ababb56374655e | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ai-intelligence-layer | 5d5ddff70393a197c5f54a45280bb5dd42b24755 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws2-alias-relationship | e4dada4601c6eb101830f9d223a9655dfa120616 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ws7-federal-signal | 6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | ai-brain-live | aac32fc49c878cc5bca099459307611562d0bac1 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / cmd/provision-tenant/main.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
Recovered source transcript
Download complete source text ↓185 lines · 7.1 KB
// Command provision-tenant creates a complete, isolated Postgres database for one client under the
// database per tenant model. It is the tenant isolation primitive: a client's data, embeddings, graphs,
// and memory all live inside this database, and a Postgres connection bound to it physically cannot read
// another tenant's database (there is no cross database query path). RLS inside the database is defense
// in depth and supports the migration from the shared database.
//
// It runs the SAME migrations as the shared database (the embedded db/migrations plus the segregated
// db/migrations_eeo), so a tenant database is schema identical: same tables, same RLS forced, same eeo
// schema the app role cannot reach, same vector(384) columns and HNSW indexes. A new tenant provisions
// EMPTY and fills only from its own data (run cmd/embed-backfill against it once it has candidates).
//
// It is an operator tool: it needs an admin (superuser) DSN to CREATE DATABASE and the cluster roles. It
// does NOT create live client databases on its own; the human runs it as part of the validated cutover.
//
// Usage:
//
// provision-tenant -admin-dsn postgres://postgres@host/postgres?sslmode=disable -name tenant_acme
package main
import (
"context"
"database/sql"
"flag"
"fmt"
"log"
"os"
"regexp"
"time"
"github.com/jackc/pgx/v5"
_ "github.com/jackc/pgx/v5/stdlib"
"github.com/pressly/goose/v3"
dbembed "github.com/missionworkforce/missionmatch/db"
)
// dbNameRe constrains the tenant database name to a safe identifier (CREATE DATABASE cannot be
// parameterized, so the name must be validated, never interpolated from untrusted input).
var dbNameRe = regexp.MustCompile(`^[a-z][a-z0-9_]{2,62}$`)
func main() {
adminDSN := flag.String("admin-dsn", os.Getenv("MM_ADMIN_DSN"), "superuser DSN to the maintenance database (CREATE DATABASE + roles)")
name := flag.String("name", "", "tenant database name (lowercase identifier, e.g. tenant_acme)")
dropFirst := flag.Bool("drop-first", false, "DANGER: drop the database first (staging only)")
flag.Parse()
if *adminDSN == "" || *name == "" {
log.Fatal("provision-tenant: -admin-dsn and -name are required")
}
if !dbNameRe.MatchString(*name) {
log.Fatalf("provision-tenant: %q is not a safe database name (want ^[a-z][a-z0-9_]{2,62}$)", *name)
}
ctx := context.Background()
if err := provision(ctx, *adminDSN, *name, *dropFirst); err != nil {
log.Fatalf("provision-tenant: %v", err)
}
log.Printf("provision-tenant: DONE. Tenant database %q is schema identical to the shared database, RLS forced, eeo segregated, vector(384) ready.", *name)
log.Printf("provision-tenant: next, run cmd/embed-backfill against this database once it has candidates.")
}
func provision(ctx context.Context, adminDSN, name string, dropFirst bool) error {
admin, err := pgx.Connect(ctx, adminDSN)
if err != nil {
return fmt.Errorf("admin connect: %w", err)
}
defer admin.Close(ctx)
// 1. Ensure the cluster roles exist (idempotent DO guards in the bootstrap).
bootstrap, err := dbembed.Bootstrap.ReadFile("bootstrap/00_roles.sql")
if err != nil {
return err
}
if _, err := admin.Exec(ctx, string(bootstrap)); err != nil {
return fmt.Errorf("role bootstrap: %w", err)
}
// 2. Create the database (CREATE DATABASE cannot run inside a transaction or be parameterized; the
// name was validated above).
if dropFirst {
_, _ = admin.Exec(ctx, "DROP DATABASE IF EXISTS "+name)
}
var exists bool
_ = admin.QueryRow(ctx, "SELECT EXISTS(SELECT 1 FROM pg_database WHERE datname=$1)", name).Scan(&exists)
if exists {
return fmt.Errorf("database %q already exists (use -drop-first in staging to recreate)", name)
}
if _, err := admin.Exec(ctx, "CREATE DATABASE "+name); err != nil {
return fmt.Errorf("create database: %w", err)
}
log.Printf("provision-tenant: created database %q", name)
// 3. In the new database: extension, schema usage, and connect privilege scoped to this database.
tenantAdminDSN := swapDB(adminDSN, name)
tdb, err := pgx.Connect(ctx, tenantAdminDSN)
if err != nil {
return fmt.Errorf("tenant connect: %w", err)
}
defer tdb.Close(ctx)
for _, stmt := range []string{
"CREATE EXTENSION IF NOT EXISTS vector",
"GRANT USAGE ON SCHEMA public TO missionmatch_app, missionmatch_compliance",
"REVOKE CONNECT ON DATABASE " + name + " FROM PUBLIC",
"GRANT CONNECT ON DATABASE " + name + " TO missionmatch_app, missionmatch_compliance, missionmatch_migrator",
} {
if _, err := tdb.Exec(ctx, stmt); err != nil {
return fmt.Errorf("setup %q: %w", stmt, err)
}
}
// 4. Run both migration sets via goose against the new database (database/sql over pgx stdlib).
sqlDB, err := sql.Open("pgx", tenantAdminDSN)
if err != nil {
return err
}
defer func() { _ = sqlDB.Close() }()
sqlDB.SetConnMaxLifetime(5 * time.Minute)
if err := goose.SetDialect("postgres"); err != nil {
return err
}
goose.SetBaseFS(dbembed.Migrations)
goose.SetTableName("goose_db_version")
if err := goose.UpContext(ctx, sqlDB, "migrations"); err != nil {
return fmt.Errorf("public migrations: %w", err)
}
log.Printf("provision-tenant: applied public schema migrations")
goose.SetBaseFS(dbembed.EEOMigrations)
goose.SetTableName("goose_db_version_eeo")
if err := goose.UpContext(ctx, sqlDB, "migrations_eeo"); err != nil {
return fmt.Errorf("eeo migrations: %w", err)
}
log.Printf("provision-tenant: applied segregated eeo migrations")
return verify(ctx, tdb)
}
// verify asserts the isolation and AI invariants the architecture requires before a tenant is usable.
func verify(ctx context.Context, tdb *pgx.Conn) error {
checks := []struct {
name string
query string
want bool
}{
{"pgvector extension", "SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname='vector')", true},
{"candidates RLS forced", "SELECT relforcerowsecurity FROM pg_class WHERE relname='candidates'", true},
{"eeo schema present", "SELECT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname='eeo')", true},
{"app has NO grant on eeo.candidate_demographics",
"SELECT NOT has_table_privilege('missionmatch_app','eeo.candidate_demographics','SELECT')", true},
{"vector(384) column on candidates",
"SELECT EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name='candidates' AND column_name='resume_embedding')", true},
}
for _, c := range checks {
var got bool
if err := tdb.QueryRow(ctx, c.query).Scan(&got); err != nil {
return fmt.Errorf("verify %s: %w", c.name, err)
}
if got != c.want {
return fmt.Errorf("verify FAILED: %s = %v, want %v", c.name, got, c.want)
}
log.Printf("provision-tenant: verified %s", c.name)
}
return nil
}
// swapDB replaces the database name in a DSN, so the admin DSN to the maintenance database is reused to
// reach the new tenant database.
func swapDB(dsn, name string) string {
cfg, err := pgx.ParseConfig(dsn)
if err != nil {
return dsn
}
cfg.Database = name
// Rebuild a key value DSN (pgx accepts both URL and key value forms).
out := fmt.Sprintf("host=%s port=%d user=%s dbname=%s", cfg.Host, cfg.Port, cfg.User, name)
if cfg.Password != "" {
out += " password=" + cfg.Password
}
if cfg.TLSConfig == nil {
out += " sslmode=disable"
}
return out
}