@homeflare/alchemy 0.6.0 → 0.8.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 +74 -41
- package/dist/caddy/admin-calls.d.ts +48 -0
- package/dist/caddy/admin-calls.d.ts.map +1 -0
- package/dist/caddy/admin-guard.d.ts +40 -0
- package/dist/caddy/admin-guard.d.ts.map +1 -0
- package/dist/caddy/admin.d.ts +73 -0
- package/dist/caddy/admin.d.ts.map +1 -0
- package/dist/caddy/caddyfile-tripwire.d.ts +5 -0
- package/dist/caddy/caddyfile-tripwire.d.ts.map +1 -0
- package/dist/caddy/config-form.d.ts +27 -0
- package/dist/caddy/config-form.d.ts.map +1 -0
- package/dist/caddy/config-lifecycle.d.ts +91 -0
- package/dist/caddy/config-lifecycle.d.ts.map +1 -0
- package/dist/caddy/config.d.ts +34 -0
- package/dist/caddy/config.d.ts.map +1 -0
- package/dist/caddy/digest.d.ts +7 -0
- package/dist/caddy/digest.d.ts.map +1 -0
- package/dist/caddy/fake-caddy.d.ts +54 -0
- package/dist/caddy/fake-caddy.d.ts.map +1 -0
- package/dist/caddy/index.d.ts +22 -0
- package/dist/caddy/index.d.ts.map +1 -0
- package/dist/caddy/index.js +970 -0
- package/dist/caddy/index.js.map +28 -0
- package/dist/caddy/local-admin.d.ts +45 -0
- package/dist/caddy/local-admin.d.ts.map +1 -0
- package/dist/caddy/providers.d.ts +14 -0
- package/dist/caddy/providers.d.ts.map +1 -0
- package/dist/caddy/with-file.d.ts +51 -0
- package/dist/caddy/with-file.d.ts.map +1 -0
- package/dist/cloudflare/fake-mesh.d.ts +58 -0
- package/dist/cloudflare/fake-mesh.d.ts.map +1 -0
- package/dist/cloudflare/index.d.ts +9 -3
- package/dist/cloudflare/index.d.ts.map +1 -1
- package/dist/cloudflare/index.js +218 -7
- package/dist/cloudflare/index.js.map +9 -4
- package/dist/cloudflare/mesh-node-api.d.ts +75 -0
- package/dist/cloudflare/mesh-node-api.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node-form.d.ts +82 -0
- package/dist/cloudflare/mesh-node-form.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node-harness.d.ts +46 -0
- package/dist/cloudflare/mesh-node-harness.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node-lifecycle.d.ts +22 -0
- package/dist/cloudflare/mesh-node-lifecycle.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node-token.d.ts +23 -0
- package/dist/cloudflare/mesh-node-token.d.ts.map +1 -0
- package/dist/cloudflare/mesh-node.d.ts +48 -0
- package/dist/cloudflare/mesh-node.d.ts.map +1 -0
- package/dist/cloudflare/providers.d.ts +1 -12
- package/dist/cloudflare/providers.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/launchd/fake-sudo.d.ts +50 -0
- package/dist/launchd/fake-sudo.d.ts.map +1 -0
- package/dist/launchd/host-effect.d.ts +18 -9
- package/dist/launchd/host-effect.d.ts.map +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.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 +342 -8
- package/dist/launchd/index.js.map +16 -12
- 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/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 +7 -5
- package/dist/launchd/runner.d.ts.map +1 -1
- package/dist/launchd/secret-tripwire.d.ts +1 -0
- package/dist/launchd/secret-tripwire.d.ts.map +1 -1
- 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 +56 -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-stage.d.ts +7 -0
- package/dist/launchd/sudo-stage.d.ts.map +1 -0
- 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-engines-roles.d.ts +32 -0
- package/dist/openbao/fake-engines-roles.d.ts.map +1 -0
- package/dist/openbao/fake-engines.d.ts +36 -0
- package/dist/openbao/fake-engines.d.ts.map +1 -0
- package/dist/openbao/fake-families.d.ts +49 -0
- package/dist/openbao/fake-families.d.ts.map +1 -0
- package/dist/openbao/fake-stack.d.ts +29 -0
- package/dist/openbao/fake-stack.d.ts.map +1 -0
- package/dist/openbao/host-approles.d.ts.map +1 -1
- package/dist/openbao/index.js +393 -234
- package/dist/openbao/index.js.map +23 -19
- 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 +6 -3
- package/dist/openbao/mfa-enforcement.d.ts.map +1 -1
- package/dist/openbao/mfa-totp.d.ts.map +1 -1
- package/dist/openbao/pki-role.d.ts.map +1 -1
- package/dist/openbao/plugin.d.ts.map +1 -1
- package/dist/openbao/policy.d.ts +2 -0
- package/dist/openbao/policy.d.ts.map +1 -1
- package/dist/openbao/proxmox-role-form.d.ts +18 -8
- package/dist/openbao/proxmox-role-form.d.ts.map +1 -1
- package/dist/openbao/proxmox-role-wire.d.ts +18 -0
- package/dist/openbao/proxmox-role-wire.d.ts.map +1 -0
- 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 +107 -0
- package/dist/openbao/rename.d.ts.map +1 -0
- 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/docs/caddy-admin.md +24 -0
- package/docs/caddy.md +199 -0
- package/docs/launchd-sudo.md +122 -0
- package/docs/launchd.md +7 -4
- package/docs/mesh-node.md +188 -0
- package/docs/peers.md +39 -0
- package/package.json +7 -2
- package/src/caddy/admin-calls.ts +128 -0
- package/src/caddy/admin-guard.ts +170 -0
- package/src/caddy/admin.ts +74 -0
- package/src/caddy/adopt-scope.test.ts +82 -0
- package/src/caddy/caddyfile-tripwire.ts +133 -0
- package/src/caddy/config-adopt.test.ts +235 -0
- package/src/caddy/config-form.ts +64 -0
- package/src/caddy/config-lifecycle.test.ts +196 -0
- package/src/caddy/config-lifecycle.ts +239 -0
- package/src/caddy/config.ts +153 -0
- package/src/caddy/digest.ts +44 -0
- package/src/caddy/fake-caddy.ts +179 -0
- package/src/caddy/guards.test.ts +156 -0
- package/src/caddy/index.ts +26 -0
- package/src/caddy/local-admin.test.ts +160 -0
- package/src/caddy/local-admin.ts +189 -0
- package/src/caddy/providers.test.ts +229 -0
- package/src/caddy/providers.ts +17 -0
- package/src/caddy/with-file.ts +66 -0
- package/src/cloudflare/fake-mesh.ts +181 -0
- package/src/cloudflare/index.ts +9 -3
- package/src/cloudflare/mesh-node-api.ts +127 -0
- package/src/cloudflare/mesh-node-edges.test.ts +103 -0
- package/src/cloudflare/mesh-node-form.test.ts +80 -0
- package/src/cloudflare/mesh-node-form.ts +115 -0
- package/src/cloudflare/mesh-node-harness.ts +124 -0
- package/src/cloudflare/mesh-node-lifecycle.ts +187 -0
- package/src/cloudflare/mesh-node-policy.test.ts +151 -0
- package/src/cloudflare/mesh-node-token.test.ts +117 -0
- package/src/cloudflare/mesh-node-token.ts +125 -0
- package/src/cloudflare/mesh-node.test.ts +172 -0
- package/src/cloudflare/mesh-node.ts +120 -0
- package/src/cloudflare/providers.ts +20 -2
- package/src/index.ts +1 -0
- package/src/launchd/fake-sudo.ts +136 -0
- package/src/launchd/host-effect.ts +33 -1
- package/src/launchd/host-file-form.ts +10 -2
- package/src/launchd/host-file-lifecycle.ts +2 -1
- package/src/launchd/index.ts +2 -0
- package/src/launchd/job-preflight.ts +3 -2
- package/src/launchd/job-validate.ts +1 -1
- 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 +7 -5
- package/src/launchd/secret-tripwire.ts +1 -1
- package/src/launchd/sudo-allowlist.test.ts +191 -0
- package/src/launchd/sudo-allowlist.ts +213 -0
- package/src/launchd/sudo-guard.test.ts +100 -0
- package/src/launchd/sudo-guard.ts +151 -0
- package/src/launchd/sudo-lifecycle.test.ts +172 -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 +235 -0
- package/src/launchd/sudo-stage.ts +28 -0
- package/src/openbao/README.md +8 -2
- package/src/openbao/REPLACE.md +126 -22
- 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 +35 -14
- package/src/openbao/cloudflare-role-wire.test.ts +8 -34
- package/src/openbao/cloudflare-role.ts +22 -8
- package/src/openbao/fake-engines-roles.ts +114 -0
- package/src/openbao/fake-engines.ts +126 -0
- package/src/openbao/fake-families.ts +182 -0
- package/src/openbao/fake-stack.ts +112 -0
- package/src/openbao/host-approles.test.ts +15 -2
- package/src/openbao/host-approles.ts +19 -4
- package/src/openbao/jwt-config.ts +26 -5
- package/src/openbao/jwt-role.ts +24 -8
- package/src/openbao/kubernetes-role.ts +20 -8
- package/src/openbao/mfa-enforcement.ts +23 -8
- package/src/openbao/mfa-totp.ts +21 -8
- package/src/openbao/pki-role.ts +19 -7
- package/src/openbao/plugin.ts +41 -15
- package/src/openbao/policy-rename.test.ts +112 -0
- package/src/openbao/policy-wire.test.ts +7 -26
- package/src/openbao/policy.ts +27 -4
- package/src/openbao/proxmox-role-form.ts +27 -8
- package/src/openbao/proxmox-role-wire.ts +24 -0
- package/src/openbao/proxmox-role.ts +52 -36
- package/src/openbao/rename-adoption.test.ts +82 -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-occupied.test.ts +166 -0
- package/src/openbao/rename.ts +166 -0
- package/src/openbao/role-rename.test.ts +205 -0
- package/src/openbao/ssh-role-erase.ts +50 -0
- package/src/openbao/ssh-role.ts +16 -54
package/dist/openbao/index.js
CHANGED
|
@@ -616,7 +616,7 @@ var BaoAuthMethodProvider = () => Provider.effect(BaoAuthMethod, Effect7.succeed
|
|
|
616
616
|
import { Resource as Resource2 } from "alchemy";
|
|
617
617
|
import { isResolved as isResolved2 } from "alchemy/Diff";
|
|
618
618
|
import * as Provider2 from "alchemy/Provider";
|
|
619
|
-
import * as
|
|
619
|
+
import * as Effect10 from "effect/Effect";
|
|
620
620
|
|
|
621
621
|
// src/openbao/auth-role-form.ts
|
|
622
622
|
var policiesOf = (live) => {
|
|
@@ -665,7 +665,6 @@ var writeBody = (props) => {
|
|
|
665
665
|
}
|
|
666
666
|
return body;
|
|
667
667
|
};
|
|
668
|
-
var isRename = (from, to) => from.toLowerCase() !== to.toLowerCase();
|
|
669
668
|
var samePolicies = (want, have) => want.length === have.length && want.every((policy, index) => policy === have[index]);
|
|
670
669
|
var sameTtl3 = (want, have) => {
|
|
671
670
|
const wantSeconds = parseDuration(want);
|
|
@@ -677,26 +676,90 @@ var matches3 = (attributes, props) => {
|
|
|
677
676
|
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
677
|
};
|
|
679
678
|
|
|
679
|
+
// src/openbao/rename-identity.ts
|
|
680
|
+
import * as Effect9 from "effect/Effect";
|
|
681
|
+
|
|
682
|
+
// src/openbao/rename.ts
|
|
683
|
+
import * as Effect8 from "effect/Effect";
|
|
684
|
+
var exact = (identity) => identity;
|
|
685
|
+
var declaredString = (news, key) => {
|
|
686
|
+
if (typeof news !== "object" || news === null)
|
|
687
|
+
return;
|
|
688
|
+
const value = news[key];
|
|
689
|
+
return typeof value === "string" ? value : undefined;
|
|
690
|
+
};
|
|
691
|
+
var isPendingProp = (news, key) => {
|
|
692
|
+
if (typeof news !== "object" || news === null)
|
|
693
|
+
return false;
|
|
694
|
+
const value = news[key];
|
|
695
|
+
return value !== undefined && typeof value !== "string";
|
|
696
|
+
};
|
|
697
|
+
var declaredOr = (news, key, fallback) => isPendingProp(news, key) ? undefined : declaredString(news, key) ?? fallback;
|
|
698
|
+
var declaredRolePath = (news, rolePath, defaultMount) => {
|
|
699
|
+
const mount = defaultMount === undefined ? declaredString(news, "mount") : declaredOr(news, "mount", defaultMount);
|
|
700
|
+
const name = declaredString(news, "name");
|
|
701
|
+
return mount === undefined || name === undefined ? undefined : rolePath(mount, name);
|
|
702
|
+
};
|
|
703
|
+
var policyKey = (name) => name.trim().toLowerCase();
|
|
704
|
+
var isMoved = (stored, declared, key = exact) => declared === undefined ? undefined : key(stored) !== key(declared);
|
|
705
|
+
var judgeMove = (family, tried, declared, pathOf, key = exact) => Effect8.gen(function* () {
|
|
706
|
+
if (tried === undefined || declared === undefined || key(tried) === key(declared)) {
|
|
707
|
+
return;
|
|
708
|
+
}
|
|
709
|
+
if ((yield* baoRead(pathOf(declared))) === undefined)
|
|
710
|
+
return { from: tried, to: declared };
|
|
711
|
+
return yield* Effect8.die(new Error(`${family}: ${tried} → ${declared} would land on an object that already exists at ` + `${declared}. Under RemovalPolicy.destroy() a resource moving off that name (a swap, a ` + "shift, or a reverted move that did not finish) deletes it after this one writes it. " + "Nothing was written. Move through a name nothing holds, in two deploys, or remove " + `${declared} by hand first.`));
|
|
712
|
+
});
|
|
713
|
+
var refuseMovedUpdate = (family, from, to) => Effect8.die(new Error(`${family}: planned as an update, but its identity moved from ${from} to ${to}. Writing ` + `${to} now would leave ${from} live with no state record. Nothing was written. Run the ` + "deploy again: once the value resolves at plan time it plans as a replace."));
|
|
714
|
+
|
|
715
|
+
// src/openbao/rename-identity.ts
|
|
716
|
+
var nameIdentity = (family, pathOf, key) => ({
|
|
717
|
+
declared: (props) => declaredString(props, "name"),
|
|
718
|
+
family,
|
|
719
|
+
key,
|
|
720
|
+
pathOf,
|
|
721
|
+
recorded: (output) => output.name
|
|
722
|
+
});
|
|
723
|
+
var roleIdentity = (family, rolePath, defaultMount, key) => ({
|
|
724
|
+
declared: (props) => declaredRolePath(props, rolePath, defaultMount),
|
|
725
|
+
family,
|
|
726
|
+
key,
|
|
727
|
+
recorded: (output) => rolePath(output.mount, output.name)
|
|
728
|
+
});
|
|
729
|
+
var foldName = (path) => path.replace(/[^/]+$/, (name) => name.toLowerCase());
|
|
730
|
+
var judgeRename = (identity, olds, news, output) => judgeMove(identity.family, output === undefined ? identity.declared(olds) : identity.recorded(output), identity.declared(news), identity.pathOf ?? ((path) => path), identity.key);
|
|
731
|
+
var guardRename = (identity, news, output) => {
|
|
732
|
+
if (output === undefined)
|
|
733
|
+
return Effect9.void;
|
|
734
|
+
const from = identity.recorded(output);
|
|
735
|
+
const to = identity.declared(news);
|
|
736
|
+
return to !== undefined && isMoved(from, to, identity.key) === true ? refuseMovedUpdate(identity.family, from, to) : Effect9.void;
|
|
737
|
+
};
|
|
738
|
+
|
|
680
739
|
// src/openbao/auth-role.ts
|
|
681
740
|
var BaoAuthRole = Resource2("Bao.AuthRole", {
|
|
682
741
|
defaultRemovalPolicy: "retain"
|
|
683
742
|
});
|
|
684
|
-
var
|
|
743
|
+
var IDENTITY = nameIdentity("Bao.AuthRole", readPath3, foldName);
|
|
744
|
+
var readRole = (props) => Effect10.gen(function* () {
|
|
685
745
|
const live = yield* baoRead(readPath3(props.name));
|
|
686
746
|
if (live === undefined)
|
|
687
747
|
return;
|
|
688
748
|
return attributesOf3(props, live);
|
|
689
749
|
});
|
|
690
|
-
var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole,
|
|
691
|
-
list: () =>
|
|
692
|
-
read:
|
|
750
|
+
var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole, Effect10.succeed(BaoAuthRole.Provider.of({
|
|
751
|
+
list: () => Effect10.succeed([]),
|
|
752
|
+
read: Effect10.fn(function* ({ olds }) {
|
|
693
753
|
return yield* readRole(olds);
|
|
694
754
|
}),
|
|
695
|
-
diff:
|
|
696
|
-
|
|
755
|
+
diff: Effect10.fn(function* ({ news, olds, output }) {
|
|
756
|
+
const move = yield* judgeRename(IDENTITY, olds, news, output);
|
|
757
|
+
if (output === undefined)
|
|
697
758
|
return;
|
|
698
|
-
if (
|
|
759
|
+
if (move !== undefined)
|
|
699
760
|
return { action: "replace" };
|
|
761
|
+
if (!isResolved2(news))
|
|
762
|
+
return;
|
|
700
763
|
const live = yield* readRole(news);
|
|
701
764
|
if (live === undefined)
|
|
702
765
|
return { action: "update" };
|
|
@@ -704,24 +767,25 @@ var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole, Effect8.succeed(Ba
|
|
|
704
767
|
return { action: "noop" };
|
|
705
768
|
return { action: "update" };
|
|
706
769
|
}),
|
|
707
|
-
reconcile:
|
|
770
|
+
reconcile: Effect10.fn(function* ({ news, output }) {
|
|
771
|
+
yield* guardRename(IDENTITY, news, output);
|
|
708
772
|
const live = yield* readRole(news);
|
|
709
773
|
if (live === undefined || !matches3(live, news)) {
|
|
710
774
|
yield* baoWrite("PUT", readPath3(news.name), writeBody(news));
|
|
711
775
|
}
|
|
712
776
|
const after = yield* readRole(news);
|
|
713
777
|
if (after === undefined) {
|
|
714
|
-
return yield*
|
|
778
|
+
return yield* Effect10.die(new Error(`Bao.AuthRole ${news.name}: write returned no error but the role is still absent.`));
|
|
715
779
|
}
|
|
716
780
|
return after;
|
|
717
781
|
}),
|
|
718
|
-
delete:
|
|
782
|
+
delete: Effect10.fn(function* ({ output }) {
|
|
719
783
|
yield* baoDelete(readPath3(output.name));
|
|
720
784
|
return;
|
|
721
785
|
})
|
|
722
786
|
})));
|
|
723
787
|
// src/openbao/bao-identity.ts
|
|
724
|
-
import * as
|
|
788
|
+
import * as Effect11 from "effect/Effect";
|
|
725
789
|
import * as FetchHttpClient3 from "effect/unstable/http/FetchHttpClient";
|
|
726
790
|
|
|
727
791
|
// src/openbao/bao-namespace.ts
|
|
@@ -769,42 +833,42 @@ var checkHealth = (address, expectedCluster, body) => {
|
|
|
769
833
|
}
|
|
770
834
|
return { clusterId: text3(body["cluster_id"]), version: text3(body["version"]) };
|
|
771
835
|
};
|
|
772
|
-
var assertBaoIdentityEffect = (expected) =>
|
|
836
|
+
var assertBaoIdentityEffect = (expected) => Effect11.gen(function* () {
|
|
773
837
|
const env = yield* BaoEnv;
|
|
774
838
|
const address = addressOf(env);
|
|
775
839
|
const clusterName = expected.clusterName.trim();
|
|
776
840
|
if (clusterName === "") {
|
|
777
|
-
return yield*
|
|
841
|
+
return yield* Effect11.fail(new BaoIdentityError("input", "clusterName is empty, so there is nothing to compare."));
|
|
778
842
|
}
|
|
779
843
|
const namespace = canonicalNamespace(expected.namespace);
|
|
780
844
|
const sent = envNamespace(env);
|
|
781
845
|
if (sent !== namespace) {
|
|
782
|
-
return yield*
|
|
846
|
+
return yield* Effect11.fail(new BaoIdentityError("mismatch", `BAO_NAMESPACE resolves to \`${namespaceLabel(sent)}\`, but this stack expects ` + `\`${namespaceLabel(namespace)}\`.`));
|
|
783
847
|
}
|
|
784
848
|
const anonymous = { ...env, BAO_NAMESPACE: "", BAO_TOKEN: "" };
|
|
785
|
-
const body = yield* baoCall("read", "GET", HEALTH_PATH).pipe(
|
|
849
|
+
const body = yield* baoCall("read", "GET", HEALTH_PATH).pipe(Effect11.provideService(BaoEnv, anonymous), Effect11.mapError(unreachable(address, "sys/health")));
|
|
786
850
|
const health = checkHealth(address, clusterName, body);
|
|
787
851
|
if (health instanceof BaoIdentityError)
|
|
788
|
-
return yield*
|
|
852
|
+
return yield* Effect11.fail(health);
|
|
789
853
|
if (namespace !== "") {
|
|
790
854
|
const scoped = { ...env, BAO_NAMESPACE: namespace, BAO_TOKEN: "" };
|
|
791
|
-
const probe = yield* baoCall("read", "GET", NAMESPACE_PROBE_PATH).pipe(
|
|
855
|
+
const probe = yield* baoCall("read", "GET", NAMESPACE_PROBE_PATH).pipe(Effect11.provideService(BaoEnv, scoped), Effect11.mapError(unreachable(address, `the namespace probe for \`${namespace}\``)));
|
|
792
856
|
if (probe === undefined) {
|
|
793
|
-
return yield*
|
|
857
|
+
return yield* Effect11.fail(new BaoIdentityError("mismatch", `cluster \`${clusterName}\` at ${address} has no namespace \`${namespace}\`.`));
|
|
794
858
|
}
|
|
795
859
|
}
|
|
796
860
|
return { address, clusterName, namespace, ...health };
|
|
797
861
|
});
|
|
798
862
|
var assertBaoIdentity = (input) => {
|
|
799
863
|
const effect3 = assertBaoIdentityEffect(input);
|
|
800
|
-
const scoped = input.env === undefined ? effect3 :
|
|
801
|
-
return
|
|
864
|
+
const scoped = input.env === undefined ? effect3 : Effect11.provideService(effect3, BaoEnv, input.env);
|
|
865
|
+
return Effect11.runPromise(scoped.pipe(Effect11.provide(FetchHttpClient3.layer)));
|
|
802
866
|
};
|
|
803
867
|
// src/openbao/cloudflare-role.ts
|
|
804
868
|
import { Resource as Resource3 } from "alchemy";
|
|
805
869
|
import { isResolved as isResolved3 } from "alchemy/Diff";
|
|
806
870
|
import * as Provider3 from "alchemy/Provider";
|
|
807
|
-
import * as
|
|
871
|
+
import * as Effect14 from "effect/Effect";
|
|
808
872
|
|
|
809
873
|
// src/openbao/cloudflare-group-scope.ts
|
|
810
874
|
var zoneResource = (zoneId) => `com.cloudflare.api.account.zone.${zoneId}`;
|
|
@@ -824,7 +888,7 @@ var groupKey = (name, scope) => `${scope} ${name}`;
|
|
|
824
888
|
|
|
825
889
|
// src/openbao/cloudflare-permission-groups.ts
|
|
826
890
|
import * as Context2 from "effect/Context";
|
|
827
|
-
import * as
|
|
891
|
+
import * as Effect13 from "effect/Effect";
|
|
828
892
|
|
|
829
893
|
// src/openbao/cloudflare-permission-groups-solve.ts
|
|
830
894
|
var observationsOf = (declared, live) => declared.flatMap((role) => {
|
|
@@ -994,7 +1058,7 @@ var samePolicies2 = (want, have) => want.length === have.length && want.every((w
|
|
|
994
1058
|
});
|
|
995
1059
|
|
|
996
1060
|
// src/openbao/cloudflare-role-wire.ts
|
|
997
|
-
import * as
|
|
1061
|
+
import * as Effect12 from "effect/Effect";
|
|
998
1062
|
|
|
999
1063
|
// src/openbao/cloudflare-role-form.ts
|
|
1000
1064
|
var rolePath = (mount, name) => `${mountPath(mount)}/roles/${name}`;
|
|
@@ -1059,7 +1123,7 @@ var differences = (props, policies, live) => {
|
|
|
1059
1123
|
};
|
|
1060
1124
|
|
|
1061
1125
|
// src/openbao/cloudflare-role-wire.ts
|
|
1062
|
-
var readCloudflareRole = (mount, name) =>
|
|
1126
|
+
var readCloudflareRole = (mount, name) => Effect12.map(baoRead(rolePath(mount, name)), (data) => data === undefined ? undefined : liveRoleOf(data));
|
|
1063
1127
|
var writeCloudflareRole = (mount, name, body) => baoWrite("PUT", rolePath(mount, name), body);
|
|
1064
1128
|
var deleteCloudflareRole = (mount, name) => baoDelete(rolePath(mount, name));
|
|
1065
1129
|
|
|
@@ -1081,9 +1145,9 @@ var pick = (mount, groups, refs, hint) => {
|
|
|
1081
1145
|
const unknown = refs.filter((ref) => !groups.has(groupKey(ref.name, ref.scope)));
|
|
1082
1146
|
if (unknown.length > 0) {
|
|
1083
1147
|
const problems = unknown.map((ref) => `unknown group ${JSON.stringify(ref.name)} at scope ${ref.scope} — ${hint}`);
|
|
1084
|
-
return
|
|
1148
|
+
return Effect13.fail(new CloudflareGroupsError(mount, problems));
|
|
1085
1149
|
}
|
|
1086
|
-
return
|
|
1150
|
+
return Effect13.succeed(new Map(refs.flatMap((ref) => {
|
|
1087
1151
|
const key = groupKey(ref.name, ref.scope);
|
|
1088
1152
|
const id = groups.get(key);
|
|
1089
1153
|
return id === undefined ? [] : [[key, id]];
|
|
@@ -1091,15 +1155,15 @@ var pick = (mount, groups, refs, hint) => {
|
|
|
1091
1155
|
};
|
|
1092
1156
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1093
1157
|
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) =>
|
|
1158
|
+
var deniedNamed = (mount, read) => Effect13.catchIf(read, (error) => error.status === 403, () => Effect13.fail(new CloudflareGroupsError(mount, [deniedHint(mount)])));
|
|
1159
|
+
var engineGroups = (mount) => Effect13.flatMap(deniedNamed(mount, baoRead(`${mountPath(mount)}/permission-groups`)), (data) => {
|
|
1096
1160
|
const list = data?.["permission_groups"];
|
|
1097
1161
|
if (data === undefined) {
|
|
1098
1162
|
const why = "GET <mount>/permission-groups answered 404 — the endpoint is not deployed here";
|
|
1099
|
-
return
|
|
1163
|
+
return Effect13.fail(new CloudflareGroupsError(mount, [why]));
|
|
1100
1164
|
}
|
|
1101
1165
|
if (!Array.isArray(list)) {
|
|
1102
|
-
return
|
|
1166
|
+
return Effect13.fail(new CloudflareGroupsError(mount, ["no permission_groups array in reply"]));
|
|
1103
1167
|
}
|
|
1104
1168
|
const scoped = new Map;
|
|
1105
1169
|
const idsOf = new Map;
|
|
@@ -1126,24 +1190,24 @@ var engineGroups = (mount) => Effect11.flatMap(deniedNamed(mount, baoRead(`${mou
|
|
|
1126
1190
|
const only = [...ids];
|
|
1127
1191
|
return ids.size === 1 && only[0] !== undefined ? [[name, only[0]]] : [];
|
|
1128
1192
|
}));
|
|
1129
|
-
return problems.length > 0 ?
|
|
1193
|
+
return problems.length > 0 ? Effect13.fail(new CloudflareGroupsError(mount, problems)) : Effect13.succeed(new Map([...atEveryScope(sole), ...scoped]));
|
|
1130
1194
|
});
|
|
1131
|
-
var permissionGroupsFromEngine = () =>
|
|
1195
|
+
var permissionGroupsFromEngine = () => Effect13.sync(() => {
|
|
1132
1196
|
const cache = new Map;
|
|
1133
|
-
const cachedFor = (mount) =>
|
|
1197
|
+
const cachedFor = (mount) => Effect13.suspend(() => {
|
|
1134
1198
|
const hit = cache.get(mountPath(mount));
|
|
1135
1199
|
if (hit !== undefined)
|
|
1136
1200
|
return hit;
|
|
1137
|
-
return
|
|
1201
|
+
return Effect13.flatMap(Effect13.cached(engineGroups(mount)), (lookup) => {
|
|
1138
1202
|
cache.set(mountPath(mount), lookup);
|
|
1139
1203
|
return lookup;
|
|
1140
1204
|
});
|
|
1141
1205
|
});
|
|
1142
1206
|
return CloudflarePermissionGroups.of({
|
|
1143
|
-
resolve: (mount, refs) =>
|
|
1207
|
+
resolve: (mount, refs) => Effect13.flatMap(cachedFor(mount), (groups) => pick(mount, groups, refs, "the engine does not list it for this account at that scope"))
|
|
1144
1208
|
});
|
|
1145
1209
|
});
|
|
1146
|
-
var permissionGroupsFromLiveRoles = (declared) =>
|
|
1210
|
+
var permissionGroupsFromLiveRoles = (declared) => Effect13.gen(function* () {
|
|
1147
1211
|
const accountOf = new Map;
|
|
1148
1212
|
const byAccount = new Map;
|
|
1149
1213
|
for (const [mount, roles] of declared) {
|
|
@@ -1154,9 +1218,9 @@ var permissionGroupsFromLiveRoles = (declared) => Effect11.gen(function* () {
|
|
|
1154
1218
|
}
|
|
1155
1219
|
const solved = new Map;
|
|
1156
1220
|
for (const [account, roles] of byAccount) {
|
|
1157
|
-
const solve =
|
|
1221
|
+
const solve = Effect13.gen(function* () {
|
|
1158
1222
|
const live = new Map;
|
|
1159
|
-
yield*
|
|
1223
|
+
yield* Effect13.all(roles.map((role) => Effect13.map(readCloudflareRole(role.mount, role.name), (read) => {
|
|
1160
1224
|
if (read?.policies !== undefined) {
|
|
1161
1225
|
live.set(`${role.mount}/${role.name}`, read.policies);
|
|
1162
1226
|
}
|
|
@@ -1164,11 +1228,11 @@ var permissionGroupsFromLiveRoles = (declared) => Effect11.gen(function* () {
|
|
|
1164
1228
|
const result = solveGroups(observationsOf(roles, live));
|
|
1165
1229
|
const problems = describeProblems(result);
|
|
1166
1230
|
if (problems.length > 0) {
|
|
1167
|
-
return yield*
|
|
1231
|
+
return yield* Effect13.fail(new CloudflareGroupsError(`account ${account}`, problems));
|
|
1168
1232
|
}
|
|
1169
1233
|
return atEveryScope(result.groups);
|
|
1170
1234
|
});
|
|
1171
|
-
solved.set(account, yield*
|
|
1235
|
+
solved.set(account, yield* Effect13.cached(solve));
|
|
1172
1236
|
}
|
|
1173
1237
|
return CloudflarePermissionGroups.of({
|
|
1174
1238
|
resolve: (mount, refs) => {
|
|
@@ -1176,10 +1240,10 @@ var permissionGroupsFromLiveRoles = (declared) => Effect11.gen(function* () {
|
|
|
1176
1240
|
const lookup = account === undefined ? undefined : solved.get(account);
|
|
1177
1241
|
if (account === undefined || lookup === undefined) {
|
|
1178
1242
|
const why = "no declared role on this mount, so no live role can vouch for its groups";
|
|
1179
|
-
return
|
|
1243
|
+
return Effect13.fail(new CloudflareGroupsError(mount, [why]));
|
|
1180
1244
|
}
|
|
1181
1245
|
const hint = `no live role on account ${account} carries it; a NEW group needs the engine endpoint`;
|
|
1182
|
-
return
|
|
1246
|
+
return Effect13.flatMap(lookup, (groups) => pick(mount, groups, refs, hint));
|
|
1183
1247
|
}
|
|
1184
1248
|
});
|
|
1185
1249
|
});
|
|
@@ -1188,9 +1252,10 @@ var permissionGroupsFromLiveRoles = (declared) => Effect11.gen(function* () {
|
|
|
1188
1252
|
var BaoCloudflareRole = Resource3("Bao.CloudflareRole", {
|
|
1189
1253
|
defaultRemovalPolicy: "retain"
|
|
1190
1254
|
});
|
|
1191
|
-
var
|
|
1255
|
+
var IDENTITY2 = roleIdentity("Bao.CloudflareRole", rolePath);
|
|
1256
|
+
var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect14.gen(function* () {
|
|
1192
1257
|
const groups = yield* CloudflarePermissionGroups;
|
|
1193
|
-
const resolved = (props) =>
|
|
1258
|
+
const resolved = (props) => Effect14.gen(function* () {
|
|
1194
1259
|
const refs = new Map;
|
|
1195
1260
|
for (const policy of props.policies) {
|
|
1196
1261
|
const scope = policy.scope ?? scopeOfResource(policy.resource);
|
|
@@ -1200,18 +1265,23 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1200
1265
|
const ids = yield* groups.resolve(props.mount, [...refs.values()]);
|
|
1201
1266
|
const { missing, policies } = resolvePolicies(props.policies, ids);
|
|
1202
1267
|
if (missing.length > 0) {
|
|
1203
|
-
return yield*
|
|
1268
|
+
return yield* Effect14.die(new Error(`Bao.CloudflareRole ${rolePath(props.mount, props.name)}: groups ` + `${missing.join(", ")} came back unresolved from a lookup that reported success.`));
|
|
1204
1269
|
}
|
|
1205
1270
|
return policies;
|
|
1206
1271
|
});
|
|
1207
1272
|
return BaoCloudflareRole.Provider.of({
|
|
1208
|
-
list: () =>
|
|
1209
|
-
read:
|
|
1273
|
+
list: () => Effect14.succeed([]),
|
|
1274
|
+
read: Effect14.fn(function* ({ olds }) {
|
|
1210
1275
|
const live = yield* readCloudflareRole(olds.mount, olds.name);
|
|
1211
1276
|
return live === undefined ? undefined : attributesOf4(olds, live);
|
|
1212
1277
|
}),
|
|
1213
|
-
diff:
|
|
1214
|
-
|
|
1278
|
+
diff: Effect14.fn(function* ({ news, olds, output }) {
|
|
1279
|
+
const move = yield* judgeRename(IDENTITY2, olds, news, output);
|
|
1280
|
+
if (output === undefined)
|
|
1281
|
+
return;
|
|
1282
|
+
if (move !== undefined)
|
|
1283
|
+
return { action: "replace" };
|
|
1284
|
+
if (!isResolved3(news))
|
|
1215
1285
|
return;
|
|
1216
1286
|
if (refusalOf(news) !== undefined)
|
|
1217
1287
|
return { action: "update" };
|
|
@@ -1221,11 +1291,12 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1221
1291
|
return { action: "update" };
|
|
1222
1292
|
return differences(news, policies, live).length === 0 ? { action: "noop" } : { action: "update" };
|
|
1223
1293
|
}),
|
|
1224
|
-
reconcile:
|
|
1294
|
+
reconcile: Effect14.fn(function* ({ news, output }) {
|
|
1225
1295
|
const path = rolePath(news.mount, news.name);
|
|
1296
|
+
yield* guardRename(IDENTITY2, news, output);
|
|
1226
1297
|
const refusal2 = refusalOf(news);
|
|
1227
1298
|
if (refusal2 !== undefined) {
|
|
1228
|
-
return yield*
|
|
1299
|
+
return yield* Effect14.die(new Error(`Bao.CloudflareRole ${path}: ${refusal2}.`));
|
|
1229
1300
|
}
|
|
1230
1301
|
const policies = yield* resolved(news);
|
|
1231
1302
|
const live = yield* readCloudflareRole(news.mount, news.name);
|
|
@@ -1234,15 +1305,15 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1234
1305
|
}
|
|
1235
1306
|
const after = yield* readCloudflareRole(news.mount, news.name);
|
|
1236
1307
|
if (after === undefined) {
|
|
1237
|
-
return yield*
|
|
1308
|
+
return yield* Effect14.die(new Error(`Bao.CloudflareRole ${path}: the write succeeded but the role is absent.`));
|
|
1238
1309
|
}
|
|
1239
1310
|
const left = differences(news, policies, after);
|
|
1240
1311
|
if (left.length > 0) {
|
|
1241
|
-
return yield*
|
|
1312
|
+
return yield* Effect14.die(new Error(`Bao.CloudflareRole ${path}: wrote cleanly but reads back different in ` + `${left.map((d) => d.field).join(", ")}. Inspect the role before retrying.`));
|
|
1242
1313
|
}
|
|
1243
1314
|
return attributesOf4(news, after);
|
|
1244
1315
|
}),
|
|
1245
|
-
delete:
|
|
1316
|
+
delete: Effect14.fn(function* ({ output }) {
|
|
1246
1317
|
yield* deleteCloudflareRole(output.mount, output.name);
|
|
1247
1318
|
return;
|
|
1248
1319
|
})
|
|
@@ -1465,17 +1536,19 @@ var hostAppRoles = (input) => {
|
|
|
1465
1536
|
if (!NAME.test(host.name)) {
|
|
1466
1537
|
problems.push(`host \`${host.name}\` is not lowercase letters, digits, single hyphens`);
|
|
1467
1538
|
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1539
|
+
const name = hostRoleName(host.class, host.name);
|
|
1540
|
+
if (seen.has(name)) {
|
|
1541
|
+
problems.push(`host \`${host.name}\` is listed twice in class \`${host.class}\``);
|
|
1542
|
+
}
|
|
1543
|
+
seen.add(name);
|
|
1544
|
+
const spec = Object.hasOwn(input.classes, host.class) ? input.classes[host.class] : undefined;
|
|
1472
1545
|
if (spec === undefined) {
|
|
1473
1546
|
problems.push(`host \`${host.name}\` names unknown class \`${host.class}\``);
|
|
1474
1547
|
continue;
|
|
1475
1548
|
}
|
|
1476
1549
|
roles.push({
|
|
1477
1550
|
bindSecretId: true,
|
|
1478
|
-
name
|
|
1551
|
+
name,
|
|
1479
1552
|
secretIdNumUses: spec.secretIdNumUses ?? 0,
|
|
1480
1553
|
secretIdTtl: spec.secretIdTtl,
|
|
1481
1554
|
tokenMaxTtl: spec.tokenMaxTtl,
|
|
@@ -1492,7 +1565,7 @@ var hostAppRoles = (input) => {
|
|
|
1492
1565
|
import { Resource as Resource4 } from "alchemy";
|
|
1493
1566
|
import { isResolved as isResolved4 } from "alchemy/Diff";
|
|
1494
1567
|
import * as Provider4 from "alchemy/Provider";
|
|
1495
|
-
import * as
|
|
1568
|
+
import * as Effect16 from "effect/Effect";
|
|
1496
1569
|
|
|
1497
1570
|
// src/openbao/jwt-config-form.ts
|
|
1498
1571
|
var text5 = (value) => typeof value === "string" ? value.trim() : "";
|
|
@@ -1582,16 +1655,16 @@ var problems = (props) => {
|
|
|
1582
1655
|
};
|
|
1583
1656
|
|
|
1584
1657
|
// src/openbao/role-reconcile.ts
|
|
1585
|
-
import * as
|
|
1586
|
-
var readRoleAt = (spec) =>
|
|
1587
|
-
var planRole = (spec) =>
|
|
1658
|
+
import * as Effect15 from "effect/Effect";
|
|
1659
|
+
var readRoleAt = (spec) => Effect15.map(baoRead(spec.path), (live) => live === undefined ? undefined : { attributes: spec.attributesOf(live), live });
|
|
1660
|
+
var planRole = (spec) => Effect15.gen(function* () {
|
|
1588
1661
|
if (spec.problems.length > 0)
|
|
1589
1662
|
return "update";
|
|
1590
1663
|
const found = yield* readRoleAt(spec);
|
|
1591
1664
|
return found !== undefined && spec.matches(found.attributes) ? "noop" : "update";
|
|
1592
1665
|
});
|
|
1593
|
-
var refuse2 = (spec, message) =>
|
|
1594
|
-
var reconcileRole = (spec) =>
|
|
1666
|
+
var refuse2 = (spec, message) => Effect15.die(new Error(`${spec.family} ${spec.path}: ${message}`));
|
|
1667
|
+
var reconcileRole = (spec) => Effect15.gen(function* () {
|
|
1595
1668
|
if (spec.problems.length > 0)
|
|
1596
1669
|
return yield* refuse2(spec, spec.problems.join("; "));
|
|
1597
1670
|
const found = yield* readRoleAt(spec);
|
|
@@ -1615,6 +1688,14 @@ var reconcileRole = (spec) => Effect13.gen(function* () {
|
|
|
1615
1688
|
var BaoJwtAuthConfig = Resource4("Bao.JwtAuthConfig", {
|
|
1616
1689
|
defaultRemovalPolicy: "retain"
|
|
1617
1690
|
});
|
|
1691
|
+
var IDENTITY3 = {
|
|
1692
|
+
declared: (props) => {
|
|
1693
|
+
const mount = declaredOr(props, "mount", "jwt");
|
|
1694
|
+
return mount === undefined ? undefined : configPath({ mount });
|
|
1695
|
+
},
|
|
1696
|
+
family: "Bao.JwtAuthConfig",
|
|
1697
|
+
recorded: (output) => configPath(output)
|
|
1698
|
+
};
|
|
1618
1699
|
var jwtConfigSpec = (props) => ({
|
|
1619
1700
|
attributesOf: (live) => attributesOf5(props, live),
|
|
1620
1701
|
body: writeBody3(props),
|
|
@@ -1624,29 +1705,33 @@ var jwtConfigSpec = (props) => ({
|
|
|
1624
1705
|
problems: problems(props),
|
|
1625
1706
|
wouldErase
|
|
1626
1707
|
});
|
|
1627
|
-
var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig,
|
|
1628
|
-
list: () =>
|
|
1629
|
-
read:
|
|
1708
|
+
var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig, Effect16.succeed(BaoJwtAuthConfig.Provider.of({
|
|
1709
|
+
list: () => Effect16.succeed([]),
|
|
1710
|
+
read: Effect16.fn(function* ({ olds }) {
|
|
1630
1711
|
const found = yield* readRoleAt(jwtConfigSpec(olds));
|
|
1631
1712
|
return found?.attributes;
|
|
1632
1713
|
}),
|
|
1633
|
-
diff:
|
|
1634
|
-
|
|
1714
|
+
diff: Effect16.fn(function* ({ news, olds, output }) {
|
|
1715
|
+
const move = yield* judgeRename(IDENTITY3, olds, news, output);
|
|
1716
|
+
if (output === undefined)
|
|
1635
1717
|
return;
|
|
1636
|
-
if (
|
|
1718
|
+
if (move !== undefined)
|
|
1637
1719
|
return { action: "replace" };
|
|
1720
|
+
if (!isResolved4(news))
|
|
1721
|
+
return;
|
|
1638
1722
|
return { action: yield* planRole(jwtConfigSpec(news)) };
|
|
1639
1723
|
}),
|
|
1640
|
-
reconcile:
|
|
1724
|
+
reconcile: Effect16.fn(function* ({ news, output }) {
|
|
1725
|
+
yield* guardRename(IDENTITY3, news, output);
|
|
1641
1726
|
return yield* reconcileRole(jwtConfigSpec(news));
|
|
1642
1727
|
}),
|
|
1643
|
-
delete: () =>
|
|
1728
|
+
delete: () => Effect16.void
|
|
1644
1729
|
})));
|
|
1645
1730
|
// src/openbao/jwt-role.ts
|
|
1646
1731
|
import { Resource as Resource5 } from "alchemy";
|
|
1647
1732
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1648
1733
|
import * as Provider5 from "alchemy/Provider";
|
|
1649
|
-
import * as
|
|
1734
|
+
import * as Effect17 from "effect/Effect";
|
|
1650
1735
|
|
|
1651
1736
|
// src/openbao/auth-token-form.ts
|
|
1652
1737
|
var sortedSet2 = (values) => [...new Set(values)].sort();
|
|
@@ -1848,6 +1933,7 @@ var problems2 = (props) => {
|
|
|
1848
1933
|
var BaoJwtRole = Resource5("Bao.JwtRole", {
|
|
1849
1934
|
defaultRemovalPolicy: "retain"
|
|
1850
1935
|
});
|
|
1936
|
+
var IDENTITY4 = roleIdentity("Bao.JwtRole", (mount, name) => rolePath2({ mount, name }), "jwt", foldName);
|
|
1851
1937
|
var jwtRoleSpec = (props) => ({
|
|
1852
1938
|
attributesOf: (live) => attributesOf6(props, live),
|
|
1853
1939
|
body: writeBody4(props),
|
|
@@ -1856,24 +1942,27 @@ var jwtRoleSpec = (props) => ({
|
|
|
1856
1942
|
path: rolePath2(props),
|
|
1857
1943
|
problems: problems2(props)
|
|
1858
1944
|
});
|
|
1859
|
-
var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole,
|
|
1860
|
-
list: () =>
|
|
1861
|
-
read:
|
|
1945
|
+
var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole, Effect17.succeed(BaoJwtRole.Provider.of({
|
|
1946
|
+
list: () => Effect17.succeed([]),
|
|
1947
|
+
read: Effect17.fn(function* ({ olds }) {
|
|
1862
1948
|
const found = yield* readRoleAt(jwtRoleSpec(olds));
|
|
1863
1949
|
return found?.attributes;
|
|
1864
1950
|
}),
|
|
1865
|
-
diff:
|
|
1866
|
-
|
|
1951
|
+
diff: Effect17.fn(function* ({ news, olds, output }) {
|
|
1952
|
+
const move = yield* judgeRename(IDENTITY4, olds, news, output);
|
|
1953
|
+
if (output === undefined)
|
|
1867
1954
|
return;
|
|
1868
|
-
if (
|
|
1955
|
+
if (move !== undefined)
|
|
1869
1956
|
return { action: "replace" };
|
|
1870
|
-
|
|
1957
|
+
if (!isResolved5(news))
|
|
1958
|
+
return;
|
|
1871
1959
|
return { action: yield* planRole(jwtRoleSpec(news)) };
|
|
1872
1960
|
}),
|
|
1873
|
-
reconcile:
|
|
1961
|
+
reconcile: Effect17.fn(function* ({ news, output }) {
|
|
1962
|
+
yield* guardRename(IDENTITY4, news, output);
|
|
1874
1963
|
return yield* reconcileRole(jwtRoleSpec(news));
|
|
1875
1964
|
}),
|
|
1876
|
-
delete:
|
|
1965
|
+
delete: Effect17.fn(function* ({ output }) {
|
|
1877
1966
|
yield* baoDelete(rolePath2(output));
|
|
1878
1967
|
return;
|
|
1879
1968
|
})
|
|
@@ -1882,7 +1971,7 @@ var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole, Effect15.succeed(Bao
|
|
|
1882
1971
|
import { Resource as Resource6 } from "alchemy";
|
|
1883
1972
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1884
1973
|
import * as Provider6 from "alchemy/Provider";
|
|
1885
|
-
import * as
|
|
1974
|
+
import * as Effect18 from "effect/Effect";
|
|
1886
1975
|
|
|
1887
1976
|
// src/openbao/kubernetes-role-form.ts
|
|
1888
1977
|
var sortedSet4 = (values) => [...new Set(values)].sort();
|
|
@@ -1951,6 +2040,7 @@ var problems3 = (props) => {
|
|
|
1951
2040
|
var BaoKubernetesRole = Resource6("Bao.KubernetesRole", {
|
|
1952
2041
|
defaultRemovalPolicy: "retain"
|
|
1953
2042
|
});
|
|
2043
|
+
var IDENTITY5 = roleIdentity("Bao.KubernetesRole", (mount, name) => rolePath3({ mount, name }), "kubernetes", foldName);
|
|
1954
2044
|
var kubernetesRoleSpec = (props) => ({
|
|
1955
2045
|
attributesOf: (live) => attributesOf7(props, live),
|
|
1956
2046
|
body: writeBody5(props),
|
|
@@ -1959,24 +2049,27 @@ var kubernetesRoleSpec = (props) => ({
|
|
|
1959
2049
|
path: rolePath3(props),
|
|
1960
2050
|
problems: problems3(props)
|
|
1961
2051
|
});
|
|
1962
|
-
var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole,
|
|
1963
|
-
list: () =>
|
|
1964
|
-
read:
|
|
2052
|
+
var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole, Effect18.succeed(BaoKubernetesRole.Provider.of({
|
|
2053
|
+
list: () => Effect18.succeed([]),
|
|
2054
|
+
read: Effect18.fn(function* ({ olds }) {
|
|
1965
2055
|
const found = yield* readRoleAt(kubernetesRoleSpec(olds));
|
|
1966
2056
|
return found?.attributes;
|
|
1967
2057
|
}),
|
|
1968
|
-
diff:
|
|
1969
|
-
|
|
2058
|
+
diff: Effect18.fn(function* ({ news, olds, output }) {
|
|
2059
|
+
const move = yield* judgeRename(IDENTITY5, olds, news, output);
|
|
2060
|
+
if (output === undefined)
|
|
1970
2061
|
return;
|
|
1971
|
-
if (
|
|
2062
|
+
if (move !== undefined)
|
|
1972
2063
|
return { action: "replace" };
|
|
1973
|
-
|
|
2064
|
+
if (!isResolved6(news))
|
|
2065
|
+
return;
|
|
1974
2066
|
return { action: yield* planRole(kubernetesRoleSpec(news)) };
|
|
1975
2067
|
}),
|
|
1976
|
-
reconcile:
|
|
2068
|
+
reconcile: Effect18.fn(function* ({ news, output }) {
|
|
2069
|
+
yield* guardRename(IDENTITY5, news, output);
|
|
1977
2070
|
return yield* reconcileRole(kubernetesRoleSpec(news));
|
|
1978
2071
|
}),
|
|
1979
|
-
delete:
|
|
2072
|
+
delete: Effect18.fn(function* ({ output }) {
|
|
1980
2073
|
yield* baoDelete(rolePath3(output));
|
|
1981
2074
|
return;
|
|
1982
2075
|
})
|
|
@@ -1985,7 +2078,7 @@ var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole, Effect
|
|
|
1985
2078
|
import { Resource as Resource7 } from "alchemy";
|
|
1986
2079
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
1987
2080
|
import * as Provider7 from "alchemy/Provider";
|
|
1988
|
-
import * as
|
|
2081
|
+
import * as Effect20 from "effect/Effect";
|
|
1989
2082
|
|
|
1990
2083
|
// src/openbao/mfa-enforcement-form.ts
|
|
1991
2084
|
var sortedSet5 = (values) => [...new Set(values.map((value) => value.trim()))].filter((value) => value !== "").sort();
|
|
@@ -2053,16 +2146,16 @@ var problems4 = (props, missingPaths) => {
|
|
|
2053
2146
|
};
|
|
2054
2147
|
|
|
2055
2148
|
// src/openbao/mfa-wire.ts
|
|
2056
|
-
import * as
|
|
2149
|
+
import * as Effect19 from "effect/Effect";
|
|
2057
2150
|
var TOTP_PATH = "identity/mfa/method/totp";
|
|
2058
2151
|
var METHODS_PATH = "identity/mfa/method";
|
|
2059
2152
|
var enforcementPath = (name) => `identity/mfa/login-enforcement/${name}`;
|
|
2060
2153
|
var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
2061
|
-
var ownNamespacePath =
|
|
2154
|
+
var ownNamespacePath = Effect19.gen(function* () {
|
|
2062
2155
|
const env = yield* BaoEnv;
|
|
2063
2156
|
return namespacePath(envNamespace(env));
|
|
2064
2157
|
});
|
|
2065
|
-
var findTotp = (name) =>
|
|
2158
|
+
var findTotp = (name) => Effect19.gen(function* () {
|
|
2066
2159
|
const listing = yield* baoRead(`${METHODS_PATH}?list=true`);
|
|
2067
2160
|
const info = record4(listing?.["key_info"]) ?? {};
|
|
2068
2161
|
const own = yield* ownNamespacePath;
|
|
@@ -2071,17 +2164,17 @@ var findTotp = (name) => Effect17.gen(function* () {
|
|
|
2071
2164
|
if (live === undefined || live["name"] !== name || live["namespace_path"] !== own)
|
|
2072
2165
|
continue;
|
|
2073
2166
|
if (live["type"] !== "totp") {
|
|
2074
|
-
return yield*
|
|
2167
|
+
return yield* Effect19.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.`));
|
|
2075
2168
|
}
|
|
2076
2169
|
return { id, live };
|
|
2077
2170
|
}
|
|
2078
2171
|
return;
|
|
2079
2172
|
});
|
|
2080
|
-
var writeTotp = (body) =>
|
|
2173
|
+
var writeTotp = (body) => Effect19.asVoid(baoCall("write", "POST", TOTP_PATH, body));
|
|
2081
2174
|
var deleteTotp = (id) => baoDelete(`${TOTP_PATH}/${id}`);
|
|
2082
2175
|
var readEnforcement = (name) => baoRead(enforcementPath(name));
|
|
2083
|
-
var writeEnforcement = (name, body) =>
|
|
2084
|
-
var authAccessors = (paths) =>
|
|
2176
|
+
var writeEnforcement = (name, body) => Effect19.asVoid(baoCall("write", "POST", enforcementPath(name), body));
|
|
2177
|
+
var authAccessors = (paths) => Effect19.gen(function* () {
|
|
2085
2178
|
if (paths.length === 0)
|
|
2086
2179
|
return { accessors: [], missing: [] };
|
|
2087
2180
|
const table = (yield* baoRead("sys/auth")) ?? {};
|
|
@@ -2101,20 +2194,21 @@ var authAccessors = (paths) => Effect17.gen(function* () {
|
|
|
2101
2194
|
var BaoMfaLoginEnforcement = Resource7("Bao.MfaLoginEnforcement", {
|
|
2102
2195
|
defaultRemovalPolicy: "retain"
|
|
2103
2196
|
});
|
|
2104
|
-
var
|
|
2105
|
-
var
|
|
2197
|
+
var IDENTITY6 = nameIdentity("Bao.MfaLoginEnforcement", enforcementPath);
|
|
2198
|
+
var refuse3 = (name, message) => Effect20.die(new Error(`Bao.MfaLoginEnforcement ${name}: ${message}`));
|
|
2199
|
+
var resolveTargets = (props) => Effect20.map(authAccessors(props.authMethodPaths ?? []), ({ accessors, missing }) => ({
|
|
2106
2200
|
bad: problems4(props, missing),
|
|
2107
2201
|
resolved: accessors
|
|
2108
2202
|
}));
|
|
2109
|
-
var readLive = (name) =>
|
|
2110
|
-
var planEnforcement = (props) =>
|
|
2203
|
+
var readLive = (name) => Effect20.map(readEnforcement(name), (live) => live === undefined ? undefined : attributesOf8(name, live));
|
|
2204
|
+
var planEnforcement = (props) => Effect20.gen(function* () {
|
|
2111
2205
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2112
2206
|
if (bad.length > 0)
|
|
2113
2207
|
return "update";
|
|
2114
2208
|
const live = yield* readLive(props.name);
|
|
2115
2209
|
return live !== undefined && matches7(live, props, resolved) ? "noop" : "update";
|
|
2116
2210
|
});
|
|
2117
|
-
var reconcileEnforcement = (props) =>
|
|
2211
|
+
var reconcileEnforcement = (props) => Effect20.gen(function* () {
|
|
2118
2212
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2119
2213
|
if (bad.length > 0)
|
|
2120
2214
|
return yield* refuse3(props.name, bad.join("; "));
|
|
@@ -2130,22 +2224,26 @@ var reconcileEnforcement = (props) => Effect18.gen(function* () {
|
|
|
2130
2224
|
}
|
|
2131
2225
|
return after;
|
|
2132
2226
|
});
|
|
2133
|
-
var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforcement,
|
|
2134
|
-
list: () =>
|
|
2135
|
-
read:
|
|
2227
|
+
var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforcement, Effect20.succeed(BaoMfaLoginEnforcement.Provider.of({
|
|
2228
|
+
list: () => Effect20.succeed([]),
|
|
2229
|
+
read: Effect20.fn(function* ({ olds }) {
|
|
2136
2230
|
return yield* readLive(olds.name);
|
|
2137
2231
|
}),
|
|
2138
|
-
diff:
|
|
2139
|
-
|
|
2232
|
+
diff: Effect20.fn(function* ({ news, olds, output }) {
|
|
2233
|
+
const move = yield* judgeRename(IDENTITY6, olds, news, output);
|
|
2234
|
+
if (output === undefined)
|
|
2140
2235
|
return;
|
|
2141
|
-
if (
|
|
2236
|
+
if (move !== undefined)
|
|
2142
2237
|
return { action: "replace" };
|
|
2238
|
+
if (!isResolved7(news))
|
|
2239
|
+
return;
|
|
2143
2240
|
return { action: yield* planEnforcement(news) };
|
|
2144
2241
|
}),
|
|
2145
|
-
reconcile:
|
|
2242
|
+
reconcile: Effect20.fn(function* ({ news, output }) {
|
|
2243
|
+
yield* guardRename(IDENTITY6, news, output);
|
|
2146
2244
|
return yield* reconcileEnforcement(news);
|
|
2147
2245
|
}),
|
|
2148
|
-
delete:
|
|
2246
|
+
delete: Effect20.fn(function* ({ output }) {
|
|
2149
2247
|
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.");
|
|
2150
2248
|
})
|
|
2151
2249
|
})));
|
|
@@ -2153,7 +2251,7 @@ var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforceme
|
|
|
2153
2251
|
import { Resource as Resource8 } from "alchemy";
|
|
2154
2252
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2155
2253
|
import * as Provider8 from "alchemy/Provider";
|
|
2156
|
-
import * as
|
|
2254
|
+
import * as Effect21 from "effect/Effect";
|
|
2157
2255
|
|
|
2158
2256
|
// src/openbao/mfa-totp-form.ts
|
|
2159
2257
|
var canonical6 = (input) => ({
|
|
@@ -2234,45 +2332,51 @@ var problems5 = (props) => {
|
|
|
2234
2332
|
var BaoMfaTotpMethod = Resource8("Bao.MfaTotpMethod", {
|
|
2235
2333
|
defaultRemovalPolicy: "retain"
|
|
2236
2334
|
});
|
|
2237
|
-
var refuse4 = (
|
|
2238
|
-
var readTotp = (props) =>
|
|
2239
|
-
var planTotp = (props) =>
|
|
2335
|
+
var refuse4 = (name, message) => Effect21.die(new Error(`Bao.MfaTotpMethod ${name}: ${message}`));
|
|
2336
|
+
var readTotp = (props) => Effect21.map(findTotp(props.name), (found) => found === undefined ? undefined : attributesOf9(found.id, found.live));
|
|
2337
|
+
var planTotp = (props) => Effect21.gen(function* () {
|
|
2240
2338
|
if (problems5(props).length > 0)
|
|
2241
2339
|
return "update";
|
|
2242
2340
|
const live = yield* readTotp(props);
|
|
2243
2341
|
return live !== undefined && matches8(live, props) ? "noop" : "update";
|
|
2244
2342
|
});
|
|
2245
|
-
var reconcileTotp = (props) =>
|
|
2343
|
+
var reconcileTotp = (props) => Effect21.gen(function* () {
|
|
2246
2344
|
const bad = problems5(props);
|
|
2247
2345
|
if (bad.length > 0)
|
|
2248
|
-
return yield* refuse4(props, bad.join("; "));
|
|
2346
|
+
return yield* refuse4(props.name, bad.join("; "));
|
|
2249
2347
|
const live = yield* readTotp(props);
|
|
2250
2348
|
if (live === undefined || !matches8(live, props))
|
|
2251
2349
|
yield* writeTotp(writeBody7(props));
|
|
2252
2350
|
const after = yield* readTotp(props);
|
|
2253
2351
|
if (after === undefined)
|
|
2254
|
-
return yield* refuse4(props, "the write succeeded but no method has that name.");
|
|
2352
|
+
return yield* refuse4(props.name, "the write succeeded but no method has that name.");
|
|
2255
2353
|
if (!matches8(after, props))
|
|
2256
|
-
return yield* refuse4(props, "the method read back different.");
|
|
2354
|
+
return yield* refuse4(props.name, "the method read back different.");
|
|
2257
2355
|
return after;
|
|
2258
2356
|
});
|
|
2259
|
-
var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod,
|
|
2260
|
-
list: () =>
|
|
2261
|
-
read:
|
|
2357
|
+
var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod, Effect21.succeed(BaoMfaTotpMethod.Provider.of({
|
|
2358
|
+
list: () => Effect21.succeed([]),
|
|
2359
|
+
read: Effect21.fn(function* ({ olds }) {
|
|
2262
2360
|
return yield* readTotp(olds);
|
|
2263
2361
|
}),
|
|
2264
|
-
diff:
|
|
2362
|
+
diff: Effect21.fn(function* ({ news, output }) {
|
|
2363
|
+
const name = declaredString(news, "name");
|
|
2364
|
+
if (output !== undefined && name !== undefined) {
|
|
2365
|
+
const rename = renameProblem(output.name, name);
|
|
2366
|
+
if (rename !== undefined)
|
|
2367
|
+
return yield* refuse4(name, rename);
|
|
2368
|
+
}
|
|
2265
2369
|
if (output === undefined || !isResolved8(news))
|
|
2266
2370
|
return;
|
|
2267
|
-
const rename = renameProblem(output.name, news.name);
|
|
2268
|
-
if (rename !== undefined)
|
|
2269
|
-
return yield* refuse4(news, rename);
|
|
2270
2371
|
return { action: yield* planTotp(news) };
|
|
2271
2372
|
}),
|
|
2272
|
-
reconcile:
|
|
2373
|
+
reconcile: Effect21.fn(function* ({ news, output }) {
|
|
2374
|
+
const rename = output === undefined ? undefined : renameProblem(output.name, news.name);
|
|
2375
|
+
if (rename !== undefined)
|
|
2376
|
+
return yield* refuse4(news.name, rename);
|
|
2273
2377
|
return yield* reconcileTotp(news);
|
|
2274
2378
|
}),
|
|
2275
|
-
delete:
|
|
2379
|
+
delete: Effect21.fn(function* ({ output }) {
|
|
2276
2380
|
yield* deleteTotp(output.methodId);
|
|
2277
2381
|
return;
|
|
2278
2382
|
})
|
|
@@ -2281,24 +2385,24 @@ var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod, Effect19
|
|
|
2281
2385
|
import { Resource as Resource9 } from "alchemy";
|
|
2282
2386
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2283
2387
|
import * as Provider9 from "alchemy/Provider";
|
|
2284
|
-
import * as
|
|
2388
|
+
import * as Effect24 from "effect/Effect";
|
|
2285
2389
|
|
|
2286
2390
|
// src/openbao/mount-reconcile.ts
|
|
2287
|
-
import * as
|
|
2391
|
+
import * as Effect23 from "effect/Effect";
|
|
2288
2392
|
|
|
2289
2393
|
// src/openbao/mount-wire.ts
|
|
2290
|
-
import * as
|
|
2291
|
-
var absentFromTable2 = (path, asked) => baoRead("sys/mounts").pipe(
|
|
2394
|
+
import * as Effect22 from "effect/Effect";
|
|
2395
|
+
var absentFromTable2 = (path, asked) => baoRead("sys/mounts").pipe(Effect22.mapError((listing) => new BaoError(asked.status, asked.method, asked.path, [
|
|
2292
2396
|
...asked.errors,
|
|
2293
2397
|
`sys/mounts could not confirm the mount is absent: ${listing.message}`
|
|
2294
|
-
])),
|
|
2295
|
-
var readMountData = (path) => baoRead(readPath(path)).pipe(
|
|
2398
|
+
])), Effect22.flatMap((table) => table !== undefined && !Object.hasOwn(table, `${mountPath(path)}/`) ? Effect22.succeed(undefined) : Effect22.fail(asked)));
|
|
2399
|
+
var readMountData = (path) => baoRead(readPath(path)).pipe(Effect22.catchIf((error) => error.status === 400, (error) => absentFromTable2(path, error)));
|
|
2296
2400
|
var enableMount = (props) => baoWrite("POST", readPath(props.path), enableBody(props));
|
|
2297
2401
|
var tuneMount = (props) => baoWrite("POST", tunePath(props.path), tuneBody(props));
|
|
2298
2402
|
var disableMount = (path) => baoDelete(readPath(path));
|
|
2299
2403
|
|
|
2300
2404
|
// src/openbao/mount-reconcile.ts
|
|
2301
|
-
var readMount = (props) =>
|
|
2405
|
+
var readMount = (props) => Effect23.gen(function* () {
|
|
2302
2406
|
const live = yield* readMountData(props.path);
|
|
2303
2407
|
if (live === undefined)
|
|
2304
2408
|
return;
|
|
@@ -2311,10 +2415,10 @@ var moveTarget2 = (props) => ({
|
|
|
2311
2415
|
type: props.type,
|
|
2312
2416
|
wire: mountPath
|
|
2313
2417
|
});
|
|
2314
|
-
var reconcileMount = (news, stated, options) =>
|
|
2418
|
+
var reconcileMount = (news, stated, options) => Effect23.gen(function* () {
|
|
2315
2419
|
const move = planMove("Bao.Mount", stated, news.path, news.remountFrom);
|
|
2316
2420
|
if (move.kind === "refuse")
|
|
2317
|
-
return yield*
|
|
2421
|
+
return yield* Effect23.die(new Error(move.message));
|
|
2318
2422
|
if (move.kind === "move")
|
|
2319
2423
|
yield* performMove(moveTarget2(news), move.from, options);
|
|
2320
2424
|
let live = yield* readMount(news);
|
|
@@ -2324,13 +2428,13 @@ var reconcileMount = (news, stated, options) => Effect21.gen(function* () {
|
|
|
2324
2428
|
yield* tuneMount(news);
|
|
2325
2429
|
} else if (!matches(live, news)) {
|
|
2326
2430
|
if (live.type !== news.type) {
|
|
2327
|
-
return yield*
|
|
2431
|
+
return yield* Effect23.die(new Error(`Bao.Mount ${mountPath(news.path)}: live type ${live.type} != ${news.type}. ` + "Secrets engine type is immutable — replace manually."));
|
|
2328
2432
|
}
|
|
2329
2433
|
yield* tuneMount(news);
|
|
2330
2434
|
}
|
|
2331
2435
|
live = yield* readMount(news);
|
|
2332
2436
|
if (live === undefined) {
|
|
2333
|
-
return yield*
|
|
2437
|
+
return yield* Effect23.die(new Error(`Bao.Mount ${mountPath(news.path)}: write returned no error but the mount is still absent.`));
|
|
2334
2438
|
}
|
|
2335
2439
|
return live;
|
|
2336
2440
|
});
|
|
@@ -2339,17 +2443,17 @@ var reconcileMount = (news, stated, options) => Effect21.gen(function* () {
|
|
|
2339
2443
|
var BaoMount = Resource9("Bao.Mount", {
|
|
2340
2444
|
defaultRemovalPolicy: "retain"
|
|
2341
2445
|
});
|
|
2342
|
-
var BaoMountProvider = () => Provider9.effect(BaoMount,
|
|
2343
|
-
list: () =>
|
|
2344
|
-
read:
|
|
2446
|
+
var BaoMountProvider = () => Provider9.effect(BaoMount, Effect24.succeed(BaoMount.Provider.of({
|
|
2447
|
+
list: () => Effect24.succeed([]),
|
|
2448
|
+
read: Effect24.fn(function* ({ olds }) {
|
|
2345
2449
|
return yield* readMount(olds);
|
|
2346
2450
|
}),
|
|
2347
|
-
diff:
|
|
2451
|
+
diff: Effect24.fn(function* ({ news, output }) {
|
|
2348
2452
|
if (output === undefined || !isResolved9(news))
|
|
2349
2453
|
return;
|
|
2350
2454
|
const move = planMove("Bao.Mount", output.path, news.path, news.remountFrom);
|
|
2351
2455
|
if (move.kind === "refuse")
|
|
2352
|
-
return yield*
|
|
2456
|
+
return yield* Effect24.die(new Error(move.message));
|
|
2353
2457
|
if (move.kind === "move")
|
|
2354
2458
|
return { action: "update" };
|
|
2355
2459
|
const live = yield* readMount(news);
|
|
@@ -2361,10 +2465,10 @@ var BaoMountProvider = () => Provider9.effect(BaoMount, Effect22.succeed(BaoMoun
|
|
|
2361
2465
|
return { action: "noop" };
|
|
2362
2466
|
return { action: "update" };
|
|
2363
2467
|
}),
|
|
2364
|
-
reconcile:
|
|
2468
|
+
reconcile: Effect24.fn(function* ({ news, output }) {
|
|
2365
2469
|
return yield* reconcileMount(news, output?.path);
|
|
2366
2470
|
}),
|
|
2367
|
-
delete:
|
|
2471
|
+
delete: Effect24.fn(function* ({ output }) {
|
|
2368
2472
|
yield* disableMount(output.path);
|
|
2369
2473
|
return;
|
|
2370
2474
|
})
|
|
@@ -2373,7 +2477,7 @@ var BaoMountProvider = () => Provider9.effect(BaoMount, Effect22.succeed(BaoMoun
|
|
|
2373
2477
|
import { Resource as Resource10 } from "alchemy";
|
|
2374
2478
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2375
2479
|
import * as Provider10 from "alchemy/Provider";
|
|
2376
|
-
import * as
|
|
2480
|
+
import * as Effect25 from "effect/Effect";
|
|
2377
2481
|
|
|
2378
2482
|
// src/openbao/pki-role-canonical.ts
|
|
2379
2483
|
var DEFAULT_KEY_USAGE = [
|
|
@@ -2539,22 +2643,26 @@ var problems6 = (props) => {
|
|
|
2539
2643
|
var BaoPkiRole = Resource10("Bao.PkiRole", {
|
|
2540
2644
|
defaultRemovalPolicy: "retain"
|
|
2541
2645
|
});
|
|
2542
|
-
var
|
|
2646
|
+
var IDENTITY7 = roleIdentity("Bao.PkiRole", (mount, name) => rolePath4({ mount, name }), "pki");
|
|
2647
|
+
var readRole2 = (props) => Effect25.gen(function* () {
|
|
2543
2648
|
const live = yield* baoRead(rolePath4(props));
|
|
2544
2649
|
if (live === undefined)
|
|
2545
2650
|
return;
|
|
2546
2651
|
return attributesOf10(props, live);
|
|
2547
2652
|
});
|
|
2548
|
-
var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole,
|
|
2549
|
-
list: () =>
|
|
2550
|
-
read:
|
|
2653
|
+
var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect25.succeed(BaoPkiRole.Provider.of({
|
|
2654
|
+
list: () => Effect25.succeed([]),
|
|
2655
|
+
read: Effect25.fn(function* ({ olds }) {
|
|
2551
2656
|
return yield* readRole2(olds);
|
|
2552
2657
|
}),
|
|
2553
|
-
diff:
|
|
2554
|
-
|
|
2658
|
+
diff: Effect25.fn(function* ({ news, olds, output }) {
|
|
2659
|
+
const move = yield* judgeRename(IDENTITY7, olds, news, output);
|
|
2660
|
+
if (output === undefined)
|
|
2555
2661
|
return;
|
|
2556
|
-
if (
|
|
2662
|
+
if (move !== undefined)
|
|
2557
2663
|
return { action: "replace" };
|
|
2664
|
+
if (!isResolved10(news))
|
|
2665
|
+
return;
|
|
2558
2666
|
if (problems6(news).length > 0)
|
|
2559
2667
|
return { action: "update" };
|
|
2560
2668
|
const live = yield* readRole2(news);
|
|
@@ -2562,11 +2670,12 @@ var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect23.succeed(Ba
|
|
|
2562
2670
|
return { action: "update" };
|
|
2563
2671
|
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
2564
2672
|
}),
|
|
2565
|
-
reconcile:
|
|
2673
|
+
reconcile: Effect25.fn(function* ({ news, output }) {
|
|
2566
2674
|
const path = rolePath4(news);
|
|
2675
|
+
yield* guardRename(IDENTITY7, news, output);
|
|
2567
2676
|
const bad = problems6(news);
|
|
2568
2677
|
if (bad.length > 0) {
|
|
2569
|
-
return yield*
|
|
2678
|
+
return yield* Effect25.die(new Error(`Bao.PkiRole ${path}: ${bad.join(" ")}`));
|
|
2570
2679
|
}
|
|
2571
2680
|
const live = yield* readRole2(news);
|
|
2572
2681
|
if (live === undefined || !matches9(live, news)) {
|
|
@@ -2574,14 +2683,14 @@ var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect23.succeed(Ba
|
|
|
2574
2683
|
}
|
|
2575
2684
|
const after = yield* readRole2(news);
|
|
2576
2685
|
if (after === undefined) {
|
|
2577
|
-
return yield*
|
|
2686
|
+
return yield* Effect25.die(new Error(`Bao.PkiRole ${path}: write reported success but the role is absent.`));
|
|
2578
2687
|
}
|
|
2579
2688
|
if (!matches9(after, news)) {
|
|
2580
|
-
return yield*
|
|
2689
|
+
return yield* Effect25.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.`));
|
|
2581
2690
|
}
|
|
2582
2691
|
return after;
|
|
2583
2692
|
}),
|
|
2584
|
-
delete:
|
|
2693
|
+
delete: Effect25.fn(function* ({ output }) {
|
|
2585
2694
|
yield* baoDelete(rolePath4(output));
|
|
2586
2695
|
return;
|
|
2587
2696
|
})
|
|
@@ -2590,7 +2699,7 @@ var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect23.succeed(Ba
|
|
|
2590
2699
|
import { Resource as Resource11 } from "alchemy";
|
|
2591
2700
|
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
2592
2701
|
import * as Provider11 from "alchemy/Provider";
|
|
2593
|
-
import * as
|
|
2702
|
+
import * as Effect27 from "effect/Effect";
|
|
2594
2703
|
|
|
2595
2704
|
// src/openbao/plugin-form.ts
|
|
2596
2705
|
var resolve = (props) => ({
|
|
@@ -2646,7 +2755,7 @@ var sameArgs = (want, have) => want.length === have.length && want.every((entry,
|
|
|
2646
2755
|
var matches10 = (attributes, form) => !attributes.builtin && attributes.version === form.version && attributes.sha256 === form.sha256 && attributes.command === form.command && sameArgs(form.args, attributes.args);
|
|
2647
2756
|
|
|
2648
2757
|
// src/openbao/plugin-reconcile.ts
|
|
2649
|
-
import * as
|
|
2758
|
+
import * as Effect26 from "effect/Effect";
|
|
2650
2759
|
|
|
2651
2760
|
// src/openbao/plugin-wire.ts
|
|
2652
2761
|
var readPluginData = (form) => baoRead(versionedPath(form.type, form.name, form.version));
|
|
@@ -2654,10 +2763,10 @@ var registerPlugin = (form) => baoWrite("PUT", catalogPath(form.type, form.name)
|
|
|
2654
2763
|
var deregisterPlugin = (type, name, version) => baoDelete(versionedPath(type, name, version));
|
|
2655
2764
|
|
|
2656
2765
|
// src/openbao/plugin-reconcile.ts
|
|
2657
|
-
var readEntry = (form) =>
|
|
2658
|
-
var refuse5 = (form, message) =>
|
|
2766
|
+
var readEntry = (form) => Effect26.map(readPluginData(form), (live) => live === undefined ? undefined : { attributes: attributesOf11(form, live), live });
|
|
2767
|
+
var refuse5 = (form, message) => Effect26.die(new Error(`Bao.Plugin ${versionedPath(form.type, form.name, form.version)}: ${message}`));
|
|
2659
2768
|
var SELF_REPORTED = "the write succeeded but the read-back does not match. If the binary reports its own version, " + "OpenBao filed the registration under it (plugin_catalog.go setInternal) — declare `version` " + "as exactly the version the binary reports; that adopts the entry this write just made.";
|
|
2660
|
-
var reconcilePlugin = (props) =>
|
|
2769
|
+
var reconcilePlugin = (props) => Effect26.gen(function* () {
|
|
2661
2770
|
const form = resolve(props);
|
|
2662
2771
|
const bad = problems7(form);
|
|
2663
2772
|
if (bad.length > 0)
|
|
@@ -2684,28 +2793,43 @@ var reconcilePlugin = (props) => Effect24.gen(function* () {
|
|
|
2684
2793
|
var BaoPlugin = Resource11("Bao.Plugin", {
|
|
2685
2794
|
defaultRemovalPolicy: "retain"
|
|
2686
2795
|
});
|
|
2687
|
-
var
|
|
2688
|
-
|
|
2689
|
-
|
|
2796
|
+
var IDENTITY8 = {
|
|
2797
|
+
declared: (props) => {
|
|
2798
|
+
const type = declaredString(props, "type");
|
|
2799
|
+
const name = declaredString(props, "name");
|
|
2800
|
+
const version = declaredOr(props, "version", "");
|
|
2801
|
+
if (type === undefined || name === undefined || version === undefined)
|
|
2802
|
+
return;
|
|
2803
|
+
return versionedPath(type, name, version);
|
|
2804
|
+
},
|
|
2805
|
+
family: "Bao.Plugin",
|
|
2806
|
+
recorded: (output) => versionedPath(output.type, output.name, output.version)
|
|
2807
|
+
};
|
|
2808
|
+
var BaoPluginProvider = () => Provider11.effect(BaoPlugin, Effect27.succeed(BaoPlugin.Provider.of({
|
|
2809
|
+
list: () => Effect27.succeed([]),
|
|
2810
|
+
read: Effect27.fn(function* ({ olds }) {
|
|
2690
2811
|
const found = yield* readEntry(resolve(olds));
|
|
2691
2812
|
return found?.attributes;
|
|
2692
2813
|
}),
|
|
2693
|
-
diff:
|
|
2694
|
-
|
|
2814
|
+
diff: Effect27.fn(function* ({ news, olds, output }) {
|
|
2815
|
+
const move = yield* judgeRename(IDENTITY8, olds, news, output);
|
|
2816
|
+
if (output === undefined)
|
|
2695
2817
|
return;
|
|
2696
|
-
|
|
2697
|
-
if (output.name !== form.name || output.type !== form.type || output.version !== form.version) {
|
|
2818
|
+
if (move !== undefined)
|
|
2698
2819
|
return { action: "replace" };
|
|
2699
|
-
|
|
2820
|
+
if (!isResolved11(news))
|
|
2821
|
+
return;
|
|
2822
|
+
const form = resolve(news);
|
|
2700
2823
|
const found = yield* readEntry(form);
|
|
2701
2824
|
if (found === undefined)
|
|
2702
2825
|
return { action: "update" };
|
|
2703
2826
|
return matches10(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
2704
2827
|
}),
|
|
2705
|
-
reconcile:
|
|
2828
|
+
reconcile: Effect27.fn(function* ({ news, output }) {
|
|
2829
|
+
yield* guardRename(IDENTITY8, news, output);
|
|
2706
2830
|
return yield* reconcilePlugin(news);
|
|
2707
2831
|
}),
|
|
2708
|
-
delete:
|
|
2832
|
+
delete: Effect27.fn(function* ({ output }) {
|
|
2709
2833
|
yield* deregisterPlugin(output.type, output.name, output.version);
|
|
2710
2834
|
return;
|
|
2711
2835
|
})
|
|
@@ -2714,7 +2838,7 @@ var BaoPluginProvider = () => Provider11.effect(BaoPlugin, Effect25.succeed(BaoP
|
|
|
2714
2838
|
import { Resource as Resource12 } from "alchemy";
|
|
2715
2839
|
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
2716
2840
|
import * as Provider12 from "alchemy/Provider";
|
|
2717
|
-
import * as
|
|
2841
|
+
import * as Effect29 from "effect/Effect";
|
|
2718
2842
|
import * as FileSystem from "effect/FileSystem";
|
|
2719
2843
|
import * as Path from "effect/Path";
|
|
2720
2844
|
|
|
@@ -2722,13 +2846,13 @@ import * as Path from "effect/Path";
|
|
|
2722
2846
|
var isEmptyAssembly = (parts, joined) => parts === 0 || !/^\s*path\s+"/m.test(joined);
|
|
2723
2847
|
|
|
2724
2848
|
// src/openbao/policy-wire.ts
|
|
2725
|
-
import * as
|
|
2849
|
+
import * as Effect28 from "effect/Effect";
|
|
2726
2850
|
var policyPath = (name) => `sys/policies/acl/${name}`;
|
|
2727
|
-
var readPolicy = (name) =>
|
|
2851
|
+
var readPolicy = (name) => Effect28.flatMap(baoRead(policyPath(name)), (data) => {
|
|
2728
2852
|
if (data === undefined)
|
|
2729
|
-
return
|
|
2853
|
+
return Effect28.succeed("");
|
|
2730
2854
|
const text11 = data["policy"];
|
|
2731
|
-
return typeof text11 === "string" ?
|
|
2855
|
+
return typeof text11 === "string" ? Effect28.succeed(text11) : Effect28.fail(new BaoError(200, "GET", policyPath(name), ["no data.policy in the response"]));
|
|
2732
2856
|
});
|
|
2733
2857
|
var writePolicy = (name, hcl) => baoWrite("PUT", policyPath(name), { policy: hcl });
|
|
2734
2858
|
var deletePolicy = (name) => baoDelete(policyPath(name));
|
|
@@ -2737,6 +2861,7 @@ var deletePolicy = (name) => baoDelete(policyPath(name));
|
|
|
2737
2861
|
var BaoPolicy = Resource12("Bao.Policy", {
|
|
2738
2862
|
defaultRemovalPolicy: "retain"
|
|
2739
2863
|
});
|
|
2864
|
+
var IDENTITY9 = nameIdentity("Bao.Policy", policyPath, policyKey);
|
|
2740
2865
|
var grantsOf = (hcl) => (hcl.match(/^path /gm) ?? []).length;
|
|
2741
2866
|
var attributesOf12 = (name, hcl, parts) => ({
|
|
2742
2867
|
name,
|
|
@@ -2744,10 +2869,10 @@ var attributesOf12 = (name, hcl, parts) => ({
|
|
|
2744
2869
|
grants: grantsOf(hcl),
|
|
2745
2870
|
parts
|
|
2746
2871
|
});
|
|
2747
|
-
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy,
|
|
2872
|
+
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect29.gen(function* () {
|
|
2748
2873
|
const fs = yield* FileSystem.FileSystem;
|
|
2749
2874
|
const path = yield* Path.Path;
|
|
2750
|
-
const assemble = (dir) =>
|
|
2875
|
+
const assemble = (dir) => Effect29.gen(function* () {
|
|
2751
2876
|
const entries2 = (yield* fs.readDirectory(dir)).filter((f) => f.endsWith(".hcl")).sort();
|
|
2752
2877
|
let joined = "";
|
|
2753
2878
|
for (const f of entries2)
|
|
@@ -2756,23 +2881,29 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect27.gen(function
|
|
|
2756
2881
|
return { joined, parts: entries2.length };
|
|
2757
2882
|
});
|
|
2758
2883
|
return BaoPolicy.Provider.of({
|
|
2759
|
-
list: () =>
|
|
2760
|
-
read:
|
|
2884
|
+
list: () => Effect29.succeed([]),
|
|
2885
|
+
read: Effect29.fn(function* ({ olds }) {
|
|
2761
2886
|
const live = yield* readPolicy(olds.name);
|
|
2762
2887
|
return live.length === 0 ? undefined : attributesOf12(olds.name, live, 0);
|
|
2763
2888
|
}),
|
|
2764
|
-
diff:
|
|
2765
|
-
|
|
2889
|
+
diff: Effect29.fn(function* ({ news, olds, output }) {
|
|
2890
|
+
const move = yield* judgeRename(IDENTITY9, olds, news, output);
|
|
2891
|
+
if (output === undefined)
|
|
2892
|
+
return;
|
|
2893
|
+
if (move !== undefined)
|
|
2894
|
+
return { action: "replace" };
|
|
2895
|
+
if (!isResolved12(news))
|
|
2766
2896
|
return;
|
|
2767
2897
|
const { joined } = yield* assemble(news.fragments);
|
|
2768
2898
|
const live = yield* readPolicy(news.name);
|
|
2769
2899
|
return live.length > 0 && sha256(live) === sha256(joined) ? { action: "noop" } : { action: "update" };
|
|
2770
2900
|
}),
|
|
2771
|
-
reconcile:
|
|
2901
|
+
reconcile: Effect29.fn(function* ({ news, output }) {
|
|
2772
2902
|
const name = news.name;
|
|
2903
|
+
yield* guardRename(IDENTITY9, news, output);
|
|
2773
2904
|
const { joined, parts } = yield* assemble(news.fragments);
|
|
2774
2905
|
if (isEmptyAssembly(parts, joined))
|
|
2775
|
-
return yield*
|
|
2906
|
+
return yield* Effect29.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.`));
|
|
2776
2907
|
const current = yield* readPolicy(name);
|
|
2777
2908
|
if (current.length > 0 && sha256(current) === sha256(joined)) {
|
|
2778
2909
|
return attributesOf12(name, joined, parts);
|
|
@@ -2780,7 +2911,7 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect27.gen(function
|
|
|
2780
2911
|
yield* writePolicy(name, joined);
|
|
2781
2912
|
return attributesOf12(name, joined, parts);
|
|
2782
2913
|
}),
|
|
2783
|
-
delete:
|
|
2914
|
+
delete: Effect29.fn(function* ({ output }) {
|
|
2784
2915
|
yield* deletePolicy(output.name);
|
|
2785
2916
|
return;
|
|
2786
2917
|
})
|
|
@@ -2790,7 +2921,7 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect27.gen(function
|
|
|
2790
2921
|
import { Resource as Resource13 } from "alchemy";
|
|
2791
2922
|
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
2792
2923
|
import * as Provider13 from "alchemy/Provider";
|
|
2793
|
-
import * as
|
|
2924
|
+
import * as Effect31 from "effect/Effect";
|
|
2794
2925
|
|
|
2795
2926
|
// src/openbao/proxmox-role-form.ts
|
|
2796
2927
|
var text11 = (value) => typeof value === "string" ? value : "";
|
|
@@ -2836,25 +2967,44 @@ var sameTtl5 = (want, have) => {
|
|
|
2836
2967
|
const haveSeconds = ttlSeconds(have);
|
|
2837
2968
|
return wantSeconds !== undefined && wantSeconds === haveSeconds;
|
|
2838
2969
|
};
|
|
2970
|
+
var rescopeRefusal = (before, mintUser, allowMintUserChange) => before === mintUser || allowMintUserChange === before ? undefined : `re-scopes mint_user ${before} → ${mintUser}. Every token this role mints inherits ` + `the ACL of that PVE user. To re-scope deliberately, declare allowMintUserChange: '${before}'.`;
|
|
2839
2971
|
var matches11 = (attributes, props) => attributes.mintUser === props.mintUser && sameTtl5(props.ttl, attributes.ttl) && sameTtl5(props.maxTtl, attributes.maxTtl);
|
|
2840
2972
|
|
|
2841
|
-
// src/openbao/proxmox-role.ts
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
});
|
|
2845
|
-
var readRole3 = (props) => Effect28.gen(function* () {
|
|
2973
|
+
// src/openbao/proxmox-role-wire.ts
|
|
2974
|
+
import * as Effect30 from "effect/Effect";
|
|
2975
|
+
var readRole3 = (props) => Effect30.gen(function* () {
|
|
2846
2976
|
const live = yield* baoRead(rolePath5(props.mount, props.name));
|
|
2847
2977
|
if (live === undefined)
|
|
2848
2978
|
return;
|
|
2849
2979
|
return attributesOf13(props, live);
|
|
2850
2980
|
});
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2981
|
+
|
|
2982
|
+
// src/openbao/proxmox-role.ts
|
|
2983
|
+
var BaoProxmoxRole = Resource13("Bao.ProxmoxRole", {
|
|
2984
|
+
defaultRemovalPolicy: "retain"
|
|
2985
|
+
});
|
|
2986
|
+
var IDENTITY10 = roleIdentity("Bao.ProxmoxRole", rolePath5);
|
|
2987
|
+
var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect31.succeed(BaoProxmoxRole.Provider.of({
|
|
2988
|
+
list: () => Effect31.succeed([]),
|
|
2989
|
+
read: Effect31.fn(function* ({ olds }) {
|
|
2854
2990
|
return yield* readRole3(olds);
|
|
2855
2991
|
}),
|
|
2856
|
-
diff:
|
|
2857
|
-
|
|
2992
|
+
diff: Effect31.fn(function* ({ news, olds, output }) {
|
|
2993
|
+
const move = yield* judgeRename(IDENTITY10, olds, news, output);
|
|
2994
|
+
if (output === undefined)
|
|
2995
|
+
return;
|
|
2996
|
+
if (move !== undefined) {
|
|
2997
|
+
const mintUser = declaredString(news, "mintUser");
|
|
2998
|
+
if (mintUser === undefined || isPendingProp(news, "allowMintUserChange"))
|
|
2999
|
+
return;
|
|
3000
|
+
const from = (yield* readRole3(output))?.mintUser ?? output.mintUser;
|
|
3001
|
+
const allow = declaredString(news, "allowMintUserChange");
|
|
3002
|
+
const refusal2 = rescopeRefusal(from, mintUser, allow);
|
|
3003
|
+
if (refusal2 === undefined)
|
|
3004
|
+
return { action: "replace" };
|
|
3005
|
+
return yield* Effect31.die(new Error(`Bao.ProxmoxRole ${move.from} → ${move.to}: the rename ${refusal2}`));
|
|
3006
|
+
}
|
|
3007
|
+
if (!isResolved13(news))
|
|
2858
3008
|
return;
|
|
2859
3009
|
const live = yield* readRole3(news);
|
|
2860
3010
|
if (live === undefined)
|
|
@@ -2863,25 +3013,28 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect28.su
|
|
|
2863
3013
|
return { action: "noop" };
|
|
2864
3014
|
return { action: "update" };
|
|
2865
3015
|
}),
|
|
2866
|
-
reconcile:
|
|
3016
|
+
reconcile: Effect31.fn(function* ({ news, output }) {
|
|
3017
|
+
const path = rolePath5(news.mount, news.name);
|
|
3018
|
+
yield* guardRename(IDENTITY10, news, output);
|
|
2867
3019
|
const live = yield* readRole3(news);
|
|
2868
|
-
|
|
2869
|
-
|
|
3020
|
+
const rescope = live === undefined ? undefined : rescopeRefusal(live.mintUser, news.mintUser, news.allowMintUserChange);
|
|
3021
|
+
if (rescope !== undefined) {
|
|
3022
|
+
return yield* Effect31.die(new Error(`Bao.ProxmoxRole ${path}: ${rescope}`));
|
|
2870
3023
|
}
|
|
2871
3024
|
if (live === undefined || !matches11(live, news)) {
|
|
2872
3025
|
const write = writeBody9(news);
|
|
2873
3026
|
if (!write.ok) {
|
|
2874
|
-
return yield*
|
|
3027
|
+
return yield* Effect31.die(new Error(`Bao.ProxmoxRole ${path}: unparseable duration ` + `${write.bad.join(", ")}. Use 30s / 5m / 1h / 1d, or 0.`));
|
|
2875
3028
|
}
|
|
2876
|
-
yield* baoWrite("PUT",
|
|
3029
|
+
yield* baoWrite("PUT", path, write.body);
|
|
2877
3030
|
}
|
|
2878
3031
|
const after = yield* readRole3(news);
|
|
2879
3032
|
if (after === undefined) {
|
|
2880
|
-
return yield*
|
|
3033
|
+
return yield* Effect31.die(new Error(`Bao.ProxmoxRole ${path}: write returned no error ` + "but the role is still absent."));
|
|
2881
3034
|
}
|
|
2882
3035
|
return after;
|
|
2883
3036
|
}),
|
|
2884
|
-
delete:
|
|
3037
|
+
delete: Effect31.fn(function* ({ output }) {
|
|
2885
3038
|
yield* baoDelete(rolePath5(output.mount, output.name));
|
|
2886
3039
|
return;
|
|
2887
3040
|
})
|
|
@@ -2890,7 +3043,7 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect28.su
|
|
|
2890
3043
|
import { Resource as Resource14 } from "alchemy";
|
|
2891
3044
|
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
2892
3045
|
import * as Provider14 from "alchemy/Provider";
|
|
2893
|
-
import * as
|
|
3046
|
+
import * as Effect32 from "effect/Effect";
|
|
2894
3047
|
|
|
2895
3048
|
// src/openbao/ssh-role-form.ts
|
|
2896
3049
|
var readPath4 = (mount, name) => `${sshMountOf(mount)}/roles/${name}`;
|
|
@@ -2978,16 +3131,7 @@ var sameTtl6 = (want, have) => parseDuration(want) === have;
|
|
|
2978
3131
|
var badDurations = (form) => ["ttl", "maxTtl"].filter((field) => parseDuration(form[field]) === undefined);
|
|
2979
3132
|
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);
|
|
2980
3133
|
|
|
2981
|
-
// src/openbao/ssh-role.ts
|
|
2982
|
-
var BaoSshRole = Resource14("Bao.SshRole", {
|
|
2983
|
-
defaultRemovalPolicy: "retain"
|
|
2984
|
-
});
|
|
2985
|
-
var readRole4 = (form) => Effect29.gen(function* () {
|
|
2986
|
-
const live = yield* baoRead(readPath4(form.mount, form.name));
|
|
2987
|
-
if (live === undefined)
|
|
2988
|
-
return;
|
|
2989
|
-
return { attributes: attributesOf14(form, live), live };
|
|
2990
|
-
});
|
|
3134
|
+
// src/openbao/ssh-role-erase.ts
|
|
2991
3135
|
var UNMANAGED_DEFAULTS = {
|
|
2992
3136
|
algorithm_signer: "default",
|
|
2993
3137
|
allow_commas_in_identity_templates: false,
|
|
@@ -3008,28 +3152,43 @@ var wouldErase2 = (live) => {
|
|
|
3008
3152
|
}
|
|
3009
3153
|
return lost.sort();
|
|
3010
3154
|
};
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3155
|
+
|
|
3156
|
+
// src/openbao/ssh-role.ts
|
|
3157
|
+
var BaoSshRole = Resource14("Bao.SshRole", {
|
|
3158
|
+
defaultRemovalPolicy: "retain"
|
|
3159
|
+
});
|
|
3160
|
+
var IDENTITY11 = roleIdentity("Bao.SshRole", readPath4, "ssh");
|
|
3161
|
+
var readRole4 = (form) => Effect32.gen(function* () {
|
|
3162
|
+
const live = yield* baoRead(readPath4(form.mount, form.name));
|
|
3163
|
+
if (live === undefined)
|
|
3164
|
+
return;
|
|
3165
|
+
return { attributes: attributesOf14(form, live), live };
|
|
3166
|
+
});
|
|
3167
|
+
var refuse6 = (message) => Effect32.die(new Error(message));
|
|
3168
|
+
var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect32.succeed(BaoSshRole.Provider.of({
|
|
3169
|
+
list: () => Effect32.succeed([]),
|
|
3170
|
+
read: Effect32.fn(function* ({ olds }) {
|
|
3015
3171
|
const found = yield* readRole4(resolve2(olds));
|
|
3016
3172
|
return found?.attributes;
|
|
3017
3173
|
}),
|
|
3018
|
-
diff:
|
|
3019
|
-
|
|
3174
|
+
diff: Effect32.fn(function* ({ news, olds, output }) {
|
|
3175
|
+
const move = yield* judgeRename(IDENTITY11, olds, news, output);
|
|
3176
|
+
if (output === undefined)
|
|
3020
3177
|
return;
|
|
3021
|
-
|
|
3022
|
-
if (output.mount !== form.mount || output.name !== form.name) {
|
|
3178
|
+
if (move !== undefined)
|
|
3023
3179
|
return { action: "replace" };
|
|
3024
|
-
|
|
3180
|
+
if (!isResolved14(news))
|
|
3181
|
+
return;
|
|
3182
|
+
const form = resolve2(news);
|
|
3025
3183
|
const found = yield* readRole4(form);
|
|
3026
3184
|
if (found === undefined)
|
|
3027
3185
|
return { action: "update" };
|
|
3028
3186
|
return matches12(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
3029
3187
|
}),
|
|
3030
|
-
reconcile:
|
|
3188
|
+
reconcile: Effect32.fn(function* ({ news, output }) {
|
|
3031
3189
|
const form = resolve2(news);
|
|
3032
3190
|
const path = readPath4(form.mount, form.name);
|
|
3191
|
+
yield* guardRename(IDENTITY11, news, output);
|
|
3033
3192
|
const bad = badDurations(form);
|
|
3034
3193
|
if (bad.length > 0) {
|
|
3035
3194
|
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.");
|
|
@@ -3053,7 +3212,7 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect29.succeed(Ba
|
|
|
3053
3212
|
}
|
|
3054
3213
|
return after.attributes;
|
|
3055
3214
|
}),
|
|
3056
|
-
delete:
|
|
3215
|
+
delete: Effect32.fn(function* ({ output }) {
|
|
3057
3216
|
yield* baoDelete(readPath4(output.mount, output.name));
|
|
3058
3217
|
return;
|
|
3059
3218
|
})
|
|
@@ -3107,5 +3266,5 @@ export {
|
|
|
3107
3266
|
revokeSelfEffect
|
|
3108
3267
|
};
|
|
3109
3268
|
|
|
3110
|
-
//# debugId=
|
|
3269
|
+
//# debugId=B83B2582FB998CE264756E2164756E21
|
|
3111
3270
|
//# sourceMappingURL=index.js.map
|