@homeflare/alchemy 0.7.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 +26 -37
- 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 +71 -13
- package/dist/caddy/index.js.map +9 -9
- package/dist/caddy/with-file.d.ts +7 -3
- package/dist/caddy/with-file.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 +15 -11
- 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/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 +8 -2
- package/dist/openbao/fake-engines.d.ts.map +1 -1
- package/dist/openbao/fake-families.d.ts +49 -0
- package/dist/openbao/fake-families.d.ts.map +1 -0
- package/dist/openbao/host-approles.d.ts.map +1 -1
- package/dist/openbao/index.js +359 -280
- package/dist/openbao/index.js.map +21 -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.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/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 +73 -54
- package/docs/launchd-sudo.md +122 -0
- package/docs/launchd.md +7 -4
- package/docs/peers.md +39 -0
- package/package.json +1 -1
- 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 -11
- 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/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/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 +65 -37
- 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.ts +6 -14
- package/src/openbao/fake-engines-roles.ts +114 -0
- package/src/openbao/fake-engines.ts +18 -11
- package/src/openbao/fake-families.ts +182 -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.ts +7 -7
- package/src/openbao/proxmox-role.ts +7 -16
- 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.ts +19 -15
- 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,54 +1240,22 @@ 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
|
});
|
|
1186
1250
|
|
|
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
1251
|
// src/openbao/cloudflare-role.ts
|
|
1221
1252
|
var BaoCloudflareRole = Resource3("Bao.CloudflareRole", {
|
|
1222
1253
|
defaultRemovalPolicy: "retain"
|
|
1223
1254
|
});
|
|
1224
|
-
var
|
|
1255
|
+
var IDENTITY2 = roleIdentity("Bao.CloudflareRole", rolePath);
|
|
1256
|
+
var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect14.gen(function* () {
|
|
1225
1257
|
const groups = yield* CloudflarePermissionGroups;
|
|
1226
|
-
const resolved = (props) =>
|
|
1258
|
+
const resolved = (props) => Effect14.gen(function* () {
|
|
1227
1259
|
const refs = new Map;
|
|
1228
1260
|
for (const policy of props.policies) {
|
|
1229
1261
|
const scope = policy.scope ?? scopeOfResource(policy.resource);
|
|
@@ -1233,20 +1265,18 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1233
1265
|
const ids = yield* groups.resolve(props.mount, [...refs.values()]);
|
|
1234
1266
|
const { missing, policies } = resolvePolicies(props.policies, ids);
|
|
1235
1267
|
if (missing.length > 0) {
|
|
1236
|
-
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.`));
|
|
1237
1269
|
}
|
|
1238
1270
|
return policies;
|
|
1239
1271
|
});
|
|
1240
1272
|
return BaoCloudflareRole.Provider.of({
|
|
1241
|
-
list: () =>
|
|
1242
|
-
read:
|
|
1273
|
+
list: () => Effect14.succeed([]),
|
|
1274
|
+
read: Effect14.fn(function* ({ olds }) {
|
|
1243
1275
|
const live = yield* readCloudflareRole(olds.mount, olds.name);
|
|
1244
1276
|
return live === undefined ? undefined : attributesOf4(olds, live);
|
|
1245
1277
|
}),
|
|
1246
|
-
diff:
|
|
1247
|
-
const
|
|
1248
|
-
const declared = declaredRolePath(news, rolePath);
|
|
1249
|
-
const move = yield* judgeMove("Bao.CloudflareRole", tried, declared, (path) => path);
|
|
1278
|
+
diff: Effect14.fn(function* ({ news, olds, output }) {
|
|
1279
|
+
const move = yield* judgeRename(IDENTITY2, olds, news, output);
|
|
1250
1280
|
if (output === undefined)
|
|
1251
1281
|
return;
|
|
1252
1282
|
if (move !== undefined)
|
|
@@ -1261,15 +1291,12 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1261
1291
|
return { action: "update" };
|
|
1262
1292
|
return differences(news, policies, live).length === 0 ? { action: "noop" } : { action: "update" };
|
|
1263
1293
|
}),
|
|
1264
|
-
reconcile:
|
|
1294
|
+
reconcile: Effect14.fn(function* ({ news, output }) {
|
|
1265
1295
|
const path = rolePath(news.mount, news.name);
|
|
1266
|
-
|
|
1267
|
-
if (isMoved(before, path) === true) {
|
|
1268
|
-
return yield* refuseMovedUpdate("Bao.CloudflareRole", before, path);
|
|
1269
|
-
}
|
|
1296
|
+
yield* guardRename(IDENTITY2, news, output);
|
|
1270
1297
|
const refusal2 = refusalOf(news);
|
|
1271
1298
|
if (refusal2 !== undefined) {
|
|
1272
|
-
return yield*
|
|
1299
|
+
return yield* Effect14.die(new Error(`Bao.CloudflareRole ${path}: ${refusal2}.`));
|
|
1273
1300
|
}
|
|
1274
1301
|
const policies = yield* resolved(news);
|
|
1275
1302
|
const live = yield* readCloudflareRole(news.mount, news.name);
|
|
@@ -1278,15 +1305,15 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1278
1305
|
}
|
|
1279
1306
|
const after = yield* readCloudflareRole(news.mount, news.name);
|
|
1280
1307
|
if (after === undefined) {
|
|
1281
|
-
return yield*
|
|
1308
|
+
return yield* Effect14.die(new Error(`Bao.CloudflareRole ${path}: the write succeeded but the role is absent.`));
|
|
1282
1309
|
}
|
|
1283
1310
|
const left = differences(news, policies, after);
|
|
1284
1311
|
if (left.length > 0) {
|
|
1285
|
-
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.`));
|
|
1286
1313
|
}
|
|
1287
1314
|
return attributesOf4(news, after);
|
|
1288
1315
|
}),
|
|
1289
|
-
delete:
|
|
1316
|
+
delete: Effect14.fn(function* ({ output }) {
|
|
1290
1317
|
yield* deleteCloudflareRole(output.mount, output.name);
|
|
1291
1318
|
return;
|
|
1292
1319
|
})
|
|
@@ -1509,17 +1536,19 @@ var hostAppRoles = (input) => {
|
|
|
1509
1536
|
if (!NAME.test(host.name)) {
|
|
1510
1537
|
problems.push(`host \`${host.name}\` is not lowercase letters, digits, single hyphens`);
|
|
1511
1538
|
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
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;
|
|
1516
1545
|
if (spec === undefined) {
|
|
1517
1546
|
problems.push(`host \`${host.name}\` names unknown class \`${host.class}\``);
|
|
1518
1547
|
continue;
|
|
1519
1548
|
}
|
|
1520
1549
|
roles.push({
|
|
1521
1550
|
bindSecretId: true,
|
|
1522
|
-
name
|
|
1551
|
+
name,
|
|
1523
1552
|
secretIdNumUses: spec.secretIdNumUses ?? 0,
|
|
1524
1553
|
secretIdTtl: spec.secretIdTtl,
|
|
1525
1554
|
tokenMaxTtl: spec.tokenMaxTtl,
|
|
@@ -1536,7 +1565,7 @@ var hostAppRoles = (input) => {
|
|
|
1536
1565
|
import { Resource as Resource4 } from "alchemy";
|
|
1537
1566
|
import { isResolved as isResolved4 } from "alchemy/Diff";
|
|
1538
1567
|
import * as Provider4 from "alchemy/Provider";
|
|
1539
|
-
import * as
|
|
1568
|
+
import * as Effect16 from "effect/Effect";
|
|
1540
1569
|
|
|
1541
1570
|
// src/openbao/jwt-config-form.ts
|
|
1542
1571
|
var text5 = (value) => typeof value === "string" ? value.trim() : "";
|
|
@@ -1626,16 +1655,16 @@ var problems = (props) => {
|
|
|
1626
1655
|
};
|
|
1627
1656
|
|
|
1628
1657
|
// src/openbao/role-reconcile.ts
|
|
1629
|
-
import * as
|
|
1630
|
-
var readRoleAt = (spec) =>
|
|
1631
|
-
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* () {
|
|
1632
1661
|
if (spec.problems.length > 0)
|
|
1633
1662
|
return "update";
|
|
1634
1663
|
const found = yield* readRoleAt(spec);
|
|
1635
1664
|
return found !== undefined && spec.matches(found.attributes) ? "noop" : "update";
|
|
1636
1665
|
});
|
|
1637
|
-
var refuse2 = (spec, message) =>
|
|
1638
|
-
var reconcileRole = (spec) =>
|
|
1666
|
+
var refuse2 = (spec, message) => Effect15.die(new Error(`${spec.family} ${spec.path}: ${message}`));
|
|
1667
|
+
var reconcileRole = (spec) => Effect15.gen(function* () {
|
|
1639
1668
|
if (spec.problems.length > 0)
|
|
1640
1669
|
return yield* refuse2(spec, spec.problems.join("; "));
|
|
1641
1670
|
const found = yield* readRoleAt(spec);
|
|
@@ -1659,6 +1688,14 @@ var reconcileRole = (spec) => Effect14.gen(function* () {
|
|
|
1659
1688
|
var BaoJwtAuthConfig = Resource4("Bao.JwtAuthConfig", {
|
|
1660
1689
|
defaultRemovalPolicy: "retain"
|
|
1661
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
|
+
};
|
|
1662
1699
|
var jwtConfigSpec = (props) => ({
|
|
1663
1700
|
attributesOf: (live) => attributesOf5(props, live),
|
|
1664
1701
|
body: writeBody3(props),
|
|
@@ -1668,29 +1705,33 @@ var jwtConfigSpec = (props) => ({
|
|
|
1668
1705
|
problems: problems(props),
|
|
1669
1706
|
wouldErase
|
|
1670
1707
|
});
|
|
1671
|
-
var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig,
|
|
1672
|
-
list: () =>
|
|
1673
|
-
read:
|
|
1708
|
+
var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig, Effect16.succeed(BaoJwtAuthConfig.Provider.of({
|
|
1709
|
+
list: () => Effect16.succeed([]),
|
|
1710
|
+
read: Effect16.fn(function* ({ olds }) {
|
|
1674
1711
|
const found = yield* readRoleAt(jwtConfigSpec(olds));
|
|
1675
1712
|
return found?.attributes;
|
|
1676
1713
|
}),
|
|
1677
|
-
diff:
|
|
1678
|
-
|
|
1714
|
+
diff: Effect16.fn(function* ({ news, olds, output }) {
|
|
1715
|
+
const move = yield* judgeRename(IDENTITY3, olds, news, output);
|
|
1716
|
+
if (output === undefined)
|
|
1679
1717
|
return;
|
|
1680
|
-
if (
|
|
1718
|
+
if (move !== undefined)
|
|
1681
1719
|
return { action: "replace" };
|
|
1720
|
+
if (!isResolved4(news))
|
|
1721
|
+
return;
|
|
1682
1722
|
return { action: yield* planRole(jwtConfigSpec(news)) };
|
|
1683
1723
|
}),
|
|
1684
|
-
reconcile:
|
|
1724
|
+
reconcile: Effect16.fn(function* ({ news, output }) {
|
|
1725
|
+
yield* guardRename(IDENTITY3, news, output);
|
|
1685
1726
|
return yield* reconcileRole(jwtConfigSpec(news));
|
|
1686
1727
|
}),
|
|
1687
|
-
delete: () =>
|
|
1728
|
+
delete: () => Effect16.void
|
|
1688
1729
|
})));
|
|
1689
1730
|
// src/openbao/jwt-role.ts
|
|
1690
1731
|
import { Resource as Resource5 } from "alchemy";
|
|
1691
1732
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1692
1733
|
import * as Provider5 from "alchemy/Provider";
|
|
1693
|
-
import * as
|
|
1734
|
+
import * as Effect17 from "effect/Effect";
|
|
1694
1735
|
|
|
1695
1736
|
// src/openbao/auth-token-form.ts
|
|
1696
1737
|
var sortedSet2 = (values) => [...new Set(values)].sort();
|
|
@@ -1892,6 +1933,7 @@ var problems2 = (props) => {
|
|
|
1892
1933
|
var BaoJwtRole = Resource5("Bao.JwtRole", {
|
|
1893
1934
|
defaultRemovalPolicy: "retain"
|
|
1894
1935
|
});
|
|
1936
|
+
var IDENTITY4 = roleIdentity("Bao.JwtRole", (mount, name) => rolePath2({ mount, name }), "jwt", foldName);
|
|
1895
1937
|
var jwtRoleSpec = (props) => ({
|
|
1896
1938
|
attributesOf: (live) => attributesOf6(props, live),
|
|
1897
1939
|
body: writeBody4(props),
|
|
@@ -1900,24 +1942,27 @@ var jwtRoleSpec = (props) => ({
|
|
|
1900
1942
|
path: rolePath2(props),
|
|
1901
1943
|
problems: problems2(props)
|
|
1902
1944
|
});
|
|
1903
|
-
var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole,
|
|
1904
|
-
list: () =>
|
|
1905
|
-
read:
|
|
1945
|
+
var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole, Effect17.succeed(BaoJwtRole.Provider.of({
|
|
1946
|
+
list: () => Effect17.succeed([]),
|
|
1947
|
+
read: Effect17.fn(function* ({ olds }) {
|
|
1906
1948
|
const found = yield* readRoleAt(jwtRoleSpec(olds));
|
|
1907
1949
|
return found?.attributes;
|
|
1908
1950
|
}),
|
|
1909
|
-
diff:
|
|
1910
|
-
|
|
1951
|
+
diff: Effect17.fn(function* ({ news, olds, output }) {
|
|
1952
|
+
const move = yield* judgeRename(IDENTITY4, olds, news, output);
|
|
1953
|
+
if (output === undefined)
|
|
1911
1954
|
return;
|
|
1912
|
-
if (
|
|
1955
|
+
if (move !== undefined)
|
|
1913
1956
|
return { action: "replace" };
|
|
1914
|
-
|
|
1957
|
+
if (!isResolved5(news))
|
|
1958
|
+
return;
|
|
1915
1959
|
return { action: yield* planRole(jwtRoleSpec(news)) };
|
|
1916
1960
|
}),
|
|
1917
|
-
reconcile:
|
|
1961
|
+
reconcile: Effect17.fn(function* ({ news, output }) {
|
|
1962
|
+
yield* guardRename(IDENTITY4, news, output);
|
|
1918
1963
|
return yield* reconcileRole(jwtRoleSpec(news));
|
|
1919
1964
|
}),
|
|
1920
|
-
delete:
|
|
1965
|
+
delete: Effect17.fn(function* ({ output }) {
|
|
1921
1966
|
yield* baoDelete(rolePath2(output));
|
|
1922
1967
|
return;
|
|
1923
1968
|
})
|
|
@@ -1926,7 +1971,7 @@ var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole, Effect16.succeed(Bao
|
|
|
1926
1971
|
import { Resource as Resource6 } from "alchemy";
|
|
1927
1972
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
1928
1973
|
import * as Provider6 from "alchemy/Provider";
|
|
1929
|
-
import * as
|
|
1974
|
+
import * as Effect18 from "effect/Effect";
|
|
1930
1975
|
|
|
1931
1976
|
// src/openbao/kubernetes-role-form.ts
|
|
1932
1977
|
var sortedSet4 = (values) => [...new Set(values)].sort();
|
|
@@ -1995,6 +2040,7 @@ var problems3 = (props) => {
|
|
|
1995
2040
|
var BaoKubernetesRole = Resource6("Bao.KubernetesRole", {
|
|
1996
2041
|
defaultRemovalPolicy: "retain"
|
|
1997
2042
|
});
|
|
2043
|
+
var IDENTITY5 = roleIdentity("Bao.KubernetesRole", (mount, name) => rolePath3({ mount, name }), "kubernetes", foldName);
|
|
1998
2044
|
var kubernetesRoleSpec = (props) => ({
|
|
1999
2045
|
attributesOf: (live) => attributesOf7(props, live),
|
|
2000
2046
|
body: writeBody5(props),
|
|
@@ -2003,24 +2049,27 @@ var kubernetesRoleSpec = (props) => ({
|
|
|
2003
2049
|
path: rolePath3(props),
|
|
2004
2050
|
problems: problems3(props)
|
|
2005
2051
|
});
|
|
2006
|
-
var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole,
|
|
2007
|
-
list: () =>
|
|
2008
|
-
read:
|
|
2052
|
+
var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole, Effect18.succeed(BaoKubernetesRole.Provider.of({
|
|
2053
|
+
list: () => Effect18.succeed([]),
|
|
2054
|
+
read: Effect18.fn(function* ({ olds }) {
|
|
2009
2055
|
const found = yield* readRoleAt(kubernetesRoleSpec(olds));
|
|
2010
2056
|
return found?.attributes;
|
|
2011
2057
|
}),
|
|
2012
|
-
diff:
|
|
2013
|
-
|
|
2058
|
+
diff: Effect18.fn(function* ({ news, olds, output }) {
|
|
2059
|
+
const move = yield* judgeRename(IDENTITY5, olds, news, output);
|
|
2060
|
+
if (output === undefined)
|
|
2014
2061
|
return;
|
|
2015
|
-
if (
|
|
2062
|
+
if (move !== undefined)
|
|
2016
2063
|
return { action: "replace" };
|
|
2017
|
-
|
|
2064
|
+
if (!isResolved6(news))
|
|
2065
|
+
return;
|
|
2018
2066
|
return { action: yield* planRole(kubernetesRoleSpec(news)) };
|
|
2019
2067
|
}),
|
|
2020
|
-
reconcile:
|
|
2068
|
+
reconcile: Effect18.fn(function* ({ news, output }) {
|
|
2069
|
+
yield* guardRename(IDENTITY5, news, output);
|
|
2021
2070
|
return yield* reconcileRole(kubernetesRoleSpec(news));
|
|
2022
2071
|
}),
|
|
2023
|
-
delete:
|
|
2072
|
+
delete: Effect18.fn(function* ({ output }) {
|
|
2024
2073
|
yield* baoDelete(rolePath3(output));
|
|
2025
2074
|
return;
|
|
2026
2075
|
})
|
|
@@ -2029,7 +2078,7 @@ var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole, Effect
|
|
|
2029
2078
|
import { Resource as Resource7 } from "alchemy";
|
|
2030
2079
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2031
2080
|
import * as Provider7 from "alchemy/Provider";
|
|
2032
|
-
import * as
|
|
2081
|
+
import * as Effect20 from "effect/Effect";
|
|
2033
2082
|
|
|
2034
2083
|
// src/openbao/mfa-enforcement-form.ts
|
|
2035
2084
|
var sortedSet5 = (values) => [...new Set(values.map((value) => value.trim()))].filter((value) => value !== "").sort();
|
|
@@ -2097,16 +2146,16 @@ var problems4 = (props, missingPaths) => {
|
|
|
2097
2146
|
};
|
|
2098
2147
|
|
|
2099
2148
|
// src/openbao/mfa-wire.ts
|
|
2100
|
-
import * as
|
|
2149
|
+
import * as Effect19 from "effect/Effect";
|
|
2101
2150
|
var TOTP_PATH = "identity/mfa/method/totp";
|
|
2102
2151
|
var METHODS_PATH = "identity/mfa/method";
|
|
2103
2152
|
var enforcementPath = (name) => `identity/mfa/login-enforcement/${name}`;
|
|
2104
2153
|
var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
2105
|
-
var ownNamespacePath =
|
|
2154
|
+
var ownNamespacePath = Effect19.gen(function* () {
|
|
2106
2155
|
const env = yield* BaoEnv;
|
|
2107
2156
|
return namespacePath(envNamespace(env));
|
|
2108
2157
|
});
|
|
2109
|
-
var findTotp = (name) =>
|
|
2158
|
+
var findTotp = (name) => Effect19.gen(function* () {
|
|
2110
2159
|
const listing = yield* baoRead(`${METHODS_PATH}?list=true`);
|
|
2111
2160
|
const info = record4(listing?.["key_info"]) ?? {};
|
|
2112
2161
|
const own = yield* ownNamespacePath;
|
|
@@ -2115,17 +2164,17 @@ var findTotp = (name) => Effect18.gen(function* () {
|
|
|
2115
2164
|
if (live === undefined || live["name"] !== name || live["namespace_path"] !== own)
|
|
2116
2165
|
continue;
|
|
2117
2166
|
if (live["type"] !== "totp") {
|
|
2118
|
-
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.`));
|
|
2119
2168
|
}
|
|
2120
2169
|
return { id, live };
|
|
2121
2170
|
}
|
|
2122
2171
|
return;
|
|
2123
2172
|
});
|
|
2124
|
-
var writeTotp = (body) =>
|
|
2173
|
+
var writeTotp = (body) => Effect19.asVoid(baoCall("write", "POST", TOTP_PATH, body));
|
|
2125
2174
|
var deleteTotp = (id) => baoDelete(`${TOTP_PATH}/${id}`);
|
|
2126
2175
|
var readEnforcement = (name) => baoRead(enforcementPath(name));
|
|
2127
|
-
var writeEnforcement = (name, body) =>
|
|
2128
|
-
var authAccessors = (paths) =>
|
|
2176
|
+
var writeEnforcement = (name, body) => Effect19.asVoid(baoCall("write", "POST", enforcementPath(name), body));
|
|
2177
|
+
var authAccessors = (paths) => Effect19.gen(function* () {
|
|
2129
2178
|
if (paths.length === 0)
|
|
2130
2179
|
return { accessors: [], missing: [] };
|
|
2131
2180
|
const table = (yield* baoRead("sys/auth")) ?? {};
|
|
@@ -2145,20 +2194,21 @@ var authAccessors = (paths) => Effect18.gen(function* () {
|
|
|
2145
2194
|
var BaoMfaLoginEnforcement = Resource7("Bao.MfaLoginEnforcement", {
|
|
2146
2195
|
defaultRemovalPolicy: "retain"
|
|
2147
2196
|
});
|
|
2148
|
-
var
|
|
2149
|
-
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 }) => ({
|
|
2150
2200
|
bad: problems4(props, missing),
|
|
2151
2201
|
resolved: accessors
|
|
2152
2202
|
}));
|
|
2153
|
-
var readLive = (name) =>
|
|
2154
|
-
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* () {
|
|
2155
2205
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2156
2206
|
if (bad.length > 0)
|
|
2157
2207
|
return "update";
|
|
2158
2208
|
const live = yield* readLive(props.name);
|
|
2159
2209
|
return live !== undefined && matches7(live, props, resolved) ? "noop" : "update";
|
|
2160
2210
|
});
|
|
2161
|
-
var reconcileEnforcement = (props) =>
|
|
2211
|
+
var reconcileEnforcement = (props) => Effect20.gen(function* () {
|
|
2162
2212
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2163
2213
|
if (bad.length > 0)
|
|
2164
2214
|
return yield* refuse3(props.name, bad.join("; "));
|
|
@@ -2174,22 +2224,26 @@ var reconcileEnforcement = (props) => Effect19.gen(function* () {
|
|
|
2174
2224
|
}
|
|
2175
2225
|
return after;
|
|
2176
2226
|
});
|
|
2177
|
-
var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforcement,
|
|
2178
|
-
list: () =>
|
|
2179
|
-
read:
|
|
2227
|
+
var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforcement, Effect20.succeed(BaoMfaLoginEnforcement.Provider.of({
|
|
2228
|
+
list: () => Effect20.succeed([]),
|
|
2229
|
+
read: Effect20.fn(function* ({ olds }) {
|
|
2180
2230
|
return yield* readLive(olds.name);
|
|
2181
2231
|
}),
|
|
2182
|
-
diff:
|
|
2183
|
-
|
|
2232
|
+
diff: Effect20.fn(function* ({ news, olds, output }) {
|
|
2233
|
+
const move = yield* judgeRename(IDENTITY6, olds, news, output);
|
|
2234
|
+
if (output === undefined)
|
|
2184
2235
|
return;
|
|
2185
|
-
if (
|
|
2236
|
+
if (move !== undefined)
|
|
2186
2237
|
return { action: "replace" };
|
|
2238
|
+
if (!isResolved7(news))
|
|
2239
|
+
return;
|
|
2187
2240
|
return { action: yield* planEnforcement(news) };
|
|
2188
2241
|
}),
|
|
2189
|
-
reconcile:
|
|
2242
|
+
reconcile: Effect20.fn(function* ({ news, output }) {
|
|
2243
|
+
yield* guardRename(IDENTITY6, news, output);
|
|
2190
2244
|
return yield* reconcileEnforcement(news);
|
|
2191
2245
|
}),
|
|
2192
|
-
delete:
|
|
2246
|
+
delete: Effect20.fn(function* ({ output }) {
|
|
2193
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.");
|
|
2194
2248
|
})
|
|
2195
2249
|
})));
|
|
@@ -2197,7 +2251,7 @@ var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforceme
|
|
|
2197
2251
|
import { Resource as Resource8 } from "alchemy";
|
|
2198
2252
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2199
2253
|
import * as Provider8 from "alchemy/Provider";
|
|
2200
|
-
import * as
|
|
2254
|
+
import * as Effect21 from "effect/Effect";
|
|
2201
2255
|
|
|
2202
2256
|
// src/openbao/mfa-totp-form.ts
|
|
2203
2257
|
var canonical6 = (input) => ({
|
|
@@ -2278,45 +2332,51 @@ var problems5 = (props) => {
|
|
|
2278
2332
|
var BaoMfaTotpMethod = Resource8("Bao.MfaTotpMethod", {
|
|
2279
2333
|
defaultRemovalPolicy: "retain"
|
|
2280
2334
|
});
|
|
2281
|
-
var refuse4 = (
|
|
2282
|
-
var readTotp = (props) =>
|
|
2283
|
-
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* () {
|
|
2284
2338
|
if (problems5(props).length > 0)
|
|
2285
2339
|
return "update";
|
|
2286
2340
|
const live = yield* readTotp(props);
|
|
2287
2341
|
return live !== undefined && matches8(live, props) ? "noop" : "update";
|
|
2288
2342
|
});
|
|
2289
|
-
var reconcileTotp = (props) =>
|
|
2343
|
+
var reconcileTotp = (props) => Effect21.gen(function* () {
|
|
2290
2344
|
const bad = problems5(props);
|
|
2291
2345
|
if (bad.length > 0)
|
|
2292
|
-
return yield* refuse4(props, bad.join("; "));
|
|
2346
|
+
return yield* refuse4(props.name, bad.join("; "));
|
|
2293
2347
|
const live = yield* readTotp(props);
|
|
2294
2348
|
if (live === undefined || !matches8(live, props))
|
|
2295
2349
|
yield* writeTotp(writeBody7(props));
|
|
2296
2350
|
const after = yield* readTotp(props);
|
|
2297
2351
|
if (after === undefined)
|
|
2298
|
-
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.");
|
|
2299
2353
|
if (!matches8(after, props))
|
|
2300
|
-
return yield* refuse4(props, "the method read back different.");
|
|
2354
|
+
return yield* refuse4(props.name, "the method read back different.");
|
|
2301
2355
|
return after;
|
|
2302
2356
|
});
|
|
2303
|
-
var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod,
|
|
2304
|
-
list: () =>
|
|
2305
|
-
read:
|
|
2357
|
+
var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod, Effect21.succeed(BaoMfaTotpMethod.Provider.of({
|
|
2358
|
+
list: () => Effect21.succeed([]),
|
|
2359
|
+
read: Effect21.fn(function* ({ olds }) {
|
|
2306
2360
|
return yield* readTotp(olds);
|
|
2307
2361
|
}),
|
|
2308
|
-
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
|
+
}
|
|
2309
2369
|
if (output === undefined || !isResolved8(news))
|
|
2310
2370
|
return;
|
|
2311
|
-
const rename = renameProblem(output.name, news.name);
|
|
2312
|
-
if (rename !== undefined)
|
|
2313
|
-
return yield* refuse4(news, rename);
|
|
2314
2371
|
return { action: yield* planTotp(news) };
|
|
2315
2372
|
}),
|
|
2316
|
-
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);
|
|
2317
2377
|
return yield* reconcileTotp(news);
|
|
2318
2378
|
}),
|
|
2319
|
-
delete:
|
|
2379
|
+
delete: Effect21.fn(function* ({ output }) {
|
|
2320
2380
|
yield* deleteTotp(output.methodId);
|
|
2321
2381
|
return;
|
|
2322
2382
|
})
|
|
@@ -2325,24 +2385,24 @@ var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod, Effect20
|
|
|
2325
2385
|
import { Resource as Resource9 } from "alchemy";
|
|
2326
2386
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2327
2387
|
import * as Provider9 from "alchemy/Provider";
|
|
2328
|
-
import * as
|
|
2388
|
+
import * as Effect24 from "effect/Effect";
|
|
2329
2389
|
|
|
2330
2390
|
// src/openbao/mount-reconcile.ts
|
|
2331
|
-
import * as
|
|
2391
|
+
import * as Effect23 from "effect/Effect";
|
|
2332
2392
|
|
|
2333
2393
|
// src/openbao/mount-wire.ts
|
|
2334
|
-
import * as
|
|
2335
|
-
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, [
|
|
2336
2396
|
...asked.errors,
|
|
2337
2397
|
`sys/mounts could not confirm the mount is absent: ${listing.message}`
|
|
2338
|
-
])),
|
|
2339
|
-
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)));
|
|
2340
2400
|
var enableMount = (props) => baoWrite("POST", readPath(props.path), enableBody(props));
|
|
2341
2401
|
var tuneMount = (props) => baoWrite("POST", tunePath(props.path), tuneBody(props));
|
|
2342
2402
|
var disableMount = (path) => baoDelete(readPath(path));
|
|
2343
2403
|
|
|
2344
2404
|
// src/openbao/mount-reconcile.ts
|
|
2345
|
-
var readMount = (props) =>
|
|
2405
|
+
var readMount = (props) => Effect23.gen(function* () {
|
|
2346
2406
|
const live = yield* readMountData(props.path);
|
|
2347
2407
|
if (live === undefined)
|
|
2348
2408
|
return;
|
|
@@ -2355,10 +2415,10 @@ var moveTarget2 = (props) => ({
|
|
|
2355
2415
|
type: props.type,
|
|
2356
2416
|
wire: mountPath
|
|
2357
2417
|
});
|
|
2358
|
-
var reconcileMount = (news, stated, options) =>
|
|
2418
|
+
var reconcileMount = (news, stated, options) => Effect23.gen(function* () {
|
|
2359
2419
|
const move = planMove("Bao.Mount", stated, news.path, news.remountFrom);
|
|
2360
2420
|
if (move.kind === "refuse")
|
|
2361
|
-
return yield*
|
|
2421
|
+
return yield* Effect23.die(new Error(move.message));
|
|
2362
2422
|
if (move.kind === "move")
|
|
2363
2423
|
yield* performMove(moveTarget2(news), move.from, options);
|
|
2364
2424
|
let live = yield* readMount(news);
|
|
@@ -2368,13 +2428,13 @@ var reconcileMount = (news, stated, options) => Effect22.gen(function* () {
|
|
|
2368
2428
|
yield* tuneMount(news);
|
|
2369
2429
|
} else if (!matches(live, news)) {
|
|
2370
2430
|
if (live.type !== news.type) {
|
|
2371
|
-
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."));
|
|
2372
2432
|
}
|
|
2373
2433
|
yield* tuneMount(news);
|
|
2374
2434
|
}
|
|
2375
2435
|
live = yield* readMount(news);
|
|
2376
2436
|
if (live === undefined) {
|
|
2377
|
-
return yield*
|
|
2437
|
+
return yield* Effect23.die(new Error(`Bao.Mount ${mountPath(news.path)}: write returned no error but the mount is still absent.`));
|
|
2378
2438
|
}
|
|
2379
2439
|
return live;
|
|
2380
2440
|
});
|
|
@@ -2383,17 +2443,17 @@ var reconcileMount = (news, stated, options) => Effect22.gen(function* () {
|
|
|
2383
2443
|
var BaoMount = Resource9("Bao.Mount", {
|
|
2384
2444
|
defaultRemovalPolicy: "retain"
|
|
2385
2445
|
});
|
|
2386
|
-
var BaoMountProvider = () => Provider9.effect(BaoMount,
|
|
2387
|
-
list: () =>
|
|
2388
|
-
read:
|
|
2446
|
+
var BaoMountProvider = () => Provider9.effect(BaoMount, Effect24.succeed(BaoMount.Provider.of({
|
|
2447
|
+
list: () => Effect24.succeed([]),
|
|
2448
|
+
read: Effect24.fn(function* ({ olds }) {
|
|
2389
2449
|
return yield* readMount(olds);
|
|
2390
2450
|
}),
|
|
2391
|
-
diff:
|
|
2451
|
+
diff: Effect24.fn(function* ({ news, output }) {
|
|
2392
2452
|
if (output === undefined || !isResolved9(news))
|
|
2393
2453
|
return;
|
|
2394
2454
|
const move = planMove("Bao.Mount", output.path, news.path, news.remountFrom);
|
|
2395
2455
|
if (move.kind === "refuse")
|
|
2396
|
-
return yield*
|
|
2456
|
+
return yield* Effect24.die(new Error(move.message));
|
|
2397
2457
|
if (move.kind === "move")
|
|
2398
2458
|
return { action: "update" };
|
|
2399
2459
|
const live = yield* readMount(news);
|
|
@@ -2405,10 +2465,10 @@ var BaoMountProvider = () => Provider9.effect(BaoMount, Effect23.succeed(BaoMoun
|
|
|
2405
2465
|
return { action: "noop" };
|
|
2406
2466
|
return { action: "update" };
|
|
2407
2467
|
}),
|
|
2408
|
-
reconcile:
|
|
2468
|
+
reconcile: Effect24.fn(function* ({ news, output }) {
|
|
2409
2469
|
return yield* reconcileMount(news, output?.path);
|
|
2410
2470
|
}),
|
|
2411
|
-
delete:
|
|
2471
|
+
delete: Effect24.fn(function* ({ output }) {
|
|
2412
2472
|
yield* disableMount(output.path);
|
|
2413
2473
|
return;
|
|
2414
2474
|
})
|
|
@@ -2417,7 +2477,7 @@ var BaoMountProvider = () => Provider9.effect(BaoMount, Effect23.succeed(BaoMoun
|
|
|
2417
2477
|
import { Resource as Resource10 } from "alchemy";
|
|
2418
2478
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2419
2479
|
import * as Provider10 from "alchemy/Provider";
|
|
2420
|
-
import * as
|
|
2480
|
+
import * as Effect25 from "effect/Effect";
|
|
2421
2481
|
|
|
2422
2482
|
// src/openbao/pki-role-canonical.ts
|
|
2423
2483
|
var DEFAULT_KEY_USAGE = [
|
|
@@ -2583,22 +2643,26 @@ var problems6 = (props) => {
|
|
|
2583
2643
|
var BaoPkiRole = Resource10("Bao.PkiRole", {
|
|
2584
2644
|
defaultRemovalPolicy: "retain"
|
|
2585
2645
|
});
|
|
2586
|
-
var
|
|
2646
|
+
var IDENTITY7 = roleIdentity("Bao.PkiRole", (mount, name) => rolePath4({ mount, name }), "pki");
|
|
2647
|
+
var readRole2 = (props) => Effect25.gen(function* () {
|
|
2587
2648
|
const live = yield* baoRead(rolePath4(props));
|
|
2588
2649
|
if (live === undefined)
|
|
2589
2650
|
return;
|
|
2590
2651
|
return attributesOf10(props, live);
|
|
2591
2652
|
});
|
|
2592
|
-
var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole,
|
|
2593
|
-
list: () =>
|
|
2594
|
-
read:
|
|
2653
|
+
var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect25.succeed(BaoPkiRole.Provider.of({
|
|
2654
|
+
list: () => Effect25.succeed([]),
|
|
2655
|
+
read: Effect25.fn(function* ({ olds }) {
|
|
2595
2656
|
return yield* readRole2(olds);
|
|
2596
2657
|
}),
|
|
2597
|
-
diff:
|
|
2598
|
-
|
|
2658
|
+
diff: Effect25.fn(function* ({ news, olds, output }) {
|
|
2659
|
+
const move = yield* judgeRename(IDENTITY7, olds, news, output);
|
|
2660
|
+
if (output === undefined)
|
|
2599
2661
|
return;
|
|
2600
|
-
if (
|
|
2662
|
+
if (move !== undefined)
|
|
2601
2663
|
return { action: "replace" };
|
|
2664
|
+
if (!isResolved10(news))
|
|
2665
|
+
return;
|
|
2602
2666
|
if (problems6(news).length > 0)
|
|
2603
2667
|
return { action: "update" };
|
|
2604
2668
|
const live = yield* readRole2(news);
|
|
@@ -2606,11 +2670,12 @@ var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect24.succeed(Ba
|
|
|
2606
2670
|
return { action: "update" };
|
|
2607
2671
|
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
2608
2672
|
}),
|
|
2609
|
-
reconcile:
|
|
2673
|
+
reconcile: Effect25.fn(function* ({ news, output }) {
|
|
2610
2674
|
const path = rolePath4(news);
|
|
2675
|
+
yield* guardRename(IDENTITY7, news, output);
|
|
2611
2676
|
const bad = problems6(news);
|
|
2612
2677
|
if (bad.length > 0) {
|
|
2613
|
-
return yield*
|
|
2678
|
+
return yield* Effect25.die(new Error(`Bao.PkiRole ${path}: ${bad.join(" ")}`));
|
|
2614
2679
|
}
|
|
2615
2680
|
const live = yield* readRole2(news);
|
|
2616
2681
|
if (live === undefined || !matches9(live, news)) {
|
|
@@ -2618,14 +2683,14 @@ var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect24.succeed(Ba
|
|
|
2618
2683
|
}
|
|
2619
2684
|
const after = yield* readRole2(news);
|
|
2620
2685
|
if (after === undefined) {
|
|
2621
|
-
return yield*
|
|
2686
|
+
return yield* Effect25.die(new Error(`Bao.PkiRole ${path}: write reported success but the role is absent.`));
|
|
2622
2687
|
}
|
|
2623
2688
|
if (!matches9(after, news)) {
|
|
2624
|
-
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.`));
|
|
2625
2690
|
}
|
|
2626
2691
|
return after;
|
|
2627
2692
|
}),
|
|
2628
|
-
delete:
|
|
2693
|
+
delete: Effect25.fn(function* ({ output }) {
|
|
2629
2694
|
yield* baoDelete(rolePath4(output));
|
|
2630
2695
|
return;
|
|
2631
2696
|
})
|
|
@@ -2634,7 +2699,7 @@ var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect24.succeed(Ba
|
|
|
2634
2699
|
import { Resource as Resource11 } from "alchemy";
|
|
2635
2700
|
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
2636
2701
|
import * as Provider11 from "alchemy/Provider";
|
|
2637
|
-
import * as
|
|
2702
|
+
import * as Effect27 from "effect/Effect";
|
|
2638
2703
|
|
|
2639
2704
|
// src/openbao/plugin-form.ts
|
|
2640
2705
|
var resolve = (props) => ({
|
|
@@ -2690,7 +2755,7 @@ var sameArgs = (want, have) => want.length === have.length && want.every((entry,
|
|
|
2690
2755
|
var matches10 = (attributes, form) => !attributes.builtin && attributes.version === form.version && attributes.sha256 === form.sha256 && attributes.command === form.command && sameArgs(form.args, attributes.args);
|
|
2691
2756
|
|
|
2692
2757
|
// src/openbao/plugin-reconcile.ts
|
|
2693
|
-
import * as
|
|
2758
|
+
import * as Effect26 from "effect/Effect";
|
|
2694
2759
|
|
|
2695
2760
|
// src/openbao/plugin-wire.ts
|
|
2696
2761
|
var readPluginData = (form) => baoRead(versionedPath(form.type, form.name, form.version));
|
|
@@ -2698,10 +2763,10 @@ var registerPlugin = (form) => baoWrite("PUT", catalogPath(form.type, form.name)
|
|
|
2698
2763
|
var deregisterPlugin = (type, name, version) => baoDelete(versionedPath(type, name, version));
|
|
2699
2764
|
|
|
2700
2765
|
// src/openbao/plugin-reconcile.ts
|
|
2701
|
-
var readEntry = (form) =>
|
|
2702
|
-
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}`));
|
|
2703
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.";
|
|
2704
|
-
var reconcilePlugin = (props) =>
|
|
2769
|
+
var reconcilePlugin = (props) => Effect26.gen(function* () {
|
|
2705
2770
|
const form = resolve(props);
|
|
2706
2771
|
const bad = problems7(form);
|
|
2707
2772
|
if (bad.length > 0)
|
|
@@ -2728,28 +2793,43 @@ var reconcilePlugin = (props) => Effect25.gen(function* () {
|
|
|
2728
2793
|
var BaoPlugin = Resource11("Bao.Plugin", {
|
|
2729
2794
|
defaultRemovalPolicy: "retain"
|
|
2730
2795
|
});
|
|
2731
|
-
var
|
|
2732
|
-
|
|
2733
|
-
|
|
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 }) {
|
|
2734
2811
|
const found = yield* readEntry(resolve(olds));
|
|
2735
2812
|
return found?.attributes;
|
|
2736
2813
|
}),
|
|
2737
|
-
diff:
|
|
2738
|
-
|
|
2814
|
+
diff: Effect27.fn(function* ({ news, olds, output }) {
|
|
2815
|
+
const move = yield* judgeRename(IDENTITY8, olds, news, output);
|
|
2816
|
+
if (output === undefined)
|
|
2739
2817
|
return;
|
|
2740
|
-
|
|
2741
|
-
if (output.name !== form.name || output.type !== form.type || output.version !== form.version) {
|
|
2818
|
+
if (move !== undefined)
|
|
2742
2819
|
return { action: "replace" };
|
|
2743
|
-
|
|
2820
|
+
if (!isResolved11(news))
|
|
2821
|
+
return;
|
|
2822
|
+
const form = resolve(news);
|
|
2744
2823
|
const found = yield* readEntry(form);
|
|
2745
2824
|
if (found === undefined)
|
|
2746
2825
|
return { action: "update" };
|
|
2747
2826
|
return matches10(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
2748
2827
|
}),
|
|
2749
|
-
reconcile:
|
|
2828
|
+
reconcile: Effect27.fn(function* ({ news, output }) {
|
|
2829
|
+
yield* guardRename(IDENTITY8, news, output);
|
|
2750
2830
|
return yield* reconcilePlugin(news);
|
|
2751
2831
|
}),
|
|
2752
|
-
delete:
|
|
2832
|
+
delete: Effect27.fn(function* ({ output }) {
|
|
2753
2833
|
yield* deregisterPlugin(output.type, output.name, output.version);
|
|
2754
2834
|
return;
|
|
2755
2835
|
})
|
|
@@ -2758,7 +2838,7 @@ var BaoPluginProvider = () => Provider11.effect(BaoPlugin, Effect26.succeed(BaoP
|
|
|
2758
2838
|
import { Resource as Resource12 } from "alchemy";
|
|
2759
2839
|
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
2760
2840
|
import * as Provider12 from "alchemy/Provider";
|
|
2761
|
-
import * as
|
|
2841
|
+
import * as Effect29 from "effect/Effect";
|
|
2762
2842
|
import * as FileSystem from "effect/FileSystem";
|
|
2763
2843
|
import * as Path from "effect/Path";
|
|
2764
2844
|
|
|
@@ -2766,13 +2846,13 @@ import * as Path from "effect/Path";
|
|
|
2766
2846
|
var isEmptyAssembly = (parts, joined) => parts === 0 || !/^\s*path\s+"/m.test(joined);
|
|
2767
2847
|
|
|
2768
2848
|
// src/openbao/policy-wire.ts
|
|
2769
|
-
import * as
|
|
2849
|
+
import * as Effect28 from "effect/Effect";
|
|
2770
2850
|
var policyPath = (name) => `sys/policies/acl/${name}`;
|
|
2771
|
-
var readPolicy = (name) =>
|
|
2851
|
+
var readPolicy = (name) => Effect28.flatMap(baoRead(policyPath(name)), (data) => {
|
|
2772
2852
|
if (data === undefined)
|
|
2773
|
-
return
|
|
2853
|
+
return Effect28.succeed("");
|
|
2774
2854
|
const text11 = data["policy"];
|
|
2775
|
-
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"]));
|
|
2776
2856
|
});
|
|
2777
2857
|
var writePolicy = (name, hcl) => baoWrite("PUT", policyPath(name), { policy: hcl });
|
|
2778
2858
|
var deletePolicy = (name) => baoDelete(policyPath(name));
|
|
@@ -2781,6 +2861,7 @@ var deletePolicy = (name) => baoDelete(policyPath(name));
|
|
|
2781
2861
|
var BaoPolicy = Resource12("Bao.Policy", {
|
|
2782
2862
|
defaultRemovalPolicy: "retain"
|
|
2783
2863
|
});
|
|
2864
|
+
var IDENTITY9 = nameIdentity("Bao.Policy", policyPath, policyKey);
|
|
2784
2865
|
var grantsOf = (hcl) => (hcl.match(/^path /gm) ?? []).length;
|
|
2785
2866
|
var attributesOf12 = (name, hcl, parts) => ({
|
|
2786
2867
|
name,
|
|
@@ -2788,10 +2869,10 @@ var attributesOf12 = (name, hcl, parts) => ({
|
|
|
2788
2869
|
grants: grantsOf(hcl),
|
|
2789
2870
|
parts
|
|
2790
2871
|
});
|
|
2791
|
-
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy,
|
|
2872
|
+
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect29.gen(function* () {
|
|
2792
2873
|
const fs = yield* FileSystem.FileSystem;
|
|
2793
2874
|
const path = yield* Path.Path;
|
|
2794
|
-
const assemble = (dir) =>
|
|
2875
|
+
const assemble = (dir) => Effect29.gen(function* () {
|
|
2795
2876
|
const entries2 = (yield* fs.readDirectory(dir)).filter((f) => f.endsWith(".hcl")).sort();
|
|
2796
2877
|
let joined = "";
|
|
2797
2878
|
for (const f of entries2)
|
|
@@ -2800,15 +2881,13 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect28.gen(function
|
|
|
2800
2881
|
return { joined, parts: entries2.length };
|
|
2801
2882
|
});
|
|
2802
2883
|
return BaoPolicy.Provider.of({
|
|
2803
|
-
list: () =>
|
|
2804
|
-
read:
|
|
2884
|
+
list: () => Effect29.succeed([]),
|
|
2885
|
+
read: Effect29.fn(function* ({ olds }) {
|
|
2805
2886
|
const live = yield* readPolicy(olds.name);
|
|
2806
2887
|
return live.length === 0 ? undefined : attributesOf12(olds.name, live, 0);
|
|
2807
2888
|
}),
|
|
2808
|
-
diff:
|
|
2809
|
-
const
|
|
2810
|
-
const declared = declaredString(news, "name");
|
|
2811
|
-
const move = yield* judgeMove("Bao.Policy", tried, declared, policyPath, policyKey);
|
|
2889
|
+
diff: Effect29.fn(function* ({ news, olds, output }) {
|
|
2890
|
+
const move = yield* judgeRename(IDENTITY9, olds, news, output);
|
|
2812
2891
|
if (output === undefined)
|
|
2813
2892
|
return;
|
|
2814
2893
|
if (move !== undefined)
|
|
@@ -2819,14 +2898,12 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect28.gen(function
|
|
|
2819
2898
|
const live = yield* readPolicy(news.name);
|
|
2820
2899
|
return live.length > 0 && sha256(live) === sha256(joined) ? { action: "noop" } : { action: "update" };
|
|
2821
2900
|
}),
|
|
2822
|
-
reconcile:
|
|
2901
|
+
reconcile: Effect29.fn(function* ({ news, output }) {
|
|
2823
2902
|
const name = news.name;
|
|
2824
|
-
|
|
2825
|
-
return yield* refuseMovedUpdate(`Bao.Policy ${name}`, output.name, name);
|
|
2826
|
-
}
|
|
2903
|
+
yield* guardRename(IDENTITY9, news, output);
|
|
2827
2904
|
const { joined, parts } = yield* assemble(news.fragments);
|
|
2828
2905
|
if (isEmptyAssembly(parts, joined))
|
|
2829
|
-
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.`));
|
|
2830
2907
|
const current = yield* readPolicy(name);
|
|
2831
2908
|
if (current.length > 0 && sha256(current) === sha256(joined)) {
|
|
2832
2909
|
return attributesOf12(name, joined, parts);
|
|
@@ -2834,7 +2911,7 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect28.gen(function
|
|
|
2834
2911
|
yield* writePolicy(name, joined);
|
|
2835
2912
|
return attributesOf12(name, joined, parts);
|
|
2836
2913
|
}),
|
|
2837
|
-
delete:
|
|
2914
|
+
delete: Effect29.fn(function* ({ output }) {
|
|
2838
2915
|
yield* deletePolicy(output.name);
|
|
2839
2916
|
return;
|
|
2840
2917
|
})
|
|
@@ -2844,7 +2921,7 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect28.gen(function
|
|
|
2844
2921
|
import { Resource as Resource13 } from "alchemy";
|
|
2845
2922
|
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
2846
2923
|
import * as Provider13 from "alchemy/Provider";
|
|
2847
|
-
import * as
|
|
2924
|
+
import * as Effect31 from "effect/Effect";
|
|
2848
2925
|
|
|
2849
2926
|
// src/openbao/proxmox-role-form.ts
|
|
2850
2927
|
var text11 = (value) => typeof value === "string" ? value : "";
|
|
@@ -2894,8 +2971,8 @@ var rescopeRefusal = (before, mintUser, allowMintUserChange) => before === mintU
|
|
|
2894
2971
|
var matches11 = (attributes, props) => attributes.mintUser === props.mintUser && sameTtl5(props.ttl, attributes.ttl) && sameTtl5(props.maxTtl, attributes.maxTtl);
|
|
2895
2972
|
|
|
2896
2973
|
// src/openbao/proxmox-role-wire.ts
|
|
2897
|
-
import * as
|
|
2898
|
-
var readRole3 = (props) =>
|
|
2974
|
+
import * as Effect30 from "effect/Effect";
|
|
2975
|
+
var readRole3 = (props) => Effect30.gen(function* () {
|
|
2899
2976
|
const live = yield* baoRead(rolePath5(props.mount, props.name));
|
|
2900
2977
|
if (live === undefined)
|
|
2901
2978
|
return;
|
|
@@ -2906,15 +2983,14 @@ var readRole3 = (props) => Effect29.gen(function* () {
|
|
|
2906
2983
|
var BaoProxmoxRole = Resource13("Bao.ProxmoxRole", {
|
|
2907
2984
|
defaultRemovalPolicy: "retain"
|
|
2908
2985
|
});
|
|
2909
|
-
var
|
|
2910
|
-
|
|
2911
|
-
|
|
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 }) {
|
|
2912
2990
|
return yield* readRole3(olds);
|
|
2913
2991
|
}),
|
|
2914
|
-
diff:
|
|
2915
|
-
const
|
|
2916
|
-
const declared = declaredRolePath(news, rolePath5);
|
|
2917
|
-
const move = yield* judgeMove("Bao.ProxmoxRole", tried, declared, (path) => path);
|
|
2992
|
+
diff: Effect31.fn(function* ({ news, olds, output }) {
|
|
2993
|
+
const move = yield* judgeRename(IDENTITY10, olds, news, output);
|
|
2918
2994
|
if (output === undefined)
|
|
2919
2995
|
return;
|
|
2920
2996
|
if (move !== undefined) {
|
|
@@ -2926,7 +3002,7 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect30.su
|
|
|
2926
3002
|
const refusal2 = rescopeRefusal(from, mintUser, allow);
|
|
2927
3003
|
if (refusal2 === undefined)
|
|
2928
3004
|
return { action: "replace" };
|
|
2929
|
-
return yield*
|
|
3005
|
+
return yield* Effect31.die(new Error(`Bao.ProxmoxRole ${move.from} → ${move.to}: the rename ${refusal2}`));
|
|
2930
3006
|
}
|
|
2931
3007
|
if (!isResolved13(news))
|
|
2932
3008
|
return;
|
|
@@ -2937,31 +3013,28 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect30.su
|
|
|
2937
3013
|
return { action: "noop" };
|
|
2938
3014
|
return { action: "update" };
|
|
2939
3015
|
}),
|
|
2940
|
-
reconcile:
|
|
3016
|
+
reconcile: Effect31.fn(function* ({ news, output }) {
|
|
2941
3017
|
const path = rolePath5(news.mount, news.name);
|
|
2942
|
-
|
|
2943
|
-
if (isMoved(before, path) === true) {
|
|
2944
|
-
return yield* refuseMovedUpdate("Bao.ProxmoxRole", before, path);
|
|
2945
|
-
}
|
|
3018
|
+
yield* guardRename(IDENTITY10, news, output);
|
|
2946
3019
|
const live = yield* readRole3(news);
|
|
2947
3020
|
const rescope = live === undefined ? undefined : rescopeRefusal(live.mintUser, news.mintUser, news.allowMintUserChange);
|
|
2948
3021
|
if (rescope !== undefined) {
|
|
2949
|
-
return yield*
|
|
3022
|
+
return yield* Effect31.die(new Error(`Bao.ProxmoxRole ${path}: ${rescope}`));
|
|
2950
3023
|
}
|
|
2951
3024
|
if (live === undefined || !matches11(live, news)) {
|
|
2952
3025
|
const write = writeBody9(news);
|
|
2953
3026
|
if (!write.ok) {
|
|
2954
|
-
return yield*
|
|
3027
|
+
return yield* Effect31.die(new Error(`Bao.ProxmoxRole ${path}: unparseable duration ` + `${write.bad.join(", ")}. Use 30s / 5m / 1h / 1d, or 0.`));
|
|
2955
3028
|
}
|
|
2956
3029
|
yield* baoWrite("PUT", path, write.body);
|
|
2957
3030
|
}
|
|
2958
3031
|
const after = yield* readRole3(news);
|
|
2959
3032
|
if (after === undefined) {
|
|
2960
|
-
return yield*
|
|
3033
|
+
return yield* Effect31.die(new Error(`Bao.ProxmoxRole ${path}: write returned no error ` + "but the role is still absent."));
|
|
2961
3034
|
}
|
|
2962
3035
|
return after;
|
|
2963
3036
|
}),
|
|
2964
|
-
delete:
|
|
3037
|
+
delete: Effect31.fn(function* ({ output }) {
|
|
2965
3038
|
yield* baoDelete(rolePath5(output.mount, output.name));
|
|
2966
3039
|
return;
|
|
2967
3040
|
})
|
|
@@ -2970,7 +3043,7 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect30.su
|
|
|
2970
3043
|
import { Resource as Resource14 } from "alchemy";
|
|
2971
3044
|
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
2972
3045
|
import * as Provider14 from "alchemy/Provider";
|
|
2973
|
-
import * as
|
|
3046
|
+
import * as Effect32 from "effect/Effect";
|
|
2974
3047
|
|
|
2975
3048
|
// src/openbao/ssh-role-form.ts
|
|
2976
3049
|
var readPath4 = (mount, name) => `${sshMountOf(mount)}/roles/${name}`;
|
|
@@ -3058,16 +3131,7 @@ var sameTtl6 = (want, have) => parseDuration(want) === have;
|
|
|
3058
3131
|
var badDurations = (form) => ["ttl", "maxTtl"].filter((field) => parseDuration(form[field]) === undefined);
|
|
3059
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);
|
|
3060
3133
|
|
|
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
|
-
});
|
|
3134
|
+
// src/openbao/ssh-role-erase.ts
|
|
3071
3135
|
var UNMANAGED_DEFAULTS = {
|
|
3072
3136
|
algorithm_signer: "default",
|
|
3073
3137
|
allow_commas_in_identity_templates: false,
|
|
@@ -3088,28 +3152,43 @@ var wouldErase2 = (live) => {
|
|
|
3088
3152
|
}
|
|
3089
3153
|
return lost.sort();
|
|
3090
3154
|
};
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
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 }) {
|
|
3095
3171
|
const found = yield* readRole4(resolve2(olds));
|
|
3096
3172
|
return found?.attributes;
|
|
3097
3173
|
}),
|
|
3098
|
-
diff:
|
|
3099
|
-
|
|
3174
|
+
diff: Effect32.fn(function* ({ news, olds, output }) {
|
|
3175
|
+
const move = yield* judgeRename(IDENTITY11, olds, news, output);
|
|
3176
|
+
if (output === undefined)
|
|
3100
3177
|
return;
|
|
3101
|
-
|
|
3102
|
-
if (output.mount !== form.mount || output.name !== form.name) {
|
|
3178
|
+
if (move !== undefined)
|
|
3103
3179
|
return { action: "replace" };
|
|
3104
|
-
|
|
3180
|
+
if (!isResolved14(news))
|
|
3181
|
+
return;
|
|
3182
|
+
const form = resolve2(news);
|
|
3105
3183
|
const found = yield* readRole4(form);
|
|
3106
3184
|
if (found === undefined)
|
|
3107
3185
|
return { action: "update" };
|
|
3108
3186
|
return matches12(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
3109
3187
|
}),
|
|
3110
|
-
reconcile:
|
|
3188
|
+
reconcile: Effect32.fn(function* ({ news, output }) {
|
|
3111
3189
|
const form = resolve2(news);
|
|
3112
3190
|
const path = readPath4(form.mount, form.name);
|
|
3191
|
+
yield* guardRename(IDENTITY11, news, output);
|
|
3113
3192
|
const bad = badDurations(form);
|
|
3114
3193
|
if (bad.length > 0) {
|
|
3115
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.");
|
|
@@ -3133,7 +3212,7 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect31.succeed(Ba
|
|
|
3133
3212
|
}
|
|
3134
3213
|
return after.attributes;
|
|
3135
3214
|
}),
|
|
3136
|
-
delete:
|
|
3215
|
+
delete: Effect32.fn(function* ({ output }) {
|
|
3137
3216
|
yield* baoDelete(readPath4(output.mount, output.name));
|
|
3138
3217
|
return;
|
|
3139
3218
|
})
|
|
@@ -3187,5 +3266,5 @@ export {
|
|
|
3187
3266
|
revokeSelfEffect
|
|
3188
3267
|
};
|
|
3189
3268
|
|
|
3190
|
-
//# debugId=
|
|
3269
|
+
//# debugId=B83B2582FB998CE264756E2164756E21
|
|
3191
3270
|
//# sourceMappingURL=index.js.map
|