@homeflare/alchemy 0.8.0 → 0.10.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/README.md +22 -11
- package/dist/caddy/config-lifecycle.d.ts +1 -1
- package/dist/caddy/config.d.ts.map +1 -1
- package/dist/caddy/index.js +221 -53
- package/dist/caddy/index.js.map +13 -9
- package/dist/launchd/fake-runner.d.ts +1 -0
- package/dist/launchd/fake-runner.d.ts.map +1 -1
- package/dist/launchd/fake-sudo.d.ts +1 -0
- package/dist/launchd/fake-sudo.d.ts.map +1 -1
- package/dist/launchd/host-effect.d.ts +9 -18
- package/dist/launchd/host-effect.d.ts.map +1 -1
- package/dist/launchd/host-file-lifecycle.d.ts +14 -1
- package/dist/launchd/host-file-lifecycle.d.ts.map +1 -1
- package/dist/launchd/host-file.d.ts +2 -1
- package/dist/launchd/host-file.d.ts.map +1 -1
- package/dist/launchd/index.js +345 -86
- package/dist/launchd/index.js.map +18 -12
- package/dist/launchd/job-lifecycle.d.ts +8 -1
- package/dist/launchd/job-lifecycle.d.ts.map +1 -1
- package/dist/launchd/job-preflight.d.ts +13 -1
- package/dist/launchd/job-preflight.d.ts.map +1 -1
- package/dist/launchd/job.d.ts +2 -1
- package/dist/launchd/job.d.ts.map +1 -1
- package/dist/launchd/runner.d.ts +7 -0
- package/dist/launchd/runner.d.ts.map +1 -1
- package/dist/launchd/sudo-acl.d.ts +25 -0
- package/dist/launchd/sudo-acl.d.ts.map +1 -0
- package/dist/launchd/sudo-guard.d.ts +31 -4
- package/dist/launchd/sudo-guard.d.ts.map +1 -1
- package/dist/launchd/sudo-runner.d.ts +3 -3
- package/dist/launchd/sudo-runner.d.ts.map +1 -1
- package/dist/launchd/sudo-said.d.ts +10 -0
- package/dist/launchd/sudo-said.d.ts.map +1 -0
- package/dist/openbao/auth-method-reconcile.d.ts +6 -2
- package/dist/openbao/auth-method-reconcile.d.ts.map +1 -1
- package/dist/openbao/auth-method.d.ts.map +1 -1
- package/dist/openbao/auth-role.d.ts.map +1 -1
- package/dist/openbao/cloudflare-role.d.ts.map +1 -1
- package/dist/openbao/fake-bao.d.ts +18 -0
- package/dist/openbao/fake-bao.d.ts.map +1 -1
- package/dist/openbao/fake-core.d.ts +39 -0
- package/dist/openbao/fake-core.d.ts.map +1 -0
- package/dist/openbao/fake-families.d.ts +6 -3
- package/dist/openbao/fake-families.d.ts.map +1 -1
- package/dist/openbao/fake-mounts.d.ts +16 -0
- package/dist/openbao/fake-mounts.d.ts.map +1 -0
- package/dist/openbao/fake-stack.d.ts +5 -1
- package/dist/openbao/fake-stack.d.ts.map +1 -1
- package/dist/openbao/index.js +541 -270
- package/dist/openbao/index.js.map +26 -21
- package/dist/openbao/jwt-config.d.ts.map +1 -1
- package/dist/openbao/jwt-role.d.ts.map +1 -1
- package/dist/openbao/kubernetes-role.d.ts.map +1 -1
- package/dist/openbao/mfa-enforcement.d.ts +6 -2
- package/dist/openbao/mfa-enforcement.d.ts.map +1 -1
- package/dist/openbao/mfa-totp.d.ts +6 -2
- package/dist/openbao/mfa-totp.d.ts.map +1 -1
- package/dist/openbao/mount-reconcile.d.ts +5 -1
- package/dist/openbao/mount-reconcile.d.ts.map +1 -1
- package/dist/openbao/mount.d.ts.map +1 -1
- package/dist/openbao/pki-role.d.ts.map +1 -1
- package/dist/openbao/plugin-reconcile.d.ts +6 -2
- package/dist/openbao/plugin-reconcile.d.ts.map +1 -1
- package/dist/openbao/plugin.d.ts.map +1 -1
- package/dist/openbao/policy.d.ts.map +1 -1
- package/dist/openbao/proxmox-role.d.ts.map +1 -1
- package/dist/openbao/role-reconcile.d.ts +11 -1
- package/dist/openbao/role-reconcile.d.ts.map +1 -1
- package/dist/openbao/ssh-role.d.ts.map +1 -1
- package/dist/ownership/adopt.d.ts +52 -0
- package/dist/ownership/adopt.d.ts.map +1 -0
- package/dist/ownership/probe.d.ts +13 -0
- package/dist/ownership/probe.d.ts.map +1 -0
- package/dist/ownership/resume.d.ts +40 -0
- package/dist/ownership/resume.d.ts.map +1 -0
- package/dist/ownership/rows.d.ts +33 -0
- package/dist/ownership/rows.d.ts.map +1 -0
- package/dist/ownership/whole.d.ts +14 -0
- package/dist/ownership/whole.d.ts.map +1 -0
- package/dist/proxmox/ceph-pool-form.d.ts +3 -3
- package/dist/proxmox/ceph-pool.d.ts.map +1 -1
- package/dist/proxmox/fake-bao-env.d.ts +3 -0
- package/dist/proxmox/fake-bao-env.d.ts.map +1 -0
- package/dist/proxmox/fake-pve-lxc.d.ts +42 -0
- package/dist/proxmox/fake-pve-lxc.d.ts.map +1 -0
- package/dist/proxmox/fake-pve.d.ts +38 -0
- package/dist/proxmox/fake-pve.d.ts.map +1 -0
- package/dist/proxmox/index.d.ts +6 -2
- package/dist/proxmox/index.d.ts.map +1 -1
- package/dist/proxmox/index.js +970 -186
- package/dist/proxmox/index.js.map +22 -9
- package/dist/proxmox/lxc-create-form.d.ts +6 -0
- package/dist/proxmox/lxc-create-form.d.ts.map +1 -0
- package/dist/proxmox/lxc-harness.d.ts +34 -0
- package/dist/proxmox/lxc-harness.d.ts.map +1 -0
- package/dist/proxmox/lxc-identity.d.ts +18 -0
- package/dist/proxmox/lxc-identity.d.ts.map +1 -0
- package/dist/proxmox/lxc-judge.d.ts +46 -0
- package/dist/proxmox/lxc-judge.d.ts.map +1 -0
- package/dist/proxmox/lxc-lifecycle.d.ts +68 -0
- package/dist/proxmox/lxc-lifecycle.d.ts.map +1 -0
- package/dist/proxmox/lxc-props.d.ts +139 -0
- package/dist/proxmox/lxc-props.d.ts.map +1 -0
- package/dist/proxmox/lxc-volume.d.ts +29 -0
- package/dist/proxmox/lxc-volume.d.ts.map +1 -0
- package/dist/proxmox/lxc-wire.d.ts +51 -0
- package/dist/proxmox/lxc-wire.d.ts.map +1 -0
- package/dist/proxmox/lxc.d.ts +27 -47
- package/dist/proxmox/lxc.d.ts.map +1 -1
- package/dist/proxmox/network-apply-read.d.ts +1 -1
- package/dist/proxmox/network-apply-read.d.ts.map +1 -1
- package/dist/proxmox/pbs-datastore.d.ts.map +1 -1
- package/dist/proxmox/resource.d.ts.map +1 -1
- package/dist/proxmox/update-guard.d.ts +27 -0
- package/dist/proxmox/update-guard.d.ts.map +1 -0
- package/dist/verify/args.d.ts +16 -0
- package/dist/verify/args.d.ts.map +1 -0
- package/dist/verify/cli.d.ts +3 -0
- package/dist/verify/cli.d.ts.map +1 -0
- package/dist/verify/cli.js +320 -0
- package/dist/verify/cli.js.map +15 -0
- package/dist/verify/fake-engine.d.ts +57 -0
- package/dist/verify/fake-engine.d.ts.map +1 -0
- package/dist/verify/index.d.ts +16 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +297 -0
- package/dist/verify/index.js.map +14 -0
- package/dist/verify/report.d.ts +6 -0
- package/dist/verify/report.d.ts.map +1 -0
- package/dist/verify/rows.d.ts +57 -0
- package/dist/verify/rows.d.ts.map +1 -0
- package/dist/verify/spy.d.ts +31 -0
- package/dist/verify/spy.d.ts.map +1 -0
- package/dist/verify/verify.d.ts +43 -0
- package/dist/verify/verify.d.ts.map +1 -0
- package/docs/adopt-verify.md +108 -0
- package/docs/adopted-deploys.md +85 -0
- package/docs/credentials.md +15 -0
- package/docs/launchd-sudo.md +31 -6
- package/docs/launchd.md +7 -3
- package/docs/ownership.md +113 -0
- package/docs/proxmox-lxc.md +196 -0
- package/docs/proxmox.md +12 -0
- package/package.json +9 -2
- package/src/caddy/adopt-scope.test.ts +1 -1
- package/src/caddy/config-lifecycle.ts +1 -1
- package/src/caddy/config.ts +2 -1
- package/src/launchd/adopt-apply.test.ts +166 -0
- package/src/launchd/fake-runner.ts +26 -4
- package/src/launchd/host-effect.ts +1 -33
- package/src/launchd/host-file-lifecycle.ts +39 -14
- package/src/launchd/host-file.ts +13 -4
- package/src/launchd/job-lifecycle.ts +22 -14
- package/src/launchd/job-preflight.ts +18 -1
- package/src/launchd/job.ts +13 -4
- package/src/launchd/runner.ts +7 -0
- package/src/launchd/sudo-acl.ts +68 -0
- package/src/launchd/sudo-chain.test.ts +121 -0
- package/src/launchd/sudo-guard.ts +89 -10
- package/src/launchd/sudo-modes.test.ts +135 -0
- package/src/launchd/sudo-runner.ts +40 -59
- package/src/launchd/sudo-said.ts +58 -0
- package/src/openbao/README.md +5 -2
- package/src/openbao/REPLACE.md +13 -11
- package/src/openbao/adopt-core.test.ts +119 -0
- package/src/openbao/adopt-families.test.ts +97 -0
- package/src/openbao/adopt-holes.test.ts +168 -0
- package/src/openbao/adopt-recovery.test.ts +71 -0
- package/src/openbao/auth-method-reconcile.ts +15 -3
- package/src/openbao/auth-method.ts +15 -6
- package/src/openbao/auth-role.ts +14 -4
- package/src/openbao/cloudflare-role.ts +17 -4
- package/src/openbao/fake-bao.ts +52 -0
- package/src/openbao/fake-core.ts +141 -0
- package/src/openbao/fake-families.ts +11 -5
- package/src/openbao/fake-mounts.ts +74 -0
- package/src/openbao/fake-stack.ts +17 -4
- package/src/openbao/jwt-config.ts +10 -7
- package/src/openbao/jwt-role.ts +10 -7
- package/src/openbao/kubernetes-role.ts +13 -7
- package/src/openbao/mfa-enforcement.ts +20 -6
- package/src/openbao/mfa-totp.ts +22 -7
- package/src/openbao/mount-move.test.ts +2 -35
- package/src/openbao/mount-reconcile.ts +13 -2
- package/src/openbao/mount.ts +15 -6
- package/src/openbao/pki-role.ts +15 -4
- package/src/openbao/plugin-reconcile.ts +16 -5
- package/src/openbao/plugin.ts +17 -6
- package/src/openbao/policy.ts +17 -4
- package/src/openbao/proxmox-role.ts +13 -4
- package/src/openbao/rename-adoption.test.ts +32 -19
- package/src/openbao/role-reconcile.ts +23 -0
- package/src/openbao/ssh-role.ts +14 -4
- package/src/ownership/adopt.ts +122 -0
- package/src/ownership/ownership.test.ts +200 -0
- package/src/ownership/probe.ts +65 -0
- package/src/ownership/resume.ts +118 -0
- package/src/ownership/rows.ts +117 -0
- package/src/ownership/whole.test.ts +39 -0
- package/src/ownership/whole.ts +60 -0
- package/src/proxmox/adopt-noop.test.ts +112 -0
- package/src/proxmox/ceph-pool-adopt.test.ts +88 -0
- package/src/proxmox/ceph-pool-form.ts +3 -3
- package/src/proxmox/ceph-pool.ts +10 -3
- package/src/proxmox/fake-bao-env.ts +28 -0
- package/src/proxmox/fake-pve-lxc.ts +210 -0
- package/src/proxmox/fake-pve.ts +75 -0
- package/src/proxmox/index.test.ts +6 -6
- package/src/proxmox/index.ts +6 -2
- package/src/proxmox/lxc-adopt.test.ts +170 -0
- package/src/proxmox/lxc-create-form.ts +76 -0
- package/src/proxmox/lxc-create.test.ts +126 -0
- package/src/proxmox/lxc-guards.test.ts +158 -0
- package/src/proxmox/lxc-harness.ts +150 -0
- package/src/proxmox/lxc-identity.ts +43 -0
- package/src/proxmox/lxc-judge.test.ts +175 -0
- package/src/proxmox/lxc-judge.ts +196 -0
- package/src/proxmox/lxc-lifecycle.ts +200 -0
- package/src/proxmox/lxc-ownership.test.ts +159 -0
- package/src/proxmox/lxc-props.ts +215 -0
- package/src/proxmox/lxc-read.test.ts +60 -0
- package/src/proxmox/lxc-volume.test.ts +96 -0
- package/src/proxmox/lxc-volume.ts +153 -0
- package/src/proxmox/lxc-wire.ts +210 -0
- package/src/proxmox/lxc.ts +216 -93
- package/src/proxmox/network-apply-read.ts +3 -1
- package/src/proxmox/pbs-datastore.ts +4 -3
- package/src/proxmox/resource.ts +7 -7
- package/src/proxmox/update-guard.ts +31 -0
- package/src/verify/args.ts +82 -0
- package/src/verify/cli.test.ts +86 -0
- package/src/verify/cli.ts +49 -0
- package/src/verify/fake-engine.ts +158 -0
- package/src/verify/index.ts +36 -0
- package/src/verify/report.ts +52 -0
- package/src/verify/rows.ts +169 -0
- package/src/verify/spy.test.ts +141 -0
- package/src/verify/spy.ts +149 -0
- package/src/verify/verify.test.ts +124 -0
- package/src/verify/verify.ts +172 -0
package/dist/openbao/index.js
CHANGED
|
@@ -297,7 +297,202 @@ var revokeSelf = (token, env) => runWith(env, revokeSelfEffect(token));
|
|
|
297
297
|
import { Resource } from "alchemy";
|
|
298
298
|
import { isResolved } from "alchemy/Diff";
|
|
299
299
|
import * as Provider from "alchemy/Provider";
|
|
300
|
+
import * as Effect12 from "effect/Effect";
|
|
301
|
+
|
|
302
|
+
// src/ownership/adopt.ts
|
|
303
|
+
import { AdoptPolicy } from "alchemy/AdoptPolicy";
|
|
304
|
+
import { AlchemyContext } from "alchemy/AlchemyContext";
|
|
305
|
+
import { Stack as Stack3 } from "alchemy/Stack";
|
|
306
|
+
import * as Effect6 from "effect/Effect";
|
|
307
|
+
import * as Option5 from "effect/Option";
|
|
308
|
+
|
|
309
|
+
// src/ownership/resume.ts
|
|
310
|
+
import { Unowned } from "alchemy/AdoptPolicy";
|
|
311
|
+
import { Artifacts } from "alchemy/Artifacts";
|
|
312
|
+
import * as Effect3 from "effect/Effect";
|
|
313
|
+
import * as Option2 from "effect/Option";
|
|
314
|
+
var PROVEN = "homeflare/ownership/resumes";
|
|
315
|
+
var UNFINISHED = "homeflare/ownership/unfinished";
|
|
316
|
+
var note = (key, instanceId) => Effect3.gen(function* () {
|
|
317
|
+
const bag = yield* Effect3.serviceOption(Artifacts);
|
|
318
|
+
if (Option2.isSome(bag))
|
|
319
|
+
yield* bag.value.set(key, instanceId);
|
|
320
|
+
});
|
|
321
|
+
var noted = (key, instanceId) => Effect3.gen(function* () {
|
|
322
|
+
const bag = yield* Effect3.serviceOption(Artifacts);
|
|
323
|
+
if (Option2.isNone(bag))
|
|
324
|
+
return false;
|
|
325
|
+
return (yield* bag.value.get(key)) === instanceId;
|
|
326
|
+
});
|
|
327
|
+
var noteUnfinished = (instanceId) => Effect3.as(note(UNFINISHED, instanceId), undefined);
|
|
328
|
+
var noteResume = (instanceId, recovered) => Effect3.gen(function* () {
|
|
329
|
+
yield* noteUnfinished(instanceId);
|
|
330
|
+
const unproven = () => Effect3.succeed(undefined);
|
|
331
|
+
const found = yield* recovered.pipe(Effect3.catch(unproven), Effect3.catchDefect(unproven));
|
|
332
|
+
if (found === undefined || found === null || Unowned.is(found))
|
|
333
|
+
return;
|
|
334
|
+
yield* note(PROVEN, instanceId);
|
|
335
|
+
});
|
|
336
|
+
var resumes = (instanceId) => noted(PROVEN, instanceId);
|
|
337
|
+
var unfinished = (instanceId) => noted(UNFINISHED, instanceId);
|
|
338
|
+
var provingResumes = (service) => {
|
|
339
|
+
const { diff, read } = service;
|
|
340
|
+
if (diff === undefined || read === undefined)
|
|
341
|
+
return service;
|
|
342
|
+
const proving = (input) => Effect3.gen(function* () {
|
|
343
|
+
if (input.output === undefined) {
|
|
344
|
+
yield* noteResume(input.instanceId, read({ ...input, output: undefined }));
|
|
345
|
+
}
|
|
346
|
+
return yield* diff(input);
|
|
347
|
+
});
|
|
348
|
+
return { ...service, diff: proving };
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// src/ownership/rows.ts
|
|
352
|
+
import { Stack as Stack2 } from "alchemy/Stack";
|
|
353
|
+
import { State, isActionState } from "alchemy/State/State";
|
|
354
|
+
import * as Effect5 from "effect/Effect";
|
|
355
|
+
import * as Option4 from "effect/Option";
|
|
356
|
+
|
|
357
|
+
// src/ownership/whole.ts
|
|
358
|
+
import { Stack } from "alchemy/Stack";
|
|
359
|
+
import * as Effect4 from "effect/Effect";
|
|
360
|
+
import * as Option3 from "effect/Option";
|
|
361
|
+
var absent = (value) => value === undefined || value === null;
|
|
362
|
+
var isPlainObject = (value) => {
|
|
363
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
364
|
+
return false;
|
|
365
|
+
const proto = Object.getPrototypeOf(value);
|
|
366
|
+
return proto === Object.prototype || proto === null;
|
|
367
|
+
};
|
|
368
|
+
var carries = (declared, recorded) => {
|
|
369
|
+
if (absent(declared))
|
|
370
|
+
return true;
|
|
371
|
+
if (absent(recorded))
|
|
372
|
+
return false;
|
|
373
|
+
if (Array.isArray(declared)) {
|
|
374
|
+
if (!Array.isArray(recorded))
|
|
375
|
+
return false;
|
|
376
|
+
return declared.every((each, index) => carries(each, recorded[index]));
|
|
377
|
+
}
|
|
378
|
+
if (isPlainObject(declared)) {
|
|
379
|
+
if (!isPlainObject(recorded))
|
|
380
|
+
return false;
|
|
381
|
+
return Object.entries(declared).every(([key, each]) => carries(each, recorded[key]));
|
|
382
|
+
}
|
|
383
|
+
return true;
|
|
384
|
+
};
|
|
385
|
+
var wholeDeclaration = (fqn, props) => Effect4.map(Effect4.serviceOption(Stack), (stack) => {
|
|
386
|
+
const declared = Option3.isSome(stack) ? stack.value.resources[fqn] : undefined;
|
|
387
|
+
return declared !== undefined && carries(declared.Props, props);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// src/ownership/rows.ts
|
|
391
|
+
var storeOf = Effect5.gen(function* () {
|
|
392
|
+
const stack = yield* Effect5.serviceOption(Stack2);
|
|
393
|
+
const state = yield* Effect5.serviceOption(State);
|
|
394
|
+
if (Option4.isNone(stack) || Option4.isNone(state))
|
|
395
|
+
return;
|
|
396
|
+
const store = yield* state.value;
|
|
397
|
+
const where = { stack: stack.value.name, stage: stack.value.stage };
|
|
398
|
+
return { resources: stack.value.resources, store, where };
|
|
399
|
+
});
|
|
400
|
+
var rowAt = (store, where, fqn) => store.get({ ...where, fqn }).pipe(Effect5.orElseSucceed(() => {
|
|
401
|
+
return;
|
|
402
|
+
}));
|
|
403
|
+
var generationOf = (row, instanceId) => {
|
|
404
|
+
let at = row;
|
|
405
|
+
while (typeof at === "object" && at !== null && !isActionState(at)) {
|
|
406
|
+
const generation = at;
|
|
407
|
+
if (generation.instanceId === instanceId)
|
|
408
|
+
return generation;
|
|
409
|
+
at = generation.old;
|
|
410
|
+
}
|
|
411
|
+
return;
|
|
412
|
+
};
|
|
413
|
+
var recordedGeneration = (fqn, instanceId) => Effect5.gen(function* () {
|
|
414
|
+
const found = yield* storeOf;
|
|
415
|
+
if (found === undefined)
|
|
416
|
+
return;
|
|
417
|
+
for (const at of [fqn, ...found.resources[fqn]?.FormerFqns ?? []]) {
|
|
418
|
+
const generation = generationOf(yield* rowAt(found.store, found.where, at), instanceId);
|
|
419
|
+
if (generation !== undefined)
|
|
420
|
+
return generation;
|
|
421
|
+
}
|
|
422
|
+
return;
|
|
423
|
+
});
|
|
424
|
+
var recordedInstance = (fqn, instanceId) => Effect5.gen(function* () {
|
|
425
|
+
const generation = yield* recordedGeneration(fqn, instanceId);
|
|
426
|
+
if (generation === undefined)
|
|
427
|
+
return "absent";
|
|
428
|
+
return (yield* wholeDeclaration(fqn, generation.props)) ? "whole" : "partial";
|
|
429
|
+
});
|
|
430
|
+
var isCreate = (fqn, instanceId) => Effect5.map(recordedGeneration(fqn, instanceId), (generation) => generation?.status === "creating");
|
|
431
|
+
var forgetRefusedCreate = (fqn, instanceId) => Effect5.gen(function* () {
|
|
432
|
+
const found = yield* storeOf;
|
|
433
|
+
if (found === undefined)
|
|
434
|
+
return;
|
|
435
|
+
const row = yield* rowAt(found.store, found.where, fqn);
|
|
436
|
+
const mine = row;
|
|
437
|
+
if (mine?.status !== "creating" || mine.instanceId !== instanceId || mine.attr !== undefined) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
yield* found.store.delete({ ...found.where, fqn }).pipe(Effect5.ignore);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
// src/ownership/adopt.ts
|
|
444
|
+
var adoptEnabled = (fqn) => Effect6.gen(function* () {
|
|
445
|
+
const stack = yield* Effect6.serviceOption(Stack3);
|
|
446
|
+
const scoped = Option5.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;
|
|
447
|
+
if (scoped !== undefined)
|
|
448
|
+
return scoped;
|
|
449
|
+
const policy = yield* Effect6.serviceOption(AdoptPolicy);
|
|
450
|
+
if (Option5.isSome(policy))
|
|
451
|
+
return policy.value;
|
|
452
|
+
const context = yield* Effect6.serviceOption(AlchemyContext);
|
|
453
|
+
return Option5.isSome(context) ? context.value.adopt : false;
|
|
454
|
+
});
|
|
455
|
+
var adoptable = (owner) => Effect6.gen(function* () {
|
|
456
|
+
if (yield* isCreate(owner.fqn, owner.instanceId))
|
|
457
|
+
return true;
|
|
458
|
+
return yield* unfinished(owner.instanceId);
|
|
459
|
+
});
|
|
460
|
+
var adoptsAtApply = (owner) => Effect6.gen(function* () {
|
|
461
|
+
if (!(yield* adoptEnabled(owner.fqn)))
|
|
462
|
+
return false;
|
|
463
|
+
return yield* adoptable(owner);
|
|
464
|
+
});
|
|
465
|
+
var refuseTakeover = (owner, what) => Effect6.gen(function* () {
|
|
466
|
+
if (owner.output !== undefined)
|
|
467
|
+
return;
|
|
468
|
+
if (yield* resumes(owner.instanceId))
|
|
469
|
+
return;
|
|
470
|
+
const may = yield* adoptable(owner);
|
|
471
|
+
if (may && (yield* adoptEnabled(owner.fqn)))
|
|
472
|
+
return;
|
|
473
|
+
yield* forgetRefusedCreate(owner.fqn, owner.instanceId);
|
|
474
|
+
const remedy = may ? "Deploy with --adopt (or wrap the resource in adopt(true)) to take it over, or remove it first." : "It is the new identity of a replace, which --adopt does not cover: remove it first.";
|
|
475
|
+
return yield* Effect6.die(new Error(`${what}: already exists, and this stack holds no state for it — the plan could not ask ` + "first (a prop was still an Output, a replace moved onto it, or it appeared after the " + `plan). Nothing was written. ${remedy}`));
|
|
476
|
+
});
|
|
477
|
+
var claimFor = (owner) => (what) => refuseTakeover(owner, what);
|
|
478
|
+
|
|
479
|
+
// src/ownership/probe.ts
|
|
480
|
+
import { Unowned as Unowned2 } from "alchemy/AdoptPolicy";
|
|
300
481
|
import * as Effect7 from "effect/Effect";
|
|
482
|
+
var ownedRead = (ask, found, settled) => Effect7.gen(function* () {
|
|
483
|
+
if (found === undefined || ask.output !== undefined)
|
|
484
|
+
return found;
|
|
485
|
+
const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);
|
|
486
|
+
if (recorded === "absent")
|
|
487
|
+
return Unowned2(found);
|
|
488
|
+
if (recorded === "partial") {
|
|
489
|
+
yield* Effect7.logWarning(`${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` + "was still an Output when it was written), so the live object is not proven ours");
|
|
490
|
+
return Unowned2(found);
|
|
491
|
+
}
|
|
492
|
+
const unproven = (reason) => Effect7.as(Effect7.logWarning(`${ask.fqn}: the interrupted create's object could not be compared with its props ` + `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`), false);
|
|
493
|
+
const ours = yield* settled.pipe(Effect7.catch(unproven), Effect7.catchDefect(unproven));
|
|
494
|
+
return ours ? found : Unowned2(found);
|
|
495
|
+
});
|
|
301
496
|
|
|
302
497
|
// src/openbao/digest.ts
|
|
303
498
|
var canonical = (text) => text.trimEnd();
|
|
@@ -438,24 +633,24 @@ var matches2 = (attributes, props) => attributes.type === props.type && (props.d
|
|
|
438
633
|
var wantsTune2 = (props) => props.description !== undefined || props.defaultLeaseTtl !== undefined || props.maxLeaseTtl !== undefined;
|
|
439
634
|
|
|
440
635
|
// src/openbao/auth-method-reconcile.ts
|
|
441
|
-
import * as
|
|
636
|
+
import * as Effect11 from "effect/Effect";
|
|
442
637
|
|
|
443
638
|
// src/openbao/auth-method-wire.ts
|
|
444
|
-
import * as
|
|
445
|
-
var absentFromTable = (path, asked) => baoRead("sys/auth").pipe(
|
|
639
|
+
import * as Effect8 from "effect/Effect";
|
|
640
|
+
var absentFromTable = (path, asked) => baoRead("sys/auth").pipe(Effect8.mapError((listing) => new BaoError(asked.status, asked.method, asked.path, [
|
|
446
641
|
...asked.errors,
|
|
447
642
|
`sys/auth could not confirm the method is absent: ${listing.message}`
|
|
448
|
-
])),
|
|
449
|
-
var readAuthMethodData = (path) => baoRead(readPath2(path)).pipe(
|
|
643
|
+
])), Effect8.flatMap((table) => table !== undefined && !Object.hasOwn(table, `${authPath(path)}/`) ? Effect8.succeed(undefined) : Effect8.fail(asked)));
|
|
644
|
+
var readAuthMethodData = (path) => baoRead(readPath2(path)).pipe(Effect8.catchIf((error) => error.status === 400, (error) => absentFromTable(path, error)));
|
|
450
645
|
var enableAuthMethod = (props) => baoWrite("POST", readPath2(props.path), enableBody2(props));
|
|
451
646
|
var tuneAuthMethod = (props) => baoWrite("POST", tunePath2(props.path), tuneBody2(props));
|
|
452
647
|
var disableAuthMethod = (path) => baoDelete(readPath2(path));
|
|
453
648
|
|
|
454
649
|
// src/openbao/mount-move.ts
|
|
455
|
-
import * as
|
|
650
|
+
import * as Effect10 from "effect/Effect";
|
|
456
651
|
|
|
457
652
|
// src/openbao/remount-wire.ts
|
|
458
|
-
import * as
|
|
653
|
+
import * as Effect9 from "effect/Effect";
|
|
459
654
|
class RemountError extends Error {
|
|
460
655
|
constructor(message) {
|
|
461
656
|
super(message);
|
|
@@ -463,17 +658,17 @@ class RemountError extends Error {
|
|
|
463
658
|
}
|
|
464
659
|
}
|
|
465
660
|
var record = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
466
|
-
var startRemount = (from, to) =>
|
|
661
|
+
var startRemount = (from, to) => Effect9.flatMap(baoCall("write", "POST", "sys/remount", { from, to }), (body) => {
|
|
467
662
|
const id = record(body?.["data"])?.["migration_id"];
|
|
468
|
-
return typeof id === "string" && id !== "" ?
|
|
663
|
+
return typeof id === "string" && id !== "" ? Effect9.succeed(id) : Effect9.fail(new RemountError(`sys/remount ${from} -> ${to} answered no migration_id.`));
|
|
469
664
|
});
|
|
470
|
-
var remountStatus = (id) =>
|
|
665
|
+
var remountStatus = (id) => Effect9.map(baoRead(`sys/remount/status/${encodeURIComponent(id)}`), (data) => {
|
|
471
666
|
if (data === undefined)
|
|
472
667
|
return;
|
|
473
668
|
const status = record(data["migration_info"])?.["status"];
|
|
474
669
|
return typeof status === "string" ? status : "unknown";
|
|
475
670
|
});
|
|
476
|
-
var remountAndWait = (from, to, confirm, options = {}) =>
|
|
671
|
+
var remountAndWait = (from, to, confirm, options = {}) => Effect9.gen(function* () {
|
|
477
672
|
const interval = options.intervalMillis ?? 1000;
|
|
478
673
|
const attempts = Math.max(1, options.attempts ?? 120);
|
|
479
674
|
const id = yield* startRemount(from, to);
|
|
@@ -483,17 +678,17 @@ var remountAndWait = (from, to, confirm, options = {}) => Effect4.gen(function*
|
|
|
483
678
|
if (status === "success")
|
|
484
679
|
return;
|
|
485
680
|
if (status === "failure") {
|
|
486
|
-
return yield*
|
|
681
|
+
return yield* Effect9.fail(new RemountError(`${named} FAILED. The server log carries the reason, tagged with that migration_id. ` + "Read sys/mounts (or sys/auth) before retrying: the source may be tainted."));
|
|
487
682
|
}
|
|
488
683
|
if (status === undefined) {
|
|
489
684
|
if (yield* confirm)
|
|
490
685
|
return;
|
|
491
|
-
return yield*
|
|
686
|
+
return yield* Effect9.fail(new RemountError(`${named}: the server no longer knows the migration (its tracker is in memory, lost ` + "on a restart or leader change), and the mount table does not show the move done."));
|
|
492
687
|
}
|
|
493
688
|
if (attempt < attempts)
|
|
494
|
-
yield*
|
|
689
|
+
yield* Effect9.sleep(interval);
|
|
495
690
|
}
|
|
496
|
-
return yield*
|
|
691
|
+
return yield* Effect9.fail(new RemountError(`${named} is still in progress after ${String(attempts)} status reads. Do not re-run ` + `until sys/remount/status/${id} settles.`));
|
|
497
692
|
});
|
|
498
693
|
|
|
499
694
|
// src/openbao/mount-move.ts
|
|
@@ -520,8 +715,8 @@ var planMove = (family, stated, path, remountFrom) => {
|
|
|
520
715
|
}
|
|
521
716
|
return { kind: "move", from };
|
|
522
717
|
};
|
|
523
|
-
var refuse = (message) =>
|
|
524
|
-
var performMove = (target, from, options) =>
|
|
718
|
+
var refuse = (message) => Effect10.die(new Error(message));
|
|
719
|
+
var performMove = (target, from, options) => Effect10.gen(function* () {
|
|
525
720
|
const to = mountPath(target.path);
|
|
526
721
|
const source = yield* target.read(from);
|
|
527
722
|
const landed = yield* target.read(to);
|
|
@@ -536,12 +731,12 @@ var performMove = (target, from, options) => Effect5.gen(function* () {
|
|
|
536
731
|
if (source.type !== target.type) {
|
|
537
732
|
return yield* refuse(`${target.family}: ${from} is type ${source.type}, not ${target.type}. A remount keeps the ` + "type; fix the declaration first.");
|
|
538
733
|
}
|
|
539
|
-
const confirm =
|
|
734
|
+
const confirm = Effect10.map(Effect10.all([target.read(from), target.read(to)]), ([gone, there]) => gone === undefined && there !== undefined);
|
|
540
735
|
yield* remountAndWait(target.wire(from), target.wire(to), confirm, options);
|
|
541
736
|
});
|
|
542
737
|
|
|
543
738
|
// src/openbao/auth-method-reconcile.ts
|
|
544
|
-
var readMethod = (props) =>
|
|
739
|
+
var readMethod = (props) => Effect11.gen(function* () {
|
|
545
740
|
const live = yield* readAuthMethodData(props.path);
|
|
546
741
|
if (live === undefined)
|
|
547
742
|
return;
|
|
@@ -554,10 +749,16 @@ var moveTarget = (props) => ({
|
|
|
554
749
|
type: props.type,
|
|
555
750
|
wire: (path) => `auth/${authPath(path)}`
|
|
556
751
|
});
|
|
557
|
-
var reconcileAuthMethod = (news, stated, options) =>
|
|
752
|
+
var reconcileAuthMethod = (news, stated, options, claim) => Effect11.gen(function* () {
|
|
558
753
|
const move = planMove("Bao.AuthMethod", stated, news.path, news.remountFrom);
|
|
559
754
|
if (move.kind === "refuse")
|
|
560
|
-
return yield*
|
|
755
|
+
return yield* Effect11.die(new Error(move.message));
|
|
756
|
+
const first = stated === undefined ? claim : undefined;
|
|
757
|
+
if (first !== undefined && move.kind === "move") {
|
|
758
|
+
const source = yield* readMethod({ ...news, path: move.from });
|
|
759
|
+
if (source !== undefined)
|
|
760
|
+
yield* first(`Bao.AuthMethod ${move.from} (the remountFrom source)`);
|
|
761
|
+
}
|
|
561
762
|
if (move.kind === "move")
|
|
562
763
|
yield* performMove(moveTarget(news), move.from, options);
|
|
563
764
|
let live = yield* readMethod(news);
|
|
@@ -565,15 +766,18 @@ var reconcileAuthMethod = (news, stated, options) => Effect6.gen(function* () {
|
|
|
565
766
|
yield* enableAuthMethod(news);
|
|
566
767
|
if (wantsTune2(news))
|
|
567
768
|
yield* tuneAuthMethod(news);
|
|
568
|
-
} else
|
|
769
|
+
} else {
|
|
569
770
|
if (live.type !== news.type) {
|
|
570
|
-
return yield*
|
|
771
|
+
return yield* Effect11.die(new Error(`Bao.AuthMethod ${authPath(news.path)}: live type ${live.type} != ${news.type}. ` + "Auth method type is immutable — replace manually."));
|
|
571
772
|
}
|
|
572
|
-
|
|
773
|
+
if (first !== undefined)
|
|
774
|
+
yield* first(`Bao.AuthMethod ${authPath(news.path)}`);
|
|
775
|
+
if (!matches2(live, news))
|
|
776
|
+
yield* tuneAuthMethod(news);
|
|
573
777
|
}
|
|
574
778
|
live = yield* readMethod(news);
|
|
575
779
|
if (live === undefined) {
|
|
576
|
-
return yield*
|
|
780
|
+
return yield* Effect11.die(new Error(`Bao.AuthMethod ${authPath(news.path)}: write returned no error but the method is still absent.`));
|
|
577
781
|
}
|
|
578
782
|
return live;
|
|
579
783
|
});
|
|
@@ -582,17 +786,21 @@ var reconcileAuthMethod = (news, stated, options) => Effect6.gen(function* () {
|
|
|
582
786
|
var BaoAuthMethod = Resource("Bao.AuthMethod", {
|
|
583
787
|
defaultRemovalPolicy: "retain"
|
|
584
788
|
});
|
|
585
|
-
var BaoAuthMethodProvider = () => Provider.effect(BaoAuthMethod,
|
|
586
|
-
list: () =>
|
|
587
|
-
read:
|
|
588
|
-
|
|
789
|
+
var BaoAuthMethodProvider = () => Provider.effect(BaoAuthMethod, Effect12.succeed(BaoAuthMethod.Provider.of({
|
|
790
|
+
list: () => Effect12.succeed([]),
|
|
791
|
+
read: Effect12.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
792
|
+
const found = yield* readMethod(olds);
|
|
793
|
+
const ours = Effect12.sync(() => found !== undefined && matches2(found, olds));
|
|
794
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
589
795
|
}),
|
|
590
|
-
diff:
|
|
591
|
-
if (output === undefined
|
|
796
|
+
diff: Effect12.fn(function* ({ news, output }) {
|
|
797
|
+
if (output === undefined)
|
|
798
|
+
return;
|
|
799
|
+
if (!isResolved(news))
|
|
592
800
|
return;
|
|
593
801
|
const move = planMove("Bao.AuthMethod", output.path, news.path, news.remountFrom);
|
|
594
802
|
if (move.kind === "refuse")
|
|
595
|
-
return yield*
|
|
803
|
+
return yield* Effect12.die(new Error(move.message));
|
|
596
804
|
if (move.kind === "move")
|
|
597
805
|
return { action: "update" };
|
|
598
806
|
const live = yield* readMethod(news);
|
|
@@ -604,19 +812,20 @@ var BaoAuthMethodProvider = () => Provider.effect(BaoAuthMethod, Effect7.succeed
|
|
|
604
812
|
return { action: "noop" };
|
|
605
813
|
return { action: "update" };
|
|
606
814
|
}),
|
|
607
|
-
reconcile:
|
|
608
|
-
|
|
815
|
+
reconcile: Effect12.fn(function* ({ fqn, instanceId, news, output }) {
|
|
816
|
+
const claim = claimFor({ fqn, instanceId, output });
|
|
817
|
+
return yield* reconcileAuthMethod(news, output?.path, undefined, claim);
|
|
609
818
|
}),
|
|
610
|
-
delete:
|
|
819
|
+
delete: Effect12.fn(function* ({ output }) {
|
|
611
820
|
yield* disableAuthMethod(output.path);
|
|
612
821
|
return;
|
|
613
822
|
})
|
|
614
|
-
})));
|
|
823
|
+
})).pipe(Effect12.map(provingResumes)));
|
|
615
824
|
// src/openbao/auth-role.ts
|
|
616
825
|
import { Resource as Resource2 } from "alchemy";
|
|
617
826
|
import { isResolved as isResolved2 } from "alchemy/Diff";
|
|
618
827
|
import * as Provider2 from "alchemy/Provider";
|
|
619
|
-
import * as
|
|
828
|
+
import * as Effect15 from "effect/Effect";
|
|
620
829
|
|
|
621
830
|
// src/openbao/auth-role-form.ts
|
|
622
831
|
var policiesOf = (live) => {
|
|
@@ -677,10 +886,10 @@ var matches3 = (attributes, props) => {
|
|
|
677
886
|
};
|
|
678
887
|
|
|
679
888
|
// src/openbao/rename-identity.ts
|
|
680
|
-
import * as
|
|
889
|
+
import * as Effect14 from "effect/Effect";
|
|
681
890
|
|
|
682
891
|
// src/openbao/rename.ts
|
|
683
|
-
import * as
|
|
892
|
+
import * as Effect13 from "effect/Effect";
|
|
684
893
|
var exact = (identity) => identity;
|
|
685
894
|
var declaredString = (news, key) => {
|
|
686
895
|
if (typeof news !== "object" || news === null)
|
|
@@ -702,15 +911,15 @@ var declaredRolePath = (news, rolePath, defaultMount) => {
|
|
|
702
911
|
};
|
|
703
912
|
var policyKey = (name) => name.trim().toLowerCase();
|
|
704
913
|
var isMoved = (stored, declared, key = exact) => declared === undefined ? undefined : key(stored) !== key(declared);
|
|
705
|
-
var judgeMove = (family, tried, declared, pathOf, key = exact) =>
|
|
914
|
+
var judgeMove = (family, tried, declared, pathOf, key = exact) => Effect13.gen(function* () {
|
|
706
915
|
if (tried === undefined || declared === undefined || key(tried) === key(declared)) {
|
|
707
916
|
return;
|
|
708
917
|
}
|
|
709
918
|
if ((yield* baoRead(pathOf(declared))) === undefined)
|
|
710
919
|
return { from: tried, to: declared };
|
|
711
|
-
return yield*
|
|
920
|
+
return yield* Effect13.die(new Error(`${family}: ${tried} → ${declared} would land on an object that already exists at ` + `${declared}. Under RemovalPolicy.destroy() a resource moving off that name (a swap, a ` + "shift, or a reverted move that did not finish) deletes it after this one writes it. " + "Nothing was written. Move through a name nothing holds, in two deploys, or remove " + `${declared} by hand first.`));
|
|
712
921
|
});
|
|
713
|
-
var refuseMovedUpdate = (family, from, to) =>
|
|
922
|
+
var refuseMovedUpdate = (family, from, to) => Effect13.die(new Error(`${family}: planned as an update, but its identity moved from ${from} to ${to}. Writing ` + `${to} now would leave ${from} live with no state record. Nothing was written. Run the ` + "deploy again: once the value resolves at plan time it plans as a replace."));
|
|
714
923
|
|
|
715
924
|
// src/openbao/rename-identity.ts
|
|
716
925
|
var nameIdentity = (family, pathOf, key) => ({
|
|
@@ -730,10 +939,10 @@ var foldName = (path) => path.replace(/[^/]+$/, (name) => name.toLowerCase());
|
|
|
730
939
|
var judgeRename = (identity, olds, news, output) => judgeMove(identity.family, output === undefined ? identity.declared(olds) : identity.recorded(output), identity.declared(news), identity.pathOf ?? ((path) => path), identity.key);
|
|
731
940
|
var guardRename = (identity, news, output) => {
|
|
732
941
|
if (output === undefined)
|
|
733
|
-
return
|
|
942
|
+
return Effect14.void;
|
|
734
943
|
const from = identity.recorded(output);
|
|
735
944
|
const to = identity.declared(news);
|
|
736
|
-
return to !== undefined && isMoved(from, to, identity.key) === true ? refuseMovedUpdate(identity.family, from, to) :
|
|
945
|
+
return to !== undefined && isMoved(from, to, identity.key) === true ? refuseMovedUpdate(identity.family, from, to) : Effect14.void;
|
|
737
946
|
};
|
|
738
947
|
|
|
739
948
|
// src/openbao/auth-role.ts
|
|
@@ -741,18 +950,20 @@ var BaoAuthRole = Resource2("Bao.AuthRole", {
|
|
|
741
950
|
defaultRemovalPolicy: "retain"
|
|
742
951
|
});
|
|
743
952
|
var IDENTITY = nameIdentity("Bao.AuthRole", readPath3, foldName);
|
|
744
|
-
var readRole = (props) =>
|
|
953
|
+
var readRole = (props) => Effect15.gen(function* () {
|
|
745
954
|
const live = yield* baoRead(readPath3(props.name));
|
|
746
955
|
if (live === undefined)
|
|
747
956
|
return;
|
|
748
957
|
return attributesOf3(props, live);
|
|
749
958
|
});
|
|
750
|
-
var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole,
|
|
751
|
-
list: () =>
|
|
752
|
-
read:
|
|
753
|
-
|
|
959
|
+
var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole, Effect15.succeed(BaoAuthRole.Provider.of({
|
|
960
|
+
list: () => Effect15.succeed([]),
|
|
961
|
+
read: Effect15.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
962
|
+
const found = yield* readRole(olds);
|
|
963
|
+
const ours = Effect15.sync(() => found !== undefined && matches3(found, olds));
|
|
964
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
754
965
|
}),
|
|
755
|
-
diff:
|
|
966
|
+
diff: Effect15.fn(function* ({ news, olds, output }) {
|
|
756
967
|
const move = yield* judgeRename(IDENTITY, olds, news, output);
|
|
757
968
|
if (output === undefined)
|
|
758
969
|
return;
|
|
@@ -767,25 +978,28 @@ var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole, Effect10.succeed(B
|
|
|
767
978
|
return { action: "noop" };
|
|
768
979
|
return { action: "update" };
|
|
769
980
|
}),
|
|
770
|
-
reconcile:
|
|
981
|
+
reconcile: Effect15.fn(function* ({ fqn, instanceId, news, output }) {
|
|
771
982
|
yield* guardRename(IDENTITY, news, output);
|
|
772
983
|
const live = yield* readRole(news);
|
|
984
|
+
const path = readPath3(news.name);
|
|
985
|
+
if (live !== undefined)
|
|
986
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.AuthRole ${path}`);
|
|
773
987
|
if (live === undefined || !matches3(live, news)) {
|
|
774
988
|
yield* baoWrite("PUT", readPath3(news.name), writeBody(news));
|
|
775
989
|
}
|
|
776
990
|
const after = yield* readRole(news);
|
|
777
991
|
if (after === undefined) {
|
|
778
|
-
return yield*
|
|
992
|
+
return yield* Effect15.die(new Error(`Bao.AuthRole ${news.name}: write returned no error but the role is still absent.`));
|
|
779
993
|
}
|
|
780
994
|
return after;
|
|
781
995
|
}),
|
|
782
|
-
delete:
|
|
996
|
+
delete: Effect15.fn(function* ({ output }) {
|
|
783
997
|
yield* baoDelete(readPath3(output.name));
|
|
784
998
|
return;
|
|
785
999
|
})
|
|
786
|
-
})));
|
|
1000
|
+
})).pipe(Effect15.map(provingResumes)));
|
|
787
1001
|
// src/openbao/bao-identity.ts
|
|
788
|
-
import * as
|
|
1002
|
+
import * as Effect16 from "effect/Effect";
|
|
789
1003
|
import * as FetchHttpClient3 from "effect/unstable/http/FetchHttpClient";
|
|
790
1004
|
|
|
791
1005
|
// src/openbao/bao-namespace.ts
|
|
@@ -833,42 +1047,42 @@ var checkHealth = (address, expectedCluster, body) => {
|
|
|
833
1047
|
}
|
|
834
1048
|
return { clusterId: text3(body["cluster_id"]), version: text3(body["version"]) };
|
|
835
1049
|
};
|
|
836
|
-
var assertBaoIdentityEffect = (expected) =>
|
|
1050
|
+
var assertBaoIdentityEffect = (expected) => Effect16.gen(function* () {
|
|
837
1051
|
const env = yield* BaoEnv;
|
|
838
1052
|
const address = addressOf(env);
|
|
839
1053
|
const clusterName = expected.clusterName.trim();
|
|
840
1054
|
if (clusterName === "") {
|
|
841
|
-
return yield*
|
|
1055
|
+
return yield* Effect16.fail(new BaoIdentityError("input", "clusterName is empty, so there is nothing to compare."));
|
|
842
1056
|
}
|
|
843
1057
|
const namespace = canonicalNamespace(expected.namespace);
|
|
844
1058
|
const sent = envNamespace(env);
|
|
845
1059
|
if (sent !== namespace) {
|
|
846
|
-
return yield*
|
|
1060
|
+
return yield* Effect16.fail(new BaoIdentityError("mismatch", `BAO_NAMESPACE resolves to \`${namespaceLabel(sent)}\`, but this stack expects ` + `\`${namespaceLabel(namespace)}\`.`));
|
|
847
1061
|
}
|
|
848
1062
|
const anonymous = { ...env, BAO_NAMESPACE: "", BAO_TOKEN: "" };
|
|
849
|
-
const body = yield* baoCall("read", "GET", HEALTH_PATH).pipe(
|
|
1063
|
+
const body = yield* baoCall("read", "GET", HEALTH_PATH).pipe(Effect16.provideService(BaoEnv, anonymous), Effect16.mapError(unreachable(address, "sys/health")));
|
|
850
1064
|
const health = checkHealth(address, clusterName, body);
|
|
851
1065
|
if (health instanceof BaoIdentityError)
|
|
852
|
-
return yield*
|
|
1066
|
+
return yield* Effect16.fail(health);
|
|
853
1067
|
if (namespace !== "") {
|
|
854
1068
|
const scoped = { ...env, BAO_NAMESPACE: namespace, BAO_TOKEN: "" };
|
|
855
|
-
const probe = yield* baoCall("read", "GET", NAMESPACE_PROBE_PATH).pipe(
|
|
1069
|
+
const probe = yield* baoCall("read", "GET", NAMESPACE_PROBE_PATH).pipe(Effect16.provideService(BaoEnv, scoped), Effect16.mapError(unreachable(address, `the namespace probe for \`${namespace}\``)));
|
|
856
1070
|
if (probe === undefined) {
|
|
857
|
-
return yield*
|
|
1071
|
+
return yield* Effect16.fail(new BaoIdentityError("mismatch", `cluster \`${clusterName}\` at ${address} has no namespace \`${namespace}\`.`));
|
|
858
1072
|
}
|
|
859
1073
|
}
|
|
860
1074
|
return { address, clusterName, namespace, ...health };
|
|
861
1075
|
});
|
|
862
1076
|
var assertBaoIdentity = (input) => {
|
|
863
1077
|
const effect3 = assertBaoIdentityEffect(input);
|
|
864
|
-
const scoped = input.env === undefined ? effect3 :
|
|
865
|
-
return
|
|
1078
|
+
const scoped = input.env === undefined ? effect3 : Effect16.provideService(effect3, BaoEnv, input.env);
|
|
1079
|
+
return Effect16.runPromise(scoped.pipe(Effect16.provide(FetchHttpClient3.layer)));
|
|
866
1080
|
};
|
|
867
1081
|
// src/openbao/cloudflare-role.ts
|
|
868
1082
|
import { Resource as Resource3 } from "alchemy";
|
|
869
1083
|
import { isResolved as isResolved3 } from "alchemy/Diff";
|
|
870
1084
|
import * as Provider3 from "alchemy/Provider";
|
|
871
|
-
import * as
|
|
1085
|
+
import * as Effect19 from "effect/Effect";
|
|
872
1086
|
|
|
873
1087
|
// src/openbao/cloudflare-group-scope.ts
|
|
874
1088
|
var zoneResource = (zoneId) => `com.cloudflare.api.account.zone.${zoneId}`;
|
|
@@ -888,7 +1102,7 @@ var groupKey = (name, scope) => `${scope} ${name}`;
|
|
|
888
1102
|
|
|
889
1103
|
// src/openbao/cloudflare-permission-groups.ts
|
|
890
1104
|
import * as Context2 from "effect/Context";
|
|
891
|
-
import * as
|
|
1105
|
+
import * as Effect18 from "effect/Effect";
|
|
892
1106
|
|
|
893
1107
|
// src/openbao/cloudflare-permission-groups-solve.ts
|
|
894
1108
|
var observationsOf = (declared, live) => declared.flatMap((role) => {
|
|
@@ -1058,7 +1272,7 @@ var samePolicies2 = (want, have) => want.length === have.length && want.every((w
|
|
|
1058
1272
|
});
|
|
1059
1273
|
|
|
1060
1274
|
// src/openbao/cloudflare-role-wire.ts
|
|
1061
|
-
import * as
|
|
1275
|
+
import * as Effect17 from "effect/Effect";
|
|
1062
1276
|
|
|
1063
1277
|
// src/openbao/cloudflare-role-form.ts
|
|
1064
1278
|
var rolePath = (mount, name) => `${mountPath(mount)}/roles/${name}`;
|
|
@@ -1123,7 +1337,7 @@ var differences = (props, policies, live) => {
|
|
|
1123
1337
|
};
|
|
1124
1338
|
|
|
1125
1339
|
// src/openbao/cloudflare-role-wire.ts
|
|
1126
|
-
var readCloudflareRole = (mount, name) =>
|
|
1340
|
+
var readCloudflareRole = (mount, name) => Effect17.map(baoRead(rolePath(mount, name)), (data) => data === undefined ? undefined : liveRoleOf(data));
|
|
1127
1341
|
var writeCloudflareRole = (mount, name, body) => baoWrite("PUT", rolePath(mount, name), body);
|
|
1128
1342
|
var deleteCloudflareRole = (mount, name) => baoDelete(rolePath(mount, name));
|
|
1129
1343
|
|
|
@@ -1145,9 +1359,9 @@ var pick = (mount, groups, refs, hint) => {
|
|
|
1145
1359
|
const unknown = refs.filter((ref) => !groups.has(groupKey(ref.name, ref.scope)));
|
|
1146
1360
|
if (unknown.length > 0) {
|
|
1147
1361
|
const problems = unknown.map((ref) => `unknown group ${JSON.stringify(ref.name)} at scope ${ref.scope} — ${hint}`);
|
|
1148
|
-
return
|
|
1362
|
+
return Effect18.fail(new CloudflareGroupsError(mount, problems));
|
|
1149
1363
|
}
|
|
1150
|
-
return
|
|
1364
|
+
return Effect18.succeed(new Map(refs.flatMap((ref) => {
|
|
1151
1365
|
const key = groupKey(ref.name, ref.scope);
|
|
1152
1366
|
const id = groups.get(key);
|
|
1153
1367
|
return id === undefined ? [] : [[key, id]];
|
|
@@ -1155,15 +1369,15 @@ var pick = (mount, groups, refs, hint) => {
|
|
|
1155
1369
|
};
|
|
1156
1370
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1157
1371
|
var deniedHint = (mount) => `GET ${mountPath(mount)}/permission-groups answered 403 — this token's policy carries no ` + `\`path "${mountPath(mount)}/permission-groups" { capabilities = ["read"] }\` grant. ` + "It is declared in ../platform/secrets/vault/policies/homeflare-admin/" + "20-cloudflare-permission-groups.hcl and applies with `alchemy deploy` of this stack";
|
|
1158
|
-
var deniedNamed = (mount, read) =>
|
|
1159
|
-
var engineGroups = (mount) =>
|
|
1372
|
+
var deniedNamed = (mount, read) => Effect18.catchIf(read, (error) => error.status === 403, () => Effect18.fail(new CloudflareGroupsError(mount, [deniedHint(mount)])));
|
|
1373
|
+
var engineGroups = (mount) => Effect18.flatMap(deniedNamed(mount, baoRead(`${mountPath(mount)}/permission-groups`)), (data) => {
|
|
1160
1374
|
const list = data?.["permission_groups"];
|
|
1161
1375
|
if (data === undefined) {
|
|
1162
1376
|
const why = "GET <mount>/permission-groups answered 404 — the endpoint is not deployed here";
|
|
1163
|
-
return
|
|
1377
|
+
return Effect18.fail(new CloudflareGroupsError(mount, [why]));
|
|
1164
1378
|
}
|
|
1165
1379
|
if (!Array.isArray(list)) {
|
|
1166
|
-
return
|
|
1380
|
+
return Effect18.fail(new CloudflareGroupsError(mount, ["no permission_groups array in reply"]));
|
|
1167
1381
|
}
|
|
1168
1382
|
const scoped = new Map;
|
|
1169
1383
|
const idsOf = new Map;
|
|
@@ -1190,24 +1404,24 @@ var engineGroups = (mount) => Effect13.flatMap(deniedNamed(mount, baoRead(`${mou
|
|
|
1190
1404
|
const only = [...ids];
|
|
1191
1405
|
return ids.size === 1 && only[0] !== undefined ? [[name, only[0]]] : [];
|
|
1192
1406
|
}));
|
|
1193
|
-
return problems.length > 0 ?
|
|
1407
|
+
return problems.length > 0 ? Effect18.fail(new CloudflareGroupsError(mount, problems)) : Effect18.succeed(new Map([...atEveryScope(sole), ...scoped]));
|
|
1194
1408
|
});
|
|
1195
|
-
var permissionGroupsFromEngine = () =>
|
|
1409
|
+
var permissionGroupsFromEngine = () => Effect18.sync(() => {
|
|
1196
1410
|
const cache = new Map;
|
|
1197
|
-
const cachedFor = (mount) =>
|
|
1411
|
+
const cachedFor = (mount) => Effect18.suspend(() => {
|
|
1198
1412
|
const hit = cache.get(mountPath(mount));
|
|
1199
1413
|
if (hit !== undefined)
|
|
1200
1414
|
return hit;
|
|
1201
|
-
return
|
|
1415
|
+
return Effect18.flatMap(Effect18.cached(engineGroups(mount)), (lookup) => {
|
|
1202
1416
|
cache.set(mountPath(mount), lookup);
|
|
1203
1417
|
return lookup;
|
|
1204
1418
|
});
|
|
1205
1419
|
});
|
|
1206
1420
|
return CloudflarePermissionGroups.of({
|
|
1207
|
-
resolve: (mount, refs) =>
|
|
1421
|
+
resolve: (mount, refs) => Effect18.flatMap(cachedFor(mount), (groups) => pick(mount, groups, refs, "the engine does not list it for this account at that scope"))
|
|
1208
1422
|
});
|
|
1209
1423
|
});
|
|
1210
|
-
var permissionGroupsFromLiveRoles = (declared) =>
|
|
1424
|
+
var permissionGroupsFromLiveRoles = (declared) => Effect18.gen(function* () {
|
|
1211
1425
|
const accountOf = new Map;
|
|
1212
1426
|
const byAccount = new Map;
|
|
1213
1427
|
for (const [mount, roles] of declared) {
|
|
@@ -1218,9 +1432,9 @@ var permissionGroupsFromLiveRoles = (declared) => Effect13.gen(function* () {
|
|
|
1218
1432
|
}
|
|
1219
1433
|
const solved = new Map;
|
|
1220
1434
|
for (const [account, roles] of byAccount) {
|
|
1221
|
-
const solve =
|
|
1435
|
+
const solve = Effect18.gen(function* () {
|
|
1222
1436
|
const live = new Map;
|
|
1223
|
-
yield*
|
|
1437
|
+
yield* Effect18.all(roles.map((role) => Effect18.map(readCloudflareRole(role.mount, role.name), (read) => {
|
|
1224
1438
|
if (read?.policies !== undefined) {
|
|
1225
1439
|
live.set(`${role.mount}/${role.name}`, read.policies);
|
|
1226
1440
|
}
|
|
@@ -1228,11 +1442,11 @@ var permissionGroupsFromLiveRoles = (declared) => Effect13.gen(function* () {
|
|
|
1228
1442
|
const result = solveGroups(observationsOf(roles, live));
|
|
1229
1443
|
const problems = describeProblems(result);
|
|
1230
1444
|
if (problems.length > 0) {
|
|
1231
|
-
return yield*
|
|
1445
|
+
return yield* Effect18.fail(new CloudflareGroupsError(`account ${account}`, problems));
|
|
1232
1446
|
}
|
|
1233
1447
|
return atEveryScope(result.groups);
|
|
1234
1448
|
});
|
|
1235
|
-
solved.set(account, yield*
|
|
1449
|
+
solved.set(account, yield* Effect18.cached(solve));
|
|
1236
1450
|
}
|
|
1237
1451
|
return CloudflarePermissionGroups.of({
|
|
1238
1452
|
resolve: (mount, refs) => {
|
|
@@ -1240,10 +1454,10 @@ var permissionGroupsFromLiveRoles = (declared) => Effect13.gen(function* () {
|
|
|
1240
1454
|
const lookup = account === undefined ? undefined : solved.get(account);
|
|
1241
1455
|
if (account === undefined || lookup === undefined) {
|
|
1242
1456
|
const why = "no declared role on this mount, so no live role can vouch for its groups";
|
|
1243
|
-
return
|
|
1457
|
+
return Effect18.fail(new CloudflareGroupsError(mount, [why]));
|
|
1244
1458
|
}
|
|
1245
1459
|
const hint = `no live role on account ${account} carries it; a NEW group needs the engine endpoint`;
|
|
1246
|
-
return
|
|
1460
|
+
return Effect18.flatMap(lookup, (groups) => pick(mount, groups, refs, hint));
|
|
1247
1461
|
}
|
|
1248
1462
|
});
|
|
1249
1463
|
});
|
|
@@ -1253,9 +1467,9 @@ var BaoCloudflareRole = Resource3("Bao.CloudflareRole", {
|
|
|
1253
1467
|
defaultRemovalPolicy: "retain"
|
|
1254
1468
|
});
|
|
1255
1469
|
var IDENTITY2 = roleIdentity("Bao.CloudflareRole", rolePath);
|
|
1256
|
-
var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole,
|
|
1470
|
+
var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect19.gen(function* () {
|
|
1257
1471
|
const groups = yield* CloudflarePermissionGroups;
|
|
1258
|
-
const resolved = (props) =>
|
|
1472
|
+
const resolved = (props) => Effect19.gen(function* () {
|
|
1259
1473
|
const refs = new Map;
|
|
1260
1474
|
for (const policy of props.policies) {
|
|
1261
1475
|
const scope = policy.scope ?? scopeOfResource(policy.resource);
|
|
@@ -1265,17 +1479,23 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1265
1479
|
const ids = yield* groups.resolve(props.mount, [...refs.values()]);
|
|
1266
1480
|
const { missing, policies } = resolvePolicies(props.policies, ids);
|
|
1267
1481
|
if (missing.length > 0) {
|
|
1268
|
-
return yield*
|
|
1482
|
+
return yield* Effect19.die(new Error(`Bao.CloudflareRole ${rolePath(props.mount, props.name)}: groups ` + `${missing.join(", ")} came back unresolved from a lookup that reported success.`));
|
|
1269
1483
|
}
|
|
1270
1484
|
return policies;
|
|
1271
1485
|
});
|
|
1272
1486
|
return BaoCloudflareRole.Provider.of({
|
|
1273
|
-
list: () =>
|
|
1274
|
-
read:
|
|
1487
|
+
list: () => Effect19.succeed([]),
|
|
1488
|
+
read: Effect19.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
1275
1489
|
const live = yield* readCloudflareRole(olds.mount, olds.name);
|
|
1276
|
-
|
|
1490
|
+
const found = live === undefined ? undefined : attributesOf4(olds, live);
|
|
1491
|
+
const ours = Effect19.gen(function* () {
|
|
1492
|
+
if (live === undefined || refusalOf(olds) !== undefined)
|
|
1493
|
+
return false;
|
|
1494
|
+
return differences(olds, yield* resolved(olds), live).length === 0;
|
|
1495
|
+
});
|
|
1496
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
1277
1497
|
}),
|
|
1278
|
-
diff:
|
|
1498
|
+
diff: Effect19.fn(function* ({ news, olds, output }) {
|
|
1279
1499
|
const move = yield* judgeRename(IDENTITY2, olds, news, output);
|
|
1280
1500
|
if (output === undefined)
|
|
1281
1501
|
return;
|
|
@@ -1291,34 +1511,37 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1291
1511
|
return { action: "update" };
|
|
1292
1512
|
return differences(news, policies, live).length === 0 ? { action: "noop" } : { action: "update" };
|
|
1293
1513
|
}),
|
|
1294
|
-
reconcile:
|
|
1514
|
+
reconcile: Effect19.fn(function* ({ fqn, instanceId, news, output }) {
|
|
1295
1515
|
const path = rolePath(news.mount, news.name);
|
|
1296
1516
|
yield* guardRename(IDENTITY2, news, output);
|
|
1297
1517
|
const refusal2 = refusalOf(news);
|
|
1298
1518
|
if (refusal2 !== undefined) {
|
|
1299
|
-
return yield*
|
|
1519
|
+
return yield* Effect19.die(new Error(`Bao.CloudflareRole ${path}: ${refusal2}.`));
|
|
1300
1520
|
}
|
|
1301
1521
|
const policies = yield* resolved(news);
|
|
1302
1522
|
const live = yield* readCloudflareRole(news.mount, news.name);
|
|
1523
|
+
if (live !== undefined) {
|
|
1524
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.CloudflareRole ${path}`);
|
|
1525
|
+
}
|
|
1303
1526
|
if (live === undefined || differences(news, policies, live).length > 0) {
|
|
1304
1527
|
yield* writeCloudflareRole(news.mount, news.name, writeBody2(news, policies));
|
|
1305
1528
|
}
|
|
1306
1529
|
const after = yield* readCloudflareRole(news.mount, news.name);
|
|
1307
1530
|
if (after === undefined) {
|
|
1308
|
-
return yield*
|
|
1531
|
+
return yield* Effect19.die(new Error(`Bao.CloudflareRole ${path}: the write succeeded but the role is absent.`));
|
|
1309
1532
|
}
|
|
1310
1533
|
const left = differences(news, policies, after);
|
|
1311
1534
|
if (left.length > 0) {
|
|
1312
|
-
return yield*
|
|
1535
|
+
return yield* Effect19.die(new Error(`Bao.CloudflareRole ${path}: wrote cleanly but reads back different in ` + `${left.map((d) => d.field).join(", ")}. Inspect the role before retrying.`));
|
|
1313
1536
|
}
|
|
1314
1537
|
return attributesOf4(news, after);
|
|
1315
1538
|
}),
|
|
1316
|
-
delete:
|
|
1539
|
+
delete: Effect19.fn(function* ({ output }) {
|
|
1317
1540
|
yield* deleteCloudflareRole(output.mount, output.name);
|
|
1318
1541
|
return;
|
|
1319
1542
|
})
|
|
1320
1543
|
});
|
|
1321
|
-
}));
|
|
1544
|
+
}).pipe(Effect19.map(provingResumes)));
|
|
1322
1545
|
// src/openbao/cloudflare-roles-expand.ts
|
|
1323
1546
|
var slug = (name) => trimRuns(name.toLowerCase().replace(/[^a-z0-9]+/g, "-"), "-");
|
|
1324
1547
|
var zoneSlug = (zone) => `${slug(zone.name)}${zone.internal ? "-internal" : ""}`;
|
|
@@ -1565,7 +1788,7 @@ var hostAppRoles = (input) => {
|
|
|
1565
1788
|
import { Resource as Resource4 } from "alchemy";
|
|
1566
1789
|
import { isResolved as isResolved4 } from "alchemy/Diff";
|
|
1567
1790
|
import * as Provider4 from "alchemy/Provider";
|
|
1568
|
-
import * as
|
|
1791
|
+
import * as Effect21 from "effect/Effect";
|
|
1569
1792
|
|
|
1570
1793
|
// src/openbao/jwt-config-form.ts
|
|
1571
1794
|
var text5 = (value) => typeof value === "string" ? value.trim() : "";
|
|
@@ -1655,19 +1878,25 @@ var problems = (props) => {
|
|
|
1655
1878
|
};
|
|
1656
1879
|
|
|
1657
1880
|
// src/openbao/role-reconcile.ts
|
|
1658
|
-
import * as
|
|
1659
|
-
var readRoleAt = (spec) =>
|
|
1660
|
-
var
|
|
1881
|
+
import * as Effect20 from "effect/Effect";
|
|
1882
|
+
var readRoleAt = (spec) => Effect20.map(baoRead(spec.path), (live) => live === undefined ? undefined : { attributes: spec.attributesOf(live), live });
|
|
1883
|
+
var readOwnedRole = (ask, spec) => Effect20.flatMap(readRoleAt(spec), (found) => {
|
|
1884
|
+
const ours = Effect20.sync(() => found !== undefined && spec.problems.length === 0 && spec.matches(found.attributes));
|
|
1885
|
+
return ownedRead(ask, found?.attributes, ours);
|
|
1886
|
+
});
|
|
1887
|
+
var planRole = (spec) => Effect20.gen(function* () {
|
|
1661
1888
|
if (spec.problems.length > 0)
|
|
1662
1889
|
return "update";
|
|
1663
1890
|
const found = yield* readRoleAt(spec);
|
|
1664
1891
|
return found !== undefined && spec.matches(found.attributes) ? "noop" : "update";
|
|
1665
1892
|
});
|
|
1666
|
-
var refuse2 = (spec, message) =>
|
|
1667
|
-
var reconcileRole = (spec) =>
|
|
1893
|
+
var refuse2 = (spec, message) => Effect20.die(new Error(`${spec.family} ${spec.path}: ${message}`));
|
|
1894
|
+
var reconcileRole = (spec, claim) => Effect20.gen(function* () {
|
|
1668
1895
|
if (spec.problems.length > 0)
|
|
1669
1896
|
return yield* refuse2(spec, spec.problems.join("; "));
|
|
1670
1897
|
const found = yield* readRoleAt(spec);
|
|
1898
|
+
if (found !== undefined && claim !== undefined)
|
|
1899
|
+
yield* claim(`${spec.family} ${spec.path}`);
|
|
1671
1900
|
if (found === undefined || !spec.matches(found.attributes)) {
|
|
1672
1901
|
const lost = found === undefined ? [] : spec.wouldErase?.(found.live) ?? [];
|
|
1673
1902
|
if (lost.length > 0) {
|
|
@@ -1705,13 +1934,12 @@ var jwtConfigSpec = (props) => ({
|
|
|
1705
1934
|
problems: problems(props),
|
|
1706
1935
|
wouldErase
|
|
1707
1936
|
});
|
|
1708
|
-
var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig,
|
|
1709
|
-
list: () =>
|
|
1710
|
-
read:
|
|
1711
|
-
|
|
1712
|
-
return found?.attributes;
|
|
1937
|
+
var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig, Effect21.succeed(BaoJwtAuthConfig.Provider.of({
|
|
1938
|
+
list: () => Effect21.succeed([]),
|
|
1939
|
+
read: Effect21.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
1940
|
+
return yield* readOwnedRole({ fqn, instanceId, output }, jwtConfigSpec(olds));
|
|
1713
1941
|
}),
|
|
1714
|
-
diff:
|
|
1942
|
+
diff: Effect21.fn(function* ({ news, olds, output }) {
|
|
1715
1943
|
const move = yield* judgeRename(IDENTITY3, olds, news, output);
|
|
1716
1944
|
if (output === undefined)
|
|
1717
1945
|
return;
|
|
@@ -1721,17 +1949,17 @@ var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig, Effect16
|
|
|
1721
1949
|
return;
|
|
1722
1950
|
return { action: yield* planRole(jwtConfigSpec(news)) };
|
|
1723
1951
|
}),
|
|
1724
|
-
reconcile:
|
|
1952
|
+
reconcile: Effect21.fn(function* ({ fqn, instanceId, news, output }) {
|
|
1725
1953
|
yield* guardRename(IDENTITY3, news, output);
|
|
1726
|
-
return yield* reconcileRole(jwtConfigSpec(news));
|
|
1954
|
+
return yield* reconcileRole(jwtConfigSpec(news), claimFor({ fqn, instanceId, output }));
|
|
1727
1955
|
}),
|
|
1728
|
-
delete: () =>
|
|
1729
|
-
})));
|
|
1956
|
+
delete: () => Effect21.void
|
|
1957
|
+
})).pipe(Effect21.map(provingResumes)));
|
|
1730
1958
|
// src/openbao/jwt-role.ts
|
|
1731
1959
|
import { Resource as Resource5 } from "alchemy";
|
|
1732
1960
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1733
1961
|
import * as Provider5 from "alchemy/Provider";
|
|
1734
|
-
import * as
|
|
1962
|
+
import * as Effect22 from "effect/Effect";
|
|
1735
1963
|
|
|
1736
1964
|
// src/openbao/auth-token-form.ts
|
|
1737
1965
|
var sortedSet2 = (values) => [...new Set(values)].sort();
|
|
@@ -1942,13 +2170,12 @@ var jwtRoleSpec = (props) => ({
|
|
|
1942
2170
|
path: rolePath2(props),
|
|
1943
2171
|
problems: problems2(props)
|
|
1944
2172
|
});
|
|
1945
|
-
var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole,
|
|
1946
|
-
list: () =>
|
|
1947
|
-
read:
|
|
1948
|
-
|
|
1949
|
-
return found?.attributes;
|
|
2173
|
+
var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole, Effect22.succeed(BaoJwtRole.Provider.of({
|
|
2174
|
+
list: () => Effect22.succeed([]),
|
|
2175
|
+
read: Effect22.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2176
|
+
return yield* readOwnedRole({ fqn, instanceId, output }, jwtRoleSpec(olds));
|
|
1950
2177
|
}),
|
|
1951
|
-
diff:
|
|
2178
|
+
diff: Effect22.fn(function* ({ news, olds, output }) {
|
|
1952
2179
|
const move = yield* judgeRename(IDENTITY4, olds, news, output);
|
|
1953
2180
|
if (output === undefined)
|
|
1954
2181
|
return;
|
|
@@ -1958,20 +2185,20 @@ var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole, Effect17.succeed(Bao
|
|
|
1958
2185
|
return;
|
|
1959
2186
|
return { action: yield* planRole(jwtRoleSpec(news)) };
|
|
1960
2187
|
}),
|
|
1961
|
-
reconcile:
|
|
2188
|
+
reconcile: Effect22.fn(function* ({ fqn, instanceId, news, output }) {
|
|
1962
2189
|
yield* guardRename(IDENTITY4, news, output);
|
|
1963
|
-
return yield* reconcileRole(jwtRoleSpec(news));
|
|
2190
|
+
return yield* reconcileRole(jwtRoleSpec(news), claimFor({ fqn, instanceId, output }));
|
|
1964
2191
|
}),
|
|
1965
|
-
delete:
|
|
2192
|
+
delete: Effect22.fn(function* ({ output }) {
|
|
1966
2193
|
yield* baoDelete(rolePath2(output));
|
|
1967
2194
|
return;
|
|
1968
2195
|
})
|
|
1969
|
-
})));
|
|
2196
|
+
})).pipe(Effect22.map(provingResumes)));
|
|
1970
2197
|
// src/openbao/kubernetes-role.ts
|
|
1971
2198
|
import { Resource as Resource6 } from "alchemy";
|
|
1972
2199
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1973
2200
|
import * as Provider6 from "alchemy/Provider";
|
|
1974
|
-
import * as
|
|
2201
|
+
import * as Effect23 from "effect/Effect";
|
|
1975
2202
|
|
|
1976
2203
|
// src/openbao/kubernetes-role-form.ts
|
|
1977
2204
|
var sortedSet4 = (values) => [...new Set(values)].sort();
|
|
@@ -2049,13 +2276,12 @@ var kubernetesRoleSpec = (props) => ({
|
|
|
2049
2276
|
path: rolePath3(props),
|
|
2050
2277
|
problems: problems3(props)
|
|
2051
2278
|
});
|
|
2052
|
-
var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole,
|
|
2053
|
-
list: () =>
|
|
2054
|
-
read:
|
|
2055
|
-
|
|
2056
|
-
return found?.attributes;
|
|
2279
|
+
var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole, Effect23.succeed(BaoKubernetesRole.Provider.of({
|
|
2280
|
+
list: () => Effect23.succeed([]),
|
|
2281
|
+
read: Effect23.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2282
|
+
return yield* readOwnedRole({ fqn, instanceId, output }, kubernetesRoleSpec(olds));
|
|
2057
2283
|
}),
|
|
2058
|
-
diff:
|
|
2284
|
+
diff: Effect23.fn(function* ({ news, olds, output }) {
|
|
2059
2285
|
const move = yield* judgeRename(IDENTITY5, olds, news, output);
|
|
2060
2286
|
if (output === undefined)
|
|
2061
2287
|
return;
|
|
@@ -2065,20 +2291,20 @@ var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole, Effect
|
|
|
2065
2291
|
return;
|
|
2066
2292
|
return { action: yield* planRole(kubernetesRoleSpec(news)) };
|
|
2067
2293
|
}),
|
|
2068
|
-
reconcile:
|
|
2294
|
+
reconcile: Effect23.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2069
2295
|
yield* guardRename(IDENTITY5, news, output);
|
|
2070
|
-
return yield* reconcileRole(kubernetesRoleSpec(news));
|
|
2296
|
+
return yield* reconcileRole(kubernetesRoleSpec(news), claimFor({ fqn, instanceId, output }));
|
|
2071
2297
|
}),
|
|
2072
|
-
delete:
|
|
2298
|
+
delete: Effect23.fn(function* ({ output }) {
|
|
2073
2299
|
yield* baoDelete(rolePath3(output));
|
|
2074
2300
|
return;
|
|
2075
2301
|
})
|
|
2076
|
-
})));
|
|
2302
|
+
})).pipe(Effect23.map(provingResumes)));
|
|
2077
2303
|
// src/openbao/mfa-enforcement.ts
|
|
2078
2304
|
import { Resource as Resource7 } from "alchemy";
|
|
2079
2305
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2080
2306
|
import * as Provider7 from "alchemy/Provider";
|
|
2081
|
-
import * as
|
|
2307
|
+
import * as Effect25 from "effect/Effect";
|
|
2082
2308
|
|
|
2083
2309
|
// src/openbao/mfa-enforcement-form.ts
|
|
2084
2310
|
var sortedSet5 = (values) => [...new Set(values.map((value) => value.trim()))].filter((value) => value !== "").sort();
|
|
@@ -2146,16 +2372,16 @@ var problems4 = (props, missingPaths) => {
|
|
|
2146
2372
|
};
|
|
2147
2373
|
|
|
2148
2374
|
// src/openbao/mfa-wire.ts
|
|
2149
|
-
import * as
|
|
2375
|
+
import * as Effect24 from "effect/Effect";
|
|
2150
2376
|
var TOTP_PATH = "identity/mfa/method/totp";
|
|
2151
2377
|
var METHODS_PATH = "identity/mfa/method";
|
|
2152
2378
|
var enforcementPath = (name) => `identity/mfa/login-enforcement/${name}`;
|
|
2153
2379
|
var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
2154
|
-
var ownNamespacePath =
|
|
2380
|
+
var ownNamespacePath = Effect24.gen(function* () {
|
|
2155
2381
|
const env = yield* BaoEnv;
|
|
2156
2382
|
return namespacePath(envNamespace(env));
|
|
2157
2383
|
});
|
|
2158
|
-
var findTotp = (name) =>
|
|
2384
|
+
var findTotp = (name) => Effect24.gen(function* () {
|
|
2159
2385
|
const listing = yield* baoRead(`${METHODS_PATH}?list=true`);
|
|
2160
2386
|
const info = record4(listing?.["key_info"]) ?? {};
|
|
2161
2387
|
const own = yield* ownNamespacePath;
|
|
@@ -2164,17 +2390,17 @@ var findTotp = (name) => Effect19.gen(function* () {
|
|
|
2164
2390
|
if (live === undefined || live["name"] !== name || live["namespace_path"] !== own)
|
|
2165
2391
|
continue;
|
|
2166
2392
|
if (live["type"] !== "totp") {
|
|
2167
|
-
return yield*
|
|
2393
|
+
return yield* Effect24.die(new Error(`Bao.MfaTotpMethod ${name}: that name belongs to a ${String(live["type"])} method ` + `(${id}) in this namespace, and a TOTP write would convert it. Pick another name.`));
|
|
2168
2394
|
}
|
|
2169
2395
|
return { id, live };
|
|
2170
2396
|
}
|
|
2171
2397
|
return;
|
|
2172
2398
|
});
|
|
2173
|
-
var writeTotp = (body) =>
|
|
2399
|
+
var writeTotp = (body) => Effect24.asVoid(baoCall("write", "POST", TOTP_PATH, body));
|
|
2174
2400
|
var deleteTotp = (id) => baoDelete(`${TOTP_PATH}/${id}`);
|
|
2175
2401
|
var readEnforcement = (name) => baoRead(enforcementPath(name));
|
|
2176
|
-
var writeEnforcement = (name, body) =>
|
|
2177
|
-
var authAccessors = (paths) =>
|
|
2402
|
+
var writeEnforcement = (name, body) => Effect24.asVoid(baoCall("write", "POST", enforcementPath(name), body));
|
|
2403
|
+
var authAccessors = (paths) => Effect24.gen(function* () {
|
|
2178
2404
|
if (paths.length === 0)
|
|
2179
2405
|
return { accessors: [], missing: [] };
|
|
2180
2406
|
const table = (yield* baoRead("sys/auth")) ?? {};
|
|
@@ -2195,24 +2421,27 @@ var BaoMfaLoginEnforcement = Resource7("Bao.MfaLoginEnforcement", {
|
|
|
2195
2421
|
defaultRemovalPolicy: "retain"
|
|
2196
2422
|
});
|
|
2197
2423
|
var IDENTITY6 = nameIdentity("Bao.MfaLoginEnforcement", enforcementPath);
|
|
2198
|
-
var refuse3 = (name, message) =>
|
|
2199
|
-
var resolveTargets = (props) =>
|
|
2424
|
+
var refuse3 = (name, message) => Effect25.die(new Error(`Bao.MfaLoginEnforcement ${name}: ${message}`));
|
|
2425
|
+
var resolveTargets = (props) => Effect25.map(authAccessors(props.authMethodPaths ?? []), ({ accessors, missing }) => ({
|
|
2200
2426
|
bad: problems4(props, missing),
|
|
2201
2427
|
resolved: accessors
|
|
2202
2428
|
}));
|
|
2203
|
-
var readLive = (name) =>
|
|
2204
|
-
var planEnforcement = (props) =>
|
|
2429
|
+
var readLive = (name) => Effect25.map(readEnforcement(name), (live) => live === undefined ? undefined : attributesOf8(name, live));
|
|
2430
|
+
var planEnforcement = (props) => Effect25.gen(function* () {
|
|
2205
2431
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2206
2432
|
if (bad.length > 0)
|
|
2207
2433
|
return "update";
|
|
2208
2434
|
const live = yield* readLive(props.name);
|
|
2209
2435
|
return live !== undefined && matches7(live, props, resolved) ? "noop" : "update";
|
|
2210
2436
|
});
|
|
2211
|
-
var reconcileEnforcement = (props) =>
|
|
2437
|
+
var reconcileEnforcement = (props, claim) => Effect25.gen(function* () {
|
|
2212
2438
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2213
2439
|
if (bad.length > 0)
|
|
2214
2440
|
return yield* refuse3(props.name, bad.join("; "));
|
|
2215
2441
|
const live = yield* readLive(props.name);
|
|
2442
|
+
if (live !== undefined && claim !== undefined) {
|
|
2443
|
+
yield* claim(`Bao.MfaLoginEnforcement ${props.name}`);
|
|
2444
|
+
}
|
|
2216
2445
|
if (live === undefined || !matches7(live, props, resolved)) {
|
|
2217
2446
|
yield* writeEnforcement(props.name, writeBody6(canonicalFromProps4(props, resolved)));
|
|
2218
2447
|
}
|
|
@@ -2224,12 +2453,14 @@ var reconcileEnforcement = (props) => Effect20.gen(function* () {
|
|
|
2224
2453
|
}
|
|
2225
2454
|
return after;
|
|
2226
2455
|
});
|
|
2227
|
-
var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforcement,
|
|
2228
|
-
list: () =>
|
|
2229
|
-
read:
|
|
2230
|
-
|
|
2456
|
+
var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforcement, Effect25.succeed(BaoMfaLoginEnforcement.Provider.of({
|
|
2457
|
+
list: () => Effect25.succeed([]),
|
|
2458
|
+
read: Effect25.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2459
|
+
const found = yield* readLive(olds.name);
|
|
2460
|
+
const ours = Effect25.map(planEnforcement(olds), (plan) => plan === "noop");
|
|
2461
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2231
2462
|
}),
|
|
2232
|
-
diff:
|
|
2463
|
+
diff: Effect25.fn(function* ({ news, olds, output }) {
|
|
2233
2464
|
const move = yield* judgeRename(IDENTITY6, olds, news, output);
|
|
2234
2465
|
if (output === undefined)
|
|
2235
2466
|
return;
|
|
@@ -2239,19 +2470,19 @@ var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforceme
|
|
|
2239
2470
|
return;
|
|
2240
2471
|
return { action: yield* planEnforcement(news) };
|
|
2241
2472
|
}),
|
|
2242
|
-
reconcile:
|
|
2473
|
+
reconcile: Effect25.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2243
2474
|
yield* guardRename(IDENTITY6, news, output);
|
|
2244
|
-
return yield* reconcileEnforcement(news);
|
|
2475
|
+
return yield* reconcileEnforcement(news, claimFor({ fqn, instanceId, output }));
|
|
2245
2476
|
}),
|
|
2246
|
-
delete:
|
|
2477
|
+
delete: Effect25.fn(function* ({ output }) {
|
|
2247
2478
|
return yield* refuse3(output.name, "REFUSING to delete: OpenBao 2.6.2 drops a login enforcement from memory only, and it " + "returns on the next unseal (openbao/openbao#4030). Set this resource back to " + "retain to drop it from state; remove it for good only once the server is fixed.");
|
|
2248
2479
|
})
|
|
2249
|
-
})));
|
|
2480
|
+
})).pipe(Effect25.map(provingResumes)));
|
|
2250
2481
|
// src/openbao/mfa-totp.ts
|
|
2251
2482
|
import { Resource as Resource8 } from "alchemy";
|
|
2252
2483
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2253
2484
|
import * as Provider8 from "alchemy/Provider";
|
|
2254
|
-
import * as
|
|
2485
|
+
import * as Effect26 from "effect/Effect";
|
|
2255
2486
|
|
|
2256
2487
|
// src/openbao/mfa-totp-form.ts
|
|
2257
2488
|
var canonical6 = (input) => ({
|
|
@@ -2332,19 +2563,21 @@ var problems5 = (props) => {
|
|
|
2332
2563
|
var BaoMfaTotpMethod = Resource8("Bao.MfaTotpMethod", {
|
|
2333
2564
|
defaultRemovalPolicy: "retain"
|
|
2334
2565
|
});
|
|
2335
|
-
var refuse4 = (name, message) =>
|
|
2336
|
-
var readTotp = (props) =>
|
|
2337
|
-
var planTotp = (props) =>
|
|
2566
|
+
var refuse4 = (name, message) => Effect26.die(new Error(`Bao.MfaTotpMethod ${name}: ${message}`));
|
|
2567
|
+
var readTotp = (props) => Effect26.map(findTotp(props.name), (found) => found === undefined ? undefined : attributesOf9(found.id, found.live));
|
|
2568
|
+
var planTotp = (props) => Effect26.gen(function* () {
|
|
2338
2569
|
if (problems5(props).length > 0)
|
|
2339
2570
|
return "update";
|
|
2340
2571
|
const live = yield* readTotp(props);
|
|
2341
2572
|
return live !== undefined && matches8(live, props) ? "noop" : "update";
|
|
2342
2573
|
});
|
|
2343
|
-
var reconcileTotp = (props) =>
|
|
2574
|
+
var reconcileTotp = (props, claim) => Effect26.gen(function* () {
|
|
2344
2575
|
const bad = problems5(props);
|
|
2345
2576
|
if (bad.length > 0)
|
|
2346
2577
|
return yield* refuse4(props.name, bad.join("; "));
|
|
2347
2578
|
const live = yield* readTotp(props);
|
|
2579
|
+
if (live !== undefined && claim !== undefined)
|
|
2580
|
+
yield* claim(`Bao.MfaTotpMethod ${props.name}`);
|
|
2348
2581
|
if (live === undefined || !matches8(live, props))
|
|
2349
2582
|
yield* writeTotp(writeBody7(props));
|
|
2350
2583
|
const after = yield* readTotp(props);
|
|
@@ -2354,55 +2587,59 @@ var reconcileTotp = (props) => Effect21.gen(function* () {
|
|
|
2354
2587
|
return yield* refuse4(props.name, "the method read back different.");
|
|
2355
2588
|
return after;
|
|
2356
2589
|
});
|
|
2357
|
-
var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod,
|
|
2358
|
-
list: () =>
|
|
2359
|
-
read:
|
|
2360
|
-
|
|
2590
|
+
var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod, Effect26.succeed(BaoMfaTotpMethod.Provider.of({
|
|
2591
|
+
list: () => Effect26.succeed([]),
|
|
2592
|
+
read: Effect26.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2593
|
+
const found = yield* readTotp(olds);
|
|
2594
|
+
const ours = Effect26.sync(() => found !== undefined && problems5(olds).length === 0 && matches8(found, olds));
|
|
2595
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2361
2596
|
}),
|
|
2362
|
-
diff:
|
|
2597
|
+
diff: Effect26.fn(function* ({ news, output }) {
|
|
2363
2598
|
const name = declaredString(news, "name");
|
|
2364
2599
|
if (output !== undefined && name !== undefined) {
|
|
2365
2600
|
const rename = renameProblem(output.name, name);
|
|
2366
2601
|
if (rename !== undefined)
|
|
2367
2602
|
return yield* refuse4(name, rename);
|
|
2368
2603
|
}
|
|
2369
|
-
if (output === undefined
|
|
2604
|
+
if (output === undefined)
|
|
2605
|
+
return;
|
|
2606
|
+
if (!isResolved8(news))
|
|
2370
2607
|
return;
|
|
2371
2608
|
return { action: yield* planTotp(news) };
|
|
2372
2609
|
}),
|
|
2373
|
-
reconcile:
|
|
2610
|
+
reconcile: Effect26.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2374
2611
|
const rename = output === undefined ? undefined : renameProblem(output.name, news.name);
|
|
2375
2612
|
if (rename !== undefined)
|
|
2376
2613
|
return yield* refuse4(news.name, rename);
|
|
2377
|
-
return yield* reconcileTotp(news);
|
|
2614
|
+
return yield* reconcileTotp(news, claimFor({ fqn, instanceId, output }));
|
|
2378
2615
|
}),
|
|
2379
|
-
delete:
|
|
2616
|
+
delete: Effect26.fn(function* ({ output }) {
|
|
2380
2617
|
yield* deleteTotp(output.methodId);
|
|
2381
2618
|
return;
|
|
2382
2619
|
})
|
|
2383
|
-
})));
|
|
2620
|
+
})).pipe(Effect26.map(provingResumes)));
|
|
2384
2621
|
// src/openbao/mount.ts
|
|
2385
2622
|
import { Resource as Resource9 } from "alchemy";
|
|
2386
2623
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2387
2624
|
import * as Provider9 from "alchemy/Provider";
|
|
2388
|
-
import * as
|
|
2625
|
+
import * as Effect29 from "effect/Effect";
|
|
2389
2626
|
|
|
2390
2627
|
// src/openbao/mount-reconcile.ts
|
|
2391
|
-
import * as
|
|
2628
|
+
import * as Effect28 from "effect/Effect";
|
|
2392
2629
|
|
|
2393
2630
|
// src/openbao/mount-wire.ts
|
|
2394
|
-
import * as
|
|
2395
|
-
var absentFromTable2 = (path, asked) => baoRead("sys/mounts").pipe(
|
|
2631
|
+
import * as Effect27 from "effect/Effect";
|
|
2632
|
+
var absentFromTable2 = (path, asked) => baoRead("sys/mounts").pipe(Effect27.mapError((listing) => new BaoError(asked.status, asked.method, asked.path, [
|
|
2396
2633
|
...asked.errors,
|
|
2397
2634
|
`sys/mounts could not confirm the mount is absent: ${listing.message}`
|
|
2398
|
-
])),
|
|
2399
|
-
var readMountData = (path) => baoRead(readPath(path)).pipe(
|
|
2635
|
+
])), Effect27.flatMap((table) => table !== undefined && !Object.hasOwn(table, `${mountPath(path)}/`) ? Effect27.succeed(undefined) : Effect27.fail(asked)));
|
|
2636
|
+
var readMountData = (path) => baoRead(readPath(path)).pipe(Effect27.catchIf((error) => error.status === 400, (error) => absentFromTable2(path, error)));
|
|
2400
2637
|
var enableMount = (props) => baoWrite("POST", readPath(props.path), enableBody(props));
|
|
2401
2638
|
var tuneMount = (props) => baoWrite("POST", tunePath(props.path), tuneBody(props));
|
|
2402
2639
|
var disableMount = (path) => baoDelete(readPath(path));
|
|
2403
2640
|
|
|
2404
2641
|
// src/openbao/mount-reconcile.ts
|
|
2405
|
-
var readMount = (props) =>
|
|
2642
|
+
var readMount = (props) => Effect28.gen(function* () {
|
|
2406
2643
|
const live = yield* readMountData(props.path);
|
|
2407
2644
|
if (live === undefined)
|
|
2408
2645
|
return;
|
|
@@ -2415,10 +2652,16 @@ var moveTarget2 = (props) => ({
|
|
|
2415
2652
|
type: props.type,
|
|
2416
2653
|
wire: mountPath
|
|
2417
2654
|
});
|
|
2418
|
-
var reconcileMount = (news, stated, options) =>
|
|
2655
|
+
var reconcileMount = (news, stated, options, claim) => Effect28.gen(function* () {
|
|
2419
2656
|
const move = planMove("Bao.Mount", stated, news.path, news.remountFrom);
|
|
2420
2657
|
if (move.kind === "refuse")
|
|
2421
|
-
return yield*
|
|
2658
|
+
return yield* Effect28.die(new Error(move.message));
|
|
2659
|
+
const first = stated === undefined ? claim : undefined;
|
|
2660
|
+
if (first !== undefined && move.kind === "move") {
|
|
2661
|
+
const source = yield* readMount({ ...news, path: move.from });
|
|
2662
|
+
if (source !== undefined)
|
|
2663
|
+
yield* first(`Bao.Mount ${move.from} (the remountFrom source)`);
|
|
2664
|
+
}
|
|
2422
2665
|
if (move.kind === "move")
|
|
2423
2666
|
yield* performMove(moveTarget2(news), move.from, options);
|
|
2424
2667
|
let live = yield* readMount(news);
|
|
@@ -2426,15 +2669,18 @@ var reconcileMount = (news, stated, options) => Effect23.gen(function* () {
|
|
|
2426
2669
|
yield* enableMount(news);
|
|
2427
2670
|
if (wantsTune(news))
|
|
2428
2671
|
yield* tuneMount(news);
|
|
2429
|
-
} else
|
|
2672
|
+
} else {
|
|
2430
2673
|
if (live.type !== news.type) {
|
|
2431
|
-
return yield*
|
|
2674
|
+
return yield* Effect28.die(new Error(`Bao.Mount ${mountPath(news.path)}: live type ${live.type} != ${news.type}. ` + "Secrets engine type is immutable — replace manually."));
|
|
2432
2675
|
}
|
|
2433
|
-
|
|
2676
|
+
if (first !== undefined)
|
|
2677
|
+
yield* first(`Bao.Mount ${mountPath(news.path)}`);
|
|
2678
|
+
if (!matches(live, news))
|
|
2679
|
+
yield* tuneMount(news);
|
|
2434
2680
|
}
|
|
2435
2681
|
live = yield* readMount(news);
|
|
2436
2682
|
if (live === undefined) {
|
|
2437
|
-
return yield*
|
|
2683
|
+
return yield* Effect28.die(new Error(`Bao.Mount ${mountPath(news.path)}: write returned no error but the mount is still absent.`));
|
|
2438
2684
|
}
|
|
2439
2685
|
return live;
|
|
2440
2686
|
});
|
|
@@ -2443,17 +2689,21 @@ var reconcileMount = (news, stated, options) => Effect23.gen(function* () {
|
|
|
2443
2689
|
var BaoMount = Resource9("Bao.Mount", {
|
|
2444
2690
|
defaultRemovalPolicy: "retain"
|
|
2445
2691
|
});
|
|
2446
|
-
var BaoMountProvider = () => Provider9.effect(BaoMount,
|
|
2447
|
-
list: () =>
|
|
2448
|
-
read:
|
|
2449
|
-
|
|
2692
|
+
var BaoMountProvider = () => Provider9.effect(BaoMount, Effect29.succeed(BaoMount.Provider.of({
|
|
2693
|
+
list: () => Effect29.succeed([]),
|
|
2694
|
+
read: Effect29.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2695
|
+
const found = yield* readMount(olds);
|
|
2696
|
+
const ours = Effect29.sync(() => found !== undefined && matches(found, olds));
|
|
2697
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2450
2698
|
}),
|
|
2451
|
-
diff:
|
|
2452
|
-
if (output === undefined
|
|
2699
|
+
diff: Effect29.fn(function* ({ news, output }) {
|
|
2700
|
+
if (output === undefined)
|
|
2701
|
+
return;
|
|
2702
|
+
if (!isResolved9(news))
|
|
2453
2703
|
return;
|
|
2454
2704
|
const move = planMove("Bao.Mount", output.path, news.path, news.remountFrom);
|
|
2455
2705
|
if (move.kind === "refuse")
|
|
2456
|
-
return yield*
|
|
2706
|
+
return yield* Effect29.die(new Error(move.message));
|
|
2457
2707
|
if (move.kind === "move")
|
|
2458
2708
|
return { action: "update" };
|
|
2459
2709
|
const live = yield* readMount(news);
|
|
@@ -2465,19 +2715,20 @@ var BaoMountProvider = () => Provider9.effect(BaoMount, Effect24.succeed(BaoMoun
|
|
|
2465
2715
|
return { action: "noop" };
|
|
2466
2716
|
return { action: "update" };
|
|
2467
2717
|
}),
|
|
2468
|
-
reconcile:
|
|
2469
|
-
|
|
2718
|
+
reconcile: Effect29.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2719
|
+
const claim = claimFor({ fqn, instanceId, output });
|
|
2720
|
+
return yield* reconcileMount(news, output?.path, undefined, claim);
|
|
2470
2721
|
}),
|
|
2471
|
-
delete:
|
|
2722
|
+
delete: Effect29.fn(function* ({ output }) {
|
|
2472
2723
|
yield* disableMount(output.path);
|
|
2473
2724
|
return;
|
|
2474
2725
|
})
|
|
2475
|
-
})));
|
|
2726
|
+
})).pipe(Effect29.map(provingResumes)));
|
|
2476
2727
|
// src/openbao/pki-role.ts
|
|
2477
2728
|
import { Resource as Resource10 } from "alchemy";
|
|
2478
2729
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2479
2730
|
import * as Provider10 from "alchemy/Provider";
|
|
2480
|
-
import * as
|
|
2731
|
+
import * as Effect30 from "effect/Effect";
|
|
2481
2732
|
|
|
2482
2733
|
// src/openbao/pki-role-canonical.ts
|
|
2483
2734
|
var DEFAULT_KEY_USAGE = [
|
|
@@ -2644,18 +2895,20 @@ var BaoPkiRole = Resource10("Bao.PkiRole", {
|
|
|
2644
2895
|
defaultRemovalPolicy: "retain"
|
|
2645
2896
|
});
|
|
2646
2897
|
var IDENTITY7 = roleIdentity("Bao.PkiRole", (mount, name) => rolePath4({ mount, name }), "pki");
|
|
2647
|
-
var readRole2 = (props) =>
|
|
2898
|
+
var readRole2 = (props) => Effect30.gen(function* () {
|
|
2648
2899
|
const live = yield* baoRead(rolePath4(props));
|
|
2649
2900
|
if (live === undefined)
|
|
2650
2901
|
return;
|
|
2651
2902
|
return attributesOf10(props, live);
|
|
2652
2903
|
});
|
|
2653
|
-
var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole,
|
|
2654
|
-
list: () =>
|
|
2655
|
-
read:
|
|
2656
|
-
|
|
2904
|
+
var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect30.succeed(BaoPkiRole.Provider.of({
|
|
2905
|
+
list: () => Effect30.succeed([]),
|
|
2906
|
+
read: Effect30.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2907
|
+
const found = yield* readRole2(olds);
|
|
2908
|
+
const ours = Effect30.sync(() => found !== undefined && problems6(olds).length === 0 && matches9(found, olds));
|
|
2909
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2657
2910
|
}),
|
|
2658
|
-
diff:
|
|
2911
|
+
diff: Effect30.fn(function* ({ news, olds, output }) {
|
|
2659
2912
|
const move = yield* judgeRename(IDENTITY7, olds, news, output);
|
|
2660
2913
|
if (output === undefined)
|
|
2661
2914
|
return;
|
|
@@ -2670,36 +2923,38 @@ var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect25.succeed(Ba
|
|
|
2670
2923
|
return { action: "update" };
|
|
2671
2924
|
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
2672
2925
|
}),
|
|
2673
|
-
reconcile:
|
|
2926
|
+
reconcile: Effect30.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2674
2927
|
const path = rolePath4(news);
|
|
2675
2928
|
yield* guardRename(IDENTITY7, news, output);
|
|
2676
2929
|
const bad = problems6(news);
|
|
2677
2930
|
if (bad.length > 0) {
|
|
2678
|
-
return yield*
|
|
2931
|
+
return yield* Effect30.die(new Error(`Bao.PkiRole ${path}: ${bad.join(" ")}`));
|
|
2679
2932
|
}
|
|
2680
2933
|
const live = yield* readRole2(news);
|
|
2934
|
+
if (live !== undefined)
|
|
2935
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.PkiRole ${path}`);
|
|
2681
2936
|
if (live === undefined || !matches9(live, news)) {
|
|
2682
2937
|
yield* baoWrite("PUT", path, writeBody8(news));
|
|
2683
2938
|
}
|
|
2684
2939
|
const after = yield* readRole2(news);
|
|
2685
2940
|
if (after === undefined) {
|
|
2686
|
-
return yield*
|
|
2941
|
+
return yield* Effect30.die(new Error(`Bao.PkiRole ${path}: write reported success but the role is absent.`));
|
|
2687
2942
|
}
|
|
2688
2943
|
if (!matches9(after, news)) {
|
|
2689
|
-
return yield*
|
|
2944
|
+
return yield* Effect30.die(new Error(`Bao.PkiRole ${path}: wrote cleanly but the role read back different. ` + "OpenBao stored something other than what was declared — inspect with " + `\`bao read ${path}\` before retrying.`));
|
|
2690
2945
|
}
|
|
2691
2946
|
return after;
|
|
2692
2947
|
}),
|
|
2693
|
-
delete:
|
|
2948
|
+
delete: Effect30.fn(function* ({ output }) {
|
|
2694
2949
|
yield* baoDelete(rolePath4(output));
|
|
2695
2950
|
return;
|
|
2696
2951
|
})
|
|
2697
|
-
})));
|
|
2952
|
+
})).pipe(Effect30.map(provingResumes)));
|
|
2698
2953
|
// src/openbao/plugin.ts
|
|
2699
2954
|
import { Resource as Resource11 } from "alchemy";
|
|
2700
2955
|
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
2701
2956
|
import * as Provider11 from "alchemy/Provider";
|
|
2702
|
-
import * as
|
|
2957
|
+
import * as Effect32 from "effect/Effect";
|
|
2703
2958
|
|
|
2704
2959
|
// src/openbao/plugin-form.ts
|
|
2705
2960
|
var resolve = (props) => ({
|
|
@@ -2755,7 +3010,7 @@ var sameArgs = (want, have) => want.length === have.length && want.every((entry,
|
|
|
2755
3010
|
var matches10 = (attributes, form) => !attributes.builtin && attributes.version === form.version && attributes.sha256 === form.sha256 && attributes.command === form.command && sameArgs(form.args, attributes.args);
|
|
2756
3011
|
|
|
2757
3012
|
// src/openbao/plugin-reconcile.ts
|
|
2758
|
-
import * as
|
|
3013
|
+
import * as Effect31 from "effect/Effect";
|
|
2759
3014
|
|
|
2760
3015
|
// src/openbao/plugin-wire.ts
|
|
2761
3016
|
var readPluginData = (form) => baoRead(versionedPath(form.type, form.name, form.version));
|
|
@@ -2763,15 +3018,18 @@ var registerPlugin = (form) => baoWrite("PUT", catalogPath(form.type, form.name)
|
|
|
2763
3018
|
var deregisterPlugin = (type, name, version) => baoDelete(versionedPath(type, name, version));
|
|
2764
3019
|
|
|
2765
3020
|
// src/openbao/plugin-reconcile.ts
|
|
2766
|
-
var readEntry = (form) =>
|
|
2767
|
-
var refuse5 = (form, message) =>
|
|
2768
|
-
var SELF_REPORTED = "the write succeeded but the read-back does not match. If the binary reports its own version, " + "OpenBao filed the registration under it (plugin_catalog.go setInternal) — declare `version` " + "as exactly the version the binary reports
|
|
2769
|
-
var reconcilePlugin = (props) =>
|
|
3021
|
+
var readEntry = (form) => Effect31.map(readPluginData(form), (live) => live === undefined ? undefined : { attributes: attributesOf11(form, live), live });
|
|
3022
|
+
var refuse5 = (form, message) => Effect31.die(new Error(`Bao.Plugin ${versionedPath(form.type, form.name, form.version)}: ${message}`));
|
|
3023
|
+
var SELF_REPORTED = "the write succeeded but the read-back does not match. If the binary reports its own version, " + "OpenBao filed the registration under it (plugin_catalog.go setInternal) — declare `version` " + "as exactly the version the binary reports, and deploy once with --adopt: that adopts the " + "entry this write just made.";
|
|
3024
|
+
var reconcilePlugin = (props, claim) => Effect31.gen(function* () {
|
|
2770
3025
|
const form = resolve(props);
|
|
2771
3026
|
const bad = problems7(form);
|
|
2772
3027
|
if (bad.length > 0)
|
|
2773
3028
|
return yield* refuse5(form, bad.join("; "));
|
|
2774
3029
|
const found = yield* readEntry(form);
|
|
3030
|
+
if (found !== undefined && claim !== undefined) {
|
|
3031
|
+
yield* claim(`Bao.Plugin ${versionedPath(form.type, form.name, form.version)}`);
|
|
3032
|
+
}
|
|
2775
3033
|
if (found !== undefined && !matches10(found.attributes, form)) {
|
|
2776
3034
|
if (found.live["declarative"] === true || found.live["oci"] === true) {
|
|
2777
3035
|
return yield* refuse5(form, "the live entry is declarative/OCI; manage it in server config.");
|
|
@@ -2805,13 +3063,15 @@ var IDENTITY8 = {
|
|
|
2805
3063
|
family: "Bao.Plugin",
|
|
2806
3064
|
recorded: (output) => versionedPath(output.type, output.name, output.version)
|
|
2807
3065
|
};
|
|
2808
|
-
var BaoPluginProvider = () => Provider11.effect(BaoPlugin,
|
|
2809
|
-
list: () =>
|
|
2810
|
-
read:
|
|
2811
|
-
const
|
|
2812
|
-
|
|
3066
|
+
var BaoPluginProvider = () => Provider11.effect(BaoPlugin, Effect32.succeed(BaoPlugin.Provider.of({
|
|
3067
|
+
list: () => Effect32.succeed([]),
|
|
3068
|
+
read: Effect32.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
3069
|
+
const form = resolve(olds);
|
|
3070
|
+
const found = yield* readEntry(form);
|
|
3071
|
+
const ours = Effect32.sync(() => found !== undefined && problems7(form).length === 0 && matches10(found.attributes, form));
|
|
3072
|
+
return yield* ownedRead({ fqn, instanceId, output }, found?.attributes, ours);
|
|
2813
3073
|
}),
|
|
2814
|
-
diff:
|
|
3074
|
+
diff: Effect32.fn(function* ({ news, olds, output }) {
|
|
2815
3075
|
const move = yield* judgeRename(IDENTITY8, olds, news, output);
|
|
2816
3076
|
if (output === undefined)
|
|
2817
3077
|
return;
|
|
@@ -2825,20 +3085,20 @@ var BaoPluginProvider = () => Provider11.effect(BaoPlugin, Effect27.succeed(BaoP
|
|
|
2825
3085
|
return { action: "update" };
|
|
2826
3086
|
return matches10(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
2827
3087
|
}),
|
|
2828
|
-
reconcile:
|
|
3088
|
+
reconcile: Effect32.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2829
3089
|
yield* guardRename(IDENTITY8, news, output);
|
|
2830
|
-
return yield* reconcilePlugin(news);
|
|
3090
|
+
return yield* reconcilePlugin(news, claimFor({ fqn, instanceId, output }));
|
|
2831
3091
|
}),
|
|
2832
|
-
delete:
|
|
3092
|
+
delete: Effect32.fn(function* ({ output }) {
|
|
2833
3093
|
yield* deregisterPlugin(output.type, output.name, output.version);
|
|
2834
3094
|
return;
|
|
2835
3095
|
})
|
|
2836
|
-
})));
|
|
3096
|
+
})).pipe(Effect32.map(provingResumes)));
|
|
2837
3097
|
// src/openbao/policy.ts
|
|
2838
3098
|
import { Resource as Resource12 } from "alchemy";
|
|
2839
3099
|
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
2840
3100
|
import * as Provider12 from "alchemy/Provider";
|
|
2841
|
-
import * as
|
|
3101
|
+
import * as Effect34 from "effect/Effect";
|
|
2842
3102
|
import * as FileSystem from "effect/FileSystem";
|
|
2843
3103
|
import * as Path from "effect/Path";
|
|
2844
3104
|
|
|
@@ -2846,13 +3106,13 @@ import * as Path from "effect/Path";
|
|
|
2846
3106
|
var isEmptyAssembly = (parts, joined) => parts === 0 || !/^\s*path\s+"/m.test(joined);
|
|
2847
3107
|
|
|
2848
3108
|
// src/openbao/policy-wire.ts
|
|
2849
|
-
import * as
|
|
3109
|
+
import * as Effect33 from "effect/Effect";
|
|
2850
3110
|
var policyPath = (name) => `sys/policies/acl/${name}`;
|
|
2851
|
-
var readPolicy = (name) =>
|
|
3111
|
+
var readPolicy = (name) => Effect33.flatMap(baoRead(policyPath(name)), (data) => {
|
|
2852
3112
|
if (data === undefined)
|
|
2853
|
-
return
|
|
3113
|
+
return Effect33.succeed("");
|
|
2854
3114
|
const text11 = data["policy"];
|
|
2855
|
-
return typeof text11 === "string" ?
|
|
3115
|
+
return typeof text11 === "string" ? Effect33.succeed(text11) : Effect33.fail(new BaoError(200, "GET", policyPath(name), ["no data.policy in the response"]));
|
|
2856
3116
|
});
|
|
2857
3117
|
var writePolicy = (name, hcl) => baoWrite("PUT", policyPath(name), { policy: hcl });
|
|
2858
3118
|
var deletePolicy = (name) => baoDelete(policyPath(name));
|
|
@@ -2869,10 +3129,10 @@ var attributesOf12 = (name, hcl, parts) => ({
|
|
|
2869
3129
|
grants: grantsOf(hcl),
|
|
2870
3130
|
parts
|
|
2871
3131
|
});
|
|
2872
|
-
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy,
|
|
3132
|
+
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect34.gen(function* () {
|
|
2873
3133
|
const fs = yield* FileSystem.FileSystem;
|
|
2874
3134
|
const path = yield* Path.Path;
|
|
2875
|
-
const assemble = (dir) =>
|
|
3135
|
+
const assemble = (dir) => Effect34.gen(function* () {
|
|
2876
3136
|
const entries2 = (yield* fs.readDirectory(dir)).filter((f) => f.endsWith(".hcl")).sort();
|
|
2877
3137
|
let joined = "";
|
|
2878
3138
|
for (const f of entries2)
|
|
@@ -2881,12 +3141,14 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect29.gen(function
|
|
|
2881
3141
|
return { joined, parts: entries2.length };
|
|
2882
3142
|
});
|
|
2883
3143
|
return BaoPolicy.Provider.of({
|
|
2884
|
-
list: () =>
|
|
2885
|
-
read:
|
|
3144
|
+
list: () => Effect34.succeed([]),
|
|
3145
|
+
read: Effect34.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2886
3146
|
const live = yield* readPolicy(olds.name);
|
|
2887
|
-
|
|
3147
|
+
const found = live.length === 0 ? undefined : attributesOf12(olds.name, live, 0);
|
|
3148
|
+
const ours = Effect34.map(assemble(olds.fragments), (a) => sha256(a.joined) === found?.digest);
|
|
3149
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2888
3150
|
}),
|
|
2889
|
-
diff:
|
|
3151
|
+
diff: Effect34.fn(function* ({ news, olds, output }) {
|
|
2890
3152
|
const move = yield* judgeRename(IDENTITY9, olds, news, output);
|
|
2891
3153
|
if (output === undefined)
|
|
2892
3154
|
return;
|
|
@@ -2898,30 +3160,32 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect29.gen(function
|
|
|
2898
3160
|
const live = yield* readPolicy(news.name);
|
|
2899
3161
|
return live.length > 0 && sha256(live) === sha256(joined) ? { action: "noop" } : { action: "update" };
|
|
2900
3162
|
}),
|
|
2901
|
-
reconcile:
|
|
3163
|
+
reconcile: Effect34.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2902
3164
|
const name = news.name;
|
|
2903
3165
|
yield* guardRename(IDENTITY9, news, output);
|
|
2904
3166
|
const { joined, parts } = yield* assemble(news.fragments);
|
|
2905
3167
|
if (isEmptyAssembly(parts, joined))
|
|
2906
|
-
return yield*
|
|
3168
|
+
return yield* Effect34.die(new Error(`Bao.Policy ${name}: the fragments under ${news.fragments} carry no path grant ` + `(${String(parts)} file(s)). Writing it would revoke every grant the policy carries.`));
|
|
2907
3169
|
const current = yield* readPolicy(name);
|
|
3170
|
+
if (current.length > 0)
|
|
3171
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.Policy ${name}`);
|
|
2908
3172
|
if (current.length > 0 && sha256(current) === sha256(joined)) {
|
|
2909
3173
|
return attributesOf12(name, joined, parts);
|
|
2910
3174
|
}
|
|
2911
3175
|
yield* writePolicy(name, joined);
|
|
2912
3176
|
return attributesOf12(name, joined, parts);
|
|
2913
3177
|
}),
|
|
2914
|
-
delete:
|
|
3178
|
+
delete: Effect34.fn(function* ({ output }) {
|
|
2915
3179
|
yield* deletePolicy(output.name);
|
|
2916
3180
|
return;
|
|
2917
3181
|
})
|
|
2918
3182
|
});
|
|
2919
|
-
}));
|
|
3183
|
+
}).pipe(Effect34.map(provingResumes)));
|
|
2920
3184
|
// src/openbao/proxmox-role.ts
|
|
2921
3185
|
import { Resource as Resource13 } from "alchemy";
|
|
2922
3186
|
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
2923
3187
|
import * as Provider13 from "alchemy/Provider";
|
|
2924
|
-
import * as
|
|
3188
|
+
import * as Effect36 from "effect/Effect";
|
|
2925
3189
|
|
|
2926
3190
|
// src/openbao/proxmox-role-form.ts
|
|
2927
3191
|
var text11 = (value) => typeof value === "string" ? value : "";
|
|
@@ -2971,8 +3235,8 @@ var rescopeRefusal = (before, mintUser, allowMintUserChange) => before === mintU
|
|
|
2971
3235
|
var matches11 = (attributes, props) => attributes.mintUser === props.mintUser && sameTtl5(props.ttl, attributes.ttl) && sameTtl5(props.maxTtl, attributes.maxTtl);
|
|
2972
3236
|
|
|
2973
3237
|
// src/openbao/proxmox-role-wire.ts
|
|
2974
|
-
import * as
|
|
2975
|
-
var readRole3 = (props) =>
|
|
3238
|
+
import * as Effect35 from "effect/Effect";
|
|
3239
|
+
var readRole3 = (props) => Effect35.gen(function* () {
|
|
2976
3240
|
const live = yield* baoRead(rolePath5(props.mount, props.name));
|
|
2977
3241
|
if (live === undefined)
|
|
2978
3242
|
return;
|
|
@@ -2984,12 +3248,14 @@ var BaoProxmoxRole = Resource13("Bao.ProxmoxRole", {
|
|
|
2984
3248
|
defaultRemovalPolicy: "retain"
|
|
2985
3249
|
});
|
|
2986
3250
|
var IDENTITY10 = roleIdentity("Bao.ProxmoxRole", rolePath5);
|
|
2987
|
-
var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole,
|
|
2988
|
-
list: () =>
|
|
2989
|
-
read:
|
|
2990
|
-
|
|
3251
|
+
var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect36.succeed(BaoProxmoxRole.Provider.of({
|
|
3252
|
+
list: () => Effect36.succeed([]),
|
|
3253
|
+
read: Effect36.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
3254
|
+
const found = yield* readRole3(olds);
|
|
3255
|
+
const ours = Effect36.sync(() => found !== undefined && matches11(found, olds));
|
|
3256
|
+
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2991
3257
|
}),
|
|
2992
|
-
diff:
|
|
3258
|
+
diff: Effect36.fn(function* ({ news, olds, output }) {
|
|
2993
3259
|
const move = yield* judgeRename(IDENTITY10, olds, news, output);
|
|
2994
3260
|
if (output === undefined)
|
|
2995
3261
|
return;
|
|
@@ -3002,7 +3268,7 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect31.su
|
|
|
3002
3268
|
const refusal2 = rescopeRefusal(from, mintUser, allow);
|
|
3003
3269
|
if (refusal2 === undefined)
|
|
3004
3270
|
return { action: "replace" };
|
|
3005
|
-
return yield*
|
|
3271
|
+
return yield* Effect36.die(new Error(`Bao.ProxmoxRole ${move.from} → ${move.to}: the rename ${refusal2}`));
|
|
3006
3272
|
}
|
|
3007
3273
|
if (!isResolved13(news))
|
|
3008
3274
|
return;
|
|
@@ -3013,37 +3279,39 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect31.su
|
|
|
3013
3279
|
return { action: "noop" };
|
|
3014
3280
|
return { action: "update" };
|
|
3015
3281
|
}),
|
|
3016
|
-
reconcile:
|
|
3282
|
+
reconcile: Effect36.fn(function* ({ fqn, instanceId, news, output }) {
|
|
3017
3283
|
const path = rolePath5(news.mount, news.name);
|
|
3018
3284
|
yield* guardRename(IDENTITY10, news, output);
|
|
3019
3285
|
const live = yield* readRole3(news);
|
|
3286
|
+
if (live !== undefined)
|
|
3287
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.ProxmoxRole ${path}`);
|
|
3020
3288
|
const rescope = live === undefined ? undefined : rescopeRefusal(live.mintUser, news.mintUser, news.allowMintUserChange);
|
|
3021
3289
|
if (rescope !== undefined) {
|
|
3022
|
-
return yield*
|
|
3290
|
+
return yield* Effect36.die(new Error(`Bao.ProxmoxRole ${path}: ${rescope}`));
|
|
3023
3291
|
}
|
|
3024
3292
|
if (live === undefined || !matches11(live, news)) {
|
|
3025
3293
|
const write = writeBody9(news);
|
|
3026
3294
|
if (!write.ok) {
|
|
3027
|
-
return yield*
|
|
3295
|
+
return yield* Effect36.die(new Error(`Bao.ProxmoxRole ${path}: unparseable duration ` + `${write.bad.join(", ")}. Use 30s / 5m / 1h / 1d, or 0.`));
|
|
3028
3296
|
}
|
|
3029
3297
|
yield* baoWrite("PUT", path, write.body);
|
|
3030
3298
|
}
|
|
3031
3299
|
const after = yield* readRole3(news);
|
|
3032
3300
|
if (after === undefined) {
|
|
3033
|
-
return yield*
|
|
3301
|
+
return yield* Effect36.die(new Error(`Bao.ProxmoxRole ${path}: write returned no error ` + "but the role is still absent."));
|
|
3034
3302
|
}
|
|
3035
3303
|
return after;
|
|
3036
3304
|
}),
|
|
3037
|
-
delete:
|
|
3305
|
+
delete: Effect36.fn(function* ({ output }) {
|
|
3038
3306
|
yield* baoDelete(rolePath5(output.mount, output.name));
|
|
3039
3307
|
return;
|
|
3040
3308
|
})
|
|
3041
|
-
})));
|
|
3309
|
+
})).pipe(Effect36.map(provingResumes)));
|
|
3042
3310
|
// src/openbao/ssh-role.ts
|
|
3043
3311
|
import { Resource as Resource14 } from "alchemy";
|
|
3044
3312
|
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
3045
3313
|
import * as Provider14 from "alchemy/Provider";
|
|
3046
|
-
import * as
|
|
3314
|
+
import * as Effect37 from "effect/Effect";
|
|
3047
3315
|
|
|
3048
3316
|
// src/openbao/ssh-role-form.ts
|
|
3049
3317
|
var readPath4 = (mount, name) => `${sshMountOf(mount)}/roles/${name}`;
|
|
@@ -3104,7 +3372,7 @@ var attributesOf14 = (form, live) => {
|
|
|
3104
3372
|
};
|
|
3105
3373
|
return { ...attrs, digest: sha256(JSON.stringify(attrs)) };
|
|
3106
3374
|
};
|
|
3107
|
-
var mapValue = (
|
|
3375
|
+
var mapValue = (map23) => extMap(map23);
|
|
3108
3376
|
var writeBody10 = (form) => ({
|
|
3109
3377
|
key_type: "ca",
|
|
3110
3378
|
allowed_users: form.allowedUsers.join(","),
|
|
@@ -3158,20 +3426,21 @@ var BaoSshRole = Resource14("Bao.SshRole", {
|
|
|
3158
3426
|
defaultRemovalPolicy: "retain"
|
|
3159
3427
|
});
|
|
3160
3428
|
var IDENTITY11 = roleIdentity("Bao.SshRole", readPath4, "ssh");
|
|
3161
|
-
var readRole4 = (form) =>
|
|
3429
|
+
var readRole4 = (form) => Effect37.gen(function* () {
|
|
3162
3430
|
const live = yield* baoRead(readPath4(form.mount, form.name));
|
|
3163
3431
|
if (live === undefined)
|
|
3164
3432
|
return;
|
|
3165
3433
|
return { attributes: attributesOf14(form, live), live };
|
|
3166
3434
|
});
|
|
3167
|
-
var refuse6 = (message) =>
|
|
3168
|
-
var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole,
|
|
3169
|
-
list: () =>
|
|
3170
|
-
read:
|
|
3435
|
+
var refuse6 = (message) => Effect37.die(new Error(message));
|
|
3436
|
+
var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect37.succeed(BaoSshRole.Provider.of({
|
|
3437
|
+
list: () => Effect37.succeed([]),
|
|
3438
|
+
read: Effect37.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
3171
3439
|
const found = yield* readRole4(resolve2(olds));
|
|
3172
|
-
|
|
3440
|
+
const ours = Effect37.sync(() => found !== undefined && matches12(found.attributes, resolve2(olds)));
|
|
3441
|
+
return yield* ownedRead({ fqn, instanceId, output }, found?.attributes, ours);
|
|
3173
3442
|
}),
|
|
3174
|
-
diff:
|
|
3443
|
+
diff: Effect37.fn(function* ({ news, olds, output }) {
|
|
3175
3444
|
const move = yield* judgeRename(IDENTITY11, olds, news, output);
|
|
3176
3445
|
if (output === undefined)
|
|
3177
3446
|
return;
|
|
@@ -3185,7 +3454,7 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect32.succeed(Ba
|
|
|
3185
3454
|
return { action: "update" };
|
|
3186
3455
|
return matches12(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
3187
3456
|
}),
|
|
3188
|
-
reconcile:
|
|
3457
|
+
reconcile: Effect37.fn(function* ({ fqn, instanceId, news, output }) {
|
|
3189
3458
|
const form = resolve2(news);
|
|
3190
3459
|
const path = readPath4(form.mount, form.name);
|
|
3191
3460
|
yield* guardRename(IDENTITY11, news, output);
|
|
@@ -3197,6 +3466,8 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect32.succeed(Ba
|
|
|
3197
3466
|
return yield* refuse6(`Bao.SshRole ${path}: allowUserCertificates with an empty allowedUsers and ` + "allowEmptyPrincipals false. Every sign request against it would be rejected.");
|
|
3198
3467
|
}
|
|
3199
3468
|
const found = yield* readRole4(form);
|
|
3469
|
+
if (found !== undefined)
|
|
3470
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.SshRole ${path}`);
|
|
3200
3471
|
if (found === undefined || !matches12(found.attributes, form)) {
|
|
3201
3472
|
if (found !== undefined) {
|
|
3202
3473
|
const lost = wouldErase2(found.live);
|
|
@@ -3212,11 +3483,11 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect32.succeed(Ba
|
|
|
3212
3483
|
}
|
|
3213
3484
|
return after.attributes;
|
|
3214
3485
|
}),
|
|
3215
|
-
delete:
|
|
3486
|
+
delete: Effect37.fn(function* ({ output }) {
|
|
3216
3487
|
yield* baoDelete(readPath4(output.mount, output.name));
|
|
3217
3488
|
return;
|
|
3218
3489
|
})
|
|
3219
|
-
})));
|
|
3490
|
+
})).pipe(Effect37.map(provingResumes)));
|
|
3220
3491
|
export {
|
|
3221
3492
|
BaoAuthMethod,
|
|
3222
3493
|
BaoAuthMethodProvider,
|
|
@@ -3266,5 +3537,5 @@ export {
|
|
|
3266
3537
|
revokeSelfEffect
|
|
3267
3538
|
};
|
|
3268
3539
|
|
|
3269
|
-
//# debugId=
|
|
3540
|
+
//# debugId=9AA407497A9014D964756E2164756E21
|
|
3270
3541
|
//# sourceMappingURL=index.js.map
|