@ankhorage/infra 4.1.2 → 4.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @ankhorage/infra
2
2
 
3
+ ## 4.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 9cb5d75: Require generated app-image builds to execute the app-installed Expo CLI and fail before export when dependencies are missing.
8
+
3
9
  ## 4.1.2
4
10
 
5
11
  ### Patch Changes
@@ -351,10 +351,12 @@ ${appRuntimeEnabled ? `- App: \`http://127.0.0.1:${supabaseHostPorts.app}\`\n` :
351
351
 
352
352
  ## App Image Export
353
353
 
354
- \`build-app-image.sh\` clears the Expo/Metro bundler cache before every web export. Expo
355
- inlines \`EXPO_PUBLIC_*\` values into the browser bundle, so cache invalidation ensures a
356
- rotated browser-safe Supabase URL or anon key replaces the previous value before the Docker
357
- image is built. Privileged Supabase credentials are not written to the app's public env file.
354
+ \`build-app-image.sh\` requires the app-installed \`node_modules/.bin/expo\` and never resolves
355
+ Expo globally or through the network. It clears the Expo/Metro bundler cache before every web
356
+ export. Expo inlines \`EXPO_PUBLIC_*\` values into the browser bundle, so cache invalidation
357
+ ensures a rotated browser-safe Supabase URL or anon key replaces the previous value before the
358
+ Docker image is built. Privileged Supabase credentials are not written to the app's public env
359
+ file.
358
360
 
359
361
  ## Runtime Conventions
360
362
 
@@ -2675,29 +2677,31 @@ if [[ "\${APP_BUILD_ENABLED}" != "true" ]]; then
2675
2677
  exit 0
2676
2678
  fi
2677
2679
 
2678
- if ! command -v docker >/dev/null 2>&1; then
2679
- echo "docker is required to build app image."
2680
+ if [[ ! -f "\${APP_SOURCE_DIR}/package.json" ]]; then
2681
+ echo "APP_SOURCE_DIR does not look like an app root: \${APP_SOURCE_DIR}"
2680
2682
  exit 1
2681
2683
  fi
2682
2684
 
2683
- if ! command -v bunx >/dev/null 2>&1; then
2684
- echo "bunx is required to export the app for container image build."
2685
+ if [[ ! -f "\${DOCKERFILE_PATH}" ]]; then
2686
+ echo "Dockerfile for app image build is missing: \${DOCKERFILE_PATH}"
2685
2687
  exit 1
2686
2688
  fi
2687
2689
 
2688
- if [[ ! -f "\${APP_SOURCE_DIR}/package.json" ]]; then
2689
- echo "APP_SOURCE_DIR does not look like an app root: \${APP_SOURCE_DIR}"
2690
+ EXPO_CLI="\${APP_SOURCE_DIR}/node_modules/.bin/expo"
2691
+ if [[ ! -x "\${EXPO_CLI}" ]]; then
2692
+ echo "App-owned Expo CLI is missing: \${EXPO_CLI}" >&2
2693
+ echo "Run 'bun install --frozen-lockfile' in \${APP_SOURCE_DIR} before building the app image." >&2
2690
2694
  exit 1
2691
2695
  fi
2692
2696
 
2693
- if [[ ! -f "\${DOCKERFILE_PATH}" ]]; then
2694
- echo "Dockerfile for app image build is missing: \${DOCKERFILE_PATH}"
2697
+ if ! command -v docker >/dev/null 2>&1; then
2698
+ echo "docker is required to build app image."
2695
2699
  exit 1
2696
2700
  fi
2697
2701
 
2698
2702
  (
2699
2703
  cd "\${APP_SOURCE_DIR}"
2700
- bunx expo export --platform web --clear --output-dir "\${APP_WEB_EXPORT_DIR}"
2704
+ "\${EXPO_CLI}" export --platform web --clear --output-dir "\${APP_WEB_EXPORT_DIR}"
2701
2705
  )
2702
2706
 
2703
2707
  if [[ "\${APP_WEB_EXPORT_DIR}" = /* ]]; then
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/minikube/base/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GeneratedInfrastructureFile } from '../../../types';\nimport type { InfraManifestInput } from '../../../types';\nimport type { ResolvedProfileModel } from '../auth/supabase/profile';\nimport { resolveSupabaseProfileModel } from '../auth/supabase/profile';\nimport type { MinikubeProviderLifecycle } from '../contracts';\nimport { getSupabaseMigrationCommandScript } from './supabaseMigrations';\n\nexport const APP_NAMESPACE = 'app';\nconst SUPABASE_NAMESPACE = 'supabase';\n\ninterface SupabaseHostPorts {\n app: number;\n gateway: number;\n studio: number;\n db: number;\n}\n\ninterface AppInfraStorageMetadata {\n provider: 'supabase';\n bucketsCsv: string;\n defaultBucket: string;\n}\n\ninterface SupabaseImagePins {\n postgres: string;\n auth: string;\n rest: string;\n realtime: string;\n storage: string;\n imgproxy: string;\n meta: string;\n gateway: string;\n studio: string;\n}\n\ninterface SupabaseOAuthProviderRuntime {\n id: string;\n envPrefix: string;\n credentialsRef: string;\n callbackRoute: string;\n}\n\nconst SUPABASE_IMAGES: SupabaseImagePins = {\n postgres: 'supabase/postgres:17.6.1.136',\n auth: 'supabase/gotrue:v2.189.0',\n rest: 'postgrest/postgrest:v14.12',\n realtime: 'supabase/realtime:v2.102.3',\n storage: 'supabase/storage-api:v1.60.4',\n imgproxy: 'darthsim/imgproxy:v3.30.1',\n meta: 'supabase/postgres-meta:v0.96.6',\n gateway: 'kong/kong:3.9.1',\n studio: 'supabase/studio:2026.07.07-sha-a6a04f2',\n};\n\nconst PORT_BASE = 18080;\nconst PORT_BUCKET_SIZE = 20;\nconst PORT_BUCKET_COUNT = 1000;\nconst PORT_REFERENCE_SLUG = 'my-app';\n\nexport function generateMinikubeBaseArtifacts(args: {\n manifest: InfraManifestInput;\n appSlug: string;\n appRuntimeEnabled: boolean;\n extraResources: string[];\n providerNamespaces: string[];\n providerLifecycle: MinikubeProviderLifecycle[];\n extraEnvEntries: string[];\n}): GeneratedInfrastructureFile[] {\n const {\n manifest,\n appSlug,\n appRuntimeEnabled,\n extraResources,\n providerNamespaces,\n providerLifecycle,\n extraEnvEntries,\n } = args;\n\n const root = 'infra/minikube';\n const k8sRoot = `${root}/k8s`;\n const scriptsRoot = `${root}/scripts`;\n const appImageRoot = `${root}/app-image`;\n const defaultAppImage = getDefaultAppImage(appSlug);\n const supabaseHostPorts = resolveSupabaseHostPorts(appSlug);\n\n const authScope = manifest.auth?.scope ?? 'none';\n const authProvider = manifest.auth?.provider ?? 'none';\n const authzEngine = manifest.auth?.authorization?.engine ?? 'none';\n const databaseProvider = manifest.database?.provider ?? 'none';\n const secretStoreProvider = manifest.secretStore?.provider ?? 'none';\n const storageMetadata = resolveAppInfraStorageMetadata(manifest);\n const profileModel = resolveSupabaseProfileModel(manifest);\n const oauthProviders = resolveSupabaseOAuthProviders(manifest);\n const monitoringEnabled = manifest.deployment?.monitoring === true;\n const domain = manifest.networking?.domain ?? '';\n const supabaseKubernetesEnabled =\n authProvider === 'supabase' ||\n databaseProvider === 'supabase' ||\n storageMetadata !== null ||\n secretStoreProvider === 'supabase-vault';\n\n const supabaseResources = supabaseKubernetesEnabled ? getSupabaseResourceFiles(k8sRoot) : [];\n const namespaceResources = [\n 'namespaces/app.yaml',\n ...(supabaseKubernetesEnabled ? ['namespaces/supabase.yaml'] : []),\n ...providerNamespaces.map((namespace) => `namespaces/${namespace}.yaml`),\n ];\n\n return [\n {\n path: `${root}/README.md`,\n content: getReadmeMarkdown({\n appSlug,\n appRuntimeEnabled,\n defaultAppImage,\n monitoringEnabled,\n authProvider,\n authzEngine,\n extraResources,\n supabaseHostPorts,\n supabaseKubernetesEnabled,\n profileModel,\n oauthProviders,\n providerNamespaces,\n providerLifecycle,\n }),\n },\n {\n path: `${root}/.env.example`,\n content: getEnvExample({\n appSlug,\n domain,\n extraEnvEntries,\n defaultAppImage,\n supabaseHostPorts,\n supabaseKubernetesEnabled,\n oauthProviders,\n }),\n },\n {\n path: `${k8sRoot}/namespaces/app.yaml`,\n content: getNamespaceManifest(APP_NAMESPACE),\n },\n ...(supabaseKubernetesEnabled\n ? [\n {\n path: `${k8sRoot}/namespaces/supabase.yaml`,\n content: getNamespaceManifest(SUPABASE_NAMESPACE),\n },\n ]\n : []),\n ...providerNamespaces.map((namespace) => ({\n path: `${k8sRoot}/namespaces/${namespace}.yaml`,\n content: getNamespaceManifest(namespace),\n })),\n ...(appRuntimeEnabled\n ? [\n {\n path: `${k8sRoot}/app.configmap.yaml`,\n content: getAppConfigMap({\n appSlug,\n authScope,\n authProvider,\n databaseProvider,\n secretStoreProvider,\n storageMetadata,\n monitoringEnabled,\n domain,\n }),\n },\n {\n path: `${k8sRoot}/app/deployment.yaml`,\n content: getAppDeploymentManifest(defaultAppImage),\n },\n {\n path: `${k8sRoot}/app/service.yaml`,\n content: getAppServiceManifest(),\n },\n ]\n : []),\n ...supabaseResources,\n {\n path: `${k8sRoot}/kustomization.yaml`,\n content: getKustomizationManifest({\n namespaceResources,\n appRuntimeEnabled,\n supabaseEnabled: supabaseKubernetesEnabled,\n extraResources,\n }),\n },\n {\n path: `${scriptsRoot}/up.sh`,\n content: getUpScript({\n appSlug,\n appRuntimeEnabled,\n defaultAppImage,\n supabaseKubernetesEnabled,\n profileModel,\n secretStoreProvider,\n supabaseHostPorts,\n oauthProviders,\n providerLifecycle,\n }),\n executable: true,\n },\n {\n path: `${scriptsRoot}/build-app-image.sh`,\n content: getBuildAppImageScript({ appSlug, defaultAppImage }),\n executable: true,\n },\n {\n path: `${scriptsRoot}/port-forward.sh`,\n content: getPortForwardScript({\n appSlug,\n appRuntimeEnabled,\n supabaseKubernetesEnabled,\n supabaseHostPorts,\n }),\n executable: true,\n },\n {\n path: `${scriptsRoot}/down.sh`,\n content: getDownScript(appSlug),\n executable: true,\n },\n {\n path: `${scriptsRoot}/reset.sh`,\n content: getResetScript({\n appSlug,\n supabaseKubernetesEnabled,\n providerNamespaces,\n }),\n executable: true,\n },\n {\n path: `${scriptsRoot}/destroy.sh`,\n content: getDestroyScript(appSlug),\n executable: true,\n },\n {\n path: `${scriptsRoot}/status.sh`,\n content: getStatusScript({\n appSlug,\n appRuntimeEnabled,\n supabaseKubernetesEnabled,\n profileModel,\n supabaseHostPorts,\n providerNamespaces,\n providerLifecycle,\n }),\n executable: true,\n },\n {\n path: `${appImageRoot}/Dockerfile`,\n content: getAppImageDockerfile(),\n },\n ];\n}\n\nfunction getReadmeMarkdown(args: {\n appSlug: string;\n appRuntimeEnabled: boolean;\n defaultAppImage: string;\n monitoringEnabled: boolean;\n authProvider: string;\n authzEngine: string;\n extraResources: string[];\n supabaseHostPorts: SupabaseHostPorts;\n supabaseKubernetesEnabled: boolean;\n profileModel: ResolvedProfileModel;\n oauthProviders: readonly SupabaseOAuthProviderRuntime[];\n providerNamespaces: readonly string[];\n providerLifecycle: readonly MinikubeProviderLifecycle[];\n}): string {\n const {\n appSlug,\n appRuntimeEnabled,\n defaultAppImage,\n monitoringEnabled,\n authProvider,\n authzEngine,\n extraResources,\n supabaseHostPorts,\n supabaseKubernetesEnabled,\n profileModel,\n oauthProviders,\n providerNamespaces,\n providerLifecycle,\n } = args;\n const resourceLines = [\n 'namespaces/app.yaml',\n ...(supabaseKubernetesEnabled ? ['namespaces/supabase.yaml'] : []),\n ...providerNamespaces.map((namespace) => `namespaces/${namespace}.yaml`),\n ...(appRuntimeEnabled ? ['app.configmap.yaml', 'app/deployment.yaml', 'app/service.yaml'] : []),\n ...(supabaseKubernetesEnabled\n ? [\n 'supabase/bootstrap.sql',\n 'supabase/postgres.init.configmap.yaml',\n 'supabase/postgres.pvc.yaml',\n 'supabase/postgres.yaml',\n 'supabase/auth.yaml',\n 'supabase/rest.yaml',\n 'supabase/realtime.yaml',\n 'supabase/storage.yaml',\n 'supabase/imgproxy.yaml',\n 'supabase/meta.yaml',\n 'supabase/gateway.template.yml',\n 'supabase/kong-entrypoint.sh',\n 'supabase/gateway.yaml',\n 'supabase/studio.yaml',\n ]\n : []),\n ...extraResources,\n ]\n .map((resource) => `- \\`k8s/${resource}\\``)\n .join('\\n');\n\n const resetNamespaces = [\n APP_NAMESPACE,\n ...(supabaseKubernetesEnabled ? [SUPABASE_NAMESPACE] : []),\n ...providerNamespaces,\n ];\n const resetDescription = `deletes and recreates namespaces ${resetNamespaces\n .map((namespace) => `\\`${namespace}\\``)\n .join(\n ', ',\n )} inside the existing profile. This removes app-owned Kubernetes state and provider-owned PVC data for reset namespaces`;\n const providerNamespaceLine =\n providerNamespaces.length > 0\n ? `- Provider namespaces: \\`${providerNamespaces.join('`, `')}\\`\\n`\n : '';\n const providerLifecycleLines =\n providerLifecycle.length > 0\n ? `## Provider Lifecycle Contributions\\n\\n${providerLifecycle\n .map((provider) => {\n const readiness =\n provider.readinessChecks.length > 0\n ? provider.readinessChecks\n .map((check) => `\\`${check.resource}\\` in namespace \\`${check.namespace}\\``)\n .join(', ')\n : 'none';\n const endpoints =\n provider.endpoints.length > 0\n ? provider.endpoints\n .map((endpoint) => `\\`${endpoint.name}\\` = \\`${endpoint.url}\\``)\n .join(', ')\n : 'none';\n return `- \\`${provider.id}\\`: namespace \\`${provider.namespace}\\`; readiness ${readiness}; endpoints ${endpoints}`;\n })\n .join('\\n')}`\n : '';\n const oauthDescription =\n oauthProviders.length > 0\n ? `\\nConfigured OAuth providers are wired into GoTrue through generated \\`GOTRUE_EXTERNAL_*\\` runtime keys. The keys are named in \\`.env.example\\`; values must come from trusted secret resolution for the configured \\`credentialsRef\\` entries.`\n : '';\n\n const runtimeForwardDescription = appRuntimeEnabled\n ? supabaseKubernetesEnabled\n ? '`app` and `supabase-gateway`'\n : '`app`'\n : supabaseKubernetesEnabled\n ? '`supabase-gateway`'\n : 'no host endpoints';\n\n return `# Minikube Infra\n\nThis directory is generated from \\`ankh.config.json\\` (infra manifest).\n\n## Ownership Model\n\n- App slug / Minikube profile: \\`${appSlug}\\`\n- App runtime: \\`${appRuntimeEnabled ? `deployment/app-runtime in namespace ${APP_NAMESPACE}` : 'disabled (no enabled Web deploy target)'}\\`\n- Supabase namespace: \\`${supabaseKubernetesEnabled ? SUPABASE_NAMESPACE : 'unused'}\\`\n${providerNamespaceLine}- Default app image: \\`${defaultAppImage}\\`\n\nOne app owns one complete Minikube profile. Provider-owned workloads are separated by\nKubernetes namespace inside that profile. There is no shared \\`minikube\\` profile and no\nhost-level Supabase Compose runtime.\n\n## Quick Start\n\n1. Copy env template:\n \\`\\`\\`bash\n cp .env.example .env\n \\`\\`\\`\n2. Adjust optional values in \\`.env\\`; missing Supabase development secrets are generated by \\`up.sh\\`.\n3. Start infra:\n \\`\\`\\`bash\n ./scripts/up.sh\n \\`\\`\\`\n4. Check status:\n \\`\\`\\`bash\n ./scripts/status.sh\n \\`\\`\\`\n5. Stop the app-owned cluster without deleting data:\n \\`\\`\\`bash\n ./scripts/down.sh\n \\`\\`\\`\n\n## Lifecycle Semantics\n\n- \\`up.sh\\`: starts \\`minikube -p ${appSlug}\\`, deploys provider namespaces, runs migrations with CLI telemetry disabled for that command, starts slug-owned port-forwards${appRuntimeEnabled ? ', and deploys the Web app runtime' : ''}.\n- \\`down.sh\\`: stops slug-owned port-forwards, then stops \\`minikube -p ${appSlug}\\`. Persistent data remains in the profile.\n- \\`reset.sh\\`: requires \\`ANKH_RESET_CONFIRM=${appSlug}\\`; ${resetDescription}. It does not delete the Minikube profile.\n- \\`destroy.sh\\`: deletes only \\`minikube -p ${appSlug}\\`.\n\n### Port-forward groups\n\n- \\`./scripts/port-forward.sh start runtime\\` idempotently ensures ${runtimeForwardDescription}, the generated host endpoints required by the running application. The same group supports \\`stop\\` and \\`status\\`.\n- \\`runtime\\` excludes \\`studio\\` and \\`db-migration\\`, which are operational/bootstrap endpoints.\n- \\`all\\` retains every generated forward, including operational/bootstrap endpoints.\n- Concrete targets remain available for individual lifecycle control.\n\n## Generated Resources\n\n${resourceLines}\n\n## Supabase Runtime\n\nSupabase runtime ownership is Kubernetes. Migration authoring/history remains Supabase\nmigration files. Migration execution targets the Kubernetes Postgres endpoint through\n\\`SUPABASE_TELEMETRY_DISABLED=1 supabase --yes migration up --db-url \"$SUPABASE_DB_URL\"\\`.\nThe migration process does not require stdin. \\`--yes\\` remains defense in depth for future\nCLI prompts; it is not the hang fix. Command-scoped telemetry disable avoids the unbounded\ntelemetry shutdown in Supabase CLI 2.106.0 when PostHog is blocked, without changing the\nuser's persistent telemetry preference. Migration failures stop \\`up.sh\\`, and the completion\nmessage is printed only after a zero exit status. No migration deadline is added; using a\ncurrent Supabase CLI remains recommended.\n\nSupabase manifests are generated from the current official Supabase self-hosting Docker\ntopology, service documentation, environment-variable contracts, and pinned official images.\nKubernetes/Helm is treated as community-driven upstream guidance, not an official\ndistribution copied by this generator.\n${oauthDescription}\n\nPinned images:\n\n- Postgres: \\`${SUPABASE_IMAGES.postgres}\\`\n- Auth: \\`${SUPABASE_IMAGES.auth}\\`\n- PostgREST: \\`${SUPABASE_IMAGES.rest}\\`\n- Realtime: \\`${SUPABASE_IMAGES.realtime}\\`\n- Storage: \\`${SUPABASE_IMAGES.storage}\\`\n- Gateway: \\`${SUPABASE_IMAGES.gateway}\\`\n- Studio: \\`${SUPABASE_IMAGES.studio}\\`\n\n## Host URLs\n\n${appRuntimeEnabled ? `- App: \\`http://127.0.0.1:${supabaseHostPorts.app}\\`\\n` : ''}- Supabase gateway: \\`http://127.0.0.1:${supabaseHostPorts.gateway}\\`\n- Studio: \\`http://127.0.0.1:${supabaseHostPorts.studio}\\`\n- DB migration endpoint: \\`127.0.0.1:${supabaseHostPorts.db}\\`\n\n## App Image Export\n\n\\`build-app-image.sh\\` clears the Expo/Metro bundler cache before every web export. Expo\ninlines \\`EXPO_PUBLIC_*\\` values into the browser bundle, so cache invalidation ensures a\nrotated browser-safe Supabase URL or anon key replaces the previous value before the Docker\nimage is built. Privileged Supabase credentials are not written to the app's public env file.\n\n## Runtime Conventions\n\n- Monitoring requested: \\`${monitoringEnabled ? 'true' : 'false'}\\`\n- Auth provider: \\`${authProvider}\\`\n- Authorization engine: \\`${authzEngine}\\`\n${profileModel.enabled ? '- Generated profile reconciliation lives in `supabase/generated/auth_profiles.sql` and records checksum state in `ankhorage_internal.generated_schema_state`.\\n' : ''}\n${providerLifecycleLines}\n`;\n}\n\nfunction getEnvExample(args: {\n appSlug: string;\n domain: string;\n extraEnvEntries: string[];\n defaultAppImage: string;\n supabaseHostPorts: SupabaseHostPorts;\n supabaseKubernetesEnabled: boolean;\n oauthProviders: readonly SupabaseOAuthProviderRuntime[];\n}): string {\n const { appSlug, domain, extraEnvEntries, defaultAppImage, supabaseHostPorts, oauthProviders } =\n args;\n\n const baseEntries = [\n '# App-owned Minikube profile configuration',\n `ANKH_APP_SLUG=${appSlug}`,\n 'MINIKUBE_DRIVER=docker',\n 'APP_BUILD_ENABLED=true',\n 'APP_SOURCE_DIR=',\n 'APP_WEB_EXPORT_DIR=.ankh/web-export',\n `APP_IMAGE=${defaultAppImage}`,\n 'APP_IMAGE_SYNC_STRATEGY=docker-load',\n 'APP_IMAGE_CLEANUP_ON_DESTROY=true',\n 'APP_IMAGE_CLEANUP_MINIKUBE=true',\n 'APP_IMAGE_CLEANUP_DOCKER=true',\n `APP_PORT_FORWARD_LOCAL_PORT=${supabaseHostPorts.app}`,\n 'APP_PORT_FORWARD_REMOTE_PORT=80',\n `SUPABASE_GATEWAY_FORWARD_LOCAL_PORT=${supabaseHostPorts.gateway}`,\n 'SUPABASE_GATEWAY_FORWARD_REMOTE_PORT=8000',\n `SUPABASE_STUDIO_FORWARD_LOCAL_PORT=${supabaseHostPorts.studio}`,\n 'SUPABASE_STUDIO_FORWARD_REMOTE_PORT=3000',\n `SUPABASE_DB_FORWARD_LOCAL_PORT=${supabaseHostPorts.db}`,\n 'SUPABASE_DB_FORWARD_REMOTE_PORT=5432',\n 'APP_REPLICAS=1',\n 'APP_FORCE_ROLLOUT_RESTART=true',\n '',\n '# Optional private registry auth for APP_IMAGE',\n 'APP_IMAGE_PULL_SECRET_NAME=',\n 'APP_IMAGE_PULL_SECRET_SERVER=ghcr.io',\n 'APP_IMAGE_PULL_SECRET_USERNAME=',\n 'APP_IMAGE_PULL_SECRET_PASSWORD=',\n 'APP_IMAGE_PULL_SECRET_EMAIL=',\n '',\n '# Optional app networking domain',\n `APP_DOMAIN=${domain}`,\n '',\n '# Supabase Kubernetes runtime secrets',\n 'POSTGRES_PASSWORD=',\n 'JWT_SECRET=',\n 'SUPABASE_ANON_KEY=',\n 'SUPABASE_SERVICE_ROLE_KEY=',\n 'SUPABASE_PUBLISHABLE_KEY=',\n 'SUPABASE_SECRET_KEY=',\n 'DASHBOARD_USERNAME=supabase',\n 'DASHBOARD_PASSWORD=',\n 'SECRET_KEY_BASE=',\n 'REALTIME_DB_ENC_KEY=',\n 'PG_META_CRYPTO_KEY=',\n 'S3_PROTOCOL_ACCESS_KEY_ID=',\n 'S3_PROTOCOL_ACCESS_KEY_SECRET=',\n 'JWT_EXPIRY=3600',\n 'SITE_URL=',\n 'OAUTH_NATIVE_REDIRECT_URLS=',\n 'ADDITIONAL_REDIRECT_URLS=',\n 'SUPABASE_PUBLIC_URL=',\n 'API_EXTERNAL_URL=',\n 'ENABLE_EMAIL_SIGNUP=true',\n 'ENABLE_EMAIL_AUTOCONFIRM=true',\n 'SMTP_ADMIN_EMAIL=admin@example.com',\n 'SMTP_HOST=localhost',\n 'SMTP_PORT=2500',\n 'SMTP_USER=',\n 'SMTP_PASS=',\n 'SMTP_SENDER_NAME=Ankhorage',\n 'PGRST_DB_SCHEMAS=public,storage,graphql_public',\n 'PGRST_DB_MAX_ROWS=1000',\n 'PGRST_DB_EXTRA_SEARCH_PATH=public',\n 'GLOBAL_S3_BUCKET=stub',\n 'STORAGE_TENANT_ID=stub',\n 'REGION=stub',\n 'SUPABASE_DB_URL=',\n 'EXPO_PUBLIC_SUPABASE_URL=',\n 'EXPO_PUBLIC_SUPABASE_ANON_KEY=',\n ...getOAuthEnvExampleEntries(oauthProviders),\n '',\n '# Adapter-provided runtime keys',\n ];\n\n const merged = [...baseEntries, ...extraEnvEntries];\n const unique: string[] = [];\n for (const entry of merged) {\n if (!unique.includes(entry)) unique.push(entry);\n }\n\n return `${unique.join('\\n')}\\n`;\n}\n\nfunction getOAuthEnvExampleEntries(providers: readonly SupabaseOAuthProviderRuntime[]): string[] {\n if (providers.length === 0) return [];\n\n return [\n '',\n '# OAuth provider runtime values resolved from trusted credentialsRef entries',\n ...providers.flatMap((provider) => [\n `# ${provider.id}: ${provider.credentialsRef}`,\n `GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID=`,\n `GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET=`,\n `GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI=`,\n ]),\n ];\n}\n\nfunction getOAuthScriptEnvDefaults(providers: readonly SupabaseOAuthProviderRuntime[]): string {\n if (providers.length === 0) return '';\n\n return providers\n .map(\n (\n provider,\n ) => ` export GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID=\"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID:-}\"\n export GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET=\"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET:-}\"\n export GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI=\"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI:-\\${API_EXTERNAL_URL}/callback}\"`,\n )\n .join('\\n');\n}\n\nfunction getOAuthRuntimeSecretLines(providers: readonly SupabaseOAuthProviderRuntime[]): string {\n if (providers.length === 0) return '';\n\n return providers\n .map(\n (provider) => `GOTRUE_EXTERNAL_${provider.envPrefix}_ENABLED=true\nGOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID=\\${GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID}\nGOTRUE_EXTERNAL_${provider.envPrefix}_SECRET=\\${GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET}\nGOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI=\\${GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI}`,\n )\n .join('\\n');\n}\n\nfunction getOAuthRuntimeValidationScript(\n providers: readonly SupabaseOAuthProviderRuntime[],\n): string {\n if (providers.length === 0) return '';\n\n const checks = providers\n .map(\n (\n provider,\n ) => ` if [[ -z \"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID:-}\" || -z \"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET:-}\" ]]; then\n echo \"OAuth provider ${provider.id} requires trusted runtime values GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID and GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET from credentialsRef ${provider.credentialsRef}.\"\n exit 1\n fi`,\n )\n .join('\\n');\n\n return `\n # OAuth provider secrets must be resolved by trusted host code before Kubernetes sync.\n${checks}`;\n}\n\nfunction getSupabaseOAuthCallbackRoute(providers: readonly SupabaseOAuthProviderRuntime[]): string {\n return providers[0]?.callbackRoute ?? '/auth/callback';\n}\n\nfunction getOAuthVaultResolutionScript(args: {\n appSlug: string;\n oauthProviders: readonly SupabaseOAuthProviderRuntime[];\n secretStoreProvider: string;\n}): string {\n const { appSlug, oauthProviders, secretStoreProvider } = args;\n if (secretStoreProvider !== 'supabase-vault' || oauthProviders.length === 0) {\n return `\nresolve_oauth_credentials_from_vault() {\n return 0\n}\n`;\n }\n\n const lines = oauthProviders\n .map((provider) => {\n const ref = escapeSingleQuotedSql(provider.credentialsRef);\n const idKey = `GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID`;\n const secretKey = `GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET`;\n\n return ` if [[ -z \"\\${${idKey}:-}\" || -z \"\\${${secretKey}:-}\" ]]; then\n local resolved_client_id resolved_client_secret\n resolved_client_id=\"$(resolve_vault_secret_field '${ref}' 'clientId')\"\n resolved_client_secret=\"$(resolve_vault_secret_field '${ref}' 'clientSecret')\"\n if [[ -n \"\\${resolved_client_id}\" ]]; then\n export ${idKey}=\"\\${resolved_client_id}\"\n fi\n if [[ -n \"\\${resolved_client_secret}\" ]]; then\n export ${secretKey}=\"\\${resolved_client_secret}\"\n fi\n fi`;\n })\n .join('\\n');\n\n return `\nresolve_vault_secret_field() {\n local ref=\"\\${1}\"\n local field=\"\\${2}\"\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -Atq -c \"select coalesce(decrypted.decrypted_secret::jsonb ->> '\\${field}', '') from ankh_secret_store.secret_metadata metadata join vault.decrypted_secrets decrypted on decrypted.id = metadata.vault_secret_id where metadata.project_id = '${escapeSingleQuotedSql(\n appSlug,\n )}' and metadata.environment = 'local' and metadata.secret_ref = '\\${ref}' limit 1;\" 2>/dev/null || true\n}\n\nresolve_oauth_credentials_from_vault() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n${lines}\n}\n`;\n}\n\nfunction escapeSingleQuotedSql(value: string): string {\n return value.replace(/'/gu, \"''\");\n}\n\nfunction escapeShellDoubleQuoted(value: string): string {\n return value.replace(/[\"\\\\$`]/gu, (char) => `\\\\${char}`);\n}\n\nfunction getProviderLifecycleStageScripts(\n providerLifecycle: readonly MinikubeProviderLifecycle[],\n): string {\n return `${getProviderLifecycleCommandFunction({\n functionName: 'run_provider_migrations',\n emptyReturn: 'return 0',\n commands: providerLifecycle.flatMap((provider) =>\n provider.migrationCommands.map((command) => ({\n providerId: provider.id,\n label: command.label,\n command: command.command,\n })),\n ),\n })}\n\n${getProviderLifecycleCommandFunction({\n functionName: 'run_provider_reconciliation',\n emptyReturn: 'return 0',\n commands: providerLifecycle.flatMap((provider) =>\n provider.reconciliationCommands.map((command) => ({\n providerId: provider.id,\n label: command.label,\n command: command.command,\n })),\n ),\n})}\n\n${getProviderReadinessFunction(providerLifecycle)}`;\n}\n\nfunction getProviderLifecycleCommandFunction(args: {\n functionName: string;\n emptyReturn: string;\n commands: readonly { providerId: string; label: string; command: string }[];\n}): string {\n if (args.commands.length === 0) {\n return `${args.functionName}() {\n ${args.emptyReturn}\n}`;\n }\n\n const body = args.commands\n .map(\n (command) => ` echo \"Running provider ${escapeShellDoubleQuoted(\n command.providerId,\n )} ${escapeShellDoubleQuoted(command.label)}.\"\n${indentShellBlock(command.command.trim(), 2)}`,\n )\n .join('\\n\\n');\n\n return `${args.functionName}() {\n${body}\n}`;\n}\n\nfunction getProviderReadinessFunction(\n providerLifecycle: readonly MinikubeProviderLifecycle[],\n): string {\n const checks = providerLifecycle.flatMap((provider) =>\n provider.readinessChecks.map((check) => ({ providerId: provider.id, ...check })),\n );\n\n if (checks.length === 0) {\n return `wait_for_provider_readiness() {\n return 0\n}`;\n }\n\n const body = checks\n .map(\n (check) =>\n ` kubectl --context \"\\${PROFILE}\" -n \"${escapeShellDoubleQuoted(\n check.namespace,\n )}\" rollout status \"${escapeShellDoubleQuoted(\n check.resource,\n )}\" --timeout=${check.timeoutSeconds}s`,\n )\n .join('\\n');\n\n return `wait_for_provider_readiness() {\n${body}\n}`;\n}\n\nfunction getProviderStatusScript(providerLifecycle: readonly MinikubeProviderLifecycle[]): string {\n if (providerLifecycle.length === 0) {\n return '';\n }\n\n return providerLifecycle\n .map((provider) => {\n const endpointLines = provider.endpoints\n .map(\n (endpoint) =>\n ` echo \"- provider ${escapeShellDoubleQuoted(\n provider.id,\n )} endpoint/${escapeShellDoubleQuoted(endpoint.name)}: ${escapeShellDoubleQuoted(\n endpoint.url,\n )}\"`,\n )\n .join('\\n');\n const readinessLines = provider.readinessChecks\n .map(\n (check) => ` if kubectl --context \"\\${PROFILE}\" -n \"${escapeShellDoubleQuoted(\n check.namespace,\n )}\" rollout status \"${escapeShellDoubleQuoted(\n check.resource,\n )}\" --timeout=5s >/dev/null 2>&1; then\n echo \"- provider ${escapeShellDoubleQuoted(provider.id)}/${escapeShellDoubleQuoted(\n check.label,\n )}: ready\"\n else\n echo \"- provider ${escapeShellDoubleQuoted(provider.id)}/${escapeShellDoubleQuoted(\n check.label,\n )}: not ready\"\n fi`,\n )\n .join('\\n');\n const customStatusLines = provider.statusChecks\n .map(\n (check) => ` echo \"Running provider ${escapeShellDoubleQuoted(\n provider.id,\n )} status check ${escapeShellDoubleQuoted(check.label)}.\"\n${indentShellBlock(check.command.trim(), 2)}`,\n )\n .join('\\n');\n\n return [endpointLines, readinessLines, customStatusLines].filter(Boolean).join('\\n');\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction indentShellBlock(value: string, spaces: number): string {\n const indent = ' '.repeat(spaces);\n return value\n .split('\\n')\n .map((line) => `${indent}${line}`)\n .join('\\n');\n}\n\nfunction getNamespaceManifest(namespace: string): string {\n return `apiVersion: v1\nkind: Namespace\nmetadata:\n name: ${namespace}\n labels:\n app.kubernetes.io/part-of: ankhorage\n ankhorage.io/namespace-role: ${namespace}\n`;\n}\n\nfunction getAppConfigMap(args: {\n appSlug: string;\n authScope: string;\n authProvider: string;\n databaseProvider: string;\n secretStoreProvider: string;\n storageMetadata: AppInfraStorageMetadata | null;\n monitoringEnabled: boolean;\n domain: string;\n}): string {\n const {\n appSlug,\n authScope,\n authProvider,\n databaseProvider,\n secretStoreProvider,\n storageMetadata,\n monitoringEnabled,\n domain,\n } = args;\n\n const storageLines = storageMetadata\n ? ` STORAGE_PROVIDER: \"${storageMetadata.provider}\"\n STORAGE_BUCKETS: \"${escapeYamlDoubleQuoted(storageMetadata.bucketsCsv)}\"\n STORAGE_DEFAULT_BUCKET: \"${escapeYamlDoubleQuoted(storageMetadata.defaultBucket)}\"\n`\n : '';\n\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: app-infra-config\n namespace: ${APP_NAMESPACE}\ndata:\n ANKH_APP_SLUG: \"${appSlug}\"\n DEPLOYMENT_TARGET: \"minikube\"\n APP_NAMESPACE: \"${APP_NAMESPACE}\"\n SUPABASE_NAMESPACE: \"${SUPABASE_NAMESPACE}\"\n MONITORING_ENABLED: \"${monitoringEnabled ? 'true' : 'false'}\"\n AUTH_SCOPE: \"${authScope}\"\n AUTH_PROVIDER: \"${authProvider}\"\n DATABASE_PROVIDER: \"${databaseProvider}\"\n SECRET_STORE_PROVIDER: \"${secretStoreProvider}\"\n${storageLines} NETWORK_DOMAIN: \"${escapeYamlDoubleQuoted(domain)}\"\n`;\n}\n\nfunction resolveAppInfraStorageMetadata(\n manifest: InfraManifestInput,\n): AppInfraStorageMetadata | null {\n const spec = manifest.storage;\n if (!spec) return null;\n\n const buckets = normalizeBuckets(spec.buckets);\n if (buckets.length === 0) return null;\n const [defaultBucket] = buckets;\n if (!defaultBucket) return null;\n\n if (spec.provider === 'supabase') {\n return {\n provider: 'supabase',\n bucketsCsv: buckets.join(','),\n defaultBucket,\n };\n }\n\n if (spec.provider === 'auto') {\n const shouldResolveToSupabase =\n manifest.database?.provider === 'supabase' || manifest.auth?.provider === 'supabase';\n\n if (!shouldResolveToSupabase) return null;\n\n return {\n provider: 'supabase',\n bucketsCsv: buckets.join(','),\n defaultBucket,\n };\n }\n\n return null;\n}\n\nfunction resolveSupabaseOAuthProviders(\n manifest: InfraManifestInput,\n): readonly SupabaseOAuthProviderRuntime[] {\n const oauth = manifest.auth?.oauth;\n if (!oauth?.enabled) return [];\n const callbackRoute = normalizeOAuthCallbackRoute(oauth.callbackRoute);\n\n return oauth.providers\n .filter((provider) => provider.enabled !== false)\n .map((provider) => {\n const id = provider.id.trim();\n const credentialsRef = provider.credentialsRef?.trim();\n if (!credentialsRef) {\n throw new Error(`OAuth provider \"${id}\" is enabled but does not define credentialsRef.`);\n }\n\n const envPrefix = id\n .toUpperCase()\n .replace(/[^A-Z0-9]+/gu, '_')\n .replace(/^_+|_+$/gu, '');\n if (!envPrefix) {\n throw new Error(`OAuth provider \"${id}\" cannot be mapped to GoTrue environment keys.`);\n }\n\n return {\n id,\n envPrefix,\n credentialsRef,\n callbackRoute,\n };\n });\n}\n\nfunction normalizeOAuthCallbackRoute(rawRoute: string | undefined): string {\n const trimmedRoute = rawRoute?.trim();\n const route = trimmedRoute && trimmedRoute.length > 0 ? trimmedRoute : '/auth/callback';\n const withLeadingSlash = route.startsWith('/') ? route : `/${route}`;\n return withLeadingSlash.replace(/\\/+/gu, '/');\n}\n\nfunction normalizeBuckets(rawBuckets: readonly string[]): string[] {\n const normalized: string[] = [];\n const seen = new Set<string>();\n\n for (const raw of rawBuckets) {\n const bucket = raw.trim();\n if (!bucket) continue;\n if (seen.has(bucket)) continue;\n seen.add(bucket);\n normalized.push(bucket);\n }\n\n return normalized;\n}\n\nfunction getKustomizationManifest(args: {\n namespaceResources: string[];\n appRuntimeEnabled: boolean;\n supabaseEnabled: boolean;\n extraResources: string[];\n}): string {\n const supabaseResources = args.supabaseEnabled\n ? [\n 'supabase/postgres.init.configmap.yaml',\n 'supabase/postgres.pvc.yaml',\n 'supabase/postgres.yaml',\n 'supabase/auth.yaml',\n 'supabase/rest.yaml',\n 'supabase/realtime.yaml',\n 'supabase/imgproxy.yaml',\n 'supabase/storage.yaml',\n 'supabase/meta.yaml',\n 'supabase/gateway.yaml',\n 'supabase/studio.yaml',\n ]\n : [];\n const resources = [\n ...args.namespaceResources,\n ...(args.appRuntimeEnabled\n ? ['app.configmap.yaml', 'app/deployment.yaml', 'app/service.yaml']\n : []),\n ...supabaseResources,\n ...args.extraResources,\n ];\n const resourceLines = resources.map((resource) => ` - ${resource}`).join('\\n');\n\n return `apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nresources:\n${resourceLines}\n`;\n}\n\nfunction getAppDeploymentManifest(defaultAppImage: string): string {\n return `apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: app-runtime\n namespace: ${APP_NAMESPACE}\n labels:\n app.kubernetes.io/name: app-runtime\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: app-runtime\n template:\n metadata:\n labels:\n app.kubernetes.io/name: app-runtime\n spec:\n containers:\n - name: app\n image: ${defaultAppImage}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 8080\n name: http\n envFrom:\n - configMapRef:\n name: app-infra-config\n - configMapRef:\n name: app-runtime-auth-env\n optional: true\n - configMapRef:\n name: app-runtime-storage-env\n optional: true\n - secretRef:\n name: supabase-public-runtime\n optional: true\n readinessProbe:\n httpGet:\n path: /\n port: http\n initialDelaySeconds: 5\n periodSeconds: 10\n livenessProbe:\n httpGet:\n path: /\n port: http\n initialDelaySeconds: 15\n periodSeconds: 20\n`;\n}\n\nfunction getAppServiceManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: app-runtime\n namespace: ${APP_NAMESPACE}\n labels:\n app.kubernetes.io/name: app-runtime\nspec:\n type: ClusterIP\n selector:\n app.kubernetes.io/name: app-runtime\n ports:\n - name: http\n port: 80\n targetPort: http\n`;\n}\n\nfunction getSupabaseResourceFiles(k8sRoot: string): GeneratedInfrastructureFile[] {\n return [\n {\n path: `${k8sRoot}/supabase/bootstrap.sql`,\n content: getSupabaseBootstrapSql(),\n },\n {\n path: `${k8sRoot}/supabase/postgres.init.configmap.yaml`,\n content: getSupabasePostgresInitConfigMap(),\n },\n {\n path: `${k8sRoot}/supabase/postgres.pvc.yaml`,\n content: getSupabasePvcManifest('supabase-postgres-data', '20Gi'),\n },\n {\n path: `${k8sRoot}/supabase/postgres.yaml`,\n content: getSupabasePostgresManifest(),\n },\n {\n path: `${k8sRoot}/supabase/auth.yaml`,\n content: getSupabaseAuthManifest(),\n },\n {\n path: `${k8sRoot}/supabase/rest.yaml`,\n content: getSupabaseRestManifest(),\n },\n {\n path: `${k8sRoot}/supabase/realtime.yaml`,\n content: getSupabaseRealtimeManifest(),\n },\n {\n path: `${k8sRoot}/supabase/storage.yaml`,\n content: getSupabaseStorageManifest(),\n },\n {\n path: `${k8sRoot}/supabase/imgproxy.yaml`,\n content: getSupabaseImgproxyManifest(),\n },\n {\n path: `${k8sRoot}/supabase/meta.yaml`,\n content: getSupabaseMetaManifest(),\n },\n {\n path: `${k8sRoot}/supabase/gateway.template.yml`,\n content: getSupabaseGatewayTemplate(),\n },\n {\n path: `${k8sRoot}/supabase/kong-entrypoint.sh`,\n content: getSupabaseKongEntrypointScript(),\n executable: true,\n },\n {\n path: `${k8sRoot}/supabase/gateway.yaml`,\n content: getSupabaseGatewayManifest(),\n },\n {\n path: `${k8sRoot}/supabase/studio.yaml`,\n content: getSupabaseStudioManifest(),\n },\n ];\n}\n\nfunction getSupabaseBootstrapSql(): string {\n return `-- Generated from the official Supabase self-hosting Docker database bootstrap contract.\n-- Applied by scripts/up.sh after Postgres is ready and before Supabase services start.\n\\\\set pgpass \\`echo \"$POSTGRES_PASSWORD\"\\`\n\\\\set jwt_secret \\`echo \"$JWT_SECRET\"\\`\n\\\\set jwt_exp \\`echo \"$JWT_EXP\"\\`\n\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'anon') THEN\n CREATE ROLE anon NOLOGIN NOINHERIT;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticated') THEN\n CREATE ROLE authenticated NOLOGIN NOINHERIT;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'service_role') THEN\n CREATE ROLE service_role NOLOGIN NOINHERIT BYPASSRLS;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticator') THEN\n CREATE ROLE authenticator NOINHERIT LOGIN;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_admin') THEN\n CREATE ROLE supabase_admin LOGIN CREATEROLE CREATEDB REPLICATION BYPASSRLS;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_auth_admin') THEN\n CREATE ROLE supabase_auth_admin LOGIN CREATEROLE;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_storage_admin') THEN\n CREATE ROLE supabase_storage_admin LOGIN CREATEROLE;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_functions_admin') THEN\n CREATE ROLE supabase_functions_admin LOGIN CREATEROLE;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'pgbouncer') THEN\n CREATE ROLE pgbouncer LOGIN;\n END IF;\nEND\n$$;\n\nALTER ROLE authenticator WITH PASSWORD :'pgpass';\nALTER ROLE pgbouncer WITH PASSWORD :'pgpass';\nALTER ROLE supabase_auth_admin WITH PASSWORD :'pgpass';\nALTER ROLE supabase_functions_admin WITH PASSWORD :'pgpass';\nALTER ROLE supabase_storage_admin WITH PASSWORD :'pgpass';\nALTER ROLE supabase_admin WITH PASSWORD :'pgpass';\n\nGRANT anon, authenticated, service_role TO authenticator;\nGRANT anon, authenticated, service_role TO supabase_storage_admin;\nGRANT postgres TO supabase_auth_admin;\nGRANT postgres TO supabase_storage_admin;\nGRANT postgres TO supabase_functions_admin;\nGRANT pg_monitor TO supabase_admin;\n\nCREATE SCHEMA IF NOT EXISTS auth AUTHORIZATION supabase_auth_admin;\nCREATE SCHEMA IF NOT EXISTS storage AUTHORIZATION supabase_storage_admin;\nCREATE SCHEMA IF NOT EXISTS graphql_public;\nCREATE SCHEMA IF NOT EXISTS _realtime AUTHORIZATION supabase_admin;\n\nGRANT USAGE ON SCHEMA public, graphql_public TO anon, authenticated, service_role;\nGRANT USAGE ON SCHEMA auth TO supabase_auth_admin;\nGRANT USAGE ON SCHEMA storage TO supabase_storage_admin, anon, authenticated, service_role;\nGRANT USAGE ON SCHEMA _realtime TO supabase_admin;\n\nALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO anon, authenticated, service_role;\nALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO anon, authenticated, service_role;\n\nALTER DATABASE postgres SET \"app.settings.jwt_secret\" TO :'jwt_secret';\nALTER DATABASE postgres SET \"app.settings.jwt_exp\" TO :'jwt_exp';\n\nSELECT 'CREATE DATABASE _supabase WITH OWNER supabase_admin'\nWHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '_supabase')\\\\gexec\n`;\n}\n\nfunction getSupabasePostgresInitConfigMap(): string {\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: supabase-postgres-init\n namespace: ${SUPABASE_NAMESPACE}\ndata:\n 99-ankhorage-local-dev-extensions.sql: |\n -- Local Minikube bootstrap for extension setup performed before runtime migrations.\n alter role postgres with superuser;\n grant pg_read_server_files to postgres;\n grant pg_read_server_files to supabase_admin;\n grant execute on function pg_read_file(text) to public;\n grant execute on function pg_read_file(text, bigint, bigint) to public;\n`;\n}\n\nfunction getSupabasePvcManifest(name: string, size: string): string {\n return `apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n name: ${name}\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n accessModes:\n - ReadWriteOnce\n resources:\n requests:\n storage: ${size}\n`;\n}\n\nfunction getSupabasePostgresManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: postgres\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-postgres\n ports:\n - name: postgres\n port: 5432\n targetPort: postgres\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: postgres\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-postgres\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-postgres\n spec:\n containers:\n - name: postgres\n image: ${SUPABASE_IMAGES.postgres}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 5432\n name: postgres\n env:\n - name: POSTGRES_USER\n value: postgres\n - name: POSTGRES_PASSWORD\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: POSTGRES_PASSWORD\n - name: PGPASSWORD\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: POSTGRES_PASSWORD\n - name: POSTGRES_DB\n value: postgres\n - name: PGDATABASE\n value: postgres\n - name: PGPORT\n value: \"5432\"\n - name: POSTGRES_PORT\n value: \"5432\"\n - name: POSTGRES_HOST\n value: /var/run/postgresql\n - name: JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: JWT_EXP\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: JWT_EXPIRY\n volumeMounts:\n - name: data\n mountPath: /var/lib/postgresql/data\n - name: init-scripts\n mountPath: /docker-entrypoint-initdb.d/99-ankhorage-local-dev-extensions.sql\n subPath: 99-ankhorage-local-dev-extensions.sql\n readinessProbe:\n exec:\n command: [\"pg_isready\", \"-U\", \"postgres\"]\n initialDelaySeconds: 15\n periodSeconds: 5\n livenessProbe:\n exec:\n command: [\"pg_isready\", \"-U\", \"postgres\"]\n initialDelaySeconds: 30\n periodSeconds: 10\n args:\n - postgres\n - -c\n - config_file=/etc/postgresql/postgresql.conf\n - -c\n - log_min_messages=fatal\n volumes:\n - name: data\n persistentVolumeClaim:\n claimName: supabase-postgres-data\n - name: init-scripts\n configMap:\n name: supabase-postgres-init\n`;\n}\n\nfunction getSupabaseAuthManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: auth\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-auth\n ports:\n - name: http\n port: 9999\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: auth\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-auth\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-auth\n spec:\n containers:\n - name: auth\n image: ${SUPABASE_IMAGES.auth}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 9999\n name: http\n env:\n - name: GOTRUE_API_HOST\n value: \"0.0.0.0\"\n - name: GOTRUE_API_PORT\n value: \"9999\"\n - name: API_EXTERNAL_URL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: API_EXTERNAL_URL\n - name: GOTRUE_SITE_URL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SITE_URL\n - name: GOTRUE_URI_ALLOW_LIST\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: ADDITIONAL_REDIRECT_URLS\n - name: GOTRUE_JWT_ISSUER\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: API_EXTERNAL_URL\n - name: GOTRUE_DB_DRIVER\n value: postgres\n - name: GOTRUE_DB_DATABASE_URL\n value: \"postgres://supabase_auth_admin:$(POSTGRES_PASSWORD)@postgres.${SUPABASE_NAMESPACE}.svc.cluster.local:5432/postgres?search_path=auth&sslmode=disable\"\n - name: GOTRUE_JWT_AUD\n value: authenticated\n - name: GOTRUE_JWT_DEFAULT_GROUP_NAME\n value: authenticated\n - name: GOTRUE_JWT_ADMIN_ROLES\n value: service_role\n - name: GOTRUE_JWT_EXP\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: JWT_EXPIRY\n - name: GOTRUE_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: GOTRUE_EXTERNAL_EMAIL_ENABLED\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: ENABLE_EMAIL_SIGNUP\n - name: GOTRUE_MAILER_AUTOCONFIRM\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: ENABLE_EMAIL_AUTOCONFIRM\n - name: GOTRUE_SMTP_ADMIN_EMAIL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SMTP_ADMIN_EMAIL\n - name: GOTRUE_SMTP_HOST\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SMTP_HOST\n - name: GOTRUE_SMTP_PORT\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SMTP_PORT\n - name: GOTRUE_SMTP_USER\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SMTP_USER\n - name: GOTRUE_SMTP_PASS\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SMTP_PASS\n - name: GOTRUE_SMTP_SENDER_NAME\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SMTP_SENDER_NAME\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n - configMapRef:\n name: supabase-runtime-config\n readinessProbe:\n httpGet:\n path: /health\n port: http\n initialDelaySeconds: 10\n periodSeconds: 10\n`;\n}\n\nfunction getSupabaseRestManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: rest\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-rest\n ports:\n - name: http\n port: 3000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: rest\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-rest\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-rest\n spec:\n containers:\n - name: rest\n image: ${SUPABASE_IMAGES.rest}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 3000\n name: http\n env:\n - name: PGRST_DB_URI\n value: \"postgres://authenticator:$(POSTGRES_PASSWORD)@postgres.${SUPABASE_NAMESPACE}.svc.cluster.local:5432/postgres\"\n - name: PGRST_DB_SCHEMAS\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: PGRST_DB_SCHEMAS\n - name: PGRST_DB_ANON_ROLE\n value: anon\n - name: PGRST_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: PGRST_DB_USE_LEGACY_GUCS\n value: \"false\"\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n - configMapRef:\n name: supabase-runtime-config\n`;\n}\n\nfunction getSupabaseRealtimeManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: realtime\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-realtime\n ports:\n - name: http\n port: 4000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: realtime\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-realtime\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-realtime\n spec:\n containers:\n - name: realtime\n image: ${SUPABASE_IMAGES.realtime}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 4000\n name: http\n env:\n - name: PORT\n value: \"4000\"\n - name: DB_HOST\n value: \"postgres.${SUPABASE_NAMESPACE}.svc.cluster.local\"\n - name: DB_PORT\n value: \"5432\"\n - name: DB_NAME\n value: postgres\n - name: DB_USER\n value: supabase_admin\n - name: DB_PASSWORD\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: POSTGRES_PASSWORD\n - name: API_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: SECRET_KEY_BASE\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SECRET_KEY_BASE\n - name: DB_AFTER_CONNECT_QUERY\n value: \"SET search_path TO _realtime\"\n - name: DB_ENC_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: REALTIME_DB_ENC_KEY\n - name: METRICS_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: APP_NAME\n value: realtime\n - name: SEED_SELF_HOST\n value: \"true\"\n - name: RUN_JANITOR\n value: \"true\"\n - name: DISABLE_HEALTHCHECK_LOGGING\n value: \"true\"\n`;\n}\n\nfunction getSupabaseStorageManifest(): string {\n return `${getSupabasePvcManifest('supabase-storage-data', '10Gi')}\n---\napiVersion: v1\nkind: Service\nmetadata:\n name: storage\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-storage\n ports:\n - name: http\n port: 5000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: storage\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-storage\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-storage\n spec:\n containers:\n - name: storage\n image: ${SUPABASE_IMAGES.storage}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 5000\n name: http\n env:\n - name: ANON_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_ANON_KEY\n - name: SERVICE_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_SERVICE_ROLE_KEY\n - name: AUTH_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: DATABASE_URL\n value: \"postgres://supabase_storage_admin:$(POSTGRES_PASSWORD)@postgres.${SUPABASE_NAMESPACE}.svc.cluster.local:5432/postgres?search_path=storage&sslmode=disable\"\n - name: POSTGREST_URL\n value: \"http://rest.${SUPABASE_NAMESPACE}.svc.cluster.local:3000\"\n - name: STORAGE_BACKEND\n value: file\n - name: STORAGE_PUBLIC_URL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SUPABASE_PUBLIC_URL\n - name: REQUEST_ALLOW_X_FORWARDED_PATH\n value: \"true\"\n - name: FILE_SIZE_LIMIT\n value: \"52428800\"\n - name: FILE_STORAGE_BACKEND_PATH\n value: /var/lib/storage\n - name: TENANT_ID\n value: stub\n - name: REGION\n value: local\n - name: GLOBAL_S3_BUCKET\n value: local\n - name: IMGPROXY_URL\n value: \"http://imgproxy.${SUPABASE_NAMESPACE}.svc.cluster.local:5001\"\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n - configMapRef:\n name: supabase-runtime-config\n volumeMounts:\n - name: storage\n mountPath: /var/lib/storage\n volumes:\n - name: storage\n persistentVolumeClaim:\n claimName: supabase-storage-data\n`;\n}\n\nfunction getSupabaseImgproxyManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: imgproxy\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-imgproxy\n ports:\n - name: http\n port: 5001\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: imgproxy\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-imgproxy\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-imgproxy\n spec:\n containers:\n - name: imgproxy\n image: ${SUPABASE_IMAGES.imgproxy}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 5001\n name: http\n env:\n - name: IMGPROXY_BIND\n value: \":5001\"\n`;\n}\n\nfunction getSupabaseMetaManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: meta\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-meta\n ports:\n - name: http\n port: 8080\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: meta\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-meta\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-meta\n spec:\n containers:\n - name: meta\n image: ${SUPABASE_IMAGES.meta}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 8080\n name: http\n env:\n - name: PG_META_PORT\n value: \"8080\"\n - name: PG_META_DB_HOST\n value: \"postgres.${SUPABASE_NAMESPACE}.svc.cluster.local\"\n - name: PG_META_DB_PORT\n value: \"5432\"\n - name: PG_META_DB_NAME\n value: postgres\n - name: PG_META_DB_USER\n value: postgres\n - name: PG_META_DB_PASSWORD\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: POSTGRES_PASSWORD\n - name: CRYPTO_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: PG_META_CRYPTO_KEY\n`;\n}\n\nfunction getSupabaseGatewayTemplate(): string {\n return `_format_version: \"2.1\"\n_transform: true\n\nconsumers:\n - username: DASHBOARD\n - username: anon\n keyauth_credentials:\n - key: $SUPABASE_ANON_KEY\n - key: $SUPABASE_PUBLISHABLE_KEY\n - username: service_role\n keyauth_credentials:\n - key: $SUPABASE_SERVICE_KEY\n - key: $SUPABASE_SECRET_KEY\n\nacls:\n - consumer: anon\n group: anon\n - consumer: service_role\n group: admin\n\nbasicauth_credentials:\n - consumer: DASHBOARD\n username: \"$DASHBOARD_USERNAME\"\n password: \"$DASHBOARD_PASSWORD\"\n\nservices:\n - name: auth-v1-open\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/verify\n routes:\n - name: auth-v1-open\n strip_path: true\n paths: [/auth/v1/verify]\n plugins:\n - name: cors\n - name: auth-v1-open-callback\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/callback\n routes:\n - name: auth-v1-open-callback\n strip_path: true\n paths: [/auth/v1/callback]\n plugins:\n - name: cors\n - name: auth-v1-open-authorize\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/authorize\n routes:\n - name: auth-v1-open-authorize\n strip_path: true\n paths: [/auth/v1/authorize]\n plugins:\n - name: cors\n - name: auth-v1-open-jwks\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/.well-known/jwks.json\n routes:\n - name: auth-v1-open-jwks\n strip_path: true\n paths: [/auth/v1/.well-known/jwks.json]\n plugins:\n - name: cors\n - name: auth-v1\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/\n routes:\n - name: auth-v1-all\n strip_path: true\n paths: [/auth/v1/]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: rest-v1\n url: http://rest.${SUPABASE_NAMESPACE}.svc.cluster.local:3000/\n routes:\n - name: rest-v1-all\n strip_path: true\n paths: [/rest/v1/]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: graphql-v1\n url: http://rest.${SUPABASE_NAMESPACE}.svc.cluster.local:3000/rpc/graphql\n routes:\n - name: graphql-v1-all\n strip_path: true\n paths: [/graphql/v1]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"Content-Profile: graphql_public\"\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: realtime-v1-ws\n url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/socket\n protocol: ws\n routes:\n - name: realtime-v1-ws\n strip_path: true\n paths: [/realtime/v1/]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"x-api-key:$LUA_RT_WS_EXPR\"\n replace:\n querystring:\n - \"apikey:$LUA_RT_WS_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: realtime-v1-rest-openapi\n url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/api/openapi\n protocol: http\n routes:\n - name: realtime-v1-rest-openapi\n strip_path: true\n paths: [/realtime/v1/api/openapi]\n plugins:\n - name: request-termination\n config:\n status_code: 403\n message: \"Access is forbidden.\"\n - name: realtime-v1-rest-tenants\n url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/api/tenants\n protocol: http\n routes:\n - name: realtime-v1-rest-tenants\n strip_path: true\n paths: [/realtime/v1/api/tenants]\n plugins:\n - name: request-termination\n config:\n status_code: 403\n message: \"Access is forbidden.\"\n - name: realtime-v1-rest\n url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/api\n protocol: http\n routes:\n - name: realtime-v1-rest\n strip_path: true\n paths: [/realtime/v1/api]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: storage-v1\n url: http://storage.${SUPABASE_NAMESPACE}.svc.cluster.local:5000/\n routes:\n - name: storage-v1-all\n strip_path: true\n paths: [/storage/v1/]\n plugins:\n - name: cors\n - name: request-transformer\n config:\n add:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: post-function\n config:\n access:\n - |\n local auth = kong.request.get_header(\"authorization\")\n if auth == nil or auth == \"\" or auth:find(\"^%s*$\") then\n kong.service.request.clear_header(\"authorization\")\n end\n - name: meta\n url: http://meta.${SUPABASE_NAMESPACE}.svc.cluster.local:8080/\n routes:\n - name: meta-all\n strip_path: true\n paths: [/pg/]\n plugins:\n - name: key-auth\n config:\n hide_credentials: false\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin]\n - name: dashboard\n url: http://studio.${SUPABASE_NAMESPACE}.svc.cluster.local:3000/\n routes:\n - name: dashboard-all\n strip_path: true\n paths: [/]\n plugins:\n - name: cors\n - name: basic-auth\n config:\n hide_credentials: true\n`;\n}\n\nfunction getSupabaseKongEntrypointScript(): string {\n return `#!/bin/sh\nset -eu\n\nif [ -n \"\\${SUPABASE_SECRET_KEY:-}\" ] && [ -n \"\\${SUPABASE_PUBLISHABLE_KEY:-}\" ]; then\n export LUA_AUTH_EXPR=\"\\\\$((headers.authorization ~= nil and headers.authorization:sub(1, 10) ~= 'Bearer sb_' and headers.authorization) or (headers.apikey == '\\${SUPABASE_SECRET_KEY}' and 'Bearer \\${SERVICE_ROLE_KEY_ASYMMETRIC:-}') or (headers.apikey == '\\${SUPABASE_PUBLISHABLE_KEY}' and 'Bearer \\${ANON_KEY_ASYMMETRIC:-}') or headers.apikey)\"\n export LUA_RT_WS_EXPR=\"\\\\$((query_params.apikey == '\\${SUPABASE_SECRET_KEY}' and '\\${SERVICE_ROLE_KEY_ASYMMETRIC:-}') or (query_params.apikey == '\\${SUPABASE_PUBLISHABLE_KEY}' and '\\${ANON_KEY_ASYMMETRIC:-}') or query_params.apikey)\"\nelse\n export LUA_AUTH_EXPR=\"\\\\$((headers.authorization ~= nil and headers.authorization:sub(1, 10) ~= 'Bearer sb_' and headers.authorization) or headers.apikey)\"\n export LUA_RT_WS_EXPR=\"\\\\$(query_params.apikey)\"\nfi\n\nawk '{\n result = \"\"\n rest = $0\n while (match(rest, /\\\\$[A-Za-z_][A-Za-z_0-9]*/)) {\n varname = substr(rest, RSTART + 1, RLENGTH - 1)\n if (varname in ENVIRON) {\n result = result substr(rest, 1, RSTART - 1) ENVIRON[varname]\n } else {\n result = result substr(rest, 1, RSTART + RLENGTH - 1)\n }\n rest = substr(rest, RSTART + RLENGTH)\n }\n print result rest\n}' /home/kong/temp.yml > \"\\${KONG_DECLARATIVE_CONFIG}\"\n\nsed -i '/^[[:space:]]*- key:[[:space:]]*$/d' \"\\${KONG_DECLARATIVE_CONFIG}\"\n\nexec /entrypoint.sh kong docker-start\n`;\n}\n\nfunction getSupabaseGatewayManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: gateway\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-gateway\n ports:\n - name: http\n port: 8000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: gateway\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-gateway\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-gateway\n spec:\n containers:\n - name: gateway\n image: ${SUPABASE_IMAGES.gateway}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 8000\n name: http\n env:\n - name: KONG_DATABASE\n value: \"off\"\n - name: KONG_DECLARATIVE_CONFIG\n value: /usr/local/kong/kong.yml\n - name: KONG_ROUTER_FLAVOR\n value: expressions\n - name: KONG_DNS_ORDER\n value: LAST,A,CNAME\n - name: KONG_DNS_NOT_FOUND_TTL\n value: \"1\"\n - name: KONG_PLUGINS\n value: request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction,post-function\n - name: KONG_PROXY_LISTEN\n value: \"0.0.0.0:8000\"\n - name: SUPABASE_SERVICE_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_SERVICE_ROLE_KEY\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n volumeMounts:\n - name: config\n mountPath: /home/kong/temp.yml\n subPath: temp.yml\n readOnly: true\n - name: entrypoint\n mountPath: /home/kong/kong-entrypoint.sh\n subPath: kong-entrypoint.sh\n readOnly: true\n command: [\"/bin/sh\", \"/home/kong/kong-entrypoint.sh\"]\n readinessProbe:\n exec:\n command: [\"kong\", \"health\"]\n initialDelaySeconds: 10\n periodSeconds: 10\n volumes:\n - name: config\n configMap:\n name: supabase-gateway-config\n - name: entrypoint\n configMap:\n name: supabase-kong-entrypoint\n defaultMode: 0755\n`;\n}\n\nfunction getSupabaseStudioManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: studio\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-studio\n ports:\n - name: http\n port: 3000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: studio\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-studio\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-studio\n spec:\n containers:\n - name: studio\n image: ${SUPABASE_IMAGES.studio}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 3000\n name: http\n env:\n - name: HOSTNAME\n value: \"0.0.0.0\"\n - name: STUDIO_PG_META_URL\n value: \"http://meta.${SUPABASE_NAMESPACE}.svc.cluster.local:8080\"\n - name: SUPABASE_URL\n value: \"http://gateway.${SUPABASE_NAMESPACE}.svc.cluster.local:8000\"\n - name: SUPABASE_PUBLIC_URL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SUPABASE_PUBLIC_URL\n - name: SUPABASE_ANON_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_ANON_KEY\n - name: SUPABASE_SERVICE_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_SERVICE_ROLE_KEY\n - name: AUTH_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n - configMapRef:\n name: supabase-runtime-config\n`;\n}\n\nfunction getUpScript(args: {\n appSlug: string;\n appRuntimeEnabled: boolean;\n defaultAppImage: string;\n supabaseKubernetesEnabled: boolean;\n profileModel: ResolvedProfileModel;\n secretStoreProvider: string;\n supabaseHostPorts: SupabaseHostPorts;\n oauthProviders: readonly SupabaseOAuthProviderRuntime[];\n providerLifecycle: readonly MinikubeProviderLifecycle[];\n}): string {\n const {\n appSlug,\n appRuntimeEnabled,\n defaultAppImage,\n supabaseKubernetesEnabled,\n profileModel,\n secretStoreProvider,\n supabaseHostPorts,\n oauthProviders,\n providerLifecycle,\n } = args;\n const oauthEnvDefaults = getOAuthScriptEnvDefaults(oauthProviders);\n const oauthRuntimeSecretLines = getOAuthRuntimeSecretLines(oauthProviders);\n const oauthValidation = getOAuthRuntimeValidationScript(oauthProviders);\n const oauthCallbackRoute = getSupabaseOAuthCallbackRoute(oauthProviders);\n const providerLifecycleStageScripts = getProviderLifecycleStageScripts(providerLifecycle);\n const oauthVaultResolution = getOAuthVaultResolutionScript({\n appSlug,\n oauthProviders,\n secretStoreProvider,\n });\n const supabaseMigrationCommand = getSupabaseMigrationCommandScript();\n const disabledAppRuntimeReconciliation = appRuntimeEnabled\n ? ''\n : `reconcile_disabled_app_runtime() {\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" delete deployment/app-runtime service/app-runtime configmap/app-infra-config --ignore-not-found\n \"\\${PORT_FORWARD_SCRIPT}\" stop obsolete\n}\n`;\n const reconcileDisabledAppRuntime = appRuntimeEnabled ? '' : 'reconcile_disabled_app_runtime';\n\n return `#!/usr/bin/env bash\nset -Eeuo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nK8S_DIR=\"\\${ROOT_DIR}/k8s\"\nBUILD_SCRIPT=\"\\${SCRIPT_DIR}/build-app-image.sh\"\nPORT_FORWARD_SCRIPT=\"\\${SCRIPT_DIR}/port-forward.sh\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-}\"\nDRIVER=\"\\${MINIKUBE_DRIVER:-}\"\nAPP_NAMESPACE=\"${APP_NAMESPACE}\"\nSUPABASE_NAMESPACE=\"${SUPABASE_NAMESPACE}\"\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nAPP_RUNTIME_ENABLED=\"${appRuntimeEnabled ? 'true' : 'false'}\"\nAPP_BUILD_ENABLED=\"\\${APP_BUILD_ENABLED:-}\"\nAPP_SOURCE_DIR=\"\\${APP_SOURCE_DIR:-}\"\nAPP_WEB_EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR:-}\"\nAPP_IMAGE=\"\\${APP_IMAGE:-}\"\nAPP_IMAGE_SYNC_STRATEGY=\"\\${APP_IMAGE_SYNC_STRATEGY:-}\"\nAPP_REPLICAS=\"\\${APP_REPLICAS:-}\"\nAPP_FORCE_ROLLOUT_RESTART=\"\\${APP_FORCE_ROLLOUT_RESTART:-}\"\nAPP_IMAGE_PULL_SECRET_NAME=\"\\${APP_IMAGE_PULL_SECRET_NAME:-}\"\nAPP_IMAGE_PULL_SECRET_SERVER=\"\\${APP_IMAGE_PULL_SECRET_SERVER:-}\"\nAPP_IMAGE_PULL_SECRET_USERNAME=\"\\${APP_IMAGE_PULL_SECRET_USERNAME:-}\"\nAPP_IMAGE_PULL_SECRET_PASSWORD=\"\\${APP_IMAGE_PULL_SECRET_PASSWORD:-}\"\nAPP_IMAGE_PULL_SECRET_EMAIL=\"\\${APP_IMAGE_PULL_SECRET_EMAIL:-}\"\nAPP_PORT_FORWARD_LOCAL_PORT=\"\\${APP_PORT_FORWARD_LOCAL_PORT:-}\"\nSUPABASE_GATEWAY_FORWARD_LOCAL_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-}\"\nSUPABASE_DB_FORWARD_LOCAL_PORT=\"\\${SUPABASE_DB_FORWARD_LOCAL_PORT:-}\"\nSUPABASE_DB_URL=\"\\${SUPABASE_DB_URL:-}\"\nSUPABASE_PROFILE_ENABLED=\"${profileModel.enabled ? 'true' : 'false'}\"\nSUPABASE_PROFILE_RECONCILE_FILE=\"\\${ROOT_DIR}/supabase/generated/auth_profiles.sql\"\n\nrequire_command() {\n if ! command -v \"\\${1}\" >/dev/null 2>&1; then\n echo \"\\${1} is required but not installed.\"\n exit 1\n fi\n}\n\nload_env_file_preserving_process_env() {\n local line trimmed key value current\n if [[ ! -f \"\\${ROOT_DIR}/.env\" ]]; then\n return 0\n fi\n\n while IFS= read -r line || [[ -n \"\\${line}\" ]]; do\n trimmed=\"$(printf '%s' \"\\${line}\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')\"\n if [[ -z \"\\${trimmed}\" || \"\\${trimmed}\" == \\\\#* || \"\\${trimmed}\" != *=* ]]; then\n continue\n fi\n\n key=\"\\${trimmed%%=*}\"\n value=\"\\${trimmed#*=}\"\n key=\"\\${key//[[:space:]]/}\"\n value=\"$(printf '%s' \"\\${value}\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')\"\n value=\"\\${value%\\\\\"}\"\n value=\"\\${value#\\\\\"}\"\n value=\"\\${value%\\\\'}\"\n value=\"\\${value#\\\\'}\"\n current=\"\\${!key:-}\"\n if [[ -n \"\\${current}\" ]]; then\n continue\n fi\n export \"\\${key}=\\${value}\"\n done < \"\\${ROOT_DIR}/.env\"\n}\n\nenv_file_value() {\n local key=\"\\${1}\"\n if [[ ! -f \"\\${ROOT_DIR}/.env\" ]]; then\n return 0\n fi\n awk -F= -v key=\"\\${key}\" '$1 == key { value = substr($0, index($0, \"=\") + 1) } END { print value }' \"\\${ROOT_DIR}/.env\"\n}\n\nenv_file_has_key() {\n local key=\"\\${1}\"\n if [[ ! -f \"\\${ROOT_DIR}/.env\" ]]; then\n return 1\n fi\n awk -F= -v key=\"\\${key}\" '$1 == key { found = 1 } END { exit found ? 0 : 1 }' \"\\${ROOT_DIR}/.env\"\n}\n\nwrite_env_value() {\n local key=\"\\${1}\"\n local value=\"\\${2}\"\n local tmp_env\n mkdir -p \"\\${ROOT_DIR}\"\n touch \"\\${ROOT_DIR}/.env\"\n tmp_env=\"$(mktemp)\"\n awk -F= -v key=\"\\${key}\" -v value=\"\\${value}\" '\n $1 == key {\n print key \"=\" value\n found = 1\n next\n }\n { print }\n END {\n if (!found) print key \"=\" value\n }\n ' \"\\${ROOT_DIR}/.env\" > \"\\${tmp_env}\"\n mv \"\\${tmp_env}\" \"\\${ROOT_DIR}/.env\"\n}\n\nwrite_key_value_file_value() {\n local file_path=\"\\${1}\"\n local key=\"\\${2}\"\n local value=\"\\${3}\"\n local tmp_env\n mkdir -p \"$(dirname \"\\${file_path}\")\"\n touch \"\\${file_path}\"\n tmp_env=\"$(mktemp)\"\n awk -F= -v key=\"\\${key}\" -v value=\"\\${value}\" '\n $1 == key {\n print key \"=\" value\n found = 1\n next\n }\n { print }\n END {\n if (!found) print key \"=\" value\n }\n ' \"\\${file_path}\" > \"\\${tmp_env}\"\n mv \"\\${tmp_env}\" \"\\${file_path}\"\n}\n\nsync_app_public_supabase_env() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n if [[ -z \"\\${APP_SOURCE_DIR:-}\" ]]; then\n echo \"APP_SOURCE_DIR is required to write app Supabase public environment.\"\n exit 1\n fi\n\n local app_env_file=\"\\${APP_SOURCE_DIR}/.env.local\"\n write_key_value_file_value \"\\${app_env_file}\" \"EXPO_PUBLIC_SUPABASE_URL\" \"\\${EXPO_PUBLIC_SUPABASE_URL}\"\n write_key_value_file_value \"\\${app_env_file}\" \"EXPO_PUBLIC_SUPABASE_ANON_KEY\" \"\\${EXPO_PUBLIC_SUPABASE_ANON_KEY}\"\n}\n\nset_required_env_default() {\n local key=\"\\${1}\"\n local value=\"\\${2}\"\n local current=\"\\${!key:-}\"\n if [[ -n \"\\${current}\" ]]; then\n write_env_value \"\\${key}\" \"\\${current}\"\n return 0\n fi\n\n current=\"$(env_file_value \"\\${key}\")\"\n if [[ -n \"\\${current}\" ]]; then\n export \"\\${key}=\\${current}\"\n return 0\n fi\n\n write_env_value \"\\${key}\" \"\\${value}\"\n export \"\\${key}=\\${value}\"\n}\n\nset_optional_env_default() {\n local key=\"\\${1}\"\n local value=\"\\${2}\"\n local current=\"\\${!key:-}\"\n if env_file_has_key \"\\${key}\"; then\n export \"\\${key}=\\${current}\"\n return 0\n fi\n if [[ -n \"\\${current}\" ]]; then\n write_env_value \"\\${key}\" \"\\${current}\"\n return 0\n fi\n write_env_value \"\\${key}\" \"\\${value}\"\n export \"\\${key}=\\${value}\"\n}\n\nset_env_default() {\n set_required_env_default \"\\${1}\" \"\\${2}\"\n}\n\nderive_additional_redirect_urls() {\n local callback_route=\"${oauthCallbackRoute}\"\n local callback_path=\"\\${callback_route#/}\"\n local site_url_without_slash=\"\\${SITE_URL%/}\"\n local urls=\"\\${site_url_without_slash},\\${site_url_without_slash}/\\${callback_path}\"\n if [[ -n \"\\${OAUTH_NATIVE_REDIRECT_URLS:-}\" ]]; then\n urls=\"\\${urls},\\${OAUTH_NATIVE_REDIRECT_URLS}\"\n fi\n printf '%s' \"\\${urls}\"\n}\n\nrandom_base64() {\n openssl rand -base64 \"\\${1}\" | tr -d '\\\\n'\n}\n\nrandom_hex() {\n openssl rand -hex \"\\${1}\" | tr -d '\\\\n'\n}\n\nbase64url() {\n openssl base64 -A | tr '+/' '-_' | tr -d '='\n}\n\ngenerate_supabase_jwt() {\n local role=\"\\${1}\"\n local iat exp header payload signature\n iat=\"$(date +%s)\"\n exp=\"$((iat + 315360000))\"\n header=\"$(printf '{\"alg\":\"HS256\",\"typ\":\"JWT\"}' | base64url)\"\n payload=\"$(printf '{\"role\":\"%s\",\"iss\":\"supabase-demo\",\"iat\":%s,\"exp\":%s}' \"\\${role}\" \"\\${iat}\" \"\\${exp}\" | base64url)\"\n signature=\"$(printf '%s.%s' \"\\${header}\" \"\\${payload}\" | openssl dgst -binary -sha256 -hmac \"\\${JWT_SECRET}\" | base64url)\"\n printf '%s.%s.%s' \"\\${header}\" \"\\${payload}\" \"\\${signature}\"\n}\n\nensure_supabase_runtime_env() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n require_command openssl\n\n set_required_env_default POSTGRES_PASSWORD \"$(random_hex 32)\"\n set_required_env_default JWT_SECRET \"$(random_base64 48)\"\n set_required_env_default SUPABASE_ANON_KEY \"$(generate_supabase_jwt anon)\"\n set_required_env_default SUPABASE_SERVICE_ROLE_KEY \"$(generate_supabase_jwt service_role)\"\n set_required_env_default DASHBOARD_USERNAME \"supabase\"\n set_required_env_default DASHBOARD_PASSWORD \"$(random_base64 24)\"\n set_required_env_default SECRET_KEY_BASE \"$(random_base64 48)\"\n set_required_env_default REALTIME_DB_ENC_KEY \"$(random_hex 8)\"\n set_required_env_default PG_META_CRYPTO_KEY \"$(random_base64 32)\"\n set_required_env_default S3_PROTOCOL_ACCESS_KEY_ID \"$(random_hex 16)\"\n set_required_env_default S3_PROTOCOL_ACCESS_KEY_SECRET \"$(random_hex 32)\"\n set_required_env_default JWT_EXPIRY \"3600\"\n set_required_env_default SUPABASE_GATEWAY_FORWARD_LOCAL_PORT \"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}\"\n set_required_env_default APP_PORT_FORWARD_LOCAL_PORT \"\\${APP_PORT_FORWARD_LOCAL_PORT:-${supabaseHostPorts.app}}\"\n set_required_env_default SUPABASE_PUBLIC_URL \"http://127.0.0.1:\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT}\"\n set_required_env_default API_EXTERNAL_URL \"\\${SUPABASE_PUBLIC_URL}/auth/v1\"\n set_required_env_default SITE_URL \"http://127.0.0.1:\\${APP_PORT_FORWARD_LOCAL_PORT}\"\n export OAUTH_NATIVE_REDIRECT_URLS=\"\\${OAUTH_NATIVE_REDIRECT_URLS:-}\"\n set_required_env_default ADDITIONAL_REDIRECT_URLS \"$(derive_additional_redirect_urls)\"\n set_required_env_default ENABLE_EMAIL_SIGNUP \"true\"\n set_required_env_default ENABLE_EMAIL_AUTOCONFIRM \"true\"\n set_required_env_default SMTP_ADMIN_EMAIL \"admin@example.com\"\n set_required_env_default SMTP_HOST \"localhost\"\n set_required_env_default SMTP_PORT \"2500\"\n set_optional_env_default SMTP_USER \"\"\n set_optional_env_default SMTP_PASS \"\"\n set_required_env_default SMTP_SENDER_NAME \"Ankhorage\"\n set_required_env_default PGRST_DB_SCHEMAS \"public,storage,graphql_public\"\n set_required_env_default PGRST_DB_MAX_ROWS \"1000\"\n set_required_env_default PGRST_DB_EXTRA_SEARCH_PATH \"public\"\n set_required_env_default GLOBAL_S3_BUCKET \"stub\"\n set_required_env_default STORAGE_TENANT_ID \"stub\"\n set_required_env_default REGION \"stub\"\n set_required_env_default SUPABASE_DB_FORWARD_LOCAL_PORT \"\\${SUPABASE_DB_FORWARD_LOCAL_PORT:-${supabaseHostPorts.db}}\"\n set_required_env_default SUPABASE_DB_URL \"postgres://postgres:\\${POSTGRES_PASSWORD}@127.0.0.1:\\${SUPABASE_DB_FORWARD_LOCAL_PORT}/postgres?sslmode=disable\"\n set_required_env_default EXPO_PUBLIC_SUPABASE_URL \"\\${SUPABASE_PUBLIC_URL}\"\n set_required_env_default EXPO_PUBLIC_SUPABASE_ANON_KEY \"\\${SUPABASE_ANON_KEY}\"\n${oauthEnvDefaults}\n}\n${oauthVaultResolution}\n\nsync_supabase_secrets() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n local tmp_runtime tmp_public\n tmp_runtime=\"$(mktemp)\"\n tmp_public=\"$(mktemp)\"\n trap 'rm -f \"\\${tmp_runtime}\" \"\\${tmp_public}\"' EXIT\n\n cat > \"\\${tmp_runtime}\" <<EOF\nPOSTGRES_PASSWORD=\\${POSTGRES_PASSWORD}\nJWT_SECRET=\\${JWT_SECRET}\nSUPABASE_ANON_KEY=\\${SUPABASE_ANON_KEY}\nSUPABASE_SERVICE_ROLE_KEY=\\${SUPABASE_SERVICE_ROLE_KEY}\nSUPABASE_PUBLISHABLE_KEY=\\${SUPABASE_PUBLISHABLE_KEY:-}\nSUPABASE_SECRET_KEY=\\${SUPABASE_SECRET_KEY:-}\nDASHBOARD_USERNAME=\\${DASHBOARD_USERNAME:-supabase}\nDASHBOARD_PASSWORD=\\${DASHBOARD_PASSWORD:-}\nSMTP_USER=\\${SMTP_USER:-}\nSMTP_PASS=\\${SMTP_PASS:-}\nSECRET_KEY_BASE=\\${SECRET_KEY_BASE}\nREALTIME_DB_ENC_KEY=\\${REALTIME_DB_ENC_KEY}\nPG_META_CRYPTO_KEY=\\${PG_META_CRYPTO_KEY}\nS3_PROTOCOL_ACCESS_KEY_ID=\\${S3_PROTOCOL_ACCESS_KEY_ID}\nS3_PROTOCOL_ACCESS_KEY_SECRET=\\${S3_PROTOCOL_ACCESS_KEY_SECRET}\n${oauthRuntimeSecretLines}\nEOF\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" create secret generic supabase-runtime-secrets --from-env-file=\"\\${tmp_runtime}\" --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" apply -f -\n\n cat > \"\\${tmp_public}\" <<EOF\nEXPO_PUBLIC_SUPABASE_URL=\\${EXPO_PUBLIC_SUPABASE_URL}\nEXPO_PUBLIC_SUPABASE_ANON_KEY=\\${EXPO_PUBLIC_SUPABASE_ANON_KEY}\nSUPABASE_URL=http://gateway.${SUPABASE_NAMESPACE}.svc.cluster.local:8000\nSUPABASE_ANON_KEY=\\${SUPABASE_ANON_KEY}\nEOF\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" create secret generic supabase-public-runtime --from-env-file=\"\\${tmp_public}\" --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" apply -f -\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" create configmap supabase-runtime-config \\\n --from-literal=SUPABASE_PUBLIC_URL=\"\\${SUPABASE_PUBLIC_URL}\" \\\n --from-literal=API_EXTERNAL_URL=\"\\${API_EXTERNAL_URL}\" \\\n --from-literal=SITE_URL=\"\\${SITE_URL}\" \\\n --from-literal=ADDITIONAL_REDIRECT_URLS=\"\\${ADDITIONAL_REDIRECT_URLS}\" \\\n --from-literal=JWT_EXPIRY=\"\\${JWT_EXPIRY}\" \\\n --from-literal=ENABLE_EMAIL_SIGNUP=\"\\${ENABLE_EMAIL_SIGNUP}\" \\\n --from-literal=ENABLE_EMAIL_AUTOCONFIRM=\"\\${ENABLE_EMAIL_AUTOCONFIRM}\" \\\n --from-literal=SMTP_ADMIN_EMAIL=\"\\${SMTP_ADMIN_EMAIL}\" \\\n --from-literal=SMTP_HOST=\"\\${SMTP_HOST}\" \\\n --from-literal=SMTP_PORT=\"\\${SMTP_PORT}\" \\\n --from-literal=SMTP_SENDER_NAME=\"\\${SMTP_SENDER_NAME}\" \\\n --from-literal=PGRST_DB_SCHEMAS=\"\\${PGRST_DB_SCHEMAS}\" \\\n --from-literal=PGRST_DB_MAX_ROWS=\"\\${PGRST_DB_MAX_ROWS}\" \\\n --from-literal=PGRST_DB_EXTRA_SEARCH_PATH=\"\\${PGRST_DB_EXTRA_SEARCH_PATH}\" \\\n --from-literal=GLOBAL_S3_BUCKET=\"\\${GLOBAL_S3_BUCKET}\" \\\n --from-literal=STORAGE_TENANT_ID=\"\\${STORAGE_TENANT_ID}\" \\\n --from-literal=REGION=\"\\${REGION}\" \\\n --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" apply -f -\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" create configmap supabase-gateway-config \\\n --from-file=temp.yml=\"\\${K8S_DIR}/supabase/gateway.template.yml\" \\\n --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" apply -f -\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" create configmap supabase-kong-entrypoint \\\n --from-file=kong-entrypoint.sh=\"\\${K8S_DIR}/supabase/kong-entrypoint.sh\" \\\n --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" apply -f -\n\n rm -f \"\\${tmp_runtime}\" \"\\${tmp_public}\"\n trap - EXIT\n}\n\ndocker_load_image_to_minikube() {\n if command -v docker >/dev/null 2>&1 && docker image inspect \"\\${APP_IMAGE}\" >/dev/null 2>&1; then\n minikube -p \"\\${PROFILE}\" image load --daemon=true --overwrite=true \"\\${APP_IMAGE}\" >/dev/null\n return 0\n fi\n\n return 1\n}\n\nrun_supabase_migrations() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n export SUPABASE_DB_URL PGSSLMODE=disable\n\n if [[ -d \"\\${ROOT_DIR}/supabase/migrations\" ]]; then\n require_command supabase\n (\n cd \"\\${ROOT_DIR}\"\n${indentShellBlock(supabaseMigrationCommand, 6)}\n )\n fi\n}\n\nreconcile_supabase_profile() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n if [[ \"\\${SUPABASE_PROFILE_ENABLED}\" == \"true\" && -f \"\\${SUPABASE_PROFILE_RECONCILE_FILE}\" ]]; then\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -q -f \"\\${SUPABASE_PROFILE_RECONCILE_FILE}\"\n fi\n}\n\nreload_postgrest_schema() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -q -c \"notify pgrst, 'reload schema';\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout restart deployment/rest >/dev/null\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/rest --timeout=600s\n}\n\nbootstrap_supabase_vault_migration() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n if [[ -f \"\\${ROOT_DIR}/supabase/migrations/202607120001_ankhorage_supabase_vault.sql\" ]]; then\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" exec deployment/postgres -- psql -U postgres -d postgres -v ON_ERROR_STOP=1 -q -c \"alter role postgres with superuser;\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" exec deployment/postgres -- psql -U postgres -d postgres -v ON_ERROR_STOP=1 -q -c \"create schema if not exists vault; grant pg_read_server_files to postgres; grant pg_read_server_files to supabase_admin; grant execute on function pg_read_file(text) to public; grant execute on function pg_read_file(text, bigint, bigint) to public;\"\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -q -f \"\\${ROOT_DIR}/supabase/migrations/202607120001_ankhorage_supabase_vault.sql\"\n fi\n}\n\nbootstrap_supabase_database() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n require_command psql\n export POSTGRES_PASSWORD JWT_SECRET JWT_EXP=\"\\${JWT_EXPIRY}\" POSTGRES_USER=postgres\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -q -f \"\\${K8S_DIR}/supabase/bootstrap.sql\"\n}\n\nwait_for_supabase_database() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n require_command psql\n if ! \"\\${PORT_FORWARD_SCRIPT}\" start db-migration; then\n echo \"Failed to start db-migration port-forward for Supabase bootstrap.\"\n \"\\${PORT_FORWARD_SCRIPT}\" status db-migration || true\n exit 1\n fi\n for attempt in {1..60}; do\n if PGPASSWORD=\"\\${POSTGRES_PASSWORD}\" psql -h 127.0.0.1 -p \"\\${SUPABASE_DB_FORWARD_LOCAL_PORT}\" -U postgres -d postgres -v ON_ERROR_STOP=1 -Atq -c 'select 1' >/dev/null 2>&1; then\n return 0\n fi\n sleep 2\n done\n\n echo \"Postgres did not accept SQL connections as postgres before bootstrap.\"\n \"\\${PORT_FORWARD_SCRIPT}\" status db-migration || true\n exit 1\n}\n\napply_supabase_runtime_workloads() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/auth.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/rest.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/realtime.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/imgproxy.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/storage.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/meta.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/gateway.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/studio.yaml\"\n}\n\napply_namespace_manifests() {\n local namespace_manifest\n for namespace_manifest in \"\\${K8S_DIR}\"/namespaces/*.yaml; do\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${namespace_manifest}\"\n done\n}\n\n${disabledAppRuntimeReconciliation}\n${providerLifecycleStageScripts}\n\nload_env_file_preserving_process_env\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nDRIVER=\"\\${MINIKUBE_DRIVER:-docker}\"\nAPP_BUILD_ENABLED=\"\\${APP_BUILD_ENABLED:-true}\"\nAPP_SOURCE_DIR=\"\\${APP_SOURCE_DIR:-$(cd \"\\${ROOT_DIR}/../..\" && pwd)}\"\nAPP_WEB_EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR:-.ankh/web-export}\"\nAPP_IMAGE=\"\\${APP_IMAGE:-${defaultAppImage}}\"\nAPP_IMAGE_SYNC_STRATEGY=\"\\${APP_IMAGE_SYNC_STRATEGY:-docker-load}\"\nAPP_REPLICAS=\"\\${APP_REPLICAS:-1}\"\nAPP_FORCE_ROLLOUT_RESTART=\"\\${APP_FORCE_ROLLOUT_RESTART:-true}\"\nAPP_IMAGE_PULL_SECRET_NAME=\"\\${APP_IMAGE_PULL_SECRET_NAME:-}\"\nAPP_IMAGE_PULL_SECRET_SERVER=\"\\${APP_IMAGE_PULL_SECRET_SERVER:-ghcr.io}\"\nAPP_IMAGE_PULL_SECRET_USERNAME=\"\\${APP_IMAGE_PULL_SECRET_USERNAME:-}\"\nAPP_IMAGE_PULL_SECRET_PASSWORD=\"\\${APP_IMAGE_PULL_SECRET_PASSWORD:-}\"\nAPP_IMAGE_PULL_SECRET_EMAIL=\"\\${APP_IMAGE_PULL_SECRET_EMAIL:-}\"\nAPP_PORT_FORWARD_LOCAL_PORT=\"\\${APP_PORT_FORWARD_LOCAL_PORT:-${supabaseHostPorts.app}}\"\nSUPABASE_GATEWAY_FORWARD_LOCAL_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}\"\nSUPABASE_DB_FORWARD_LOCAL_PORT=\"\\${SUPABASE_DB_FORWARD_LOCAL_PORT:-${supabaseHostPorts.db}}\"\nSUPABASE_DB_URL=\"\\${SUPABASE_DB_URL:-}\"\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\ncleanup_failed_up() {\n \"\\${PORT_FORWARD_SCRIPT}\" stop all >/dev/null 2>&1 || true\n}\n\ntrap cleanup_failed_up ERR\n\nrequire_command minikube\nrequire_command kubectl\nensure_supabase_runtime_env\nsync_app_public_supabase_env\n\nHOST_STATUS=\"$(minikube -p \"\\${PROFILE}\" status --format='{{.Host}}' 2>/dev/null || true)\"\nif [[ \"\\${HOST_STATUS}\" != \"Running\" ]]; then\n minikube start -p \"\\${PROFILE}\" --driver=\"\\${DRIVER}\"\nfi\n\nif [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" == \"true\" ]]; then\n apply_namespace_manifests\n sync_supabase_secrets\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/postgres.init.configmap.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/postgres.pvc.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/postgres.yaml\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/postgres --timeout=900s\n wait_for_supabase_database\n bootstrap_supabase_database\n bootstrap_supabase_vault_migration\n resolve_oauth_credentials_from_vault\n${oauthValidation}\n sync_supabase_secrets\n apply_supabase_runtime_workloads\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/auth --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/rest --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/realtime --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/storage --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/gateway --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/studio --timeout=600s\n run_supabase_migrations\n reconcile_supabase_profile\n reload_postgrest_schema\n \"\\${PORT_FORWARD_SCRIPT}\" start supabase-gateway >/dev/null\n \"\\${PORT_FORWARD_SCRIPT}\" start studio >/dev/null\nelse\n kubectl --context \"\\${PROFILE}\" apply -k \"\\${K8S_DIR}\"\nfi\n\nif [[ \"\\${APP_RUNTIME_ENABLED}\" == \"true\" && \"\\${APP_BUILD_ENABLED}\" == \"true\" ]]; then\n if [[ ! -x \"\\${BUILD_SCRIPT}\" ]]; then\n echo \"Missing build helper script: \\${BUILD_SCRIPT}\"\n exit 1\n fi\n\n \"\\${BUILD_SCRIPT}\"\nfi\n\nif [[ \"\\${APP_WEB_EXPORT_DIR}\" = /* ]]; then\n EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR}\"\nelse\n EXPORT_DIR=\"\\${APP_SOURCE_DIR}/\\${APP_WEB_EXPORT_DIR}\"\nfi\n\nif [[ \"\\${APP_RUNTIME_ENABLED}\" == \"true\" ]]; then\ncase \"\\${APP_IMAGE_SYNC_STRATEGY}\" in\n minikube-build)\n if [[ ! -f \"\\${EXPORT_DIR}/index.html\" ]]; then\n echo \"Expected web export output not found at \\${EXPORT_DIR}/index.html\"\n exit 1\n fi\n minikube -p \"\\${PROFILE}\" image build -t \"\\${APP_IMAGE}\" -f \"\\${ROOT_DIR}/app-image/Dockerfile\" \"\\${EXPORT_DIR}\" >/dev/null\n ;;\n docker-load)\n if ! docker_load_image_to_minikube; then\n echo \"Skipping docker-load image sync; local Docker image \\${APP_IMAGE} not found.\"\n fi\n ;;\n none)\n echo \"Skipping local image sync (APP_IMAGE_SYNC_STRATEGY=none).\"\n ;;\n *)\n echo \"Unsupported APP_IMAGE_SYNC_STRATEGY=\\${APP_IMAGE_SYNC_STRATEGY}. Use minikube-build, docker-load, or none.\"\n exit 1\n ;;\nesac\nfi\n\nif [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" == \"true\" ]]; then\n kubectl --context \"\\${PROFILE}\" apply -k \"\\${K8S_DIR}\"\nfi\n\n${reconcileDisabledAppRuntime}\nwait_for_provider_readiness\nrun_provider_migrations\nrun_provider_reconciliation\n\nif [[ \"\\${APP_RUNTIME_ENABLED}\" == \"true\" ]]; then\nif [[ -n \"\\${APP_IMAGE_PULL_SECRET_NAME}\" ]]; then\n if [[ -z \"\\${APP_IMAGE_PULL_SECRET_USERNAME}\" || -z \"\\${APP_IMAGE_PULL_SECRET_PASSWORD}\" ]]; then\n echo \"APP_IMAGE_PULL_SECRET_NAME is set, but username/password are missing.\"\n exit 1\n fi\n\n SECRET_EMAIL_ARG=()\n if [[ -n \"\\${APP_IMAGE_PULL_SECRET_EMAIL}\" ]]; then\n SECRET_EMAIL_ARG=(--docker-email=\"\\${APP_IMAGE_PULL_SECRET_EMAIL}\")\n fi\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" create secret docker-registry \"\\${APP_IMAGE_PULL_SECRET_NAME}\" --docker-server=\"\\${APP_IMAGE_PULL_SECRET_SERVER}\" --docker-username=\"\\${APP_IMAGE_PULL_SECRET_USERNAME}\" --docker-password=\"\\${APP_IMAGE_PULL_SECRET_PASSWORD}\" \"\\${SECRET_EMAIL_ARG[@]}\" --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" apply -f -\n\n PULL_SECRET_PATCH=\"$(cat <<EOF\n{\"spec\":{\"template\":{\"spec\":{\"imagePullSecrets\":[{\"name\":\"\\${APP_IMAGE_PULL_SECRET_NAME}\"}]}}}}\nEOF\n)\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" patch deployment app-runtime --type=merge --patch \"\\${PULL_SECRET_PATCH}\" >/dev/null\nelse\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" patch deployment app-runtime --type=json --patch='[{\"op\":\"remove\",\"path\":\"/spec/template/spec/imagePullSecrets\"}]' >/dev/null 2>&1 || true\nfi\n\nkubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" set image deployment/app-runtime app=\"\\${APP_IMAGE}\" >/dev/null\nkubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" scale deployment/app-runtime --replicas=\"\\${APP_REPLICAS}\" >/dev/null\n\nif [[ \"\\${APP_FORCE_ROLLOUT_RESTART}\" == \"true\" ]]; then\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" rollout restart deployment/app-runtime >/dev/null\nfi\n\nkubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" rollout status deployment/app-runtime --timeout=180s >/dev/null\n\"\\${PORT_FORWARD_SCRIPT}\" start app >/dev/null\nfi\n\ntrap - ERR\necho \"Minikube infrastructure for '\\${PROFILE}' is running.\"\n`;\n}\n\nfunction getBuildAppImageScript(args: { appSlug: string; defaultAppImage: string }): string {\n const { appSlug, defaultAppImage } = args;\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nDOCKERFILE_PATH=\"\\${ROOT_DIR}/app-image/Dockerfile\"\nAPP_SLUG=\"${appSlug}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\n\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nAPP_BUILD_ENABLED=\"\\${APP_BUILD_ENABLED:-true}\"\nAPP_SOURCE_DIR=\"\\${APP_SOURCE_DIR:-$(cd \"\\${ROOT_DIR}/../..\" && pwd)}\"\nAPP_WEB_EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR:-.ankh/web-export}\"\nAPP_IMAGE=\"\\${APP_IMAGE:-${defaultAppImage}}\"\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\nif [[ \"\\${APP_BUILD_ENABLED}\" != \"true\" ]]; then\n echo \"Skipping app image build (APP_BUILD_ENABLED=\\${APP_BUILD_ENABLED}).\"\n exit 0\nfi\n\nif ! command -v docker >/dev/null 2>&1; then\n echo \"docker is required to build app image.\"\n exit 1\nfi\n\nif ! command -v bunx >/dev/null 2>&1; then\n echo \"bunx is required to export the app for container image build.\"\n exit 1\nfi\n\nif [[ ! -f \"\\${APP_SOURCE_DIR}/package.json\" ]]; then\n echo \"APP_SOURCE_DIR does not look like an app root: \\${APP_SOURCE_DIR}\"\n exit 1\nfi\n\nif [[ ! -f \"\\${DOCKERFILE_PATH}\" ]]; then\n echo \"Dockerfile for app image build is missing: \\${DOCKERFILE_PATH}\"\n exit 1\nfi\n\n(\n cd \"\\${APP_SOURCE_DIR}\"\n bunx expo export --platform web --clear --output-dir \"\\${APP_WEB_EXPORT_DIR}\"\n)\n\nif [[ \"\\${APP_WEB_EXPORT_DIR}\" = /* ]]; then\n EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR}\"\nelse\n EXPORT_DIR=\"\\${APP_SOURCE_DIR}/\\${APP_WEB_EXPORT_DIR}\"\nfi\n\nif [[ ! -f \"\\${EXPORT_DIR}/index.html\" ]]; then\n echo \"Expected web export output not found at \\${EXPORT_DIR}/index.html\"\n exit 1\nfi\n\ndocker build -t \"\\${APP_IMAGE}\" \\\n --label \"ankhorage.kind=generated-app\" \\\n --label \"ankhorage.app_slug=\\${PROFILE}\" \\\n --label \"ankhorage.image=\\${APP_IMAGE}\" \\\n -f \"\\${DOCKERFILE_PATH}\" \\\n \"\\${EXPORT_DIR}\"\necho \"Built app image: \\${APP_IMAGE} (profile: \\${PROFILE})\"\n`;\n}\n\nfunction getAppImageDockerfile(): string {\n return `FROM nginx:1.27-alpine\n\nRUN cat <<'EOF' > /etc/nginx/conf.d/default.conf\nserver {\n listen 8080;\n absolute_redirect off;\n server_name _;\n root /usr/share/nginx/html;\n index index.html;\n\n location / {\n try_files $uri $uri/ /index.html;\n }\n}\nEOF\n\nCOPY . /usr/share/nginx/html\n\nEXPOSE 8080\n\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n`;\n}\n\nfunction getPortForwardScript(args: {\n appSlug: string;\n appRuntimeEnabled: boolean;\n supabaseKubernetesEnabled: boolean;\n supabaseHostPorts: SupabaseHostPorts;\n}): string {\n const { appSlug, appRuntimeEnabled, supabaseKubernetesEnabled, supabaseHostPorts } = args;\n const runtimeForwardNames = [\n ...(appRuntimeEnabled ? ['app'] : []),\n ...(supabaseKubernetesEnabled ? ['supabase-gateway'] : []),\n ];\n const allForwardNames = [\n ...runtimeForwardNames,\n ...(supabaseKubernetesEnabled ? ['studio', 'db-migration'] : []),\n ];\n const managedForwardNames = ['app', 'supabase-gateway', 'studio', 'db-migration'];\n const obsoleteForwardNames = managedForwardNames.filter(\n (name) => !allForwardNames.includes(name),\n );\n const appTargetCase = ` app)\n echo \"${APP_NAMESPACE} service/app-runtime \\${APP_PORT_FORWARD_LOCAL_PORT} \\${APP_PORT_FORWARD_REMOTE_PORT}\"\n ;;`;\n const supabaseTargetCases = ` supabase-gateway)\n echo \"${SUPABASE_NAMESPACE} service/gateway \\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT} \\${SUPABASE_GATEWAY_FORWARD_REMOTE_PORT}\"\n ;;\n studio)\n echo \"${SUPABASE_NAMESPACE} service/studio \\${SUPABASE_STUDIO_FORWARD_LOCAL_PORT} \\${SUPABASE_STUDIO_FORWARD_REMOTE_PORT}\"\n ;;\n db-migration)\n echo \"${SUPABASE_NAMESPACE} service/postgres \\${SUPABASE_DB_FORWARD_LOCAL_PORT} \\${SUPABASE_DB_FORWARD_REMOTE_PORT}\"\n ;;`;\n const concreteForwardNames = [\n ...(appRuntimeEnabled ? ['app'] : []),\n ...(supabaseKubernetesEnabled ? ['supabase-gateway', 'studio', 'db-migration'] : []),\n ];\n const forwardUsage = [...concreteForwardNames, 'runtime', 'all'].join('|');\n const forwardNamesDescription =\n concreteForwardNames.length > 0\n ? `${concreteForwardNames.join(', ')}, runtime, or all`\n : 'runtime or all';\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nSTATE_DIR=\"\\${ROOT_DIR}/.state/forwards\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nAPP_RUNTIME_ENABLED=\"${appRuntimeEnabled ? 'true' : 'false'}\"\nAPP_PORT_FORWARD_LOCAL_PORT=\"\\${APP_PORT_FORWARD_LOCAL_PORT:-${supabaseHostPorts.app}}\"\nAPP_PORT_FORWARD_REMOTE_PORT=\"\\${APP_PORT_FORWARD_REMOTE_PORT:-80}\"\nSUPABASE_GATEWAY_FORWARD_LOCAL_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}\"\nSUPABASE_GATEWAY_FORWARD_REMOTE_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_REMOTE_PORT:-8000}\"\nSUPABASE_STUDIO_FORWARD_LOCAL_PORT=\"\\${SUPABASE_STUDIO_FORWARD_LOCAL_PORT:-${supabaseHostPorts.studio}}\"\nSUPABASE_STUDIO_FORWARD_REMOTE_PORT=\"\\${SUPABASE_STUDIO_FORWARD_REMOTE_PORT:-3000}\"\nSUPABASE_DB_FORWARD_LOCAL_PORT=\"\\${SUPABASE_DB_FORWARD_LOCAL_PORT:-${supabaseHostPorts.db}}\"\nSUPABASE_DB_FORWARD_REMOTE_PORT=\"\\${SUPABASE_DB_FORWARD_REMOTE_PORT:-5432}\"\nRUNTIME_FORWARD_NAMES=(${runtimeForwardNames.join(' ')})\nALL_FORWARD_NAMES=(${allForwardNames.join(' ')})\nMANAGED_FORWARD_NAMES=(${managedForwardNames.join(' ')})\nOBSOLETE_FORWARD_NAMES=(${obsoleteForwardNames.join(' ')})\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nAPP_RUNTIME_ENABLED=\"${appRuntimeEnabled ? 'true' : 'false'}\"\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\nif ! command -v kubectl >/dev/null 2>&1; then\n echo \"kubectl is required but not installed.\"\n exit 1\nfi\n\nmkdir -p \"\\${STATE_DIR}\"\n\npid_file_for() {\n echo \"\\${STATE_DIR}/\\${PROFILE}-\\${1}.pid\"\n}\n\ntarget_for() {\n case \"\\${1}\" in\n${appTargetCase}\n${supabaseTargetCases}\n *)\n echo \"Unknown forward '\\${1}'. Use ${forwardNamesDescription}.\" >&2\n return 1\n ;;\n esac\n}\n\nis_pid_running() {\n local pid=\"\\${1}\"\n [[ -n \"\\${pid}\" ]] && kill -0 \"\\${pid}\" >/dev/null 2>&1\n}\n\nis_port_accepting() {\n local port=\"\\${1}\"\n (echo >/dev/tcp/127.0.0.1/\"\\${port}\") >/dev/null 2>&1\n}\n\nprint_forward_log_tail() {\n local name=\"\\${1}\"\n local log_file=\"\\${STATE_DIR}/\\${PROFILE}-\\${name}.log\"\n if [[ -s \"\\${log_file}\" ]]; then\n echo \"\\${name}: recent kubectl port-forward log:\"\n tail -n 20 \"\\${log_file}\"\n fi\n}\n\nprocess_command_for_pid() {\n local pid=\"\\${1}\"\n ps -p \"\\${pid}\" -o command= 2>/dev/null || true\n}\n\nprocess_name_for_pid() {\n local pid=\"\\${1}\"\n ps -p \"\\${pid}\" -o comm= 2>/dev/null || true\n}\n\nis_owned_forward_process() {\n local pid=\"\\${1}\"\n local namespace=\"\\${2}\"\n local resource=\"\\${3}\"\n local local_port=\"\\${4}\"\n local remote_port=\"\\${5}\"\n local command\n local process_name\n command=\"$(process_command_for_pid \"\\${pid}\")\"\n process_name=\"$(process_name_for_pid \"\\${pid}\")\"\n\n case \"\\${process_name}\" in\n *kubectl) ;;\n *) return 1 ;;\n esac\n\n case \"\\${command}\" in\n *\"kubectl --context \\${PROFILE} -n \\${namespace} port-forward \\${resource} \\${local_port}:\\${remote_port}\"*)\n return 0\n ;;\n *)\n return 1\n ;;\n esac\n}\n\nhandle_non_owned_forward_pid() {\n local name=\"\\${1}\"\n local pid=\"\\${2}\"\n local pid_file=\"\\${3}\"\n local local_port=\"\\${4}\"\n echo \"\\${name}: stale pid file pointed at non-owned live pid \\${pid}; removing ownership record \\${pid_file}\"\n rm -f \"\\${pid_file}\"\n\n if is_port_accepting \"\\${local_port}\"; then\n echo \"\\${name}: port occupied by non-owned process on local port \\${local_port}\"\n return 1\n fi\n\n return 0\n}\n\nterminate_forward_process() {\n local name=\"\\${1}\"\n local pid=\"\\${2}\"\n local namespace=\"\\${3}\"\n local resource=\"\\${4}\"\n local local_port=\"\\${5}\"\n local remote_port=\"\\${6}\"\n\n if [[ -z \"\\${pid}\" ]]; then\n return 0\n fi\n\n if is_pid_running \"\\${pid}\" && ! is_owned_forward_process \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\"; then\n echo \"\\${name}: refusing to terminate non-owned live pid \\${pid}\"\n return 1\n fi\n\n if is_pid_running \"\\${pid}\"; then\n kill \"\\${pid}\" >/dev/null 2>&1 || true\n for attempt in {1..20}; do\n if ! is_pid_running \"\\${pid}\"; then\n break\n fi\n sleep 0.25\n done\n fi\n\n if is_pid_running \"\\${pid}\"; then\n kill -KILL \"\\${pid}\" >/dev/null 2>&1 || true\n for attempt in {1..20}; do\n if ! is_pid_running \"\\${pid}\"; then\n break\n fi\n sleep 0.25\n done\n fi\n\n if is_pid_running \"\\${pid}\"; then\n echo \"\\${name}: failed to stop owned port-forward pid \\${pid}\"\n return 1\n fi\n\n for attempt in {1..20}; do\n if ! is_port_accepting \"\\${local_port}\"; then\n return 0\n fi\n sleep 0.25\n done\n\n echo \"\\${name}: owned port-forward pid \\${pid} stopped, but local port \\${local_port} is still accepting connections\"\n return 1\n}\n\nstart_forward() {\n local name=\"\\${1}\"\n local pid_file\n pid_file=\"$(pid_file_for \"\\${name}\")\"\n read -r namespace resource local_port remote_port <<<\"$(target_for \"\\${name}\")\"\n\n if [[ \"\\${name}\" == \"app\" && \"\\${APP_RUNTIME_ENABLED}\" != \"true\" ]]; then\n echo \"\\${name}: skipped (Web app runtime disabled)\"\n return 0\n fi\n\n if [[ -f \"\\${pid_file}\" ]]; then\n local existing_pid\n existing_pid=\"$(cat \"\\${pid_file}\")\"\n if is_pid_running \"\\${existing_pid}\"; then\n if ! is_owned_forward_process \"\\${existing_pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\"; then\n handle_non_owned_forward_pid \"\\${name}\" \"\\${existing_pid}\" \"\\${pid_file}\" \"\\${local_port}\" || return 1\n elif is_port_accepting \"\\${local_port}\"; then\n echo \"\\${name}: running (pid \\${existing_pid})\"\n return 0\n else\n echo \"\\${name}: stale running pid \\${existing_pid} was not accepting local port \\${local_port}; restarting\"\n terminate_forward_process \"\\${name}\" \"\\${existing_pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\" || return 1\n rm -f \"\\${pid_file}\"\n fi\n else\n rm -f \"\\${pid_file}\"\n fi\n fi\n\n if [[ \"\\${namespace}\" == \"${SUPABASE_NAMESPACE}\" && \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n echo \"\\${name}: skipped (Supabase Kubernetes disabled)\"\n return 0\n fi\n\n if ! kubectl --context \"\\${PROFILE}\" -n \"\\${namespace}\" get \"\\${resource}\" >/dev/null 2>&1; then\n echo \"\\${name}: target \\${namespace}/\\${resource} not found\"\n return 1\n fi\n\n for start_attempt in {1..5}; do\n nohup kubectl --context \"\\${PROFILE}\" -n \"\\${namespace}\" port-forward \"\\${resource}\" \"\\${local_port}:\\${remote_port}\" >\"\\${STATE_DIR}/\\${PROFILE}-\\${name}.log\" 2>&1 &\n local pid=\"$!\"\n echo \"\\${pid}\" > \"\\${pid_file}\"\n\n for readiness_attempt in {1..20}; do\n if ! is_pid_running \"\\${pid}\"; then\n rm -f \"\\${pid_file}\"\n if [[ \"\\${start_attempt}\" -lt 5 ]]; then\n echo \"\\${name}: port-forward attempt \\${start_attempt} exited before readiness; retrying\"\n sleep 2\n break\n fi\n\n echo \"\\${name}: failed to start local port \\${local_port} for \\${namespace}/\\${resource}:\\${remote_port} after \\${start_attempt} attempts\"\n print_forward_log_tail \"\\${name}\"\n return 1\n fi\n if is_port_accepting \"\\${local_port}\"; then\n sleep 1\n if is_pid_running \"\\${pid}\" && is_port_accepting \"\\${local_port}\"; then\n sleep 0.5\n if is_pid_running \"\\${pid}\"; then\n echo \"\\${name}: started (pid \\${pid}, local port \\${local_port})\"\n return 0\n fi\n fi\n fi\n sleep 0.5\n done\n\n if [[ -f \"\\${pid_file}\" ]]; then\n terminate_forward_process \"\\${name}\" \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\" || return 1\n rm -f \"\\${pid_file}\"\n\n if [[ \"\\${start_attempt}\" -lt 5 ]]; then\n echo \"\\${name}: port-forward attempt \\${start_attempt} did not become ready; retrying\"\n sleep 2\n else\n echo \"\\${name}: did not become ready on local port \\${local_port} for \\${namespace}/\\${resource}:\\${remote_port} after \\${start_attempt} attempts\"\n print_forward_log_tail \"\\${name}\"\n return 1\n fi\n fi\n done\n\n return 1\n}\n\nstop_forward() {\n local name=\"\\${1}\"\n local pid_file\n pid_file=\"$(pid_file_for \"\\${name}\")\"\n read -r namespace resource local_port remote_port <<<\"$(target_for \"\\${name}\")\"\n if [[ ! -f \"\\${pid_file}\" ]]; then\n echo \"\\${name}: stopped\"\n return 0\n fi\n\n local pid\n pid=\"$(cat \"\\${pid_file}\")\"\n if is_pid_running \"\\${pid}\" && ! is_owned_forward_process \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\"; then\n handle_non_owned_forward_pid \"\\${name}\" \"\\${pid}\" \"\\${pid_file}\" \"\\${local_port}\" || return 1\n echo \"\\${name}: stopped\"\n return 0\n fi\n\n terminate_forward_process \"\\${name}\" \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\" || return 1\n rm -f \"\\${pid_file}\"\n echo \"\\${name}: stopped\"\n}\n\nstatus_forward() {\n local name=\"\\${1}\"\n local pid_file\n pid_file=\"$(pid_file_for \"\\${name}\")\"\n if [[ ! -f \"\\${pid_file}\" ]]; then\n echo \"\\${name}: stopped\"\n return 0\n fi\n\n local pid\n pid=\"$(cat \"\\${pid_file}\")\"\n if is_pid_running \"\\${pid}\"; then\n read -r namespace resource local_port remote_port <<<\"$(target_for \"\\${name}\")\"\n if ! is_owned_forward_process \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\"; then\n echo \"\\${name}: stale_pid_non_owned=\\${pid}\"\n rm -f \"\\${pid_file}\"\n return 0\n fi\n if is_port_accepting \"\\${local_port}\"; then\n echo \"\\${name}: running pid=\\${pid} url=127.0.0.1:\\${local_port} target=\\${namespace}/\\${resource}:\\${remote_port}\"\n return 0\n fi\n echo \"\\${name}: not ready pid=\\${pid} url=127.0.0.1:\\${local_port} target=\\${namespace}/\\${resource}:\\${remote_port}\"\n return 0\n fi\n\n echo \"\\${name}: crashed stale_pid=\\${pid}\"\n rm -f \"\\${pid_file}\"\n}\n\nfor_each_forward() {\n local action=\"\\${1}\"\n shift\n local name\n while [[ \"\\${#}\" -gt 0 ]]; do\n name=\"\\${1}\"\n shift\n \"\\${action}_forward\" \"\\${name}\"\n done\n}\n\nACTION=\"\\${1:-start}\"\nNAME=\"\\${2:-all}\"\n\ncase \"\\${ACTION}:\\${NAME}\" in\n start:runtime) for_each_forward start ${runtimeForwardNames.join(' ')} ;;\n stop:runtime)\n for_each_forward stop ${runtimeForwardNames.join(' ')}\n for_each_forward stop ${obsoleteForwardNames.join(' ')}\n ;;\n status:runtime) for_each_forward status ${runtimeForwardNames.join(' ')} ;;\n start:all) for_each_forward start ${allForwardNames.join(' ')} ;;\n stop:all) for_each_forward stop ${managedForwardNames.join(' ')} ;;\n status:all) for_each_forward status ${allForwardNames.join(' ')} ;;\n stop:obsolete) for_each_forward stop ${obsoleteForwardNames.join(' ')} ;;\n start:*) start_forward \"\\${NAME}\" ;;\n stop:*) stop_forward \"\\${NAME}\" ;;\n status:*) status_forward \"\\${NAME}\" ;;\n *)\n echo \"Usage: ./scripts/port-forward.sh {start|stop|status} {${forwardUsage}}\"\n exit 1\n ;;\nesac\n`;\n}\n\nfunction getDownScript(appSlug: string): string {\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\n\"\\${SCRIPT_DIR}/port-forward.sh\" stop all >/dev/null || true\n\nif command -v minikube >/dev/null 2>&1; then\n minikube stop -p \"\\${PROFILE}\"\nelse\n echo \"minikube is required but not installed.\"\n exit 1\nfi\n\necho \"Stopped Minikube profile '\\${PROFILE}'. Persistent data remains in the profile.\"\n`;\n}\n\nfunction getResetScript(args: {\n appSlug: string;\n supabaseKubernetesEnabled: boolean;\n providerNamespaces: readonly string[];\n}): string {\n const { appSlug, supabaseKubernetesEnabled, providerNamespaces } = args;\n const resetNamespaces = [\n APP_NAMESPACE,\n ...(supabaseKubernetesEnabled ? [SUPABASE_NAMESPACE] : []),\n ...providerNamespaces,\n ];\n const resetNamespaceCommands = resetNamespaces\n .map(\n (\n namespace,\n ) => `kubectl --context \"\\${PROFILE}\" delete namespace ${namespace} --ignore-not-found\nkubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/namespaces/${namespace}.yaml\"`,\n )\n .join('\\n');\n const resetScope = `Kubernetes namespaces ${resetNamespaces.join(', ')}`;\n const resetDataDescription = `reset.sh deletes and recreates namespaces ${resetNamespaces.join(\n ', ',\n )}. This resets app workloads and provider-owned data in those namespaces. It does not delete the Minikube profile.`;\n const completionDescription = `Reset namespaces ${resetNamespaces.join(', ')}`;\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nK8S_DIR=\"\\${ROOT_DIR}/k8s\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nCONFIRM=\"\\${ANKH_RESET_CONFIRM:-}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\nif [[ \"\\${CONFIRM}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"Refusing reset. Set ANKH_RESET_CONFIRM=\\${APP_SLUG} to reset ${resetScope} inside profile '\\${PROFILE}'.\"\n echo \"${resetDataDescription}\"\n exit 1\nfi\n\nif ! command -v kubectl >/dev/null 2>&1; then\n echo \"kubectl is required but not installed.\"\n exit 1\nfi\n\n\"\\${SCRIPT_DIR}/port-forward.sh\" stop all >/dev/null || true\n${resetNamespaceCommands}\necho \"${completionDescription} for profile '\\${PROFILE}'. Run ./scripts/up.sh to recreate runtime secrets, migrations, forwards, and app rollout.\"\n`;\n}\n\nfunction getDestroyScript(appSlug: string): string {\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\n\"\\${SCRIPT_DIR}/port-forward.sh\" stop all >/dev/null || true\nminikube delete -p \"\\${PROFILE}\"\necho \"Deleted Minikube profile '\\${PROFILE}'.\"\n`;\n}\n\nfunction getStatusScript(args: {\n appSlug: string;\n appRuntimeEnabled: boolean;\n supabaseKubernetesEnabled: boolean;\n profileModel: ResolvedProfileModel;\n supabaseHostPorts: SupabaseHostPorts;\n providerNamespaces: readonly string[];\n providerLifecycle: readonly MinikubeProviderLifecycle[];\n}): string {\n const {\n appSlug,\n appRuntimeEnabled,\n supabaseKubernetesEnabled,\n profileModel,\n supabaseHostPorts,\n providerNamespaces,\n providerLifecycle,\n } = args;\n const namespaces = [\n APP_NAMESPACE,\n ...(supabaseKubernetesEnabled ? [SUPABASE_NAMESPACE] : []),\n ...providerNamespaces,\n ].join(' ');\n const providerStatusScript = getProviderStatusScript(providerLifecycle);\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nSUPABASE_PROFILE_ENABLED=\"${profileModel.enabled ? 'true' : 'false'}\"\nSUPABASE_GATEWAY_FORWARD_LOCAL_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\necho \"Infra status for profile: \\${PROFILE}\"\n\nif ! command -v minikube >/dev/null 2>&1; then\n echo \"- minikube: missing\"\n exit 1\nfi\n\nHOST_STATUS=\"$(minikube -p \"\\${PROFILE}\" status --format='{{.Host}}' 2>/dev/null || true)\"\necho \"- minikube host: \\${HOST_STATUS:-missing}\"\n\nif [[ \"\\${HOST_STATUS}\" != \"Running\" ]]; then\n echo \"- cluster: stopped\"\n \"\\${SCRIPT_DIR}/port-forward.sh\" status all || true\n exit 0\nfi\n\nif ! command -v kubectl >/dev/null 2>&1; then\n echo \"- kubectl: missing\"\n exit 1\nfi\n\ncheck_secret_key() {\n local secret=\"\\${1}\"\n local key=\"\\${2}\"\n local encoded\n encoded=\"$(kubectl --context \"\\${PROFILE}\" -n ${SUPABASE_NAMESPACE} get secret \"\\${secret}\" -o \"jsonpath={.data.\\${key}}\" 2>/dev/null || true)\"\n if [[ -n \"\\${encoded}\" ]]; then\n echo \"- secret/\\${secret}:\\${key}: present\"\n else\n echo \"- secret/\\${secret}:\\${key}: missing\"\n fi\n}\n\npostgres_query() {\n local sql=\"\\${1}\"\n kubectl --context \"\\${PROFILE}\" -n ${SUPABASE_NAMESPACE} exec deployment/postgres -- psql -U postgres -d postgres -Atq -c \"\\${sql}\" 2>/dev/null || true\n}\n\nfor namespace in ${namespaces}; do\n if kubectl --context \"\\${PROFILE}\" get namespace \"\\${namespace}\" >/dev/null 2>&1; then\n echo \"- namespace/\\${namespace}: present\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${namespace}\" get pods\n else\n echo \"- namespace/\\${namespace}: missing\"\n fi\ndone\n\nif [[ \"${appRuntimeEnabled ? 'true' : 'false'}\" == \"true\" ]] && kubectl --context \"\\${PROFILE}\" -n ${APP_NAMESPACE} get deployment app-runtime >/dev/null 2>&1; then\n kubectl --context \"\\${PROFILE}\" -n ${APP_NAMESPACE} rollout status deployment/app-runtime --timeout=5s >/dev/null 2>&1 && echo \"- app-runtime: ready\" || echo \"- app-runtime: not ready\"\nfi\n\n${providerStatusScript}\n\nif [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" == \"true\" ]]; then\n for deployment in postgres auth rest realtime storage gateway studio; do\n if kubectl --context \"\\${PROFILE}\" -n ${SUPABASE_NAMESPACE} get deployment \"\\${deployment}\" >/dev/null 2>&1; then\n kubectl --context \"\\${PROFILE}\" -n ${SUPABASE_NAMESPACE} rollout status \"deployment/\\${deployment}\" --timeout=5s >/dev/null 2>&1 && echo \"- supabase/\\${deployment}: ready\" || echo \"- supabase/\\${deployment}: not ready\"\n else\n echo \"- supabase/\\${deployment}: missing\"\n fi\n done\n\n for key in POSTGRES_PASSWORD JWT_SECRET SUPABASE_ANON_KEY SUPABASE_SERVICE_ROLE_KEY SECRET_KEY_BASE REALTIME_DB_ENC_KEY PG_META_CRYPTO_KEY; do\n check_secret_key supabase-runtime-secrets \"\\${key}\"\n done\n\n db_check=\"$(postgres_query 'select 1')\"\n if [[ \"\\${db_check}\" == \"1\" ]]; then\n echo \"- postgres connectivity: ok\"\n else\n echo \"- postgres connectivity: failed\"\n fi\n\n migration_count=\"$(postgres_query \"select count(*) from supabase_migrations.schema_migrations\" || true)\"\n if [[ \"\\${migration_count}\" =~ ^[0-9]+$ ]]; then\n echo \"- migration history: \\${migration_count} applied\"\n else\n echo \"- migration history: unavailable\"\n fi\n\n if [[ \"\\${SUPABASE_PROFILE_ENABLED}\" == \"true\" ]]; then\n profile_state=\"$(postgres_query \"select count(*) from ankhorage_internal.generated_schema_state where artifact_key = 'auth.profile'\" || true)\"\n if [[ \"\\${profile_state}\" =~ ^[1-9][0-9]*$ ]]; then\n echo \"- profile reconciliation: applied\"\n else\n echo \"- profile reconciliation: missing\"\n fi\n else\n state_table=\"$(postgres_query \"select to_regclass('ankhorage_internal.generated_schema_state') is not null\" || true)\"\n if [[ \"\\${state_table}\" != \"t\" ]]; then\n echo \"- profile reconciliation: disabled\"\n else\n profile_state=\"$(postgres_query \"select coalesce((select case when table_name is null then 'stale-state-missing-table-name' when to_regclass(format('public.%I', table_name)) is null then 'stale-state-missing-table:' || table_name else 'stale-state-table-present:' || table_name end from ankhorage_internal.generated_schema_state where artifact_key = 'auth.profile'), 'disabled')\" || true)\"\n if [[ \"\\${profile_state}\" == \"disabled\" ]]; then\n echo \"- profile reconciliation: disabled\"\n else\n echo \"- profile reconciliation: unexpected \\${profile_state}\"\n fi\n fi\n fi\n\n vault_state=\"$(postgres_query \"select exists(select 1 from pg_namespace where nspname = 'vault')\" || true)\"\n if [[ \"\\${vault_state}\" == \"t\" ]]; then\n echo \"- vault schema: present\"\n else\n echo \"- vault schema: absent\"\n fi\n\n if command -v curl >/dev/null 2>&1; then\n public_url=\"\\${SUPABASE_PUBLIC_URL:-http://127.0.0.1:\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT}}\"\n if curl -fsS \"\\${public_url}/auth/v1/health\" >/dev/null 2>&1; then\n echo \"- supabase public endpoint: ok (\\${public_url})\"\n else\n echo \"- supabase public endpoint: unavailable (\\${public_url})\"\n fi\n fi\nfi\n\n\"\\${SCRIPT_DIR}/port-forward.sh\" status all || true\n`;\n}\n\nfunction getDefaultAppImage(appSlug: string): string {\n return `ankh/${appSlug}:dev`;\n}\n\nfunction resolveSupabaseHostPorts(appSlug: string): SupabaseHostPorts {\n const base = PORT_BASE + resolvePortBucket(appSlug) * PORT_BUCKET_SIZE;\n return {\n app: base,\n gateway: base + 1,\n studio: base + 2,\n db: base + 3,\n };\n}\n\nfunction resolvePortBucket(appSlug: string): number {\n const rawBucket = hashSlug(appSlug) - hashSlug(PORT_REFERENCE_SLUG);\n return (rawBucket + PORT_BUCKET_COUNT) % PORT_BUCKET_COUNT;\n}\n\nfunction hashSlug(value: string): number {\n let hash = 0;\n for (const char of value) {\n hash = (hash * 31 + char.charCodeAt(0)) % PORT_BUCKET_COUNT;\n }\n return hash;\n}\n\nfunction escapeYamlDoubleQuoted(value: string): string {\n return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"');\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/minikube/base/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GeneratedInfrastructureFile } from '../../../types';\nimport type { InfraManifestInput } from '../../../types';\nimport type { ResolvedProfileModel } from '../auth/supabase/profile';\nimport { resolveSupabaseProfileModel } from '../auth/supabase/profile';\nimport type { MinikubeProviderLifecycle } from '../contracts';\nimport { getSupabaseMigrationCommandScript } from './supabaseMigrations';\n\nexport const APP_NAMESPACE = 'app';\nconst SUPABASE_NAMESPACE = 'supabase';\n\ninterface SupabaseHostPorts {\n app: number;\n gateway: number;\n studio: number;\n db: number;\n}\n\ninterface AppInfraStorageMetadata {\n provider: 'supabase';\n bucketsCsv: string;\n defaultBucket: string;\n}\n\ninterface SupabaseImagePins {\n postgres: string;\n auth: string;\n rest: string;\n realtime: string;\n storage: string;\n imgproxy: string;\n meta: string;\n gateway: string;\n studio: string;\n}\n\ninterface SupabaseOAuthProviderRuntime {\n id: string;\n envPrefix: string;\n credentialsRef: string;\n callbackRoute: string;\n}\n\nconst SUPABASE_IMAGES: SupabaseImagePins = {\n postgres: 'supabase/postgres:17.6.1.136',\n auth: 'supabase/gotrue:v2.189.0',\n rest: 'postgrest/postgrest:v14.12',\n realtime: 'supabase/realtime:v2.102.3',\n storage: 'supabase/storage-api:v1.60.4',\n imgproxy: 'darthsim/imgproxy:v3.30.1',\n meta: 'supabase/postgres-meta:v0.96.6',\n gateway: 'kong/kong:3.9.1',\n studio: 'supabase/studio:2026.07.07-sha-a6a04f2',\n};\n\nconst PORT_BASE = 18080;\nconst PORT_BUCKET_SIZE = 20;\nconst PORT_BUCKET_COUNT = 1000;\nconst PORT_REFERENCE_SLUG = 'my-app';\n\nexport function generateMinikubeBaseArtifacts(args: {\n manifest: InfraManifestInput;\n appSlug: string;\n appRuntimeEnabled: boolean;\n extraResources: string[];\n providerNamespaces: string[];\n providerLifecycle: MinikubeProviderLifecycle[];\n extraEnvEntries: string[];\n}): GeneratedInfrastructureFile[] {\n const {\n manifest,\n appSlug,\n appRuntimeEnabled,\n extraResources,\n providerNamespaces,\n providerLifecycle,\n extraEnvEntries,\n } = args;\n\n const root = 'infra/minikube';\n const k8sRoot = `${root}/k8s`;\n const scriptsRoot = `${root}/scripts`;\n const appImageRoot = `${root}/app-image`;\n const defaultAppImage = getDefaultAppImage(appSlug);\n const supabaseHostPorts = resolveSupabaseHostPorts(appSlug);\n\n const authScope = manifest.auth?.scope ?? 'none';\n const authProvider = manifest.auth?.provider ?? 'none';\n const authzEngine = manifest.auth?.authorization?.engine ?? 'none';\n const databaseProvider = manifest.database?.provider ?? 'none';\n const secretStoreProvider = manifest.secretStore?.provider ?? 'none';\n const storageMetadata = resolveAppInfraStorageMetadata(manifest);\n const profileModel = resolveSupabaseProfileModel(manifest);\n const oauthProviders = resolveSupabaseOAuthProviders(manifest);\n const monitoringEnabled = manifest.deployment?.monitoring === true;\n const domain = manifest.networking?.domain ?? '';\n const supabaseKubernetesEnabled =\n authProvider === 'supabase' ||\n databaseProvider === 'supabase' ||\n storageMetadata !== null ||\n secretStoreProvider === 'supabase-vault';\n\n const supabaseResources = supabaseKubernetesEnabled ? getSupabaseResourceFiles(k8sRoot) : [];\n const namespaceResources = [\n 'namespaces/app.yaml',\n ...(supabaseKubernetesEnabled ? ['namespaces/supabase.yaml'] : []),\n ...providerNamespaces.map((namespace) => `namespaces/${namespace}.yaml`),\n ];\n\n return [\n {\n path: `${root}/README.md`,\n content: getReadmeMarkdown({\n appSlug,\n appRuntimeEnabled,\n defaultAppImage,\n monitoringEnabled,\n authProvider,\n authzEngine,\n extraResources,\n supabaseHostPorts,\n supabaseKubernetesEnabled,\n profileModel,\n oauthProviders,\n providerNamespaces,\n providerLifecycle,\n }),\n },\n {\n path: `${root}/.env.example`,\n content: getEnvExample({\n appSlug,\n domain,\n extraEnvEntries,\n defaultAppImage,\n supabaseHostPorts,\n supabaseKubernetesEnabled,\n oauthProviders,\n }),\n },\n {\n path: `${k8sRoot}/namespaces/app.yaml`,\n content: getNamespaceManifest(APP_NAMESPACE),\n },\n ...(supabaseKubernetesEnabled\n ? [\n {\n path: `${k8sRoot}/namespaces/supabase.yaml`,\n content: getNamespaceManifest(SUPABASE_NAMESPACE),\n },\n ]\n : []),\n ...providerNamespaces.map((namespace) => ({\n path: `${k8sRoot}/namespaces/${namespace}.yaml`,\n content: getNamespaceManifest(namespace),\n })),\n ...(appRuntimeEnabled\n ? [\n {\n path: `${k8sRoot}/app.configmap.yaml`,\n content: getAppConfigMap({\n appSlug,\n authScope,\n authProvider,\n databaseProvider,\n secretStoreProvider,\n storageMetadata,\n monitoringEnabled,\n domain,\n }),\n },\n {\n path: `${k8sRoot}/app/deployment.yaml`,\n content: getAppDeploymentManifest(defaultAppImage),\n },\n {\n path: `${k8sRoot}/app/service.yaml`,\n content: getAppServiceManifest(),\n },\n ]\n : []),\n ...supabaseResources,\n {\n path: `${k8sRoot}/kustomization.yaml`,\n content: getKustomizationManifest({\n namespaceResources,\n appRuntimeEnabled,\n supabaseEnabled: supabaseKubernetesEnabled,\n extraResources,\n }),\n },\n {\n path: `${scriptsRoot}/up.sh`,\n content: getUpScript({\n appSlug,\n appRuntimeEnabled,\n defaultAppImage,\n supabaseKubernetesEnabled,\n profileModel,\n secretStoreProvider,\n supabaseHostPorts,\n oauthProviders,\n providerLifecycle,\n }),\n executable: true,\n },\n {\n path: `${scriptsRoot}/build-app-image.sh`,\n content: getBuildAppImageScript({ appSlug, defaultAppImage }),\n executable: true,\n },\n {\n path: `${scriptsRoot}/port-forward.sh`,\n content: getPortForwardScript({\n appSlug,\n appRuntimeEnabled,\n supabaseKubernetesEnabled,\n supabaseHostPorts,\n }),\n executable: true,\n },\n {\n path: `${scriptsRoot}/down.sh`,\n content: getDownScript(appSlug),\n executable: true,\n },\n {\n path: `${scriptsRoot}/reset.sh`,\n content: getResetScript({\n appSlug,\n supabaseKubernetesEnabled,\n providerNamespaces,\n }),\n executable: true,\n },\n {\n path: `${scriptsRoot}/destroy.sh`,\n content: getDestroyScript(appSlug),\n executable: true,\n },\n {\n path: `${scriptsRoot}/status.sh`,\n content: getStatusScript({\n appSlug,\n appRuntimeEnabled,\n supabaseKubernetesEnabled,\n profileModel,\n supabaseHostPorts,\n providerNamespaces,\n providerLifecycle,\n }),\n executable: true,\n },\n {\n path: `${appImageRoot}/Dockerfile`,\n content: getAppImageDockerfile(),\n },\n ];\n}\n\nfunction getReadmeMarkdown(args: {\n appSlug: string;\n appRuntimeEnabled: boolean;\n defaultAppImage: string;\n monitoringEnabled: boolean;\n authProvider: string;\n authzEngine: string;\n extraResources: string[];\n supabaseHostPorts: SupabaseHostPorts;\n supabaseKubernetesEnabled: boolean;\n profileModel: ResolvedProfileModel;\n oauthProviders: readonly SupabaseOAuthProviderRuntime[];\n providerNamespaces: readonly string[];\n providerLifecycle: readonly MinikubeProviderLifecycle[];\n}): string {\n const {\n appSlug,\n appRuntimeEnabled,\n defaultAppImage,\n monitoringEnabled,\n authProvider,\n authzEngine,\n extraResources,\n supabaseHostPorts,\n supabaseKubernetesEnabled,\n profileModel,\n oauthProviders,\n providerNamespaces,\n providerLifecycle,\n } = args;\n const resourceLines = [\n 'namespaces/app.yaml',\n ...(supabaseKubernetesEnabled ? ['namespaces/supabase.yaml'] : []),\n ...providerNamespaces.map((namespace) => `namespaces/${namespace}.yaml`),\n ...(appRuntimeEnabled ? ['app.configmap.yaml', 'app/deployment.yaml', 'app/service.yaml'] : []),\n ...(supabaseKubernetesEnabled\n ? [\n 'supabase/bootstrap.sql',\n 'supabase/postgres.init.configmap.yaml',\n 'supabase/postgres.pvc.yaml',\n 'supabase/postgres.yaml',\n 'supabase/auth.yaml',\n 'supabase/rest.yaml',\n 'supabase/realtime.yaml',\n 'supabase/storage.yaml',\n 'supabase/imgproxy.yaml',\n 'supabase/meta.yaml',\n 'supabase/gateway.template.yml',\n 'supabase/kong-entrypoint.sh',\n 'supabase/gateway.yaml',\n 'supabase/studio.yaml',\n ]\n : []),\n ...extraResources,\n ]\n .map((resource) => `- \\`k8s/${resource}\\``)\n .join('\\n');\n\n const resetNamespaces = [\n APP_NAMESPACE,\n ...(supabaseKubernetesEnabled ? [SUPABASE_NAMESPACE] : []),\n ...providerNamespaces,\n ];\n const resetDescription = `deletes and recreates namespaces ${resetNamespaces\n .map((namespace) => `\\`${namespace}\\``)\n .join(\n ', ',\n )} inside the existing profile. This removes app-owned Kubernetes state and provider-owned PVC data for reset namespaces`;\n const providerNamespaceLine =\n providerNamespaces.length > 0\n ? `- Provider namespaces: \\`${providerNamespaces.join('`, `')}\\`\\n`\n : '';\n const providerLifecycleLines =\n providerLifecycle.length > 0\n ? `## Provider Lifecycle Contributions\\n\\n${providerLifecycle\n .map((provider) => {\n const readiness =\n provider.readinessChecks.length > 0\n ? provider.readinessChecks\n .map((check) => `\\`${check.resource}\\` in namespace \\`${check.namespace}\\``)\n .join(', ')\n : 'none';\n const endpoints =\n provider.endpoints.length > 0\n ? provider.endpoints\n .map((endpoint) => `\\`${endpoint.name}\\` = \\`${endpoint.url}\\``)\n .join(', ')\n : 'none';\n return `- \\`${provider.id}\\`: namespace \\`${provider.namespace}\\`; readiness ${readiness}; endpoints ${endpoints}`;\n })\n .join('\\n')}`\n : '';\n const oauthDescription =\n oauthProviders.length > 0\n ? `\\nConfigured OAuth providers are wired into GoTrue through generated \\`GOTRUE_EXTERNAL_*\\` runtime keys. The keys are named in \\`.env.example\\`; values must come from trusted secret resolution for the configured \\`credentialsRef\\` entries.`\n : '';\n\n const runtimeForwardDescription = appRuntimeEnabled\n ? supabaseKubernetesEnabled\n ? '`app` and `supabase-gateway`'\n : '`app`'\n : supabaseKubernetesEnabled\n ? '`supabase-gateway`'\n : 'no host endpoints';\n\n return `# Minikube Infra\n\nThis directory is generated from \\`ankh.config.json\\` (infra manifest).\n\n## Ownership Model\n\n- App slug / Minikube profile: \\`${appSlug}\\`\n- App runtime: \\`${appRuntimeEnabled ? `deployment/app-runtime in namespace ${APP_NAMESPACE}` : 'disabled (no enabled Web deploy target)'}\\`\n- Supabase namespace: \\`${supabaseKubernetesEnabled ? SUPABASE_NAMESPACE : 'unused'}\\`\n${providerNamespaceLine}- Default app image: \\`${defaultAppImage}\\`\n\nOne app owns one complete Minikube profile. Provider-owned workloads are separated by\nKubernetes namespace inside that profile. There is no shared \\`minikube\\` profile and no\nhost-level Supabase Compose runtime.\n\n## Quick Start\n\n1. Copy env template:\n \\`\\`\\`bash\n cp .env.example .env\n \\`\\`\\`\n2. Adjust optional values in \\`.env\\`; missing Supabase development secrets are generated by \\`up.sh\\`.\n3. Start infra:\n \\`\\`\\`bash\n ./scripts/up.sh\n \\`\\`\\`\n4. Check status:\n \\`\\`\\`bash\n ./scripts/status.sh\n \\`\\`\\`\n5. Stop the app-owned cluster without deleting data:\n \\`\\`\\`bash\n ./scripts/down.sh\n \\`\\`\\`\n\n## Lifecycle Semantics\n\n- \\`up.sh\\`: starts \\`minikube -p ${appSlug}\\`, deploys provider namespaces, runs migrations with CLI telemetry disabled for that command, starts slug-owned port-forwards${appRuntimeEnabled ? ', and deploys the Web app runtime' : ''}.\n- \\`down.sh\\`: stops slug-owned port-forwards, then stops \\`minikube -p ${appSlug}\\`. Persistent data remains in the profile.\n- \\`reset.sh\\`: requires \\`ANKH_RESET_CONFIRM=${appSlug}\\`; ${resetDescription}. It does not delete the Minikube profile.\n- \\`destroy.sh\\`: deletes only \\`minikube -p ${appSlug}\\`.\n\n### Port-forward groups\n\n- \\`./scripts/port-forward.sh start runtime\\` idempotently ensures ${runtimeForwardDescription}, the generated host endpoints required by the running application. The same group supports \\`stop\\` and \\`status\\`.\n- \\`runtime\\` excludes \\`studio\\` and \\`db-migration\\`, which are operational/bootstrap endpoints.\n- \\`all\\` retains every generated forward, including operational/bootstrap endpoints.\n- Concrete targets remain available for individual lifecycle control.\n\n## Generated Resources\n\n${resourceLines}\n\n## Supabase Runtime\n\nSupabase runtime ownership is Kubernetes. Migration authoring/history remains Supabase\nmigration files. Migration execution targets the Kubernetes Postgres endpoint through\n\\`SUPABASE_TELEMETRY_DISABLED=1 supabase --yes migration up --db-url \"$SUPABASE_DB_URL\"\\`.\nThe migration process does not require stdin. \\`--yes\\` remains defense in depth for future\nCLI prompts; it is not the hang fix. Command-scoped telemetry disable avoids the unbounded\ntelemetry shutdown in Supabase CLI 2.106.0 when PostHog is blocked, without changing the\nuser's persistent telemetry preference. Migration failures stop \\`up.sh\\`, and the completion\nmessage is printed only after a zero exit status. No migration deadline is added; using a\ncurrent Supabase CLI remains recommended.\n\nSupabase manifests are generated from the current official Supabase self-hosting Docker\ntopology, service documentation, environment-variable contracts, and pinned official images.\nKubernetes/Helm is treated as community-driven upstream guidance, not an official\ndistribution copied by this generator.\n${oauthDescription}\n\nPinned images:\n\n- Postgres: \\`${SUPABASE_IMAGES.postgres}\\`\n- Auth: \\`${SUPABASE_IMAGES.auth}\\`\n- PostgREST: \\`${SUPABASE_IMAGES.rest}\\`\n- Realtime: \\`${SUPABASE_IMAGES.realtime}\\`\n- Storage: \\`${SUPABASE_IMAGES.storage}\\`\n- Gateway: \\`${SUPABASE_IMAGES.gateway}\\`\n- Studio: \\`${SUPABASE_IMAGES.studio}\\`\n\n## Host URLs\n\n${appRuntimeEnabled ? `- App: \\`http://127.0.0.1:${supabaseHostPorts.app}\\`\\n` : ''}- Supabase gateway: \\`http://127.0.0.1:${supabaseHostPorts.gateway}\\`\n- Studio: \\`http://127.0.0.1:${supabaseHostPorts.studio}\\`\n- DB migration endpoint: \\`127.0.0.1:${supabaseHostPorts.db}\\`\n\n## App Image Export\n\n\\`build-app-image.sh\\` requires the app-installed \\`node_modules/.bin/expo\\` and never resolves\nExpo globally or through the network. It clears the Expo/Metro bundler cache before every web\nexport. Expo inlines \\`EXPO_PUBLIC_*\\` values into the browser bundle, so cache invalidation\nensures a rotated browser-safe Supabase URL or anon key replaces the previous value before the\nDocker image is built. Privileged Supabase credentials are not written to the app's public env\nfile.\n\n## Runtime Conventions\n\n- Monitoring requested: \\`${monitoringEnabled ? 'true' : 'false'}\\`\n- Auth provider: \\`${authProvider}\\`\n- Authorization engine: \\`${authzEngine}\\`\n${profileModel.enabled ? '- Generated profile reconciliation lives in `supabase/generated/auth_profiles.sql` and records checksum state in `ankhorage_internal.generated_schema_state`.\\n' : ''}\n${providerLifecycleLines}\n`;\n}\n\nfunction getEnvExample(args: {\n appSlug: string;\n domain: string;\n extraEnvEntries: string[];\n defaultAppImage: string;\n supabaseHostPorts: SupabaseHostPorts;\n supabaseKubernetesEnabled: boolean;\n oauthProviders: readonly SupabaseOAuthProviderRuntime[];\n}): string {\n const { appSlug, domain, extraEnvEntries, defaultAppImage, supabaseHostPorts, oauthProviders } =\n args;\n\n const baseEntries = [\n '# App-owned Minikube profile configuration',\n `ANKH_APP_SLUG=${appSlug}`,\n 'MINIKUBE_DRIVER=docker',\n 'APP_BUILD_ENABLED=true',\n 'APP_SOURCE_DIR=',\n 'APP_WEB_EXPORT_DIR=.ankh/web-export',\n `APP_IMAGE=${defaultAppImage}`,\n 'APP_IMAGE_SYNC_STRATEGY=docker-load',\n 'APP_IMAGE_CLEANUP_ON_DESTROY=true',\n 'APP_IMAGE_CLEANUP_MINIKUBE=true',\n 'APP_IMAGE_CLEANUP_DOCKER=true',\n `APP_PORT_FORWARD_LOCAL_PORT=${supabaseHostPorts.app}`,\n 'APP_PORT_FORWARD_REMOTE_PORT=80',\n `SUPABASE_GATEWAY_FORWARD_LOCAL_PORT=${supabaseHostPorts.gateway}`,\n 'SUPABASE_GATEWAY_FORWARD_REMOTE_PORT=8000',\n `SUPABASE_STUDIO_FORWARD_LOCAL_PORT=${supabaseHostPorts.studio}`,\n 'SUPABASE_STUDIO_FORWARD_REMOTE_PORT=3000',\n `SUPABASE_DB_FORWARD_LOCAL_PORT=${supabaseHostPorts.db}`,\n 'SUPABASE_DB_FORWARD_REMOTE_PORT=5432',\n 'APP_REPLICAS=1',\n 'APP_FORCE_ROLLOUT_RESTART=true',\n '',\n '# Optional private registry auth for APP_IMAGE',\n 'APP_IMAGE_PULL_SECRET_NAME=',\n 'APP_IMAGE_PULL_SECRET_SERVER=ghcr.io',\n 'APP_IMAGE_PULL_SECRET_USERNAME=',\n 'APP_IMAGE_PULL_SECRET_PASSWORD=',\n 'APP_IMAGE_PULL_SECRET_EMAIL=',\n '',\n '# Optional app networking domain',\n `APP_DOMAIN=${domain}`,\n '',\n '# Supabase Kubernetes runtime secrets',\n 'POSTGRES_PASSWORD=',\n 'JWT_SECRET=',\n 'SUPABASE_ANON_KEY=',\n 'SUPABASE_SERVICE_ROLE_KEY=',\n 'SUPABASE_PUBLISHABLE_KEY=',\n 'SUPABASE_SECRET_KEY=',\n 'DASHBOARD_USERNAME=supabase',\n 'DASHBOARD_PASSWORD=',\n 'SECRET_KEY_BASE=',\n 'REALTIME_DB_ENC_KEY=',\n 'PG_META_CRYPTO_KEY=',\n 'S3_PROTOCOL_ACCESS_KEY_ID=',\n 'S3_PROTOCOL_ACCESS_KEY_SECRET=',\n 'JWT_EXPIRY=3600',\n 'SITE_URL=',\n 'OAUTH_NATIVE_REDIRECT_URLS=',\n 'ADDITIONAL_REDIRECT_URLS=',\n 'SUPABASE_PUBLIC_URL=',\n 'API_EXTERNAL_URL=',\n 'ENABLE_EMAIL_SIGNUP=true',\n 'ENABLE_EMAIL_AUTOCONFIRM=true',\n 'SMTP_ADMIN_EMAIL=admin@example.com',\n 'SMTP_HOST=localhost',\n 'SMTP_PORT=2500',\n 'SMTP_USER=',\n 'SMTP_PASS=',\n 'SMTP_SENDER_NAME=Ankhorage',\n 'PGRST_DB_SCHEMAS=public,storage,graphql_public',\n 'PGRST_DB_MAX_ROWS=1000',\n 'PGRST_DB_EXTRA_SEARCH_PATH=public',\n 'GLOBAL_S3_BUCKET=stub',\n 'STORAGE_TENANT_ID=stub',\n 'REGION=stub',\n 'SUPABASE_DB_URL=',\n 'EXPO_PUBLIC_SUPABASE_URL=',\n 'EXPO_PUBLIC_SUPABASE_ANON_KEY=',\n ...getOAuthEnvExampleEntries(oauthProviders),\n '',\n '# Adapter-provided runtime keys',\n ];\n\n const merged = [...baseEntries, ...extraEnvEntries];\n const unique: string[] = [];\n for (const entry of merged) {\n if (!unique.includes(entry)) unique.push(entry);\n }\n\n return `${unique.join('\\n')}\\n`;\n}\n\nfunction getOAuthEnvExampleEntries(providers: readonly SupabaseOAuthProviderRuntime[]): string[] {\n if (providers.length === 0) return [];\n\n return [\n '',\n '# OAuth provider runtime values resolved from trusted credentialsRef entries',\n ...providers.flatMap((provider) => [\n `# ${provider.id}: ${provider.credentialsRef}`,\n `GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID=`,\n `GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET=`,\n `GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI=`,\n ]),\n ];\n}\n\nfunction getOAuthScriptEnvDefaults(providers: readonly SupabaseOAuthProviderRuntime[]): string {\n if (providers.length === 0) return '';\n\n return providers\n .map(\n (\n provider,\n ) => ` export GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID=\"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID:-}\"\n export GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET=\"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET:-}\"\n export GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI=\"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI:-\\${API_EXTERNAL_URL}/callback}\"`,\n )\n .join('\\n');\n}\n\nfunction getOAuthRuntimeSecretLines(providers: readonly SupabaseOAuthProviderRuntime[]): string {\n if (providers.length === 0) return '';\n\n return providers\n .map(\n (provider) => `GOTRUE_EXTERNAL_${provider.envPrefix}_ENABLED=true\nGOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID=\\${GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID}\nGOTRUE_EXTERNAL_${provider.envPrefix}_SECRET=\\${GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET}\nGOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI=\\${GOTRUE_EXTERNAL_${provider.envPrefix}_REDIRECT_URI}`,\n )\n .join('\\n');\n}\n\nfunction getOAuthRuntimeValidationScript(\n providers: readonly SupabaseOAuthProviderRuntime[],\n): string {\n if (providers.length === 0) return '';\n\n const checks = providers\n .map(\n (\n provider,\n ) => ` if [[ -z \"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID:-}\" || -z \"\\${GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET:-}\" ]]; then\n echo \"OAuth provider ${provider.id} requires trusted runtime values GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID and GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET from credentialsRef ${provider.credentialsRef}.\"\n exit 1\n fi`,\n )\n .join('\\n');\n\n return `\n # OAuth provider secrets must be resolved by trusted host code before Kubernetes sync.\n${checks}`;\n}\n\nfunction getSupabaseOAuthCallbackRoute(providers: readonly SupabaseOAuthProviderRuntime[]): string {\n return providers[0]?.callbackRoute ?? '/auth/callback';\n}\n\nfunction getOAuthVaultResolutionScript(args: {\n appSlug: string;\n oauthProviders: readonly SupabaseOAuthProviderRuntime[];\n secretStoreProvider: string;\n}): string {\n const { appSlug, oauthProviders, secretStoreProvider } = args;\n if (secretStoreProvider !== 'supabase-vault' || oauthProviders.length === 0) {\n return `\nresolve_oauth_credentials_from_vault() {\n return 0\n}\n`;\n }\n\n const lines = oauthProviders\n .map((provider) => {\n const ref = escapeSingleQuotedSql(provider.credentialsRef);\n const idKey = `GOTRUE_EXTERNAL_${provider.envPrefix}_CLIENT_ID`;\n const secretKey = `GOTRUE_EXTERNAL_${provider.envPrefix}_SECRET`;\n\n return ` if [[ -z \"\\${${idKey}:-}\" || -z \"\\${${secretKey}:-}\" ]]; then\n local resolved_client_id resolved_client_secret\n resolved_client_id=\"$(resolve_vault_secret_field '${ref}' 'clientId')\"\n resolved_client_secret=\"$(resolve_vault_secret_field '${ref}' 'clientSecret')\"\n if [[ -n \"\\${resolved_client_id}\" ]]; then\n export ${idKey}=\"\\${resolved_client_id}\"\n fi\n if [[ -n \"\\${resolved_client_secret}\" ]]; then\n export ${secretKey}=\"\\${resolved_client_secret}\"\n fi\n fi`;\n })\n .join('\\n');\n\n return `\nresolve_vault_secret_field() {\n local ref=\"\\${1}\"\n local field=\"\\${2}\"\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -Atq -c \"select coalesce(decrypted.decrypted_secret::jsonb ->> '\\${field}', '') from ankh_secret_store.secret_metadata metadata join vault.decrypted_secrets decrypted on decrypted.id = metadata.vault_secret_id where metadata.project_id = '${escapeSingleQuotedSql(\n appSlug,\n )}' and metadata.environment = 'local' and metadata.secret_ref = '\\${ref}' limit 1;\" 2>/dev/null || true\n}\n\nresolve_oauth_credentials_from_vault() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n${lines}\n}\n`;\n}\n\nfunction escapeSingleQuotedSql(value: string): string {\n return value.replace(/'/gu, \"''\");\n}\n\nfunction escapeShellDoubleQuoted(value: string): string {\n return value.replace(/[\"\\\\$`]/gu, (char) => `\\\\${char}`);\n}\n\nfunction getProviderLifecycleStageScripts(\n providerLifecycle: readonly MinikubeProviderLifecycle[],\n): string {\n return `${getProviderLifecycleCommandFunction({\n functionName: 'run_provider_migrations',\n emptyReturn: 'return 0',\n commands: providerLifecycle.flatMap((provider) =>\n provider.migrationCommands.map((command) => ({\n providerId: provider.id,\n label: command.label,\n command: command.command,\n })),\n ),\n })}\n\n${getProviderLifecycleCommandFunction({\n functionName: 'run_provider_reconciliation',\n emptyReturn: 'return 0',\n commands: providerLifecycle.flatMap((provider) =>\n provider.reconciliationCommands.map((command) => ({\n providerId: provider.id,\n label: command.label,\n command: command.command,\n })),\n ),\n})}\n\n${getProviderReadinessFunction(providerLifecycle)}`;\n}\n\nfunction getProviderLifecycleCommandFunction(args: {\n functionName: string;\n emptyReturn: string;\n commands: readonly { providerId: string; label: string; command: string }[];\n}): string {\n if (args.commands.length === 0) {\n return `${args.functionName}() {\n ${args.emptyReturn}\n}`;\n }\n\n const body = args.commands\n .map(\n (command) => ` echo \"Running provider ${escapeShellDoubleQuoted(\n command.providerId,\n )} ${escapeShellDoubleQuoted(command.label)}.\"\n${indentShellBlock(command.command.trim(), 2)}`,\n )\n .join('\\n\\n');\n\n return `${args.functionName}() {\n${body}\n}`;\n}\n\nfunction getProviderReadinessFunction(\n providerLifecycle: readonly MinikubeProviderLifecycle[],\n): string {\n const checks = providerLifecycle.flatMap((provider) =>\n provider.readinessChecks.map((check) => ({ providerId: provider.id, ...check })),\n );\n\n if (checks.length === 0) {\n return `wait_for_provider_readiness() {\n return 0\n}`;\n }\n\n const body = checks\n .map(\n (check) =>\n ` kubectl --context \"\\${PROFILE}\" -n \"${escapeShellDoubleQuoted(\n check.namespace,\n )}\" rollout status \"${escapeShellDoubleQuoted(\n check.resource,\n )}\" --timeout=${check.timeoutSeconds}s`,\n )\n .join('\\n');\n\n return `wait_for_provider_readiness() {\n${body}\n}`;\n}\n\nfunction getProviderStatusScript(providerLifecycle: readonly MinikubeProviderLifecycle[]): string {\n if (providerLifecycle.length === 0) {\n return '';\n }\n\n return providerLifecycle\n .map((provider) => {\n const endpointLines = provider.endpoints\n .map(\n (endpoint) =>\n ` echo \"- provider ${escapeShellDoubleQuoted(\n provider.id,\n )} endpoint/${escapeShellDoubleQuoted(endpoint.name)}: ${escapeShellDoubleQuoted(\n endpoint.url,\n )}\"`,\n )\n .join('\\n');\n const readinessLines = provider.readinessChecks\n .map(\n (check) => ` if kubectl --context \"\\${PROFILE}\" -n \"${escapeShellDoubleQuoted(\n check.namespace,\n )}\" rollout status \"${escapeShellDoubleQuoted(\n check.resource,\n )}\" --timeout=5s >/dev/null 2>&1; then\n echo \"- provider ${escapeShellDoubleQuoted(provider.id)}/${escapeShellDoubleQuoted(\n check.label,\n )}: ready\"\n else\n echo \"- provider ${escapeShellDoubleQuoted(provider.id)}/${escapeShellDoubleQuoted(\n check.label,\n )}: not ready\"\n fi`,\n )\n .join('\\n');\n const customStatusLines = provider.statusChecks\n .map(\n (check) => ` echo \"Running provider ${escapeShellDoubleQuoted(\n provider.id,\n )} status check ${escapeShellDoubleQuoted(check.label)}.\"\n${indentShellBlock(check.command.trim(), 2)}`,\n )\n .join('\\n');\n\n return [endpointLines, readinessLines, customStatusLines].filter(Boolean).join('\\n');\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction indentShellBlock(value: string, spaces: number): string {\n const indent = ' '.repeat(spaces);\n return value\n .split('\\n')\n .map((line) => `${indent}${line}`)\n .join('\\n');\n}\n\nfunction getNamespaceManifest(namespace: string): string {\n return `apiVersion: v1\nkind: Namespace\nmetadata:\n name: ${namespace}\n labels:\n app.kubernetes.io/part-of: ankhorage\n ankhorage.io/namespace-role: ${namespace}\n`;\n}\n\nfunction getAppConfigMap(args: {\n appSlug: string;\n authScope: string;\n authProvider: string;\n databaseProvider: string;\n secretStoreProvider: string;\n storageMetadata: AppInfraStorageMetadata | null;\n monitoringEnabled: boolean;\n domain: string;\n}): string {\n const {\n appSlug,\n authScope,\n authProvider,\n databaseProvider,\n secretStoreProvider,\n storageMetadata,\n monitoringEnabled,\n domain,\n } = args;\n\n const storageLines = storageMetadata\n ? ` STORAGE_PROVIDER: \"${storageMetadata.provider}\"\n STORAGE_BUCKETS: \"${escapeYamlDoubleQuoted(storageMetadata.bucketsCsv)}\"\n STORAGE_DEFAULT_BUCKET: \"${escapeYamlDoubleQuoted(storageMetadata.defaultBucket)}\"\n`\n : '';\n\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: app-infra-config\n namespace: ${APP_NAMESPACE}\ndata:\n ANKH_APP_SLUG: \"${appSlug}\"\n DEPLOYMENT_TARGET: \"minikube\"\n APP_NAMESPACE: \"${APP_NAMESPACE}\"\n SUPABASE_NAMESPACE: \"${SUPABASE_NAMESPACE}\"\n MONITORING_ENABLED: \"${monitoringEnabled ? 'true' : 'false'}\"\n AUTH_SCOPE: \"${authScope}\"\n AUTH_PROVIDER: \"${authProvider}\"\n DATABASE_PROVIDER: \"${databaseProvider}\"\n SECRET_STORE_PROVIDER: \"${secretStoreProvider}\"\n${storageLines} NETWORK_DOMAIN: \"${escapeYamlDoubleQuoted(domain)}\"\n`;\n}\n\nfunction resolveAppInfraStorageMetadata(\n manifest: InfraManifestInput,\n): AppInfraStorageMetadata | null {\n const spec = manifest.storage;\n if (!spec) return null;\n\n const buckets = normalizeBuckets(spec.buckets);\n if (buckets.length === 0) return null;\n const [defaultBucket] = buckets;\n if (!defaultBucket) return null;\n\n if (spec.provider === 'supabase') {\n return {\n provider: 'supabase',\n bucketsCsv: buckets.join(','),\n defaultBucket,\n };\n }\n\n if (spec.provider === 'auto') {\n const shouldResolveToSupabase =\n manifest.database?.provider === 'supabase' || manifest.auth?.provider === 'supabase';\n\n if (!shouldResolveToSupabase) return null;\n\n return {\n provider: 'supabase',\n bucketsCsv: buckets.join(','),\n defaultBucket,\n };\n }\n\n return null;\n}\n\nfunction resolveSupabaseOAuthProviders(\n manifest: InfraManifestInput,\n): readonly SupabaseOAuthProviderRuntime[] {\n const oauth = manifest.auth?.oauth;\n if (!oauth?.enabled) return [];\n const callbackRoute = normalizeOAuthCallbackRoute(oauth.callbackRoute);\n\n return oauth.providers\n .filter((provider) => provider.enabled !== false)\n .map((provider) => {\n const id = provider.id.trim();\n const credentialsRef = provider.credentialsRef?.trim();\n if (!credentialsRef) {\n throw new Error(`OAuth provider \"${id}\" is enabled but does not define credentialsRef.`);\n }\n\n const envPrefix = id\n .toUpperCase()\n .replace(/[^A-Z0-9]+/gu, '_')\n .replace(/^_+|_+$/gu, '');\n if (!envPrefix) {\n throw new Error(`OAuth provider \"${id}\" cannot be mapped to GoTrue environment keys.`);\n }\n\n return {\n id,\n envPrefix,\n credentialsRef,\n callbackRoute,\n };\n });\n}\n\nfunction normalizeOAuthCallbackRoute(rawRoute: string | undefined): string {\n const trimmedRoute = rawRoute?.trim();\n const route = trimmedRoute && trimmedRoute.length > 0 ? trimmedRoute : '/auth/callback';\n const withLeadingSlash = route.startsWith('/') ? route : `/${route}`;\n return withLeadingSlash.replace(/\\/+/gu, '/');\n}\n\nfunction normalizeBuckets(rawBuckets: readonly string[]): string[] {\n const normalized: string[] = [];\n const seen = new Set<string>();\n\n for (const raw of rawBuckets) {\n const bucket = raw.trim();\n if (!bucket) continue;\n if (seen.has(bucket)) continue;\n seen.add(bucket);\n normalized.push(bucket);\n }\n\n return normalized;\n}\n\nfunction getKustomizationManifest(args: {\n namespaceResources: string[];\n appRuntimeEnabled: boolean;\n supabaseEnabled: boolean;\n extraResources: string[];\n}): string {\n const supabaseResources = args.supabaseEnabled\n ? [\n 'supabase/postgres.init.configmap.yaml',\n 'supabase/postgres.pvc.yaml',\n 'supabase/postgres.yaml',\n 'supabase/auth.yaml',\n 'supabase/rest.yaml',\n 'supabase/realtime.yaml',\n 'supabase/imgproxy.yaml',\n 'supabase/storage.yaml',\n 'supabase/meta.yaml',\n 'supabase/gateway.yaml',\n 'supabase/studio.yaml',\n ]\n : [];\n const resources = [\n ...args.namespaceResources,\n ...(args.appRuntimeEnabled\n ? ['app.configmap.yaml', 'app/deployment.yaml', 'app/service.yaml']\n : []),\n ...supabaseResources,\n ...args.extraResources,\n ];\n const resourceLines = resources.map((resource) => ` - ${resource}`).join('\\n');\n\n return `apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nresources:\n${resourceLines}\n`;\n}\n\nfunction getAppDeploymentManifest(defaultAppImage: string): string {\n return `apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: app-runtime\n namespace: ${APP_NAMESPACE}\n labels:\n app.kubernetes.io/name: app-runtime\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: app-runtime\n template:\n metadata:\n labels:\n app.kubernetes.io/name: app-runtime\n spec:\n containers:\n - name: app\n image: ${defaultAppImage}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 8080\n name: http\n envFrom:\n - configMapRef:\n name: app-infra-config\n - configMapRef:\n name: app-runtime-auth-env\n optional: true\n - configMapRef:\n name: app-runtime-storage-env\n optional: true\n - secretRef:\n name: supabase-public-runtime\n optional: true\n readinessProbe:\n httpGet:\n path: /\n port: http\n initialDelaySeconds: 5\n periodSeconds: 10\n livenessProbe:\n httpGet:\n path: /\n port: http\n initialDelaySeconds: 15\n periodSeconds: 20\n`;\n}\n\nfunction getAppServiceManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: app-runtime\n namespace: ${APP_NAMESPACE}\n labels:\n app.kubernetes.io/name: app-runtime\nspec:\n type: ClusterIP\n selector:\n app.kubernetes.io/name: app-runtime\n ports:\n - name: http\n port: 80\n targetPort: http\n`;\n}\n\nfunction getSupabaseResourceFiles(k8sRoot: string): GeneratedInfrastructureFile[] {\n return [\n {\n path: `${k8sRoot}/supabase/bootstrap.sql`,\n content: getSupabaseBootstrapSql(),\n },\n {\n path: `${k8sRoot}/supabase/postgres.init.configmap.yaml`,\n content: getSupabasePostgresInitConfigMap(),\n },\n {\n path: `${k8sRoot}/supabase/postgres.pvc.yaml`,\n content: getSupabasePvcManifest('supabase-postgres-data', '20Gi'),\n },\n {\n path: `${k8sRoot}/supabase/postgres.yaml`,\n content: getSupabasePostgresManifest(),\n },\n {\n path: `${k8sRoot}/supabase/auth.yaml`,\n content: getSupabaseAuthManifest(),\n },\n {\n path: `${k8sRoot}/supabase/rest.yaml`,\n content: getSupabaseRestManifest(),\n },\n {\n path: `${k8sRoot}/supabase/realtime.yaml`,\n content: getSupabaseRealtimeManifest(),\n },\n {\n path: `${k8sRoot}/supabase/storage.yaml`,\n content: getSupabaseStorageManifest(),\n },\n {\n path: `${k8sRoot}/supabase/imgproxy.yaml`,\n content: getSupabaseImgproxyManifest(),\n },\n {\n path: `${k8sRoot}/supabase/meta.yaml`,\n content: getSupabaseMetaManifest(),\n },\n {\n path: `${k8sRoot}/supabase/gateway.template.yml`,\n content: getSupabaseGatewayTemplate(),\n },\n {\n path: `${k8sRoot}/supabase/kong-entrypoint.sh`,\n content: getSupabaseKongEntrypointScript(),\n executable: true,\n },\n {\n path: `${k8sRoot}/supabase/gateway.yaml`,\n content: getSupabaseGatewayManifest(),\n },\n {\n path: `${k8sRoot}/supabase/studio.yaml`,\n content: getSupabaseStudioManifest(),\n },\n ];\n}\n\nfunction getSupabaseBootstrapSql(): string {\n return `-- Generated from the official Supabase self-hosting Docker database bootstrap contract.\n-- Applied by scripts/up.sh after Postgres is ready and before Supabase services start.\n\\\\set pgpass \\`echo \"$POSTGRES_PASSWORD\"\\`\n\\\\set jwt_secret \\`echo \"$JWT_SECRET\"\\`\n\\\\set jwt_exp \\`echo \"$JWT_EXP\"\\`\n\nDO $$\nBEGIN\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'anon') THEN\n CREATE ROLE anon NOLOGIN NOINHERIT;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticated') THEN\n CREATE ROLE authenticated NOLOGIN NOINHERIT;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'service_role') THEN\n CREATE ROLE service_role NOLOGIN NOINHERIT BYPASSRLS;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'authenticator') THEN\n CREATE ROLE authenticator NOINHERIT LOGIN;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_admin') THEN\n CREATE ROLE supabase_admin LOGIN CREATEROLE CREATEDB REPLICATION BYPASSRLS;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_auth_admin') THEN\n CREATE ROLE supabase_auth_admin LOGIN CREATEROLE;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_storage_admin') THEN\n CREATE ROLE supabase_storage_admin LOGIN CREATEROLE;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'supabase_functions_admin') THEN\n CREATE ROLE supabase_functions_admin LOGIN CREATEROLE;\n END IF;\n IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = 'pgbouncer') THEN\n CREATE ROLE pgbouncer LOGIN;\n END IF;\nEND\n$$;\n\nALTER ROLE authenticator WITH PASSWORD :'pgpass';\nALTER ROLE pgbouncer WITH PASSWORD :'pgpass';\nALTER ROLE supabase_auth_admin WITH PASSWORD :'pgpass';\nALTER ROLE supabase_functions_admin WITH PASSWORD :'pgpass';\nALTER ROLE supabase_storage_admin WITH PASSWORD :'pgpass';\nALTER ROLE supabase_admin WITH PASSWORD :'pgpass';\n\nGRANT anon, authenticated, service_role TO authenticator;\nGRANT anon, authenticated, service_role TO supabase_storage_admin;\nGRANT postgres TO supabase_auth_admin;\nGRANT postgres TO supabase_storage_admin;\nGRANT postgres TO supabase_functions_admin;\nGRANT pg_monitor TO supabase_admin;\n\nCREATE SCHEMA IF NOT EXISTS auth AUTHORIZATION supabase_auth_admin;\nCREATE SCHEMA IF NOT EXISTS storage AUTHORIZATION supabase_storage_admin;\nCREATE SCHEMA IF NOT EXISTS graphql_public;\nCREATE SCHEMA IF NOT EXISTS _realtime AUTHORIZATION supabase_admin;\n\nGRANT USAGE ON SCHEMA public, graphql_public TO anon, authenticated, service_role;\nGRANT USAGE ON SCHEMA auth TO supabase_auth_admin;\nGRANT USAGE ON SCHEMA storage TO supabase_storage_admin, anon, authenticated, service_role;\nGRANT USAGE ON SCHEMA _realtime TO supabase_admin;\n\nALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO anon, authenticated, service_role;\nALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO anon, authenticated, service_role;\n\nALTER DATABASE postgres SET \"app.settings.jwt_secret\" TO :'jwt_secret';\nALTER DATABASE postgres SET \"app.settings.jwt_exp\" TO :'jwt_exp';\n\nSELECT 'CREATE DATABASE _supabase WITH OWNER supabase_admin'\nWHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '_supabase')\\\\gexec\n`;\n}\n\nfunction getSupabasePostgresInitConfigMap(): string {\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: supabase-postgres-init\n namespace: ${SUPABASE_NAMESPACE}\ndata:\n 99-ankhorage-local-dev-extensions.sql: |\n -- Local Minikube bootstrap for extension setup performed before runtime migrations.\n alter role postgres with superuser;\n grant pg_read_server_files to postgres;\n grant pg_read_server_files to supabase_admin;\n grant execute on function pg_read_file(text) to public;\n grant execute on function pg_read_file(text, bigint, bigint) to public;\n`;\n}\n\nfunction getSupabasePvcManifest(name: string, size: string): string {\n return `apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n name: ${name}\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n accessModes:\n - ReadWriteOnce\n resources:\n requests:\n storage: ${size}\n`;\n}\n\nfunction getSupabasePostgresManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: postgres\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-postgres\n ports:\n - name: postgres\n port: 5432\n targetPort: postgres\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: postgres\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-postgres\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-postgres\n spec:\n containers:\n - name: postgres\n image: ${SUPABASE_IMAGES.postgres}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 5432\n name: postgres\n env:\n - name: POSTGRES_USER\n value: postgres\n - name: POSTGRES_PASSWORD\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: POSTGRES_PASSWORD\n - name: PGPASSWORD\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: POSTGRES_PASSWORD\n - name: POSTGRES_DB\n value: postgres\n - name: PGDATABASE\n value: postgres\n - name: PGPORT\n value: \"5432\"\n - name: POSTGRES_PORT\n value: \"5432\"\n - name: POSTGRES_HOST\n value: /var/run/postgresql\n - name: JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: JWT_EXP\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: JWT_EXPIRY\n volumeMounts:\n - name: data\n mountPath: /var/lib/postgresql/data\n - name: init-scripts\n mountPath: /docker-entrypoint-initdb.d/99-ankhorage-local-dev-extensions.sql\n subPath: 99-ankhorage-local-dev-extensions.sql\n readinessProbe:\n exec:\n command: [\"pg_isready\", \"-U\", \"postgres\"]\n initialDelaySeconds: 15\n periodSeconds: 5\n livenessProbe:\n exec:\n command: [\"pg_isready\", \"-U\", \"postgres\"]\n initialDelaySeconds: 30\n periodSeconds: 10\n args:\n - postgres\n - -c\n - config_file=/etc/postgresql/postgresql.conf\n - -c\n - log_min_messages=fatal\n volumes:\n - name: data\n persistentVolumeClaim:\n claimName: supabase-postgres-data\n - name: init-scripts\n configMap:\n name: supabase-postgres-init\n`;\n}\n\nfunction getSupabaseAuthManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: auth\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-auth\n ports:\n - name: http\n port: 9999\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: auth\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-auth\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-auth\n spec:\n containers:\n - name: auth\n image: ${SUPABASE_IMAGES.auth}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 9999\n name: http\n env:\n - name: GOTRUE_API_HOST\n value: \"0.0.0.0\"\n - name: GOTRUE_API_PORT\n value: \"9999\"\n - name: API_EXTERNAL_URL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: API_EXTERNAL_URL\n - name: GOTRUE_SITE_URL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SITE_URL\n - name: GOTRUE_URI_ALLOW_LIST\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: ADDITIONAL_REDIRECT_URLS\n - name: GOTRUE_JWT_ISSUER\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: API_EXTERNAL_URL\n - name: GOTRUE_DB_DRIVER\n value: postgres\n - name: GOTRUE_DB_DATABASE_URL\n value: \"postgres://supabase_auth_admin:$(POSTGRES_PASSWORD)@postgres.${SUPABASE_NAMESPACE}.svc.cluster.local:5432/postgres?search_path=auth&sslmode=disable\"\n - name: GOTRUE_JWT_AUD\n value: authenticated\n - name: GOTRUE_JWT_DEFAULT_GROUP_NAME\n value: authenticated\n - name: GOTRUE_JWT_ADMIN_ROLES\n value: service_role\n - name: GOTRUE_JWT_EXP\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: JWT_EXPIRY\n - name: GOTRUE_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: GOTRUE_EXTERNAL_EMAIL_ENABLED\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: ENABLE_EMAIL_SIGNUP\n - name: GOTRUE_MAILER_AUTOCONFIRM\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: ENABLE_EMAIL_AUTOCONFIRM\n - name: GOTRUE_SMTP_ADMIN_EMAIL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SMTP_ADMIN_EMAIL\n - name: GOTRUE_SMTP_HOST\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SMTP_HOST\n - name: GOTRUE_SMTP_PORT\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SMTP_PORT\n - name: GOTRUE_SMTP_USER\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SMTP_USER\n - name: GOTRUE_SMTP_PASS\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SMTP_PASS\n - name: GOTRUE_SMTP_SENDER_NAME\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SMTP_SENDER_NAME\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n - configMapRef:\n name: supabase-runtime-config\n readinessProbe:\n httpGet:\n path: /health\n port: http\n initialDelaySeconds: 10\n periodSeconds: 10\n`;\n}\n\nfunction getSupabaseRestManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: rest\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-rest\n ports:\n - name: http\n port: 3000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: rest\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-rest\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-rest\n spec:\n containers:\n - name: rest\n image: ${SUPABASE_IMAGES.rest}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 3000\n name: http\n env:\n - name: PGRST_DB_URI\n value: \"postgres://authenticator:$(POSTGRES_PASSWORD)@postgres.${SUPABASE_NAMESPACE}.svc.cluster.local:5432/postgres\"\n - name: PGRST_DB_SCHEMAS\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: PGRST_DB_SCHEMAS\n - name: PGRST_DB_ANON_ROLE\n value: anon\n - name: PGRST_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: PGRST_DB_USE_LEGACY_GUCS\n value: \"false\"\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n - configMapRef:\n name: supabase-runtime-config\n`;\n}\n\nfunction getSupabaseRealtimeManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: realtime\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-realtime\n ports:\n - name: http\n port: 4000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: realtime\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-realtime\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-realtime\n spec:\n containers:\n - name: realtime\n image: ${SUPABASE_IMAGES.realtime}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 4000\n name: http\n env:\n - name: PORT\n value: \"4000\"\n - name: DB_HOST\n value: \"postgres.${SUPABASE_NAMESPACE}.svc.cluster.local\"\n - name: DB_PORT\n value: \"5432\"\n - name: DB_NAME\n value: postgres\n - name: DB_USER\n value: supabase_admin\n - name: DB_PASSWORD\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: POSTGRES_PASSWORD\n - name: API_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: SECRET_KEY_BASE\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SECRET_KEY_BASE\n - name: DB_AFTER_CONNECT_QUERY\n value: \"SET search_path TO _realtime\"\n - name: DB_ENC_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: REALTIME_DB_ENC_KEY\n - name: METRICS_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: APP_NAME\n value: realtime\n - name: SEED_SELF_HOST\n value: \"true\"\n - name: RUN_JANITOR\n value: \"true\"\n - name: DISABLE_HEALTHCHECK_LOGGING\n value: \"true\"\n`;\n}\n\nfunction getSupabaseStorageManifest(): string {\n return `${getSupabasePvcManifest('supabase-storage-data', '10Gi')}\n---\napiVersion: v1\nkind: Service\nmetadata:\n name: storage\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-storage\n ports:\n - name: http\n port: 5000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: storage\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-storage\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-storage\n spec:\n containers:\n - name: storage\n image: ${SUPABASE_IMAGES.storage}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 5000\n name: http\n env:\n - name: ANON_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_ANON_KEY\n - name: SERVICE_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_SERVICE_ROLE_KEY\n - name: AUTH_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n - name: DATABASE_URL\n value: \"postgres://supabase_storage_admin:$(POSTGRES_PASSWORD)@postgres.${SUPABASE_NAMESPACE}.svc.cluster.local:5432/postgres?search_path=storage&sslmode=disable\"\n - name: POSTGREST_URL\n value: \"http://rest.${SUPABASE_NAMESPACE}.svc.cluster.local:3000\"\n - name: STORAGE_BACKEND\n value: file\n - name: STORAGE_PUBLIC_URL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SUPABASE_PUBLIC_URL\n - name: REQUEST_ALLOW_X_FORWARDED_PATH\n value: \"true\"\n - name: FILE_SIZE_LIMIT\n value: \"52428800\"\n - name: FILE_STORAGE_BACKEND_PATH\n value: /var/lib/storage\n - name: TENANT_ID\n value: stub\n - name: REGION\n value: local\n - name: GLOBAL_S3_BUCKET\n value: local\n - name: IMGPROXY_URL\n value: \"http://imgproxy.${SUPABASE_NAMESPACE}.svc.cluster.local:5001\"\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n - configMapRef:\n name: supabase-runtime-config\n volumeMounts:\n - name: storage\n mountPath: /var/lib/storage\n volumes:\n - name: storage\n persistentVolumeClaim:\n claimName: supabase-storage-data\n`;\n}\n\nfunction getSupabaseImgproxyManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: imgproxy\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-imgproxy\n ports:\n - name: http\n port: 5001\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: imgproxy\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-imgproxy\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-imgproxy\n spec:\n containers:\n - name: imgproxy\n image: ${SUPABASE_IMAGES.imgproxy}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 5001\n name: http\n env:\n - name: IMGPROXY_BIND\n value: \":5001\"\n`;\n}\n\nfunction getSupabaseMetaManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: meta\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-meta\n ports:\n - name: http\n port: 8080\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: meta\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-meta\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-meta\n spec:\n containers:\n - name: meta\n image: ${SUPABASE_IMAGES.meta}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 8080\n name: http\n env:\n - name: PG_META_PORT\n value: \"8080\"\n - name: PG_META_DB_HOST\n value: \"postgres.${SUPABASE_NAMESPACE}.svc.cluster.local\"\n - name: PG_META_DB_PORT\n value: \"5432\"\n - name: PG_META_DB_NAME\n value: postgres\n - name: PG_META_DB_USER\n value: postgres\n - name: PG_META_DB_PASSWORD\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: POSTGRES_PASSWORD\n - name: CRYPTO_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: PG_META_CRYPTO_KEY\n`;\n}\n\nfunction getSupabaseGatewayTemplate(): string {\n return `_format_version: \"2.1\"\n_transform: true\n\nconsumers:\n - username: DASHBOARD\n - username: anon\n keyauth_credentials:\n - key: $SUPABASE_ANON_KEY\n - key: $SUPABASE_PUBLISHABLE_KEY\n - username: service_role\n keyauth_credentials:\n - key: $SUPABASE_SERVICE_KEY\n - key: $SUPABASE_SECRET_KEY\n\nacls:\n - consumer: anon\n group: anon\n - consumer: service_role\n group: admin\n\nbasicauth_credentials:\n - consumer: DASHBOARD\n username: \"$DASHBOARD_USERNAME\"\n password: \"$DASHBOARD_PASSWORD\"\n\nservices:\n - name: auth-v1-open\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/verify\n routes:\n - name: auth-v1-open\n strip_path: true\n paths: [/auth/v1/verify]\n plugins:\n - name: cors\n - name: auth-v1-open-callback\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/callback\n routes:\n - name: auth-v1-open-callback\n strip_path: true\n paths: [/auth/v1/callback]\n plugins:\n - name: cors\n - name: auth-v1-open-authorize\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/authorize\n routes:\n - name: auth-v1-open-authorize\n strip_path: true\n paths: [/auth/v1/authorize]\n plugins:\n - name: cors\n - name: auth-v1-open-jwks\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/.well-known/jwks.json\n routes:\n - name: auth-v1-open-jwks\n strip_path: true\n paths: [/auth/v1/.well-known/jwks.json]\n plugins:\n - name: cors\n - name: auth-v1\n url: http://auth.${SUPABASE_NAMESPACE}.svc.cluster.local:9999/\n routes:\n - name: auth-v1-all\n strip_path: true\n paths: [/auth/v1/]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: rest-v1\n url: http://rest.${SUPABASE_NAMESPACE}.svc.cluster.local:3000/\n routes:\n - name: rest-v1-all\n strip_path: true\n paths: [/rest/v1/]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: graphql-v1\n url: http://rest.${SUPABASE_NAMESPACE}.svc.cluster.local:3000/rpc/graphql\n routes:\n - name: graphql-v1-all\n strip_path: true\n paths: [/graphql/v1]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"Content-Profile: graphql_public\"\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: realtime-v1-ws\n url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/socket\n protocol: ws\n routes:\n - name: realtime-v1-ws\n strip_path: true\n paths: [/realtime/v1/]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"x-api-key:$LUA_RT_WS_EXPR\"\n replace:\n querystring:\n - \"apikey:$LUA_RT_WS_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: realtime-v1-rest-openapi\n url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/api/openapi\n protocol: http\n routes:\n - name: realtime-v1-rest-openapi\n strip_path: true\n paths: [/realtime/v1/api/openapi]\n plugins:\n - name: request-termination\n config:\n status_code: 403\n message: \"Access is forbidden.\"\n - name: realtime-v1-rest-tenants\n url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/api/tenants\n protocol: http\n routes:\n - name: realtime-v1-rest-tenants\n strip_path: true\n paths: [/realtime/v1/api/tenants]\n plugins:\n - name: request-termination\n config:\n status_code: 403\n message: \"Access is forbidden.\"\n - name: realtime-v1-rest\n url: http://realtime.${SUPABASE_NAMESPACE}.svc.cluster.local:4000/api\n protocol: http\n routes:\n - name: realtime-v1-rest\n strip_path: true\n paths: [/realtime/v1/api]\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: request-transformer\n config:\n add:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin, anon]\n - name: storage-v1\n url: http://storage.${SUPABASE_NAMESPACE}.svc.cluster.local:5000/\n routes:\n - name: storage-v1-all\n strip_path: true\n paths: [/storage/v1/]\n plugins:\n - name: cors\n - name: request-transformer\n config:\n add:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n replace:\n headers:\n - \"Authorization: $LUA_AUTH_EXPR\"\n - name: post-function\n config:\n access:\n - |\n local auth = kong.request.get_header(\"authorization\")\n if auth == nil or auth == \"\" or auth:find(\"^%s*$\") then\n kong.service.request.clear_header(\"authorization\")\n end\n - name: meta\n url: http://meta.${SUPABASE_NAMESPACE}.svc.cluster.local:8080/\n routes:\n - name: meta-all\n strip_path: true\n paths: [/pg/]\n plugins:\n - name: key-auth\n config:\n hide_credentials: false\n - name: acl\n config:\n hide_groups_header: true\n allow: [admin]\n - name: dashboard\n url: http://studio.${SUPABASE_NAMESPACE}.svc.cluster.local:3000/\n routes:\n - name: dashboard-all\n strip_path: true\n paths: [/]\n plugins:\n - name: cors\n - name: basic-auth\n config:\n hide_credentials: true\n`;\n}\n\nfunction getSupabaseKongEntrypointScript(): string {\n return `#!/bin/sh\nset -eu\n\nif [ -n \"\\${SUPABASE_SECRET_KEY:-}\" ] && [ -n \"\\${SUPABASE_PUBLISHABLE_KEY:-}\" ]; then\n export LUA_AUTH_EXPR=\"\\\\$((headers.authorization ~= nil and headers.authorization:sub(1, 10) ~= 'Bearer sb_' and headers.authorization) or (headers.apikey == '\\${SUPABASE_SECRET_KEY}' and 'Bearer \\${SERVICE_ROLE_KEY_ASYMMETRIC:-}') or (headers.apikey == '\\${SUPABASE_PUBLISHABLE_KEY}' and 'Bearer \\${ANON_KEY_ASYMMETRIC:-}') or headers.apikey)\"\n export LUA_RT_WS_EXPR=\"\\\\$((query_params.apikey == '\\${SUPABASE_SECRET_KEY}' and '\\${SERVICE_ROLE_KEY_ASYMMETRIC:-}') or (query_params.apikey == '\\${SUPABASE_PUBLISHABLE_KEY}' and '\\${ANON_KEY_ASYMMETRIC:-}') or query_params.apikey)\"\nelse\n export LUA_AUTH_EXPR=\"\\\\$((headers.authorization ~= nil and headers.authorization:sub(1, 10) ~= 'Bearer sb_' and headers.authorization) or headers.apikey)\"\n export LUA_RT_WS_EXPR=\"\\\\$(query_params.apikey)\"\nfi\n\nawk '{\n result = \"\"\n rest = $0\n while (match(rest, /\\\\$[A-Za-z_][A-Za-z_0-9]*/)) {\n varname = substr(rest, RSTART + 1, RLENGTH - 1)\n if (varname in ENVIRON) {\n result = result substr(rest, 1, RSTART - 1) ENVIRON[varname]\n } else {\n result = result substr(rest, 1, RSTART + RLENGTH - 1)\n }\n rest = substr(rest, RSTART + RLENGTH)\n }\n print result rest\n}' /home/kong/temp.yml > \"\\${KONG_DECLARATIVE_CONFIG}\"\n\nsed -i '/^[[:space:]]*- key:[[:space:]]*$/d' \"\\${KONG_DECLARATIVE_CONFIG}\"\n\nexec /entrypoint.sh kong docker-start\n`;\n}\n\nfunction getSupabaseGatewayManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: gateway\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-gateway\n ports:\n - name: http\n port: 8000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: gateway\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-gateway\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-gateway\n spec:\n containers:\n - name: gateway\n image: ${SUPABASE_IMAGES.gateway}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 8000\n name: http\n env:\n - name: KONG_DATABASE\n value: \"off\"\n - name: KONG_DECLARATIVE_CONFIG\n value: /usr/local/kong/kong.yml\n - name: KONG_ROUTER_FLAVOR\n value: expressions\n - name: KONG_DNS_ORDER\n value: LAST,A,CNAME\n - name: KONG_DNS_NOT_FOUND_TTL\n value: \"1\"\n - name: KONG_PLUGINS\n value: request-transformer,cors,key-auth,acl,basic-auth,request-termination,ip-restriction,post-function\n - name: KONG_PROXY_LISTEN\n value: \"0.0.0.0:8000\"\n - name: SUPABASE_SERVICE_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_SERVICE_ROLE_KEY\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n volumeMounts:\n - name: config\n mountPath: /home/kong/temp.yml\n subPath: temp.yml\n readOnly: true\n - name: entrypoint\n mountPath: /home/kong/kong-entrypoint.sh\n subPath: kong-entrypoint.sh\n readOnly: true\n command: [\"/bin/sh\", \"/home/kong/kong-entrypoint.sh\"]\n readinessProbe:\n exec:\n command: [\"kong\", \"health\"]\n initialDelaySeconds: 10\n periodSeconds: 10\n volumes:\n - name: config\n configMap:\n name: supabase-gateway-config\n - name: entrypoint\n configMap:\n name: supabase-kong-entrypoint\n defaultMode: 0755\n`;\n}\n\nfunction getSupabaseStudioManifest(): string {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: studio\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n selector:\n app.kubernetes.io/name: supabase-studio\n ports:\n - name: http\n port: 3000\n targetPort: http\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: studio\n namespace: ${SUPABASE_NAMESPACE}\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: supabase-studio\n template:\n metadata:\n labels:\n app.kubernetes.io/name: supabase-studio\n spec:\n containers:\n - name: studio\n image: ${SUPABASE_IMAGES.studio}\n imagePullPolicy: IfNotPresent\n ports:\n - containerPort: 3000\n name: http\n env:\n - name: HOSTNAME\n value: \"0.0.0.0\"\n - name: STUDIO_PG_META_URL\n value: \"http://meta.${SUPABASE_NAMESPACE}.svc.cluster.local:8080\"\n - name: SUPABASE_URL\n value: \"http://gateway.${SUPABASE_NAMESPACE}.svc.cluster.local:8000\"\n - name: SUPABASE_PUBLIC_URL\n valueFrom:\n configMapKeyRef:\n name: supabase-runtime-config\n key: SUPABASE_PUBLIC_URL\n - name: SUPABASE_ANON_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_ANON_KEY\n - name: SUPABASE_SERVICE_KEY\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: SUPABASE_SERVICE_ROLE_KEY\n - name: AUTH_JWT_SECRET\n valueFrom:\n secretKeyRef:\n name: supabase-runtime-secrets\n key: JWT_SECRET\n envFrom:\n - secretRef:\n name: supabase-runtime-secrets\n - configMapRef:\n name: supabase-runtime-config\n`;\n}\n\nfunction getUpScript(args: {\n appSlug: string;\n appRuntimeEnabled: boolean;\n defaultAppImage: string;\n supabaseKubernetesEnabled: boolean;\n profileModel: ResolvedProfileModel;\n secretStoreProvider: string;\n supabaseHostPorts: SupabaseHostPorts;\n oauthProviders: readonly SupabaseOAuthProviderRuntime[];\n providerLifecycle: readonly MinikubeProviderLifecycle[];\n}): string {\n const {\n appSlug,\n appRuntimeEnabled,\n defaultAppImage,\n supabaseKubernetesEnabled,\n profileModel,\n secretStoreProvider,\n supabaseHostPorts,\n oauthProviders,\n providerLifecycle,\n } = args;\n const oauthEnvDefaults = getOAuthScriptEnvDefaults(oauthProviders);\n const oauthRuntimeSecretLines = getOAuthRuntimeSecretLines(oauthProviders);\n const oauthValidation = getOAuthRuntimeValidationScript(oauthProviders);\n const oauthCallbackRoute = getSupabaseOAuthCallbackRoute(oauthProviders);\n const providerLifecycleStageScripts = getProviderLifecycleStageScripts(providerLifecycle);\n const oauthVaultResolution = getOAuthVaultResolutionScript({\n appSlug,\n oauthProviders,\n secretStoreProvider,\n });\n const supabaseMigrationCommand = getSupabaseMigrationCommandScript();\n const disabledAppRuntimeReconciliation = appRuntimeEnabled\n ? ''\n : `reconcile_disabled_app_runtime() {\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" delete deployment/app-runtime service/app-runtime configmap/app-infra-config --ignore-not-found\n \"\\${PORT_FORWARD_SCRIPT}\" stop obsolete\n}\n`;\n const reconcileDisabledAppRuntime = appRuntimeEnabled ? '' : 'reconcile_disabled_app_runtime';\n\n return `#!/usr/bin/env bash\nset -Eeuo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nK8S_DIR=\"\\${ROOT_DIR}/k8s\"\nBUILD_SCRIPT=\"\\${SCRIPT_DIR}/build-app-image.sh\"\nPORT_FORWARD_SCRIPT=\"\\${SCRIPT_DIR}/port-forward.sh\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-}\"\nDRIVER=\"\\${MINIKUBE_DRIVER:-}\"\nAPP_NAMESPACE=\"${APP_NAMESPACE}\"\nSUPABASE_NAMESPACE=\"${SUPABASE_NAMESPACE}\"\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nAPP_RUNTIME_ENABLED=\"${appRuntimeEnabled ? 'true' : 'false'}\"\nAPP_BUILD_ENABLED=\"\\${APP_BUILD_ENABLED:-}\"\nAPP_SOURCE_DIR=\"\\${APP_SOURCE_DIR:-}\"\nAPP_WEB_EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR:-}\"\nAPP_IMAGE=\"\\${APP_IMAGE:-}\"\nAPP_IMAGE_SYNC_STRATEGY=\"\\${APP_IMAGE_SYNC_STRATEGY:-}\"\nAPP_REPLICAS=\"\\${APP_REPLICAS:-}\"\nAPP_FORCE_ROLLOUT_RESTART=\"\\${APP_FORCE_ROLLOUT_RESTART:-}\"\nAPP_IMAGE_PULL_SECRET_NAME=\"\\${APP_IMAGE_PULL_SECRET_NAME:-}\"\nAPP_IMAGE_PULL_SECRET_SERVER=\"\\${APP_IMAGE_PULL_SECRET_SERVER:-}\"\nAPP_IMAGE_PULL_SECRET_USERNAME=\"\\${APP_IMAGE_PULL_SECRET_USERNAME:-}\"\nAPP_IMAGE_PULL_SECRET_PASSWORD=\"\\${APP_IMAGE_PULL_SECRET_PASSWORD:-}\"\nAPP_IMAGE_PULL_SECRET_EMAIL=\"\\${APP_IMAGE_PULL_SECRET_EMAIL:-}\"\nAPP_PORT_FORWARD_LOCAL_PORT=\"\\${APP_PORT_FORWARD_LOCAL_PORT:-}\"\nSUPABASE_GATEWAY_FORWARD_LOCAL_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-}\"\nSUPABASE_DB_FORWARD_LOCAL_PORT=\"\\${SUPABASE_DB_FORWARD_LOCAL_PORT:-}\"\nSUPABASE_DB_URL=\"\\${SUPABASE_DB_URL:-}\"\nSUPABASE_PROFILE_ENABLED=\"${profileModel.enabled ? 'true' : 'false'}\"\nSUPABASE_PROFILE_RECONCILE_FILE=\"\\${ROOT_DIR}/supabase/generated/auth_profiles.sql\"\n\nrequire_command() {\n if ! command -v \"\\${1}\" >/dev/null 2>&1; then\n echo \"\\${1} is required but not installed.\"\n exit 1\n fi\n}\n\nload_env_file_preserving_process_env() {\n local line trimmed key value current\n if [[ ! -f \"\\${ROOT_DIR}/.env\" ]]; then\n return 0\n fi\n\n while IFS= read -r line || [[ -n \"\\${line}\" ]]; do\n trimmed=\"$(printf '%s' \"\\${line}\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')\"\n if [[ -z \"\\${trimmed}\" || \"\\${trimmed}\" == \\\\#* || \"\\${trimmed}\" != *=* ]]; then\n continue\n fi\n\n key=\"\\${trimmed%%=*}\"\n value=\"\\${trimmed#*=}\"\n key=\"\\${key//[[:space:]]/}\"\n value=\"$(printf '%s' \"\\${value}\" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')\"\n value=\"\\${value%\\\\\"}\"\n value=\"\\${value#\\\\\"}\"\n value=\"\\${value%\\\\'}\"\n value=\"\\${value#\\\\'}\"\n current=\"\\${!key:-}\"\n if [[ -n \"\\${current}\" ]]; then\n continue\n fi\n export \"\\${key}=\\${value}\"\n done < \"\\${ROOT_DIR}/.env\"\n}\n\nenv_file_value() {\n local key=\"\\${1}\"\n if [[ ! -f \"\\${ROOT_DIR}/.env\" ]]; then\n return 0\n fi\n awk -F= -v key=\"\\${key}\" '$1 == key { value = substr($0, index($0, \"=\") + 1) } END { print value }' \"\\${ROOT_DIR}/.env\"\n}\n\nenv_file_has_key() {\n local key=\"\\${1}\"\n if [[ ! -f \"\\${ROOT_DIR}/.env\" ]]; then\n return 1\n fi\n awk -F= -v key=\"\\${key}\" '$1 == key { found = 1 } END { exit found ? 0 : 1 }' \"\\${ROOT_DIR}/.env\"\n}\n\nwrite_env_value() {\n local key=\"\\${1}\"\n local value=\"\\${2}\"\n local tmp_env\n mkdir -p \"\\${ROOT_DIR}\"\n touch \"\\${ROOT_DIR}/.env\"\n tmp_env=\"$(mktemp)\"\n awk -F= -v key=\"\\${key}\" -v value=\"\\${value}\" '\n $1 == key {\n print key \"=\" value\n found = 1\n next\n }\n { print }\n END {\n if (!found) print key \"=\" value\n }\n ' \"\\${ROOT_DIR}/.env\" > \"\\${tmp_env}\"\n mv \"\\${tmp_env}\" \"\\${ROOT_DIR}/.env\"\n}\n\nwrite_key_value_file_value() {\n local file_path=\"\\${1}\"\n local key=\"\\${2}\"\n local value=\"\\${3}\"\n local tmp_env\n mkdir -p \"$(dirname \"\\${file_path}\")\"\n touch \"\\${file_path}\"\n tmp_env=\"$(mktemp)\"\n awk -F= -v key=\"\\${key}\" -v value=\"\\${value}\" '\n $1 == key {\n print key \"=\" value\n found = 1\n next\n }\n { print }\n END {\n if (!found) print key \"=\" value\n }\n ' \"\\${file_path}\" > \"\\${tmp_env}\"\n mv \"\\${tmp_env}\" \"\\${file_path}\"\n}\n\nsync_app_public_supabase_env() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n if [[ -z \"\\${APP_SOURCE_DIR:-}\" ]]; then\n echo \"APP_SOURCE_DIR is required to write app Supabase public environment.\"\n exit 1\n fi\n\n local app_env_file=\"\\${APP_SOURCE_DIR}/.env.local\"\n write_key_value_file_value \"\\${app_env_file}\" \"EXPO_PUBLIC_SUPABASE_URL\" \"\\${EXPO_PUBLIC_SUPABASE_URL}\"\n write_key_value_file_value \"\\${app_env_file}\" \"EXPO_PUBLIC_SUPABASE_ANON_KEY\" \"\\${EXPO_PUBLIC_SUPABASE_ANON_KEY}\"\n}\n\nset_required_env_default() {\n local key=\"\\${1}\"\n local value=\"\\${2}\"\n local current=\"\\${!key:-}\"\n if [[ -n \"\\${current}\" ]]; then\n write_env_value \"\\${key}\" \"\\${current}\"\n return 0\n fi\n\n current=\"$(env_file_value \"\\${key}\")\"\n if [[ -n \"\\${current}\" ]]; then\n export \"\\${key}=\\${current}\"\n return 0\n fi\n\n write_env_value \"\\${key}\" \"\\${value}\"\n export \"\\${key}=\\${value}\"\n}\n\nset_optional_env_default() {\n local key=\"\\${1}\"\n local value=\"\\${2}\"\n local current=\"\\${!key:-}\"\n if env_file_has_key \"\\${key}\"; then\n export \"\\${key}=\\${current}\"\n return 0\n fi\n if [[ -n \"\\${current}\" ]]; then\n write_env_value \"\\${key}\" \"\\${current}\"\n return 0\n fi\n write_env_value \"\\${key}\" \"\\${value}\"\n export \"\\${key}=\\${value}\"\n}\n\nset_env_default() {\n set_required_env_default \"\\${1}\" \"\\${2}\"\n}\n\nderive_additional_redirect_urls() {\n local callback_route=\"${oauthCallbackRoute}\"\n local callback_path=\"\\${callback_route#/}\"\n local site_url_without_slash=\"\\${SITE_URL%/}\"\n local urls=\"\\${site_url_without_slash},\\${site_url_without_slash}/\\${callback_path}\"\n if [[ -n \"\\${OAUTH_NATIVE_REDIRECT_URLS:-}\" ]]; then\n urls=\"\\${urls},\\${OAUTH_NATIVE_REDIRECT_URLS}\"\n fi\n printf '%s' \"\\${urls}\"\n}\n\nrandom_base64() {\n openssl rand -base64 \"\\${1}\" | tr -d '\\\\n'\n}\n\nrandom_hex() {\n openssl rand -hex \"\\${1}\" | tr -d '\\\\n'\n}\n\nbase64url() {\n openssl base64 -A | tr '+/' '-_' | tr -d '='\n}\n\ngenerate_supabase_jwt() {\n local role=\"\\${1}\"\n local iat exp header payload signature\n iat=\"$(date +%s)\"\n exp=\"$((iat + 315360000))\"\n header=\"$(printf '{\"alg\":\"HS256\",\"typ\":\"JWT\"}' | base64url)\"\n payload=\"$(printf '{\"role\":\"%s\",\"iss\":\"supabase-demo\",\"iat\":%s,\"exp\":%s}' \"\\${role}\" \"\\${iat}\" \"\\${exp}\" | base64url)\"\n signature=\"$(printf '%s.%s' \"\\${header}\" \"\\${payload}\" | openssl dgst -binary -sha256 -hmac \"\\${JWT_SECRET}\" | base64url)\"\n printf '%s.%s.%s' \"\\${header}\" \"\\${payload}\" \"\\${signature}\"\n}\n\nensure_supabase_runtime_env() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n require_command openssl\n\n set_required_env_default POSTGRES_PASSWORD \"$(random_hex 32)\"\n set_required_env_default JWT_SECRET \"$(random_base64 48)\"\n set_required_env_default SUPABASE_ANON_KEY \"$(generate_supabase_jwt anon)\"\n set_required_env_default SUPABASE_SERVICE_ROLE_KEY \"$(generate_supabase_jwt service_role)\"\n set_required_env_default DASHBOARD_USERNAME \"supabase\"\n set_required_env_default DASHBOARD_PASSWORD \"$(random_base64 24)\"\n set_required_env_default SECRET_KEY_BASE \"$(random_base64 48)\"\n set_required_env_default REALTIME_DB_ENC_KEY \"$(random_hex 8)\"\n set_required_env_default PG_META_CRYPTO_KEY \"$(random_base64 32)\"\n set_required_env_default S3_PROTOCOL_ACCESS_KEY_ID \"$(random_hex 16)\"\n set_required_env_default S3_PROTOCOL_ACCESS_KEY_SECRET \"$(random_hex 32)\"\n set_required_env_default JWT_EXPIRY \"3600\"\n set_required_env_default SUPABASE_GATEWAY_FORWARD_LOCAL_PORT \"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}\"\n set_required_env_default APP_PORT_FORWARD_LOCAL_PORT \"\\${APP_PORT_FORWARD_LOCAL_PORT:-${supabaseHostPorts.app}}\"\n set_required_env_default SUPABASE_PUBLIC_URL \"http://127.0.0.1:\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT}\"\n set_required_env_default API_EXTERNAL_URL \"\\${SUPABASE_PUBLIC_URL}/auth/v1\"\n set_required_env_default SITE_URL \"http://127.0.0.1:\\${APP_PORT_FORWARD_LOCAL_PORT}\"\n export OAUTH_NATIVE_REDIRECT_URLS=\"\\${OAUTH_NATIVE_REDIRECT_URLS:-}\"\n set_required_env_default ADDITIONAL_REDIRECT_URLS \"$(derive_additional_redirect_urls)\"\n set_required_env_default ENABLE_EMAIL_SIGNUP \"true\"\n set_required_env_default ENABLE_EMAIL_AUTOCONFIRM \"true\"\n set_required_env_default SMTP_ADMIN_EMAIL \"admin@example.com\"\n set_required_env_default SMTP_HOST \"localhost\"\n set_required_env_default SMTP_PORT \"2500\"\n set_optional_env_default SMTP_USER \"\"\n set_optional_env_default SMTP_PASS \"\"\n set_required_env_default SMTP_SENDER_NAME \"Ankhorage\"\n set_required_env_default PGRST_DB_SCHEMAS \"public,storage,graphql_public\"\n set_required_env_default PGRST_DB_MAX_ROWS \"1000\"\n set_required_env_default PGRST_DB_EXTRA_SEARCH_PATH \"public\"\n set_required_env_default GLOBAL_S3_BUCKET \"stub\"\n set_required_env_default STORAGE_TENANT_ID \"stub\"\n set_required_env_default REGION \"stub\"\n set_required_env_default SUPABASE_DB_FORWARD_LOCAL_PORT \"\\${SUPABASE_DB_FORWARD_LOCAL_PORT:-${supabaseHostPorts.db}}\"\n set_required_env_default SUPABASE_DB_URL \"postgres://postgres:\\${POSTGRES_PASSWORD}@127.0.0.1:\\${SUPABASE_DB_FORWARD_LOCAL_PORT}/postgres?sslmode=disable\"\n set_required_env_default EXPO_PUBLIC_SUPABASE_URL \"\\${SUPABASE_PUBLIC_URL}\"\n set_required_env_default EXPO_PUBLIC_SUPABASE_ANON_KEY \"\\${SUPABASE_ANON_KEY}\"\n${oauthEnvDefaults}\n}\n${oauthVaultResolution}\n\nsync_supabase_secrets() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n local tmp_runtime tmp_public\n tmp_runtime=\"$(mktemp)\"\n tmp_public=\"$(mktemp)\"\n trap 'rm -f \"\\${tmp_runtime}\" \"\\${tmp_public}\"' EXIT\n\n cat > \"\\${tmp_runtime}\" <<EOF\nPOSTGRES_PASSWORD=\\${POSTGRES_PASSWORD}\nJWT_SECRET=\\${JWT_SECRET}\nSUPABASE_ANON_KEY=\\${SUPABASE_ANON_KEY}\nSUPABASE_SERVICE_ROLE_KEY=\\${SUPABASE_SERVICE_ROLE_KEY}\nSUPABASE_PUBLISHABLE_KEY=\\${SUPABASE_PUBLISHABLE_KEY:-}\nSUPABASE_SECRET_KEY=\\${SUPABASE_SECRET_KEY:-}\nDASHBOARD_USERNAME=\\${DASHBOARD_USERNAME:-supabase}\nDASHBOARD_PASSWORD=\\${DASHBOARD_PASSWORD:-}\nSMTP_USER=\\${SMTP_USER:-}\nSMTP_PASS=\\${SMTP_PASS:-}\nSECRET_KEY_BASE=\\${SECRET_KEY_BASE}\nREALTIME_DB_ENC_KEY=\\${REALTIME_DB_ENC_KEY}\nPG_META_CRYPTO_KEY=\\${PG_META_CRYPTO_KEY}\nS3_PROTOCOL_ACCESS_KEY_ID=\\${S3_PROTOCOL_ACCESS_KEY_ID}\nS3_PROTOCOL_ACCESS_KEY_SECRET=\\${S3_PROTOCOL_ACCESS_KEY_SECRET}\n${oauthRuntimeSecretLines}\nEOF\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" create secret generic supabase-runtime-secrets --from-env-file=\"\\${tmp_runtime}\" --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" apply -f -\n\n cat > \"\\${tmp_public}\" <<EOF\nEXPO_PUBLIC_SUPABASE_URL=\\${EXPO_PUBLIC_SUPABASE_URL}\nEXPO_PUBLIC_SUPABASE_ANON_KEY=\\${EXPO_PUBLIC_SUPABASE_ANON_KEY}\nSUPABASE_URL=http://gateway.${SUPABASE_NAMESPACE}.svc.cluster.local:8000\nSUPABASE_ANON_KEY=\\${SUPABASE_ANON_KEY}\nEOF\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" create secret generic supabase-public-runtime --from-env-file=\"\\${tmp_public}\" --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" apply -f -\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" create configmap supabase-runtime-config \\\n --from-literal=SUPABASE_PUBLIC_URL=\"\\${SUPABASE_PUBLIC_URL}\" \\\n --from-literal=API_EXTERNAL_URL=\"\\${API_EXTERNAL_URL}\" \\\n --from-literal=SITE_URL=\"\\${SITE_URL}\" \\\n --from-literal=ADDITIONAL_REDIRECT_URLS=\"\\${ADDITIONAL_REDIRECT_URLS}\" \\\n --from-literal=JWT_EXPIRY=\"\\${JWT_EXPIRY}\" \\\n --from-literal=ENABLE_EMAIL_SIGNUP=\"\\${ENABLE_EMAIL_SIGNUP}\" \\\n --from-literal=ENABLE_EMAIL_AUTOCONFIRM=\"\\${ENABLE_EMAIL_AUTOCONFIRM}\" \\\n --from-literal=SMTP_ADMIN_EMAIL=\"\\${SMTP_ADMIN_EMAIL}\" \\\n --from-literal=SMTP_HOST=\"\\${SMTP_HOST}\" \\\n --from-literal=SMTP_PORT=\"\\${SMTP_PORT}\" \\\n --from-literal=SMTP_SENDER_NAME=\"\\${SMTP_SENDER_NAME}\" \\\n --from-literal=PGRST_DB_SCHEMAS=\"\\${PGRST_DB_SCHEMAS}\" \\\n --from-literal=PGRST_DB_MAX_ROWS=\"\\${PGRST_DB_MAX_ROWS}\" \\\n --from-literal=PGRST_DB_EXTRA_SEARCH_PATH=\"\\${PGRST_DB_EXTRA_SEARCH_PATH}\" \\\n --from-literal=GLOBAL_S3_BUCKET=\"\\${GLOBAL_S3_BUCKET}\" \\\n --from-literal=STORAGE_TENANT_ID=\"\\${STORAGE_TENANT_ID}\" \\\n --from-literal=REGION=\"\\${REGION}\" \\\n --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" apply -f -\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" create configmap supabase-gateway-config \\\n --from-file=temp.yml=\"\\${K8S_DIR}/supabase/gateway.template.yml\" \\\n --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" apply -f -\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" create configmap supabase-kong-entrypoint \\\n --from-file=kong-entrypoint.sh=\"\\${K8S_DIR}/supabase/kong-entrypoint.sh\" \\\n --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" apply -f -\n\n rm -f \"\\${tmp_runtime}\" \"\\${tmp_public}\"\n trap - EXIT\n}\n\ndocker_load_image_to_minikube() {\n if command -v docker >/dev/null 2>&1 && docker image inspect \"\\${APP_IMAGE}\" >/dev/null 2>&1; then\n minikube -p \"\\${PROFILE}\" image load --daemon=true --overwrite=true \"\\${APP_IMAGE}\" >/dev/null\n return 0\n fi\n\n return 1\n}\n\nrun_supabase_migrations() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n export SUPABASE_DB_URL PGSSLMODE=disable\n\n if [[ -d \"\\${ROOT_DIR}/supabase/migrations\" ]]; then\n require_command supabase\n (\n cd \"\\${ROOT_DIR}\"\n${indentShellBlock(supabaseMigrationCommand, 6)}\n )\n fi\n}\n\nreconcile_supabase_profile() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n if [[ \"\\${SUPABASE_PROFILE_ENABLED}\" == \"true\" && -f \"\\${SUPABASE_PROFILE_RECONCILE_FILE}\" ]]; then\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -q -f \"\\${SUPABASE_PROFILE_RECONCILE_FILE}\"\n fi\n}\n\nreload_postgrest_schema() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -q -c \"notify pgrst, 'reload schema';\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout restart deployment/rest >/dev/null\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/rest --timeout=600s\n}\n\nbootstrap_supabase_vault_migration() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n if [[ -f \"\\${ROOT_DIR}/supabase/migrations/202607120001_ankhorage_supabase_vault.sql\" ]]; then\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" exec deployment/postgres -- psql -U postgres -d postgres -v ON_ERROR_STOP=1 -q -c \"alter role postgres with superuser;\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" exec deployment/postgres -- psql -U postgres -d postgres -v ON_ERROR_STOP=1 -q -c \"create schema if not exists vault; grant pg_read_server_files to postgres; grant pg_read_server_files to supabase_admin; grant execute on function pg_read_file(text) to public; grant execute on function pg_read_file(text, bigint, bigint) to public;\"\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -q -f \"\\${ROOT_DIR}/supabase/migrations/202607120001_ankhorage_supabase_vault.sql\"\n fi\n}\n\nbootstrap_supabase_database() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n require_command psql\n export POSTGRES_PASSWORD JWT_SECRET JWT_EXP=\"\\${JWT_EXPIRY}\" POSTGRES_USER=postgres\n psql \"\\${SUPABASE_DB_URL}\" -v ON_ERROR_STOP=1 -q -f \"\\${K8S_DIR}/supabase/bootstrap.sql\"\n}\n\nwait_for_supabase_database() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n require_command psql\n if ! \"\\${PORT_FORWARD_SCRIPT}\" start db-migration; then\n echo \"Failed to start db-migration port-forward for Supabase bootstrap.\"\n \"\\${PORT_FORWARD_SCRIPT}\" status db-migration || true\n exit 1\n fi\n for attempt in {1..60}; do\n if PGPASSWORD=\"\\${POSTGRES_PASSWORD}\" psql -h 127.0.0.1 -p \"\\${SUPABASE_DB_FORWARD_LOCAL_PORT}\" -U postgres -d postgres -v ON_ERROR_STOP=1 -Atq -c 'select 1' >/dev/null 2>&1; then\n return 0\n fi\n sleep 2\n done\n\n echo \"Postgres did not accept SQL connections as postgres before bootstrap.\"\n \"\\${PORT_FORWARD_SCRIPT}\" status db-migration || true\n exit 1\n}\n\napply_supabase_runtime_workloads() {\n if [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n return 0\n fi\n\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/auth.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/rest.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/realtime.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/imgproxy.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/storage.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/meta.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/gateway.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/studio.yaml\"\n}\n\napply_namespace_manifests() {\n local namespace_manifest\n for namespace_manifest in \"\\${K8S_DIR}\"/namespaces/*.yaml; do\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${namespace_manifest}\"\n done\n}\n\n${disabledAppRuntimeReconciliation}\n${providerLifecycleStageScripts}\n\nload_env_file_preserving_process_env\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nDRIVER=\"\\${MINIKUBE_DRIVER:-docker}\"\nAPP_BUILD_ENABLED=\"\\${APP_BUILD_ENABLED:-true}\"\nAPP_SOURCE_DIR=\"\\${APP_SOURCE_DIR:-$(cd \"\\${ROOT_DIR}/../..\" && pwd)}\"\nAPP_WEB_EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR:-.ankh/web-export}\"\nAPP_IMAGE=\"\\${APP_IMAGE:-${defaultAppImage}}\"\nAPP_IMAGE_SYNC_STRATEGY=\"\\${APP_IMAGE_SYNC_STRATEGY:-docker-load}\"\nAPP_REPLICAS=\"\\${APP_REPLICAS:-1}\"\nAPP_FORCE_ROLLOUT_RESTART=\"\\${APP_FORCE_ROLLOUT_RESTART:-true}\"\nAPP_IMAGE_PULL_SECRET_NAME=\"\\${APP_IMAGE_PULL_SECRET_NAME:-}\"\nAPP_IMAGE_PULL_SECRET_SERVER=\"\\${APP_IMAGE_PULL_SECRET_SERVER:-ghcr.io}\"\nAPP_IMAGE_PULL_SECRET_USERNAME=\"\\${APP_IMAGE_PULL_SECRET_USERNAME:-}\"\nAPP_IMAGE_PULL_SECRET_PASSWORD=\"\\${APP_IMAGE_PULL_SECRET_PASSWORD:-}\"\nAPP_IMAGE_PULL_SECRET_EMAIL=\"\\${APP_IMAGE_PULL_SECRET_EMAIL:-}\"\nAPP_PORT_FORWARD_LOCAL_PORT=\"\\${APP_PORT_FORWARD_LOCAL_PORT:-${supabaseHostPorts.app}}\"\nSUPABASE_GATEWAY_FORWARD_LOCAL_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}\"\nSUPABASE_DB_FORWARD_LOCAL_PORT=\"\\${SUPABASE_DB_FORWARD_LOCAL_PORT:-${supabaseHostPorts.db}}\"\nSUPABASE_DB_URL=\"\\${SUPABASE_DB_URL:-}\"\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\ncleanup_failed_up() {\n \"\\${PORT_FORWARD_SCRIPT}\" stop all >/dev/null 2>&1 || true\n}\n\ntrap cleanup_failed_up ERR\n\nrequire_command minikube\nrequire_command kubectl\nensure_supabase_runtime_env\nsync_app_public_supabase_env\n\nHOST_STATUS=\"$(minikube -p \"\\${PROFILE}\" status --format='{{.Host}}' 2>/dev/null || true)\"\nif [[ \"\\${HOST_STATUS}\" != \"Running\" ]]; then\n minikube start -p \"\\${PROFILE}\" --driver=\"\\${DRIVER}\"\nfi\n\nif [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" == \"true\" ]]; then\n apply_namespace_manifests\n sync_supabase_secrets\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/postgres.init.configmap.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/postgres.pvc.yaml\"\n kubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/supabase/postgres.yaml\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/postgres --timeout=900s\n wait_for_supabase_database\n bootstrap_supabase_database\n bootstrap_supabase_vault_migration\n resolve_oauth_credentials_from_vault\n${oauthValidation}\n sync_supabase_secrets\n apply_supabase_runtime_workloads\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/auth --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/rest --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/realtime --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/storage --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/gateway --timeout=600s\n kubectl --context \"\\${PROFILE}\" -n \"\\${SUPABASE_NAMESPACE}\" rollout status deployment/studio --timeout=600s\n run_supabase_migrations\n reconcile_supabase_profile\n reload_postgrest_schema\n \"\\${PORT_FORWARD_SCRIPT}\" start supabase-gateway >/dev/null\n \"\\${PORT_FORWARD_SCRIPT}\" start studio >/dev/null\nelse\n kubectl --context \"\\${PROFILE}\" apply -k \"\\${K8S_DIR}\"\nfi\n\nif [[ \"\\${APP_RUNTIME_ENABLED}\" == \"true\" && \"\\${APP_BUILD_ENABLED}\" == \"true\" ]]; then\n if [[ ! -x \"\\${BUILD_SCRIPT}\" ]]; then\n echo \"Missing build helper script: \\${BUILD_SCRIPT}\"\n exit 1\n fi\n\n \"\\${BUILD_SCRIPT}\"\nfi\n\nif [[ \"\\${APP_WEB_EXPORT_DIR}\" = /* ]]; then\n EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR}\"\nelse\n EXPORT_DIR=\"\\${APP_SOURCE_DIR}/\\${APP_WEB_EXPORT_DIR}\"\nfi\n\nif [[ \"\\${APP_RUNTIME_ENABLED}\" == \"true\" ]]; then\ncase \"\\${APP_IMAGE_SYNC_STRATEGY}\" in\n minikube-build)\n if [[ ! -f \"\\${EXPORT_DIR}/index.html\" ]]; then\n echo \"Expected web export output not found at \\${EXPORT_DIR}/index.html\"\n exit 1\n fi\n minikube -p \"\\${PROFILE}\" image build -t \"\\${APP_IMAGE}\" -f \"\\${ROOT_DIR}/app-image/Dockerfile\" \"\\${EXPORT_DIR}\" >/dev/null\n ;;\n docker-load)\n if ! docker_load_image_to_minikube; then\n echo \"Skipping docker-load image sync; local Docker image \\${APP_IMAGE} not found.\"\n fi\n ;;\n none)\n echo \"Skipping local image sync (APP_IMAGE_SYNC_STRATEGY=none).\"\n ;;\n *)\n echo \"Unsupported APP_IMAGE_SYNC_STRATEGY=\\${APP_IMAGE_SYNC_STRATEGY}. Use minikube-build, docker-load, or none.\"\n exit 1\n ;;\nesac\nfi\n\nif [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" == \"true\" ]]; then\n kubectl --context \"\\${PROFILE}\" apply -k \"\\${K8S_DIR}\"\nfi\n\n${reconcileDisabledAppRuntime}\nwait_for_provider_readiness\nrun_provider_migrations\nrun_provider_reconciliation\n\nif [[ \"\\${APP_RUNTIME_ENABLED}\" == \"true\" ]]; then\nif [[ -n \"\\${APP_IMAGE_PULL_SECRET_NAME}\" ]]; then\n if [[ -z \"\\${APP_IMAGE_PULL_SECRET_USERNAME}\" || -z \"\\${APP_IMAGE_PULL_SECRET_PASSWORD}\" ]]; then\n echo \"APP_IMAGE_PULL_SECRET_NAME is set, but username/password are missing.\"\n exit 1\n fi\n\n SECRET_EMAIL_ARG=()\n if [[ -n \"\\${APP_IMAGE_PULL_SECRET_EMAIL}\" ]]; then\n SECRET_EMAIL_ARG=(--docker-email=\"\\${APP_IMAGE_PULL_SECRET_EMAIL}\")\n fi\n\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" create secret docker-registry \"\\${APP_IMAGE_PULL_SECRET_NAME}\" --docker-server=\"\\${APP_IMAGE_PULL_SECRET_SERVER}\" --docker-username=\"\\${APP_IMAGE_PULL_SECRET_USERNAME}\" --docker-password=\"\\${APP_IMAGE_PULL_SECRET_PASSWORD}\" \"\\${SECRET_EMAIL_ARG[@]}\" --dry-run=client -o yaml | kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" apply -f -\n\n PULL_SECRET_PATCH=\"$(cat <<EOF\n{\"spec\":{\"template\":{\"spec\":{\"imagePullSecrets\":[{\"name\":\"\\${APP_IMAGE_PULL_SECRET_NAME}\"}]}}}}\nEOF\n)\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" patch deployment app-runtime --type=merge --patch \"\\${PULL_SECRET_PATCH}\" >/dev/null\nelse\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" patch deployment app-runtime --type=json --patch='[{\"op\":\"remove\",\"path\":\"/spec/template/spec/imagePullSecrets\"}]' >/dev/null 2>&1 || true\nfi\n\nkubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" set image deployment/app-runtime app=\"\\${APP_IMAGE}\" >/dev/null\nkubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" scale deployment/app-runtime --replicas=\"\\${APP_REPLICAS}\" >/dev/null\n\nif [[ \"\\${APP_FORCE_ROLLOUT_RESTART}\" == \"true\" ]]; then\n kubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" rollout restart deployment/app-runtime >/dev/null\nfi\n\nkubectl --context \"\\${PROFILE}\" -n \"\\${APP_NAMESPACE}\" rollout status deployment/app-runtime --timeout=180s >/dev/null\n\"\\${PORT_FORWARD_SCRIPT}\" start app >/dev/null\nfi\n\ntrap - ERR\necho \"Minikube infrastructure for '\\${PROFILE}' is running.\"\n`;\n}\n\nfunction getBuildAppImageScript(args: { appSlug: string; defaultAppImage: string }): string {\n const { appSlug, defaultAppImage } = args;\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nDOCKERFILE_PATH=\"\\${ROOT_DIR}/app-image/Dockerfile\"\nAPP_SLUG=\"${appSlug}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\n\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nAPP_BUILD_ENABLED=\"\\${APP_BUILD_ENABLED:-true}\"\nAPP_SOURCE_DIR=\"\\${APP_SOURCE_DIR:-$(cd \"\\${ROOT_DIR}/../..\" && pwd)}\"\nAPP_WEB_EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR:-.ankh/web-export}\"\nAPP_IMAGE=\"\\${APP_IMAGE:-${defaultAppImage}}\"\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\nif [[ \"\\${APP_BUILD_ENABLED}\" != \"true\" ]]; then\n echo \"Skipping app image build (APP_BUILD_ENABLED=\\${APP_BUILD_ENABLED}).\"\n exit 0\nfi\n\nif [[ ! -f \"\\${APP_SOURCE_DIR}/package.json\" ]]; then\n echo \"APP_SOURCE_DIR does not look like an app root: \\${APP_SOURCE_DIR}\"\n exit 1\nfi\n\nif [[ ! -f \"\\${DOCKERFILE_PATH}\" ]]; then\n echo \"Dockerfile for app image build is missing: \\${DOCKERFILE_PATH}\"\n exit 1\nfi\n\nEXPO_CLI=\"\\${APP_SOURCE_DIR}/node_modules/.bin/expo\"\nif [[ ! -x \"\\${EXPO_CLI}\" ]]; then\n echo \"App-owned Expo CLI is missing: \\${EXPO_CLI}\" >&2\n echo \"Run 'bun install --frozen-lockfile' in \\${APP_SOURCE_DIR} before building the app image.\" >&2\n exit 1\nfi\n\nif ! command -v docker >/dev/null 2>&1; then\n echo \"docker is required to build app image.\"\n exit 1\nfi\n\n(\n cd \"\\${APP_SOURCE_DIR}\"\n \"\\${EXPO_CLI}\" export --platform web --clear --output-dir \"\\${APP_WEB_EXPORT_DIR}\"\n)\n\nif [[ \"\\${APP_WEB_EXPORT_DIR}\" = /* ]]; then\n EXPORT_DIR=\"\\${APP_WEB_EXPORT_DIR}\"\nelse\n EXPORT_DIR=\"\\${APP_SOURCE_DIR}/\\${APP_WEB_EXPORT_DIR}\"\nfi\n\nif [[ ! -f \"\\${EXPORT_DIR}/index.html\" ]]; then\n echo \"Expected web export output not found at \\${EXPORT_DIR}/index.html\"\n exit 1\nfi\n\ndocker build -t \"\\${APP_IMAGE}\" \\\n --label \"ankhorage.kind=generated-app\" \\\n --label \"ankhorage.app_slug=\\${PROFILE}\" \\\n --label \"ankhorage.image=\\${APP_IMAGE}\" \\\n -f \"\\${DOCKERFILE_PATH}\" \\\n \"\\${EXPORT_DIR}\"\necho \"Built app image: \\${APP_IMAGE} (profile: \\${PROFILE})\"\n`;\n}\n\nfunction getAppImageDockerfile(): string {\n return `FROM nginx:1.27-alpine\n\nRUN cat <<'EOF' > /etc/nginx/conf.d/default.conf\nserver {\n listen 8080;\n absolute_redirect off;\n server_name _;\n root /usr/share/nginx/html;\n index index.html;\n\n location / {\n try_files $uri $uri/ /index.html;\n }\n}\nEOF\n\nCOPY . /usr/share/nginx/html\n\nEXPOSE 8080\n\nCMD [\"nginx\", \"-g\", \"daemon off;\"]\n`;\n}\n\nfunction getPortForwardScript(args: {\n appSlug: string;\n appRuntimeEnabled: boolean;\n supabaseKubernetesEnabled: boolean;\n supabaseHostPorts: SupabaseHostPorts;\n}): string {\n const { appSlug, appRuntimeEnabled, supabaseKubernetesEnabled, supabaseHostPorts } = args;\n const runtimeForwardNames = [\n ...(appRuntimeEnabled ? ['app'] : []),\n ...(supabaseKubernetesEnabled ? ['supabase-gateway'] : []),\n ];\n const allForwardNames = [\n ...runtimeForwardNames,\n ...(supabaseKubernetesEnabled ? ['studio', 'db-migration'] : []),\n ];\n const managedForwardNames = ['app', 'supabase-gateway', 'studio', 'db-migration'];\n const obsoleteForwardNames = managedForwardNames.filter(\n (name) => !allForwardNames.includes(name),\n );\n const appTargetCase = ` app)\n echo \"${APP_NAMESPACE} service/app-runtime \\${APP_PORT_FORWARD_LOCAL_PORT} \\${APP_PORT_FORWARD_REMOTE_PORT}\"\n ;;`;\n const supabaseTargetCases = ` supabase-gateway)\n echo \"${SUPABASE_NAMESPACE} service/gateway \\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT} \\${SUPABASE_GATEWAY_FORWARD_REMOTE_PORT}\"\n ;;\n studio)\n echo \"${SUPABASE_NAMESPACE} service/studio \\${SUPABASE_STUDIO_FORWARD_LOCAL_PORT} \\${SUPABASE_STUDIO_FORWARD_REMOTE_PORT}\"\n ;;\n db-migration)\n echo \"${SUPABASE_NAMESPACE} service/postgres \\${SUPABASE_DB_FORWARD_LOCAL_PORT} \\${SUPABASE_DB_FORWARD_REMOTE_PORT}\"\n ;;`;\n const concreteForwardNames = [\n ...(appRuntimeEnabled ? ['app'] : []),\n ...(supabaseKubernetesEnabled ? ['supabase-gateway', 'studio', 'db-migration'] : []),\n ];\n const forwardUsage = [...concreteForwardNames, 'runtime', 'all'].join('|');\n const forwardNamesDescription =\n concreteForwardNames.length > 0\n ? `${concreteForwardNames.join(', ')}, runtime, or all`\n : 'runtime or all';\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nSTATE_DIR=\"\\${ROOT_DIR}/.state/forwards\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nAPP_RUNTIME_ENABLED=\"${appRuntimeEnabled ? 'true' : 'false'}\"\nAPP_PORT_FORWARD_LOCAL_PORT=\"\\${APP_PORT_FORWARD_LOCAL_PORT:-${supabaseHostPorts.app}}\"\nAPP_PORT_FORWARD_REMOTE_PORT=\"\\${APP_PORT_FORWARD_REMOTE_PORT:-80}\"\nSUPABASE_GATEWAY_FORWARD_LOCAL_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}\"\nSUPABASE_GATEWAY_FORWARD_REMOTE_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_REMOTE_PORT:-8000}\"\nSUPABASE_STUDIO_FORWARD_LOCAL_PORT=\"\\${SUPABASE_STUDIO_FORWARD_LOCAL_PORT:-${supabaseHostPorts.studio}}\"\nSUPABASE_STUDIO_FORWARD_REMOTE_PORT=\"\\${SUPABASE_STUDIO_FORWARD_REMOTE_PORT:-3000}\"\nSUPABASE_DB_FORWARD_LOCAL_PORT=\"\\${SUPABASE_DB_FORWARD_LOCAL_PORT:-${supabaseHostPorts.db}}\"\nSUPABASE_DB_FORWARD_REMOTE_PORT=\"\\${SUPABASE_DB_FORWARD_REMOTE_PORT:-5432}\"\nRUNTIME_FORWARD_NAMES=(${runtimeForwardNames.join(' ')})\nALL_FORWARD_NAMES=(${allForwardNames.join(' ')})\nMANAGED_FORWARD_NAMES=(${managedForwardNames.join(' ')})\nOBSOLETE_FORWARD_NAMES=(${obsoleteForwardNames.join(' ')})\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nAPP_RUNTIME_ENABLED=\"${appRuntimeEnabled ? 'true' : 'false'}\"\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\nif ! command -v kubectl >/dev/null 2>&1; then\n echo \"kubectl is required but not installed.\"\n exit 1\nfi\n\nmkdir -p \"\\${STATE_DIR}\"\n\npid_file_for() {\n echo \"\\${STATE_DIR}/\\${PROFILE}-\\${1}.pid\"\n}\n\ntarget_for() {\n case \"\\${1}\" in\n${appTargetCase}\n${supabaseTargetCases}\n *)\n echo \"Unknown forward '\\${1}'. Use ${forwardNamesDescription}.\" >&2\n return 1\n ;;\n esac\n}\n\nis_pid_running() {\n local pid=\"\\${1}\"\n [[ -n \"\\${pid}\" ]] && kill -0 \"\\${pid}\" >/dev/null 2>&1\n}\n\nis_port_accepting() {\n local port=\"\\${1}\"\n (echo >/dev/tcp/127.0.0.1/\"\\${port}\") >/dev/null 2>&1\n}\n\nprint_forward_log_tail() {\n local name=\"\\${1}\"\n local log_file=\"\\${STATE_DIR}/\\${PROFILE}-\\${name}.log\"\n if [[ -s \"\\${log_file}\" ]]; then\n echo \"\\${name}: recent kubectl port-forward log:\"\n tail -n 20 \"\\${log_file}\"\n fi\n}\n\nprocess_command_for_pid() {\n local pid=\"\\${1}\"\n ps -p \"\\${pid}\" -o command= 2>/dev/null || true\n}\n\nprocess_name_for_pid() {\n local pid=\"\\${1}\"\n ps -p \"\\${pid}\" -o comm= 2>/dev/null || true\n}\n\nis_owned_forward_process() {\n local pid=\"\\${1}\"\n local namespace=\"\\${2}\"\n local resource=\"\\${3}\"\n local local_port=\"\\${4}\"\n local remote_port=\"\\${5}\"\n local command\n local process_name\n command=\"$(process_command_for_pid \"\\${pid}\")\"\n process_name=\"$(process_name_for_pid \"\\${pid}\")\"\n\n case \"\\${process_name}\" in\n *kubectl) ;;\n *) return 1 ;;\n esac\n\n case \"\\${command}\" in\n *\"kubectl --context \\${PROFILE} -n \\${namespace} port-forward \\${resource} \\${local_port}:\\${remote_port}\"*)\n return 0\n ;;\n *)\n return 1\n ;;\n esac\n}\n\nhandle_non_owned_forward_pid() {\n local name=\"\\${1}\"\n local pid=\"\\${2}\"\n local pid_file=\"\\${3}\"\n local local_port=\"\\${4}\"\n echo \"\\${name}: stale pid file pointed at non-owned live pid \\${pid}; removing ownership record \\${pid_file}\"\n rm -f \"\\${pid_file}\"\n\n if is_port_accepting \"\\${local_port}\"; then\n echo \"\\${name}: port occupied by non-owned process on local port \\${local_port}\"\n return 1\n fi\n\n return 0\n}\n\nterminate_forward_process() {\n local name=\"\\${1}\"\n local pid=\"\\${2}\"\n local namespace=\"\\${3}\"\n local resource=\"\\${4}\"\n local local_port=\"\\${5}\"\n local remote_port=\"\\${6}\"\n\n if [[ -z \"\\${pid}\" ]]; then\n return 0\n fi\n\n if is_pid_running \"\\${pid}\" && ! is_owned_forward_process \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\"; then\n echo \"\\${name}: refusing to terminate non-owned live pid \\${pid}\"\n return 1\n fi\n\n if is_pid_running \"\\${pid}\"; then\n kill \"\\${pid}\" >/dev/null 2>&1 || true\n for attempt in {1..20}; do\n if ! is_pid_running \"\\${pid}\"; then\n break\n fi\n sleep 0.25\n done\n fi\n\n if is_pid_running \"\\${pid}\"; then\n kill -KILL \"\\${pid}\" >/dev/null 2>&1 || true\n for attempt in {1..20}; do\n if ! is_pid_running \"\\${pid}\"; then\n break\n fi\n sleep 0.25\n done\n fi\n\n if is_pid_running \"\\${pid}\"; then\n echo \"\\${name}: failed to stop owned port-forward pid \\${pid}\"\n return 1\n fi\n\n for attempt in {1..20}; do\n if ! is_port_accepting \"\\${local_port}\"; then\n return 0\n fi\n sleep 0.25\n done\n\n echo \"\\${name}: owned port-forward pid \\${pid} stopped, but local port \\${local_port} is still accepting connections\"\n return 1\n}\n\nstart_forward() {\n local name=\"\\${1}\"\n local pid_file\n pid_file=\"$(pid_file_for \"\\${name}\")\"\n read -r namespace resource local_port remote_port <<<\"$(target_for \"\\${name}\")\"\n\n if [[ \"\\${name}\" == \"app\" && \"\\${APP_RUNTIME_ENABLED}\" != \"true\" ]]; then\n echo \"\\${name}: skipped (Web app runtime disabled)\"\n return 0\n fi\n\n if [[ -f \"\\${pid_file}\" ]]; then\n local existing_pid\n existing_pid=\"$(cat \"\\${pid_file}\")\"\n if is_pid_running \"\\${existing_pid}\"; then\n if ! is_owned_forward_process \"\\${existing_pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\"; then\n handle_non_owned_forward_pid \"\\${name}\" \"\\${existing_pid}\" \"\\${pid_file}\" \"\\${local_port}\" || return 1\n elif is_port_accepting \"\\${local_port}\"; then\n echo \"\\${name}: running (pid \\${existing_pid})\"\n return 0\n else\n echo \"\\${name}: stale running pid \\${existing_pid} was not accepting local port \\${local_port}; restarting\"\n terminate_forward_process \"\\${name}\" \"\\${existing_pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\" || return 1\n rm -f \"\\${pid_file}\"\n fi\n else\n rm -f \"\\${pid_file}\"\n fi\n fi\n\n if [[ \"\\${namespace}\" == \"${SUPABASE_NAMESPACE}\" && \"\\${SUPABASE_RUNTIME_ENABLED}\" != \"true\" ]]; then\n echo \"\\${name}: skipped (Supabase Kubernetes disabled)\"\n return 0\n fi\n\n if ! kubectl --context \"\\${PROFILE}\" -n \"\\${namespace}\" get \"\\${resource}\" >/dev/null 2>&1; then\n echo \"\\${name}: target \\${namespace}/\\${resource} not found\"\n return 1\n fi\n\n for start_attempt in {1..5}; do\n nohup kubectl --context \"\\${PROFILE}\" -n \"\\${namespace}\" port-forward \"\\${resource}\" \"\\${local_port}:\\${remote_port}\" >\"\\${STATE_DIR}/\\${PROFILE}-\\${name}.log\" 2>&1 &\n local pid=\"$!\"\n echo \"\\${pid}\" > \"\\${pid_file}\"\n\n for readiness_attempt in {1..20}; do\n if ! is_pid_running \"\\${pid}\"; then\n rm -f \"\\${pid_file}\"\n if [[ \"\\${start_attempt}\" -lt 5 ]]; then\n echo \"\\${name}: port-forward attempt \\${start_attempt} exited before readiness; retrying\"\n sleep 2\n break\n fi\n\n echo \"\\${name}: failed to start local port \\${local_port} for \\${namespace}/\\${resource}:\\${remote_port} after \\${start_attempt} attempts\"\n print_forward_log_tail \"\\${name}\"\n return 1\n fi\n if is_port_accepting \"\\${local_port}\"; then\n sleep 1\n if is_pid_running \"\\${pid}\" && is_port_accepting \"\\${local_port}\"; then\n sleep 0.5\n if is_pid_running \"\\${pid}\"; then\n echo \"\\${name}: started (pid \\${pid}, local port \\${local_port})\"\n return 0\n fi\n fi\n fi\n sleep 0.5\n done\n\n if [[ -f \"\\${pid_file}\" ]]; then\n terminate_forward_process \"\\${name}\" \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\" || return 1\n rm -f \"\\${pid_file}\"\n\n if [[ \"\\${start_attempt}\" -lt 5 ]]; then\n echo \"\\${name}: port-forward attempt \\${start_attempt} did not become ready; retrying\"\n sleep 2\n else\n echo \"\\${name}: did not become ready on local port \\${local_port} for \\${namespace}/\\${resource}:\\${remote_port} after \\${start_attempt} attempts\"\n print_forward_log_tail \"\\${name}\"\n return 1\n fi\n fi\n done\n\n return 1\n}\n\nstop_forward() {\n local name=\"\\${1}\"\n local pid_file\n pid_file=\"$(pid_file_for \"\\${name}\")\"\n read -r namespace resource local_port remote_port <<<\"$(target_for \"\\${name}\")\"\n if [[ ! -f \"\\${pid_file}\" ]]; then\n echo \"\\${name}: stopped\"\n return 0\n fi\n\n local pid\n pid=\"$(cat \"\\${pid_file}\")\"\n if is_pid_running \"\\${pid}\" && ! is_owned_forward_process \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\"; then\n handle_non_owned_forward_pid \"\\${name}\" \"\\${pid}\" \"\\${pid_file}\" \"\\${local_port}\" || return 1\n echo \"\\${name}: stopped\"\n return 0\n fi\n\n terminate_forward_process \"\\${name}\" \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\" || return 1\n rm -f \"\\${pid_file}\"\n echo \"\\${name}: stopped\"\n}\n\nstatus_forward() {\n local name=\"\\${1}\"\n local pid_file\n pid_file=\"$(pid_file_for \"\\${name}\")\"\n if [[ ! -f \"\\${pid_file}\" ]]; then\n echo \"\\${name}: stopped\"\n return 0\n fi\n\n local pid\n pid=\"$(cat \"\\${pid_file}\")\"\n if is_pid_running \"\\${pid}\"; then\n read -r namespace resource local_port remote_port <<<\"$(target_for \"\\${name}\")\"\n if ! is_owned_forward_process \"\\${pid}\" \"\\${namespace}\" \"\\${resource}\" \"\\${local_port}\" \"\\${remote_port}\"; then\n echo \"\\${name}: stale_pid_non_owned=\\${pid}\"\n rm -f \"\\${pid_file}\"\n return 0\n fi\n if is_port_accepting \"\\${local_port}\"; then\n echo \"\\${name}: running pid=\\${pid} url=127.0.0.1:\\${local_port} target=\\${namespace}/\\${resource}:\\${remote_port}\"\n return 0\n fi\n echo \"\\${name}: not ready pid=\\${pid} url=127.0.0.1:\\${local_port} target=\\${namespace}/\\${resource}:\\${remote_port}\"\n return 0\n fi\n\n echo \"\\${name}: crashed stale_pid=\\${pid}\"\n rm -f \"\\${pid_file}\"\n}\n\nfor_each_forward() {\n local action=\"\\${1}\"\n shift\n local name\n while [[ \"\\${#}\" -gt 0 ]]; do\n name=\"\\${1}\"\n shift\n \"\\${action}_forward\" \"\\${name}\"\n done\n}\n\nACTION=\"\\${1:-start}\"\nNAME=\"\\${2:-all}\"\n\ncase \"\\${ACTION}:\\${NAME}\" in\n start:runtime) for_each_forward start ${runtimeForwardNames.join(' ')} ;;\n stop:runtime)\n for_each_forward stop ${runtimeForwardNames.join(' ')}\n for_each_forward stop ${obsoleteForwardNames.join(' ')}\n ;;\n status:runtime) for_each_forward status ${runtimeForwardNames.join(' ')} ;;\n start:all) for_each_forward start ${allForwardNames.join(' ')} ;;\n stop:all) for_each_forward stop ${managedForwardNames.join(' ')} ;;\n status:all) for_each_forward status ${allForwardNames.join(' ')} ;;\n stop:obsolete) for_each_forward stop ${obsoleteForwardNames.join(' ')} ;;\n start:*) start_forward \"\\${NAME}\" ;;\n stop:*) stop_forward \"\\${NAME}\" ;;\n status:*) status_forward \"\\${NAME}\" ;;\n *)\n echo \"Usage: ./scripts/port-forward.sh {start|stop|status} {${forwardUsage}}\"\n exit 1\n ;;\nesac\n`;\n}\n\nfunction getDownScript(appSlug: string): string {\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\n\"\\${SCRIPT_DIR}/port-forward.sh\" stop all >/dev/null || true\n\nif command -v minikube >/dev/null 2>&1; then\n minikube stop -p \"\\${PROFILE}\"\nelse\n echo \"minikube is required but not installed.\"\n exit 1\nfi\n\necho \"Stopped Minikube profile '\\${PROFILE}'. Persistent data remains in the profile.\"\n`;\n}\n\nfunction getResetScript(args: {\n appSlug: string;\n supabaseKubernetesEnabled: boolean;\n providerNamespaces: readonly string[];\n}): string {\n const { appSlug, supabaseKubernetesEnabled, providerNamespaces } = args;\n const resetNamespaces = [\n APP_NAMESPACE,\n ...(supabaseKubernetesEnabled ? [SUPABASE_NAMESPACE] : []),\n ...providerNamespaces,\n ];\n const resetNamespaceCommands = resetNamespaces\n .map(\n (\n namespace,\n ) => `kubectl --context \"\\${PROFILE}\" delete namespace ${namespace} --ignore-not-found\nkubectl --context \"\\${PROFILE}\" apply -f \"\\${K8S_DIR}/namespaces/${namespace}.yaml\"`,\n )\n .join('\\n');\n const resetScope = `Kubernetes namespaces ${resetNamespaces.join(', ')}`;\n const resetDataDescription = `reset.sh deletes and recreates namespaces ${resetNamespaces.join(\n ', ',\n )}. This resets app workloads and provider-owned data in those namespaces. It does not delete the Minikube profile.`;\n const completionDescription = `Reset namespaces ${resetNamespaces.join(', ')}`;\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nK8S_DIR=\"\\${ROOT_DIR}/k8s\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nCONFIRM=\"\\${ANKH_RESET_CONFIRM:-}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\nif [[ \"\\${CONFIRM}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"Refusing reset. Set ANKH_RESET_CONFIRM=\\${APP_SLUG} to reset ${resetScope} inside profile '\\${PROFILE}'.\"\n echo \"${resetDataDescription}\"\n exit 1\nfi\n\nif ! command -v kubectl >/dev/null 2>&1; then\n echo \"kubectl is required but not installed.\"\n exit 1\nfi\n\n\"\\${SCRIPT_DIR}/port-forward.sh\" stop all >/dev/null || true\n${resetNamespaceCommands}\necho \"${completionDescription} for profile '\\${PROFILE}'. Run ./scripts/up.sh to recreate runtime secrets, migrations, forwards, and app rollout.\"\n`;\n}\n\nfunction getDestroyScript(appSlug: string): string {\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\n\"\\${SCRIPT_DIR}/port-forward.sh\" stop all >/dev/null || true\nminikube delete -p \"\\${PROFILE}\"\necho \"Deleted Minikube profile '\\${PROFILE}'.\"\n`;\n}\n\nfunction getStatusScript(args: {\n appSlug: string;\n appRuntimeEnabled: boolean;\n supabaseKubernetesEnabled: boolean;\n profileModel: ResolvedProfileModel;\n supabaseHostPorts: SupabaseHostPorts;\n providerNamespaces: readonly string[];\n providerLifecycle: readonly MinikubeProviderLifecycle[];\n}): string {\n const {\n appSlug,\n appRuntimeEnabled,\n supabaseKubernetesEnabled,\n profileModel,\n supabaseHostPorts,\n providerNamespaces,\n providerLifecycle,\n } = args;\n const namespaces = [\n APP_NAMESPACE,\n ...(supabaseKubernetesEnabled ? [SUPABASE_NAMESPACE] : []),\n ...providerNamespaces,\n ].join(' ');\n const providerStatusScript = getProviderStatusScript(providerLifecycle);\n\n return `#!/usr/bin/env bash\nset -euo pipefail\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"\\${BASH_SOURCE[0]}\")\" && pwd)\"\nROOT_DIR=\"$(cd \"\\${SCRIPT_DIR}/..\" && pwd)\"\nAPP_SLUG=\"${appSlug}\"\nPROFILE=\"\\${ANKH_APP_SLUG:-${appSlug}}\"\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\nSUPABASE_PROFILE_ENABLED=\"${profileModel.enabled ? 'true' : 'false'}\"\nSUPABASE_GATEWAY_FORWARD_LOCAL_PORT=\"\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT:-${supabaseHostPorts.gateway}}\"\n\nif [[ -f \"\\${ROOT_DIR}/.env\" ]]; then\n set -a\n # shellcheck disable=SC1090\n source \"\\${ROOT_DIR}/.env\"\n set +a\nfi\nSUPABASE_RUNTIME_ENABLED=\"${supabaseKubernetesEnabled ? 'true' : 'false'}\"\n\nif [[ \"\\${PROFILE}\" != \"\\${APP_SLUG}\" ]]; then\n echo \"ANKH_APP_SLUG must remain the generated canonical slug '\\${APP_SLUG}' for this infra directory.\"\n exit 1\nfi\n\necho \"Infra status for profile: \\${PROFILE}\"\n\nif ! command -v minikube >/dev/null 2>&1; then\n echo \"- minikube: missing\"\n exit 1\nfi\n\nHOST_STATUS=\"$(minikube -p \"\\${PROFILE}\" status --format='{{.Host}}' 2>/dev/null || true)\"\necho \"- minikube host: \\${HOST_STATUS:-missing}\"\n\nif [[ \"\\${HOST_STATUS}\" != \"Running\" ]]; then\n echo \"- cluster: stopped\"\n \"\\${SCRIPT_DIR}/port-forward.sh\" status all || true\n exit 0\nfi\n\nif ! command -v kubectl >/dev/null 2>&1; then\n echo \"- kubectl: missing\"\n exit 1\nfi\n\ncheck_secret_key() {\n local secret=\"\\${1}\"\n local key=\"\\${2}\"\n local encoded\n encoded=\"$(kubectl --context \"\\${PROFILE}\" -n ${SUPABASE_NAMESPACE} get secret \"\\${secret}\" -o \"jsonpath={.data.\\${key}}\" 2>/dev/null || true)\"\n if [[ -n \"\\${encoded}\" ]]; then\n echo \"- secret/\\${secret}:\\${key}: present\"\n else\n echo \"- secret/\\${secret}:\\${key}: missing\"\n fi\n}\n\npostgres_query() {\n local sql=\"\\${1}\"\n kubectl --context \"\\${PROFILE}\" -n ${SUPABASE_NAMESPACE} exec deployment/postgres -- psql -U postgres -d postgres -Atq -c \"\\${sql}\" 2>/dev/null || true\n}\n\nfor namespace in ${namespaces}; do\n if kubectl --context \"\\${PROFILE}\" get namespace \"\\${namespace}\" >/dev/null 2>&1; then\n echo \"- namespace/\\${namespace}: present\"\n kubectl --context \"\\${PROFILE}\" -n \"\\${namespace}\" get pods\n else\n echo \"- namespace/\\${namespace}: missing\"\n fi\ndone\n\nif [[ \"${appRuntimeEnabled ? 'true' : 'false'}\" == \"true\" ]] && kubectl --context \"\\${PROFILE}\" -n ${APP_NAMESPACE} get deployment app-runtime >/dev/null 2>&1; then\n kubectl --context \"\\${PROFILE}\" -n ${APP_NAMESPACE} rollout status deployment/app-runtime --timeout=5s >/dev/null 2>&1 && echo \"- app-runtime: ready\" || echo \"- app-runtime: not ready\"\nfi\n\n${providerStatusScript}\n\nif [[ \"\\${SUPABASE_RUNTIME_ENABLED}\" == \"true\" ]]; then\n for deployment in postgres auth rest realtime storage gateway studio; do\n if kubectl --context \"\\${PROFILE}\" -n ${SUPABASE_NAMESPACE} get deployment \"\\${deployment}\" >/dev/null 2>&1; then\n kubectl --context \"\\${PROFILE}\" -n ${SUPABASE_NAMESPACE} rollout status \"deployment/\\${deployment}\" --timeout=5s >/dev/null 2>&1 && echo \"- supabase/\\${deployment}: ready\" || echo \"- supabase/\\${deployment}: not ready\"\n else\n echo \"- supabase/\\${deployment}: missing\"\n fi\n done\n\n for key in POSTGRES_PASSWORD JWT_SECRET SUPABASE_ANON_KEY SUPABASE_SERVICE_ROLE_KEY SECRET_KEY_BASE REALTIME_DB_ENC_KEY PG_META_CRYPTO_KEY; do\n check_secret_key supabase-runtime-secrets \"\\${key}\"\n done\n\n db_check=\"$(postgres_query 'select 1')\"\n if [[ \"\\${db_check}\" == \"1\" ]]; then\n echo \"- postgres connectivity: ok\"\n else\n echo \"- postgres connectivity: failed\"\n fi\n\n migration_count=\"$(postgres_query \"select count(*) from supabase_migrations.schema_migrations\" || true)\"\n if [[ \"\\${migration_count}\" =~ ^[0-9]+$ ]]; then\n echo \"- migration history: \\${migration_count} applied\"\n else\n echo \"- migration history: unavailable\"\n fi\n\n if [[ \"\\${SUPABASE_PROFILE_ENABLED}\" == \"true\" ]]; then\n profile_state=\"$(postgres_query \"select count(*) from ankhorage_internal.generated_schema_state where artifact_key = 'auth.profile'\" || true)\"\n if [[ \"\\${profile_state}\" =~ ^[1-9][0-9]*$ ]]; then\n echo \"- profile reconciliation: applied\"\n else\n echo \"- profile reconciliation: missing\"\n fi\n else\n state_table=\"$(postgres_query \"select to_regclass('ankhorage_internal.generated_schema_state') is not null\" || true)\"\n if [[ \"\\${state_table}\" != \"t\" ]]; then\n echo \"- profile reconciliation: disabled\"\n else\n profile_state=\"$(postgres_query \"select coalesce((select case when table_name is null then 'stale-state-missing-table-name' when to_regclass(format('public.%I', table_name)) is null then 'stale-state-missing-table:' || table_name else 'stale-state-table-present:' || table_name end from ankhorage_internal.generated_schema_state where artifact_key = 'auth.profile'), 'disabled')\" || true)\"\n if [[ \"\\${profile_state}\" == \"disabled\" ]]; then\n echo \"- profile reconciliation: disabled\"\n else\n echo \"- profile reconciliation: unexpected \\${profile_state}\"\n fi\n fi\n fi\n\n vault_state=\"$(postgres_query \"select exists(select 1 from pg_namespace where nspname = 'vault')\" || true)\"\n if [[ \"\\${vault_state}\" == \"t\" ]]; then\n echo \"- vault schema: present\"\n else\n echo \"- vault schema: absent\"\n fi\n\n if command -v curl >/dev/null 2>&1; then\n public_url=\"\\${SUPABASE_PUBLIC_URL:-http://127.0.0.1:\\${SUPABASE_GATEWAY_FORWARD_LOCAL_PORT}}\"\n if curl -fsS \"\\${public_url}/auth/v1/health\" >/dev/null 2>&1; then\n echo \"- supabase public endpoint: ok (\\${public_url})\"\n else\n echo \"- supabase public endpoint: unavailable (\\${public_url})\"\n fi\n fi\nfi\n\n\"\\${SCRIPT_DIR}/port-forward.sh\" status all || true\n`;\n}\n\nfunction getDefaultAppImage(appSlug: string): string {\n return `ankh/${appSlug}:dev`;\n}\n\nfunction resolveSupabaseHostPorts(appSlug: string): SupabaseHostPorts {\n const base = PORT_BASE + resolvePortBucket(appSlug) * PORT_BUCKET_SIZE;\n return {\n app: base,\n gateway: base + 1,\n studio: base + 2,\n db: base + 3,\n };\n}\n\nfunction resolvePortBucket(appSlug: string): number {\n const rawBucket = hashSlug(appSlug) - hashSlug(PORT_REFERENCE_SLUG);\n return (rawBucket + PORT_BUCKET_COUNT) % PORT_BUCKET_COUNT;\n}\n\nfunction hashSlug(value: string): number {\n let hash = 0;\n for (const char of value) {\n hash = (hash * 31 + char.charCodeAt(0)) % PORT_BUCKET_COUNT;\n }\n return hash;\n}\n\nfunction escapeYamlDoubleQuoted(value: string): string {\n return value.replaceAll('\\\\', '\\\\\\\\').replaceAll('\"', '\\\\\"');\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/infra",
3
3
  "type": "module",
4
- "version": "4.1.2",
4
+ "version": "4.1.3",
5
5
  "description": "Project-aware infrastructure generation library and executable Ankh provider for Ankhorage.",
6
6
  "homepage": "https://github.com/ankhorage/infra#readme",
7
7
  "bugs": {
@@ -73,9 +73,12 @@ official Supabase Kubernetes distribution.
73
73
 
74
74
  - Default app image: `ankh/<slug>:dev`.
75
75
  - By default `up.sh` triggers `build-app-image.sh` (`APP_BUILD_ENABLED=true`) before apply.
76
- - `build-app-image.sh` runs `bunx expo export --platform web --clear`, then builds via
77
- `app-image/Dockerfile`. Clearing the Expo/Metro cache ensures rotated `EXPO_PUBLIC_*`
78
- values replace cached transforms before the browser bundle and Docker image are created.
76
+ - `build-app-image.sh` requires the app's installed `node_modules/.bin/expo`, runs
77
+ `expo export --platform web --clear` through that pinned local CLI, then builds via
78
+ `app-image/Dockerfile`. Missing app dependencies fail with an explicit frozen-install
79
+ instruction; the script never resolves Expo through `bunx` or the network. Clearing the
80
+ Expo/Metro cache ensures rotated `EXPO_PUBLIC_*` values replace cached transforms before the
81
+ browser bundle and Docker image are created.
79
82
  - `up.sh` syncs runtime image using `APP_IMAGE_SYNC_STRATEGY`:
80
83
  - `docker-load` (default): loads existing local Docker image into the app profile.
81
84
  - `minikube-build`: builds exported web artifacts directly into the profile image store.
@@ -25,7 +25,7 @@ test('re-exports rotated public environment values before building the app image
25
25
  const buildScriptPath = path.join(scriptsRoot, 'build-app-image.sh');
26
26
  const dockerfilePath = path.join(infraRoot, 'app-image', 'Dockerfile');
27
27
  const metroCachePath = path.join(workspaceRoot, 'fake-metro-cache');
28
- const bunxArgsPath = path.join(workspaceRoot, 'bunx-args');
28
+ const expoArgsPath = path.join(workspaceRoot, 'expo-args');
29
29
  const dockerArgsPath = path.join(workspaceRoot, 'docker-args');
30
30
  const exportDir = path.join(appRoot, '.ankh', 'web-export');
31
31
  const bundlePath = path.join(exportDir, '_expo', 'static', 'js', 'web', 'index-fixture.js');
@@ -49,14 +49,14 @@ test('re-exports rotated public environment values before building the app image
49
49
  await writeFile(dockerfilePath, 'FROM scratch\n', 'utf8');
50
50
  await writeFile(buildScriptPath, buildScript, 'utf8');
51
51
  await chmod(buildScriptPath, 0o755);
52
- await writeFakeBunx(path.join(fakeBin, 'bunx'));
52
+ await writeFakeExpo(path.join(appRoot, 'node_modules', '.bin', 'expo'));
53
53
  await writeFakeDocker(path.join(fakeBin, 'docker'));
54
54
 
55
55
  await writePublicEnvironment(appRoot, infraRoot, PUBLIC_KEY_A);
56
56
  await runBuildScript({
57
57
  appRoot,
58
58
  buildScriptPath,
59
- bunxArgsPath,
59
+ expoArgsPath,
60
60
  dockerArgsPath,
61
61
  fakeBin,
62
62
  metroCachePath,
@@ -70,7 +70,7 @@ test('re-exports rotated public environment values before building the app image
70
70
  await runBuildScript({
71
71
  appRoot,
72
72
  buildScriptPath,
73
- bunxArgsPath,
73
+ expoArgsPath,
74
74
  dockerArgsPath,
75
75
  fakeBin,
76
76
  metroCachePath,
@@ -80,8 +80,7 @@ test('re-exports rotated public environment values before building the app image
80
80
  expect(secondBundle).toContain(PUBLIC_KEY_B);
81
81
  expect(secondBundle).not.toContain(PUBLIC_KEY_A);
82
82
  expect(secondBundle).not.toContain(PRIVATE_SERVICE_ROLE_KEY);
83
- expect((await readFile(bunxArgsPath, 'utf8')).trim().split('\n')).toEqual([
84
- 'expo',
83
+ expect((await readFile(expoArgsPath, 'utf8')).trim().split('\n')).toEqual([
85
84
  'export',
86
85
  '--platform',
87
86
  'web',
@@ -98,6 +97,64 @@ test('re-exports rotated public environment values before building the app image
98
97
  }
99
98
  });
100
99
 
100
+ test('fails before global or network Expo resolution when app dependencies are missing', async () => {
101
+ const workspaceRoot = await mkdtemp(path.join(tmpdir(), 'ankh-infra-app-image-missing-expo-'));
102
+
103
+ try {
104
+ const appRoot = path.join(workspaceRoot, 'apps', APP_SLUG);
105
+ const infraRoot = path.join(appRoot, 'infra', 'minikube');
106
+ const scriptsRoot = path.join(infraRoot, 'scripts');
107
+ const fakeBin = path.join(workspaceRoot, 'bin');
108
+ const buildScriptPath = path.join(scriptsRoot, 'build-app-image.sh');
109
+ const dockerfilePath = path.join(infraRoot, 'app-image', 'Dockerfile');
110
+ const fallbackMarkerPath = path.join(workspaceRoot, 'forbidden-expo-fallback');
111
+ const generated = generateInfrastructure(
112
+ {
113
+ deployment: { target: 'minikube', monitoring: false },
114
+ modules: [],
115
+ },
116
+ { appManifest: createAppManifest(APP_SLUG) },
117
+ );
118
+ const buildScript = getGeneratedFile(
119
+ generated.files,
120
+ 'infra/minikube/scripts/build-app-image.sh',
121
+ );
122
+
123
+ await mkdir(path.dirname(dockerfilePath), { recursive: true });
124
+ await mkdir(fakeBin, { recursive: true });
125
+ await mkdir(scriptsRoot, { recursive: true });
126
+ await writeFile(path.join(appRoot, 'package.json'), '{}\n', 'utf8');
127
+ await writeFile(dockerfilePath, 'FROM scratch\n', 'utf8');
128
+ await writeFile(buildScriptPath, buildScript, 'utf8');
129
+ await chmod(buildScriptPath, 0o755);
130
+ await writeFakeDocker(path.join(fakeBin, 'docker'));
131
+ await writeForbiddenExpoFallback(path.join(fakeBin, 'bunx'));
132
+ await writeForbiddenExpoFallback(path.join(fakeBin, 'expo'));
133
+
134
+ const result = await executeBuildScript({
135
+ appRoot,
136
+ buildScriptPath,
137
+ dockerArgsPath: path.join(workspaceRoot, 'docker-args'),
138
+ expoArgsPath: path.join(workspaceRoot, 'expo-args'),
139
+ fakeBin,
140
+ fallbackMarkerPath,
141
+ metroCachePath: path.join(workspaceRoot, 'fake-metro-cache'),
142
+ });
143
+
144
+ expect(result.exitCode).toBe(1);
145
+ expect(result.stderr).toContain(
146
+ `App-owned Expo CLI is missing: ${appRoot}/node_modules/.bin/expo`,
147
+ );
148
+ expect(result.stderr).toContain(
149
+ `Run 'bun install --frozen-lockfile' in ${appRoot} before building the app image.`,
150
+ );
151
+ expect(buildScript).not.toContain('bunx');
152
+ expect(await Bun.file(fallbackMarkerPath).exists()).toBe(false);
153
+ } finally {
154
+ await rm(workspaceRoot, { recursive: true, force: true });
155
+ }
156
+ });
157
+
101
158
  async function writePublicEnvironment(
102
159
  appRoot: string,
103
160
  infraRoot: string,
@@ -122,19 +179,20 @@ SUPABASE_SERVICE_ROLE_KEY=${PRIVATE_SERVICE_ROLE_KEY}
122
179
  );
123
180
  }
124
181
 
125
- async function writeFakeBunx(filePath: string): Promise<void> {
182
+ async function writeFakeExpo(filePath: string): Promise<void> {
183
+ await mkdir(path.dirname(filePath), { recursive: true });
126
184
  await writeFile(
127
185
  filePath,
128
186
  `#!/usr/bin/env bash
129
187
  set -euo pipefail
130
188
 
131
- printf '%s\\n' "$@" > "\${FAKE_BUNX_ARGS_PATH:?}"
189
+ printf '%s\\n' "$@" > "\${FAKE_EXPO_ARGS_PATH:?}"
132
190
 
133
- if [[ "\${1:-}" != "expo" || "\${2:-}" != "export" ]]; then
191
+ if [[ "\${1:-}" != "export" ]]; then
134
192
  echo "Expected expo export invocation." >&2
135
193
  exit 64
136
194
  fi
137
- shift 2
195
+ shift
138
196
 
139
197
  clear_cache=false
140
198
  output_dir=""
@@ -208,20 +266,38 @@ fi
208
266
  await chmod(filePath, 0o755);
209
267
  }
210
268
 
211
- async function runBuildScript(args: {
269
+ async function writeForbiddenExpoFallback(filePath: string): Promise<void> {
270
+ await writeFile(
271
+ filePath,
272
+ `#!/usr/bin/env bash
273
+ set -euo pipefail
274
+
275
+ : > "\${FAKE_FALLBACK_MARKER_PATH:?}"
276
+ exit 86
277
+ `,
278
+ 'utf8',
279
+ );
280
+ await chmod(filePath, 0o755);
281
+ }
282
+
283
+ async function executeBuildScript(args: {
212
284
  appRoot: string;
213
285
  buildScriptPath: string;
214
- bunxArgsPath: string;
286
+ expoArgsPath: string;
215
287
  dockerArgsPath: string;
216
288
  fakeBin: string;
289
+ fallbackMarkerPath?: string;
217
290
  metroCachePath: string;
218
- }): Promise<void> {
291
+ }): Promise<{ exitCode: number | null; stderr: string; stdout: string }> {
219
292
  const child = spawn('bash', [args.buildScriptPath], {
220
293
  cwd: args.appRoot,
221
294
  env: {
222
295
  ...process.env,
223
- FAKE_BUNX_ARGS_PATH: args.bunxArgsPath,
224
296
  FAKE_DOCKER_ARGS_PATH: args.dockerArgsPath,
297
+ FAKE_EXPO_ARGS_PATH: args.expoArgsPath,
298
+ ...(args.fallbackMarkerPath === undefined
299
+ ? {}
300
+ : { FAKE_FALLBACK_MARKER_PATH: args.fallbackMarkerPath }),
225
301
  FAKE_METRO_CACHE_PATH: args.metroCachePath,
226
302
  PATH: `${args.fakeBin}:${process.env.PATH ?? ''}`,
227
303
  },
@@ -237,6 +313,19 @@ async function runBuildScript(args: {
237
313
  exitCodePromise,
238
314
  ]);
239
315
 
316
+ return { exitCode, stderr, stdout };
317
+ }
318
+
319
+ async function runBuildScript(args: {
320
+ appRoot: string;
321
+ buildScriptPath: string;
322
+ expoArgsPath: string;
323
+ dockerArgsPath: string;
324
+ fakeBin: string;
325
+ metroCachePath: string;
326
+ }): Promise<void> {
327
+ const { exitCode, stderr, stdout } = await executeBuildScript(args);
328
+
240
329
  if (exitCode !== 0) {
241
330
  throw new Error(
242
331
  `Generated build script exited with ${String(exitCode)}. stdout=${stdout} stderr=${stderr}`,
@@ -398,12 +398,16 @@ describe('generateMinikubeBaseArtifacts app-owned cluster model', () => {
398
398
  ),
399
399
  );
400
400
  expect(upScript).not.toContain('SUPABASE_SERVICE_ROLE_KEY" "${SUPABASE_SERVICE_ROLE_KEY}"');
401
+ expect(buildScript).toContain('EXPO_CLI="${APP_SOURCE_DIR}/node_modules/.bin/expo"');
401
402
  expect(buildScript).toContain(
402
- 'bunx expo export --platform web --clear --output-dir "${APP_WEB_EXPORT_DIR}"',
403
+ '"${EXPO_CLI}" export --platform web --clear --output-dir "${APP_WEB_EXPORT_DIR}"',
403
404
  );
405
+ expect(buildScript).not.toContain('bunx');
404
406
  expect(readme).toContain(
405
- '`build-app-image.sh` clears the Expo/Metro bundler cache before every web export.',
407
+ '`build-app-image.sh` requires the app-installed `node_modules/.bin/expo` and never resolves',
406
408
  );
409
+ expect(readme).toContain('Expo globally or through the network.');
410
+ expect(readme).toContain('It clears the Expo/Metro bundler cache before every web');
407
411
  });
408
412
 
409
413
  test('starts Supabase schema owners before app migrations and profile reconciliation', () => {
@@ -451,10 +451,12 @@ ${appRuntimeEnabled ? `- App: \`http://127.0.0.1:${supabaseHostPorts.app}\`\n` :
451
451
 
452
452
  ## App Image Export
453
453
 
454
- \`build-app-image.sh\` clears the Expo/Metro bundler cache before every web export. Expo
455
- inlines \`EXPO_PUBLIC_*\` values into the browser bundle, so cache invalidation ensures a
456
- rotated browser-safe Supabase URL or anon key replaces the previous value before the Docker
457
- image is built. Privileged Supabase credentials are not written to the app's public env file.
454
+ \`build-app-image.sh\` requires the app-installed \`node_modules/.bin/expo\` and never resolves
455
+ Expo globally or through the network. It clears the Expo/Metro bundler cache before every web
456
+ export. Expo inlines \`EXPO_PUBLIC_*\` values into the browser bundle, so cache invalidation
457
+ ensures a rotated browser-safe Supabase URL or anon key replaces the previous value before the
458
+ Docker image is built. Privileged Supabase credentials are not written to the app's public env
459
+ file.
458
460
 
459
461
  ## Runtime Conventions
460
462
 
@@ -2958,29 +2960,31 @@ if [[ "\${APP_BUILD_ENABLED}" != "true" ]]; then
2958
2960
  exit 0
2959
2961
  fi
2960
2962
 
2961
- if ! command -v docker >/dev/null 2>&1; then
2962
- echo "docker is required to build app image."
2963
+ if [[ ! -f "\${APP_SOURCE_DIR}/package.json" ]]; then
2964
+ echo "APP_SOURCE_DIR does not look like an app root: \${APP_SOURCE_DIR}"
2963
2965
  exit 1
2964
2966
  fi
2965
2967
 
2966
- if ! command -v bunx >/dev/null 2>&1; then
2967
- echo "bunx is required to export the app for container image build."
2968
+ if [[ ! -f "\${DOCKERFILE_PATH}" ]]; then
2969
+ echo "Dockerfile for app image build is missing: \${DOCKERFILE_PATH}"
2968
2970
  exit 1
2969
2971
  fi
2970
2972
 
2971
- if [[ ! -f "\${APP_SOURCE_DIR}/package.json" ]]; then
2972
- echo "APP_SOURCE_DIR does not look like an app root: \${APP_SOURCE_DIR}"
2973
+ EXPO_CLI="\${APP_SOURCE_DIR}/node_modules/.bin/expo"
2974
+ if [[ ! -x "\${EXPO_CLI}" ]]; then
2975
+ echo "App-owned Expo CLI is missing: \${EXPO_CLI}" >&2
2976
+ echo "Run 'bun install --frozen-lockfile' in \${APP_SOURCE_DIR} before building the app image." >&2
2973
2977
  exit 1
2974
2978
  fi
2975
2979
 
2976
- if [[ ! -f "\${DOCKERFILE_PATH}" ]]; then
2977
- echo "Dockerfile for app image build is missing: \${DOCKERFILE_PATH}"
2980
+ if ! command -v docker >/dev/null 2>&1; then
2981
+ echo "docker is required to build app image."
2978
2982
  exit 1
2979
2983
  fi
2980
2984
 
2981
2985
  (
2982
2986
  cd "\${APP_SOURCE_DIR}"
2983
- bunx expo export --platform web --clear --output-dir "\${APP_WEB_EXPORT_DIR}"
2987
+ "\${EXPO_CLI}" export --platform web --clear --output-dir "\${APP_WEB_EXPORT_DIR}"
2984
2988
  )
2985
2989
 
2986
2990
  if [[ "\${APP_WEB_EXPORT_DIR}" = /* ]]; then