@ankhorage/infra 0.3.4 → 0.3.6
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 +12 -0
- package/dist/adapters/minikube/authz/cerbos/index.d.ts +5 -1
- package/dist/adapters/minikube/authz/cerbos/index.d.ts.map +1 -1
- package/dist/adapters/minikube/authz/cerbos/index.js +1 -1
- package/dist/adapters/minikube/authz/cerbos/index.js.map +1 -1
- package/dist/adapters/minikube/index.js +1 -1
- package/dist/adapters/minikube/index.js.map +1 -1
- package/dist/apiArtifacts.d.ts +8 -0
- package/dist/apiArtifacts.d.ts.map +1 -0
- package/dist/apiArtifacts.js +35 -0
- package/dist/apiArtifacts.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/minikube/authz/cerbos/index.ts +7 -3
- package/src/adapters/minikube/index.ts +1 -1
- package/src/apiArtifacts.test.ts +56 -0
- package/src/apiArtifacts.ts +107 -0
- package/src/index.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @ankhorage/infra
|
|
2
2
|
|
|
3
|
+
## 0.3.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 89eb7cf: Generate in-memory API store methods as explicit promises without unnecessary `async`, so generated apps pass `@typescript-eslint/require-await`.
|
|
8
|
+
|
|
9
|
+
## 0.3.5
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- ad6fd70: Support authentication manifests without authorization, resolve auth routes from the canonical `infra.auth.flow`, and keep Cerbos generation compatible with manifests that omit infra context.
|
|
14
|
+
|
|
3
15
|
## 0.3.4
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -4,6 +4,10 @@ import type { MinikubeAdapterArtifacts } from '../../contracts';
|
|
|
4
4
|
export declare function generateCerbosAuthzArtifacts(args: {
|
|
5
5
|
manifest: InfraManifestInput;
|
|
6
6
|
namespace: string;
|
|
7
|
-
appManifest?:
|
|
7
|
+
appManifest?: CerbosAppManifest;
|
|
8
8
|
}): MinikubeAdapterArtifacts;
|
|
9
|
+
type CerbosAppManifest = Pick<AppManifest, 'metadata' | 'navigator' | 'screens'> & {
|
|
10
|
+
infra?: AppManifest['infra'];
|
|
11
|
+
};
|
|
12
|
+
export {};
|
|
9
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/minikube/authz/cerbos/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAkC,MAAM,sBAAsB,CAAC;AAGxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhE,wBAAgB,4BAA4B,CAAC,IAAI,EAAE;IACjD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/minikube/authz/cerbos/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAkC,MAAM,sBAAsB,CAAC;AAGxF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAEhE,wBAAgB,4BAA4B,CAAC,IAAI,EAAE;IACjD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,iBAAiB,CAAC;CACjC,GAAG,wBAAwB,CAmC3B;AA2GD,KAAK,iBAAiB,GAAG,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC,GAAG;IACjF,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;CAC9B,CAAC"}
|
|
@@ -240,7 +240,7 @@ function buildCerbosPolicyIntent(args) {
|
|
|
240
240
|
const { manifest, appManifest } = args;
|
|
241
241
|
const authScope = manifest.auth?.scope ?? 'none';
|
|
242
242
|
const routes = appManifest?.navigator ? flattenNavigatorRoutes(appManifest.navigator) : [];
|
|
243
|
-
const flow = resolveAuthFlow(appManifest?.infra
|
|
243
|
+
const flow = resolveAuthFlow(appManifest?.infra?.auth?.flow);
|
|
244
244
|
const { signInRoute } = flow;
|
|
245
245
|
const { signUpRoute } = flow;
|
|
246
246
|
const { unauthorizedRoute } = flow;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/adapters/minikube/authz/cerbos/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AppManifest, NavigatorSpec, RouteDefinition } from '@ankhorage/contracts';\nimport { resolveAuthFlow } from '@ankhorage/contracts/auth';\n\nimport type { InfraManifestInput } from '../../../../types';\nimport type { MinikubeAdapterArtifacts } from '../../contracts';\n\nexport function generateCerbosAuthzArtifacts(args: {\n manifest: InfraManifestInput;\n namespace: string;\n appManifest?: Pick<AppManifest, 'infra' | 'metadata' | 'navigator' | 'screens'>;\n}): MinikubeAdapterArtifacts {\n const { manifest, namespace, appManifest } = args;\n\n const root = 'infra/minikube/k8s/authz/cerbos';\n const resourceRoot = 'authz/cerbos';\n const intent = buildCerbosPolicyIntent({ manifest, appManifest });\n\n return {\n files: [\n {\n path: `${root}/cerbos.configmap.yaml`,\n content: getCerbosConfigMap(namespace),\n },\n {\n path: `${root}/cerbos.policy.configmap.yaml`,\n content: getCerbosPolicyConfigMap({ namespace, intent }),\n },\n {\n path: `${root}/cerbos.deployment.yaml`,\n content: getCerbosDeployment(namespace),\n },\n {\n path: `${root}/cerbos.service.yaml`,\n content: getCerbosService(namespace),\n },\n ],\n resources: [\n `${resourceRoot}/cerbos.configmap.yaml`,\n `${resourceRoot}/cerbos.policy.configmap.yaml`,\n `${resourceRoot}/cerbos.deployment.yaml`,\n `${resourceRoot}/cerbos.service.yaml`,\n ],\n envEntries: ['CERBOS_URL=http://cerbos:3592'],\n warnings: [],\n };\n}\n\nfunction getCerbosConfigMap(namespace: string) {\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cerbos-config\n namespace: ${namespace}\ndata:\n config.yaml: |\n server:\n httpListenAddr: \":3592\"\n storage:\n driver: \"disk\"\n disk:\n directory: /policies\n`;\n}\n\nfunction getCerbosPolicyConfigMap(args: { namespace: string; intent: CerbosPolicyIntent }) {\n const { namespace, intent } = args;\n const entries = getCerbosPolicyEntries(intent);\n const renderedEntries = entries\n .map((entry) => {\n const indented = indentLines(entry.content, 4);\n return ` ${entry.key}: |\n${indented}`;\n })\n .join('\\n');\n\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cerbos-policy\n namespace: ${namespace}\ndata:\n${renderedEntries}\n`;\n}\n\nfunction getCerbosDeployment(namespace: string) {\n return `apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: cerbos\n namespace: ${namespace}\n labels:\n app.kubernetes.io/name: cerbos\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: cerbos\n template:\n metadata:\n labels:\n app.kubernetes.io/name: cerbos\n spec:\n containers:\n - name: cerbos\n image: ghcr.io/cerbos/cerbos:0.40.0\n args:\n - server\n - --config=/config/config.yaml\n ports:\n - containerPort: 3592\n volumeMounts:\n - name: cerbos-config\n mountPath: /config\n - name: cerbos-policy\n mountPath: /policies\n volumes:\n - name: cerbos-config\n configMap:\n name: cerbos-config\n - name: cerbos-policy\n configMap:\n name: cerbos-policy\n`;\n}\n\nfunction getCerbosService(namespace: string) {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: cerbos\n namespace: ${namespace}\nspec:\n selector:\n app.kubernetes.io/name: cerbos\n ports:\n - name: http\n port: 3592\n targetPort: 3592\n`;\n}\n\nconst PUBLIC_GUARD_HINTS = new Set(['public', 'guest', 'anonymous', 'unauthenticated']);\nconst AUTH_GUARD_HINTS = new Set([\n 'auth',\n 'authenticated',\n 'private',\n 'protected',\n 'requiresauth',\n 'requires-auth',\n]);\n\ntype AuthScope = NonNullable<InfraManifestInput['auth']>['scope'] | 'none';\n\ninterface CerbosRouteIntent {\n name: string;\n guards: string[];\n screenId?: string;\n}\n\ninterface CerbosPolicyIntent {\n authScope: AuthScope;\n publicRoutes: string[];\n protectedRoutes: string[];\n publicScreens: string[];\n protectedScreens: string[];\n}\n\ninterface CerbosPolicyEntry {\n key: string;\n content: string;\n}\n\nfunction getCerbosPolicyEntries(intent: CerbosPolicyIntent): CerbosPolicyEntry[] {\n const entries: CerbosPolicyEntry[] = [\n {\n key: 'app.resource_policy.yaml',\n content: getAppPolicy(intent),\n },\n ];\n\n if (intent.publicRoutes.length > 0 || intent.protectedRoutes.length > 0) {\n entries.push({\n key: 'route.resource_policy.yaml',\n content: getRoutePolicy(intent),\n });\n }\n\n if (intent.publicScreens.length > 0 || intent.protectedScreens.length > 0) {\n entries.push({\n key: 'screen.resource_policy.yaml',\n content: getScreenPolicy(intent),\n });\n }\n\n return entries;\n}\n\nfunction getAppPolicy(intent: CerbosPolicyIntent): string {\n const roles = intent.authScope === 'global' ? ['authenticated'] : ['anonymous', 'authenticated'];\n\n return `apiVersion: api.cerbos.dev/v1\nresourcePolicy:\n version: \"default\"\n resource: \"app\"\n rules:\n${indentLines(renderRule({ actions: ['*'], roles }), 4)}\n`;\n}\n\nfunction getRoutePolicy(intent: CerbosPolicyIntent): string {\n const rules: string[] = [];\n\n if (intent.publicRoutes.length > 0) {\n rules.push(\n renderRule({\n actions: ['view', 'navigate'],\n roles: ['anonymous', 'authenticated'],\n conditionExpr: getInConditionExpr('route', intent.publicRoutes),\n }),\n );\n }\n\n if (intent.protectedRoutes.length > 0) {\n rules.push(\n renderRule({\n actions: ['view', 'navigate'],\n roles: ['authenticated'],\n conditionExpr: getInConditionExpr('route', intent.protectedRoutes),\n }),\n );\n }\n\n return `apiVersion: api.cerbos.dev/v1\nresourcePolicy:\n version: \"default\"\n resource: \"route\"\n rules:\n${indentLines(rules.join('\\n'), 4)}\n`;\n}\n\nfunction getScreenPolicy(intent: CerbosPolicyIntent): string {\n const rules: string[] = [];\n\n if (intent.publicScreens.length > 0) {\n rules.push(\n renderRule({\n actions: ['view', 'render'],\n roles: ['anonymous', 'authenticated'],\n conditionExpr: getInConditionExpr('screen_id', intent.publicScreens),\n }),\n );\n }\n\n if (intent.protectedScreens.length > 0) {\n rules.push(\n renderRule({\n actions: ['view', 'render'],\n roles: ['authenticated'],\n conditionExpr: getInConditionExpr('screen_id', intent.protectedScreens),\n }),\n );\n }\n\n return `apiVersion: api.cerbos.dev/v1\nresourcePolicy:\n version: \"default\"\n resource: \"screen\"\n rules:\n${indentLines(rules.join('\\n'), 4)}\n`;\n}\n\nfunction renderRule(args: { actions: string[]; roles: string[]; conditionExpr?: string }): string {\n const { actions, roles, conditionExpr } = args;\n\n const lines = [\n `- actions: ${JSON.stringify(actions)}`,\n ' effect: EFFECT_ALLOW',\n ` roles: ${JSON.stringify(roles)}`,\n ];\n\n if (conditionExpr) {\n lines.push(' condition:');\n lines.push(' match:');\n lines.push(` expr: ${JSON.stringify(conditionExpr)}`);\n }\n\n return lines.join('\\n');\n}\n\nfunction getInConditionExpr(attribute: string, values: string[]): string {\n return `request.resource.attr.${attribute} in ${JSON.stringify(values)}`;\n}\n\nfunction indentLines(content: string, spaces: number): string {\n const prefix = ' '.repeat(spaces);\n return content\n .trimEnd()\n .split('\\n')\n .map((line) => `${prefix}${line}`)\n .join('\\n');\n}\n\nfunction buildCerbosPolicyIntent(args: {\n manifest: InfraManifestInput;\n appManifest?: Pick<AppManifest, 'infra' | 'metadata' | 'navigator' | 'screens'>;\n}): CerbosPolicyIntent {\n const { manifest, appManifest } = args;\n const authScope = manifest.auth?.scope ?? 'none';\n\n const routes = appManifest?.navigator ? flattenNavigatorRoutes(appManifest.navigator) : [];\n const flow = resolveAuthFlow(appManifest?.infra.auth?.flow);\n const { signInRoute } = flow;\n const { signUpRoute } = flow;\n const { unauthorizedRoute } = flow;\n\n const publicRouteSet = new Set<string>();\n const protectedRouteSet = new Set<string>();\n\n for (const route of routes) {\n const isPublic = isPublicRoute({\n route,\n authScope,\n signInRoute,\n signUpRoute,\n unauthorizedRoute,\n });\n\n if (isPublic) {\n publicRouteSet.add(route.name);\n } else {\n protectedRouteSet.add(route.name);\n }\n }\n\n const screenVisibility = new Map<string, 'public' | 'protected'>();\n for (const route of routes) {\n if (!route.screenId) continue;\n const isPublic = publicRouteSet.has(route.name);\n\n const current = screenVisibility.get(route.screenId);\n if (current === 'protected') continue;\n screenVisibility.set(route.screenId, isPublic ? 'public' : 'protected');\n }\n\n if (appManifest?.screens) {\n const defaultVisibility: 'public' | 'protected' =\n authScope === 'global' ? 'protected' : 'public';\n\n for (const screenId of Object.keys(appManifest.screens)) {\n if (!screenVisibility.has(screenId)) {\n screenVisibility.set(screenId, defaultVisibility);\n }\n }\n }\n\n const publicScreens = [...screenVisibility.entries()]\n .filter(([, visibility]) => visibility === 'public')\n .map(([screenId]) => screenId)\n .sort();\n const protectedScreens = [...screenVisibility.entries()]\n .filter(([, visibility]) => visibility === 'protected')\n .map(([screenId]) => screenId)\n .sort();\n\n return {\n authScope,\n publicRoutes: [...publicRouteSet].sort(),\n protectedRoutes: [...protectedRouteSet].sort(),\n publicScreens,\n protectedScreens,\n };\n}\n\nfunction flattenNavigatorRoutes(navigator: NavigatorSpec): CerbosRouteIntent[] {\n const deduped = new Map<string, CerbosRouteIntent>();\n\n const walk = (current: NavigatorSpec) => {\n for (const route of current.routes) {\n const normalizedGuards = normalizeGuards(route.guards);\n const existing = deduped.get(route.name);\n deduped.set(route.name, {\n name: route.name,\n guards: unique([...(existing?.guards ?? []), ...normalizedGuards]),\n screenId: route.screenId ?? existing?.screenId,\n });\n\n if (route.navigator) {\n walk(route.navigator);\n }\n }\n };\n\n walk(navigator);\n return [...deduped.values()];\n}\n\nfunction normalizeGuards(guards?: RouteDefinition['guards']): string[] {\n return (guards ?? []).map((guard) => guard.trim().toLowerCase()).filter(Boolean);\n}\n\nfunction isPublicRoute(args: {\n route: CerbosRouteIntent;\n authScope: AuthScope;\n signInRoute?: string;\n signUpRoute?: string;\n unauthorizedRoute?: string;\n}): boolean {\n const { route, authScope, signInRoute, signUpRoute, unauthorizedRoute } = args;\n const guardSet = new Set(route.guards);\n const signInRouteName = authFlowPathToRouteName(signInRoute);\n const signUpRouteName = authFlowPathToRouteName(signUpRoute);\n const unauthorizedRouteName = authFlowPathToRouteName(unauthorizedRoute);\n\n if (\n route.name === signInRouteName ||\n route.name === signUpRouteName ||\n route.name === unauthorizedRouteName\n ) {\n return true;\n }\n\n if (hasAny(guardSet, PUBLIC_GUARD_HINTS)) {\n return true;\n }\n\n if (hasAny(guardSet, AUTH_GUARD_HINTS)) {\n return false;\n }\n\n switch (authScope) {\n case 'none':\n return true;\n case 'global':\n default:\n return false;\n }\n}\n\nfunction hasAny(values: Set<string>, candidates: Set<string>): boolean {\n for (const candidate of candidates) {\n if (values.has(candidate)) return true;\n }\n return false;\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n\nfunction authFlowPathToRouteName(routePath: string | undefined): string | undefined {\n if (!routePath) {\n return undefined;\n }\n\n const normalized = routePath.trim().replace(/^\\/+/, '').replace(/\\/+$/, '');\n return normalized === '' ? 'index' : normalized;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/adapters/minikube/authz/cerbos/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AppManifest, NavigatorSpec, RouteDefinition } from '@ankhorage/contracts';\nimport { resolveAuthFlow } from '@ankhorage/contracts/auth';\n\nimport type { InfraManifestInput } from '../../../../types';\nimport type { MinikubeAdapterArtifacts } from '../../contracts';\n\nexport function generateCerbosAuthzArtifacts(args: {\n manifest: InfraManifestInput;\n namespace: string;\n appManifest?: CerbosAppManifest;\n}): MinikubeAdapterArtifacts {\n const { manifest, namespace, appManifest } = args;\n\n const root = 'infra/minikube/k8s/authz/cerbos';\n const resourceRoot = 'authz/cerbos';\n const intent = buildCerbosPolicyIntent({ manifest, appManifest });\n\n return {\n files: [\n {\n path: `${root}/cerbos.configmap.yaml`,\n content: getCerbosConfigMap(namespace),\n },\n {\n path: `${root}/cerbos.policy.configmap.yaml`,\n content: getCerbosPolicyConfigMap({ namespace, intent }),\n },\n {\n path: `${root}/cerbos.deployment.yaml`,\n content: getCerbosDeployment(namespace),\n },\n {\n path: `${root}/cerbos.service.yaml`,\n content: getCerbosService(namespace),\n },\n ],\n resources: [\n `${resourceRoot}/cerbos.configmap.yaml`,\n `${resourceRoot}/cerbos.policy.configmap.yaml`,\n `${resourceRoot}/cerbos.deployment.yaml`,\n `${resourceRoot}/cerbos.service.yaml`,\n ],\n envEntries: ['CERBOS_URL=http://cerbos:3592'],\n warnings: [],\n };\n}\n\nfunction getCerbosConfigMap(namespace: string) {\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cerbos-config\n namespace: ${namespace}\ndata:\n config.yaml: |\n server:\n httpListenAddr: \":3592\"\n storage:\n driver: \"disk\"\n disk:\n directory: /policies\n`;\n}\n\nfunction getCerbosPolicyConfigMap(args: { namespace: string; intent: CerbosPolicyIntent }) {\n const { namespace, intent } = args;\n const entries = getCerbosPolicyEntries(intent);\n const renderedEntries = entries\n .map((entry) => {\n const indented = indentLines(entry.content, 4);\n return ` ${entry.key}: |\n${indented}`;\n })\n .join('\\n');\n\n return `apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: cerbos-policy\n namespace: ${namespace}\ndata:\n${renderedEntries}\n`;\n}\n\nfunction getCerbosDeployment(namespace: string) {\n return `apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name: cerbos\n namespace: ${namespace}\n labels:\n app.kubernetes.io/name: cerbos\nspec:\n replicas: 1\n selector:\n matchLabels:\n app.kubernetes.io/name: cerbos\n template:\n metadata:\n labels:\n app.kubernetes.io/name: cerbos\n spec:\n containers:\n - name: cerbos\n image: ghcr.io/cerbos/cerbos:0.40.0\n args:\n - server\n - --config=/config/config.yaml\n ports:\n - containerPort: 3592\n volumeMounts:\n - name: cerbos-config\n mountPath: /config\n - name: cerbos-policy\n mountPath: /policies\n volumes:\n - name: cerbos-config\n configMap:\n name: cerbos-config\n - name: cerbos-policy\n configMap:\n name: cerbos-policy\n`;\n}\n\nfunction getCerbosService(namespace: string) {\n return `apiVersion: v1\nkind: Service\nmetadata:\n name: cerbos\n namespace: ${namespace}\nspec:\n selector:\n app.kubernetes.io/name: cerbos\n ports:\n - name: http\n port: 3592\n targetPort: 3592\n`;\n}\n\nconst PUBLIC_GUARD_HINTS = new Set(['public', 'guest', 'anonymous', 'unauthenticated']);\nconst AUTH_GUARD_HINTS = new Set([\n 'auth',\n 'authenticated',\n 'private',\n 'protected',\n 'requiresauth',\n 'requires-auth',\n]);\n\ntype CerbosAppManifest = Pick<AppManifest, 'metadata' | 'navigator' | 'screens'> & {\n infra?: AppManifest['infra'];\n};\n\ntype AuthScope = NonNullable<InfraManifestInput['auth']>['scope'] | 'none';\n\ninterface CerbosRouteIntent {\n name: string;\n guards: string[];\n screenId?: string;\n}\n\ninterface CerbosPolicyIntent {\n authScope: AuthScope;\n publicRoutes: string[];\n protectedRoutes: string[];\n publicScreens: string[];\n protectedScreens: string[];\n}\n\ninterface CerbosPolicyEntry {\n key: string;\n content: string;\n}\n\nfunction getCerbosPolicyEntries(intent: CerbosPolicyIntent): CerbosPolicyEntry[] {\n const entries: CerbosPolicyEntry[] = [\n {\n key: 'app.resource_policy.yaml',\n content: getAppPolicy(intent),\n },\n ];\n\n if (intent.publicRoutes.length > 0 || intent.protectedRoutes.length > 0) {\n entries.push({\n key: 'route.resource_policy.yaml',\n content: getRoutePolicy(intent),\n });\n }\n\n if (intent.publicScreens.length > 0 || intent.protectedScreens.length > 0) {\n entries.push({\n key: 'screen.resource_policy.yaml',\n content: getScreenPolicy(intent),\n });\n }\n\n return entries;\n}\n\nfunction getAppPolicy(intent: CerbosPolicyIntent): string {\n const roles = intent.authScope === 'global' ? ['authenticated'] : ['anonymous', 'authenticated'];\n\n return `apiVersion: api.cerbos.dev/v1\nresourcePolicy:\n version: \"default\"\n resource: \"app\"\n rules:\n${indentLines(renderRule({ actions: ['*'], roles }), 4)}\n`;\n}\n\nfunction getRoutePolicy(intent: CerbosPolicyIntent): string {\n const rules: string[] = [];\n\n if (intent.publicRoutes.length > 0) {\n rules.push(\n renderRule({\n actions: ['view', 'navigate'],\n roles: ['anonymous', 'authenticated'],\n conditionExpr: getInConditionExpr('route', intent.publicRoutes),\n }),\n );\n }\n\n if (intent.protectedRoutes.length > 0) {\n rules.push(\n renderRule({\n actions: ['view', 'navigate'],\n roles: ['authenticated'],\n conditionExpr: getInConditionExpr('route', intent.protectedRoutes),\n }),\n );\n }\n\n return `apiVersion: api.cerbos.dev/v1\nresourcePolicy:\n version: \"default\"\n resource: \"route\"\n rules:\n${indentLines(rules.join('\\n'), 4)}\n`;\n}\n\nfunction getScreenPolicy(intent: CerbosPolicyIntent): string {\n const rules: string[] = [];\n\n if (intent.publicScreens.length > 0) {\n rules.push(\n renderRule({\n actions: ['view', 'render'],\n roles: ['anonymous', 'authenticated'],\n conditionExpr: getInConditionExpr('screen_id', intent.publicScreens),\n }),\n );\n }\n\n if (intent.protectedScreens.length > 0) {\n rules.push(\n renderRule({\n actions: ['view', 'render'],\n roles: ['authenticated'],\n conditionExpr: getInConditionExpr('screen_id', intent.protectedScreens),\n }),\n );\n }\n\n return `apiVersion: api.cerbos.dev/v1\nresourcePolicy:\n version: \"default\"\n resource: \"screen\"\n rules:\n${indentLines(rules.join('\\n'), 4)}\n`;\n}\n\nfunction renderRule(args: { actions: string[]; roles: string[]; conditionExpr?: string }): string {\n const { actions, roles, conditionExpr } = args;\n\n const lines = [\n `- actions: ${JSON.stringify(actions)}`,\n ' effect: EFFECT_ALLOW',\n ` roles: ${JSON.stringify(roles)}`,\n ];\n\n if (conditionExpr) {\n lines.push(' condition:');\n lines.push(' match:');\n lines.push(` expr: ${JSON.stringify(conditionExpr)}`);\n }\n\n return lines.join('\\n');\n}\n\nfunction getInConditionExpr(attribute: string, values: string[]): string {\n return `request.resource.attr.${attribute} in ${JSON.stringify(values)}`;\n}\n\nfunction indentLines(content: string, spaces: number): string {\n const prefix = ' '.repeat(spaces);\n return content\n .trimEnd()\n .split('\\n')\n .map((line) => `${prefix}${line}`)\n .join('\\n');\n}\n\nfunction buildCerbosPolicyIntent(args: {\n manifest: InfraManifestInput;\n appManifest?: CerbosAppManifest;\n}): CerbosPolicyIntent {\n const { manifest, appManifest } = args;\n const authScope = manifest.auth?.scope ?? 'none';\n\n const routes = appManifest?.navigator ? flattenNavigatorRoutes(appManifest.navigator) : [];\n const flow = resolveAuthFlow(appManifest?.infra?.auth?.flow);\n const { signInRoute } = flow;\n const { signUpRoute } = flow;\n const { unauthorizedRoute } = flow;\n\n const publicRouteSet = new Set<string>();\n const protectedRouteSet = new Set<string>();\n\n for (const route of routes) {\n const isPublic = isPublicRoute({\n route,\n authScope,\n signInRoute,\n signUpRoute,\n unauthorizedRoute,\n });\n\n if (isPublic) {\n publicRouteSet.add(route.name);\n } else {\n protectedRouteSet.add(route.name);\n }\n }\n\n const screenVisibility = new Map<string, 'public' | 'protected'>();\n for (const route of routes) {\n if (!route.screenId) continue;\n const isPublic = publicRouteSet.has(route.name);\n\n const current = screenVisibility.get(route.screenId);\n if (current === 'protected') continue;\n screenVisibility.set(route.screenId, isPublic ? 'public' : 'protected');\n }\n\n if (appManifest?.screens) {\n const defaultVisibility: 'public' | 'protected' =\n authScope === 'global' ? 'protected' : 'public';\n\n for (const screenId of Object.keys(appManifest.screens)) {\n if (!screenVisibility.has(screenId)) {\n screenVisibility.set(screenId, defaultVisibility);\n }\n }\n }\n\n const publicScreens = [...screenVisibility.entries()]\n .filter(([, visibility]) => visibility === 'public')\n .map(([screenId]) => screenId)\n .sort();\n const protectedScreens = [...screenVisibility.entries()]\n .filter(([, visibility]) => visibility === 'protected')\n .map(([screenId]) => screenId)\n .sort();\n\n return {\n authScope,\n publicRoutes: [...publicRouteSet].sort(),\n protectedRoutes: [...protectedRouteSet].sort(),\n publicScreens,\n protectedScreens,\n };\n}\n\nfunction flattenNavigatorRoutes(navigator: NavigatorSpec): CerbosRouteIntent[] {\n const deduped = new Map<string, CerbosRouteIntent>();\n\n const walk = (current: NavigatorSpec) => {\n for (const route of current.routes) {\n const normalizedGuards = normalizeGuards(route.guards);\n const existing = deduped.get(route.name);\n deduped.set(route.name, {\n name: route.name,\n guards: unique([...(existing?.guards ?? []), ...normalizedGuards]),\n screenId: route.screenId ?? existing?.screenId,\n });\n\n if (route.navigator) {\n walk(route.navigator);\n }\n }\n };\n\n walk(navigator);\n return [...deduped.values()];\n}\n\nfunction normalizeGuards(guards?: RouteDefinition['guards']): string[] {\n return (guards ?? []).map((guard) => guard.trim().toLowerCase()).filter(Boolean);\n}\n\nfunction isPublicRoute(args: {\n route: CerbosRouteIntent;\n authScope: AuthScope;\n signInRoute?: string;\n signUpRoute?: string;\n unauthorizedRoute?: string;\n}): boolean {\n const { route, authScope, signInRoute, signUpRoute, unauthorizedRoute } = args;\n const guardSet = new Set(route.guards);\n const signInRouteName = authFlowPathToRouteName(signInRoute);\n const signUpRouteName = authFlowPathToRouteName(signUpRoute);\n const unauthorizedRouteName = authFlowPathToRouteName(unauthorizedRoute);\n\n if (\n route.name === signInRouteName ||\n route.name === signUpRouteName ||\n route.name === unauthorizedRouteName\n ) {\n return true;\n }\n\n if (hasAny(guardSet, PUBLIC_GUARD_HINTS)) {\n return true;\n }\n\n if (hasAny(guardSet, AUTH_GUARD_HINTS)) {\n return false;\n }\n\n switch (authScope) {\n case 'none':\n return true;\n case 'global':\n default:\n return false;\n }\n}\n\nfunction hasAny(values: Set<string>, candidates: Set<string>): boolean {\n for (const candidate of candidates) {\n if (values.has(candidate)) return true;\n }\n return false;\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n\nfunction authFlowPathToRouteName(routePath: string | undefined): string | undefined {\n if (!routePath) {\n return undefined;\n }\n\n const normalized = routePath.trim().replace(/^\\/+/, '').replace(/\\/+$/, '');\n return normalized === '' ? 'index' : normalized;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { generateApiInfrastructureArtifacts } from '../../
|
|
1
|
+
import { generateApiInfrastructureArtifacts } from '../../apiArtifacts';
|
|
2
2
|
import { generateAuthProviderArtifacts } from './auth';
|
|
3
3
|
import { generateAuthorizationArtifacts } from './authz';
|
|
4
4
|
import { generateMinikubeBaseArtifacts } from './base';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/minikube/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kCAAkC,EAAE,MAAM,
|
|
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 { generateStorageArtifacts } from './storage';\n\nconst DEFAULT_NAMESPACE = 'ankh-app';\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\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 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 ]);\n const extraEnvEntries = unique([\n ...authArtifacts.envEntries,\n ...authzArtifacts.envEntries,\n ...storageArtifacts.envEntries,\n ]);\n\n const baseFiles = generateMinikubeBaseArtifacts({\n manifest,\n namespace,\n extraResources,\n extraEnvEntries,\n });\n\n const warnings = unique([\n ...collectWarnings(manifest),\n ...authArtifacts.warnings,\n ...authzArtifacts.warnings,\n ...storageArtifacts.warnings,\n ...apiArtifacts.warnings,\n ]);\n\n return {\n files: [\n ...baseFiles,\n ...authArtifacts.files,\n ...authzArtifacts.files,\n ...storageArtifacts.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.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 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"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AppDataManifest } from '@ankhorage/contracts';
|
|
2
|
+
import { type ApiInfrastructureArtifacts } from './apis';
|
|
3
|
+
export type { ApiInfrastructureArtifacts } from './apis';
|
|
4
|
+
export declare function generateApiInfrastructureArtifacts(args: {
|
|
5
|
+
readonly data: AppDataManifest | undefined;
|
|
6
|
+
readonly databaseProvider: string | undefined;
|
|
7
|
+
}): ApiInfrastructureArtifacts;
|
|
8
|
+
//# sourceMappingURL=apiArtifacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiArtifacts.d.ts","sourceRoot":"","sources":["../src/apiArtifacts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,OAAO,EAEL,KAAK,0BAA0B,EAChC,MAAM,QAAQ,CAAC;AAIhB,YAAY,EAAE,0BAA0B,EAAE,MAAM,QAAQ,CAAC;AAEzD,wBAAgB,kCAAkC,CAAC,IAAI,EAAE;IACvD,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/C,GAAG,0BAA0B,CAW7B"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { generateApiInfrastructureArtifacts as generateRawApiInfrastructureArtifacts, } from './apis';
|
|
2
|
+
const GENERATED_API_HANDLERS_PATH = 'src/generated/apis/apiHandlers.ts';
|
|
3
|
+
export function generateApiInfrastructureArtifacts(args) {
|
|
4
|
+
const artifacts = generateRawApiInfrastructureArtifacts(args);
|
|
5
|
+
return {
|
|
6
|
+
...artifacts,
|
|
7
|
+
files: artifacts.files.map((file) => file.path === GENERATED_API_HANDLERS_PATH
|
|
8
|
+
? { ...file, content: makeGeneratedApiHandlersLintSafe(file.content) }
|
|
9
|
+
: file),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function makeGeneratedApiHandlersLintSafe(source) {
|
|
13
|
+
let result = source;
|
|
14
|
+
result = replaceGeneratedSnippet(result, ' async list(apiId: string): Promise<readonly GeneratedApiRecord[]> {', ' list(apiId: string): Promise<readonly GeneratedApiRecord[]> {');
|
|
15
|
+
result = replaceGeneratedSnippet(result, ' return getRows(records, apiId).map(cloneRecord);', ' return Promise.resolve(getRows(records, apiId).map(cloneRecord));');
|
|
16
|
+
result = replaceGeneratedSnippet(result, ' async read(apiId: string, id: string): Promise<GeneratedApiRecord | null> {', ' read(apiId: string, id: string): Promise<GeneratedApiRecord | null> {');
|
|
17
|
+
result = replaceGeneratedSnippet(result, ' if (primaryKey === null) return null;', ' if (primaryKey === null) return Promise.resolve(null);', 3);
|
|
18
|
+
result = replaceGeneratedSnippet(result, ' return record === undefined ? null : cloneRecord(record);', ' return Promise.resolve(record === undefined ? null : cloneRecord(record));');
|
|
19
|
+
result = replaceGeneratedSnippet(result, ' async create(apiId: string, values: GeneratedApiRecord): Promise<GeneratedApiRecord> {', ' create(apiId: string, values: GeneratedApiRecord): Promise<GeneratedApiRecord> {');
|
|
20
|
+
result = replaceGeneratedSnippet(result, ' return cloneRecord(nextRecord);', ' return Promise.resolve(cloneRecord(nextRecord));', 2);
|
|
21
|
+
result = replaceGeneratedSnippet(result, ' async update(\n', ' update(\n');
|
|
22
|
+
result = replaceGeneratedSnippet(result, ' if (index < 0) return null;', ' if (index < 0) return Promise.resolve(null);');
|
|
23
|
+
result = replaceGeneratedSnippet(result, ' async delete(apiId: string, id: string): Promise<GeneratedApiRecord | null> {', ' delete(apiId: string, id: string): Promise<GeneratedApiRecord | null> {');
|
|
24
|
+
result = replaceGeneratedSnippet(result, ' if (deleted === undefined) return null;', ' if (deleted === undefined) return Promise.resolve(null);');
|
|
25
|
+
result = replaceGeneratedSnippet(result, ' return cloneRecord(deleted);', ' return Promise.resolve(cloneRecord(deleted));');
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
function replaceGeneratedSnippet(source, snippet, replacement, expectedCount = 1) {
|
|
29
|
+
const count = source.split(snippet).length - 1;
|
|
30
|
+
if (count !== expectedCount) {
|
|
31
|
+
throw new Error(`Expected generated API handler snippet ${JSON.stringify(snippet)} ${expectedCount} time(s), found ${count}.`);
|
|
32
|
+
}
|
|
33
|
+
return source.replaceAll(snippet, replacement);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=apiArtifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiArtifacts.js","sourceRoot":"","sources":["../src/apiArtifacts.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,kCAAkC,IAAI,qCAAqC,GAE5E,MAAM,QAAQ,CAAC;AAEhB,MAAM,2BAA2B,GAAG,mCAAmC,CAAC;AAIxE,MAAM,UAAU,kCAAkC,CAAC,IAGlD;IACC,MAAM,SAAS,GAAG,qCAAqC,CAAC,IAAI,CAAC,CAAC;IAE9D,OAAO;QACL,GAAG,SAAS;QACZ,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAClC,IAAI,CAAC,IAAI,KAAK,2BAA2B;YACvC,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,gCAAgC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE;YACtE,CAAC,CAAC,IAAI,CACT;KACF,CAAC;AACJ,CAAC;AAED,SAAS,gCAAgC,CAAC,MAAc;IACtD,IAAI,MAAM,GAAG,MAAM,CAAC;IAEpB,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,yEAAyE,EACzE,mEAAmE,CACpE,CAAC;IACF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,wDAAwD,EACxD,yEAAyE,CAC1E,CAAC;IACF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,iFAAiF,EACjF,2EAA2E,CAC5E,CAAC;IACF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,6CAA6C,EAC7C,8DAA8D,EAC9D,CAAC,CACF,CAAC;IACF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,iEAAiE,EACjE,kFAAkF,CACnF,CAAC;IACF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,4FAA4F,EAC5F,sFAAsF,CACvF,CAAC;IACF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,uCAAuC,EACvC,wDAAwD,EACxD,CAAC,CACF,CAAC;IACF,MAAM,GAAG,uBAAuB,CAAC,MAAM,EAAE,qBAAqB,EAAE,eAAe,CAAC,CAAC;IACjF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,mCAAmC,EACnC,oDAAoD,CACrD,CAAC;IACF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,mFAAmF,EACnF,6EAA6E,CAC9E,CAAC;IACF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,+CAA+C,EAC/C,gEAAgE,CACjE,CAAC;IACF,MAAM,GAAG,uBAAuB,CAC9B,MAAM,EACN,oCAAoC,EACpC,qDAAqD,CACtD,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,uBAAuB,CAC9B,MAAc,EACd,OAAe,EACf,WAAmB,EACnB,aAAa,GAAG,CAAC;IAEjB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;IAC/C,IAAI,KAAK,KAAK,aAAa,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,0CAA0C,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,aAAa,mBAAmB,KAAK,GAAG,CAC9G,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;AACjD,CAAC","sourcesContent":["import type { AppDataManifest } from '@ankhorage/contracts';\n\nimport {\n generateApiInfrastructureArtifacts as generateRawApiInfrastructureArtifacts,\n type ApiInfrastructureArtifacts,\n} from './apis';\n\nconst GENERATED_API_HANDLERS_PATH = 'src/generated/apis/apiHandlers.ts';\n\nexport type { ApiInfrastructureArtifacts } from './apis';\n\nexport function generateApiInfrastructureArtifacts(args: {\n readonly data: AppDataManifest | undefined;\n readonly databaseProvider: string | undefined;\n}): ApiInfrastructureArtifacts {\n const artifacts = generateRawApiInfrastructureArtifacts(args);\n\n return {\n ...artifacts,\n files: artifacts.files.map((file) =>\n file.path === GENERATED_API_HANDLERS_PATH\n ? { ...file, content: makeGeneratedApiHandlersLintSafe(file.content) }\n : file,\n ),\n };\n}\n\nfunction makeGeneratedApiHandlersLintSafe(source: string): string {\n let result = source;\n\n result = replaceGeneratedSnippet(\n result,\n ' async list(apiId: string): Promise<readonly GeneratedApiRecord[]> {',\n ' list(apiId: string): Promise<readonly GeneratedApiRecord[]> {',\n );\n result = replaceGeneratedSnippet(\n result,\n ' return getRows(records, apiId).map(cloneRecord);',\n ' return Promise.resolve(getRows(records, apiId).map(cloneRecord));',\n );\n result = replaceGeneratedSnippet(\n result,\n ' async read(apiId: string, id: string): Promise<GeneratedApiRecord | null> {',\n ' read(apiId: string, id: string): Promise<GeneratedApiRecord | null> {',\n );\n result = replaceGeneratedSnippet(\n result,\n ' if (primaryKey === null) return null;',\n ' if (primaryKey === null) return Promise.resolve(null);',\n 3,\n );\n result = replaceGeneratedSnippet(\n result,\n ' return record === undefined ? null : cloneRecord(record);',\n ' return Promise.resolve(record === undefined ? null : cloneRecord(record));',\n );\n result = replaceGeneratedSnippet(\n result,\n ' async create(apiId: string, values: GeneratedApiRecord): Promise<GeneratedApiRecord> {',\n ' create(apiId: string, values: GeneratedApiRecord): Promise<GeneratedApiRecord> {',\n );\n result = replaceGeneratedSnippet(\n result,\n ' return cloneRecord(nextRecord);',\n ' return Promise.resolve(cloneRecord(nextRecord));',\n 2,\n );\n result = replaceGeneratedSnippet(result, ' async update(\\n', ' update(\\n');\n result = replaceGeneratedSnippet(\n result,\n ' if (index < 0) return null;',\n ' if (index < 0) return Promise.resolve(null);',\n );\n result = replaceGeneratedSnippet(\n result,\n ' async delete(apiId: string, id: string): Promise<GeneratedApiRecord | null> {',\n ' delete(apiId: string, id: string): Promise<GeneratedApiRecord | null> {',\n );\n result = replaceGeneratedSnippet(\n result,\n ' if (deleted === undefined) return null;',\n ' if (deleted === undefined) return Promise.resolve(null);',\n );\n result = replaceGeneratedSnippet(\n result,\n ' return cloneRecord(deleted);',\n ' return Promise.resolve(cloneRecord(deleted));',\n );\n\n return result;\n}\n\nfunction replaceGeneratedSnippet(\n source: string,\n snippet: string,\n replacement: string,\n expectedCount = 1,\n): string {\n const count = source.split(snippet).length - 1;\n if (count !== expectedCount) {\n throw new Error(\n `Expected generated API handler snippet ${JSON.stringify(snippet)} ${expectedCount} time(s), found ${count}.`,\n );\n }\n\n return source.replaceAll(snippet, replacement);\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InfraGenerationInput, InfraManifestInput, InfrastructureGenerationOptions, InfrastructureGenerationResult } from './types';
|
|
2
|
-
export type { ApiInfrastructureArtifacts } from './
|
|
3
|
-
export { generateApiInfrastructureArtifacts } from './
|
|
2
|
+
export type { ApiInfrastructureArtifacts } from './apiArtifacts';
|
|
3
|
+
export { generateApiInfrastructureArtifacts } from './apiArtifacts';
|
|
4
4
|
export type { GeneratedFile, GeneratedInfrastructureFile, GeneratedPackageDependency, InfraDiagnostic, InfraGenerationInput, InfraGenerationOptions, InfraGenerationResult, InfraManifestInput, InfrastructureGenerationMeta, InfrastructureGenerationOptions, InfrastructureGenerationResult, PackageDependency, } from './types';
|
|
5
5
|
export declare function generateInfra(input: InfraGenerationInput): InfrastructureGenerationResult;
|
|
6
6
|
export declare function generateInfrastructure(manifest: InfraManifestInput, options?: InfrastructureGenerationOptions): InfrastructureGenerationResult;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,0BAA0B,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,EAC/B,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,kCAAkC,EAAE,MAAM,gBAAgB,CAAC;AACpE,YAAY,EACV,aAAa,EACb,2BAA2B,EAC3B,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACtB,qBAAqB,EACrB,kBAAkB,EAClB,4BAA4B,EAC5B,+BAA+B,EAC/B,8BAA8B,EAC9B,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,wBAAgB,aAAa,CAAC,KAAK,EAAE,oBAAoB,GAAG,8BAA8B,CAEzF;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,GAAE,+BAAoC,GAC5C,8BAA8B,CAUhC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { generateMinikubeInfra } from './adapters/minikube';
|
|
2
|
-
export { generateApiInfrastructureArtifacts } from './
|
|
2
|
+
export { generateApiInfrastructureArtifacts } from './apiArtifacts';
|
|
3
3
|
export function generateInfra(input) {
|
|
4
4
|
return generateInfrastructure(input.manifest, input.options ?? {});
|
|
5
5
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAS5D,OAAO,EAAE,kCAAkC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAS5D,OAAO,EAAE,kCAAkC,EAAE,MAAM,gBAAgB,CAAC;AAgBpE,MAAM,UAAU,aAAa,CAAC,KAA2B;IACvD,OAAO,sBAAsB,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,QAA4B,EAC5B,UAA2C,EAAE;IAE7C,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,kCAAkC,QAAQ,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;IAClF,CAAC;IAED,OAAO,qBAAqB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAClD,CAAC","sourcesContent":["import { generateMinikubeInfra } from './adapters/minikube';\nimport type {\n InfraGenerationInput,\n InfraManifestInput,\n InfrastructureGenerationOptions,\n InfrastructureGenerationResult,\n} from './types';\n\nexport type { ApiInfrastructureArtifacts } from './apiArtifacts';\nexport { generateApiInfrastructureArtifacts } from './apiArtifacts';\nexport type {\n GeneratedFile,\n GeneratedInfrastructureFile,\n GeneratedPackageDependency,\n InfraDiagnostic,\n InfraGenerationInput,\n InfraGenerationOptions,\n InfraGenerationResult,\n InfraManifestInput,\n InfrastructureGenerationMeta,\n InfrastructureGenerationOptions,\n InfrastructureGenerationResult,\n PackageDependency,\n} from './types';\n\nexport function generateInfra(input: InfraGenerationInput): InfrastructureGenerationResult {\n return generateInfrastructure(input.manifest, input.options ?? {});\n}\n\nexport function generateInfrastructure(\n manifest: InfraManifestInput,\n options: InfrastructureGenerationOptions = {},\n): InfrastructureGenerationResult {\n if (!manifest.deployment) {\n throw new Error('Deployment configuration is missing.');\n }\n\n if (manifest.deployment.target !== 'minikube') {\n throw new Error(`Unsupported deployment target: ${manifest.deployment.target}`);\n }\n\n return generateMinikubeInfra(manifest, options);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ankhorage/infra",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.6",
|
|
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": {
|
|
@@ -7,7 +7,7 @@ import type { MinikubeAdapterArtifacts } from '../../contracts';
|
|
|
7
7
|
export function generateCerbosAuthzArtifacts(args: {
|
|
8
8
|
manifest: InfraManifestInput;
|
|
9
9
|
namespace: string;
|
|
10
|
-
appManifest?:
|
|
10
|
+
appManifest?: CerbosAppManifest;
|
|
11
11
|
}): MinikubeAdapterArtifacts {
|
|
12
12
|
const { manifest, namespace, appManifest } = args;
|
|
13
13
|
|
|
@@ -150,6 +150,10 @@ const AUTH_GUARD_HINTS = new Set([
|
|
|
150
150
|
'requires-auth',
|
|
151
151
|
]);
|
|
152
152
|
|
|
153
|
+
type CerbosAppManifest = Pick<AppManifest, 'metadata' | 'navigator' | 'screens'> & {
|
|
154
|
+
infra?: AppManifest['infra'];
|
|
155
|
+
};
|
|
156
|
+
|
|
153
157
|
type AuthScope = NonNullable<InfraManifestInput['auth']>['scope'] | 'none';
|
|
154
158
|
|
|
155
159
|
interface CerbosRouteIntent {
|
|
@@ -305,13 +309,13 @@ function indentLines(content: string, spaces: number): string {
|
|
|
305
309
|
|
|
306
310
|
function buildCerbosPolicyIntent(args: {
|
|
307
311
|
manifest: InfraManifestInput;
|
|
308
|
-
appManifest?:
|
|
312
|
+
appManifest?: CerbosAppManifest;
|
|
309
313
|
}): CerbosPolicyIntent {
|
|
310
314
|
const { manifest, appManifest } = args;
|
|
311
315
|
const authScope = manifest.auth?.scope ?? 'none';
|
|
312
316
|
|
|
313
317
|
const routes = appManifest?.navigator ? flattenNavigatorRoutes(appManifest.navigator) : [];
|
|
314
|
-
const flow = resolveAuthFlow(appManifest?.infra
|
|
318
|
+
const flow = resolveAuthFlow(appManifest?.infra?.auth?.flow);
|
|
315
319
|
const { signInRoute } = flow;
|
|
316
320
|
const { signUpRoute } = flow;
|
|
317
321
|
const { unauthorizedRoute } = flow;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test';
|
|
2
|
+
|
|
3
|
+
import { generateApiInfrastructureArtifacts } from './apiArtifacts';
|
|
4
|
+
|
|
5
|
+
describe('generated API artifacts', () => {
|
|
6
|
+
test('emits lint-safe Promise-based memory-store methods', () => {
|
|
7
|
+
const result = generateApiInfrastructureArtifacts({
|
|
8
|
+
databaseProvider: 'supabase',
|
|
9
|
+
data: {
|
|
10
|
+
apis: {
|
|
11
|
+
items: {
|
|
12
|
+
id: 'items',
|
|
13
|
+
kind: 'generated',
|
|
14
|
+
label: 'Items',
|
|
15
|
+
description: 'Generated items API.',
|
|
16
|
+
basePath: '/api/items',
|
|
17
|
+
preset: 'crud',
|
|
18
|
+
resource: {
|
|
19
|
+
kind: 'collection',
|
|
20
|
+
collection: {
|
|
21
|
+
name: 'items',
|
|
22
|
+
primaryKey: 'id',
|
|
23
|
+
fields: [
|
|
24
|
+
{ name: 'id', type: 'uuid', required: true, unique: true },
|
|
25
|
+
{ name: 'name', type: 'text', required: true },
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
seed: [],
|
|
29
|
+
},
|
|
30
|
+
endpoints: [
|
|
31
|
+
{
|
|
32
|
+
id: 'items.list',
|
|
33
|
+
method: 'GET',
|
|
34
|
+
path: '/',
|
|
35
|
+
intent: 'list',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const handlers = result.files.find(
|
|
44
|
+
(file) => file.path === 'src/generated/apis/apiHandlers.ts',
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
expect(handlers).toBeDefined();
|
|
48
|
+
expect(handlers?.content).not.toMatch(/\basync (?:list|read|create|update|delete)\(/);
|
|
49
|
+
expect(handlers?.content).toContain(
|
|
50
|
+
'list(apiId: string): Promise<readonly GeneratedApiRecord[]>',
|
|
51
|
+
);
|
|
52
|
+
expect(handlers?.content).toContain(
|
|
53
|
+
'return Promise.resolve(getRows(records, apiId).map(cloneRecord));',
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { AppDataManifest } from '@ankhorage/contracts';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
generateApiInfrastructureArtifacts as generateRawApiInfrastructureArtifacts,
|
|
5
|
+
type ApiInfrastructureArtifacts,
|
|
6
|
+
} from './apis';
|
|
7
|
+
|
|
8
|
+
const GENERATED_API_HANDLERS_PATH = 'src/generated/apis/apiHandlers.ts';
|
|
9
|
+
|
|
10
|
+
export type { ApiInfrastructureArtifacts } from './apis';
|
|
11
|
+
|
|
12
|
+
export function generateApiInfrastructureArtifacts(args: {
|
|
13
|
+
readonly data: AppDataManifest | undefined;
|
|
14
|
+
readonly databaseProvider: string | undefined;
|
|
15
|
+
}): ApiInfrastructureArtifacts {
|
|
16
|
+
const artifacts = generateRawApiInfrastructureArtifacts(args);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
...artifacts,
|
|
20
|
+
files: artifacts.files.map((file) =>
|
|
21
|
+
file.path === GENERATED_API_HANDLERS_PATH
|
|
22
|
+
? { ...file, content: makeGeneratedApiHandlersLintSafe(file.content) }
|
|
23
|
+
: file,
|
|
24
|
+
),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function makeGeneratedApiHandlersLintSafe(source: string): string {
|
|
29
|
+
let result = source;
|
|
30
|
+
|
|
31
|
+
result = replaceGeneratedSnippet(
|
|
32
|
+
result,
|
|
33
|
+
' async list(apiId: string): Promise<readonly GeneratedApiRecord[]> {',
|
|
34
|
+
' list(apiId: string): Promise<readonly GeneratedApiRecord[]> {',
|
|
35
|
+
);
|
|
36
|
+
result = replaceGeneratedSnippet(
|
|
37
|
+
result,
|
|
38
|
+
' return getRows(records, apiId).map(cloneRecord);',
|
|
39
|
+
' return Promise.resolve(getRows(records, apiId).map(cloneRecord));',
|
|
40
|
+
);
|
|
41
|
+
result = replaceGeneratedSnippet(
|
|
42
|
+
result,
|
|
43
|
+
' async read(apiId: string, id: string): Promise<GeneratedApiRecord | null> {',
|
|
44
|
+
' read(apiId: string, id: string): Promise<GeneratedApiRecord | null> {',
|
|
45
|
+
);
|
|
46
|
+
result = replaceGeneratedSnippet(
|
|
47
|
+
result,
|
|
48
|
+
' if (primaryKey === null) return null;',
|
|
49
|
+
' if (primaryKey === null) return Promise.resolve(null);',
|
|
50
|
+
3,
|
|
51
|
+
);
|
|
52
|
+
result = replaceGeneratedSnippet(
|
|
53
|
+
result,
|
|
54
|
+
' return record === undefined ? null : cloneRecord(record);',
|
|
55
|
+
' return Promise.resolve(record === undefined ? null : cloneRecord(record));',
|
|
56
|
+
);
|
|
57
|
+
result = replaceGeneratedSnippet(
|
|
58
|
+
result,
|
|
59
|
+
' async create(apiId: string, values: GeneratedApiRecord): Promise<GeneratedApiRecord> {',
|
|
60
|
+
' create(apiId: string, values: GeneratedApiRecord): Promise<GeneratedApiRecord> {',
|
|
61
|
+
);
|
|
62
|
+
result = replaceGeneratedSnippet(
|
|
63
|
+
result,
|
|
64
|
+
' return cloneRecord(nextRecord);',
|
|
65
|
+
' return Promise.resolve(cloneRecord(nextRecord));',
|
|
66
|
+
2,
|
|
67
|
+
);
|
|
68
|
+
result = replaceGeneratedSnippet(result, ' async update(\n', ' update(\n');
|
|
69
|
+
result = replaceGeneratedSnippet(
|
|
70
|
+
result,
|
|
71
|
+
' if (index < 0) return null;',
|
|
72
|
+
' if (index < 0) return Promise.resolve(null);',
|
|
73
|
+
);
|
|
74
|
+
result = replaceGeneratedSnippet(
|
|
75
|
+
result,
|
|
76
|
+
' async delete(apiId: string, id: string): Promise<GeneratedApiRecord | null> {',
|
|
77
|
+
' delete(apiId: string, id: string): Promise<GeneratedApiRecord | null> {',
|
|
78
|
+
);
|
|
79
|
+
result = replaceGeneratedSnippet(
|
|
80
|
+
result,
|
|
81
|
+
' if (deleted === undefined) return null;',
|
|
82
|
+
' if (deleted === undefined) return Promise.resolve(null);',
|
|
83
|
+
);
|
|
84
|
+
result = replaceGeneratedSnippet(
|
|
85
|
+
result,
|
|
86
|
+
' return cloneRecord(deleted);',
|
|
87
|
+
' return Promise.resolve(cloneRecord(deleted));',
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function replaceGeneratedSnippet(
|
|
94
|
+
source: string,
|
|
95
|
+
snippet: string,
|
|
96
|
+
replacement: string,
|
|
97
|
+
expectedCount = 1,
|
|
98
|
+
): string {
|
|
99
|
+
const count = source.split(snippet).length - 1;
|
|
100
|
+
if (count !== expectedCount) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Expected generated API handler snippet ${JSON.stringify(snippet)} ${expectedCount} time(s), found ${count}.`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return source.replaceAll(snippet, replacement);
|
|
107
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -6,8 +6,8 @@ import type {
|
|
|
6
6
|
InfrastructureGenerationResult,
|
|
7
7
|
} from './types';
|
|
8
8
|
|
|
9
|
-
export type { ApiInfrastructureArtifacts } from './
|
|
10
|
-
export { generateApiInfrastructureArtifacts } from './
|
|
9
|
+
export type { ApiInfrastructureArtifacts } from './apiArtifacts';
|
|
10
|
+
export { generateApiInfrastructureArtifacts } from './apiArtifacts';
|
|
11
11
|
export type {
|
|
12
12
|
GeneratedFile,
|
|
13
13
|
GeneratedInfrastructureFile,
|