@ankhorage/infra 0.4.1 → 1.0.0
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 +15 -0
- package/README.md +1 -1
- package/dist/adapters/minikube/auth/supabase/index.d.ts.map +1 -1
- package/dist/adapters/minikube/auth/supabase/index.js +9 -39
- package/dist/adapters/minikube/auth/supabase/index.js.map +1 -1
- package/dist/adapters/minikube/auth/supabase/profile.d.ts +0 -1
- package/dist/adapters/minikube/auth/supabase/profile.d.ts.map +1 -1
- package/dist/adapters/minikube/auth/supabase/profile.js +1 -1
- package/dist/adapters/minikube/auth/supabase/profile.js.map +1 -1
- package/dist/adapters/minikube/authz/cerbos/index.d.ts.map +1 -1
- package/dist/adapters/minikube/authz/cerbos/index.js +22 -2
- package/dist/adapters/minikube/authz/cerbos/index.js.map +1 -1
- package/dist/adapters/minikube/base/index.d.ts +5 -2
- package/dist/adapters/minikube/base/index.d.ts.map +1 -1
- package/dist/adapters/minikube/base/index.js +2728 -1835
- package/dist/adapters/minikube/base/index.js.map +1 -1
- package/dist/adapters/minikube/contracts.d.ts +25 -0
- package/dist/adapters/minikube/contracts.d.ts.map +1 -1
- package/dist/adapters/minikube/contracts.js +1 -0
- package/dist/adapters/minikube/contracts.js.map +1 -1
- package/dist/adapters/minikube/index.d.ts.map +1 -1
- package/dist/adapters/minikube/index.js +18 -33
- package/dist/adapters/minikube/index.js.map +1 -1
- package/dist/adapters/minikube/secrets/supabase-vault/index.d.ts.map +1 -1
- package/dist/adapters/minikube/secrets/supabase-vault/index.js +49 -6
- package/dist/adapters/minikube/secrets/supabase-vault/index.js.map +1 -1
- package/dist/adapters/minikube/storage/supabase/index.d.ts.map +1 -1
- package/dist/adapters/minikube/storage/supabase/index.js +2 -1
- package/dist/adapters/minikube/storage/supabase/index.js.map +1 -1
- package/package.json +4 -1
- package/src/adapters/minikube/README.md +41 -38
- package/src/adapters/minikube/auth/supabase/index.ts +9 -40
- package/src/adapters/minikube/auth/supabase/profile.integration.test.ts +170 -2
- package/src/adapters/minikube/auth/supabase/profile.ts +1 -1
- package/src/adapters/minikube/authz/cerbos/index.ts +25 -3
- package/src/adapters/minikube/base/index.test.ts +380 -579
- package/src/adapters/minikube/base/index.ts +2935 -1870
- package/src/adapters/minikube/base/twoAppIsolation.integration.test.ts +636 -0
- package/src/adapters/minikube/contracts.ts +29 -0
- package/src/adapters/minikube/index.ts +18 -44
- package/src/adapters/minikube/secrets/index.test.ts +15 -7
- package/src/adapters/minikube/secrets/supabase-vault/index.ts +53 -6
- package/src/adapters/minikube/storage/supabase/index.ts +1 -5
- package/src/apis.test.ts +2 -1
- package/src/index.test.ts +63 -577
- package/src/minikubeImageLifecycle.test.ts +4 -3
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
import type { GeneratedInfrastructureFile } from '../../types';
|
|
2
|
+
interface MinikubeProviderEndpoint {
|
|
3
|
+
name: string;
|
|
4
|
+
url: string;
|
|
5
|
+
}
|
|
6
|
+
interface MinikubeProviderReadinessCheck {
|
|
7
|
+
label: string;
|
|
8
|
+
namespace: string;
|
|
9
|
+
resource: string;
|
|
10
|
+
timeoutSeconds: number;
|
|
11
|
+
}
|
|
12
|
+
interface MinikubeProviderLifecycleCommand {
|
|
13
|
+
label: string;
|
|
14
|
+
command: string;
|
|
15
|
+
}
|
|
16
|
+
export interface MinikubeProviderLifecycle {
|
|
17
|
+
id: string;
|
|
18
|
+
namespace: string;
|
|
19
|
+
endpoints: MinikubeProviderEndpoint[];
|
|
20
|
+
readinessChecks: MinikubeProviderReadinessCheck[];
|
|
21
|
+
migrationCommands: MinikubeProviderLifecycleCommand[];
|
|
22
|
+
reconciliationCommands: MinikubeProviderLifecycleCommand[];
|
|
23
|
+
statusChecks: MinikubeProviderLifecycleCommand[];
|
|
24
|
+
}
|
|
2
25
|
export interface MinikubeAdapterArtifacts {
|
|
3
26
|
files: GeneratedInfrastructureFile[];
|
|
4
27
|
resources: string[];
|
|
28
|
+
providerLifecycle: MinikubeProviderLifecycle[];
|
|
5
29
|
envEntries: string[];
|
|
6
30
|
warnings: string[];
|
|
7
31
|
}
|
|
8
32
|
export declare function emptyMinikubeArtifacts(): MinikubeAdapterArtifacts;
|
|
33
|
+
export {};
|
|
9
34
|
//# sourceMappingURL=contracts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../../src/adapters/minikube/contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAE/D,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,2BAA2B,EAAE,CAAC;IACrC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,sBAAsB,IAAI,wBAAwB,
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../../../src/adapters/minikube/contracts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AAE/D,UAAU,wBAAwB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,UAAU,8BAA8B;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,gCAAgC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,wBAAwB,EAAE,CAAC;IACtC,eAAe,EAAE,8BAA8B,EAAE,CAAC;IAClD,iBAAiB,EAAE,gCAAgC,EAAE,CAAC;IACtD,sBAAsB,EAAE,gCAAgC,EAAE,CAAC;IAC3D,YAAY,EAAE,gCAAgC,EAAE,CAAC;CAClD;AAED,MAAM,WAAW,wBAAwB;IACvC,KAAK,EAAE,2BAA2B,EAAE,CAAC;IACrC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,iBAAiB,EAAE,yBAAyB,EAAE,CAAC;IAC/C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAgB,sBAAsB,IAAI,wBAAwB,CAQjE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../../src/adapters/minikube/contracts.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../../src/adapters/minikube/contracts.ts"],"names":[],"mappings":"AAqCA,MAAM,UAAU,sBAAsB;IACpC,OAAO;QACL,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,EAAE;QACb,iBAAiB,EAAE,EAAE;QACrB,UAAU,EAAE,EAAE;QACd,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC","sourcesContent":["import type { GeneratedInfrastructureFile } from '../../types';\n\ninterface MinikubeProviderEndpoint {\n name: string;\n url: string;\n}\n\ninterface MinikubeProviderReadinessCheck {\n label: string;\n namespace: string;\n resource: string;\n timeoutSeconds: number;\n}\n\ninterface MinikubeProviderLifecycleCommand {\n label: string;\n command: string;\n}\n\nexport interface MinikubeProviderLifecycle {\n id: string;\n namespace: string;\n endpoints: MinikubeProviderEndpoint[];\n readinessChecks: MinikubeProviderReadinessCheck[];\n migrationCommands: MinikubeProviderLifecycleCommand[];\n reconciliationCommands: MinikubeProviderLifecycleCommand[];\n statusChecks: MinikubeProviderLifecycleCommand[];\n}\n\nexport interface MinikubeAdapterArtifacts {\n files: GeneratedInfrastructureFile[];\n resources: string[];\n providerLifecycle: MinikubeProviderLifecycle[];\n envEntries: string[];\n warnings: string[];\n}\n\nexport function emptyMinikubeArtifacts(): MinikubeAdapterArtifacts {\n return {\n files: [],\n resources: [],\n providerLifecycle: [],\n envEntries: [],\n warnings: [],\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,aAAa,CAAC;AASrB,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,GAAE,+BAAoC,GAC5C,8BAA8B,CAqFhC"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { generateApiInfrastructureArtifacts } from '../../apiArtifacts';
|
|
2
2
|
import { generateAuthProviderArtifacts } from './auth';
|
|
3
3
|
import { generateAuthorizationArtifacts } from './authz';
|
|
4
|
-
import { generateMinikubeBaseArtifacts } from './base';
|
|
4
|
+
import { APP_NAMESPACE, generateMinikubeBaseArtifacts } from './base';
|
|
5
5
|
import { generateSecretStoreArtifacts } from './secrets';
|
|
6
6
|
import { generateStorageArtifacts } from './storage';
|
|
7
|
-
const DEFAULT_NAMESPACE = 'ankh-app';
|
|
8
7
|
const CANONICAL_PROJECT_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$/;
|
|
9
8
|
export function generateMinikubeInfra(manifest, options = {}) {
|
|
10
9
|
if (manifest.deployment?.target !== 'minikube') {
|
|
@@ -13,10 +12,8 @@ export function generateMinikubeInfra(manifest, options = {}) {
|
|
|
13
12
|
if (manifest.database?.provider && manifest.database.provider !== 'supabase') {
|
|
14
13
|
throw new Error(`Unsupported database provider for minikube adapter: "${manifest.database.provider}". Only "supabase" is implemented.`);
|
|
15
14
|
}
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
? validateCanonicalProjectSlug(options.appManifest?.metadata.slug)
|
|
19
|
-
: null;
|
|
15
|
+
const appSlug = validateCanonicalAppSlug(options.appManifest?.metadata.slug);
|
|
16
|
+
const namespace = APP_NAMESPACE;
|
|
20
17
|
const authArtifacts = generateAuthProviderArtifacts({ manifest, namespace });
|
|
21
18
|
const authzArtifacts = generateAuthorizationArtifacts({
|
|
22
19
|
manifest,
|
|
@@ -35,6 +32,15 @@ export function generateMinikubeInfra(manifest, options = {}) {
|
|
|
35
32
|
...storageArtifacts.resources,
|
|
36
33
|
...secretStoreArtifacts.resources,
|
|
37
34
|
]);
|
|
35
|
+
const providerLifecycle = [
|
|
36
|
+
...authArtifacts.providerLifecycle,
|
|
37
|
+
...authzArtifacts.providerLifecycle,
|
|
38
|
+
...storageArtifacts.providerLifecycle,
|
|
39
|
+
...secretStoreArtifacts.providerLifecycle,
|
|
40
|
+
];
|
|
41
|
+
const providerNamespaces = unique([
|
|
42
|
+
...providerLifecycle.map((contribution) => contribution.namespace),
|
|
43
|
+
]);
|
|
38
44
|
const extraEnvEntries = unique([
|
|
39
45
|
...authArtifacts.envEntries,
|
|
40
46
|
...authzArtifacts.envEntries,
|
|
@@ -43,9 +49,10 @@ export function generateMinikubeInfra(manifest, options = {}) {
|
|
|
43
49
|
]);
|
|
44
50
|
const baseFiles = generateMinikubeBaseArtifacts({
|
|
45
51
|
manifest,
|
|
46
|
-
|
|
47
|
-
supabaseProjectId,
|
|
52
|
+
appSlug,
|
|
48
53
|
extraResources,
|
|
54
|
+
providerNamespaces,
|
|
55
|
+
providerLifecycle,
|
|
49
56
|
extraEnvEntries,
|
|
50
57
|
});
|
|
51
58
|
const warnings = unique([
|
|
@@ -112,37 +119,15 @@ function collectWarnings(manifest) {
|
|
|
112
119
|
}
|
|
113
120
|
return warnings;
|
|
114
121
|
}
|
|
115
|
-
function
|
|
116
|
-
const authProvider = manifest.auth?.provider;
|
|
117
|
-
const databaseProvider = manifest.database?.provider;
|
|
118
|
-
const storageProvider = manifest.storage?.provider;
|
|
119
|
-
const secretStoreProvider = manifest.secretStore?.provider;
|
|
120
|
-
return (authProvider === 'supabase' ||
|
|
121
|
-
databaseProvider === 'supabase' ||
|
|
122
|
-
storageProvider === 'supabase' ||
|
|
123
|
-
(storageProvider === 'auto' &&
|
|
124
|
-
(authProvider === 'supabase' || databaseProvider === 'supabase')) ||
|
|
125
|
-
secretStoreProvider === 'supabase-vault');
|
|
126
|
-
}
|
|
127
|
-
function validateCanonicalProjectSlug(slug) {
|
|
122
|
+
function validateCanonicalAppSlug(slug) {
|
|
128
123
|
if (!slug) {
|
|
129
|
-
throw new Error('Cannot generate
|
|
124
|
+
throw new Error('Cannot generate Minikube infrastructure: appManifest.metadata.slug is required.');
|
|
130
125
|
}
|
|
131
126
|
if (slug.trim() !== slug || !CANONICAL_PROJECT_SLUG_RE.test(slug)) {
|
|
132
|
-
throw new Error('Cannot generate
|
|
127
|
+
throw new Error('Cannot generate Minikube infrastructure: appManifest.metadata.slug must be a canonical lowercase slug up to 40 characters using only a-z, 0-9, and hyphens, without leading or trailing hyphens.');
|
|
133
128
|
}
|
|
134
129
|
return slug;
|
|
135
130
|
}
|
|
136
|
-
function resolveNamespace(manifest, options) {
|
|
137
|
-
const source = manifest.networking?.domain?.trim() ?? options.namespaceHint?.trim() ?? DEFAULT_NAMESPACE;
|
|
138
|
-
const normalized = source
|
|
139
|
-
.toLowerCase()
|
|
140
|
-
.replace(/[^a-z0-9-]/g, '-')
|
|
141
|
-
.replace(/-+/g, '-')
|
|
142
|
-
.replace(/^-|-$/g, '');
|
|
143
|
-
const safe = normalized.slice(0, 63).replace(/-+$/g, '');
|
|
144
|
-
return safe || DEFAULT_NAMESPACE;
|
|
145
|
-
}
|
|
146
131
|
function unique(values) {
|
|
147
132
|
return [...new Set(values)];
|
|
148
133
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { generateApiInfrastructureArtifacts } from '../../apiArtifacts';\nimport type {\n GeneratedPackageDependency,\n InfraManifestInput,\n InfrastructureGenerationOptions,\n InfrastructureGenerationResult,\n} from '../../types';\nimport { generateAuthProviderArtifacts } from './auth';\nimport { generateAuthorizationArtifacts } from './authz';\nimport { generateMinikubeBaseArtifacts } from './base';\nimport { generateSecretStoreArtifacts } from './secrets';\nimport { generateStorageArtifacts } from './storage';\n\nconst DEFAULT_NAMESPACE = 'ankh-app';\nconst CANONICAL_PROJECT_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$/;\n\nexport function generateMinikubeInfra(\n manifest: InfraManifestInput,\n options: InfrastructureGenerationOptions = {},\n): InfrastructureGenerationResult {\n if (manifest.deployment?.target !== 'minikube') {\n throw new Error(\n `Minikube adapter only supports deployment target \"minikube\" (received \"${manifest.deployment?.target ?? 'undefined'}\").`,\n );\n }\n\n if (manifest.database?.provider && manifest.database.provider !== 'supabase') {\n throw new Error(\n `Unsupported database provider for minikube adapter: \"${manifest.database.provider}\". Only \"supabase\" is implemented.`,\n );\n }\n\n const namespace = resolveNamespace(manifest, options);\n const supabaseProjectId = isSupabaseLocalEnabled(manifest)\n ? validateCanonicalProjectSlug(options.appManifest?.metadata.slug)\n : null;\n\n const authArtifacts = generateAuthProviderArtifacts({ manifest, namespace });\n const authzArtifacts = generateAuthorizationArtifacts({\n manifest,\n namespace,\n appManifest: options.appManifest,\n });\n const storageArtifacts = generateStorageArtifacts({ manifest, namespace });\n const secretStoreArtifacts = generateSecretStoreArtifacts({ manifest, namespace });\n const apiArtifacts = generateApiInfrastructureArtifacts({\n data: options.appManifest?.data,\n databaseProvider: manifest.database?.provider,\n });\n\n const extraResources = unique([\n ...authArtifacts.resources,\n ...authzArtifacts.resources,\n ...storageArtifacts.resources,\n ...secretStoreArtifacts.resources,\n ]);\n const extraEnvEntries = unique([\n ...authArtifacts.envEntries,\n ...authzArtifacts.envEntries,\n ...storageArtifacts.envEntries,\n ...secretStoreArtifacts.envEntries,\n ]);\n\n const baseFiles = generateMinikubeBaseArtifacts({\n manifest,\n namespace,\n supabaseProjectId,\n extraResources,\n extraEnvEntries,\n });\n\n const warnings = unique([\n ...collectWarnings(manifest),\n ...authArtifacts.warnings,\n ...authzArtifacts.warnings,\n ...storageArtifacts.warnings,\n ...secretStoreArtifacts.warnings,\n ...apiArtifacts.warnings,\n ]);\n\n return {\n files: [\n ...baseFiles,\n ...authArtifacts.files,\n ...authzArtifacts.files,\n ...storageArtifacts.files,\n ...secretStoreArtifacts.files,\n ...apiArtifacts.files,\n ],\n warnings,\n meta: {\n target: 'minikube',\n providers: collectProviders(manifest),\n },\n dependencies: collectDependencies(manifest),\n };\n}\n\nfunction collectProviders(manifest: InfraManifestInput): string[] {\n const providers = new Set<string>();\n\n if (manifest.auth?.provider) providers.add(manifest.auth.provider);\n if (manifest.auth?.authorization?.engine) {\n providers.add(manifest.auth.authorization.engine);\n }\n if (manifest.database?.provider) providers.add(manifest.database.provider);\n if (manifest.storage?.provider) providers.add(manifest.storage.provider);\n if (manifest.secretStore?.provider) providers.add(manifest.secretStore.provider);\n if (manifest.state?.provider) providers.add(manifest.state.provider);\n\n return [...providers].sort();\n}\n\nfunction collectDependencies(manifest: InfraManifestInput): readonly GeneratedPackageDependency[] {\n if (manifest.state?.provider !== 'legend') {\n return [];\n }\n\n return [\n {\n name: '@ankhorage/state-legend',\n version: '^0.1.0',\n reason: 'Selected by infra.state.provider=legend.',\n },\n ];\n}\n\nfunction collectWarnings(manifest: InfraManifestInput): string[] {\n const warnings: string[] = [];\n\n if (manifest.deployment?.monitoring) {\n warnings.push(\n 'Monitoring is enabled in manifest, but monitoring stack resources are not generated yet.',\n );\n }\n\n if (manifest.networking?.cdn) {\n warnings.push('CDN is enabled in manifest, but CDN resources are not generated for minikube.');\n }\n\n return warnings;\n}\n\nfunction isSupabaseLocalEnabled(manifest: InfraManifestInput): boolean {\n const authProvider = manifest.auth?.provider;\n const databaseProvider = manifest.database?.provider;\n const storageProvider = manifest.storage?.provider;\n const secretStoreProvider = manifest.secretStore?.provider;\n\n return (\n authProvider === 'supabase' ||\n databaseProvider === 'supabase' ||\n storageProvider === 'supabase' ||\n (storageProvider === 'auto' &&\n (authProvider === 'supabase' || databaseProvider === 'supabase')) ||\n secretStoreProvider === 'supabase-vault'\n );\n}\n\nfunction validateCanonicalProjectSlug(slug: string | undefined): string {\n if (!slug) {\n throw new Error(\n 'Cannot generate local Supabase infrastructure: appManifest.metadata.slug is required.',\n );\n }\n\n if (slug.trim() !== slug || !CANONICAL_PROJECT_SLUG_RE.test(slug)) {\n throw new Error(\n 'Cannot generate local Supabase infrastructure: appManifest.metadata.slug must be a canonical lowercase slug up to 40 characters using only a-z, 0-9, and hyphens, without leading or trailing hyphens.',\n );\n }\n\n return slug;\n}\n\nfunction resolveNamespace(\n manifest: InfraManifestInput,\n options: InfrastructureGenerationOptions,\n): string {\n const source =\n manifest.networking?.domain?.trim() ?? options.namespaceHint?.trim() ?? DEFAULT_NAMESPACE;\n\n const normalized = source\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '');\n\n const safe = normalized.slice(0, 63).replace(/-+$/g, '');\n return safe || DEFAULT_NAMESPACE;\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { generateApiInfrastructureArtifacts } from '../../apiArtifacts';\nimport type {\n GeneratedPackageDependency,\n InfraManifestInput,\n InfrastructureGenerationOptions,\n InfrastructureGenerationResult,\n} from '../../types';\nimport { generateAuthProviderArtifacts } from './auth';\nimport { generateAuthorizationArtifacts } from './authz';\nimport { APP_NAMESPACE, generateMinikubeBaseArtifacts } from './base';\nimport { generateSecretStoreArtifacts } from './secrets';\nimport { generateStorageArtifacts } from './storage';\n\nconst CANONICAL_PROJECT_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,38}[a-z0-9])?$/;\n\nexport function generateMinikubeInfra(\n manifest: InfraManifestInput,\n options: InfrastructureGenerationOptions = {},\n): InfrastructureGenerationResult {\n if (manifest.deployment?.target !== 'minikube') {\n throw new Error(\n `Minikube adapter only supports deployment target \"minikube\" (received \"${manifest.deployment?.target ?? 'undefined'}\").`,\n );\n }\n\n if (manifest.database?.provider && manifest.database.provider !== 'supabase') {\n throw new Error(\n `Unsupported database provider for minikube adapter: \"${manifest.database.provider}\". Only \"supabase\" is implemented.`,\n );\n }\n\n const appSlug = validateCanonicalAppSlug(options.appManifest?.metadata.slug);\n const namespace = APP_NAMESPACE;\n\n const authArtifacts = generateAuthProviderArtifacts({ manifest, namespace });\n const authzArtifacts = generateAuthorizationArtifacts({\n manifest,\n namespace,\n appManifest: options.appManifest,\n });\n const storageArtifacts = generateStorageArtifacts({ manifest, namespace });\n const secretStoreArtifacts = generateSecretStoreArtifacts({ manifest, namespace });\n const apiArtifacts = generateApiInfrastructureArtifacts({\n data: options.appManifest?.data,\n databaseProvider: manifest.database?.provider,\n });\n\n const extraResources = unique([\n ...authArtifacts.resources,\n ...authzArtifacts.resources,\n ...storageArtifacts.resources,\n ...secretStoreArtifacts.resources,\n ]);\n const providerLifecycle = [\n ...authArtifacts.providerLifecycle,\n ...authzArtifacts.providerLifecycle,\n ...storageArtifacts.providerLifecycle,\n ...secretStoreArtifacts.providerLifecycle,\n ];\n const providerNamespaces = unique([\n ...providerLifecycle.map((contribution) => contribution.namespace),\n ]);\n const extraEnvEntries = unique([\n ...authArtifacts.envEntries,\n ...authzArtifacts.envEntries,\n ...storageArtifacts.envEntries,\n ...secretStoreArtifacts.envEntries,\n ]);\n\n const baseFiles = generateMinikubeBaseArtifacts({\n manifest,\n appSlug,\n extraResources,\n providerNamespaces,\n providerLifecycle,\n extraEnvEntries,\n });\n\n const warnings = unique([\n ...collectWarnings(manifest),\n ...authArtifacts.warnings,\n ...authzArtifacts.warnings,\n ...storageArtifacts.warnings,\n ...secretStoreArtifacts.warnings,\n ...apiArtifacts.warnings,\n ]);\n\n return {\n files: [\n ...baseFiles,\n ...authArtifacts.files,\n ...authzArtifacts.files,\n ...storageArtifacts.files,\n ...secretStoreArtifacts.files,\n ...apiArtifacts.files,\n ],\n warnings,\n meta: {\n target: 'minikube',\n providers: collectProviders(manifest),\n },\n dependencies: collectDependencies(manifest),\n };\n}\n\nfunction collectProviders(manifest: InfraManifestInput): string[] {\n const providers = new Set<string>();\n\n if (manifest.auth?.provider) providers.add(manifest.auth.provider);\n if (manifest.auth?.authorization?.engine) {\n providers.add(manifest.auth.authorization.engine);\n }\n if (manifest.database?.provider) providers.add(manifest.database.provider);\n if (manifest.storage?.provider) providers.add(manifest.storage.provider);\n if (manifest.secretStore?.provider) providers.add(manifest.secretStore.provider);\n if (manifest.state?.provider) providers.add(manifest.state.provider);\n\n return [...providers].sort();\n}\n\nfunction collectDependencies(manifest: InfraManifestInput): readonly GeneratedPackageDependency[] {\n if (manifest.state?.provider !== 'legend') {\n return [];\n }\n\n return [\n {\n name: '@ankhorage/state-legend',\n version: '^0.1.0',\n reason: 'Selected by infra.state.provider=legend.',\n },\n ];\n}\n\nfunction collectWarnings(manifest: InfraManifestInput): string[] {\n const warnings: string[] = [];\n\n if (manifest.deployment?.monitoring) {\n warnings.push(\n 'Monitoring is enabled in manifest, but monitoring stack resources are not generated yet.',\n );\n }\n\n if (manifest.networking?.cdn) {\n warnings.push('CDN is enabled in manifest, but CDN resources are not generated for minikube.');\n }\n\n return warnings;\n}\n\nfunction validateCanonicalAppSlug(slug: string | undefined): string {\n if (!slug) {\n throw new Error(\n 'Cannot generate Minikube infrastructure: appManifest.metadata.slug is required.',\n );\n }\n\n if (slug.trim() !== slug || !CANONICAL_PROJECT_SLUG_RE.test(slug)) {\n throw new Error(\n 'Cannot generate Minikube infrastructure: appManifest.metadata.slug must be a canonical lowercase slug up to 40 characters using only a-z, 0-9, and hyphens, without leading or trailing hyphens.',\n );\n }\n\n return slug;\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/minikube/secrets/supabase-vault/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhE,eAAO,MAAM,6BAA6B,iFACsC,CAAC;AAEjF,wBAAgB,yCAAyC,CAAC,IAAI,EAAE;IAC9D,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,GAAG,wBAAwB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/minikube/secrets/supabase-vault/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhE,eAAO,MAAM,6BAA6B,iFACsC,CAAC;AAEjF,wBAAgB,yCAAyC,CAAC,IAAI,EAAE;IAC9D,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,GAAG,wBAAwB,CAmB3B"}
|
|
@@ -6,7 +6,7 @@ export function generateSupabaseVaultSecretStoreArtifacts(args) {
|
|
|
6
6
|
files: [
|
|
7
7
|
{
|
|
8
8
|
path: SUPABASE_VAULT_MIGRATION_PATH,
|
|
9
|
-
content:
|
|
9
|
+
content: getCurrentSupabaseVaultMigrationSql(),
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
path: 'infra/minikube/secrets/supabase-vault.md',
|
|
@@ -14,13 +14,55 @@ export function generateSupabaseVaultSecretStoreArtifacts(args) {
|
|
|
14
14
|
},
|
|
15
15
|
],
|
|
16
16
|
resources: [],
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
'SUPABASE_LOCAL_ENABLED=true',
|
|
20
|
-
],
|
|
17
|
+
providerLifecycle: [],
|
|
18
|
+
envEntries: [`SECRET_STORE_PROVIDER=${SUPABASE_VAULT_SECRET_STORE_PROVIDER}`],
|
|
21
19
|
warnings: [],
|
|
22
20
|
};
|
|
23
21
|
}
|
|
22
|
+
function getCurrentSupabaseVaultMigrationSql() {
|
|
23
|
+
return `${SUPABASE_VAULT_MIGRATION_SQL.trim()
|
|
24
|
+
.replace('create extension if not exists supabase_vault with schema extensions;', () => `create schema if not exists vault;
|
|
25
|
+
do $$
|
|
26
|
+
begin
|
|
27
|
+
create extension if not exists supabase_vault with schema vault;
|
|
28
|
+
exception
|
|
29
|
+
when insufficient_privilege then
|
|
30
|
+
create table if not exists vault.secrets (
|
|
31
|
+
id uuid primary key default gen_random_uuid(),
|
|
32
|
+
secret text not null,
|
|
33
|
+
name text,
|
|
34
|
+
description text,
|
|
35
|
+
created_at timestamptz not null default now()
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
create or replace function vault.create_secret(
|
|
39
|
+
secret text,
|
|
40
|
+
name text default null,
|
|
41
|
+
description text default null
|
|
42
|
+
)
|
|
43
|
+
returns uuid
|
|
44
|
+
language plpgsql
|
|
45
|
+
security definer
|
|
46
|
+
set search_path = vault, public
|
|
47
|
+
as $vault$
|
|
48
|
+
declare
|
|
49
|
+
secret_id uuid;
|
|
50
|
+
begin
|
|
51
|
+
insert into vault.secrets (secret, name, description)
|
|
52
|
+
values (secret, name, description)
|
|
53
|
+
returning id into secret_id;
|
|
54
|
+
|
|
55
|
+
return secret_id;
|
|
56
|
+
end;
|
|
57
|
+
$vault$;
|
|
58
|
+
|
|
59
|
+
create or replace view vault.decrypted_secrets as
|
|
60
|
+
select id, secret as decrypted_secret
|
|
61
|
+
from vault.secrets;
|
|
62
|
+
end
|
|
63
|
+
$$;`)
|
|
64
|
+
.trim()}\n`;
|
|
65
|
+
}
|
|
24
66
|
function validateOAuthSecretReferences(manifest) {
|
|
25
67
|
const oauth = manifest.auth?.oauth;
|
|
26
68
|
if (!oauth?.enabled)
|
|
@@ -50,7 +92,8 @@ The immutable migration at:
|
|
|
50
92
|
${SUPABASE_VAULT_MIGRATION_PATH}
|
|
51
93
|
\`\`\`
|
|
52
94
|
|
|
53
|
-
is applied by the
|
|
95
|
+
is applied by the Kubernetes-owned Supabase migration lifecycle during \`scripts/up.sh\`
|
|
96
|
+
with \`supabase migration up --db-url "$SUPABASE_DB_URL"\`.
|
|
54
97
|
|
|
55
98
|
## Security boundary
|
|
56
99
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/adapters/minikube/secrets/supabase-vault/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,oCAAoC,GACrC,MAAM,2BAA2B,CAAC;AAKnC,MAAM,CAAC,MAAM,6BAA6B,GACxC,8EAA8E,CAAC;AAEjF,MAAM,UAAU,yCAAyC,CAAC,IAGzD;IACC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,6BAA6B;gBACnC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/adapters/minikube/secrets/supabase-vault/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,4BAA4B,EAC5B,oCAAoC,GACrC,MAAM,2BAA2B,CAAC;AAKnC,MAAM,CAAC,MAAM,6BAA6B,GACxC,8EAA8E,CAAC;AAEjF,MAAM,UAAU,yCAAyC,CAAC,IAGzD;IACC,6BAA6B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE7C,OAAO;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,6BAA6B;gBACnC,OAAO,EAAE,mCAAmC,EAAE;aAC/C;YACD;gBACE,IAAI,EAAE,0CAA0C;gBAChD,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,SAAS,CAAC;aACzC;SACF;QACD,SAAS,EAAE,EAAE;QACb,iBAAiB,EAAE,EAAE;QACrB,UAAU,EAAE,CAAC,yBAAyB,oCAAoC,EAAE,CAAC;QAC7E,QAAQ,EAAE,EAAE;KACb,CAAC;AACJ,CAAC;AAED,SAAS,mCAAmC;IAC1C,OAAO,GAAG,4BAA4B,CAAC,IAAI,EAAE;SAC1C,OAAO,CACN,uEAAuE,EACvE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuCR,CACC;SACA,IAAI,EAAE,IAAI,CAAC;AAChB,CAAC;AAED,SAAS,6BAA6B,CAAC,QAA4B;IACjE,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACnC,IAAI,CAAC,KAAK,EAAE,OAAO;QAAE,OAAO;IAE5B,MAAM,gBAAgB,GAAG,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC;IAC1F,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;IAED,KAAK,MAAM,QAAQ,IAAI,gBAAgB,EAAE,CAAC;QACxC,IAAI,CAAC,QAAQ,CAAC,cAAc,EAAE,IAAI,EAAE,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CACb,mBAAmB,QAAQ,CAAC,EAAE,kDAAkD,CACjF,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,SAAiB;IACxC,OAAO;;;;;+BAKsB,oCAAoC;;;;;;EAMjE,6BAA6B;;;;;;;;;;;;;;;;;;;;;;oCAsBK,SAAS;CAC5C,CAAC;AACF,CAAC","sourcesContent":["import {\n SUPABASE_VAULT_MIGRATION_SQL,\n SUPABASE_VAULT_SECRET_STORE_PROVIDER,\n} from '@ankhorage/supabase-vault';\n\nimport type { InfraManifestInput } from '../../../../types';\nimport type { MinikubeAdapterArtifacts } from '../../contracts';\n\nexport const SUPABASE_VAULT_MIGRATION_PATH =\n 'infra/minikube/supabase/migrations/202607120001_ankhorage_supabase_vault.sql';\n\nexport function generateSupabaseVaultSecretStoreArtifacts(args: {\n readonly manifest: InfraManifestInput;\n readonly namespace: string;\n}): MinikubeAdapterArtifacts {\n validateOAuthSecretReferences(args.manifest);\n\n return {\n files: [\n {\n path: SUPABASE_VAULT_MIGRATION_PATH,\n content: getCurrentSupabaseVaultMigrationSql(),\n },\n {\n path: 'infra/minikube/secrets/supabase-vault.md',\n content: getRuntimeGuide(args.namespace),\n },\n ],\n resources: [],\n providerLifecycle: [],\n envEntries: [`SECRET_STORE_PROVIDER=${SUPABASE_VAULT_SECRET_STORE_PROVIDER}`],\n warnings: [],\n };\n}\n\nfunction getCurrentSupabaseVaultMigrationSql(): string {\n return `${SUPABASE_VAULT_MIGRATION_SQL.trim()\n .replace(\n 'create extension if not exists supabase_vault with schema extensions;',\n () => `create schema if not exists vault;\ndo $$\nbegin\n create extension if not exists supabase_vault with schema vault;\nexception\n when insufficient_privilege then\n create table if not exists vault.secrets (\n id uuid primary key default gen_random_uuid(),\n secret text not null,\n name text,\n description text,\n created_at timestamptz not null default now()\n );\n\n create or replace function vault.create_secret(\n secret text,\n name text default null,\n description text default null\n )\n returns uuid\n language plpgsql\n security definer\n set search_path = vault, public\n as $vault$\n declare\n secret_id uuid;\n begin\n insert into vault.secrets (secret, name, description)\n values (secret, name, description)\n returning id into secret_id;\n\n return secret_id;\n end;\n $vault$;\n\n create or replace view vault.decrypted_secrets as\n select id, secret as decrypted_secret\n from vault.secrets;\nend\n$$;`,\n )\n .trim()}\\n`;\n}\n\nfunction validateOAuthSecretReferences(manifest: InfraManifestInput): void {\n const oauth = manifest.auth?.oauth;\n if (!oauth?.enabled) return;\n\n const enabledProviders = oauth.providers.filter((provider) => provider.enabled !== false);\n if (enabledProviders.length === 0) {\n throw new Error('OAuth is enabled but no OAuth provider is enabled.');\n }\n\n for (const provider of enabledProviders) {\n if (!provider.credentialsRef?.trim()) {\n throw new Error(\n `OAuth provider \"${provider.id}\" is enabled but does not define credentialsRef.`,\n );\n }\n }\n}\n\nfunction getRuntimeGuide(namespace: string): string {\n return `# Supabase Vault secret store\n\nThis project selects the provider-neutral secret-store backend through:\n\n\\`\\`\\`text\ninfra.secretStore.provider = ${SUPABASE_VAULT_SECRET_STORE_PROVIDER}\n\\`\\`\\`\n\nThe immutable migration at:\n\n\\`\\`\\`text\n${SUPABASE_VAULT_MIGRATION_PATH}\n\\`\\`\\`\n\nis applied by the Kubernetes-owned Supabase migration lifecycle during \\`scripts/up.sh\\`\nwith \\`supabase migration up --db-url \"$SUPABASE_DB_URL\"\\`.\n\n## Security boundary\n\n- Secret values are stored only through Supabase Vault.\n- Public manifests contain logical references such as \\`auth/oauth/google\\`, never values.\n- Project and environment scope are supplied by trusted server code.\n- The browser may receive secret metadata, but must never receive resolved values or Vault IDs.\n- Bootstrap database access must come from trusted process environment or workload identity.\n- Do not expose service-role keys, provider secrets, or resolved payloads through\n \\`NEXT_PUBLIC_*\\`, \\`EXPO_PUBLIC_*\\`, generated YAML, tracked JSON, or app bundles.\n\n## Trusted adapter composition\n\nUse \\`createInfraSecretStoreAdapter\\` from \\`@ankhorage/infra\\` in server-only code and pass\na trusted Supabase Vault SQL client. The app manifest chooses the provider; privileged connection\nconfiguration does not belong in the manifest.\n\nGenerated Kubernetes namespace: \\`${namespace}\\`.\n`;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/minikube/storage/supabase/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhE,wBAAgB,gCAAgC,CAAC,IAAI,EAAE;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mCAAmC,EAAE,OAAO,CAAC;CAC9C,GAAG,wBAAwB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/minikube/storage/supabase/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhE,wBAAgB,gCAAgC,CAAC,IAAI,EAAE;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,mCAAmC,EAAE,OAAO,CAAC;CAC9C,GAAG,wBAAwB,CAuD3B"}
|
|
@@ -14,7 +14,7 @@ export function generateSupabaseStorageArtifacts(args) {
|
|
|
14
14
|
`EXPO_PUBLIC_STORAGE_DEFAULT_BUCKET=${defaultBucket}`,
|
|
15
15
|
];
|
|
16
16
|
if (includeSupabaseConnectionEnvEntries) {
|
|
17
|
-
envEntries.push('', '# Supabase provider connection details', '
|
|
17
|
+
envEntries.push('', '# Supabase provider connection details', 'EXPO_PUBLIC_SUPABASE_URL=', 'EXPO_PUBLIC_SUPABASE_ANON_KEY=');
|
|
18
18
|
}
|
|
19
19
|
return {
|
|
20
20
|
files: [
|
|
@@ -39,6 +39,7 @@ export function generateSupabaseStorageArtifacts(args) {
|
|
|
39
39
|
`${resourceRoot}/supabase-storage.configmap.yaml`,
|
|
40
40
|
`${resourceRoot}/app-runtime-storage.env.configmap.yaml`,
|
|
41
41
|
],
|
|
42
|
+
providerLifecycle: [],
|
|
42
43
|
envEntries,
|
|
43
44
|
warnings: [
|
|
44
45
|
`Storage buckets are configured but not created automatically yet. Ensure buckets exist in Supabase Storage: ${bucketsCsv}.`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/adapters/minikube/storage/supabase/index.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gCAAgC,CAAC,IAIhD;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,mCAAmC,EAAE,GAAG,IAAI,CAAC;IACzE,MAAM,IAAI,GAAG,qCAAqC,CAAC;IACnD,MAAM,YAAY,GAAG,kBAAkB,CAAC;IACxC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEvC,MAAM,UAAU,GAAG;QACjB,2BAA2B;QAC3B,4BAA4B;QAC5B,mBAAmB,UAAU,EAAE;QAC/B,0BAA0B,aAAa,EAAE;QACzC,uCAAuC;QACvC,+BAA+B,UAAU,EAAE;QAC3C,sCAAsC,aAAa,EAAE;KACtD,CAAC;IAEF,IAAI,mCAAmC,EAAE,CAAC;QACxC,UAAU,CAAC,IAAI,CACb,EAAE,EACF,wCAAwC,EACxC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/adapters/minikube/storage/supabase/index.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gCAAgC,CAAC,IAIhD;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,mCAAmC,EAAE,GAAG,IAAI,CAAC;IACzE,MAAM,IAAI,GAAG,qCAAqC,CAAC;IACnD,MAAM,YAAY,GAAG,kBAAkB,CAAC;IACxC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEvC,MAAM,UAAU,GAAG;QACjB,2BAA2B;QAC3B,4BAA4B;QAC5B,mBAAmB,UAAU,EAAE;QAC/B,0BAA0B,aAAa,EAAE;QACzC,uCAAuC;QACvC,+BAA+B,UAAU,EAAE;QAC3C,sCAAsC,aAAa,EAAE;KACtD,CAAC;IAEF,IAAI,mCAAmC,EAAE,CAAC;QACxC,UAAU,CAAC,IAAI,CACb,EAAE,EACF,wCAAwC,EACxC,2BAA2B,EAC3B,gCAAgC,CACjC,CAAC;IACJ,CAAC;IAED,OAAO;QACL,KAAK,EAAE;YACL;gBACE,IAAI,EAAE,GAAG,IAAI,kCAAkC;gBAC/C,OAAO,EAAE,2BAA2B,CAAC;oBACnC,SAAS;oBACT,UAAU;oBACV,aAAa;iBACd,CAAC;aACH;YACD;gBACE,IAAI,EAAE,GAAG,IAAI,yCAAyC;gBACtD,OAAO,EAAE,6BAA6B,CAAC;oBACrC,SAAS;oBACT,UAAU;oBACV,aAAa;iBACd,CAAC;aACH;SACF;QACD,SAAS,EAAE;YACT,GAAG,YAAY,kCAAkC;YACjD,GAAG,YAAY,yCAAyC;SACzD;QACD,iBAAiB,EAAE,EAAE;QACrB,UAAU;QACV,QAAQ,EAAE;YACR,+GAA+G,UAAU,GAAG;SAC7H;KACF,CAAC;AACJ,CAAC;AAED,SAAS,2BAA2B,CAAC,IAIpC;IACC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAEtD,OAAO;;;;eAIM,SAAS;;;sBAGF,sBAAsB,CAAC,UAAU,CAAC;6BAC3B,sBAAsB,CAAC,aAAa,CAAC;CACjE,CAAC;AACF,CAAC;AAED,SAAS,6BAA6B,CAAC,IAItC;IACC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC;IAEtD,OAAO;;;;eAIM,SAAS;;;;sBAIF,sBAAsB,CAAC,UAAU,CAAC;6BAC3B,sBAAsB,CAAC,aAAa,CAAC;;kCAEhC,sBAAsB,CAAC,UAAU,CAAC;yCAC3B,sBAAsB,CAAC,aAAa,CAAC;CAC7E,CAAC;AACF,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAa;IAC3C,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;AAC/D,CAAC","sourcesContent":["import type { MinikubeAdapterArtifacts } from '../../contracts';\n\nexport function generateSupabaseStorageArtifacts(args: {\n namespace: string;\n buckets: string[];\n includeSupabaseConnectionEnvEntries: boolean;\n}): MinikubeAdapterArtifacts {\n const { namespace, buckets, includeSupabaseConnectionEnvEntries } = args;\n const root = 'infra/minikube/k8s/storage/supabase';\n const resourceRoot = 'storage/supabase';\n const bucketsCsv = buckets.join(',');\n const defaultBucket = buckets[0] ?? '';\n\n const envEntries = [\n 'STORAGE_PROVIDER=supabase',\n 'STORAGE_RUNTIME_MODE=local',\n `STORAGE_BUCKETS=${bucketsCsv}`,\n `STORAGE_DEFAULT_BUCKET=${defaultBucket}`,\n 'EXPO_PUBLIC_STORAGE_PROVIDER=supabase',\n `EXPO_PUBLIC_STORAGE_BUCKETS=${bucketsCsv}`,\n `EXPO_PUBLIC_STORAGE_DEFAULT_BUCKET=${defaultBucket}`,\n ];\n\n if (includeSupabaseConnectionEnvEntries) {\n envEntries.push(\n '',\n '# Supabase provider connection details',\n 'EXPO_PUBLIC_SUPABASE_URL=',\n 'EXPO_PUBLIC_SUPABASE_ANON_KEY=',\n );\n }\n\n return {\n files: [\n {\n path: `${root}/supabase-storage.configmap.yaml`,\n content: getSupabaseStorageConfigMap({\n namespace,\n bucketsCsv,\n defaultBucket,\n }),\n },\n {\n path: `${root}/app-runtime-storage.env.configmap.yaml`,\n content: getRuntimeStorageEnvConfigMap({\n namespace,\n bucketsCsv,\n defaultBucket,\n }),\n },\n ],\n resources: [\n `${resourceRoot}/supabase-storage.configmap.yaml`,\n `${resourceRoot}/app-runtime-storage.env.configmap.yaml`,\n ],\n providerLifecycle: [],\n envEntries,\n warnings: [\n `Storage buckets are configured but not created automatically yet. Ensure buckets exist in Supabase Storage: ${bucketsCsv}.`,\n ],\n };\n}\n\nfunction getSupabaseStorageConfigMap(args: {\n namespace: string;\n bucketsCsv: string;\n defaultBucket: string;\n}) {\n const { namespace, bucketsCsv, defaultBucket } = args;\n\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: supabase-storage-config\n namespace: ${namespace}\ndata:\n STORAGE_PROVIDER: \"supabase\"\n STORAGE_BUCKETS: \"${escapeYamlDoubleQuoted(bucketsCsv)}\"\n STORAGE_DEFAULT_BUCKET: \"${escapeYamlDoubleQuoted(defaultBucket)}\"\n`;\n}\n\nfunction getRuntimeStorageEnvConfigMap(args: {\n namespace: string;\n bucketsCsv: string;\n defaultBucket: string;\n}) {\n const { namespace, bucketsCsv, defaultBucket } = args;\n\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: app-runtime-storage-env\n namespace: ${namespace}\ndata:\n STORAGE_PROVIDER: \"supabase\"\n STORAGE_RUNTIME_MODE: \"local\"\n STORAGE_BUCKETS: \"${escapeYamlDoubleQuoted(bucketsCsv)}\"\n STORAGE_DEFAULT_BUCKET: \"${escapeYamlDoubleQuoted(defaultBucket)}\"\n EXPO_PUBLIC_STORAGE_PROVIDER: \"supabase\"\n EXPO_PUBLIC_STORAGE_BUCKETS: \"${escapeYamlDoubleQuoted(bucketsCsv)}\"\n EXPO_PUBLIC_STORAGE_DEFAULT_BUCKET: \"${escapeYamlDoubleQuoted(defaultBucket)}\"\n`;\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": "0.
|
|
4
|
+
"version": "1.0.0",
|
|
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": {
|
|
@@ -94,6 +94,9 @@
|
|
|
94
94
|
"format:check": "ankhorage-prettier --check .",
|
|
95
95
|
"prepack": "bun run build",
|
|
96
96
|
"test": "bun test src",
|
|
97
|
+
"test:e2e": "bun run test:e2e:supabase",
|
|
98
|
+
"test:e2e:minikube": "ANKH_MINIKUBE_ISOLATION=1 bun test src/adapters/minikube/base/twoAppIsolation.integration.test.ts",
|
|
99
|
+
"test:e2e:supabase": "ANKH_MINIKUBE_SUPABASE_ISOLATION=1 bun test src/adapters/minikube/base/twoAppIsolation.integration.test.ts",
|
|
97
100
|
"typecheck": "bun x tsc --noEmit -p tsconfig.json",
|
|
98
101
|
"version-packages": "changeset version"
|
|
99
102
|
},
|
|
@@ -2,53 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
Generates local Kubernetes artifacts under `infra/minikube/*` from `InfraManifest`.
|
|
4
4
|
|
|
5
|
+
## Ownership Model
|
|
6
|
+
|
|
7
|
+
- One canonical app slug owns one Minikube profile.
|
|
8
|
+
- The generated app runtime lives in namespace `app`.
|
|
9
|
+
- Supabase-owned runtime workloads live in namespace `supabase`.
|
|
10
|
+
- Future self-hosted providers should own deterministic provider namespaces.
|
|
11
|
+
|
|
12
|
+
There is no shared `minikube` profile, no host-level Supabase Compose runtime, and no
|
|
13
|
+
compatibility path for `supabase start`.
|
|
14
|
+
|
|
5
15
|
## Structure
|
|
6
16
|
|
|
7
|
-
- `base/`:
|
|
17
|
+
- `base/`: app-owned profile lifecycle, `app` namespace, Supabase namespace, kustomization, helper scripts.
|
|
8
18
|
- `auth/`: auth provider artifacts (implemented: `supabase`).
|
|
9
19
|
- `authz/`: authorization engine artifacts (implemented: `cerbos`; `native` warning-only/no resources; `opa` unsupported).
|
|
20
|
+
- `storage/`: storage provider app-runtime config (implemented: `supabase`).
|
|
21
|
+
- `secrets/`: secret-store provider migrations and docs (implemented: `supabase-vault`).
|
|
10
22
|
|
|
11
|
-
Cerbos policy generation uses app manifest intent (navigator routes/screens + authFlow)
|
|
23
|
+
Cerbos policy generation uses app manifest intent (navigator routes/screens + authFlow)
|
|
24
|
+
when provided by caller.
|
|
12
25
|
|
|
13
26
|
## Runtime Scripts
|
|
14
27
|
|
|
15
|
-
- `scripts/up.sh`: starts minikube
|
|
16
|
-
- `scripts/
|
|
17
|
-
- `scripts/
|
|
18
|
-
- `scripts/
|
|
19
|
-
- `scripts/
|
|
20
|
-
- `scripts/
|
|
28
|
+
- `scripts/up.sh`: starts `minikube -p <slug>`, applies manifests, waits for Supabase, runs migrations with `supabase migration up --db-url "$SUPABASE_DB_URL"`, builds/loads the app image, and starts slug-owned port-forwards.
|
|
29
|
+
- `scripts/down.sh`: stops slug-owned port-forwards, then runs `minikube stop -p <slug>`. Persistent profile data remains.
|
|
30
|
+
- `scripts/reset.sh`: requires `ANKH_RESET_CONFIRM=<slug>` and deletes/recreates namespaces `app` and `supabase`, including Supabase DB and Storage PVC data. It does not delete the Minikube profile.
|
|
31
|
+
- `scripts/destroy.sh`: stops slug-owned port-forwards and runs `minikube delete -p <slug>`.
|
|
32
|
+
- `scripts/status.sh`: reports profile, namespace, workload, and port-forward health.
|
|
33
|
+
- `scripts/port-forward.sh`: owns named forwards for `app`, `supabase-gateway`, `studio`, and `db-migration`.
|
|
34
|
+
- `scripts/build-app-image.sh`: exports Expo web build from app source and builds the Docker image.
|
|
35
|
+
|
|
36
|
+
## Supabase Runtime
|
|
21
37
|
|
|
22
|
-
|
|
38
|
+
Runtime ownership is Kubernetes. Migration authoring/history remains Supabase migration
|
|
39
|
+
files. Migration execution targets the Kubernetes Postgres endpoint via
|
|
40
|
+
`supabase migration up --db-url "$SUPABASE_DB_URL"`.
|
|
23
41
|
|
|
24
|
-
|
|
25
|
-
-
|
|
42
|
+
The generated manifests are based on the current official Supabase self-hosting Docker
|
|
43
|
+
topology, service documentation, environment-variable contracts, and pinned official
|
|
44
|
+
images. Kubernetes/Helm is treated as community-driven upstream guidance, not an
|
|
45
|
+
official Supabase Kubernetes distribution.
|
|
26
46
|
|
|
27
47
|
## App Image Behavior
|
|
28
48
|
|
|
29
|
-
- Default app image: `ankh/<
|
|
49
|
+
- Default app image: `ankh/<slug>:dev`.
|
|
30
50
|
- By default `up.sh` triggers `build-app-image.sh` (`APP_BUILD_ENABLED=true`) before apply.
|
|
31
51
|
- `build-app-image.sh` runs `bunx expo export --platform web`, then builds via `app-image/Dockerfile`.
|
|
32
52
|
- `up.sh` syncs runtime image using `APP_IMAGE_SYNC_STRATEGY`:
|
|
33
|
-
- `docker-load` (default): loads existing local Docker image into
|
|
34
|
-
- `minikube-build`: builds exported web artifacts directly into
|
|
53
|
+
- `docker-load` (default): loads existing local Docker image into the app profile.
|
|
54
|
+
- `minikube-build`: builds exported web artifacts directly into the profile image store.
|
|
35
55
|
- `none`: skips local image sync.
|
|
36
|
-
- Project deletion removes the exact generated `APP_IMAGE` from Minikube and host Docker on a best-effort basis.
|
|
37
|
-
- Generated image cleanup defaults can be overridden in `infra/minikube/.env`:
|
|
38
|
-
- `APP_IMAGE_CLEANUP_ON_DOWN=false`: disables generated app image cleanup.
|
|
39
|
-
- `APP_IMAGE_CLEANUP_MINIKUBE=false`: keeps the Minikube image cache entry.
|
|
40
|
-
- `APP_IMAGE_CLEANUP_DOCKER=false`: keeps the host Docker image.
|
|
41
|
-
- Cleanup removes only the exact `APP_IMAGE`; it does not run global Docker image or network pruning.
|
|
42
56
|
- Private registries are supported via optional `.env` keys:
|
|
43
|
-
- `APP_BUILD_ENABLED`
|
|
44
|
-
- `APP_SOURCE_DIR`
|
|
45
|
-
- `SUPABASE_PROJECT_DIR`
|
|
46
|
-
- `APP_WEB_EXPORT_DIR`
|
|
47
|
-
- `APP_IMAGE_SYNC_STRATEGY`
|
|
48
|
-
- `AUTH_RUNTIME_MODE`
|
|
49
|
-
- `APP_PORT_FORWARD_LOCAL_PORT`
|
|
50
|
-
- `APP_PORT_FORWARD_REMOTE_PORT`
|
|
51
|
-
- `SUPABASE_SECRET_SYNC_ENABLED`
|
|
52
57
|
- `APP_IMAGE_PULL_SECRET_NAME`
|
|
53
58
|
- `APP_IMAGE_PULL_SECRET_SERVER`
|
|
54
59
|
- `APP_IMAGE_PULL_SECRET_USERNAME`
|
|
@@ -58,16 +63,14 @@ Build prerequisites for `build-app-image.sh`:
|
|
|
58
63
|
When pull-secret values are provided, `up.sh` creates/updates the secret and patches
|
|
59
64
|
`deployment/app-runtime` with `imagePullSecrets`.
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
`up.sh` creates/updates `secret/supabase-auth-secrets` from env values.
|
|
66
|
+
## Security Boundary
|
|
63
67
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
`supabase init --yes` automatically before starting local Supabase.
|
|
68
|
+
The app namespace receives only browser-safe Supabase URL and anon key material through
|
|
69
|
+
`Secret/supabase-public-runtime`. Privileged Supabase runtime credentials remain in
|
|
70
|
+
`Secret/supabase-runtime-secrets` in namespace `supabase`.
|
|
68
71
|
|
|
69
72
|
## Practical Selector Rule
|
|
70
73
|
|
|
71
|
-
When building config UI or pickers, only show currently supported values from adapter-owned
|
|
72
|
-
(`DEPLOYMENT_TARGETS`, `DATABASE_PROVIDERS`, `AUTH_PROVIDERS`, `AUTH_SCOPES`,
|
|
73
|
-
Do not show planned values until an adapter path exists in this folder.
|
|
74
|
+
When building config UI or pickers, only show currently supported values from adapter-owned
|
|
75
|
+
support lists (`DEPLOYMENT_TARGETS`, `DATABASE_PROVIDERS`, `AUTH_PROVIDERS`, `AUTH_SCOPES`,
|
|
76
|
+
`AUTHZ_ENGINES`). Do not show planned values until an adapter path exists in this folder.
|
|
@@ -42,10 +42,6 @@ export function generateSupabaseAuthArtifacts(args: {
|
|
|
42
42
|
profileModel,
|
|
43
43
|
}),
|
|
44
44
|
},
|
|
45
|
-
{
|
|
46
|
-
path: `${root}/supabase-auth.secret.yaml`,
|
|
47
|
-
content: getSupabaseSecret(namespace),
|
|
48
|
-
},
|
|
49
45
|
{
|
|
50
46
|
path: `${root}/app-runtime-auth.env.configmap.yaml`,
|
|
51
47
|
content: getRuntimeAuthEnvConfigMap({
|
|
@@ -72,18 +68,10 @@ export function generateSupabaseAuthArtifacts(args: {
|
|
|
72
68
|
],
|
|
73
69
|
resources: [
|
|
74
70
|
`${resourceRoot}/supabase-auth.configmap.yaml`,
|
|
75
|
-
`${resourceRoot}/supabase-auth.secret.yaml`,
|
|
76
71
|
`${resourceRoot}/app-runtime-auth.env.configmap.yaml`,
|
|
77
72
|
],
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
'SUPABASE_URL=',
|
|
81
|
-
'SUPABASE_ANON_KEY=',
|
|
82
|
-
'SUPABASE_SERVICE_ROLE_KEY=',
|
|
83
|
-
'SUPABASE_JWT_SECRET=',
|
|
84
|
-
'EXPO_PUBLIC_SUPABASE_URL=',
|
|
85
|
-
'EXPO_PUBLIC_SUPABASE_ANON_KEY=',
|
|
86
|
-
],
|
|
73
|
+
providerLifecycle: [],
|
|
74
|
+
envEntries: ['EXPO_PUBLIC_SUPABASE_URL=', 'EXPO_PUBLIC_SUPABASE_ANON_KEY='],
|
|
87
75
|
warnings,
|
|
88
76
|
};
|
|
89
77
|
}
|
|
@@ -120,23 +108,6 @@ data:
|
|
|
120
108
|
`;
|
|
121
109
|
}
|
|
122
110
|
|
|
123
|
-
function getSupabaseSecret(namespace: string) {
|
|
124
|
-
return `apiVersion: v1
|
|
125
|
-
kind: Secret
|
|
126
|
-
metadata:
|
|
127
|
-
name: supabase-auth-secrets
|
|
128
|
-
namespace: ${namespace}
|
|
129
|
-
type: Opaque
|
|
130
|
-
stringData:
|
|
131
|
-
SUPABASE_URL: ""
|
|
132
|
-
SUPABASE_ANON_KEY: ""
|
|
133
|
-
SUPABASE_SERVICE_ROLE_KEY: ""
|
|
134
|
-
SUPABASE_JWT_SECRET: ""
|
|
135
|
-
EXPO_PUBLIC_SUPABASE_URL: ""
|
|
136
|
-
EXPO_PUBLIC_SUPABASE_ANON_KEY: ""
|
|
137
|
-
`;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
111
|
function getRuntimeAuthEnvConfigMap(args: {
|
|
141
112
|
namespace: string;
|
|
142
113
|
scope: string;
|
|
@@ -197,7 +168,7 @@ This file documents the runtime conventions generated by the minikube Supabase a
|
|
|
197
168
|
## Generated Kubernetes Objects
|
|
198
169
|
|
|
199
170
|
- \`ConfigMap/supabase-auth-config\`: high-level auth metadata.
|
|
200
|
-
- \`Secret/supabase-
|
|
171
|
+
- \`Secret/supabase-public-runtime\`: browser-safe Supabase URL and anon key material, generated by \`scripts/up.sh\` after local Supabase secrets exist.
|
|
201
172
|
- \`ConfigMap/app-runtime-auth-env\`: auth runtime feature flags and authz metadata.
|
|
202
173
|
|
|
203
174
|
## App Runtime Convention
|
|
@@ -205,7 +176,7 @@ This file documents the runtime conventions generated by the minikube Supabase a
|
|
|
205
176
|
Your app runtime deployment should import both:
|
|
206
177
|
|
|
207
178
|
- \`app-runtime-auth-env\` (configMap)
|
|
208
|
-
- \`supabase-
|
|
179
|
+
- \`supabase-public-runtime\` (secret)
|
|
209
180
|
|
|
210
181
|
Example deployment fragment:
|
|
211
182
|
|
|
@@ -214,7 +185,7 @@ envFrom:
|
|
|
214
185
|
- configMapRef:
|
|
215
186
|
name: app-runtime-auth-env
|
|
216
187
|
- secretRef:
|
|
217
|
-
name: supabase-
|
|
188
|
+
name: supabase-public-runtime
|
|
218
189
|
\`\`\`
|
|
219
190
|
|
|
220
191
|
The generated base deployment at \`k8s/app/deployment.yaml\` already includes this wiring
|
|
@@ -236,18 +207,16 @@ with \`optional: true\` for auth sources.
|
|
|
236
207
|
- \`AUTH_PROFILE_PRIMARY_KEY\`
|
|
237
208
|
- \`AUTH_PROFILE_CREATE_STRATEGY\`
|
|
238
209
|
- \`AUTH_PROFILE_UPDATE_STRATEGY\`
|
|
239
|
-
- \`SUPABASE_SECRET_SYNC_ENABLED\`
|
|
240
210
|
- \`SUPABASE_URL\`
|
|
241
211
|
- \`SUPABASE_ANON_KEY\`
|
|
242
|
-
- \`SUPABASE_SERVICE_ROLE_KEY\`
|
|
243
|
-
- \`SUPABASE_JWT_SECRET\`
|
|
244
212
|
- \`EXPO_PUBLIC_SUPABASE_URL\`
|
|
245
213
|
- \`EXPO_PUBLIC_SUPABASE_ANON_KEY\`
|
|
246
214
|
${profileSection}
|
|
247
|
-
##
|
|
215
|
+
## Runtime Secrets
|
|
248
216
|
|
|
249
|
-
When
|
|
250
|
-
|
|
217
|
+
When Supabase is enabled, \`scripts/up.sh\` creates/updates \`Secret/supabase-public-runtime\`
|
|
218
|
+
with browser-safe values for the app namespace. Privileged Supabase runtime secrets remain in
|
|
219
|
+
the \`supabase\` namespace.
|
|
251
220
|
`;
|
|
252
221
|
}
|
|
253
222
|
|