@ankhorage/infra 2.0.0 → 2.0.1

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
+ ## 2.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 6ff65a4: Keep Supabase Auth runtime environment assignments declarative across OAuth reconciliation so repeated Minikube Infra Up runs can safely reapply the generated deployment.
8
+
3
9
  ## 2.0.0
4
10
 
5
11
  ### Major Changes
@@ -78,9 +78,6 @@ function getOAuthProviderLifecycle(oauthRuntime) {
78
78
  }
79
79
  function getOAuthRuntimeReconciliationCommand(oauthRuntime) {
80
80
  const localPatterns = oauthRuntime.localRedirectPatterns.join(',');
81
- const providerRedirectAssignments = oauthRuntime.envPrefixes
82
- .map((prefix) => `GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI="\${oauth_provider_callback}"`)
83
- .join(' ');
84
81
  const providerExports = oauthRuntime.envPrefixes
85
82
  .map((prefix) => `export GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI="\${oauth_provider_callback}"
86
83
  write_env_value GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI "\${oauth_provider_callback}"`)
@@ -96,12 +93,7 @@ fi
96
93
  export ADDITIONAL_REDIRECT_URLS="\${oauth_redirect_allow_list}"
97
94
  write_env_value ADDITIONAL_REDIRECT_URLS "\${oauth_redirect_allow_list}"
98
95
  ${providerExports}
99
- kubectl --context "\${PROFILE}" -n supabase set env deployment/auth \\
100
- API_EXTERNAL_URL="\${API_EXTERNAL_URL}" \\
101
- GOTRUE_SITE_URL="\${SITE_URL}" \\
102
- GOTRUE_URI_ALLOW_LIST="\${oauth_redirect_allow_list}" \\
103
- GOTRUE_JWT_ISSUER="\${API_EXTERNAL_URL}" \\
104
- ${providerRedirectAssignments} >/dev/null
96
+ sync_supabase_secrets
105
97
  kubectl --context "\${PROFILE}" -n supabase rollout restart deployment/auth >/dev/null
106
98
  kubectl --context "\${PROFILE}" -n supabase rollout status deployment/auth --timeout=600s`;
107
99
  }
@@ -136,9 +128,11 @@ Local Minikube reconciliation adds only callback-scoped loopback patterns:
136
128
  ${localPatterns}
137
129
 
138
130
  Native callback URIs may be supplied through \`OAUTH_NATIVE_REDIRECT_URLS\`. The generated
139
- provider lifecycle writes only redirect metadata, never OAuth client secrets. It updates the
140
- GoTrue deployment environment, forces \`deployment/auth\` to restart, and waits up to 600
141
- seconds for the rollout. A failed rollout stops Infra Up before its success message.
131
+ provider lifecycle persists redirect metadata, re-syncs the canonical Supabase runtime
132
+ ConfigMap and Secret sources, then forces \`deployment/auth\` to restart and waits up to 600
133
+ seconds for the rollout. OAuth credential values remain sourced from trusted secret resolution
134
+ and are never embedded in generated files. A failed rollout stops Infra Up before its success
135
+ message.
142
136
  `;
143
137
  }
144
138
  //# sourceMappingURL=oauthRuntime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauthRuntime.js","sourceRoot":"","sources":["../../../../src/adapters/minikube/auth/oauthRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLocalAuthRedirectPatterns, normalizeAuthCallbackRoute } from '../../../authRedirects';\nimport type { InfraManifestInput } from '../../../types';\nimport type { MinikubeAdapterArtifacts, MinikubeProviderLifecycle } from '../contracts';\n\ninterface SupabaseOAuthRuntimeModel {\n callbackRoute: string;\n envPrefixes: readonly string[];\n localRedirectPatterns: readonly string[];\n}\n\nexport function generateSupabaseOAuthRuntimeArtifacts(\n manifest: InfraManifestInput,\n): MinikubeAdapterArtifacts {\n const oauthRuntime = resolveOAuthRuntimeModel(manifest);\n if (!oauthRuntime) {\n return {\n files: [],\n resources: [],\n providerLifecycle: [],\n envEntries: [],\n warnings: [],\n };\n }\n\n return {\n files: [\n {\n path: 'infra/minikube/auth/oauth-runtime.md',\n content: getOAuthRuntimeGuide(oauthRuntime),\n },\n ],\n resources: [],\n providerLifecycle: [getOAuthProviderLifecycle(oauthRuntime)],\n envEntries: [],\n warnings: [],\n };\n}\n\nfunction resolveOAuthRuntimeModel(manifest: InfraManifestInput): SupabaseOAuthRuntimeModel | null {\n const oauth = manifest.auth?.oauth;\n if (!oauth?.enabled) return null;\n\n const providers = oauth.providers.filter((provider) => provider.enabled !== false);\n if (providers.length === 0) return null;\n\n const callbackRoute = normalizeAuthCallbackRoute(oauth.callbackRoute);\n const envPrefixes = providers.map((provider) => {\n const prefix = provider.id\n .trim()\n .toUpperCase()\n .replace(/[^A-Z0-9]+/gu, '_')\n .replace(/^_+|_+$/gu, '');\n if (!prefix) {\n throw new Error(\n `OAuth provider \"${provider.id}\" cannot be mapped to GoTrue environment keys.`,\n );\n }\n return prefix;\n });\n\n return {\n callbackRoute,\n envPrefixes,\n localRedirectPatterns: getLocalAuthRedirectPatterns(callbackRoute),\n };\n}\n\nfunction getOAuthProviderLifecycle(\n oauthRuntime: SupabaseOAuthRuntimeModel,\n): MinikubeProviderLifecycle {\n return {\n id: 'supabase-auth',\n namespace: 'supabase',\n endpoints: [],\n readinessChecks: [\n {\n label: 'GoTrue',\n namespace: 'supabase',\n resource: 'deployment/auth',\n timeoutSeconds: 600,\n },\n ],\n migrationCommands: [],\n reconciliationCommands: [\n {\n label: 'OAuth redirect and runtime rollout reconciliation',\n command: getOAuthRuntimeReconciliationCommand(oauthRuntime),\n },\n ],\n statusChecks: [\n {\n label: 'OAuth redirect configuration',\n command: getOAuthRuntimeStatusCommand(oauthRuntime),\n },\n ],\n };\n}\n\nfunction getOAuthRuntimeReconciliationCommand(oauthRuntime: SupabaseOAuthRuntimeModel): string {\n const localPatterns = oauthRuntime.localRedirectPatterns.join(',');\n const providerRedirectAssignments = oauthRuntime.envPrefixes\n .map((prefix) => `GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI=\"\\${oauth_provider_callback}\"`)\n .join(' ');\n const providerExports = oauthRuntime.envPrefixes\n .map(\n (prefix) => `export GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI=\"\\${oauth_provider_callback}\"\nwrite_env_value GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI \"\\${oauth_provider_callback}\"`,\n )\n .join('\\n');\n\n return `oauth_callback_route='${oauthRuntime.callbackRoute}'\noauth_callback_path=\"\\${oauth_callback_route#/}\"\noauth_site_url=\"\\${SITE_URL%/}\"\noauth_provider_callback=\"\\${API_EXTERNAL_URL%/}/callback\"\noauth_redirect_allow_list=\"\\${oauth_site_url},\\${oauth_site_url}/\\${oauth_callback_path},${localPatterns}\"\nif [[ -n \"\\${OAUTH_NATIVE_REDIRECT_URLS:-}\" ]]; then\n oauth_redirect_allow_list=\"\\${oauth_redirect_allow_list},\\${OAUTH_NATIVE_REDIRECT_URLS}\"\nfi\nexport ADDITIONAL_REDIRECT_URLS=\"\\${oauth_redirect_allow_list}\"\nwrite_env_value ADDITIONAL_REDIRECT_URLS \"\\${oauth_redirect_allow_list}\"\n${providerExports}\nkubectl --context \"\\${PROFILE}\" -n supabase set env deployment/auth \\\\\n API_EXTERNAL_URL=\"\\${API_EXTERNAL_URL}\" \\\\\n GOTRUE_SITE_URL=\"\\${SITE_URL}\" \\\\\n GOTRUE_URI_ALLOW_LIST=\"\\${oauth_redirect_allow_list}\" \\\\\n GOTRUE_JWT_ISSUER=\"\\${API_EXTERNAL_URL}\" \\\\\n ${providerRedirectAssignments} >/dev/null\nkubectl --context \"\\${PROFILE}\" -n supabase rollout restart deployment/auth >/dev/null\nkubectl --context \"\\${PROFILE}\" -n supabase rollout status deployment/auth --timeout=600s`;\n}\n\nfunction getOAuthRuntimeStatusCommand(oauthRuntime: SupabaseOAuthRuntimeModel): string {\n return `oauth_callback_route='${oauthRuntime.callbackRoute}'\noauth_callback_path=\"\\${oauth_callback_route#/}\"\nif [[ -n \"\\${API_EXTERNAL_URL:-}\" ]]; then\n echo \"- provider supabase-auth/provider-callback: \\${API_EXTERNAL_URL%/}/callback\"\nelse\n echo \"- provider supabase-auth/provider-callback: unavailable\"\nfi\nif [[ -n \"\\${SITE_URL:-}\" ]]; then\n echo \"- provider supabase-auth/app-callback: \\${SITE_URL%/}/\\${oauth_callback_path}\"\nelse\n echo \"- provider supabase-auth/app-callback: unavailable\"\nfi\necho \"- provider supabase-auth/local-callback-patterns: ${oauthRuntime.localRedirectPatterns.join(',')}\"`;\n}\n\nfunction getOAuthRuntimeGuide(oauthRuntime: SupabaseOAuthRuntimeModel): string {\n const localPatterns = oauthRuntime.localRedirectPatterns\n .map((pattern) => `- \\`${pattern}\\``)\n .join('\\n');\n\n return `# Supabase OAuth Runtime Reconciliation\n\nThe provider callback is derived from the active project gateway as\n\\`\\${API_EXTERNAL_URL%/}/callback\\`, which resolves to the project-owned\n\\`/auth/v1/callback\\` endpoint. GoTrue-to-app redirects use the configured callback route\n\\`${oauthRuntime.callbackRoute}\\`.\n\nLocal Minikube reconciliation adds only callback-scoped loopback patterns:\n\n${localPatterns}\n\nNative callback URIs may be supplied through \\`OAUTH_NATIVE_REDIRECT_URLS\\`. The generated\nprovider lifecycle writes only redirect metadata, never OAuth client secrets. It updates the\nGoTrue deployment environment, forces \\`deployment/auth\\` to restart, and waits up to 600\nseconds for the rollout. A failed rollout stops Infra Up before its success message.\n`;\n}\n"]}
1
+ {"version":3,"file":"oauthRuntime.js","sourceRoot":"","sources":["../../../../src/adapters/minikube/auth/oauthRuntime.ts"],"names":[],"mappings":"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","sourcesContent":["import { getLocalAuthRedirectPatterns, normalizeAuthCallbackRoute } from '../../../authRedirects';\nimport type { InfraManifestInput } from '../../../types';\nimport type { MinikubeAdapterArtifacts, MinikubeProviderLifecycle } from '../contracts';\n\ninterface SupabaseOAuthRuntimeModel {\n callbackRoute: string;\n envPrefixes: readonly string[];\n localRedirectPatterns: readonly string[];\n}\n\nexport function generateSupabaseOAuthRuntimeArtifacts(\n manifest: InfraManifestInput,\n): MinikubeAdapterArtifacts {\n const oauthRuntime = resolveOAuthRuntimeModel(manifest);\n if (!oauthRuntime) {\n return {\n files: [],\n resources: [],\n providerLifecycle: [],\n envEntries: [],\n warnings: [],\n };\n }\n\n return {\n files: [\n {\n path: 'infra/minikube/auth/oauth-runtime.md',\n content: getOAuthRuntimeGuide(oauthRuntime),\n },\n ],\n resources: [],\n providerLifecycle: [getOAuthProviderLifecycle(oauthRuntime)],\n envEntries: [],\n warnings: [],\n };\n}\n\nfunction resolveOAuthRuntimeModel(manifest: InfraManifestInput): SupabaseOAuthRuntimeModel | null {\n const oauth = manifest.auth?.oauth;\n if (!oauth?.enabled) return null;\n\n const providers = oauth.providers.filter((provider) => provider.enabled !== false);\n if (providers.length === 0) return null;\n\n const callbackRoute = normalizeAuthCallbackRoute(oauth.callbackRoute);\n const envPrefixes = providers.map((provider) => {\n const prefix = provider.id\n .trim()\n .toUpperCase()\n .replace(/[^A-Z0-9]+/gu, '_')\n .replace(/^_+|_+$/gu, '');\n if (!prefix) {\n throw new Error(\n `OAuth provider \"${provider.id}\" cannot be mapped to GoTrue environment keys.`,\n );\n }\n return prefix;\n });\n\n return {\n callbackRoute,\n envPrefixes,\n localRedirectPatterns: getLocalAuthRedirectPatterns(callbackRoute),\n };\n}\n\nfunction getOAuthProviderLifecycle(\n oauthRuntime: SupabaseOAuthRuntimeModel,\n): MinikubeProviderLifecycle {\n return {\n id: 'supabase-auth',\n namespace: 'supabase',\n endpoints: [],\n readinessChecks: [\n {\n label: 'GoTrue',\n namespace: 'supabase',\n resource: 'deployment/auth',\n timeoutSeconds: 600,\n },\n ],\n migrationCommands: [],\n reconciliationCommands: [\n {\n label: 'OAuth redirect and runtime rollout reconciliation',\n command: getOAuthRuntimeReconciliationCommand(oauthRuntime),\n },\n ],\n statusChecks: [\n {\n label: 'OAuth redirect configuration',\n command: getOAuthRuntimeStatusCommand(oauthRuntime),\n },\n ],\n };\n}\n\nfunction getOAuthRuntimeReconciliationCommand(oauthRuntime: SupabaseOAuthRuntimeModel): string {\n const localPatterns = oauthRuntime.localRedirectPatterns.join(',');\n const providerExports = oauthRuntime.envPrefixes\n .map(\n (prefix) => `export GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI=\"\\${oauth_provider_callback}\"\nwrite_env_value GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI \"\\${oauth_provider_callback}\"`,\n )\n .join('\\n');\n\n return `oauth_callback_route='${oauthRuntime.callbackRoute}'\noauth_callback_path=\"\\${oauth_callback_route#/}\"\noauth_site_url=\"\\${SITE_URL%/}\"\noauth_provider_callback=\"\\${API_EXTERNAL_URL%/}/callback\"\noauth_redirect_allow_list=\"\\${oauth_site_url},\\${oauth_site_url}/\\${oauth_callback_path},${localPatterns}\"\nif [[ -n \"\\${OAUTH_NATIVE_REDIRECT_URLS:-}\" ]]; then\n oauth_redirect_allow_list=\"\\${oauth_redirect_allow_list},\\${OAUTH_NATIVE_REDIRECT_URLS}\"\nfi\nexport ADDITIONAL_REDIRECT_URLS=\"\\${oauth_redirect_allow_list}\"\nwrite_env_value ADDITIONAL_REDIRECT_URLS \"\\${oauth_redirect_allow_list}\"\n${providerExports}\nsync_supabase_secrets\nkubectl --context \"\\${PROFILE}\" -n supabase rollout restart deployment/auth >/dev/null\nkubectl --context \"\\${PROFILE}\" -n supabase rollout status deployment/auth --timeout=600s`;\n}\n\nfunction getOAuthRuntimeStatusCommand(oauthRuntime: SupabaseOAuthRuntimeModel): string {\n return `oauth_callback_route='${oauthRuntime.callbackRoute}'\noauth_callback_path=\"\\${oauth_callback_route#/}\"\nif [[ -n \"\\${API_EXTERNAL_URL:-}\" ]]; then\n echo \"- provider supabase-auth/provider-callback: \\${API_EXTERNAL_URL%/}/callback\"\nelse\n echo \"- provider supabase-auth/provider-callback: unavailable\"\nfi\nif [[ -n \"\\${SITE_URL:-}\" ]]; then\n echo \"- provider supabase-auth/app-callback: \\${SITE_URL%/}/\\${oauth_callback_path}\"\nelse\n echo \"- provider supabase-auth/app-callback: unavailable\"\nfi\necho \"- provider supabase-auth/local-callback-patterns: ${oauthRuntime.localRedirectPatterns.join(',')}\"`;\n}\n\nfunction getOAuthRuntimeGuide(oauthRuntime: SupabaseOAuthRuntimeModel): string {\n const localPatterns = oauthRuntime.localRedirectPatterns\n .map((pattern) => `- \\`${pattern}\\``)\n .join('\\n');\n\n return `# Supabase OAuth Runtime Reconciliation\n\nThe provider callback is derived from the active project gateway as\n\\`\\${API_EXTERNAL_URL%/}/callback\\`, which resolves to the project-owned\n\\`/auth/v1/callback\\` endpoint. GoTrue-to-app redirects use the configured callback route\n\\`${oauthRuntime.callbackRoute}\\`.\n\nLocal Minikube reconciliation adds only callback-scoped loopback patterns:\n\n${localPatterns}\n\nNative callback URIs may be supplied through \\`OAUTH_NATIVE_REDIRECT_URLS\\`. The generated\nprovider lifecycle persists redirect metadata, re-syncs the canonical Supabase runtime\nConfigMap and Secret sources, then forces \\`deployment/auth\\` to restart and waits up to 600\nseconds for the rollout. OAuth credential values remain sourced from trusted secret resolution\nand are never embedded in generated files. A failed rollout stops Infra Up before its success\nmessage.\n`;\n}\n"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ankhorage/infra",
3
3
  "type": "module",
4
- "version": "2.0.0",
4
+ "version": "2.0.1",
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": {
@@ -98,9 +98,6 @@ function getOAuthProviderLifecycle(
98
98
 
99
99
  function getOAuthRuntimeReconciliationCommand(oauthRuntime: SupabaseOAuthRuntimeModel): string {
100
100
  const localPatterns = oauthRuntime.localRedirectPatterns.join(',');
101
- const providerRedirectAssignments = oauthRuntime.envPrefixes
102
- .map((prefix) => `GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI="\${oauth_provider_callback}"`)
103
- .join(' ');
104
101
  const providerExports = oauthRuntime.envPrefixes
105
102
  .map(
106
103
  (prefix) => `export GOTRUE_EXTERNAL_${prefix}_REDIRECT_URI="\${oauth_provider_callback}"
@@ -119,12 +116,7 @@ fi
119
116
  export ADDITIONAL_REDIRECT_URLS="\${oauth_redirect_allow_list}"
120
117
  write_env_value ADDITIONAL_REDIRECT_URLS "\${oauth_redirect_allow_list}"
121
118
  ${providerExports}
122
- kubectl --context "\${PROFILE}" -n supabase set env deployment/auth \\
123
- API_EXTERNAL_URL="\${API_EXTERNAL_URL}" \\
124
- GOTRUE_SITE_URL="\${SITE_URL}" \\
125
- GOTRUE_URI_ALLOW_LIST="\${oauth_redirect_allow_list}" \\
126
- GOTRUE_JWT_ISSUER="\${API_EXTERNAL_URL}" \\
127
- ${providerRedirectAssignments} >/dev/null
119
+ sync_supabase_secrets
128
120
  kubectl --context "\${PROFILE}" -n supabase rollout restart deployment/auth >/dev/null
129
121
  kubectl --context "\${PROFILE}" -n supabase rollout status deployment/auth --timeout=600s`;
130
122
  }
@@ -162,8 +154,10 @@ Local Minikube reconciliation adds only callback-scoped loopback patterns:
162
154
  ${localPatterns}
163
155
 
164
156
  Native callback URIs may be supplied through \`OAUTH_NATIVE_REDIRECT_URLS\`. The generated
165
- provider lifecycle writes only redirect metadata, never OAuth client secrets. It updates the
166
- GoTrue deployment environment, forces \`deployment/auth\` to restart, and waits up to 600
167
- seconds for the rollout. A failed rollout stops Infra Up before its success message.
157
+ provider lifecycle persists redirect metadata, re-syncs the canonical Supabase runtime
158
+ ConfigMap and Secret sources, then forces \`deployment/auth\` to restart and waits up to 600
159
+ seconds for the rollout. OAuth credential values remain sourced from trusted secret resolution
160
+ and are never embedded in generated files. A failed rollout stops Infra Up before its success
161
+ message.
168
162
  `;
169
163
  }
@@ -12,6 +12,7 @@ describe('Supabase OAuth runtime reconciliation', () => {
12
12
  const command = lifecycle?.reconciliationCommands[0]?.command ?? '';
13
13
  const statusCommand = lifecycle?.statusChecks[0]?.command ?? '';
14
14
  const guide = getFile(artifacts.files, 'infra/minikube/auth/oauth-runtime.md');
15
+ const normalizedGuide = guide.replace(/\s+/gu, ' ');
15
16
 
16
17
  expect(lifecycle?.id).toBe('supabase-auth');
17
18
  expect(lifecycle?.namespace).toBe('supabase');
@@ -28,10 +29,11 @@ describe('Supabase OAuth runtime reconciliation', () => {
28
29
  expect(command).toContain('http://localhost:*/auth/callback');
29
30
  expect(command).toContain('OAUTH_NATIVE_REDIRECT_URLS');
30
31
  expect(command).toContain('GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI="${oauth_provider_callback}"');
31
- expect(command).toContain('GOTRUE_URI_ALLOW_LIST="${oauth_redirect_allow_list}"');
32
+ expect(command).toContain('sync_supabase_secrets');
33
+ expect(command).not.toContain('set env deployment/auth');
32
34
  expect(command).toContain('rollout restart deployment/auth');
33
35
  expect(command).toContain('rollout status deployment/auth --timeout=600s');
34
- expect(command.indexOf('set env deployment/auth')).toBeLessThan(
36
+ expect(command.indexOf('sync_supabase_secrets')).toBeLessThan(
35
37
  command.indexOf('rollout restart deployment/auth'),
36
38
  );
37
39
  expect(command.indexOf('rollout restart deployment/auth')).toBeLessThan(
@@ -41,15 +43,19 @@ describe('Supabase OAuth runtime reconciliation', () => {
41
43
  expect(command).not.toContain('GOTRUE_EXTERNAL_GOOGLE_SECRET=');
42
44
  expect(statusCommand).toContain('provider supabase-auth/provider-callback');
43
45
  expect(statusCommand).toContain('provider supabase-auth/app-callback');
44
- expect(guide).toContain('Supabase OAuth Runtime Reconciliation');
45
- expect(guide).toContain('A failed rollout stops Infra Up before its success message.');
46
+ expect(normalizedGuide).toContain('Supabase OAuth Runtime Reconciliation');
47
+ expect(normalizedGuide).toContain('re-syncs the canonical Supabase runtime');
48
+ expect(normalizedGuide).toContain(
49
+ 'A failed rollout stops Infra Up before its success message.',
50
+ );
46
51
  });
47
52
 
48
- test('integrates reconciliation after generated runtime resources without duplicate namespaces', () => {
53
+ test('keeps Auth deployment environment declarative across reconciliation', () => {
49
54
  const result = generateInfrastructure(createOAuthManifest(), {
50
55
  appManifest: createAppManifest('oauth-app'),
51
56
  });
52
57
  const upScript = getFile(result.files, 'infra/minikube/scripts/up.sh');
58
+ const authManifest = getFile(result.files, 'infra/minikube/k8s/supabase/auth.yaml');
53
59
  const kustomization = getFile(result.files, 'infra/minikube/k8s/kustomization.yaml');
54
60
  const statusScript = getFile(result.files, 'infra/minikube/scripts/status.sh');
55
61
 
@@ -57,15 +63,20 @@ describe('Supabase OAuth runtime reconciliation', () => {
57
63
  expect(upScript).toContain(
58
64
  'Running provider supabase-auth OAuth redirect and runtime rollout reconciliation.',
59
65
  );
60
- expect(upScript).toContain(
66
+ expect(upScript).not.toContain(
61
67
  'kubectl --context "${PROFILE}" -n supabase set env deployment/auth',
62
68
  );
69
+ expect(upScript).toContain('sync_supabase_secrets');
63
70
  expect(upScript).toContain(
64
71
  'kubectl --context "${PROFILE}" -n supabase rollout restart deployment/auth',
65
72
  );
66
73
  expect(upScript).toContain(
67
74
  'kubectl --context "${PROFILE}" -n supabase rollout status deployment/auth --timeout=600s',
68
75
  );
76
+ expect(authManifest).toContain('name: API_EXTERNAL_URL\n valueFrom:');
77
+ expect(authManifest).toContain('name: GOTRUE_SITE_URL\n valueFrom:');
78
+ expect(authManifest).toContain('name: GOTRUE_URI_ALLOW_LIST\n valueFrom:');
79
+ expect(authManifest).toContain('name: GOTRUE_JWT_ISSUER\n valueFrom:');
69
80
  expect(upScript.lastIndexOf('run_provider_reconciliation')).toBeLessThan(
70
81
  upScript.lastIndexOf('echo "Minikube infrastructure for \'${PROFILE}\' is running."'),
71
82
  );