Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 31 additions & 23 deletions apps/cli-go/internal/start/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -1107,29 +1107,7 @@ EOF
ctx,
container.Config{
Image: utils.Config.Studio.Image,
Env: []string{
"CURRENT_CLI_VERSION=" + utils.Version,
"STUDIO_PG_META_URL=http://" + utils.PgmetaId + ":8080",
"POSTGRES_PASSWORD=" + dbConfig.Password,
"SUPABASE_URL=http://" + utils.KongId + ":8000",
"SUPABASE_PUBLIC_URL=" + utils.Config.Studio.ApiUrl,
"AUTH_JWT_SECRET=" + utils.Config.Auth.JwtSecret.Value,
"SUPABASE_ANON_KEY=" + utils.Config.Auth.AnonKey.Value,
"SUPABASE_SERVICE_KEY=" + utils.Config.Auth.ServiceRoleKey.Value,
"LOGFLARE_PRIVATE_ACCESS_TOKEN=" + utils.Config.Analytics.ApiKey,
"OPENAI_API_KEY=" + utils.Config.Studio.OpenaiApiKey.Value,
"PGRST_DB_SCHEMAS=" + strings.Join(utils.Config.Api.Schemas, ","),
"PGRST_DB_EXTRA_SEARCH_PATH=" + strings.Join(utils.Config.Api.ExtraSearchPath, ","),
fmt.Sprintf("PGRST_DB_MAX_ROWS=%d", utils.Config.Api.MaxRows),
fmt.Sprintf("LOGFLARE_URL=http://%v:4000", utils.LogflareId),
fmt.Sprintf("NEXT_PUBLIC_ENABLE_LOGS=%v", utils.Config.Analytics.Enabled),
fmt.Sprintf("NEXT_ANALYTICS_BACKEND_PROVIDER=%v", utils.Config.Analytics.Backend),
"EDGE_FUNCTIONS_MANAGEMENT_FOLDER=" + utils.ToDockerPath(filepath.Join(workdir, utils.FunctionsDir)),
"SNIPPETS_MANAGEMENT_FOLDER=" + containerSnippetsPath,
// Ref: https://github.com/vercel/next.js/issues/51684#issuecomment-1612834913
"HOSTNAME=0.0.0.0",
"POSTGRES_USER_READ_WRITE=postgres",
},
Env: buildStudioEnv(dbConfig, workdir, containerSnippetsPath),
Healthcheck: &container.HealthConfig{
Test: []string{"CMD-SHELL", `node --eval="fetch('http://127.0.0.1:3000/api/platform/profile').then((r) => {if (!r.ok) throw new Error(r.status)})"`},
Interval: 10 * time.Second,
Expand Down Expand Up @@ -1280,6 +1258,36 @@ func formatMapForEnvConfig(input map[string]string, output *bytes.Buffer) {
}
}

func buildStudioEnv(dbConfig pgconn.Config, workdir, containerSnippetsPath string) []string {
return []string{
"CURRENT_CLI_VERSION=" + utils.Version,
"STUDIO_PG_META_URL=http://" + utils.PgmetaId + ":8080",
"POSTGRES_PASSWORD=" + dbConfig.Password,
"SUPABASE_URL=http://" + utils.KongId + ":8000",
"SUPABASE_PUBLIC_URL=" + utils.Config.Studio.ApiUrl,
"AUTH_JWT_SECRET=" + utils.Config.Auth.JwtSecret.Value,
"SUPABASE_ANON_KEY=" + utils.Config.Auth.AnonKey.Value,
"SUPABASE_SERVICE_KEY=" + utils.Config.Auth.ServiceRoleKey.Value,
"SUPABASE_PUBLISHABLE_KEY=" + utils.Config.Auth.PublishableKey.Value,
"SUPABASE_SECRET_KEY=" + utils.Config.Auth.SecretKey.Value,
"S3_PROTOCOL_ACCESS_KEY_ID=" + utils.Config.Storage.S3Credentials.AccessKeyId,
"S3_PROTOCOL_ACCESS_KEY_SECRET=" + utils.Config.Storage.S3Credentials.SecretAccessKey,
"LOGFLARE_PRIVATE_ACCESS_TOKEN=" + utils.Config.Analytics.ApiKey,
"OPENAI_API_KEY=" + utils.Config.Studio.OpenaiApiKey.Value,
"PGRST_DB_SCHEMAS=" + strings.Join(utils.Config.Api.Schemas, ","),
"PGRST_DB_EXTRA_SEARCH_PATH=" + strings.Join(utils.Config.Api.ExtraSearchPath, ","),
fmt.Sprintf("PGRST_DB_MAX_ROWS=%d", utils.Config.Api.MaxRows),
fmt.Sprintf("LOGFLARE_URL=http://%v:4000", utils.LogflareId),
fmt.Sprintf("NEXT_PUBLIC_ENABLE_LOGS=%v", utils.Config.Analytics.Enabled),
fmt.Sprintf("NEXT_ANALYTICS_BACKEND_PROVIDER=%v", utils.Config.Analytics.Backend),
"EDGE_FUNCTIONS_MANAGEMENT_FOLDER=" + utils.ToDockerPath(filepath.Join(workdir, utils.FunctionsDir)),
"SNIPPETS_MANAGEMENT_FOLDER=" + containerSnippetsPath,
// Ref: https://github.com/vercel/next.js/issues/51684#issuecomment-1612834913
"HOSTNAME=0.0.0.0",
"POSTGRES_USER_READ_WRITE=postgres",
}
}

func buildGotrueEnv(dbConfig pgconn.Config) []string {
var testOTP bytes.Buffer
if len(utils.Config.Auth.Sms.TestOTP) > 0 {
Expand Down
44 changes: 44 additions & 0 deletions apps/cli-go/internal/start/start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,50 @@ func TestBuildGotrueEnv(t *testing.T) {
})
}

func TestBuildStudioEnv(t *testing.T) {
originalConfig := utils.Config
originalKongId := utils.KongId
originalPgmetaId := utils.PgmetaId
originalLogflareId := utils.LogflareId
originalVersion := utils.Version
t.Cleanup(func() {
utils.Config = originalConfig
utils.KongId = originalKongId
utils.PgmetaId = originalPgmetaId
utils.LogflareId = originalLogflareId
utils.Version = originalVersion
})

utils.Config = config.NewConfig()
utils.Config.Studio.ApiUrl = "http://127.0.0.1:54321"
utils.Config.Auth.JwtSecret.Value = "jwt-secret"
utils.Config.Auth.AnonKey.Value = "anon-key"
utils.Config.Auth.ServiceRoleKey.Value = "service-role-key"
utils.Config.Auth.PublishableKey.Value = "sb_publishable_test"
utils.Config.Auth.SecretKey.Value = "sb_secret_test"
utils.Config.Storage.S3Credentials.AccessKeyId = "s3-access-key"
utils.Config.Storage.S3Credentials.SecretAccessKey = "s3-secret-key"
utils.KongId = "test-kong"
utils.PgmetaId = "test-pgmeta"
utils.LogflareId = "test-logflare"
utils.Version = "test-version"

env := envToMap(buildStudioEnv(
pgconn.Config{Password: "postgres"},
"/project",
"/project/supabase/.temp/snippets",
))

assert.Equal(t, "anon-key", env["SUPABASE_ANON_KEY"])
assert.Equal(t, "service-role-key", env["SUPABASE_SERVICE_KEY"])
assert.Equal(t, "sb_publishable_test", env["SUPABASE_PUBLISHABLE_KEY"])
assert.Equal(t, "sb_secret_test", env["SUPABASE_SECRET_KEY"])
assert.Equal(t, "s3-access-key", env["S3_PROTOCOL_ACCESS_KEY_ID"])
assert.Equal(t, "s3-secret-key", env["S3_PROTOCOL_ACCESS_KEY_SECRET"])
assert.Equal(t, "http://test-kong:8000", env["SUPABASE_URL"])
assert.Equal(t, "http://test-pgmeta:8080", env["STUDIO_PG_META_URL"])
}

func TestFormatMapForEnvConfig(t *testing.T) {
t.Run("It produces the correct format and removes the trailing comma", func(t *testing.T) {
testcases := []struct {
Expand Down
8 changes: 7 additions & 1 deletion packages/stack/src/StackBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ import { makePostgresService, makePostgresServiceDocker } from "./services/postg
import { makePostgrestService, makePostgrestServiceDocker } from "./services/postgrest.ts";
import { makeRealtimeServiceDocker } from "./services/realtime.ts";
import { type ServiceDependency } from "./services/service-utils.ts";
import { makeStorageServiceDocker } from "./services/storage.ts";
import {
LOCAL_S3_PROTOCOL_ACCESS_KEY_ID,
LOCAL_S3_PROTOCOL_ACCESS_KEY_SECRET,
makeStorageServiceDocker,
} from "./services/storage.ts";
import { makeStudioServiceDocker } from "./services/studio.ts";
import { makeVectorServiceDocker } from "./services/vector.ts";
import type { PreparedStackArtifacts } from "./StackPreparation.ts";
Expand Down Expand Up @@ -879,6 +883,8 @@ export class StackBuilder extends Context.Service<
pgmetaUrl: pgmetaConfig === false ? "" : `http://${serviceHost}:${pgmetaConfig.port}`,
publishableKey: config.publishableKey,
secretKey: config.secretKey,
s3ProtocolAccessKeyId: LOCAL_S3_PROTOCOL_ACCESS_KEY_ID,
s3ProtocolAccessKeySecret: LOCAL_S3_PROTOCOL_ACCESS_KEY_SECRET,
jwtSecret: config.jwtSecret,
analyticsEnabled: config.analytics !== false,
analyticsBackend: config.analytics !== false ? config.analytics.backend : "postgres",
Expand Down
35 changes: 35 additions & 0 deletions packages/stack/src/services/services.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
import { makePostgresService, makePostgresServiceDocker } from "./postgres.ts";
import { makePostgrestService } from "./postgrest.ts";
import { makePoolerServiceDocker, poolerContainerPorts } from "./pooler.ts";
import { LOCAL_S3_PROTOCOL_ACCESS_KEY_ID, LOCAL_S3_PROTOCOL_ACCESS_KEY_SECRET } from "./storage.ts";
import { makeStudioServiceDocker } from "./studio.ts";
import { makeVectorServiceDocker } from "./vector.ts";
import { DEFAULT_VERSIONS, dockerImageForService } from "../versions.ts";

Expand Down Expand Up @@ -81,6 +83,39 @@ describe("analyticsDockerRuntimeNetwork", () => {
});
});

describe("makeStudioServiceDocker", () => {
it("injects legacy keys, opaque keys, and S3 protocol credentials", () => {
const def = makeStudioServiceDocker({
image: dockerImageForService("studio", DEFAULT_VERSIONS.studio),
apiPort: API_PORT,
port: 54323,
apiUrl: "http://host.docker.internal:54321",
publicApiUrl: "http://127.0.0.1:54321",
pgmetaUrl: "http://host.docker.internal:54322",
publishableKey: "sb_publishable_test",
secretKey: "sb_secret_test",
s3ProtocolAccessKeyId: LOCAL_S3_PROTOCOL_ACCESS_KEY_ID,
s3ProtocolAccessKeySecret: LOCAL_S3_PROTOCOL_ACCESS_KEY_SECRET,
jwtSecret: JWT_SECRET,
analyticsEnabled: true,
analyticsBackend: "postgres",
analyticsUrl: "http://host.docker.internal:54327",
analyticsApiKey: "test-api-key",
networkArgs: ["-p", "54323:54323"],
dependencies: [{ service: "pgmeta", condition: "healthy" }],
});

expect(def.args).toContain("SUPABASE_ANON_KEY=sb_publishable_test");
expect(def.args).toContain("SUPABASE_SERVICE_KEY=sb_secret_test");
expect(def.args).toContain("SUPABASE_PUBLISHABLE_KEY=sb_publishable_test");
expect(def.args).toContain("SUPABASE_SECRET_KEY=sb_secret_test");
expect(def.args).toContain(`S3_PROTOCOL_ACCESS_KEY_ID=${LOCAL_S3_PROTOCOL_ACCESS_KEY_ID}`);
expect(def.args).toContain(
`S3_PROTOCOL_ACCESS_KEY_SECRET=${LOCAL_S3_PROTOCOL_ACCESS_KEY_SECRET}`,
);
});
});

describe("makePostgresService (dockerAccessible)", () => {
it("creates per-run pg_hba.conf instead of mutating shared cache", () => {
const tempDir = mkdtempSync(path.join(tmpdir(), "stack-postgres-service-"));
Expand Down
7 changes: 5 additions & 2 deletions packages/stack/src/services/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ interface DockerStorageOptions {

const STORAGE_DATA_DIR = "/var/lib/storage";

export const LOCAL_S3_PROTOCOL_ACCESS_KEY_ID = "local";
export const LOCAL_S3_PROTOCOL_ACCESS_KEY_SECRET = "local-secret";

const orphanCleanup = (opts: DockerStorageOptions) =>
opts.cleanupDataDirOnExit ? removePathOnOrphanCleanup(opts.dataDir, { recursive: true }) : [];

Expand Down Expand Up @@ -66,8 +69,8 @@ export const makeStorageServiceDocker = (opts: DockerStorageOptions): ServiceDef
IMGPROXY_URL: opts.imgproxyUrl,
TUS_URL_PATH: "/storage/v1/upload/resumable",
S3_PROTOCOL_ENABLED: String(opts.s3ProtocolEnabled),
S3_PROTOCOL_ACCESS_KEY_ID: "local",
S3_PROTOCOL_ACCESS_KEY_SECRET: "local-secret",
S3_PROTOCOL_ACCESS_KEY_ID: LOCAL_S3_PROTOCOL_ACCESS_KEY_ID,
S3_PROTOCOL_ACCESS_KEY_SECRET: LOCAL_S3_PROTOCOL_ACCESS_KEY_SECRET,
S3_PROTOCOL_PREFIX: "/storage/v1",
UPLOAD_FILE_SIZE_LIMIT: "52428800000",
UPLOAD_FILE_SIZE_LIMIT_STANDARD: "5242880000",
Expand Down
6 changes: 6 additions & 0 deletions packages/stack/src/services/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ interface DockerStudioOptions {
readonly pgmetaUrl: string;
readonly publishableKey: string;
readonly secretKey: string;
readonly s3ProtocolAccessKeyId: string;
readonly s3ProtocolAccessKeySecret: string;
readonly jwtSecret: string;
readonly analyticsEnabled: boolean;
readonly analyticsBackend: "postgres" | "bigquery";
Expand Down Expand Up @@ -48,6 +50,10 @@ export const makeStudioServiceDocker = (opts: DockerStudioOptions): ServiceDef =
AUTH_JWT_SECRET: opts.jwtSecret,
SUPABASE_ANON_KEY: opts.publishableKey,
SUPABASE_SERVICE_KEY: opts.secretKey,
SUPABASE_PUBLISHABLE_KEY: opts.publishableKey,
SUPABASE_SECRET_KEY: opts.secretKey,
S3_PROTOCOL_ACCESS_KEY_ID: opts.s3ProtocolAccessKeyId,
S3_PROTOCOL_ACCESS_KEY_SECRET: opts.s3ProtocolAccessKeySecret,
LOGFLARE_PRIVATE_ACCESS_TOKEN: opts.analyticsApiKey,
LOGFLARE_URL: opts.analyticsUrl,
NEXT_PUBLIC_ENABLE_LOGS: String(opts.analyticsEnabled),
Expand Down
Loading