@homeflare/alchemy 0.7.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 +45 -45
- package/dist/caddy/config-lifecycle.d.ts +49 -3
- package/dist/caddy/config-lifecycle.d.ts.map +1 -1
- package/dist/caddy/config.d.ts +6 -2
- package/dist/caddy/config.d.ts.map +1 -1
- package/dist/caddy/fake-caddy.d.ts +11 -0
- package/dist/caddy/fake-caddy.d.ts.map +1 -1
- package/dist/caddy/index.d.ts +2 -1
- package/dist/caddy/index.d.ts.map +1 -1
- package/dist/caddy/index.js +270 -44
- package/dist/caddy/index.js.map +15 -11
- package/dist/caddy/with-file.d.ts +7 -3
- package/dist/caddy/with-file.d.ts.map +1 -1
- 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 +51 -0
- package/dist/launchd/fake-sudo.d.ts.map +1 -0
- package/dist/launchd/host-effect.d.ts +1 -1
- package/dist/launchd/host-file-form.d.ts +5 -0
- package/dist/launchd/host-file-form.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.d.ts +2 -0
- package/dist/launchd/index.d.ts.map +1 -1
- package/dist/launchd/index.js +642 -49
- package/dist/launchd/index.js.map +24 -14
- 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-validate.d.ts +2 -0
- package/dist/launchd/job-validate.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/local-runner.d.ts +2 -0
- package/dist/launchd/local-runner.d.ts.map +1 -1
- package/dist/launchd/providers.d.ts +2 -1
- package/dist/launchd/providers.d.ts.map +1 -1
- package/dist/launchd/runner.d.ts +14 -5
- 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-allowlist.d.ts +47 -0
- package/dist/launchd/sudo-allowlist.d.ts.map +1 -0
- package/dist/launchd/sudo-guard.d.ts +83 -0
- package/dist/launchd/sudo-guard.d.ts.map +1 -0
- package/dist/launchd/sudo-runner.d.ts +60 -0
- package/dist/launchd/sudo-runner.d.ts.map +1 -0
- package/dist/launchd/sudo-said.d.ts +10 -0
- package/dist/launchd/sudo-said.d.ts.map +1 -0
- package/dist/launchd/sudo-stage.d.ts +7 -0
- package/dist/launchd/sudo-stage.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-form.d.ts +0 -9
- package/dist/openbao/auth-role-form.d.ts.map +1 -1
- package/dist/openbao/auth-role.d.ts +3 -2
- 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-engines-roles.d.ts +32 -0
- package/dist/openbao/fake-engines-roles.d.ts.map +1 -0
- package/dist/openbao/fake-engines.d.ts +8 -2
- package/dist/openbao/fake-engines.d.ts.map +1 -1
- package/dist/openbao/fake-families.d.ts +52 -0
- package/dist/openbao/fake-families.d.ts.map +1 -0
- 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/host-approles.d.ts.map +1 -1
- package/dist/openbao/index.js +709 -359
- package/dist/openbao/index.js.map +32 -25
- package/dist/openbao/jwt-config.d.ts +5 -0
- package/dist/openbao/jwt-config.d.ts.map +1 -1
- package/dist/openbao/jwt-role.d.ts +2 -1
- package/dist/openbao/jwt-role.d.ts.map +1 -1
- package/dist/openbao/kubernetes-role.d.ts +2 -1
- package/dist/openbao/kubernetes-role.d.ts.map +1 -1
- package/dist/openbao/mfa-enforcement.d.ts +12 -5
- 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/rename-identity.d.ts +69 -0
- package/dist/openbao/rename-identity.d.ts.map +1 -0
- package/dist/openbao/rename.d.ts +13 -12
- package/dist/openbao/rename.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-erase.d.ts +11 -0
- package/dist/openbao/ssh-role-erase.d.ts.map +1 -0
- 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/caddy-admin.md +24 -0
- package/docs/caddy.md +73 -54
- package/docs/credentials.md +15 -0
- package/docs/launchd-sudo.md +147 -0
- package/docs/launchd.md +14 -7
- package/docs/ownership.md +113 -0
- package/docs/peers.md +39 -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 +82 -0
- package/src/caddy/config-adopt.test.ts +235 -0
- package/src/caddy/config-lifecycle.test.ts +31 -53
- package/src/caddy/config-lifecycle.ts +98 -7
- package/src/caddy/config.ts +48 -10
- package/src/caddy/fake-caddy.ts +19 -0
- package/src/caddy/index.ts +2 -1
- package/src/caddy/providers.test.ts +8 -23
- package/src/caddy/with-file.ts +7 -3
- package/src/launchd/adopt-apply.test.ts +166 -0
- package/src/launchd/fake-runner.ts +26 -4
- package/src/launchd/fake-sudo.ts +136 -0
- package/src/launchd/host-effect.ts +1 -1
- package/src/launchd/host-file-form.ts +10 -2
- package/src/launchd/host-file-lifecycle.ts +41 -15
- package/src/launchd/host-file.ts +13 -4
- package/src/launchd/index.ts +2 -0
- package/src/launchd/job-lifecycle.ts +22 -14
- package/src/launchd/job-preflight.ts +21 -3
- package/src/launchd/job-validate.ts +1 -1
- package/src/launchd/job.ts +13 -4
- package/src/launchd/local-runner.ts +6 -3
- package/src/launchd/providers.test.ts +3 -0
- package/src/launchd/providers.ts +2 -1
- package/src/launchd/runner.ts +14 -5
- package/src/launchd/sudo-acl.ts +68 -0
- package/src/launchd/sudo-allowlist.test.ts +191 -0
- package/src/launchd/sudo-allowlist.ts +213 -0
- package/src/launchd/sudo-chain.test.ts +121 -0
- package/src/launchd/sudo-guard.test.ts +100 -0
- package/src/launchd/sudo-guard.ts +230 -0
- package/src/launchd/sudo-lifecycle.test.ts +172 -0
- package/src/launchd/sudo-modes.test.ts +135 -0
- package/src/launchd/sudo-runner-files.test.ts +240 -0
- package/src/launchd/sudo-runner.test.ts +126 -0
- package/src/launchd/sudo-runner.ts +216 -0
- package/src/launchd/sudo-said.ts +58 -0
- package/src/launchd/sudo-stage.ts +28 -0
- package/src/openbao/README.md +11 -2
- package/src/openbao/REPLACE.md +67 -37
- 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-form.test.ts +2 -16
- package/src/openbao/auth-role-form.ts +0 -11
- package/src/openbao/auth-role.ts +48 -17
- package/src/openbao/cloudflare-role.ts +23 -18
- package/src/openbao/fake-bao.ts +52 -0
- package/src/openbao/fake-core.ts +141 -0
- package/src/openbao/fake-engines-roles.ts +114 -0
- package/src/openbao/fake-engines.ts +18 -11
- package/src/openbao/fake-families.ts +188 -0
- package/src/openbao/fake-mounts.ts +74 -0
- package/src/openbao/fake-stack.ts +17 -4
- package/src/openbao/host-approles.test.ts +15 -2
- package/src/openbao/host-approles.ts +19 -4
- package/src/openbao/jwt-config.ts +35 -11
- package/src/openbao/jwt-role.ts +33 -14
- package/src/openbao/kubernetes-role.ts +32 -14
- package/src/openbao/mfa-enforcement.ts +42 -13
- package/src/openbao/mfa-totp.ts +42 -14
- 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 +33 -10
- package/src/openbao/plugin-reconcile.ts +16 -5
- package/src/openbao/plugin.ts +57 -20
- package/src/openbao/policy.ts +24 -11
- package/src/openbao/proxmox-role.ts +20 -20
- package/src/openbao/rename-adoption.test.ts +95 -0
- package/src/openbao/rename-families.test.ts +122 -0
- package/src/openbao/rename-identity.test.ts +129 -0
- package/src/openbao/rename-identity.ts +117 -0
- package/src/openbao/rename.ts +19 -15
- package/src/openbao/role-reconcile.ts +23 -0
- package/src/openbao/ssh-role-erase.ts +50 -0
- package/src/openbao/ssh-role.ts +29 -57
- 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) => {
|
|
@@ -665,7 +874,6 @@ var writeBody = (props) => {
|
|
|
665
874
|
}
|
|
666
875
|
return body;
|
|
667
876
|
};
|
|
668
|
-
var isRename = (from, to) => from.toLowerCase() !== to.toLowerCase();
|
|
669
877
|
var samePolicies = (want, have) => want.length === have.length && want.every((policy, index) => policy === have[index]);
|
|
670
878
|
var sameTtl3 = (want, have) => {
|
|
671
879
|
const wantSeconds = parseDuration(want);
|
|
@@ -677,26 +885,92 @@ var matches3 = (attributes, props) => {
|
|
|
677
885
|
return samePolicies(wantPolicies, attributes.tokenPolicies) && sameTtl3(props.tokenTtl, attributes.tokenTtl) && sameTtl3(props.tokenMaxTtl, attributes.tokenMaxTtl) && sameTtl3(props.secretIdTtl, attributes.secretIdTtl) && (props.bindSecretId === undefined || attributes.bindSecretId === props.bindSecretId) && (props.secretIdNumUses === undefined || attributes.secretIdNumUses === props.secretIdNumUses);
|
|
678
886
|
};
|
|
679
887
|
|
|
888
|
+
// src/openbao/rename-identity.ts
|
|
889
|
+
import * as Effect14 from "effect/Effect";
|
|
890
|
+
|
|
891
|
+
// src/openbao/rename.ts
|
|
892
|
+
import * as Effect13 from "effect/Effect";
|
|
893
|
+
var exact = (identity) => identity;
|
|
894
|
+
var declaredString = (news, key) => {
|
|
895
|
+
if (typeof news !== "object" || news === null)
|
|
896
|
+
return;
|
|
897
|
+
const value = news[key];
|
|
898
|
+
return typeof value === "string" ? value : undefined;
|
|
899
|
+
};
|
|
900
|
+
var isPendingProp = (news, key) => {
|
|
901
|
+
if (typeof news !== "object" || news === null)
|
|
902
|
+
return false;
|
|
903
|
+
const value = news[key];
|
|
904
|
+
return value !== undefined && typeof value !== "string";
|
|
905
|
+
};
|
|
906
|
+
var declaredOr = (news, key, fallback) => isPendingProp(news, key) ? undefined : declaredString(news, key) ?? fallback;
|
|
907
|
+
var declaredRolePath = (news, rolePath, defaultMount) => {
|
|
908
|
+
const mount = defaultMount === undefined ? declaredString(news, "mount") : declaredOr(news, "mount", defaultMount);
|
|
909
|
+
const name = declaredString(news, "name");
|
|
910
|
+
return mount === undefined || name === undefined ? undefined : rolePath(mount, name);
|
|
911
|
+
};
|
|
912
|
+
var policyKey = (name) => name.trim().toLowerCase();
|
|
913
|
+
var isMoved = (stored, declared, key = exact) => declared === undefined ? undefined : key(stored) !== key(declared);
|
|
914
|
+
var judgeMove = (family, tried, declared, pathOf, key = exact) => Effect13.gen(function* () {
|
|
915
|
+
if (tried === undefined || declared === undefined || key(tried) === key(declared)) {
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
if ((yield* baoRead(pathOf(declared))) === undefined)
|
|
919
|
+
return { from: tried, to: declared };
|
|
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.`));
|
|
921
|
+
});
|
|
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."));
|
|
923
|
+
|
|
924
|
+
// src/openbao/rename-identity.ts
|
|
925
|
+
var nameIdentity = (family, pathOf, key) => ({
|
|
926
|
+
declared: (props) => declaredString(props, "name"),
|
|
927
|
+
family,
|
|
928
|
+
key,
|
|
929
|
+
pathOf,
|
|
930
|
+
recorded: (output) => output.name
|
|
931
|
+
});
|
|
932
|
+
var roleIdentity = (family, rolePath, defaultMount, key) => ({
|
|
933
|
+
declared: (props) => declaredRolePath(props, rolePath, defaultMount),
|
|
934
|
+
family,
|
|
935
|
+
key,
|
|
936
|
+
recorded: (output) => rolePath(output.mount, output.name)
|
|
937
|
+
});
|
|
938
|
+
var foldName = (path) => path.replace(/[^/]+$/, (name) => name.toLowerCase());
|
|
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);
|
|
940
|
+
var guardRename = (identity, news, output) => {
|
|
941
|
+
if (output === undefined)
|
|
942
|
+
return Effect14.void;
|
|
943
|
+
const from = identity.recorded(output);
|
|
944
|
+
const to = identity.declared(news);
|
|
945
|
+
return to !== undefined && isMoved(from, to, identity.key) === true ? refuseMovedUpdate(identity.family, from, to) : Effect14.void;
|
|
946
|
+
};
|
|
947
|
+
|
|
680
948
|
// src/openbao/auth-role.ts
|
|
681
949
|
var BaoAuthRole = Resource2("Bao.AuthRole", {
|
|
682
950
|
defaultRemovalPolicy: "retain"
|
|
683
951
|
});
|
|
684
|
-
var
|
|
952
|
+
var IDENTITY = nameIdentity("Bao.AuthRole", readPath3, foldName);
|
|
953
|
+
var readRole = (props) => Effect15.gen(function* () {
|
|
685
954
|
const live = yield* baoRead(readPath3(props.name));
|
|
686
955
|
if (live === undefined)
|
|
687
956
|
return;
|
|
688
957
|
return attributesOf3(props, live);
|
|
689
958
|
});
|
|
690
|
-
var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole,
|
|
691
|
-
list: () =>
|
|
692
|
-
read:
|
|
693
|
-
|
|
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);
|
|
694
965
|
}),
|
|
695
|
-
diff:
|
|
696
|
-
|
|
966
|
+
diff: Effect15.fn(function* ({ news, olds, output }) {
|
|
967
|
+
const move = yield* judgeRename(IDENTITY, olds, news, output);
|
|
968
|
+
if (output === undefined)
|
|
697
969
|
return;
|
|
698
|
-
if (
|
|
970
|
+
if (move !== undefined)
|
|
699
971
|
return { action: "replace" };
|
|
972
|
+
if (!isResolved2(news))
|
|
973
|
+
return;
|
|
700
974
|
const live = yield* readRole(news);
|
|
701
975
|
if (live === undefined)
|
|
702
976
|
return { action: "update" };
|
|
@@ -704,24 +978,28 @@ var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole, Effect8.succeed(Ba
|
|
|
704
978
|
return { action: "noop" };
|
|
705
979
|
return { action: "update" };
|
|
706
980
|
}),
|
|
707
|
-
reconcile:
|
|
981
|
+
reconcile: Effect15.fn(function* ({ fqn, instanceId, news, output }) {
|
|
982
|
+
yield* guardRename(IDENTITY, news, output);
|
|
708
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}`);
|
|
709
987
|
if (live === undefined || !matches3(live, news)) {
|
|
710
988
|
yield* baoWrite("PUT", readPath3(news.name), writeBody(news));
|
|
711
989
|
}
|
|
712
990
|
const after = yield* readRole(news);
|
|
713
991
|
if (after === undefined) {
|
|
714
|
-
return yield*
|
|
992
|
+
return yield* Effect15.die(new Error(`Bao.AuthRole ${news.name}: write returned no error but the role is still absent.`));
|
|
715
993
|
}
|
|
716
994
|
return after;
|
|
717
995
|
}),
|
|
718
|
-
delete:
|
|
996
|
+
delete: Effect15.fn(function* ({ output }) {
|
|
719
997
|
yield* baoDelete(readPath3(output.name));
|
|
720
998
|
return;
|
|
721
999
|
})
|
|
722
|
-
})));
|
|
1000
|
+
})).pipe(Effect15.map(provingResumes)));
|
|
723
1001
|
// src/openbao/bao-identity.ts
|
|
724
|
-
import * as
|
|
1002
|
+
import * as Effect16 from "effect/Effect";
|
|
725
1003
|
import * as FetchHttpClient3 from "effect/unstable/http/FetchHttpClient";
|
|
726
1004
|
|
|
727
1005
|
// src/openbao/bao-namespace.ts
|
|
@@ -769,42 +1047,42 @@ var checkHealth = (address, expectedCluster, body) => {
|
|
|
769
1047
|
}
|
|
770
1048
|
return { clusterId: text3(body["cluster_id"]), version: text3(body["version"]) };
|
|
771
1049
|
};
|
|
772
|
-
var assertBaoIdentityEffect = (expected) =>
|
|
1050
|
+
var assertBaoIdentityEffect = (expected) => Effect16.gen(function* () {
|
|
773
1051
|
const env = yield* BaoEnv;
|
|
774
1052
|
const address = addressOf(env);
|
|
775
1053
|
const clusterName = expected.clusterName.trim();
|
|
776
1054
|
if (clusterName === "") {
|
|
777
|
-
return yield*
|
|
1055
|
+
return yield* Effect16.fail(new BaoIdentityError("input", "clusterName is empty, so there is nothing to compare."));
|
|
778
1056
|
}
|
|
779
1057
|
const namespace = canonicalNamespace(expected.namespace);
|
|
780
1058
|
const sent = envNamespace(env);
|
|
781
1059
|
if (sent !== namespace) {
|
|
782
|
-
return yield*
|
|
1060
|
+
return yield* Effect16.fail(new BaoIdentityError("mismatch", `BAO_NAMESPACE resolves to \`${namespaceLabel(sent)}\`, but this stack expects ` + `\`${namespaceLabel(namespace)}\`.`));
|
|
783
1061
|
}
|
|
784
1062
|
const anonymous = { ...env, BAO_NAMESPACE: "", BAO_TOKEN: "" };
|
|
785
|
-
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")));
|
|
786
1064
|
const health = checkHealth(address, clusterName, body);
|
|
787
1065
|
if (health instanceof BaoIdentityError)
|
|
788
|
-
return yield*
|
|
1066
|
+
return yield* Effect16.fail(health);
|
|
789
1067
|
if (namespace !== "") {
|
|
790
1068
|
const scoped = { ...env, BAO_NAMESPACE: namespace, BAO_TOKEN: "" };
|
|
791
|
-
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}\``)));
|
|
792
1070
|
if (probe === undefined) {
|
|
793
|
-
return yield*
|
|
1071
|
+
return yield* Effect16.fail(new BaoIdentityError("mismatch", `cluster \`${clusterName}\` at ${address} has no namespace \`${namespace}\`.`));
|
|
794
1072
|
}
|
|
795
1073
|
}
|
|
796
1074
|
return { address, clusterName, namespace, ...health };
|
|
797
1075
|
});
|
|
798
1076
|
var assertBaoIdentity = (input) => {
|
|
799
1077
|
const effect3 = assertBaoIdentityEffect(input);
|
|
800
|
-
const scoped = input.env === undefined ? effect3 :
|
|
801
|
-
return
|
|
1078
|
+
const scoped = input.env === undefined ? effect3 : Effect16.provideService(effect3, BaoEnv, input.env);
|
|
1079
|
+
return Effect16.runPromise(scoped.pipe(Effect16.provide(FetchHttpClient3.layer)));
|
|
802
1080
|
};
|
|
803
1081
|
// src/openbao/cloudflare-role.ts
|
|
804
1082
|
import { Resource as Resource3 } from "alchemy";
|
|
805
1083
|
import { isResolved as isResolved3 } from "alchemy/Diff";
|
|
806
1084
|
import * as Provider3 from "alchemy/Provider";
|
|
807
|
-
import * as
|
|
1085
|
+
import * as Effect19 from "effect/Effect";
|
|
808
1086
|
|
|
809
1087
|
// src/openbao/cloudflare-group-scope.ts
|
|
810
1088
|
var zoneResource = (zoneId) => `com.cloudflare.api.account.zone.${zoneId}`;
|
|
@@ -824,7 +1102,7 @@ var groupKey = (name, scope) => `${scope} ${name}`;
|
|
|
824
1102
|
|
|
825
1103
|
// src/openbao/cloudflare-permission-groups.ts
|
|
826
1104
|
import * as Context2 from "effect/Context";
|
|
827
|
-
import * as
|
|
1105
|
+
import * as Effect18 from "effect/Effect";
|
|
828
1106
|
|
|
829
1107
|
// src/openbao/cloudflare-permission-groups-solve.ts
|
|
830
1108
|
var observationsOf = (declared, live) => declared.flatMap((role) => {
|
|
@@ -994,7 +1272,7 @@ var samePolicies2 = (want, have) => want.length === have.length && want.every((w
|
|
|
994
1272
|
});
|
|
995
1273
|
|
|
996
1274
|
// src/openbao/cloudflare-role-wire.ts
|
|
997
|
-
import * as
|
|
1275
|
+
import * as Effect17 from "effect/Effect";
|
|
998
1276
|
|
|
999
1277
|
// src/openbao/cloudflare-role-form.ts
|
|
1000
1278
|
var rolePath = (mount, name) => `${mountPath(mount)}/roles/${name}`;
|
|
@@ -1059,7 +1337,7 @@ var differences = (props, policies, live) => {
|
|
|
1059
1337
|
};
|
|
1060
1338
|
|
|
1061
1339
|
// src/openbao/cloudflare-role-wire.ts
|
|
1062
|
-
var readCloudflareRole = (mount, name) =>
|
|
1340
|
+
var readCloudflareRole = (mount, name) => Effect17.map(baoRead(rolePath(mount, name)), (data) => data === undefined ? undefined : liveRoleOf(data));
|
|
1063
1341
|
var writeCloudflareRole = (mount, name, body) => baoWrite("PUT", rolePath(mount, name), body);
|
|
1064
1342
|
var deleteCloudflareRole = (mount, name) => baoDelete(rolePath(mount, name));
|
|
1065
1343
|
|
|
@@ -1081,9 +1359,9 @@ var pick = (mount, groups, refs, hint) => {
|
|
|
1081
1359
|
const unknown = refs.filter((ref) => !groups.has(groupKey(ref.name, ref.scope)));
|
|
1082
1360
|
if (unknown.length > 0) {
|
|
1083
1361
|
const problems = unknown.map((ref) => `unknown group ${JSON.stringify(ref.name)} at scope ${ref.scope} — ${hint}`);
|
|
1084
|
-
return
|
|
1362
|
+
return Effect18.fail(new CloudflareGroupsError(mount, problems));
|
|
1085
1363
|
}
|
|
1086
|
-
return
|
|
1364
|
+
return Effect18.succeed(new Map(refs.flatMap((ref) => {
|
|
1087
1365
|
const key = groupKey(ref.name, ref.scope);
|
|
1088
1366
|
const id = groups.get(key);
|
|
1089
1367
|
return id === undefined ? [] : [[key, id]];
|
|
@@ -1091,15 +1369,15 @@ var pick = (mount, groups, refs, hint) => {
|
|
|
1091
1369
|
};
|
|
1092
1370
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1093
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";
|
|
1094
|
-
var deniedNamed = (mount, read) =>
|
|
1095
|
-
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) => {
|
|
1096
1374
|
const list = data?.["permission_groups"];
|
|
1097
1375
|
if (data === undefined) {
|
|
1098
1376
|
const why = "GET <mount>/permission-groups answered 404 — the endpoint is not deployed here";
|
|
1099
|
-
return
|
|
1377
|
+
return Effect18.fail(new CloudflareGroupsError(mount, [why]));
|
|
1100
1378
|
}
|
|
1101
1379
|
if (!Array.isArray(list)) {
|
|
1102
|
-
return
|
|
1380
|
+
return Effect18.fail(new CloudflareGroupsError(mount, ["no permission_groups array in reply"]));
|
|
1103
1381
|
}
|
|
1104
1382
|
const scoped = new Map;
|
|
1105
1383
|
const idsOf = new Map;
|
|
@@ -1126,24 +1404,24 @@ var engineGroups = (mount) => Effect11.flatMap(deniedNamed(mount, baoRead(`${mou
|
|
|
1126
1404
|
const only = [...ids];
|
|
1127
1405
|
return ids.size === 1 && only[0] !== undefined ? [[name, only[0]]] : [];
|
|
1128
1406
|
}));
|
|
1129
|
-
return problems.length > 0 ?
|
|
1407
|
+
return problems.length > 0 ? Effect18.fail(new CloudflareGroupsError(mount, problems)) : Effect18.succeed(new Map([...atEveryScope(sole), ...scoped]));
|
|
1130
1408
|
});
|
|
1131
|
-
var permissionGroupsFromEngine = () =>
|
|
1409
|
+
var permissionGroupsFromEngine = () => Effect18.sync(() => {
|
|
1132
1410
|
const cache = new Map;
|
|
1133
|
-
const cachedFor = (mount) =>
|
|
1411
|
+
const cachedFor = (mount) => Effect18.suspend(() => {
|
|
1134
1412
|
const hit = cache.get(mountPath(mount));
|
|
1135
1413
|
if (hit !== undefined)
|
|
1136
1414
|
return hit;
|
|
1137
|
-
return
|
|
1415
|
+
return Effect18.flatMap(Effect18.cached(engineGroups(mount)), (lookup) => {
|
|
1138
1416
|
cache.set(mountPath(mount), lookup);
|
|
1139
1417
|
return lookup;
|
|
1140
1418
|
});
|
|
1141
1419
|
});
|
|
1142
1420
|
return CloudflarePermissionGroups.of({
|
|
1143
|
-
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"))
|
|
1144
1422
|
});
|
|
1145
1423
|
});
|
|
1146
|
-
var permissionGroupsFromLiveRoles = (declared) =>
|
|
1424
|
+
var permissionGroupsFromLiveRoles = (declared) => Effect18.gen(function* () {
|
|
1147
1425
|
const accountOf = new Map;
|
|
1148
1426
|
const byAccount = new Map;
|
|
1149
1427
|
for (const [mount, roles] of declared) {
|
|
@@ -1154,9 +1432,9 @@ var permissionGroupsFromLiveRoles = (declared) => Effect11.gen(function* () {
|
|
|
1154
1432
|
}
|
|
1155
1433
|
const solved = new Map;
|
|
1156
1434
|
for (const [account, roles] of byAccount) {
|
|
1157
|
-
const solve =
|
|
1435
|
+
const solve = Effect18.gen(function* () {
|
|
1158
1436
|
const live = new Map;
|
|
1159
|
-
yield*
|
|
1437
|
+
yield* Effect18.all(roles.map((role) => Effect18.map(readCloudflareRole(role.mount, role.name), (read) => {
|
|
1160
1438
|
if (read?.policies !== undefined) {
|
|
1161
1439
|
live.set(`${role.mount}/${role.name}`, read.policies);
|
|
1162
1440
|
}
|
|
@@ -1164,11 +1442,11 @@ var permissionGroupsFromLiveRoles = (declared) => Effect11.gen(function* () {
|
|
|
1164
1442
|
const result = solveGroups(observationsOf(roles, live));
|
|
1165
1443
|
const problems = describeProblems(result);
|
|
1166
1444
|
if (problems.length > 0) {
|
|
1167
|
-
return yield*
|
|
1445
|
+
return yield* Effect18.fail(new CloudflareGroupsError(`account ${account}`, problems));
|
|
1168
1446
|
}
|
|
1169
1447
|
return atEveryScope(result.groups);
|
|
1170
1448
|
});
|
|
1171
|
-
solved.set(account, yield*
|
|
1449
|
+
solved.set(account, yield* Effect18.cached(solve));
|
|
1172
1450
|
}
|
|
1173
1451
|
return CloudflarePermissionGroups.of({
|
|
1174
1452
|
resolve: (mount, refs) => {
|
|
@@ -1176,54 +1454,22 @@ var permissionGroupsFromLiveRoles = (declared) => Effect11.gen(function* () {
|
|
|
1176
1454
|
const lookup = account === undefined ? undefined : solved.get(account);
|
|
1177
1455
|
if (account === undefined || lookup === undefined) {
|
|
1178
1456
|
const why = "no declared role on this mount, so no live role can vouch for its groups";
|
|
1179
|
-
return
|
|
1457
|
+
return Effect18.fail(new CloudflareGroupsError(mount, [why]));
|
|
1180
1458
|
}
|
|
1181
1459
|
const hint = `no live role on account ${account} carries it; a NEW group needs the engine endpoint`;
|
|
1182
|
-
return
|
|
1460
|
+
return Effect18.flatMap(lookup, (groups) => pick(mount, groups, refs, hint));
|
|
1183
1461
|
}
|
|
1184
1462
|
});
|
|
1185
1463
|
});
|
|
1186
1464
|
|
|
1187
|
-
// src/openbao/rename.ts
|
|
1188
|
-
import * as Effect12 from "effect/Effect";
|
|
1189
|
-
var exact = (identity) => identity;
|
|
1190
|
-
var declaredString = (news, key) => {
|
|
1191
|
-
if (typeof news !== "object" || news === null)
|
|
1192
|
-
return;
|
|
1193
|
-
const value = news[key];
|
|
1194
|
-
return typeof value === "string" ? value : undefined;
|
|
1195
|
-
};
|
|
1196
|
-
var isPendingProp = (news, key) => {
|
|
1197
|
-
if (typeof news !== "object" || news === null)
|
|
1198
|
-
return false;
|
|
1199
|
-
const value = news[key];
|
|
1200
|
-
return value !== undefined && typeof value !== "string";
|
|
1201
|
-
};
|
|
1202
|
-
var declaredRolePath = (news, rolePath2) => {
|
|
1203
|
-
const mount = declaredString(news, "mount");
|
|
1204
|
-
const name = declaredString(news, "name");
|
|
1205
|
-
return mount === undefined || name === undefined ? undefined : rolePath2(mount, name);
|
|
1206
|
-
};
|
|
1207
|
-
var policyKey = (name) => name.trim().toLowerCase();
|
|
1208
|
-
var isMoved = (stored, declared, key = exact) => declared === undefined ? undefined : key(stored) !== key(declared);
|
|
1209
|
-
var triedRolePath = (output, olds, rolePath2) => output === undefined ? declaredRolePath(olds, rolePath2) : rolePath2(output.mount, output.name);
|
|
1210
|
-
var judgeMove = (family, tried, declared, pathOf, key = exact) => Effect12.gen(function* () {
|
|
1211
|
-
if (tried === undefined || declared === undefined || key(tried) === key(declared)) {
|
|
1212
|
-
return;
|
|
1213
|
-
}
|
|
1214
|
-
if ((yield* baoRead(pathOf(declared))) === undefined)
|
|
1215
|
-
return { from: tried, to: declared };
|
|
1216
|
-
return yield* Effect12.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.`));
|
|
1217
|
-
});
|
|
1218
|
-
var refuseMovedUpdate = (family, from, to) => Effect12.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."));
|
|
1219
|
-
|
|
1220
1465
|
// src/openbao/cloudflare-role.ts
|
|
1221
1466
|
var BaoCloudflareRole = Resource3("Bao.CloudflareRole", {
|
|
1222
1467
|
defaultRemovalPolicy: "retain"
|
|
1223
1468
|
});
|
|
1224
|
-
var
|
|
1469
|
+
var IDENTITY2 = roleIdentity("Bao.CloudflareRole", rolePath);
|
|
1470
|
+
var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect19.gen(function* () {
|
|
1225
1471
|
const groups = yield* CloudflarePermissionGroups;
|
|
1226
|
-
const resolved = (props) =>
|
|
1472
|
+
const resolved = (props) => Effect19.gen(function* () {
|
|
1227
1473
|
const refs = new Map;
|
|
1228
1474
|
for (const policy of props.policies) {
|
|
1229
1475
|
const scope = policy.scope ?? scopeOfResource(policy.resource);
|
|
@@ -1233,20 +1479,24 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1233
1479
|
const ids = yield* groups.resolve(props.mount, [...refs.values()]);
|
|
1234
1480
|
const { missing, policies } = resolvePolicies(props.policies, ids);
|
|
1235
1481
|
if (missing.length > 0) {
|
|
1236
|
-
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.`));
|
|
1237
1483
|
}
|
|
1238
1484
|
return policies;
|
|
1239
1485
|
});
|
|
1240
1486
|
return BaoCloudflareRole.Provider.of({
|
|
1241
|
-
list: () =>
|
|
1242
|
-
read:
|
|
1487
|
+
list: () => Effect19.succeed([]),
|
|
1488
|
+
read: Effect19.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
1243
1489
|
const live = yield* readCloudflareRole(olds.mount, olds.name);
|
|
1244
|
-
|
|
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);
|
|
1245
1497
|
}),
|
|
1246
|
-
diff:
|
|
1247
|
-
const
|
|
1248
|
-
const declared = declaredRolePath(news, rolePath);
|
|
1249
|
-
const move = yield* judgeMove("Bao.CloudflareRole", tried, declared, (path) => path);
|
|
1498
|
+
diff: Effect19.fn(function* ({ news, olds, output }) {
|
|
1499
|
+
const move = yield* judgeRename(IDENTITY2, olds, news, output);
|
|
1250
1500
|
if (output === undefined)
|
|
1251
1501
|
return;
|
|
1252
1502
|
if (move !== undefined)
|
|
@@ -1261,37 +1511,37 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1261
1511
|
return { action: "update" };
|
|
1262
1512
|
return differences(news, policies, live).length === 0 ? { action: "noop" } : { action: "update" };
|
|
1263
1513
|
}),
|
|
1264
|
-
reconcile:
|
|
1514
|
+
reconcile: Effect19.fn(function* ({ fqn, instanceId, news, output }) {
|
|
1265
1515
|
const path = rolePath(news.mount, news.name);
|
|
1266
|
-
|
|
1267
|
-
if (isMoved(before, path) === true) {
|
|
1268
|
-
return yield* refuseMovedUpdate("Bao.CloudflareRole", before, path);
|
|
1269
|
-
}
|
|
1516
|
+
yield* guardRename(IDENTITY2, news, output);
|
|
1270
1517
|
const refusal2 = refusalOf(news);
|
|
1271
1518
|
if (refusal2 !== undefined) {
|
|
1272
|
-
return yield*
|
|
1519
|
+
return yield* Effect19.die(new Error(`Bao.CloudflareRole ${path}: ${refusal2}.`));
|
|
1273
1520
|
}
|
|
1274
1521
|
const policies = yield* resolved(news);
|
|
1275
1522
|
const live = yield* readCloudflareRole(news.mount, news.name);
|
|
1523
|
+
if (live !== undefined) {
|
|
1524
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.CloudflareRole ${path}`);
|
|
1525
|
+
}
|
|
1276
1526
|
if (live === undefined || differences(news, policies, live).length > 0) {
|
|
1277
1527
|
yield* writeCloudflareRole(news.mount, news.name, writeBody2(news, policies));
|
|
1278
1528
|
}
|
|
1279
1529
|
const after = yield* readCloudflareRole(news.mount, news.name);
|
|
1280
1530
|
if (after === undefined) {
|
|
1281
|
-
return yield*
|
|
1531
|
+
return yield* Effect19.die(new Error(`Bao.CloudflareRole ${path}: the write succeeded but the role is absent.`));
|
|
1282
1532
|
}
|
|
1283
1533
|
const left = differences(news, policies, after);
|
|
1284
1534
|
if (left.length > 0) {
|
|
1285
|
-
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.`));
|
|
1286
1536
|
}
|
|
1287
1537
|
return attributesOf4(news, after);
|
|
1288
1538
|
}),
|
|
1289
|
-
delete:
|
|
1539
|
+
delete: Effect19.fn(function* ({ output }) {
|
|
1290
1540
|
yield* deleteCloudflareRole(output.mount, output.name);
|
|
1291
1541
|
return;
|
|
1292
1542
|
})
|
|
1293
1543
|
});
|
|
1294
|
-
}));
|
|
1544
|
+
}).pipe(Effect19.map(provingResumes)));
|
|
1295
1545
|
// src/openbao/cloudflare-roles-expand.ts
|
|
1296
1546
|
var slug = (name) => trimRuns(name.toLowerCase().replace(/[^a-z0-9]+/g, "-"), "-");
|
|
1297
1547
|
var zoneSlug = (zone) => `${slug(zone.name)}${zone.internal ? "-internal" : ""}`;
|
|
@@ -1509,17 +1759,19 @@ var hostAppRoles = (input) => {
|
|
|
1509
1759
|
if (!NAME.test(host.name)) {
|
|
1510
1760
|
problems.push(`host \`${host.name}\` is not lowercase letters, digits, single hyphens`);
|
|
1511
1761
|
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1762
|
+
const name = hostRoleName(host.class, host.name);
|
|
1763
|
+
if (seen.has(name)) {
|
|
1764
|
+
problems.push(`host \`${host.name}\` is listed twice in class \`${host.class}\``);
|
|
1765
|
+
}
|
|
1766
|
+
seen.add(name);
|
|
1767
|
+
const spec = Object.hasOwn(input.classes, host.class) ? input.classes[host.class] : undefined;
|
|
1516
1768
|
if (spec === undefined) {
|
|
1517
1769
|
problems.push(`host \`${host.name}\` names unknown class \`${host.class}\``);
|
|
1518
1770
|
continue;
|
|
1519
1771
|
}
|
|
1520
1772
|
roles.push({
|
|
1521
1773
|
bindSecretId: true,
|
|
1522
|
-
name
|
|
1774
|
+
name,
|
|
1523
1775
|
secretIdNumUses: spec.secretIdNumUses ?? 0,
|
|
1524
1776
|
secretIdTtl: spec.secretIdTtl,
|
|
1525
1777
|
tokenMaxTtl: spec.tokenMaxTtl,
|
|
@@ -1536,7 +1788,7 @@ var hostAppRoles = (input) => {
|
|
|
1536
1788
|
import { Resource as Resource4 } from "alchemy";
|
|
1537
1789
|
import { isResolved as isResolved4 } from "alchemy/Diff";
|
|
1538
1790
|
import * as Provider4 from "alchemy/Provider";
|
|
1539
|
-
import * as
|
|
1791
|
+
import * as Effect21 from "effect/Effect";
|
|
1540
1792
|
|
|
1541
1793
|
// src/openbao/jwt-config-form.ts
|
|
1542
1794
|
var text5 = (value) => typeof value === "string" ? value.trim() : "";
|
|
@@ -1626,19 +1878,25 @@ var problems = (props) => {
|
|
|
1626
1878
|
};
|
|
1627
1879
|
|
|
1628
1880
|
// src/openbao/role-reconcile.ts
|
|
1629
|
-
import * as
|
|
1630
|
-
var readRoleAt = (spec) =>
|
|
1631
|
-
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* () {
|
|
1632
1888
|
if (spec.problems.length > 0)
|
|
1633
1889
|
return "update";
|
|
1634
1890
|
const found = yield* readRoleAt(spec);
|
|
1635
1891
|
return found !== undefined && spec.matches(found.attributes) ? "noop" : "update";
|
|
1636
1892
|
});
|
|
1637
|
-
var refuse2 = (spec, message) =>
|
|
1638
|
-
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* () {
|
|
1639
1895
|
if (spec.problems.length > 0)
|
|
1640
1896
|
return yield* refuse2(spec, spec.problems.join("; "));
|
|
1641
1897
|
const found = yield* readRoleAt(spec);
|
|
1898
|
+
if (found !== undefined && claim !== undefined)
|
|
1899
|
+
yield* claim(`${spec.family} ${spec.path}`);
|
|
1642
1900
|
if (found === undefined || !spec.matches(found.attributes)) {
|
|
1643
1901
|
const lost = found === undefined ? [] : spec.wouldErase?.(found.live) ?? [];
|
|
1644
1902
|
if (lost.length > 0) {
|
|
@@ -1659,6 +1917,14 @@ var reconcileRole = (spec) => Effect14.gen(function* () {
|
|
|
1659
1917
|
var BaoJwtAuthConfig = Resource4("Bao.JwtAuthConfig", {
|
|
1660
1918
|
defaultRemovalPolicy: "retain"
|
|
1661
1919
|
});
|
|
1920
|
+
var IDENTITY3 = {
|
|
1921
|
+
declared: (props) => {
|
|
1922
|
+
const mount = declaredOr(props, "mount", "jwt");
|
|
1923
|
+
return mount === undefined ? undefined : configPath({ mount });
|
|
1924
|
+
},
|
|
1925
|
+
family: "Bao.JwtAuthConfig",
|
|
1926
|
+
recorded: (output) => configPath(output)
|
|
1927
|
+
};
|
|
1662
1928
|
var jwtConfigSpec = (props) => ({
|
|
1663
1929
|
attributesOf: (live) => attributesOf5(props, live),
|
|
1664
1930
|
body: writeBody3(props),
|
|
@@ -1668,29 +1934,32 @@ var jwtConfigSpec = (props) => ({
|
|
|
1668
1934
|
problems: problems(props),
|
|
1669
1935
|
wouldErase
|
|
1670
1936
|
});
|
|
1671
|
-
var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig,
|
|
1672
|
-
list: () =>
|
|
1673
|
-
read:
|
|
1674
|
-
|
|
1675
|
-
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));
|
|
1676
1941
|
}),
|
|
1677
|
-
diff:
|
|
1678
|
-
|
|
1942
|
+
diff: Effect21.fn(function* ({ news, olds, output }) {
|
|
1943
|
+
const move = yield* judgeRename(IDENTITY3, olds, news, output);
|
|
1944
|
+
if (output === undefined)
|
|
1679
1945
|
return;
|
|
1680
|
-
if (
|
|
1946
|
+
if (move !== undefined)
|
|
1681
1947
|
return { action: "replace" };
|
|
1948
|
+
if (!isResolved4(news))
|
|
1949
|
+
return;
|
|
1682
1950
|
return { action: yield* planRole(jwtConfigSpec(news)) };
|
|
1683
1951
|
}),
|
|
1684
|
-
reconcile:
|
|
1685
|
-
|
|
1952
|
+
reconcile: Effect21.fn(function* ({ fqn, instanceId, news, output }) {
|
|
1953
|
+
yield* guardRename(IDENTITY3, news, output);
|
|
1954
|
+
return yield* reconcileRole(jwtConfigSpec(news), claimFor({ fqn, instanceId, output }));
|
|
1686
1955
|
}),
|
|
1687
|
-
delete: () =>
|
|
1688
|
-
})));
|
|
1956
|
+
delete: () => Effect21.void
|
|
1957
|
+
})).pipe(Effect21.map(provingResumes)));
|
|
1689
1958
|
// src/openbao/jwt-role.ts
|
|
1690
1959
|
import { Resource as Resource5 } from "alchemy";
|
|
1691
1960
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1692
1961
|
import * as Provider5 from "alchemy/Provider";
|
|
1693
|
-
import * as
|
|
1962
|
+
import * as Effect22 from "effect/Effect";
|
|
1694
1963
|
|
|
1695
1964
|
// src/openbao/auth-token-form.ts
|
|
1696
1965
|
var sortedSet2 = (values) => [...new Set(values)].sort();
|
|
@@ -1892,6 +2161,7 @@ var problems2 = (props) => {
|
|
|
1892
2161
|
var BaoJwtRole = Resource5("Bao.JwtRole", {
|
|
1893
2162
|
defaultRemovalPolicy: "retain"
|
|
1894
2163
|
});
|
|
2164
|
+
var IDENTITY4 = roleIdentity("Bao.JwtRole", (mount, name) => rolePath2({ mount, name }), "jwt", foldName);
|
|
1895
2165
|
var jwtRoleSpec = (props) => ({
|
|
1896
2166
|
attributesOf: (live) => attributesOf6(props, live),
|
|
1897
2167
|
body: writeBody4(props),
|
|
@@ -1900,33 +2170,35 @@ var jwtRoleSpec = (props) => ({
|
|
|
1900
2170
|
path: rolePath2(props),
|
|
1901
2171
|
problems: problems2(props)
|
|
1902
2172
|
});
|
|
1903
|
-
var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole,
|
|
1904
|
-
list: () =>
|
|
1905
|
-
read:
|
|
1906
|
-
|
|
1907
|
-
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));
|
|
1908
2177
|
}),
|
|
1909
|
-
diff:
|
|
1910
|
-
|
|
2178
|
+
diff: Effect22.fn(function* ({ news, olds, output }) {
|
|
2179
|
+
const move = yield* judgeRename(IDENTITY4, olds, news, output);
|
|
2180
|
+
if (output === undefined)
|
|
1911
2181
|
return;
|
|
1912
|
-
if (
|
|
2182
|
+
if (move !== undefined)
|
|
1913
2183
|
return { action: "replace" };
|
|
1914
|
-
|
|
2184
|
+
if (!isResolved5(news))
|
|
2185
|
+
return;
|
|
1915
2186
|
return { action: yield* planRole(jwtRoleSpec(news)) };
|
|
1916
2187
|
}),
|
|
1917
|
-
reconcile:
|
|
1918
|
-
|
|
2188
|
+
reconcile: Effect22.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2189
|
+
yield* guardRename(IDENTITY4, news, output);
|
|
2190
|
+
return yield* reconcileRole(jwtRoleSpec(news), claimFor({ fqn, instanceId, output }));
|
|
1919
2191
|
}),
|
|
1920
|
-
delete:
|
|
2192
|
+
delete: Effect22.fn(function* ({ output }) {
|
|
1921
2193
|
yield* baoDelete(rolePath2(output));
|
|
1922
2194
|
return;
|
|
1923
2195
|
})
|
|
1924
|
-
})));
|
|
2196
|
+
})).pipe(Effect22.map(provingResumes)));
|
|
1925
2197
|
// src/openbao/kubernetes-role.ts
|
|
1926
2198
|
import { Resource as Resource6 } from "alchemy";
|
|
1927
2199
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1928
2200
|
import * as Provider6 from "alchemy/Provider";
|
|
1929
|
-
import * as
|
|
2201
|
+
import * as Effect23 from "effect/Effect";
|
|
1930
2202
|
|
|
1931
2203
|
// src/openbao/kubernetes-role-form.ts
|
|
1932
2204
|
var sortedSet4 = (values) => [...new Set(values)].sort();
|
|
@@ -1995,6 +2267,7 @@ var problems3 = (props) => {
|
|
|
1995
2267
|
var BaoKubernetesRole = Resource6("Bao.KubernetesRole", {
|
|
1996
2268
|
defaultRemovalPolicy: "retain"
|
|
1997
2269
|
});
|
|
2270
|
+
var IDENTITY5 = roleIdentity("Bao.KubernetesRole", (mount, name) => rolePath3({ mount, name }), "kubernetes", foldName);
|
|
1998
2271
|
var kubernetesRoleSpec = (props) => ({
|
|
1999
2272
|
attributesOf: (live) => attributesOf7(props, live),
|
|
2000
2273
|
body: writeBody5(props),
|
|
@@ -2003,33 +2276,35 @@ var kubernetesRoleSpec = (props) => ({
|
|
|
2003
2276
|
path: rolePath3(props),
|
|
2004
2277
|
problems: problems3(props)
|
|
2005
2278
|
});
|
|
2006
|
-
var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole,
|
|
2007
|
-
list: () =>
|
|
2008
|
-
read:
|
|
2009
|
-
|
|
2010
|
-
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));
|
|
2011
2283
|
}),
|
|
2012
|
-
diff:
|
|
2013
|
-
|
|
2284
|
+
diff: Effect23.fn(function* ({ news, olds, output }) {
|
|
2285
|
+
const move = yield* judgeRename(IDENTITY5, olds, news, output);
|
|
2286
|
+
if (output === undefined)
|
|
2014
2287
|
return;
|
|
2015
|
-
if (
|
|
2288
|
+
if (move !== undefined)
|
|
2016
2289
|
return { action: "replace" };
|
|
2017
|
-
|
|
2290
|
+
if (!isResolved6(news))
|
|
2291
|
+
return;
|
|
2018
2292
|
return { action: yield* planRole(kubernetesRoleSpec(news)) };
|
|
2019
2293
|
}),
|
|
2020
|
-
reconcile:
|
|
2021
|
-
|
|
2294
|
+
reconcile: Effect23.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2295
|
+
yield* guardRename(IDENTITY5, news, output);
|
|
2296
|
+
return yield* reconcileRole(kubernetesRoleSpec(news), claimFor({ fqn, instanceId, output }));
|
|
2022
2297
|
}),
|
|
2023
|
-
delete:
|
|
2298
|
+
delete: Effect23.fn(function* ({ output }) {
|
|
2024
2299
|
yield* baoDelete(rolePath3(output));
|
|
2025
2300
|
return;
|
|
2026
2301
|
})
|
|
2027
|
-
})));
|
|
2302
|
+
})).pipe(Effect23.map(provingResumes)));
|
|
2028
2303
|
// src/openbao/mfa-enforcement.ts
|
|
2029
2304
|
import { Resource as Resource7 } from "alchemy";
|
|
2030
2305
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2031
2306
|
import * as Provider7 from "alchemy/Provider";
|
|
2032
|
-
import * as
|
|
2307
|
+
import * as Effect25 from "effect/Effect";
|
|
2033
2308
|
|
|
2034
2309
|
// src/openbao/mfa-enforcement-form.ts
|
|
2035
2310
|
var sortedSet5 = (values) => [...new Set(values.map((value) => value.trim()))].filter((value) => value !== "").sort();
|
|
@@ -2097,16 +2372,16 @@ var problems4 = (props, missingPaths) => {
|
|
|
2097
2372
|
};
|
|
2098
2373
|
|
|
2099
2374
|
// src/openbao/mfa-wire.ts
|
|
2100
|
-
import * as
|
|
2375
|
+
import * as Effect24 from "effect/Effect";
|
|
2101
2376
|
var TOTP_PATH = "identity/mfa/method/totp";
|
|
2102
2377
|
var METHODS_PATH = "identity/mfa/method";
|
|
2103
2378
|
var enforcementPath = (name) => `identity/mfa/login-enforcement/${name}`;
|
|
2104
2379
|
var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
2105
|
-
var ownNamespacePath =
|
|
2380
|
+
var ownNamespacePath = Effect24.gen(function* () {
|
|
2106
2381
|
const env = yield* BaoEnv;
|
|
2107
2382
|
return namespacePath(envNamespace(env));
|
|
2108
2383
|
});
|
|
2109
|
-
var findTotp = (name) =>
|
|
2384
|
+
var findTotp = (name) => Effect24.gen(function* () {
|
|
2110
2385
|
const listing = yield* baoRead(`${METHODS_PATH}?list=true`);
|
|
2111
2386
|
const info = record4(listing?.["key_info"]) ?? {};
|
|
2112
2387
|
const own = yield* ownNamespacePath;
|
|
@@ -2115,17 +2390,17 @@ var findTotp = (name) => Effect18.gen(function* () {
|
|
|
2115
2390
|
if (live === undefined || live["name"] !== name || live["namespace_path"] !== own)
|
|
2116
2391
|
continue;
|
|
2117
2392
|
if (live["type"] !== "totp") {
|
|
2118
|
-
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.`));
|
|
2119
2394
|
}
|
|
2120
2395
|
return { id, live };
|
|
2121
2396
|
}
|
|
2122
2397
|
return;
|
|
2123
2398
|
});
|
|
2124
|
-
var writeTotp = (body) =>
|
|
2399
|
+
var writeTotp = (body) => Effect24.asVoid(baoCall("write", "POST", TOTP_PATH, body));
|
|
2125
2400
|
var deleteTotp = (id) => baoDelete(`${TOTP_PATH}/${id}`);
|
|
2126
2401
|
var readEnforcement = (name) => baoRead(enforcementPath(name));
|
|
2127
|
-
var writeEnforcement = (name, body) =>
|
|
2128
|
-
var authAccessors = (paths) =>
|
|
2402
|
+
var writeEnforcement = (name, body) => Effect24.asVoid(baoCall("write", "POST", enforcementPath(name), body));
|
|
2403
|
+
var authAccessors = (paths) => Effect24.gen(function* () {
|
|
2129
2404
|
if (paths.length === 0)
|
|
2130
2405
|
return { accessors: [], missing: [] };
|
|
2131
2406
|
const table = (yield* baoRead("sys/auth")) ?? {};
|
|
@@ -2145,24 +2420,28 @@ var authAccessors = (paths) => Effect18.gen(function* () {
|
|
|
2145
2420
|
var BaoMfaLoginEnforcement = Resource7("Bao.MfaLoginEnforcement", {
|
|
2146
2421
|
defaultRemovalPolicy: "retain"
|
|
2147
2422
|
});
|
|
2148
|
-
var
|
|
2149
|
-
var
|
|
2423
|
+
var IDENTITY6 = nameIdentity("Bao.MfaLoginEnforcement", enforcementPath);
|
|
2424
|
+
var refuse3 = (name, message) => Effect25.die(new Error(`Bao.MfaLoginEnforcement ${name}: ${message}`));
|
|
2425
|
+
var resolveTargets = (props) => Effect25.map(authAccessors(props.authMethodPaths ?? []), ({ accessors, missing }) => ({
|
|
2150
2426
|
bad: problems4(props, missing),
|
|
2151
2427
|
resolved: accessors
|
|
2152
2428
|
}));
|
|
2153
|
-
var readLive = (name) =>
|
|
2154
|
-
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* () {
|
|
2155
2431
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2156
2432
|
if (bad.length > 0)
|
|
2157
2433
|
return "update";
|
|
2158
2434
|
const live = yield* readLive(props.name);
|
|
2159
2435
|
return live !== undefined && matches7(live, props, resolved) ? "noop" : "update";
|
|
2160
2436
|
});
|
|
2161
|
-
var reconcileEnforcement = (props) =>
|
|
2437
|
+
var reconcileEnforcement = (props, claim) => Effect25.gen(function* () {
|
|
2162
2438
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2163
2439
|
if (bad.length > 0)
|
|
2164
2440
|
return yield* refuse3(props.name, bad.join("; "));
|
|
2165
2441
|
const live = yield* readLive(props.name);
|
|
2442
|
+
if (live !== undefined && claim !== undefined) {
|
|
2443
|
+
yield* claim(`Bao.MfaLoginEnforcement ${props.name}`);
|
|
2444
|
+
}
|
|
2166
2445
|
if (live === undefined || !matches7(live, props, resolved)) {
|
|
2167
2446
|
yield* writeEnforcement(props.name, writeBody6(canonicalFromProps4(props, resolved)));
|
|
2168
2447
|
}
|
|
@@ -2174,30 +2453,36 @@ var reconcileEnforcement = (props) => Effect19.gen(function* () {
|
|
|
2174
2453
|
}
|
|
2175
2454
|
return after;
|
|
2176
2455
|
});
|
|
2177
|
-
var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforcement,
|
|
2178
|
-
list: () =>
|
|
2179
|
-
read:
|
|
2180
|
-
|
|
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);
|
|
2181
2462
|
}),
|
|
2182
|
-
diff:
|
|
2183
|
-
|
|
2463
|
+
diff: Effect25.fn(function* ({ news, olds, output }) {
|
|
2464
|
+
const move = yield* judgeRename(IDENTITY6, olds, news, output);
|
|
2465
|
+
if (output === undefined)
|
|
2184
2466
|
return;
|
|
2185
|
-
if (
|
|
2467
|
+
if (move !== undefined)
|
|
2186
2468
|
return { action: "replace" };
|
|
2469
|
+
if (!isResolved7(news))
|
|
2470
|
+
return;
|
|
2187
2471
|
return { action: yield* planEnforcement(news) };
|
|
2188
2472
|
}),
|
|
2189
|
-
reconcile:
|
|
2190
|
-
|
|
2473
|
+
reconcile: Effect25.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2474
|
+
yield* guardRename(IDENTITY6, news, output);
|
|
2475
|
+
return yield* reconcileEnforcement(news, claimFor({ fqn, instanceId, output }));
|
|
2191
2476
|
}),
|
|
2192
|
-
delete:
|
|
2477
|
+
delete: Effect25.fn(function* ({ output }) {
|
|
2193
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.");
|
|
2194
2479
|
})
|
|
2195
|
-
})));
|
|
2480
|
+
})).pipe(Effect25.map(provingResumes)));
|
|
2196
2481
|
// src/openbao/mfa-totp.ts
|
|
2197
2482
|
import { Resource as Resource8 } from "alchemy";
|
|
2198
2483
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2199
2484
|
import * as Provider8 from "alchemy/Provider";
|
|
2200
|
-
import * as
|
|
2485
|
+
import * as Effect26 from "effect/Effect";
|
|
2201
2486
|
|
|
2202
2487
|
// src/openbao/mfa-totp-form.ts
|
|
2203
2488
|
var canonical6 = (input) => ({
|
|
@@ -2278,71 +2563,83 @@ var problems5 = (props) => {
|
|
|
2278
2563
|
var BaoMfaTotpMethod = Resource8("Bao.MfaTotpMethod", {
|
|
2279
2564
|
defaultRemovalPolicy: "retain"
|
|
2280
2565
|
});
|
|
2281
|
-
var refuse4 = (
|
|
2282
|
-
var readTotp = (props) =>
|
|
2283
|
-
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* () {
|
|
2284
2569
|
if (problems5(props).length > 0)
|
|
2285
2570
|
return "update";
|
|
2286
2571
|
const live = yield* readTotp(props);
|
|
2287
2572
|
return live !== undefined && matches8(live, props) ? "noop" : "update";
|
|
2288
2573
|
});
|
|
2289
|
-
var reconcileTotp = (props) =>
|
|
2574
|
+
var reconcileTotp = (props, claim) => Effect26.gen(function* () {
|
|
2290
2575
|
const bad = problems5(props);
|
|
2291
2576
|
if (bad.length > 0)
|
|
2292
|
-
return yield* refuse4(props, bad.join("; "));
|
|
2577
|
+
return yield* refuse4(props.name, bad.join("; "));
|
|
2293
2578
|
const live = yield* readTotp(props);
|
|
2579
|
+
if (live !== undefined && claim !== undefined)
|
|
2580
|
+
yield* claim(`Bao.MfaTotpMethod ${props.name}`);
|
|
2294
2581
|
if (live === undefined || !matches8(live, props))
|
|
2295
2582
|
yield* writeTotp(writeBody7(props));
|
|
2296
2583
|
const after = yield* readTotp(props);
|
|
2297
2584
|
if (after === undefined)
|
|
2298
|
-
return yield* refuse4(props, "the write succeeded but no method has that name.");
|
|
2585
|
+
return yield* refuse4(props.name, "the write succeeded but no method has that name.");
|
|
2299
2586
|
if (!matches8(after, props))
|
|
2300
|
-
return yield* refuse4(props, "the method read back different.");
|
|
2587
|
+
return yield* refuse4(props.name, "the method read back different.");
|
|
2301
2588
|
return after;
|
|
2302
2589
|
});
|
|
2303
|
-
var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod,
|
|
2304
|
-
list: () =>
|
|
2305
|
-
read:
|
|
2306
|
-
|
|
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);
|
|
2307
2596
|
}),
|
|
2308
|
-
diff:
|
|
2309
|
-
|
|
2597
|
+
diff: Effect26.fn(function* ({ news, output }) {
|
|
2598
|
+
const name = declaredString(news, "name");
|
|
2599
|
+
if (output !== undefined && name !== undefined) {
|
|
2600
|
+
const rename = renameProblem(output.name, name);
|
|
2601
|
+
if (rename !== undefined)
|
|
2602
|
+
return yield* refuse4(name, rename);
|
|
2603
|
+
}
|
|
2604
|
+
if (output === undefined)
|
|
2605
|
+
return;
|
|
2606
|
+
if (!isResolved8(news))
|
|
2310
2607
|
return;
|
|
2311
|
-
const rename = renameProblem(output.name, news.name);
|
|
2312
|
-
if (rename !== undefined)
|
|
2313
|
-
return yield* refuse4(news, rename);
|
|
2314
2608
|
return { action: yield* planTotp(news) };
|
|
2315
2609
|
}),
|
|
2316
|
-
reconcile:
|
|
2317
|
-
|
|
2610
|
+
reconcile: Effect26.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2611
|
+
const rename = output === undefined ? undefined : renameProblem(output.name, news.name);
|
|
2612
|
+
if (rename !== undefined)
|
|
2613
|
+
return yield* refuse4(news.name, rename);
|
|
2614
|
+
return yield* reconcileTotp(news, claimFor({ fqn, instanceId, output }));
|
|
2318
2615
|
}),
|
|
2319
|
-
delete:
|
|
2616
|
+
delete: Effect26.fn(function* ({ output }) {
|
|
2320
2617
|
yield* deleteTotp(output.methodId);
|
|
2321
2618
|
return;
|
|
2322
2619
|
})
|
|
2323
|
-
})));
|
|
2620
|
+
})).pipe(Effect26.map(provingResumes)));
|
|
2324
2621
|
// src/openbao/mount.ts
|
|
2325
2622
|
import { Resource as Resource9 } from "alchemy";
|
|
2326
2623
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2327
2624
|
import * as Provider9 from "alchemy/Provider";
|
|
2328
|
-
import * as
|
|
2625
|
+
import * as Effect29 from "effect/Effect";
|
|
2329
2626
|
|
|
2330
2627
|
// src/openbao/mount-reconcile.ts
|
|
2331
|
-
import * as
|
|
2628
|
+
import * as Effect28 from "effect/Effect";
|
|
2332
2629
|
|
|
2333
2630
|
// src/openbao/mount-wire.ts
|
|
2334
|
-
import * as
|
|
2335
|
-
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, [
|
|
2336
2633
|
...asked.errors,
|
|
2337
2634
|
`sys/mounts could not confirm the mount is absent: ${listing.message}`
|
|
2338
|
-
])),
|
|
2339
|
-
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)));
|
|
2340
2637
|
var enableMount = (props) => baoWrite("POST", readPath(props.path), enableBody(props));
|
|
2341
2638
|
var tuneMount = (props) => baoWrite("POST", tunePath(props.path), tuneBody(props));
|
|
2342
2639
|
var disableMount = (path) => baoDelete(readPath(path));
|
|
2343
2640
|
|
|
2344
2641
|
// src/openbao/mount-reconcile.ts
|
|
2345
|
-
var readMount = (props) =>
|
|
2642
|
+
var readMount = (props) => Effect28.gen(function* () {
|
|
2346
2643
|
const live = yield* readMountData(props.path);
|
|
2347
2644
|
if (live === undefined)
|
|
2348
2645
|
return;
|
|
@@ -2355,10 +2652,16 @@ var moveTarget2 = (props) => ({
|
|
|
2355
2652
|
type: props.type,
|
|
2356
2653
|
wire: mountPath
|
|
2357
2654
|
});
|
|
2358
|
-
var reconcileMount = (news, stated, options) =>
|
|
2655
|
+
var reconcileMount = (news, stated, options, claim) => Effect28.gen(function* () {
|
|
2359
2656
|
const move = planMove("Bao.Mount", stated, news.path, news.remountFrom);
|
|
2360
2657
|
if (move.kind === "refuse")
|
|
2361
|
-
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
|
+
}
|
|
2362
2665
|
if (move.kind === "move")
|
|
2363
2666
|
yield* performMove(moveTarget2(news), move.from, options);
|
|
2364
2667
|
let live = yield* readMount(news);
|
|
@@ -2366,15 +2669,18 @@ var reconcileMount = (news, stated, options) => Effect22.gen(function* () {
|
|
|
2366
2669
|
yield* enableMount(news);
|
|
2367
2670
|
if (wantsTune(news))
|
|
2368
2671
|
yield* tuneMount(news);
|
|
2369
|
-
} else
|
|
2672
|
+
} else {
|
|
2370
2673
|
if (live.type !== news.type) {
|
|
2371
|
-
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."));
|
|
2372
2675
|
}
|
|
2373
|
-
|
|
2676
|
+
if (first !== undefined)
|
|
2677
|
+
yield* first(`Bao.Mount ${mountPath(news.path)}`);
|
|
2678
|
+
if (!matches(live, news))
|
|
2679
|
+
yield* tuneMount(news);
|
|
2374
2680
|
}
|
|
2375
2681
|
live = yield* readMount(news);
|
|
2376
2682
|
if (live === undefined) {
|
|
2377
|
-
return yield*
|
|
2683
|
+
return yield* Effect28.die(new Error(`Bao.Mount ${mountPath(news.path)}: write returned no error but the mount is still absent.`));
|
|
2378
2684
|
}
|
|
2379
2685
|
return live;
|
|
2380
2686
|
});
|
|
@@ -2383,17 +2689,21 @@ var reconcileMount = (news, stated, options) => Effect22.gen(function* () {
|
|
|
2383
2689
|
var BaoMount = Resource9("Bao.Mount", {
|
|
2384
2690
|
defaultRemovalPolicy: "retain"
|
|
2385
2691
|
});
|
|
2386
|
-
var BaoMountProvider = () => Provider9.effect(BaoMount,
|
|
2387
|
-
list: () =>
|
|
2388
|
-
read:
|
|
2389
|
-
|
|
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);
|
|
2390
2698
|
}),
|
|
2391
|
-
diff:
|
|
2392
|
-
if (output === undefined
|
|
2699
|
+
diff: Effect29.fn(function* ({ news, output }) {
|
|
2700
|
+
if (output === undefined)
|
|
2701
|
+
return;
|
|
2702
|
+
if (!isResolved9(news))
|
|
2393
2703
|
return;
|
|
2394
2704
|
const move = planMove("Bao.Mount", output.path, news.path, news.remountFrom);
|
|
2395
2705
|
if (move.kind === "refuse")
|
|
2396
|
-
return yield*
|
|
2706
|
+
return yield* Effect29.die(new Error(move.message));
|
|
2397
2707
|
if (move.kind === "move")
|
|
2398
2708
|
return { action: "update" };
|
|
2399
2709
|
const live = yield* readMount(news);
|
|
@@ -2405,19 +2715,20 @@ var BaoMountProvider = () => Provider9.effect(BaoMount, Effect23.succeed(BaoMoun
|
|
|
2405
2715
|
return { action: "noop" };
|
|
2406
2716
|
return { action: "update" };
|
|
2407
2717
|
}),
|
|
2408
|
-
reconcile:
|
|
2409
|
-
|
|
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);
|
|
2410
2721
|
}),
|
|
2411
|
-
delete:
|
|
2722
|
+
delete: Effect29.fn(function* ({ output }) {
|
|
2412
2723
|
yield* disableMount(output.path);
|
|
2413
2724
|
return;
|
|
2414
2725
|
})
|
|
2415
|
-
})));
|
|
2726
|
+
})).pipe(Effect29.map(provingResumes)));
|
|
2416
2727
|
// src/openbao/pki-role.ts
|
|
2417
2728
|
import { Resource as Resource10 } from "alchemy";
|
|
2418
2729
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2419
2730
|
import * as Provider10 from "alchemy/Provider";
|
|
2420
|
-
import * as
|
|
2731
|
+
import * as Effect30 from "effect/Effect";
|
|
2421
2732
|
|
|
2422
2733
|
// src/openbao/pki-role-canonical.ts
|
|
2423
2734
|
var DEFAULT_KEY_USAGE = [
|
|
@@ -2583,22 +2894,28 @@ var problems6 = (props) => {
|
|
|
2583
2894
|
var BaoPkiRole = Resource10("Bao.PkiRole", {
|
|
2584
2895
|
defaultRemovalPolicy: "retain"
|
|
2585
2896
|
});
|
|
2586
|
-
var
|
|
2897
|
+
var IDENTITY7 = roleIdentity("Bao.PkiRole", (mount, name) => rolePath4({ mount, name }), "pki");
|
|
2898
|
+
var readRole2 = (props) => Effect30.gen(function* () {
|
|
2587
2899
|
const live = yield* baoRead(rolePath4(props));
|
|
2588
2900
|
if (live === undefined)
|
|
2589
2901
|
return;
|
|
2590
2902
|
return attributesOf10(props, live);
|
|
2591
2903
|
});
|
|
2592
|
-
var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole,
|
|
2593
|
-
list: () =>
|
|
2594
|
-
read:
|
|
2595
|
-
|
|
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);
|
|
2596
2910
|
}),
|
|
2597
|
-
diff:
|
|
2598
|
-
|
|
2911
|
+
diff: Effect30.fn(function* ({ news, olds, output }) {
|
|
2912
|
+
const move = yield* judgeRename(IDENTITY7, olds, news, output);
|
|
2913
|
+
if (output === undefined)
|
|
2599
2914
|
return;
|
|
2600
|
-
if (
|
|
2915
|
+
if (move !== undefined)
|
|
2601
2916
|
return { action: "replace" };
|
|
2917
|
+
if (!isResolved10(news))
|
|
2918
|
+
return;
|
|
2602
2919
|
if (problems6(news).length > 0)
|
|
2603
2920
|
return { action: "update" };
|
|
2604
2921
|
const live = yield* readRole2(news);
|
|
@@ -2606,35 +2923,38 @@ var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect24.succeed(Ba
|
|
|
2606
2923
|
return { action: "update" };
|
|
2607
2924
|
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
2608
2925
|
}),
|
|
2609
|
-
reconcile:
|
|
2926
|
+
reconcile: Effect30.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2610
2927
|
const path = rolePath4(news);
|
|
2928
|
+
yield* guardRename(IDENTITY7, news, output);
|
|
2611
2929
|
const bad = problems6(news);
|
|
2612
2930
|
if (bad.length > 0) {
|
|
2613
|
-
return yield*
|
|
2931
|
+
return yield* Effect30.die(new Error(`Bao.PkiRole ${path}: ${bad.join(" ")}`));
|
|
2614
2932
|
}
|
|
2615
2933
|
const live = yield* readRole2(news);
|
|
2934
|
+
if (live !== undefined)
|
|
2935
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.PkiRole ${path}`);
|
|
2616
2936
|
if (live === undefined || !matches9(live, news)) {
|
|
2617
2937
|
yield* baoWrite("PUT", path, writeBody8(news));
|
|
2618
2938
|
}
|
|
2619
2939
|
const after = yield* readRole2(news);
|
|
2620
2940
|
if (after === undefined) {
|
|
2621
|
-
return yield*
|
|
2941
|
+
return yield* Effect30.die(new Error(`Bao.PkiRole ${path}: write reported success but the role is absent.`));
|
|
2622
2942
|
}
|
|
2623
2943
|
if (!matches9(after, news)) {
|
|
2624
|
-
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.`));
|
|
2625
2945
|
}
|
|
2626
2946
|
return after;
|
|
2627
2947
|
}),
|
|
2628
|
-
delete:
|
|
2948
|
+
delete: Effect30.fn(function* ({ output }) {
|
|
2629
2949
|
yield* baoDelete(rolePath4(output));
|
|
2630
2950
|
return;
|
|
2631
2951
|
})
|
|
2632
|
-
})));
|
|
2952
|
+
})).pipe(Effect30.map(provingResumes)));
|
|
2633
2953
|
// src/openbao/plugin.ts
|
|
2634
2954
|
import { Resource as Resource11 } from "alchemy";
|
|
2635
2955
|
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
2636
2956
|
import * as Provider11 from "alchemy/Provider";
|
|
2637
|
-
import * as
|
|
2957
|
+
import * as Effect32 from "effect/Effect";
|
|
2638
2958
|
|
|
2639
2959
|
// src/openbao/plugin-form.ts
|
|
2640
2960
|
var resolve = (props) => ({
|
|
@@ -2690,7 +3010,7 @@ var sameArgs = (want, have) => want.length === have.length && want.every((entry,
|
|
|
2690
3010
|
var matches10 = (attributes, form) => !attributes.builtin && attributes.version === form.version && attributes.sha256 === form.sha256 && attributes.command === form.command && sameArgs(form.args, attributes.args);
|
|
2691
3011
|
|
|
2692
3012
|
// src/openbao/plugin-reconcile.ts
|
|
2693
|
-
import * as
|
|
3013
|
+
import * as Effect31 from "effect/Effect";
|
|
2694
3014
|
|
|
2695
3015
|
// src/openbao/plugin-wire.ts
|
|
2696
3016
|
var readPluginData = (form) => baoRead(versionedPath(form.type, form.name, form.version));
|
|
@@ -2698,15 +3018,18 @@ var registerPlugin = (form) => baoWrite("PUT", catalogPath(form.type, form.name)
|
|
|
2698
3018
|
var deregisterPlugin = (type, name, version) => baoDelete(versionedPath(type, name, version));
|
|
2699
3019
|
|
|
2700
3020
|
// src/openbao/plugin-reconcile.ts
|
|
2701
|
-
var readEntry = (form) =>
|
|
2702
|
-
var refuse5 = (form, message) =>
|
|
2703
|
-
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
|
|
2704
|
-
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* () {
|
|
2705
3025
|
const form = resolve(props);
|
|
2706
3026
|
const bad = problems7(form);
|
|
2707
3027
|
if (bad.length > 0)
|
|
2708
3028
|
return yield* refuse5(form, bad.join("; "));
|
|
2709
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
|
+
}
|
|
2710
3033
|
if (found !== undefined && !matches10(found.attributes, form)) {
|
|
2711
3034
|
if (found.live["declarative"] === true || found.live["oci"] === true) {
|
|
2712
3035
|
return yield* refuse5(form, "the live entry is declarative/OCI; manage it in server config.");
|
|
@@ -2728,37 +3051,54 @@ var reconcilePlugin = (props) => Effect25.gen(function* () {
|
|
|
2728
3051
|
var BaoPlugin = Resource11("Bao.Plugin", {
|
|
2729
3052
|
defaultRemovalPolicy: "retain"
|
|
2730
3053
|
});
|
|
2731
|
-
var
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
const
|
|
2735
|
-
|
|
3054
|
+
var IDENTITY8 = {
|
|
3055
|
+
declared: (props) => {
|
|
3056
|
+
const type = declaredString(props, "type");
|
|
3057
|
+
const name = declaredString(props, "name");
|
|
3058
|
+
const version = declaredOr(props, "version", "");
|
|
3059
|
+
if (type === undefined || name === undefined || version === undefined)
|
|
3060
|
+
return;
|
|
3061
|
+
return versionedPath(type, name, version);
|
|
3062
|
+
},
|
|
3063
|
+
family: "Bao.Plugin",
|
|
3064
|
+
recorded: (output) => versionedPath(output.type, output.name, output.version)
|
|
3065
|
+
};
|
|
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);
|
|
2736
3073
|
}),
|
|
2737
|
-
diff:
|
|
2738
|
-
|
|
3074
|
+
diff: Effect32.fn(function* ({ news, olds, output }) {
|
|
3075
|
+
const move = yield* judgeRename(IDENTITY8, olds, news, output);
|
|
3076
|
+
if (output === undefined)
|
|
2739
3077
|
return;
|
|
2740
|
-
|
|
2741
|
-
if (output.name !== form.name || output.type !== form.type || output.version !== form.version) {
|
|
3078
|
+
if (move !== undefined)
|
|
2742
3079
|
return { action: "replace" };
|
|
2743
|
-
|
|
3080
|
+
if (!isResolved11(news))
|
|
3081
|
+
return;
|
|
3082
|
+
const form = resolve(news);
|
|
2744
3083
|
const found = yield* readEntry(form);
|
|
2745
3084
|
if (found === undefined)
|
|
2746
3085
|
return { action: "update" };
|
|
2747
3086
|
return matches10(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
2748
3087
|
}),
|
|
2749
|
-
reconcile:
|
|
2750
|
-
|
|
3088
|
+
reconcile: Effect32.fn(function* ({ fqn, instanceId, news, output }) {
|
|
3089
|
+
yield* guardRename(IDENTITY8, news, output);
|
|
3090
|
+
return yield* reconcilePlugin(news, claimFor({ fqn, instanceId, output }));
|
|
2751
3091
|
}),
|
|
2752
|
-
delete:
|
|
3092
|
+
delete: Effect32.fn(function* ({ output }) {
|
|
2753
3093
|
yield* deregisterPlugin(output.type, output.name, output.version);
|
|
2754
3094
|
return;
|
|
2755
3095
|
})
|
|
2756
|
-
})));
|
|
3096
|
+
})).pipe(Effect32.map(provingResumes)));
|
|
2757
3097
|
// src/openbao/policy.ts
|
|
2758
3098
|
import { Resource as Resource12 } from "alchemy";
|
|
2759
3099
|
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
2760
3100
|
import * as Provider12 from "alchemy/Provider";
|
|
2761
|
-
import * as
|
|
3101
|
+
import * as Effect34 from "effect/Effect";
|
|
2762
3102
|
import * as FileSystem from "effect/FileSystem";
|
|
2763
3103
|
import * as Path from "effect/Path";
|
|
2764
3104
|
|
|
@@ -2766,13 +3106,13 @@ import * as Path from "effect/Path";
|
|
|
2766
3106
|
var isEmptyAssembly = (parts, joined) => parts === 0 || !/^\s*path\s+"/m.test(joined);
|
|
2767
3107
|
|
|
2768
3108
|
// src/openbao/policy-wire.ts
|
|
2769
|
-
import * as
|
|
3109
|
+
import * as Effect33 from "effect/Effect";
|
|
2770
3110
|
var policyPath = (name) => `sys/policies/acl/${name}`;
|
|
2771
|
-
var readPolicy = (name) =>
|
|
3111
|
+
var readPolicy = (name) => Effect33.flatMap(baoRead(policyPath(name)), (data) => {
|
|
2772
3112
|
if (data === undefined)
|
|
2773
|
-
return
|
|
3113
|
+
return Effect33.succeed("");
|
|
2774
3114
|
const text11 = data["policy"];
|
|
2775
|
-
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"]));
|
|
2776
3116
|
});
|
|
2777
3117
|
var writePolicy = (name, hcl) => baoWrite("PUT", policyPath(name), { policy: hcl });
|
|
2778
3118
|
var deletePolicy = (name) => baoDelete(policyPath(name));
|
|
@@ -2781,6 +3121,7 @@ var deletePolicy = (name) => baoDelete(policyPath(name));
|
|
|
2781
3121
|
var BaoPolicy = Resource12("Bao.Policy", {
|
|
2782
3122
|
defaultRemovalPolicy: "retain"
|
|
2783
3123
|
});
|
|
3124
|
+
var IDENTITY9 = nameIdentity("Bao.Policy", policyPath, policyKey);
|
|
2784
3125
|
var grantsOf = (hcl) => (hcl.match(/^path /gm) ?? []).length;
|
|
2785
3126
|
var attributesOf12 = (name, hcl, parts) => ({
|
|
2786
3127
|
name,
|
|
@@ -2788,10 +3129,10 @@ var attributesOf12 = (name, hcl, parts) => ({
|
|
|
2788
3129
|
grants: grantsOf(hcl),
|
|
2789
3130
|
parts
|
|
2790
3131
|
});
|
|
2791
|
-
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy,
|
|
3132
|
+
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect34.gen(function* () {
|
|
2792
3133
|
const fs = yield* FileSystem.FileSystem;
|
|
2793
3134
|
const path = yield* Path.Path;
|
|
2794
|
-
const assemble = (dir) =>
|
|
3135
|
+
const assemble = (dir) => Effect34.gen(function* () {
|
|
2795
3136
|
const entries2 = (yield* fs.readDirectory(dir)).filter((f) => f.endsWith(".hcl")).sort();
|
|
2796
3137
|
let joined = "";
|
|
2797
3138
|
for (const f of entries2)
|
|
@@ -2800,15 +3141,15 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect28.gen(function
|
|
|
2800
3141
|
return { joined, parts: entries2.length };
|
|
2801
3142
|
});
|
|
2802
3143
|
return BaoPolicy.Provider.of({
|
|
2803
|
-
list: () =>
|
|
2804
|
-
read:
|
|
3144
|
+
list: () => Effect34.succeed([]),
|
|
3145
|
+
read: Effect34.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2805
3146
|
const live = yield* readPolicy(olds.name);
|
|
2806
|
-
|
|
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);
|
|
2807
3150
|
}),
|
|
2808
|
-
diff:
|
|
2809
|
-
const
|
|
2810
|
-
const declared = declaredString(news, "name");
|
|
2811
|
-
const move = yield* judgeMove("Bao.Policy", tried, declared, policyPath, policyKey);
|
|
3151
|
+
diff: Effect34.fn(function* ({ news, olds, output }) {
|
|
3152
|
+
const move = yield* judgeRename(IDENTITY9, olds, news, output);
|
|
2812
3153
|
if (output === undefined)
|
|
2813
3154
|
return;
|
|
2814
3155
|
if (move !== undefined)
|
|
@@ -2819,32 +3160,32 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect28.gen(function
|
|
|
2819
3160
|
const live = yield* readPolicy(news.name);
|
|
2820
3161
|
return live.length > 0 && sha256(live) === sha256(joined) ? { action: "noop" } : { action: "update" };
|
|
2821
3162
|
}),
|
|
2822
|
-
reconcile:
|
|
3163
|
+
reconcile: Effect34.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2823
3164
|
const name = news.name;
|
|
2824
|
-
|
|
2825
|
-
return yield* refuseMovedUpdate(`Bao.Policy ${name}`, output.name, name);
|
|
2826
|
-
}
|
|
3165
|
+
yield* guardRename(IDENTITY9, news, output);
|
|
2827
3166
|
const { joined, parts } = yield* assemble(news.fragments);
|
|
2828
3167
|
if (isEmptyAssembly(parts, joined))
|
|
2829
|
-
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.`));
|
|
2830
3169
|
const current = yield* readPolicy(name);
|
|
3170
|
+
if (current.length > 0)
|
|
3171
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.Policy ${name}`);
|
|
2831
3172
|
if (current.length > 0 && sha256(current) === sha256(joined)) {
|
|
2832
3173
|
return attributesOf12(name, joined, parts);
|
|
2833
3174
|
}
|
|
2834
3175
|
yield* writePolicy(name, joined);
|
|
2835
3176
|
return attributesOf12(name, joined, parts);
|
|
2836
3177
|
}),
|
|
2837
|
-
delete:
|
|
3178
|
+
delete: Effect34.fn(function* ({ output }) {
|
|
2838
3179
|
yield* deletePolicy(output.name);
|
|
2839
3180
|
return;
|
|
2840
3181
|
})
|
|
2841
3182
|
});
|
|
2842
|
-
}));
|
|
3183
|
+
}).pipe(Effect34.map(provingResumes)));
|
|
2843
3184
|
// src/openbao/proxmox-role.ts
|
|
2844
3185
|
import { Resource as Resource13 } from "alchemy";
|
|
2845
3186
|
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
2846
3187
|
import * as Provider13 from "alchemy/Provider";
|
|
2847
|
-
import * as
|
|
3188
|
+
import * as Effect36 from "effect/Effect";
|
|
2848
3189
|
|
|
2849
3190
|
// src/openbao/proxmox-role-form.ts
|
|
2850
3191
|
var text11 = (value) => typeof value === "string" ? value : "";
|
|
@@ -2894,8 +3235,8 @@ var rescopeRefusal = (before, mintUser, allowMintUserChange) => before === mintU
|
|
|
2894
3235
|
var matches11 = (attributes, props) => attributes.mintUser === props.mintUser && sameTtl5(props.ttl, attributes.ttl) && sameTtl5(props.maxTtl, attributes.maxTtl);
|
|
2895
3236
|
|
|
2896
3237
|
// src/openbao/proxmox-role-wire.ts
|
|
2897
|
-
import * as
|
|
2898
|
-
var readRole3 = (props) =>
|
|
3238
|
+
import * as Effect35 from "effect/Effect";
|
|
3239
|
+
var readRole3 = (props) => Effect35.gen(function* () {
|
|
2899
3240
|
const live = yield* baoRead(rolePath5(props.mount, props.name));
|
|
2900
3241
|
if (live === undefined)
|
|
2901
3242
|
return;
|
|
@@ -2906,15 +3247,16 @@ var readRole3 = (props) => Effect29.gen(function* () {
|
|
|
2906
3247
|
var BaoProxmoxRole = Resource13("Bao.ProxmoxRole", {
|
|
2907
3248
|
defaultRemovalPolicy: "retain"
|
|
2908
3249
|
});
|
|
2909
|
-
var
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
3250
|
+
var IDENTITY10 = roleIdentity("Bao.ProxmoxRole", rolePath5);
|
|
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);
|
|
2913
3257
|
}),
|
|
2914
|
-
diff:
|
|
2915
|
-
const
|
|
2916
|
-
const declared = declaredRolePath(news, rolePath5);
|
|
2917
|
-
const move = yield* judgeMove("Bao.ProxmoxRole", tried, declared, (path) => path);
|
|
3258
|
+
diff: Effect36.fn(function* ({ news, olds, output }) {
|
|
3259
|
+
const move = yield* judgeRename(IDENTITY10, olds, news, output);
|
|
2918
3260
|
if (output === undefined)
|
|
2919
3261
|
return;
|
|
2920
3262
|
if (move !== undefined) {
|
|
@@ -2926,7 +3268,7 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect30.su
|
|
|
2926
3268
|
const refusal2 = rescopeRefusal(from, mintUser, allow);
|
|
2927
3269
|
if (refusal2 === undefined)
|
|
2928
3270
|
return { action: "replace" };
|
|
2929
|
-
return yield*
|
|
3271
|
+
return yield* Effect36.die(new Error(`Bao.ProxmoxRole ${move.from} → ${move.to}: the rename ${refusal2}`));
|
|
2930
3272
|
}
|
|
2931
3273
|
if (!isResolved13(news))
|
|
2932
3274
|
return;
|
|
@@ -2937,40 +3279,39 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect30.su
|
|
|
2937
3279
|
return { action: "noop" };
|
|
2938
3280
|
return { action: "update" };
|
|
2939
3281
|
}),
|
|
2940
|
-
reconcile:
|
|
3282
|
+
reconcile: Effect36.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2941
3283
|
const path = rolePath5(news.mount, news.name);
|
|
2942
|
-
|
|
2943
|
-
if (isMoved(before, path) === true) {
|
|
2944
|
-
return yield* refuseMovedUpdate("Bao.ProxmoxRole", before, path);
|
|
2945
|
-
}
|
|
3284
|
+
yield* guardRename(IDENTITY10, news, output);
|
|
2946
3285
|
const live = yield* readRole3(news);
|
|
3286
|
+
if (live !== undefined)
|
|
3287
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.ProxmoxRole ${path}`);
|
|
2947
3288
|
const rescope = live === undefined ? undefined : rescopeRefusal(live.mintUser, news.mintUser, news.allowMintUserChange);
|
|
2948
3289
|
if (rescope !== undefined) {
|
|
2949
|
-
return yield*
|
|
3290
|
+
return yield* Effect36.die(new Error(`Bao.ProxmoxRole ${path}: ${rescope}`));
|
|
2950
3291
|
}
|
|
2951
3292
|
if (live === undefined || !matches11(live, news)) {
|
|
2952
3293
|
const write = writeBody9(news);
|
|
2953
3294
|
if (!write.ok) {
|
|
2954
|
-
return yield*
|
|
3295
|
+
return yield* Effect36.die(new Error(`Bao.ProxmoxRole ${path}: unparseable duration ` + `${write.bad.join(", ")}. Use 30s / 5m / 1h / 1d, or 0.`));
|
|
2955
3296
|
}
|
|
2956
3297
|
yield* baoWrite("PUT", path, write.body);
|
|
2957
3298
|
}
|
|
2958
3299
|
const after = yield* readRole3(news);
|
|
2959
3300
|
if (after === undefined) {
|
|
2960
|
-
return yield*
|
|
3301
|
+
return yield* Effect36.die(new Error(`Bao.ProxmoxRole ${path}: write returned no error ` + "but the role is still absent."));
|
|
2961
3302
|
}
|
|
2962
3303
|
return after;
|
|
2963
3304
|
}),
|
|
2964
|
-
delete:
|
|
3305
|
+
delete: Effect36.fn(function* ({ output }) {
|
|
2965
3306
|
yield* baoDelete(rolePath5(output.mount, output.name));
|
|
2966
3307
|
return;
|
|
2967
3308
|
})
|
|
2968
|
-
})));
|
|
3309
|
+
})).pipe(Effect36.map(provingResumes)));
|
|
2969
3310
|
// src/openbao/ssh-role.ts
|
|
2970
3311
|
import { Resource as Resource14 } from "alchemy";
|
|
2971
3312
|
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
2972
3313
|
import * as Provider14 from "alchemy/Provider";
|
|
2973
|
-
import * as
|
|
3314
|
+
import * as Effect37 from "effect/Effect";
|
|
2974
3315
|
|
|
2975
3316
|
// src/openbao/ssh-role-form.ts
|
|
2976
3317
|
var readPath4 = (mount, name) => `${sshMountOf(mount)}/roles/${name}`;
|
|
@@ -3031,7 +3372,7 @@ var attributesOf14 = (form, live) => {
|
|
|
3031
3372
|
};
|
|
3032
3373
|
return { ...attrs, digest: sha256(JSON.stringify(attrs)) };
|
|
3033
3374
|
};
|
|
3034
|
-
var mapValue = (
|
|
3375
|
+
var mapValue = (map23) => extMap(map23);
|
|
3035
3376
|
var writeBody10 = (form) => ({
|
|
3036
3377
|
key_type: "ca",
|
|
3037
3378
|
allowed_users: form.allowedUsers.join(","),
|
|
@@ -3058,16 +3399,7 @@ var sameTtl6 = (want, have) => parseDuration(want) === have;
|
|
|
3058
3399
|
var badDurations = (form) => ["ttl", "maxTtl"].filter((field) => parseDuration(form[field]) === undefined);
|
|
3059
3400
|
var matches12 = (attributes, form) => attributes.keyType === "ca" && sameList2(form.allowedUsers, attributes.allowedUsers) && attributes.defaultUser === form.defaultUser && attributes.allowUserCertificates === form.allowUserCertificates && attributes.allowHostCertificates === form.allowHostCertificates && sameList2(form.allowedDomains, attributes.allowedDomains) && attributes.allowSubdomains === form.allowSubdomains && attributes.allowBareDomains === form.allowBareDomains && sameList2(form.allowedExtensions, attributes.allowedExtensions) && sameMap(form.defaultExtensions, attributes.defaultExtensions) && sameList2(form.allowedCriticalOptions, attributes.allowedCriticalOptions) && sameMap(form.defaultCriticalOptions, attributes.defaultCriticalOptions) && attributes.allowEmptyPrincipals === form.allowEmptyPrincipals && sameTtl6(form.ttl, attributes.ttlSeconds) && sameTtl6(form.maxTtl, attributes.maxTtlSeconds);
|
|
3060
3401
|
|
|
3061
|
-
// src/openbao/ssh-role.ts
|
|
3062
|
-
var BaoSshRole = Resource14("Bao.SshRole", {
|
|
3063
|
-
defaultRemovalPolicy: "retain"
|
|
3064
|
-
});
|
|
3065
|
-
var readRole4 = (form) => Effect31.gen(function* () {
|
|
3066
|
-
const live = yield* baoRead(readPath4(form.mount, form.name));
|
|
3067
|
-
if (live === undefined)
|
|
3068
|
-
return;
|
|
3069
|
-
return { attributes: attributesOf14(form, live), live };
|
|
3070
|
-
});
|
|
3402
|
+
// src/openbao/ssh-role-erase.ts
|
|
3071
3403
|
var UNMANAGED_DEFAULTS = {
|
|
3072
3404
|
algorithm_signer: "default",
|
|
3073
3405
|
allow_commas_in_identity_templates: false,
|
|
@@ -3088,28 +3420,44 @@ var wouldErase2 = (live) => {
|
|
|
3088
3420
|
}
|
|
3089
3421
|
return lost.sort();
|
|
3090
3422
|
};
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3423
|
+
|
|
3424
|
+
// src/openbao/ssh-role.ts
|
|
3425
|
+
var BaoSshRole = Resource14("Bao.SshRole", {
|
|
3426
|
+
defaultRemovalPolicy: "retain"
|
|
3427
|
+
});
|
|
3428
|
+
var IDENTITY11 = roleIdentity("Bao.SshRole", readPath4, "ssh");
|
|
3429
|
+
var readRole4 = (form) => Effect37.gen(function* () {
|
|
3430
|
+
const live = yield* baoRead(readPath4(form.mount, form.name));
|
|
3431
|
+
if (live === undefined)
|
|
3432
|
+
return;
|
|
3433
|
+
return { attributes: attributesOf14(form, live), live };
|
|
3434
|
+
});
|
|
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 }) {
|
|
3095
3439
|
const found = yield* readRole4(resolve2(olds));
|
|
3096
|
-
|
|
3440
|
+
const ours = Effect37.sync(() => found !== undefined && matches12(found.attributes, resolve2(olds)));
|
|
3441
|
+
return yield* ownedRead({ fqn, instanceId, output }, found?.attributes, ours);
|
|
3097
3442
|
}),
|
|
3098
|
-
diff:
|
|
3099
|
-
|
|
3443
|
+
diff: Effect37.fn(function* ({ news, olds, output }) {
|
|
3444
|
+
const move = yield* judgeRename(IDENTITY11, olds, news, output);
|
|
3445
|
+
if (output === undefined)
|
|
3100
3446
|
return;
|
|
3101
|
-
|
|
3102
|
-
if (output.mount !== form.mount || output.name !== form.name) {
|
|
3447
|
+
if (move !== undefined)
|
|
3103
3448
|
return { action: "replace" };
|
|
3104
|
-
|
|
3449
|
+
if (!isResolved14(news))
|
|
3450
|
+
return;
|
|
3451
|
+
const form = resolve2(news);
|
|
3105
3452
|
const found = yield* readRole4(form);
|
|
3106
3453
|
if (found === undefined)
|
|
3107
3454
|
return { action: "update" };
|
|
3108
3455
|
return matches12(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
3109
3456
|
}),
|
|
3110
|
-
reconcile:
|
|
3457
|
+
reconcile: Effect37.fn(function* ({ fqn, instanceId, news, output }) {
|
|
3111
3458
|
const form = resolve2(news);
|
|
3112
3459
|
const path = readPath4(form.mount, form.name);
|
|
3460
|
+
yield* guardRename(IDENTITY11, news, output);
|
|
3113
3461
|
const bad = badDurations(form);
|
|
3114
3462
|
if (bad.length > 0) {
|
|
3115
3463
|
return yield* refuse6(`Bao.SshRole ${path}: ${bad.join(", ")} is not a duration parseDuration understands ` + "(`0` or `<n>s|m|h|d`). It would write, then report update on every plan forever.");
|
|
@@ -3118,6 +3466,8 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect31.succeed(Ba
|
|
|
3118
3466
|
return yield* refuse6(`Bao.SshRole ${path}: allowUserCertificates with an empty allowedUsers and ` + "allowEmptyPrincipals false. Every sign request against it would be rejected.");
|
|
3119
3467
|
}
|
|
3120
3468
|
const found = yield* readRole4(form);
|
|
3469
|
+
if (found !== undefined)
|
|
3470
|
+
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.SshRole ${path}`);
|
|
3121
3471
|
if (found === undefined || !matches12(found.attributes, form)) {
|
|
3122
3472
|
if (found !== undefined) {
|
|
3123
3473
|
const lost = wouldErase2(found.live);
|
|
@@ -3133,11 +3483,11 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect31.succeed(Ba
|
|
|
3133
3483
|
}
|
|
3134
3484
|
return after.attributes;
|
|
3135
3485
|
}),
|
|
3136
|
-
delete:
|
|
3486
|
+
delete: Effect37.fn(function* ({ output }) {
|
|
3137
3487
|
yield* baoDelete(readPath4(output.mount, output.name));
|
|
3138
3488
|
return;
|
|
3139
3489
|
})
|
|
3140
|
-
})));
|
|
3490
|
+
})).pipe(Effect37.map(provingResumes)));
|
|
3141
3491
|
export {
|
|
3142
3492
|
BaoAuthMethod,
|
|
3143
3493
|
BaoAuthMethodProvider,
|
|
@@ -3187,5 +3537,5 @@ export {
|
|
|
3187
3537
|
revokeSelfEffect
|
|
3188
3538
|
};
|
|
3189
3539
|
|
|
3190
|
-
//# debugId=
|
|
3540
|
+
//# debugId=9AA407497A9014D964756E2164756E21
|
|
3191
3541
|
//# sourceMappingURL=index.js.map
|