Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
34df941
chore(deps): bump github.com/docker/go-connections from 0.7.0 to 0.8.…
dependabot[bot] Aug 1, 2026
d63bb58
fix(cli): port shadow database provisioning to native TS (CLI-1956)
Coly010 Aug 1, 2026
5c8d247
fix(cli): reject non-object pg-delta apply JSON instead of an uncheck…
Coly010 Aug 1, 2026
abfc802
fix(cli): fix Windows path, symlink, and directory-walk-error parity …
Coly010 Aug 1, 2026
c7c1fb4
fix(cli): gate shadow/fresh-db JWKS resolution on majorVersion >= 15 …
Coly010 Aug 1, 2026
38da7d7
fix(cli): treat non-directory declarative schema paths as absent, mat…
Coly010 Aug 1, 2026
d9fb78a
fix(cli): validate pg-delta apply result's array/number fields before…
Coly010 Aug 1, 2026
18e5b09
fix(cli): treat null pg-delta apply statement as absent, matching Go'…
Coly010 Aug 1, 2026
def594d
fix(cli): don't follow symlinked directories in shadow schema walks, …
Coly010 Aug 1, 2026
6ecf6a4
fix(cli): treat null pg-delta diagnostic statementId as absent, match…
Coly010 Aug 1, 2026
2314756
chore(cli-go): remove ToPostgresURLWithoutPassword, dead since CLI-19…
Coly010 Aug 1, 2026
f278200
fix(cli): re-provision a fresh shadow on db pull's pooler-retry, matc…
Coly010 Aug 1, 2026
2845e23
fix(cli): reject malformed pg-delta apply result array elements, matc…
Coly010 Aug 1, 2026
22c923c
fix(cli): propagate stat failures, skip symlinked roots, use Go's byt…
Coly010 Aug 1, 2026
2cf66e6
fix(cli): reject fractional pg-delta apply counters, matching Go's in…
Coly010 Aug 1, 2026
36af3d6
fix(cli): preserve POSIX backslashes and reject empty schema_paths gl…
Coly010 Aug 1, 2026
fadb97d
fix(cli): treat an empty --network-id override as unset, matching Go'…
Coly010 Aug 1, 2026
3a4f121
fix(cli): thread the resolved shadow password and preserve schema-wal…
Coly010 Aug 1, 2026
fc06094
fix(cli): preserve the stat failure cause for a matched schema_paths …
Coly010 Aug 1, 2026
eebccc6
fix(cli): preserve the declarative-walk error prefix, matching Go (re…
Coly010 Aug 1, 2026
0b95e21
fix(cli): report shadow-removal launch/collection failures, matching …
Coly010 Aug 1, 2026
0372627
fix(cli): accept null scalar fields on pg-delta issues/diagnostics, m…
Coly010 Aug 1, 2026
de3eb12
fix(cli): accept null top-level pg-delta counters, matching Go's enco…
Coly010 Aug 1, 2026
7e1ffbc
fix(cli): truncate pg-delta SQL summaries by UTF-8 bytes, matching Go…
Coly010 Aug 1, 2026
d86c2dd
fix(cli): preserve byte-exact pg-delta apply/debug output, matching G…
Coly010 Aug 1, 2026
35ccd0f
fix(cli): resolve the pull shadow image after the creation banner, ma…
Coly010 Aug 1, 2026
b85008f
Merge remote-tracking branch 'origin/develop' into columferry/cli-195…
Coly010 Aug 3, 2026
e14c199
fix(cli): repair merge fallout from develop (debug-flag arity, stale …
Coly010 Aug 3, 2026
71c7576
Merge remote-tracking branch 'origin/columferry/cli-1955-port-db-rese…
Coly010 Aug 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 0 additions & 78 deletions apps/cli-go/cmd/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,76 +200,6 @@ var (
},
}

shadowMode string
shadowTargetLocal bool
shadowUsePgDelta bool
shadowSchema []string
shadowProjectRef string

// dbShadowCmd is a hidden seam used by the native-TypeScript db diff/pull
// commands to provision the throwaway shadow database that the diff "source"
// runs against, then leave it running so the TS caller can run the differ
// (migra or pg-delta) itself and remove the container afterwards. It prints
// three newline-separated lines to stdout: the container id, the source
// Postgres URL, and an optional target-override URL (empty unless the
// local-target declarative branch redirects the diff target to a second
// shadow database). The URLs are emitted WITHOUT the password
// (ToPostgresURLWithoutPassword) so we never log a credential to stdout
// (CWE-312); the TS caller re-injects the local Postgres password it already
// resolves from config.toml, which is the same value the shadow uses. Shadow
// provisioning (start.SetupDatabase) is not yet ported, which is why this
// stays in Go.
dbShadowCmd = &cobra.Command{
Use: "__shadow",
Hidden: true,
Short: "Internal: provision a shadow database for the native db diff/pull commands",
RunE: func(cmd *cobra.Command, args []string) error {
// The hidden __shadow command carries none of the db-url/local/linked
// target flags, so the root PersistentPreRunE's ParseDatabaseConfig
// never loads supabase/config.toml (it only loads when a target flag
// is set, internal/utils/flags/db_url.go:46-90). Load it explicitly so
// the shadow is provisioned from the project's [db] settings — shadow
// port, Postgres version, service baseline, and especially the
// password: the native-TS caller injects the config.toml password into
// the seam URLs, so the shadow must be created with that same password.
fsys := afero.NewOsFs()
// On the linked path the native-TS caller passes the resolved project
// ref via --project-ref so the shadow is built from the same
// remote-merged config the Go monolith uses: LoadConfig seeds
// utils.Config.ProjectId from flags.ProjectRef and merges the matching
// [remotes.<ref>] block (pkg/config/config.go). Omitted on local/db-url
// shadows, which the monolith never remote-merges, so the base config is
// used exactly as before.
if len(shadowProjectRef) > 0 {
flags.ProjectRef = shadowProjectRef
}
if err := flags.LoadConfig(fsys); err != nil {
return err
}
var src diff.ShadowSource
var err error
switch shadowMode {
case "declarative":
src, err = diff.PrepareRawShadow(cmd.Context())
case "diff", "":
src, err = diff.PrepareShadowSource(cmd.Context(), shadowSchema, shadowTargetLocal, shadowUsePgDelta, fsys)
default:
return fmt.Errorf("unknown shadow mode: %s", shadowMode)
}
if err != nil {
return err
}
fmt.Println(src.Container)
fmt.Println(utils.ToPostgresURLWithoutPassword(src.Source))
if src.TargetOverride != nil {
fmt.Println(utils.ToPostgresURLWithoutPassword(*src.TargetOverride))
} else {
fmt.Println("")
}
return nil
},
}

dbRemoteCmd = &cobra.Command{
Hidden: true,
Use: "remote",
Expand Down Expand Up @@ -612,14 +542,6 @@ func init() {
pullFlags.StringVarP(&dbPassword, "password", "p", "", "Password to your remote Postgres database.")
cobra.CheckErr(viper.BindPFlag("DB_PASSWORD", pullFlags.Lookup("password")))
dbCmd.AddCommand(dbPullCmd)
// Build hidden shadow-provisioning seam command
shadowFlags := dbShadowCmd.Flags()
shadowFlags.StringVar(&shadowMode, "mode", "diff", "Shadow mode: diff (baseline + migrations) or declarative (bare shadow).")
shadowFlags.BoolVar(&shadowTargetLocal, "target-local", false, "Whether the diff target is the local database (enables the declarative-schema branch).")
shadowFlags.BoolVar(&shadowUsePgDelta, "use-pg-delta", false, "Whether pg-delta is the active diff engine (selects the declarative-apply path).")
shadowFlags.StringSliceVarP(&shadowSchema, "schema", "s", []string{}, "Comma separated list of schema to include.")
shadowFlags.StringVar(&shadowProjectRef, "project-ref", "", "Linked project ref, so the shadow merges the matching [remotes.<ref>] config override.")
dbCmd.AddCommand(dbShadowCmd)
// Build remote command
remoteFlags := dbRemoteCmd.PersistentFlags()
remoteFlags.StringSliceVarP(&schema, "schema", "s", []string{}, "Comma separated list of schema to include.")
Expand Down
11 changes: 0 additions & 11 deletions apps/cli-go/internal/utils/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,6 @@ func ToPostgresURL(config pgconn.Config) string {
return toPostgresURL(config, url.UserPassword(config.User, config.Password))
}

// ToPostgresURLWithoutPassword renders the connection URL exactly like
// ToPostgresURL but omits the password from the userinfo. Use it for callers that
// print the URL to stdout (the hidden `db __shadow` seam): embedding the password
// there is clear-text logging of a credential (CWE-312, flagged by CodeQL). The
// password is never the seam's to share — the TS caller that consumes the seam
// output re-injects the local Postgres password it already resolves from
// config.toml (`utils.Config.Db.Password`).
func ToPostgresURLWithoutPassword(config pgconn.Config) string {
return toPostgresURL(config, url.User(config.User))
}

func toPostgresURL(config pgconn.Config, userinfo *url.Userinfo) string {
timeoutSecond := int64(config.ConnectTimeout.Seconds())
if timeoutSecond == 0 {
Expand Down
17 changes: 0 additions & 17 deletions apps/cli-go/internal/utils/connect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,23 +398,6 @@ func TestPostgresURL(t *testing.T) {
assert.Equal(t, `postgresql://postgres:%21%40%23$%25%5E&%2A%28%29@[2406:da18:4fd:9b0d:80ec:9812:3e65:450b]:5432/?connect_timeout=10&options=test`, url)
}

func TestPostgresURLWithoutPassword(t *testing.T) {
config := pgconn.Config{
Host: "2406:da18:4fd:9b0d:80ec:9812:3e65:450b",
Port: 5432,
User: "postgres",
Password: "!@#$%^&*()",
RuntimeParams: map[string]string{
"options": "test",
},
}
url := ToPostgresURLWithoutPassword(config)
// Same as ToPostgresURL but with the password omitted from the userinfo, so a
// credential is never written to stdout by the db __shadow seam.
assert.Equal(t, `postgresql://postgres@[2406:da18:4fd:9b0d:80ec:9812:3e65:450b]:5432/?connect_timeout=10&options=test`, url)
assert.NotContains(t, url, "%21%40%23")
}

func TestPreserveTLSConfig(t *testing.T) {
const dsn = "postgresql://postgres:pw@example.com:5432/postgres"

Expand Down
Loading
Loading