@ankhorage/infra 0.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/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/adapters/minikube/auth/index.d.ts +7 -0
- package/dist/adapters/minikube/auth/index.d.ts.map +1 -0
- package/dist/adapters/minikube/auth/index.js +14 -0
- package/dist/adapters/minikube/auth/index.js.map +1 -0
- package/dist/adapters/minikube/auth/supabase/index.d.ts +7 -0
- package/dist/adapters/minikube/auth/supabase/index.d.ts.map +1 -0
- package/dist/adapters/minikube/auth/supabase/index.js +213 -0
- package/dist/adapters/minikube/auth/supabase/index.js.map +1 -0
- package/dist/adapters/minikube/authz/cerbos/index.d.ts +9 -0
- package/dist/adapters/minikube/authz/cerbos/index.d.ts.map +1 -0
- package/dist/adapters/minikube/authz/cerbos/index.js +360 -0
- package/dist/adapters/minikube/authz/cerbos/index.js.map +1 -0
- package/dist/adapters/minikube/authz/index.d.ts +9 -0
- package/dist/adapters/minikube/authz/index.d.ts.map +1 -0
- package/dist/adapters/minikube/authz/index.js +23 -0
- package/dist/adapters/minikube/authz/index.js.map +1 -0
- package/dist/adapters/minikube/base/index.d.ts +9 -0
- package/dist/adapters/minikube/base/index.d.ts.map +1 -0
- package/dist/adapters/minikube/base/index.js +1371 -0
- package/dist/adapters/minikube/base/index.js.map +1 -0
- package/dist/adapters/minikube/contracts.d.ts +9 -0
- package/dist/adapters/minikube/contracts.d.ts.map +1 -0
- package/dist/adapters/minikube/contracts.js +9 -0
- package/dist/adapters/minikube/contracts.js.map +1 -0
- package/dist/adapters/minikube/index.d.ts +3 -0
- package/dist/adapters/minikube/index.d.ts.map +1 -0
- package/dist/adapters/minikube/index.js +114 -0
- package/dist/adapters/minikube/index.js.map +1 -0
- package/dist/adapters/minikube/storage/index.d.ts +7 -0
- package/dist/adapters/minikube/storage/index.d.ts.map +1 -0
- package/dist/adapters/minikube/storage/index.js +77 -0
- package/dist/adapters/minikube/storage/index.js.map +1 -0
- package/dist/adapters/minikube/storage/supabase/index.d.ts +7 -0
- package/dist/adapters/minikube/storage/supabase/index.d.ts.map +1 -0
- package/dist/adapters/minikube/storage/supabase/index.js +81 -0
- package/dist/adapters/minikube/storage/supabase/index.js.map +1 -0
- package/dist/datasets.d.ts +11 -0
- package/dist/datasets.d.ts.map +1 -0
- package/dist/datasets.js +397 -0
- package/dist/datasets.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +70 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +86 -0
- package/src/adapters/minikube/README.md +73 -0
- package/src/adapters/minikube/auth/index.ts +23 -0
- package/src/adapters/minikube/auth/supabase/index.ts +269 -0
- package/src/adapters/minikube/authz/cerbos/index.ts +458 -0
- package/src/adapters/minikube/authz/index.ts +32 -0
- package/src/adapters/minikube/base/index.test.ts +103 -0
- package/src/adapters/minikube/base/index.ts +1478 -0
- package/src/adapters/minikube/contracts.ts +17 -0
- package/src/adapters/minikube/index.ts +149 -0
- package/src/adapters/minikube/storage/index.ts +91 -0
- package/src/adapters/minikube/storage/supabase/index.ts +112 -0
- package/src/datasets.test.ts +178 -0
- package/src/datasets.ts +562 -0
- package/src/index.test.ts +679 -0
- package/src/index.ts +43 -0
- package/src/minikubeImageLifecycle.test.ts +34 -0
- package/src/types.ts +82 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
export function generateCerbosAuthzArtifacts(args) {
|
|
2
|
+
const { manifest, namespace, appManifest } = args;
|
|
3
|
+
const root = 'infra/minikube/k8s/authz/cerbos';
|
|
4
|
+
const resourceRoot = 'authz/cerbos';
|
|
5
|
+
const intent = buildCerbosPolicyIntent({ manifest, appManifest });
|
|
6
|
+
return {
|
|
7
|
+
files: [
|
|
8
|
+
{
|
|
9
|
+
path: `${root}/cerbos.configmap.yaml`,
|
|
10
|
+
content: getCerbosConfigMap(namespace),
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
path: `${root}/cerbos.policy.configmap.yaml`,
|
|
14
|
+
content: getCerbosPolicyConfigMap({ namespace, intent }),
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
path: `${root}/cerbos.deployment.yaml`,
|
|
18
|
+
content: getCerbosDeployment(namespace),
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
path: `${root}/cerbos.service.yaml`,
|
|
22
|
+
content: getCerbosService(namespace),
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
resources: [
|
|
26
|
+
`${resourceRoot}/cerbos.configmap.yaml`,
|
|
27
|
+
`${resourceRoot}/cerbos.policy.configmap.yaml`,
|
|
28
|
+
`${resourceRoot}/cerbos.deployment.yaml`,
|
|
29
|
+
`${resourceRoot}/cerbos.service.yaml`,
|
|
30
|
+
],
|
|
31
|
+
envEntries: ['CERBOS_URL=http://cerbos:3592'],
|
|
32
|
+
warnings: [],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function getCerbosConfigMap(namespace) {
|
|
36
|
+
return `apiVersion: v1
|
|
37
|
+
kind: ConfigMap
|
|
38
|
+
metadata:
|
|
39
|
+
name: cerbos-config
|
|
40
|
+
namespace: ${namespace}
|
|
41
|
+
data:
|
|
42
|
+
config.yaml: |
|
|
43
|
+
server:
|
|
44
|
+
httpListenAddr: ":3592"
|
|
45
|
+
storage:
|
|
46
|
+
driver: "disk"
|
|
47
|
+
disk:
|
|
48
|
+
directory: /policies
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
function getCerbosPolicyConfigMap(args) {
|
|
52
|
+
const { namespace, intent } = args;
|
|
53
|
+
const entries = getCerbosPolicyEntries(intent);
|
|
54
|
+
const renderedEntries = entries
|
|
55
|
+
.map((entry) => {
|
|
56
|
+
const indented = indentLines(entry.content, 4);
|
|
57
|
+
return ` ${entry.key}: |
|
|
58
|
+
${indented}`;
|
|
59
|
+
})
|
|
60
|
+
.join('\n');
|
|
61
|
+
return `apiVersion: v1
|
|
62
|
+
kind: ConfigMap
|
|
63
|
+
metadata:
|
|
64
|
+
name: cerbos-policy
|
|
65
|
+
namespace: ${namespace}
|
|
66
|
+
data:
|
|
67
|
+
${renderedEntries}
|
|
68
|
+
`;
|
|
69
|
+
}
|
|
70
|
+
function getCerbosDeployment(namespace) {
|
|
71
|
+
return `apiVersion: apps/v1
|
|
72
|
+
kind: Deployment
|
|
73
|
+
metadata:
|
|
74
|
+
name: cerbos
|
|
75
|
+
namespace: ${namespace}
|
|
76
|
+
labels:
|
|
77
|
+
app.kubernetes.io/name: cerbos
|
|
78
|
+
spec:
|
|
79
|
+
replicas: 1
|
|
80
|
+
selector:
|
|
81
|
+
matchLabels:
|
|
82
|
+
app.kubernetes.io/name: cerbos
|
|
83
|
+
template:
|
|
84
|
+
metadata:
|
|
85
|
+
labels:
|
|
86
|
+
app.kubernetes.io/name: cerbos
|
|
87
|
+
spec:
|
|
88
|
+
containers:
|
|
89
|
+
- name: cerbos
|
|
90
|
+
image: ghcr.io/cerbos/cerbos:0.40.0
|
|
91
|
+
args:
|
|
92
|
+
- server
|
|
93
|
+
- --config=/config/config.yaml
|
|
94
|
+
ports:
|
|
95
|
+
- containerPort: 3592
|
|
96
|
+
volumeMounts:
|
|
97
|
+
- name: cerbos-config
|
|
98
|
+
mountPath: /config
|
|
99
|
+
- name: cerbos-policy
|
|
100
|
+
mountPath: /policies
|
|
101
|
+
volumes:
|
|
102
|
+
- name: cerbos-config
|
|
103
|
+
configMap:
|
|
104
|
+
name: cerbos-config
|
|
105
|
+
- name: cerbos-policy
|
|
106
|
+
configMap:
|
|
107
|
+
name: cerbos-policy
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
function getCerbosService(namespace) {
|
|
111
|
+
return `apiVersion: v1
|
|
112
|
+
kind: Service
|
|
113
|
+
metadata:
|
|
114
|
+
name: cerbos
|
|
115
|
+
namespace: ${namespace}
|
|
116
|
+
spec:
|
|
117
|
+
selector:
|
|
118
|
+
app.kubernetes.io/name: cerbos
|
|
119
|
+
ports:
|
|
120
|
+
- name: http
|
|
121
|
+
port: 3592
|
|
122
|
+
targetPort: 3592
|
|
123
|
+
`;
|
|
124
|
+
}
|
|
125
|
+
const PUBLIC_GUARD_HINTS = new Set(['public', 'guest', 'anonymous', 'unauthenticated']);
|
|
126
|
+
const AUTH_GUARD_HINTS = new Set([
|
|
127
|
+
'auth',
|
|
128
|
+
'authenticated',
|
|
129
|
+
'private',
|
|
130
|
+
'protected',
|
|
131
|
+
'requiresauth',
|
|
132
|
+
'requires-auth',
|
|
133
|
+
]);
|
|
134
|
+
function getCerbosPolicyEntries(intent) {
|
|
135
|
+
const entries = [
|
|
136
|
+
{
|
|
137
|
+
key: 'app.resource_policy.yaml',
|
|
138
|
+
content: getAppPolicy(intent),
|
|
139
|
+
},
|
|
140
|
+
];
|
|
141
|
+
if (intent.publicRoutes.length > 0 || intent.protectedRoutes.length > 0) {
|
|
142
|
+
entries.push({
|
|
143
|
+
key: 'route.resource_policy.yaml',
|
|
144
|
+
content: getRoutePolicy(intent),
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
if (intent.publicScreens.length > 0 || intent.protectedScreens.length > 0) {
|
|
148
|
+
entries.push({
|
|
149
|
+
key: 'screen.resource_policy.yaml',
|
|
150
|
+
content: getScreenPolicy(intent),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return entries;
|
|
154
|
+
}
|
|
155
|
+
function getAppPolicy(intent) {
|
|
156
|
+
const roles = intent.authScope === 'global' ? ['authenticated'] : ['anonymous', 'authenticated'];
|
|
157
|
+
return `apiVersion: api.cerbos.dev/v1
|
|
158
|
+
resourcePolicy:
|
|
159
|
+
version: "default"
|
|
160
|
+
resource: "app"
|
|
161
|
+
rules:
|
|
162
|
+
${indentLines(renderRule({ actions: ['*'], roles }), 4)}
|
|
163
|
+
`;
|
|
164
|
+
}
|
|
165
|
+
function getRoutePolicy(intent) {
|
|
166
|
+
const rules = [];
|
|
167
|
+
if (intent.publicRoutes.length > 0) {
|
|
168
|
+
rules.push(renderRule({
|
|
169
|
+
actions: ['view', 'navigate'],
|
|
170
|
+
roles: ['anonymous', 'authenticated'],
|
|
171
|
+
conditionExpr: getInConditionExpr('route', intent.publicRoutes),
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
if (intent.protectedRoutes.length > 0) {
|
|
175
|
+
rules.push(renderRule({
|
|
176
|
+
actions: ['view', 'navigate'],
|
|
177
|
+
roles: ['authenticated'],
|
|
178
|
+
conditionExpr: getInConditionExpr('route', intent.protectedRoutes),
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
return `apiVersion: api.cerbos.dev/v1
|
|
182
|
+
resourcePolicy:
|
|
183
|
+
version: "default"
|
|
184
|
+
resource: "route"
|
|
185
|
+
rules:
|
|
186
|
+
${indentLines(rules.join('\n'), 4)}
|
|
187
|
+
`;
|
|
188
|
+
}
|
|
189
|
+
function getScreenPolicy(intent) {
|
|
190
|
+
const rules = [];
|
|
191
|
+
if (intent.publicScreens.length > 0) {
|
|
192
|
+
rules.push(renderRule({
|
|
193
|
+
actions: ['view', 'render'],
|
|
194
|
+
roles: ['anonymous', 'authenticated'],
|
|
195
|
+
conditionExpr: getInConditionExpr('screen_id', intent.publicScreens),
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
if (intent.protectedScreens.length > 0) {
|
|
199
|
+
rules.push(renderRule({
|
|
200
|
+
actions: ['view', 'render'],
|
|
201
|
+
roles: ['authenticated'],
|
|
202
|
+
conditionExpr: getInConditionExpr('screen_id', intent.protectedScreens),
|
|
203
|
+
}));
|
|
204
|
+
}
|
|
205
|
+
return `apiVersion: api.cerbos.dev/v1
|
|
206
|
+
resourcePolicy:
|
|
207
|
+
version: "default"
|
|
208
|
+
resource: "screen"
|
|
209
|
+
rules:
|
|
210
|
+
${indentLines(rules.join('\n'), 4)}
|
|
211
|
+
`;
|
|
212
|
+
}
|
|
213
|
+
function renderRule(args) {
|
|
214
|
+
const { actions, roles, conditionExpr } = args;
|
|
215
|
+
const lines = [
|
|
216
|
+
`- actions: ${JSON.stringify(actions)}`,
|
|
217
|
+
' effect: EFFECT_ALLOW',
|
|
218
|
+
` roles: ${JSON.stringify(roles)}`,
|
|
219
|
+
];
|
|
220
|
+
if (conditionExpr) {
|
|
221
|
+
lines.push(' condition:');
|
|
222
|
+
lines.push(' match:');
|
|
223
|
+
lines.push(` expr: ${JSON.stringify(conditionExpr)}`);
|
|
224
|
+
}
|
|
225
|
+
return lines.join('\n');
|
|
226
|
+
}
|
|
227
|
+
function getInConditionExpr(attribute, values) {
|
|
228
|
+
return `request.resource.attr.${attribute} in ${JSON.stringify(values)}`;
|
|
229
|
+
}
|
|
230
|
+
function indentLines(content, spaces) {
|
|
231
|
+
const prefix = ' '.repeat(spaces);
|
|
232
|
+
return content
|
|
233
|
+
.trimEnd()
|
|
234
|
+
.split('\n')
|
|
235
|
+
.map((line) => `${prefix}${line}`)
|
|
236
|
+
.join('\n');
|
|
237
|
+
}
|
|
238
|
+
function buildCerbosPolicyIntent(args) {
|
|
239
|
+
const { manifest, appManifest } = args;
|
|
240
|
+
const authScope = manifest.auth?.scope ?? 'none';
|
|
241
|
+
const routes = appManifest?.navigator ? flattenNavigatorRoutes(appManifest.navigator) : [];
|
|
242
|
+
const signInRoute = appManifest?.settings.authFlow.signInRoute;
|
|
243
|
+
const signUpRoute = appManifest?.settings.authFlow.signUpRoute;
|
|
244
|
+
const unauthorizedRoute = appManifest?.settings.authFlow.unauthorizedRoute;
|
|
245
|
+
const publicRouteSet = new Set();
|
|
246
|
+
const protectedRouteSet = new Set();
|
|
247
|
+
for (const route of routes) {
|
|
248
|
+
const isPublic = isPublicRoute({
|
|
249
|
+
route,
|
|
250
|
+
authScope,
|
|
251
|
+
signInRoute,
|
|
252
|
+
signUpRoute,
|
|
253
|
+
unauthorizedRoute,
|
|
254
|
+
});
|
|
255
|
+
if (isPublic) {
|
|
256
|
+
publicRouteSet.add(route.name);
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
protectedRouteSet.add(route.name);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
const screenVisibility = new Map();
|
|
263
|
+
for (const route of routes) {
|
|
264
|
+
if (!route.screenId)
|
|
265
|
+
continue;
|
|
266
|
+
const isPublic = publicRouteSet.has(route.name);
|
|
267
|
+
const current = screenVisibility.get(route.screenId);
|
|
268
|
+
if (current === 'protected')
|
|
269
|
+
continue;
|
|
270
|
+
screenVisibility.set(route.screenId, isPublic ? 'public' : 'protected');
|
|
271
|
+
}
|
|
272
|
+
if (appManifest?.screens) {
|
|
273
|
+
const defaultVisibility = authScope === 'global' ? 'protected' : 'public';
|
|
274
|
+
for (const screenId of Object.keys(appManifest.screens)) {
|
|
275
|
+
if (!screenVisibility.has(screenId)) {
|
|
276
|
+
screenVisibility.set(screenId, defaultVisibility);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const publicScreens = [...screenVisibility.entries()]
|
|
281
|
+
.filter(([, visibility]) => visibility === 'public')
|
|
282
|
+
.map(([screenId]) => screenId)
|
|
283
|
+
.sort();
|
|
284
|
+
const protectedScreens = [...screenVisibility.entries()]
|
|
285
|
+
.filter(([, visibility]) => visibility === 'protected')
|
|
286
|
+
.map(([screenId]) => screenId)
|
|
287
|
+
.sort();
|
|
288
|
+
return {
|
|
289
|
+
authScope,
|
|
290
|
+
publicRoutes: [...publicRouteSet].sort(),
|
|
291
|
+
protectedRoutes: [...protectedRouteSet].sort(),
|
|
292
|
+
publicScreens,
|
|
293
|
+
protectedScreens,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function flattenNavigatorRoutes(navigator) {
|
|
297
|
+
const deduped = new Map();
|
|
298
|
+
const walk = (current) => {
|
|
299
|
+
for (const route of current.routes) {
|
|
300
|
+
const normalizedGuards = normalizeGuards(route.guards);
|
|
301
|
+
const existing = deduped.get(route.name);
|
|
302
|
+
deduped.set(route.name, {
|
|
303
|
+
name: route.name,
|
|
304
|
+
guards: unique([...(existing?.guards ?? []), ...normalizedGuards]),
|
|
305
|
+
screenId: route.screenId ?? existing?.screenId,
|
|
306
|
+
});
|
|
307
|
+
if (route.navigator) {
|
|
308
|
+
walk(route.navigator);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
walk(navigator);
|
|
313
|
+
return [...deduped.values()];
|
|
314
|
+
}
|
|
315
|
+
function normalizeGuards(guards) {
|
|
316
|
+
return (guards ?? []).map((guard) => guard.trim().toLowerCase()).filter(Boolean);
|
|
317
|
+
}
|
|
318
|
+
function isPublicRoute(args) {
|
|
319
|
+
const { route, authScope, signInRoute, signUpRoute, unauthorizedRoute } = args;
|
|
320
|
+
const guardSet = new Set(route.guards);
|
|
321
|
+
const signInRouteName = authFlowPathToRouteName(signInRoute);
|
|
322
|
+
const signUpRouteName = authFlowPathToRouteName(signUpRoute);
|
|
323
|
+
const unauthorizedRouteName = authFlowPathToRouteName(unauthorizedRoute);
|
|
324
|
+
if (route.name === signInRouteName ||
|
|
325
|
+
route.name === signUpRouteName ||
|
|
326
|
+
route.name === unauthorizedRouteName) {
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
if (hasAny(guardSet, PUBLIC_GUARD_HINTS)) {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
if (hasAny(guardSet, AUTH_GUARD_HINTS)) {
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
switch (authScope) {
|
|
336
|
+
case 'none':
|
|
337
|
+
return true;
|
|
338
|
+
case 'global':
|
|
339
|
+
default:
|
|
340
|
+
return false;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function hasAny(values, candidates) {
|
|
344
|
+
for (const candidate of candidates) {
|
|
345
|
+
if (values.has(candidate))
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
function unique(values) {
|
|
351
|
+
return [...new Set(values)];
|
|
352
|
+
}
|
|
353
|
+
function authFlowPathToRouteName(routePath) {
|
|
354
|
+
if (!routePath) {
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
const normalized = routePath.trim().replace(/^\/+/, '').replace(/\/+$/, '');
|
|
358
|
+
return normalized === '' ? 'index' : normalized;
|
|
359
|
+
}
|
|
360
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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';\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, 'metadata' | 'navigator' | 'screens' | 'settings'>;\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, 'metadata' | 'navigator' | 'screens' | 'settings'>;\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 signInRoute = appManifest?.settings.authFlow.signInRoute;\n const signUpRoute = appManifest?.settings.authFlow.signUpRoute;\n const unauthorizedRoute = appManifest?.settings.authFlow.unauthorizedRoute;\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"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AppManifest } from '@ankhorage/contracts';
|
|
2
|
+
import type { InfraManifestInput } from '../../../types';
|
|
3
|
+
import { type MinikubeAdapterArtifacts } from '../contracts';
|
|
4
|
+
export declare function generateAuthorizationArtifacts(args: {
|
|
5
|
+
manifest: InfraManifestInput;
|
|
6
|
+
namespace: string;
|
|
7
|
+
appManifest?: Pick<AppManifest, 'metadata' | 'navigator' | 'screens' | 'settings'>;
|
|
8
|
+
}): MinikubeAdapterArtifacts;
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapters/minikube/authz/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAA0B,KAAK,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAGrF,wBAAgB,8BAA8B,CAAC,IAAI,EAAE;IACnD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,CAAC,CAAC;CACpF,GAAG,wBAAwB,CAqB3B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { emptyMinikubeArtifacts } from '../contracts';
|
|
2
|
+
import { generateCerbosAuthzArtifacts } from './cerbos';
|
|
3
|
+
export function generateAuthorizationArtifacts(args) {
|
|
4
|
+
const { manifest, namespace, appManifest } = args;
|
|
5
|
+
const engine = manifest.auth?.authorization.engine;
|
|
6
|
+
if (!engine) {
|
|
7
|
+
return emptyMinikubeArtifacts();
|
|
8
|
+
}
|
|
9
|
+
switch (engine) {
|
|
10
|
+
case 'cerbos':
|
|
11
|
+
return generateCerbosAuthzArtifacts({ manifest, namespace, appManifest });
|
|
12
|
+
case 'native':
|
|
13
|
+
return {
|
|
14
|
+
...emptyMinikubeArtifacts(),
|
|
15
|
+
warnings: [
|
|
16
|
+
'Authorization engine "native" selected. No dedicated authz infrastructure artifacts were generated.',
|
|
17
|
+
],
|
|
18
|
+
};
|
|
19
|
+
default:
|
|
20
|
+
throw new Error(`Unsupported authorization engine for minikube adapter: ${String(engine)}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/adapters/minikube/authz/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,sBAAsB,EAAiC,MAAM,cAAc,CAAC;AACrF,OAAO,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAC;AAExD,MAAM,UAAU,8BAA8B,CAAC,IAI9C;IACC,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAClD,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC;IAEnD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,sBAAsB,EAAE,CAAC;IAClC,CAAC;IAED,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,4BAA4B,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;QAC5E,KAAK,QAAQ;YACX,OAAO;gBACL,GAAG,sBAAsB,EAAE;gBAC3B,QAAQ,EAAE;oBACR,qGAAqG;iBACtG;aACF,CAAC;QACJ;YACE,MAAM,IAAI,KAAK,CAAC,0DAA0D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAChG,CAAC;AACH,CAAC","sourcesContent":["import type { AppManifest } from '@ankhorage/contracts';\n\nimport type { InfraManifestInput } from '../../../types';\nimport { emptyMinikubeArtifacts, type MinikubeAdapterArtifacts } from '../contracts';\nimport { generateCerbosAuthzArtifacts } from './cerbos';\n\nexport function generateAuthorizationArtifacts(args: {\n manifest: InfraManifestInput;\n namespace: string;\n appManifest?: Pick<AppManifest, 'metadata' | 'navigator' | 'screens' | 'settings'>;\n}): MinikubeAdapterArtifacts {\n const { manifest, namespace, appManifest } = args;\n const engine = manifest.auth?.authorization.engine;\n\n if (!engine) {\n return emptyMinikubeArtifacts();\n }\n\n switch (engine) {\n case 'cerbos':\n return generateCerbosAuthzArtifacts({ manifest, namespace, appManifest });\n case 'native':\n return {\n ...emptyMinikubeArtifacts(),\n warnings: [\n 'Authorization engine \"native\" selected. No dedicated authz infrastructure artifacts were generated.',\n ],\n };\n default:\n throw new Error(`Unsupported authorization engine for minikube adapter: ${String(engine)}`);\n }\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GeneratedInfrastructureFile } from '../../../types';
|
|
2
|
+
import type { InfraManifestInput } from '../../../types';
|
|
3
|
+
export declare function generateMinikubeBaseArtifacts(args: {
|
|
4
|
+
manifest: InfraManifestInput;
|
|
5
|
+
namespace: string;
|
|
6
|
+
extraResources: string[];
|
|
7
|
+
extraEnvEntries: string[];
|
|
8
|
+
}): GeneratedInfrastructureFile[];
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapters/minikube/base/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAClE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAuBzD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IAClD,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B,GAAG,2BAA2B,EAAE,CAwGhC"}
|