// Package main is a TEST-ONLY control-plane binary, built solely to give // scripts/verify_control_plane_integration.sh a real, running HTTP server -- // backed by real PostgreSQL, running the actual api.Service used in // production -- for the Godot client to talk to over a real network // connection. It is never referenced by any Dockerfile stage or Kubernetes // manifest and must never be treated as a deployment target: fakeSteamLogin // below accepts ANY non-empty ticket string as a valid identity instead of // verifying it against the real Steam Web API, which is exactly the kind of // bypass that must stay confined to a clearly-separate binary, never a flag // on the real one (see cmd/control-plane, which has no such flag and never // should). Every other adapter here is wired identically to cmd/control-plane. package main import ( "context" "crypto/sha256" "database/sql" "encoding/hex" "flag" "fmt" "net" "net/http" "os" "os/signal" "syscall" "time" "github.com/cosmic-clash/cosmic-clash/server/api" "github.com/cosmic-clash/cosmic-clash/server/domain" "github.com/cosmic-clash/cosmic-clash/server/migrations" "github.com/cosmic-clash/cosmic-clash/server/store" _ "github.com/jackc/pgx/v5/stdlib" ) func main() { listen := flag.String("listen", "127.0.0.1:0", "HTTP listen address; port 0 picks a free port, printed on startup") dsn := flag.String("dsn", os.Getenv("COSMIC_CLASH_POSTGRES_DSN"), "PostgreSQL connection string") migrationDir := flag.String("migrations", "migrations", "directory containing numbered SQL migrations") workloadSecret := flag.String("workload-secret", envOrDefault("COSMIC_CLASH_WORKLOAD_SECRET", "testkit-workload-secret"), "HMAC secret for signed workload tokens; defaults to a fixed test value since this binary is test-only") flag.Parse() if *dsn == "" { fatalf("--dsn or COSMIC_CLASH_POSTGRES_DSN is required") } db, err := sql.Open("pgx", *dsn) if err != nil { fatalf("open PostgreSQL: %v", err) } defer db.Close() startupCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() if err := db.PingContext(startupCtx); err != nil { fatalf("ping PostgreSQL: %v", err) } if err := migrations.Apply(startupCtx, db, *migrationDir); err != nil { fatalf("apply migrations: %v", err) } service := &api.Service{ SessionBackend: store.PostgresSessions{DB: db}, SessionIssuer: store.PostgresSessions{DB: db}, SteamLogin: fakeSteamLogin{db: db}, QueueBackend: store.PostgresQueue{DB: db}, ProposalBackend: api.ProposalProviderFromStore(db), ProposalPromoter: api.ProposalPromoterFromStore(db), ServerRegistrar: api.ServerRegistrarFromStore(db), ResultSubmitter: store.PostgresResults{DB: db}, RankedProfileProvider: store.PostgresRankedProfiles{DB: db}, TierPolicy: domain.DefaultTierPolicy(), Assignment: api.AssignmentProviderFromStore(db), Roster: func(ctx context.Context, binding domain.WorkloadBinding, now time.Time) ([][]byte, error) { return store.GetAssignmentRoster(ctx, db, binding.MatchID, binding.ServerID, now) }, ProbeRecorder: store.PostgresQueue{DB: db}, WorkloadVerify: api.WorkloadVerifierFromSignedToken([]byte(*workloadSecret), db), Now: func() time.Time { return time.Now().UTC() }, } handler := service.Handler() listener, err := net.Listen("tcp", *listen) if err != nil { fatalf("listen: %v", err) } fmt.Printf("testkit-api listening on http://%s\n", listener.Addr()) server := &http.Server{Handler: handler, ReadHeaderTimeout: 5 * time.Second} serveErr := make(chan error, 1) go func() { serveErr <- server.Serve(listener) }() ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() go api.RunProposalOutboxDispatcher(ctx, db, service) go api.RunResultOutboxDispatcher(ctx, db, service) go api.RunStateOutboxDispatcher(ctx, db, service) select { case err := <-serveErr: if err != nil && err != http.ErrServerClosed { fatalf("serve: %v", err) } case <-ctx.Done(): shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second) defer shutdownCancel() _ = server.Shutdown(shutdownCtx) } } // fakeSteamLogin derives a deterministic identity from the ticket string // itself (never a real Steam Web API ticket in this binary) and ensures its // identities row exists so session issuance's foreign key is satisfied. type fakeSteamLogin struct{ db *sql.DB } func (f fakeSteamLogin) Authenticate(ctx context.Context, ticket string, _ time.Time) (domain.VerifiedIdentity, error) { if ticket == "" { return domain.VerifiedIdentity{}, fmt.Errorf("empty ticket") } digest := sha256.Sum256([]byte(ticket)) playerID := "testkit-" + hex.EncodeToString(digest[:8]) steamID := "testkit-steam-" + hex.EncodeToString(digest[8:16]) if _, err := f.db.ExecContext(ctx, `INSERT INTO identities (player_id, steam_id) VALUES ($1, $2) ON CONFLICT (player_id) DO NOTHING`, playerID, steamID); err != nil { return domain.VerifiedIdentity{}, err } return domain.VerifiedIdentity{PlayerID: playerID, SteamID: steamID}, nil } func envOrDefault(name, fallback string) string { if value := os.Getenv(name); value != "" { return value } return fallback } func fatalf(format string, args ...any) { fmt.Fprintf(os.Stderr, "testkit-api: "+format+"\n", args...) os.Exit(1) }