@homeflare/alchemy 0.37.5 → 0.37.6
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/dist/openbao/auth-role-form.d.ts +0 -6
- package/dist/openbao/auth-role-form.d.ts.map +1 -1
- package/dist/openbao/auth-role-identity.d.ts +11 -0
- package/dist/openbao/auth-role-identity.d.ts.map +1 -0
- package/dist/openbao/auth-role-wire.d.ts +23 -0
- package/dist/openbao/auth-role-wire.d.ts.map +1 -0
- package/dist/openbao/auth-role.d.ts.map +1 -1
- package/dist/openbao/bao-http.d.ts +34 -13
- package/dist/openbao/bao-http.d.ts.map +1 -1
- package/dist/openbao/distilled.d.ts +25 -0
- package/dist/openbao/distilled.d.ts.map +1 -0
- package/dist/openbao/fake-engines-roles.d.ts +5 -1
- package/dist/openbao/fake-engines-roles.d.ts.map +1 -1
- package/dist/openbao/index.js +358 -305
- package/dist/openbao/index.js.map +13 -9
- package/dist/openbao/policy-identity.d.ts +12 -0
- package/dist/openbao/policy-identity.d.ts.map +1 -0
- package/dist/openbao/policy-wire.d.ts +9 -8
- package/dist/openbao/policy-wire.d.ts.map +1 -1
- package/dist/openbao/policy.d.ts.map +1 -1
- package/dist/openbao/rename.d.ts +5 -0
- package/dist/openbao/rename.d.ts.map +1 -1
- package/dist/proxmox/index.js +2 -2
- package/dist/proxmox/index.js.map +3 -3
- package/dist/proxmox/node-network-wire.d.ts +14 -10
- package/dist/proxmox/node-network-wire.d.ts.map +1 -1
- package/docs/upstream-conformance.md +5 -3
- package/package.json +3 -2
- package/src/openbao/auth-role-form.test.ts +11 -9
- package/src/openbao/auth-role-form.ts +0 -19
- package/src/openbao/auth-role-identity.ts +24 -0
- package/src/openbao/auth-role-sdk.test.ts +155 -0
- package/src/openbao/auth-role-wire.test.ts +128 -0
- package/src/openbao/auth-role-wire.ts +89 -0
- package/src/openbao/auth-role.ts +9 -9
- package/src/openbao/bao-http.ts +9 -7
- package/src/openbao/distilled-retry.test.ts +164 -0
- package/src/openbao/distilled.test.ts +146 -0
- package/src/openbao/distilled.ts +88 -0
- package/src/openbao/fake-engines-roles.ts +9 -2
- package/src/openbao/policy-distilled.test.ts +98 -0
- package/src/openbao/policy-identity.ts +24 -0
- package/src/openbao/policy-rename.test.ts +2 -2
- package/src/openbao/policy-wire.test.ts +5 -5
- package/src/openbao/policy-wire.ts +31 -11
- package/src/openbao/policy.ts +10 -13
- package/src/openbao/rename.ts +17 -1
- package/src/proxmox/node-network-read-failure.test.ts +24 -0
- package/src/proxmox/node-network-wire.ts +15 -17
package/dist/openbao/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import * as Effect2 from "effect/Effect";
|
|
|
3
3
|
import * as FetchHttpClient2 from "effect/unstable/http/FetchHttpClient";
|
|
4
4
|
|
|
5
5
|
// src/openbao/bao-http.ts
|
|
6
|
+
import * as Cause from "effect/Cause";
|
|
6
7
|
import * as Context from "effect/Context";
|
|
7
8
|
import * as Effect from "effect/Effect";
|
|
8
9
|
import * as Option from "effect/Option";
|
|
@@ -95,11 +96,11 @@ var MAX_IN_FLIGHT = 8;
|
|
|
95
96
|
var BaoGate = Context.Reference("homeflare/openbao/BaoGate", {
|
|
96
97
|
defaultValue: () => Semaphore.makeUnsafe(MAX_IN_FLIGHT)
|
|
97
98
|
});
|
|
98
|
-
var
|
|
99
|
+
var BAO_TIMEOUT = "60 seconds";
|
|
99
100
|
var retryTransport = (effect) => Effect.retry(effect, {
|
|
100
101
|
schedule: Schedule.spaced("750 millis"),
|
|
101
102
|
times: 2,
|
|
102
|
-
while: (error) => error.status === 0
|
|
103
|
+
while: (error) => error instanceof BaoError && error.status === 0 || Cause.isTimeoutError(error)
|
|
103
104
|
});
|
|
104
105
|
var redactingToken = (effect) => Effect.gen(function* () {
|
|
105
106
|
const names = yield* Headers.CurrentRedactedNames;
|
|
@@ -124,7 +125,7 @@ var baoCall = (intent, method, path, body) => Effect.gen(function* () {
|
|
|
124
125
|
const address = resolveAddress(env);
|
|
125
126
|
const client = yield* HttpClient.HttpClient;
|
|
126
127
|
const request = HttpClientRequest.make(method)(`${address.base}/v1/${path}`).pipe(HttpClientRequest.setHeaders(headersFor(address, env)), body === undefined ? (self) => self : HttpClientRequest.bodyText(JSON.stringify(body), "application/json"));
|
|
127
|
-
const exchange = client.execute(request).pipe(Effect.flatMap((response) => Effect.map(response.text, (text2) => ({ status: response.status, text: text2 }))), Effect.timeout(
|
|
128
|
+
const exchange = client.execute(request).pipe(Effect.flatMap((response) => Effect.map(response.text, (text2) => ({ status: response.status, text: text2 }))), Effect.timeout(BAO_TIMEOUT), Effect.mapError((cause) => new BaoError(0, method, path, [cause.message])));
|
|
128
129
|
const gate = yield* BaoGate;
|
|
129
130
|
const { status, text } = yield* retryTransport(exchange.pipe(overSocket(address.socket, method, path), redactingToken, Semaphore.withPermits(gate, 1)));
|
|
130
131
|
const outcome = settle(intent, method, path, status, text);
|
|
@@ -827,7 +828,7 @@ var BaoAuthMethodProvider = () => Provider.effect(BaoAuthMethod, Effect12.succee
|
|
|
827
828
|
import { Resource as Resource2 } from "alchemy";
|
|
828
829
|
import { isResolved as isResolved2 } from "alchemy/Diff";
|
|
829
830
|
import * as Provider2 from "alchemy/Provider";
|
|
830
|
-
import * as
|
|
831
|
+
import * as Effect17 from "effect/Effect";
|
|
831
832
|
|
|
832
833
|
// src/openbao/auth-role-form.ts
|
|
833
834
|
var policiesOf = (live) => {
|
|
@@ -862,20 +863,6 @@ var attributesOf3 = (props, live) => {
|
|
|
862
863
|
return { ...attrs, digest: sha256(JSON.stringify(attrs)) };
|
|
863
864
|
};
|
|
864
865
|
var readPath3 = (name) => `auth/approle/role/${name}`;
|
|
865
|
-
var writeBody = (props) => {
|
|
866
|
-
const body = {
|
|
867
|
-
token_policies: props.tokenPolicies.join(","),
|
|
868
|
-
token_ttl: props.tokenTtl,
|
|
869
|
-
token_max_ttl: props.tokenMaxTtl,
|
|
870
|
-
secret_id_ttl: props.secretIdTtl
|
|
871
|
-
};
|
|
872
|
-
if (props.bindSecretId !== undefined)
|
|
873
|
-
body["bind_secret_id"] = String(props.bindSecretId);
|
|
874
|
-
if (props.secretIdNumUses !== undefined) {
|
|
875
|
-
body["secret_id_num_uses"] = String(props.secretIdNumUses);
|
|
876
|
-
}
|
|
877
|
-
return body;
|
|
878
|
-
};
|
|
879
866
|
var samePolicies = (want, have) => want.length === have.length && want.every((policy, index) => policy === have[index]);
|
|
880
867
|
var sameTtl3 = (want, have) => {
|
|
881
868
|
const wantSeconds = parseDuration(want);
|
|
@@ -887,12 +874,65 @@ var matches3 = (attributes, props) => {
|
|
|
887
874
|
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);
|
|
888
875
|
};
|
|
889
876
|
|
|
890
|
-
// src/openbao/
|
|
877
|
+
// src/openbao/auth-role-wire.ts
|
|
878
|
+
import {
|
|
879
|
+
appRoleDeleteRole,
|
|
880
|
+
appRoleReadRole,
|
|
881
|
+
appRoleWriteRole
|
|
882
|
+
} from "@distilled.cloud/openbao/approle";
|
|
891
883
|
import * as Effect14 from "effect/Effect";
|
|
892
884
|
|
|
893
|
-
// src/openbao/
|
|
885
|
+
// src/openbao/distilled.ts
|
|
886
|
+
import { Credentials, normalizeBaseUrl } from "@distilled.cloud/openbao/Credentials";
|
|
887
|
+
import * as Retry from "@distilled.cloud/openbao/Retry";
|
|
894
888
|
import * as Effect13 from "effect/Effect";
|
|
895
|
-
|
|
889
|
+
import * as Redacted from "effect/Redacted";
|
|
890
|
+
import * as Semaphore2 from "effect/Semaphore";
|
|
891
|
+
import { isHttpClientError } from "effect/unstable/http/HttpClientError";
|
|
892
|
+
var runBao = (operation, timeout3 = BAO_TIMEOUT) => Effect13.gen(function* () {
|
|
893
|
+
const env = yield* BaoEnv;
|
|
894
|
+
const address = resolveAddress(env);
|
|
895
|
+
const token = readBaoVariable(env, "BAO_TOKEN");
|
|
896
|
+
const gate = yield* BaoGate;
|
|
897
|
+
return yield* operation.pipe(Effect13.provideService(Credentials, Effect13.succeed({
|
|
898
|
+
apiBaseUrl: normalizeBaseUrl(address.base),
|
|
899
|
+
...address.namespace === undefined ? {} : { namespace: address.namespace },
|
|
900
|
+
...token === "" ? {} : { token: Redacted.make(token) }
|
|
901
|
+
})), Retry.none, Effect13.mapError((cause) => isHttpClientError(cause) ? new BaoError(0, "SDK", "operation", [cause.message]) : cause), Effect13.timeout(timeout3), overSocket(address.socket, "SDK", "operation"), redactingToken, Semaphore2.withPermits(gate, 1));
|
|
902
|
+
});
|
|
903
|
+
var runBaoRead = (operation, timeout3 = BAO_TIMEOUT) => retryTransport(runBao(operation, timeout3));
|
|
904
|
+
var runBaoWrite = (operation, timeout3 = BAO_TIMEOUT) => retryTransport(runBao(operation, timeout3));
|
|
905
|
+
|
|
906
|
+
// src/openbao/auth-role-wire.ts
|
|
907
|
+
var identity = (name) => ({ approle_mount_path: "approle", role_name: name });
|
|
908
|
+
var seconds = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
909
|
+
var completeRole = (live) => live !== null && typeof live === "object" && typeof live.bind_secret_id === "boolean" && seconds(live.secret_id_num_uses) && seconds(live.secret_id_ttl) && seconds(live.token_ttl) && seconds(live.token_max_ttl) && Array.isArray(live.token_policies) && live.token_policies.every((policy) => typeof policy === "string");
|
|
910
|
+
var readAuthRole = (name) => runBaoRead(appRoleReadRole(identity(name))).pipe(Effect14.flatMap((live) => completeRole(live) ? Effect14.succeed(live) : Effect14.fail(new BaoError(200, "GET", readPath3(name), ["incomplete role metadata"]))), Effect14.catchTag("NotFound", () => Effect14.succeed(undefined)));
|
|
911
|
+
var authRoleExists = (name) => readAuthRole(name).pipe(Effect14.map((live) => live !== undefined));
|
|
912
|
+
var authRoleRequest = (props) => Effect14.gen(function* () {
|
|
913
|
+
const tokenTtl = parseDuration(props.tokenTtl);
|
|
914
|
+
const tokenMaxTtl = parseDuration(props.tokenMaxTtl);
|
|
915
|
+
const secretIdTtl = parseDuration(props.secretIdTtl);
|
|
916
|
+
if (!seconds(tokenTtl) || !seconds(tokenMaxTtl) || !seconds(secretIdTtl)) {
|
|
917
|
+
return yield* Effect14.fail(new BaoError(0, "POST", readPath3(props.name), ["invalid role TTL duration"]));
|
|
918
|
+
}
|
|
919
|
+
const request = {
|
|
920
|
+
...identity(props.name),
|
|
921
|
+
token_policies: [...props.tokenPolicies],
|
|
922
|
+
token_ttl: tokenTtl,
|
|
923
|
+
token_max_ttl: tokenMaxTtl,
|
|
924
|
+
secret_id_ttl: secretIdTtl,
|
|
925
|
+
...props.bindSecretId === undefined ? {} : { bind_secret_id: props.bindSecretId },
|
|
926
|
+
...props.secretIdNumUses === undefined ? {} : { secret_id_num_uses: props.secretIdNumUses }
|
|
927
|
+
};
|
|
928
|
+
return request;
|
|
929
|
+
});
|
|
930
|
+
var writeAuthRole = (props) => authRoleRequest(props).pipe(Effect14.flatMap((request) => runBaoWrite(appRoleWriteRole(request))));
|
|
931
|
+
var deleteAuthRole = (name) => runBao(appRoleDeleteRole(identity(name))).pipe(Effect14.catchTag("NotFound", () => Effect14.void));
|
|
932
|
+
|
|
933
|
+
// src/openbao/rename.ts
|
|
934
|
+
import * as Effect15 from "effect/Effect";
|
|
935
|
+
var exact = (identity2) => identity2;
|
|
896
936
|
var declaredString = (news, key) => {
|
|
897
937
|
if (typeof news !== "object" || news === null)
|
|
898
938
|
return;
|
|
@@ -913,17 +953,19 @@ var declaredRolePath = (news, rolePath, defaultMount) => {
|
|
|
913
953
|
};
|
|
914
954
|
var policyKey = (name) => name.trim().toLowerCase();
|
|
915
955
|
var isMoved = (stored, declared, key = exact) => declared === undefined ? undefined : key(stored) !== key(declared);
|
|
916
|
-
var judgeMove = (family, tried, declared, pathOf, key = exact) =>
|
|
956
|
+
var judgeMove = (family, tried, declared, pathOf, key = exact) => judgeMoveWith(family, tried, declared, (identity2) => Effect15.map(baoRead(pathOf(identity2)), (value) => value !== undefined), key);
|
|
957
|
+
var judgeMoveWith = (family, tried, declared, occupied, key = exact) => Effect15.gen(function* () {
|
|
917
958
|
if (tried === undefined || declared === undefined || key(tried) === key(declared)) {
|
|
918
959
|
return;
|
|
919
960
|
}
|
|
920
|
-
if ((yield*
|
|
961
|
+
if (!(yield* occupied(declared)))
|
|
921
962
|
return { from: tried, to: declared };
|
|
922
|
-
return yield*
|
|
963
|
+
return yield* Effect15.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.`));
|
|
923
964
|
});
|
|
924
|
-
var refuseMovedUpdate = (family, from, to) =>
|
|
965
|
+
var refuseMovedUpdate = (family, from, to) => Effect15.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."));
|
|
925
966
|
|
|
926
967
|
// src/openbao/rename-identity.ts
|
|
968
|
+
import * as Effect16 from "effect/Effect";
|
|
927
969
|
var nameIdentity = (family, pathOf, key) => ({
|
|
928
970
|
declared: (props) => declaredString(props, "name"),
|
|
929
971
|
family,
|
|
@@ -938,35 +980,39 @@ var roleIdentity = (family, rolePath, defaultMount, key) => ({
|
|
|
938
980
|
recorded: (output) => rolePath(output.mount, output.name)
|
|
939
981
|
});
|
|
940
982
|
var foldName = (path) => path.replace(/[^/]+$/, (name) => name.toLowerCase());
|
|
941
|
-
var judgeRename = (
|
|
942
|
-
var guardRename = (
|
|
983
|
+
var judgeRename = (identity2, olds, news, output) => judgeMove(identity2.family, output === undefined ? identity2.declared(olds) : identity2.recorded(output), identity2.declared(news), identity2.pathOf ?? ((path) => path), identity2.key);
|
|
984
|
+
var guardRename = (identity2, news, output) => {
|
|
943
985
|
if (output === undefined)
|
|
944
|
-
return
|
|
945
|
-
const from =
|
|
946
|
-
const to =
|
|
947
|
-
return to !== undefined && isMoved(from, to,
|
|
986
|
+
return Effect16.void;
|
|
987
|
+
const from = identity2.recorded(output);
|
|
988
|
+
const to = identity2.declared(news);
|
|
989
|
+
return to !== undefined && isMoved(from, to, identity2.key) === true ? refuseMovedUpdate(identity2.family, from, to) : Effect16.void;
|
|
948
990
|
};
|
|
949
991
|
|
|
992
|
+
// src/openbao/auth-role-identity.ts
|
|
993
|
+
var authRoleIdentity = nameIdentity("Bao.AuthRole", readPath3, foldName);
|
|
994
|
+
var judgeAuthRoleRename = (olds, news, output) => judgeMoveWith("Bao.AuthRole", output === undefined ? declaredString(olds, "name") : output.name, declaredString(news, "name"), authRoleExists, foldName);
|
|
995
|
+
|
|
950
996
|
// src/openbao/auth-role.ts
|
|
951
997
|
var BaoAuthRole = Resource2("Bao.AuthRole", {
|
|
952
998
|
defaultRemovalPolicy: "retain"
|
|
953
999
|
});
|
|
954
|
-
var IDENTITY =
|
|
955
|
-
var readRole = (props) =>
|
|
956
|
-
const live = yield*
|
|
1000
|
+
var IDENTITY = authRoleIdentity;
|
|
1001
|
+
var readRole = (props) => Effect17.gen(function* () {
|
|
1002
|
+
const live = yield* readAuthRole(props.name);
|
|
957
1003
|
if (live === undefined)
|
|
958
1004
|
return;
|
|
959
|
-
return attributesOf3(props, live);
|
|
1005
|
+
return attributesOf3(props, { ...live });
|
|
960
1006
|
});
|
|
961
|
-
var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole,
|
|
962
|
-
list: () =>
|
|
963
|
-
read:
|
|
1007
|
+
var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole, Effect17.succeed(BaoAuthRole.Provider.of({
|
|
1008
|
+
list: () => Effect17.succeed([]),
|
|
1009
|
+
read: Effect17.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
964
1010
|
const found = yield* readRole(olds);
|
|
965
|
-
const ours =
|
|
1011
|
+
const ours = Effect17.sync(() => found !== undefined && matches3(found, olds));
|
|
966
1012
|
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
967
1013
|
}),
|
|
968
|
-
diff:
|
|
969
|
-
const move = yield*
|
|
1014
|
+
diff: Effect17.fn(function* ({ news, olds, output }) {
|
|
1015
|
+
const move = yield* judgeAuthRoleRename(olds, news, output);
|
|
970
1016
|
if (output === undefined)
|
|
971
1017
|
return;
|
|
972
1018
|
if (move !== undefined)
|
|
@@ -980,28 +1026,28 @@ var BaoAuthRoleProvider = () => Provider2.effect(BaoAuthRole, Effect15.succeed(B
|
|
|
980
1026
|
return { action: "noop" };
|
|
981
1027
|
return { action: "update" };
|
|
982
1028
|
}),
|
|
983
|
-
reconcile:
|
|
1029
|
+
reconcile: Effect17.fn(function* ({ fqn, instanceId, news, output }) {
|
|
984
1030
|
yield* guardRename(IDENTITY, news, output);
|
|
985
1031
|
const live = yield* readRole(news);
|
|
986
1032
|
const path = readPath3(news.name);
|
|
987
1033
|
if (live !== undefined)
|
|
988
1034
|
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.AuthRole ${path}`);
|
|
989
1035
|
if (live === undefined || !matches3(live, news)) {
|
|
990
|
-
yield*
|
|
1036
|
+
yield* writeAuthRole(news);
|
|
991
1037
|
}
|
|
992
1038
|
const after = yield* readRole(news);
|
|
993
1039
|
if (after === undefined) {
|
|
994
|
-
return yield*
|
|
1040
|
+
return yield* Effect17.die(new Error(`Bao.AuthRole ${news.name}: write returned no error but the role is still absent.`));
|
|
995
1041
|
}
|
|
996
1042
|
return after;
|
|
997
1043
|
}),
|
|
998
|
-
delete:
|
|
999
|
-
yield*
|
|
1044
|
+
delete: Effect17.fn(function* ({ output }) {
|
|
1045
|
+
yield* deleteAuthRole(output.name);
|
|
1000
1046
|
return;
|
|
1001
1047
|
})
|
|
1002
|
-
})).pipe(
|
|
1048
|
+
})).pipe(Effect17.map(provingResumes)));
|
|
1003
1049
|
// src/openbao/bao-identity.ts
|
|
1004
|
-
import * as
|
|
1050
|
+
import * as Effect18 from "effect/Effect";
|
|
1005
1051
|
import * as FetchHttpClient3 from "effect/unstable/http/FetchHttpClient";
|
|
1006
1052
|
|
|
1007
1053
|
// src/openbao/bao-namespace.ts
|
|
@@ -1049,42 +1095,42 @@ var checkHealth = (address, expectedCluster, body) => {
|
|
|
1049
1095
|
}
|
|
1050
1096
|
return { clusterId: text3(body["cluster_id"]), version: text3(body["version"]) };
|
|
1051
1097
|
};
|
|
1052
|
-
var assertBaoIdentityEffect = (expected) =>
|
|
1098
|
+
var assertBaoIdentityEffect = (expected) => Effect18.gen(function* () {
|
|
1053
1099
|
const env = yield* BaoEnv;
|
|
1054
1100
|
const address = addressOf(env);
|
|
1055
1101
|
const clusterName = expected.clusterName.trim();
|
|
1056
1102
|
if (clusterName === "") {
|
|
1057
|
-
return yield*
|
|
1103
|
+
return yield* Effect18.fail(new BaoIdentityError("input", "clusterName is empty, so there is nothing to compare."));
|
|
1058
1104
|
}
|
|
1059
1105
|
const namespace = canonicalNamespace(expected.namespace);
|
|
1060
1106
|
const sent = envNamespace(env);
|
|
1061
1107
|
if (sent !== namespace) {
|
|
1062
|
-
return yield*
|
|
1108
|
+
return yield* Effect18.fail(new BaoIdentityError("mismatch", `BAO_NAMESPACE resolves to \`${namespaceLabel(sent)}\`, but this stack expects ` + `\`${namespaceLabel(namespace)}\`.`));
|
|
1063
1109
|
}
|
|
1064
1110
|
const anonymous = { ...env, BAO_NAMESPACE: "", BAO_TOKEN: "" };
|
|
1065
|
-
const body = yield* baoCall("read", "GET", HEALTH_PATH).pipe(
|
|
1111
|
+
const body = yield* baoCall("read", "GET", HEALTH_PATH).pipe(Effect18.provideService(BaoEnv, anonymous), Effect18.mapError(unreachable(address, "sys/health")));
|
|
1066
1112
|
const health = checkHealth(address, clusterName, body);
|
|
1067
1113
|
if (health instanceof BaoIdentityError)
|
|
1068
|
-
return yield*
|
|
1114
|
+
return yield* Effect18.fail(health);
|
|
1069
1115
|
if (namespace !== "") {
|
|
1070
1116
|
const scoped = { ...env, BAO_NAMESPACE: namespace, BAO_TOKEN: "" };
|
|
1071
|
-
const probe = yield* baoCall("read", "GET", NAMESPACE_PROBE_PATH).pipe(
|
|
1117
|
+
const probe = yield* baoCall("read", "GET", NAMESPACE_PROBE_PATH).pipe(Effect18.provideService(BaoEnv, scoped), Effect18.mapError(unreachable(address, `the namespace probe for \`${namespace}\``)));
|
|
1072
1118
|
if (probe === undefined) {
|
|
1073
|
-
return yield*
|
|
1119
|
+
return yield* Effect18.fail(new BaoIdentityError("mismatch", `cluster \`${clusterName}\` at ${address} has no namespace \`${namespace}\`.`));
|
|
1074
1120
|
}
|
|
1075
1121
|
}
|
|
1076
1122
|
return { address, clusterName, namespace, ...health };
|
|
1077
1123
|
});
|
|
1078
1124
|
var assertBaoIdentity = (input) => {
|
|
1079
1125
|
const effect3 = assertBaoIdentityEffect(input);
|
|
1080
|
-
const scoped = input.env === undefined ? effect3 :
|
|
1081
|
-
return
|
|
1126
|
+
const scoped = input.env === undefined ? effect3 : Effect18.provideService(effect3, BaoEnv, input.env);
|
|
1127
|
+
return Effect18.runPromise(scoped.pipe(Effect18.provide(FetchHttpClient3.layer)));
|
|
1082
1128
|
};
|
|
1083
1129
|
// src/openbao/cloudflare-role.ts
|
|
1084
1130
|
import { Resource as Resource3 } from "alchemy";
|
|
1085
1131
|
import { isResolved as isResolved3 } from "alchemy/Diff";
|
|
1086
1132
|
import * as Provider3 from "alchemy/Provider";
|
|
1087
|
-
import * as
|
|
1133
|
+
import * as Effect21 from "effect/Effect";
|
|
1088
1134
|
|
|
1089
1135
|
// src/openbao/cloudflare-group-scope.ts
|
|
1090
1136
|
var zoneResource = (zoneId) => `com.cloudflare.api.account.zone.${zoneId}`;
|
|
@@ -1104,7 +1150,7 @@ var groupKey = (name, scope) => `${scope} ${name}`;
|
|
|
1104
1150
|
|
|
1105
1151
|
// src/openbao/cloudflare-permission-groups.ts
|
|
1106
1152
|
import * as Context2 from "effect/Context";
|
|
1107
|
-
import * as
|
|
1153
|
+
import * as Effect20 from "effect/Effect";
|
|
1108
1154
|
|
|
1109
1155
|
// src/openbao/cloudflare-permission-groups-solve.ts
|
|
1110
1156
|
var observationsOf = (declared, live) => declared.flatMap((role) => {
|
|
@@ -1274,18 +1320,18 @@ var samePolicies2 = (want, have) => want.length === have.length && want.every((w
|
|
|
1274
1320
|
});
|
|
1275
1321
|
|
|
1276
1322
|
// src/openbao/cloudflare-role-wire.ts
|
|
1277
|
-
import * as
|
|
1323
|
+
import * as Effect19 from "effect/Effect";
|
|
1278
1324
|
|
|
1279
1325
|
// src/openbao/cloudflare-role-form.ts
|
|
1280
1326
|
var rolePath = (mount, name) => `${mountPath(mount)}/roles/${name}`;
|
|
1281
|
-
var
|
|
1327
|
+
var seconds2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
1282
1328
|
var liveRoleOf = (data) => ({
|
|
1283
1329
|
description: typeof data["description"] === "string" ? data["description"] : "",
|
|
1284
|
-
maxTtl:
|
|
1330
|
+
maxTtl: seconds2(data["max_ttl"]),
|
|
1285
1331
|
name: typeof data["name"] === "string" ? data["name"] : "",
|
|
1286
1332
|
policies: parseLivePolicies(data["policies"]),
|
|
1287
1333
|
policiesText: typeof data["policies"] === "string" ? data["policies"] : "",
|
|
1288
|
-
ttl:
|
|
1334
|
+
ttl: seconds2(data["ttl"])
|
|
1289
1335
|
});
|
|
1290
1336
|
var attributesOf4 = (props, live) => {
|
|
1291
1337
|
const attrs = {
|
|
@@ -1311,7 +1357,7 @@ var refusalOf = (props) => {
|
|
|
1311
1357
|
return "a policy with no groups";
|
|
1312
1358
|
return;
|
|
1313
1359
|
};
|
|
1314
|
-
var
|
|
1360
|
+
var writeBody = (props, policies) => ({
|
|
1315
1361
|
description: props.description,
|
|
1316
1362
|
max_ttl: props.maxTtl,
|
|
1317
1363
|
policies: policiesJson(policies),
|
|
@@ -1339,7 +1385,7 @@ var differences = (props, policies, live) => {
|
|
|
1339
1385
|
};
|
|
1340
1386
|
|
|
1341
1387
|
// src/openbao/cloudflare-role-wire.ts
|
|
1342
|
-
var readCloudflareRole = (mount, name) =>
|
|
1388
|
+
var readCloudflareRole = (mount, name) => Effect19.map(baoRead(rolePath(mount, name)), (data) => data === undefined ? undefined : liveRoleOf(data));
|
|
1343
1389
|
var writeCloudflareRole = (mount, name, body) => baoWrite("PUT", rolePath(mount, name), body);
|
|
1344
1390
|
var deleteCloudflareRole = (mount, name) => baoDelete(rolePath(mount, name));
|
|
1345
1391
|
|
|
@@ -1361,9 +1407,9 @@ var pick = (mount, groups, refs, hint) => {
|
|
|
1361
1407
|
const unknown = refs.filter((ref) => !groups.has(groupKey(ref.name, ref.scope)));
|
|
1362
1408
|
if (unknown.length > 0) {
|
|
1363
1409
|
const problems = unknown.map((ref) => `unknown group ${JSON.stringify(ref.name)} at scope ${ref.scope} — ${hint}`);
|
|
1364
|
-
return
|
|
1410
|
+
return Effect20.fail(new CloudflareGroupsError(mount, problems));
|
|
1365
1411
|
}
|
|
1366
|
-
return
|
|
1412
|
+
return Effect20.succeed(new Map(refs.flatMap((ref) => {
|
|
1367
1413
|
const key = groupKey(ref.name, ref.scope);
|
|
1368
1414
|
const id = groups.get(key);
|
|
1369
1415
|
return id === undefined ? [] : [[key, id]];
|
|
@@ -1371,15 +1417,15 @@ var pick = (mount, groups, refs, hint) => {
|
|
|
1371
1417
|
};
|
|
1372
1418
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1373
1419
|
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";
|
|
1374
|
-
var deniedNamed = (mount, read) =>
|
|
1375
|
-
var engineGroups = (mount) =>
|
|
1420
|
+
var deniedNamed = (mount, read) => Effect20.catchIf(read, (error) => error.status === 403, () => Effect20.fail(new CloudflareGroupsError(mount, [deniedHint(mount)])));
|
|
1421
|
+
var engineGroups = (mount) => Effect20.flatMap(deniedNamed(mount, baoRead(`${mountPath(mount)}/permission-groups`)), (data) => {
|
|
1376
1422
|
const list = data?.["permission_groups"];
|
|
1377
1423
|
if (data === undefined) {
|
|
1378
1424
|
const why = "GET <mount>/permission-groups answered 404 — the endpoint is not deployed here";
|
|
1379
|
-
return
|
|
1425
|
+
return Effect20.fail(new CloudflareGroupsError(mount, [why]));
|
|
1380
1426
|
}
|
|
1381
1427
|
if (!Array.isArray(list)) {
|
|
1382
|
-
return
|
|
1428
|
+
return Effect20.fail(new CloudflareGroupsError(mount, ["no permission_groups array in reply"]));
|
|
1383
1429
|
}
|
|
1384
1430
|
const scoped = new Map;
|
|
1385
1431
|
const idsOf = new Map;
|
|
@@ -1406,24 +1452,24 @@ var engineGroups = (mount) => Effect18.flatMap(deniedNamed(mount, baoRead(`${mou
|
|
|
1406
1452
|
const only = [...ids];
|
|
1407
1453
|
return ids.size === 1 && only[0] !== undefined ? [[name, only[0]]] : [];
|
|
1408
1454
|
}));
|
|
1409
|
-
return problems.length > 0 ?
|
|
1455
|
+
return problems.length > 0 ? Effect20.fail(new CloudflareGroupsError(mount, problems)) : Effect20.succeed(new Map([...atEveryScope(sole), ...scoped]));
|
|
1410
1456
|
});
|
|
1411
|
-
var permissionGroupsFromEngine = () =>
|
|
1457
|
+
var permissionGroupsFromEngine = () => Effect20.sync(() => {
|
|
1412
1458
|
const cache = new Map;
|
|
1413
|
-
const cachedFor = (mount) =>
|
|
1459
|
+
const cachedFor = (mount) => Effect20.suspend(() => {
|
|
1414
1460
|
const hit = cache.get(mountPath(mount));
|
|
1415
1461
|
if (hit !== undefined)
|
|
1416
1462
|
return hit;
|
|
1417
|
-
return
|
|
1463
|
+
return Effect20.flatMap(Effect20.cached(engineGroups(mount)), (lookup) => {
|
|
1418
1464
|
cache.set(mountPath(mount), lookup);
|
|
1419
1465
|
return lookup;
|
|
1420
1466
|
});
|
|
1421
1467
|
});
|
|
1422
1468
|
return CloudflarePermissionGroups.of({
|
|
1423
|
-
resolve: (mount, refs) =>
|
|
1469
|
+
resolve: (mount, refs) => Effect20.flatMap(cachedFor(mount), (groups) => pick(mount, groups, refs, "the engine does not list it for this account at that scope"))
|
|
1424
1470
|
});
|
|
1425
1471
|
});
|
|
1426
|
-
var permissionGroupsFromLiveRoles = (declared) =>
|
|
1472
|
+
var permissionGroupsFromLiveRoles = (declared) => Effect20.gen(function* () {
|
|
1427
1473
|
const accountOf = new Map;
|
|
1428
1474
|
const byAccount = new Map;
|
|
1429
1475
|
for (const [mount, roles] of declared) {
|
|
@@ -1434,9 +1480,9 @@ var permissionGroupsFromLiveRoles = (declared) => Effect18.gen(function* () {
|
|
|
1434
1480
|
}
|
|
1435
1481
|
const solved = new Map;
|
|
1436
1482
|
for (const [account, roles] of byAccount) {
|
|
1437
|
-
const solve =
|
|
1483
|
+
const solve = Effect20.gen(function* () {
|
|
1438
1484
|
const live = new Map;
|
|
1439
|
-
yield*
|
|
1485
|
+
yield* Effect20.all(roles.map((role) => Effect20.map(readCloudflareRole(role.mount, role.name), (read) => {
|
|
1440
1486
|
if (read?.policies !== undefined) {
|
|
1441
1487
|
live.set(`${role.mount}/${role.name}`, read.policies);
|
|
1442
1488
|
}
|
|
@@ -1444,11 +1490,11 @@ var permissionGroupsFromLiveRoles = (declared) => Effect18.gen(function* () {
|
|
|
1444
1490
|
const result = solveGroups(observationsOf(roles, live));
|
|
1445
1491
|
const problems = describeProblems(result);
|
|
1446
1492
|
if (problems.length > 0) {
|
|
1447
|
-
return yield*
|
|
1493
|
+
return yield* Effect20.fail(new CloudflareGroupsError(`account ${account}`, problems));
|
|
1448
1494
|
}
|
|
1449
1495
|
return atEveryScope(result.groups);
|
|
1450
1496
|
});
|
|
1451
|
-
solved.set(account, yield*
|
|
1497
|
+
solved.set(account, yield* Effect20.cached(solve));
|
|
1452
1498
|
}
|
|
1453
1499
|
return CloudflarePermissionGroups.of({
|
|
1454
1500
|
resolve: (mount, refs) => {
|
|
@@ -1456,10 +1502,10 @@ var permissionGroupsFromLiveRoles = (declared) => Effect18.gen(function* () {
|
|
|
1456
1502
|
const lookup = account === undefined ? undefined : solved.get(account);
|
|
1457
1503
|
if (account === undefined || lookup === undefined) {
|
|
1458
1504
|
const why = "no declared role on this mount, so no live role can vouch for its groups";
|
|
1459
|
-
return
|
|
1505
|
+
return Effect20.fail(new CloudflareGroupsError(mount, [why]));
|
|
1460
1506
|
}
|
|
1461
1507
|
const hint = `no live role on account ${account} carries it; a NEW group needs the engine endpoint`;
|
|
1462
|
-
return
|
|
1508
|
+
return Effect20.flatMap(lookup, (groups) => pick(mount, groups, refs, hint));
|
|
1463
1509
|
}
|
|
1464
1510
|
});
|
|
1465
1511
|
});
|
|
@@ -1469,9 +1515,9 @@ var BaoCloudflareRole = Resource3("Bao.CloudflareRole", {
|
|
|
1469
1515
|
defaultRemovalPolicy: "retain"
|
|
1470
1516
|
});
|
|
1471
1517
|
var IDENTITY2 = roleIdentity("Bao.CloudflareRole", rolePath);
|
|
1472
|
-
var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole,
|
|
1518
|
+
var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect21.gen(function* () {
|
|
1473
1519
|
const groups = yield* CloudflarePermissionGroups;
|
|
1474
|
-
const resolved = (props) =>
|
|
1520
|
+
const resolved = (props) => Effect21.gen(function* () {
|
|
1475
1521
|
const refs = new Map;
|
|
1476
1522
|
for (const policy of props.policies) {
|
|
1477
1523
|
const scope = policy.scope ?? scopeOfResource(policy.resource);
|
|
@@ -1481,23 +1527,23 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1481
1527
|
const ids = yield* groups.resolve(props.mount, [...refs.values()]);
|
|
1482
1528
|
const { missing, policies } = resolvePolicies(props.policies, ids);
|
|
1483
1529
|
if (missing.length > 0) {
|
|
1484
|
-
return yield*
|
|
1530
|
+
return yield* Effect21.die(new Error(`Bao.CloudflareRole ${rolePath(props.mount, props.name)}: groups ` + `${missing.join(", ")} came back unresolved from a lookup that reported success.`));
|
|
1485
1531
|
}
|
|
1486
1532
|
return policies;
|
|
1487
1533
|
});
|
|
1488
1534
|
return BaoCloudflareRole.Provider.of({
|
|
1489
|
-
list: () =>
|
|
1490
|
-
read:
|
|
1535
|
+
list: () => Effect21.succeed([]),
|
|
1536
|
+
read: Effect21.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
1491
1537
|
const live = yield* readCloudflareRole(olds.mount, olds.name);
|
|
1492
1538
|
const found = live === undefined ? undefined : attributesOf4(olds, live);
|
|
1493
|
-
const ours =
|
|
1539
|
+
const ours = Effect21.gen(function* () {
|
|
1494
1540
|
if (live === undefined || refusalOf(olds) !== undefined)
|
|
1495
1541
|
return false;
|
|
1496
1542
|
return differences(olds, yield* resolved(olds), live).length === 0;
|
|
1497
1543
|
});
|
|
1498
1544
|
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
1499
1545
|
}),
|
|
1500
|
-
diff:
|
|
1546
|
+
diff: Effect21.fn(function* ({ news, olds, output }) {
|
|
1501
1547
|
const move = yield* judgeRename(IDENTITY2, olds, news, output);
|
|
1502
1548
|
if (output === undefined)
|
|
1503
1549
|
return;
|
|
@@ -1513,12 +1559,12 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1513
1559
|
return { action: "update" };
|
|
1514
1560
|
return differences(news, policies, live).length === 0 ? { action: "noop" } : { action: "update" };
|
|
1515
1561
|
}),
|
|
1516
|
-
reconcile:
|
|
1562
|
+
reconcile: Effect21.fn(function* ({ fqn, instanceId, news, output }) {
|
|
1517
1563
|
const path = rolePath(news.mount, news.name);
|
|
1518
1564
|
yield* guardRename(IDENTITY2, news, output);
|
|
1519
1565
|
const refusal2 = refusalOf(news);
|
|
1520
1566
|
if (refusal2 !== undefined) {
|
|
1521
|
-
return yield*
|
|
1567
|
+
return yield* Effect21.die(new Error(`Bao.CloudflareRole ${path}: ${refusal2}.`));
|
|
1522
1568
|
}
|
|
1523
1569
|
const policies = yield* resolved(news);
|
|
1524
1570
|
const live = yield* readCloudflareRole(news.mount, news.name);
|
|
@@ -1526,24 +1572,24 @@ var BaoCloudflareRoleProvider = () => Provider3.effect(BaoCloudflareRole, Effect
|
|
|
1526
1572
|
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.CloudflareRole ${path}`);
|
|
1527
1573
|
}
|
|
1528
1574
|
if (live === undefined || differences(news, policies, live).length > 0) {
|
|
1529
|
-
yield* writeCloudflareRole(news.mount, news.name,
|
|
1575
|
+
yield* writeCloudflareRole(news.mount, news.name, writeBody(news, policies));
|
|
1530
1576
|
}
|
|
1531
1577
|
const after = yield* readCloudflareRole(news.mount, news.name);
|
|
1532
1578
|
if (after === undefined) {
|
|
1533
|
-
return yield*
|
|
1579
|
+
return yield* Effect21.die(new Error(`Bao.CloudflareRole ${path}: the write succeeded but the role is absent.`));
|
|
1534
1580
|
}
|
|
1535
1581
|
const left = differences(news, policies, after);
|
|
1536
1582
|
if (left.length > 0) {
|
|
1537
|
-
return yield*
|
|
1583
|
+
return yield* Effect21.die(new Error(`Bao.CloudflareRole ${path}: wrote cleanly but reads back different in ` + `${left.map((d) => d.field).join(", ")}. Inspect the role before retrying.`));
|
|
1538
1584
|
}
|
|
1539
1585
|
return attributesOf4(news, after);
|
|
1540
1586
|
}),
|
|
1541
|
-
delete:
|
|
1587
|
+
delete: Effect21.fn(function* ({ output }) {
|
|
1542
1588
|
yield* deleteCloudflareRole(output.mount, output.name);
|
|
1543
1589
|
return;
|
|
1544
1590
|
})
|
|
1545
1591
|
});
|
|
1546
|
-
}).pipe(
|
|
1592
|
+
}).pipe(Effect21.map(provingResumes)));
|
|
1547
1593
|
// src/openbao/cloudflare-roles-expand.ts
|
|
1548
1594
|
var slug = (name) => trimRuns(name.toLowerCase().replace(/[^a-z0-9]+/g, "-"), "-");
|
|
1549
1595
|
var zoneSlug = (zone) => `${slug(zone.name)}${zone.internal ? "-internal" : ""}`;
|
|
@@ -1790,7 +1836,7 @@ var hostAppRoles = (input) => {
|
|
|
1790
1836
|
import { Resource as Resource4 } from "alchemy";
|
|
1791
1837
|
import { isResolved as isResolved4 } from "alchemy/Diff";
|
|
1792
1838
|
import * as Provider4 from "alchemy/Provider";
|
|
1793
|
-
import * as
|
|
1839
|
+
import * as Effect23 from "effect/Effect";
|
|
1794
1840
|
|
|
1795
1841
|
// src/openbao/jwt-config-form.ts
|
|
1796
1842
|
var text5 = (value) => typeof value === "string" ? value.trim() : "";
|
|
@@ -1833,7 +1879,7 @@ var attributesOf5 = (props, live) => {
|
|
|
1833
1879
|
return { ...form, digest: sha256(JSON.stringify(form)), mount: mountOf(props) };
|
|
1834
1880
|
};
|
|
1835
1881
|
var matches4 = (attributes, props) => attributes.digest === sha256(JSON.stringify(canonicalFromProps(props)));
|
|
1836
|
-
var
|
|
1882
|
+
var writeBody2 = (props) => ({
|
|
1837
1883
|
bound_issuer: props.boundIssuer ?? "",
|
|
1838
1884
|
default_role: props.defaultRole ?? "",
|
|
1839
1885
|
jwks_ca_pem: props.jwksCaPem ?? "",
|
|
@@ -1880,20 +1926,20 @@ var problems = (props) => {
|
|
|
1880
1926
|
};
|
|
1881
1927
|
|
|
1882
1928
|
// src/openbao/role-reconcile.ts
|
|
1883
|
-
import * as
|
|
1884
|
-
var readRoleAt = (spec) =>
|
|
1885
|
-
var readOwnedRole = (ask, spec) =>
|
|
1886
|
-
const ours =
|
|
1929
|
+
import * as Effect22 from "effect/Effect";
|
|
1930
|
+
var readRoleAt = (spec) => Effect22.map(baoRead(spec.path), (live) => live === undefined ? undefined : { attributes: spec.attributesOf(live), live });
|
|
1931
|
+
var readOwnedRole = (ask, spec) => Effect22.flatMap(readRoleAt(spec), (found) => {
|
|
1932
|
+
const ours = Effect22.sync(() => found !== undefined && spec.problems.length === 0 && spec.matches(found.attributes));
|
|
1887
1933
|
return ownedRead(ask, found?.attributes, ours);
|
|
1888
1934
|
});
|
|
1889
|
-
var planRole = (spec) =>
|
|
1935
|
+
var planRole = (spec) => Effect22.gen(function* () {
|
|
1890
1936
|
if (spec.problems.length > 0)
|
|
1891
1937
|
return "update";
|
|
1892
1938
|
const found = yield* readRoleAt(spec);
|
|
1893
1939
|
return found !== undefined && spec.matches(found.attributes) ? "noop" : "update";
|
|
1894
1940
|
});
|
|
1895
|
-
var refuse2 = (spec, message) =>
|
|
1896
|
-
var reconcileRole = (spec, claim) =>
|
|
1941
|
+
var refuse2 = (spec, message) => Effect22.die(new Error(`${spec.family} ${spec.path}: ${message}`));
|
|
1942
|
+
var reconcileRole = (spec, claim) => Effect22.gen(function* () {
|
|
1897
1943
|
if (spec.problems.length > 0)
|
|
1898
1944
|
return yield* refuse2(spec, spec.problems.join("; "));
|
|
1899
1945
|
const found = yield* readRoleAt(spec);
|
|
@@ -1929,19 +1975,19 @@ var IDENTITY3 = {
|
|
|
1929
1975
|
};
|
|
1930
1976
|
var jwtConfigSpec = (props) => ({
|
|
1931
1977
|
attributesOf: (live) => attributesOf5(props, live),
|
|
1932
|
-
body:
|
|
1978
|
+
body: writeBody2(props),
|
|
1933
1979
|
family: "Bao.JwtAuthConfig",
|
|
1934
1980
|
matches: (attributes) => matches4(attributes, props),
|
|
1935
1981
|
path: configPath(props),
|
|
1936
1982
|
problems: problems(props),
|
|
1937
1983
|
wouldErase
|
|
1938
1984
|
});
|
|
1939
|
-
var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig,
|
|
1940
|
-
list: () =>
|
|
1941
|
-
read:
|
|
1985
|
+
var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig, Effect23.succeed(BaoJwtAuthConfig.Provider.of({
|
|
1986
|
+
list: () => Effect23.succeed([]),
|
|
1987
|
+
read: Effect23.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
1942
1988
|
return yield* readOwnedRole({ fqn, instanceId, output }, jwtConfigSpec(olds));
|
|
1943
1989
|
}),
|
|
1944
|
-
diff:
|
|
1990
|
+
diff: Effect23.fn(function* ({ news, olds, output }) {
|
|
1945
1991
|
const move = yield* judgeRename(IDENTITY3, olds, news, output);
|
|
1946
1992
|
if (output === undefined)
|
|
1947
1993
|
return;
|
|
@@ -1951,23 +1997,23 @@ var BaoJwtAuthConfigProvider = () => Provider4.effect(BaoJwtAuthConfig, Effect21
|
|
|
1951
1997
|
return;
|
|
1952
1998
|
return { action: yield* planRole(jwtConfigSpec(news)) };
|
|
1953
1999
|
}),
|
|
1954
|
-
reconcile:
|
|
2000
|
+
reconcile: Effect23.fn(function* ({ fqn, instanceId, news, output }) {
|
|
1955
2001
|
yield* guardRename(IDENTITY3, news, output);
|
|
1956
2002
|
return yield* reconcileRole(jwtConfigSpec(news), claimFor({ fqn, instanceId, output }));
|
|
1957
2003
|
}),
|
|
1958
|
-
delete: () =>
|
|
1959
|
-
})).pipe(
|
|
2004
|
+
delete: () => Effect23.void
|
|
2005
|
+
})).pipe(Effect23.map(provingResumes)));
|
|
1960
2006
|
// src/openbao/jwt-role.ts
|
|
1961
2007
|
import { Resource as Resource5 } from "alchemy";
|
|
1962
2008
|
import { isResolved as isResolved5 } from "alchemy/Diff";
|
|
1963
2009
|
import * as Provider5 from "alchemy/Provider";
|
|
1964
|
-
import * as
|
|
2010
|
+
import * as Effect24 from "effect/Effect";
|
|
1965
2011
|
|
|
1966
2012
|
// src/openbao/auth-token-form.ts
|
|
1967
2013
|
var sortedSet2 = (values) => [...new Set(values)].sort();
|
|
1968
2014
|
var cidr = (value) => value.trim().replace(/\/(32|128)$/, "");
|
|
1969
2015
|
var strings3 = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
1970
|
-
var
|
|
2016
|
+
var seconds3 = (text6) => parseDuration(text6 ?? "0") ?? -1;
|
|
1971
2017
|
var tokenFields = (input) => ({
|
|
1972
2018
|
tokenBoundCidrs: input.tokenBoundCidrs,
|
|
1973
2019
|
tokenExplicitMaxTtlSeconds: input.tokenExplicitMaxTtlSeconds,
|
|
@@ -1992,13 +2038,13 @@ var tokenForm = (input) => ({
|
|
|
1992
2038
|
});
|
|
1993
2039
|
var tokenFormOfProps = (props) => tokenForm({
|
|
1994
2040
|
tokenBoundCidrs: props.tokenBoundCidrs ?? [],
|
|
1995
|
-
tokenExplicitMaxTtlSeconds:
|
|
1996
|
-
tokenMaxTtlSeconds:
|
|
2041
|
+
tokenExplicitMaxTtlSeconds: seconds3(props.tokenExplicitMaxTtl),
|
|
2042
|
+
tokenMaxTtlSeconds: seconds3(props.tokenMaxTtl),
|
|
1997
2043
|
tokenNoDefaultPolicy: props.tokenNoDefaultPolicy ?? false,
|
|
1998
2044
|
tokenNumUses: props.tokenNumUses ?? 0,
|
|
1999
|
-
tokenPeriodSeconds:
|
|
2045
|
+
tokenPeriodSeconds: seconds3(props.tokenPeriod),
|
|
2000
2046
|
tokenPolicies: props.tokenPolicies,
|
|
2001
|
-
tokenTtlSeconds:
|
|
2047
|
+
tokenTtlSeconds: seconds3(props.tokenTtl),
|
|
2002
2048
|
tokenType: props.tokenType ?? "default"
|
|
2003
2049
|
});
|
|
2004
2050
|
var tokenFormOfLive = (live) => tokenForm({
|
|
@@ -2032,14 +2078,14 @@ var tokenProblems = (props) => {
|
|
|
2032
2078
|
tokenTtl: props.tokenTtl
|
|
2033
2079
|
};
|
|
2034
2080
|
for (const [field, text6] of Object.entries(durations)) {
|
|
2035
|
-
if (
|
|
2081
|
+
if (seconds3(text6) < 0)
|
|
2036
2082
|
found.push(`${field}=${text6 ?? ""} is not a duration (0 or <n>s|m|h|d)`);
|
|
2037
2083
|
}
|
|
2038
|
-
const ttl =
|
|
2039
|
-
const max =
|
|
2084
|
+
const ttl = seconds3(props.tokenTtl);
|
|
2085
|
+
const max = seconds3(props.tokenMaxTtl);
|
|
2040
2086
|
if (ttl > 0 && max > 0 && ttl > max)
|
|
2041
2087
|
found.push("tokenTtl is longer than tokenMaxTtl");
|
|
2042
|
-
if (props.tokenType === "batch" && (
|
|
2088
|
+
if (props.tokenType === "batch" && (seconds3(props.tokenPeriod) > 0 || (props.tokenNumUses ?? 0) > 0)) {
|
|
2043
2089
|
found.push("a batch token cannot be periodic or use-limited (tokenutil.go:234-241)");
|
|
2044
2090
|
}
|
|
2045
2091
|
return found;
|
|
@@ -2121,7 +2167,7 @@ var attributesOf6 = (props, live) => {
|
|
|
2121
2167
|
return { ...form, digest: sha256(JSON.stringify(form)), mount: mountOf2(props), name: props.name };
|
|
2122
2168
|
};
|
|
2123
2169
|
var matches5 = (attributes, props) => attributes.digest === sha256(JSON.stringify(canonicalFromProps2(props)));
|
|
2124
|
-
var
|
|
2170
|
+
var writeBody3 = (props) => ({
|
|
2125
2171
|
allowed_redirect_uris: [...props.allowedRedirectUris ?? []],
|
|
2126
2172
|
bound_audiences: [...props.boundAudiences ?? []],
|
|
2127
2173
|
bound_claims: { ...props.boundClaims },
|
|
@@ -2166,18 +2212,18 @@ var BaoJwtRole = Resource5("Bao.JwtRole", {
|
|
|
2166
2212
|
var IDENTITY4 = roleIdentity("Bao.JwtRole", (mount, name) => rolePath2({ mount, name }), "jwt", foldName);
|
|
2167
2213
|
var jwtRoleSpec = (props) => ({
|
|
2168
2214
|
attributesOf: (live) => attributesOf6(props, live),
|
|
2169
|
-
body:
|
|
2215
|
+
body: writeBody3(props),
|
|
2170
2216
|
family: "Bao.JwtRole",
|
|
2171
2217
|
matches: (attributes) => matches5(attributes, props),
|
|
2172
2218
|
path: rolePath2(props),
|
|
2173
2219
|
problems: problems2(props)
|
|
2174
2220
|
});
|
|
2175
|
-
var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole,
|
|
2176
|
-
list: () =>
|
|
2177
|
-
read:
|
|
2221
|
+
var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole, Effect24.succeed(BaoJwtRole.Provider.of({
|
|
2222
|
+
list: () => Effect24.succeed([]),
|
|
2223
|
+
read: Effect24.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2178
2224
|
return yield* readOwnedRole({ fqn, instanceId, output }, jwtRoleSpec(olds));
|
|
2179
2225
|
}),
|
|
2180
|
-
diff:
|
|
2226
|
+
diff: Effect24.fn(function* ({ news, olds, output }) {
|
|
2181
2227
|
const move = yield* judgeRename(IDENTITY4, olds, news, output);
|
|
2182
2228
|
if (output === undefined)
|
|
2183
2229
|
return;
|
|
@@ -2187,20 +2233,20 @@ var BaoJwtRoleProvider = () => Provider5.effect(BaoJwtRole, Effect22.succeed(Bao
|
|
|
2187
2233
|
return;
|
|
2188
2234
|
return { action: yield* planRole(jwtRoleSpec(news)) };
|
|
2189
2235
|
}),
|
|
2190
|
-
reconcile:
|
|
2236
|
+
reconcile: Effect24.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2191
2237
|
yield* guardRename(IDENTITY4, news, output);
|
|
2192
2238
|
return yield* reconcileRole(jwtRoleSpec(news), claimFor({ fqn, instanceId, output }));
|
|
2193
2239
|
}),
|
|
2194
|
-
delete:
|
|
2240
|
+
delete: Effect24.fn(function* ({ output }) {
|
|
2195
2241
|
yield* baoDelete(rolePath2(output));
|
|
2196
2242
|
return;
|
|
2197
2243
|
})
|
|
2198
|
-
})).pipe(
|
|
2244
|
+
})).pipe(Effect24.map(provingResumes)));
|
|
2199
2245
|
// src/openbao/kubernetes-role.ts
|
|
2200
2246
|
import { Resource as Resource6 } from "alchemy";
|
|
2201
2247
|
import { isResolved as isResolved6 } from "alchemy/Diff";
|
|
2202
2248
|
import * as Provider6 from "alchemy/Provider";
|
|
2203
|
-
import * as
|
|
2249
|
+
import * as Effect25 from "effect/Effect";
|
|
2204
2250
|
|
|
2205
2251
|
// src/openbao/kubernetes-role-form.ts
|
|
2206
2252
|
var sortedSet4 = (values) => [...new Set(values)].sort();
|
|
@@ -2237,7 +2283,7 @@ var attributesOf7 = (props, live) => {
|
|
|
2237
2283
|
return { ...form, digest: sha256(JSON.stringify(form)), mount: mountOf3(props), name: props.name };
|
|
2238
2284
|
};
|
|
2239
2285
|
var matches6 = (attributes, props) => attributes.digest === sha256(JSON.stringify(canonicalFromProps3(props)));
|
|
2240
|
-
var
|
|
2286
|
+
var writeBody4 = (props) => ({
|
|
2241
2287
|
alias_name_source: props.aliasNameSource,
|
|
2242
2288
|
audience: props.audience ?? "",
|
|
2243
2289
|
bound_service_account_names: [...props.boundServiceAccountNames],
|
|
@@ -2272,18 +2318,18 @@ var BaoKubernetesRole = Resource6("Bao.KubernetesRole", {
|
|
|
2272
2318
|
var IDENTITY5 = roleIdentity("Bao.KubernetesRole", (mount, name) => rolePath3({ mount, name }), "kubernetes", foldName);
|
|
2273
2319
|
var kubernetesRoleSpec = (props) => ({
|
|
2274
2320
|
attributesOf: (live) => attributesOf7(props, live),
|
|
2275
|
-
body:
|
|
2321
|
+
body: writeBody4(props),
|
|
2276
2322
|
family: "Bao.KubernetesRole",
|
|
2277
2323
|
matches: (attributes) => matches6(attributes, props),
|
|
2278
2324
|
path: rolePath3(props),
|
|
2279
2325
|
problems: problems3(props)
|
|
2280
2326
|
});
|
|
2281
|
-
var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole,
|
|
2282
|
-
list: () =>
|
|
2283
|
-
read:
|
|
2327
|
+
var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole, Effect25.succeed(BaoKubernetesRole.Provider.of({
|
|
2328
|
+
list: () => Effect25.succeed([]),
|
|
2329
|
+
read: Effect25.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2284
2330
|
return yield* readOwnedRole({ fqn, instanceId, output }, kubernetesRoleSpec(olds));
|
|
2285
2331
|
}),
|
|
2286
|
-
diff:
|
|
2332
|
+
diff: Effect25.fn(function* ({ news, olds, output }) {
|
|
2287
2333
|
const move = yield* judgeRename(IDENTITY5, olds, news, output);
|
|
2288
2334
|
if (output === undefined)
|
|
2289
2335
|
return;
|
|
@@ -2293,20 +2339,20 @@ var BaoKubernetesRoleProvider = () => Provider6.effect(BaoKubernetesRole, Effect
|
|
|
2293
2339
|
return;
|
|
2294
2340
|
return { action: yield* planRole(kubernetesRoleSpec(news)) };
|
|
2295
2341
|
}),
|
|
2296
|
-
reconcile:
|
|
2342
|
+
reconcile: Effect25.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2297
2343
|
yield* guardRename(IDENTITY5, news, output);
|
|
2298
2344
|
return yield* reconcileRole(kubernetesRoleSpec(news), claimFor({ fqn, instanceId, output }));
|
|
2299
2345
|
}),
|
|
2300
|
-
delete:
|
|
2346
|
+
delete: Effect25.fn(function* ({ output }) {
|
|
2301
2347
|
yield* baoDelete(rolePath3(output));
|
|
2302
2348
|
return;
|
|
2303
2349
|
})
|
|
2304
|
-
})).pipe(
|
|
2350
|
+
})).pipe(Effect25.map(provingResumes)));
|
|
2305
2351
|
// src/openbao/mfa-enforcement.ts
|
|
2306
2352
|
import { Resource as Resource7 } from "alchemy";
|
|
2307
2353
|
import { isResolved as isResolved7 } from "alchemy/Diff";
|
|
2308
2354
|
import * as Provider7 from "alchemy/Provider";
|
|
2309
|
-
import * as
|
|
2355
|
+
import * as Effect27 from "effect/Effect";
|
|
2310
2356
|
|
|
2311
2357
|
// src/openbao/mfa-enforcement-form.ts
|
|
2312
2358
|
var sortedSet5 = (values) => [...new Set(values.map((value) => value.trim()))].filter((value) => value !== "").sort();
|
|
@@ -2344,7 +2390,7 @@ var attributesOf8 = (name, live) => {
|
|
|
2344
2390
|
};
|
|
2345
2391
|
};
|
|
2346
2392
|
var matches7 = (attributes, props, resolved) => attributes.digest === sha256(JSON.stringify(canonicalFromProps4(props, resolved)));
|
|
2347
|
-
var
|
|
2393
|
+
var writeBody5 = (form) => ({
|
|
2348
2394
|
auth_method_accessors: [...form.authMethodAccessors],
|
|
2349
2395
|
auth_method_types: [...form.authMethodTypes],
|
|
2350
2396
|
identity_entity_ids: [...form.identityEntityIds],
|
|
@@ -2374,16 +2420,16 @@ var problems4 = (props, missingPaths) => {
|
|
|
2374
2420
|
};
|
|
2375
2421
|
|
|
2376
2422
|
// src/openbao/mfa-wire.ts
|
|
2377
|
-
import * as
|
|
2423
|
+
import * as Effect26 from "effect/Effect";
|
|
2378
2424
|
var TOTP_PATH = "identity/mfa/method/totp";
|
|
2379
2425
|
var METHODS_PATH = "identity/mfa/method";
|
|
2380
2426
|
var enforcementPath = (name) => `identity/mfa/login-enforcement/${name}`;
|
|
2381
2427
|
var record4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
2382
|
-
var ownNamespacePath =
|
|
2428
|
+
var ownNamespacePath = Effect26.gen(function* () {
|
|
2383
2429
|
const env = yield* BaoEnv;
|
|
2384
2430
|
return namespacePath(envNamespace(env));
|
|
2385
2431
|
});
|
|
2386
|
-
var findTotp = (name) =>
|
|
2432
|
+
var findTotp = (name) => Effect26.gen(function* () {
|
|
2387
2433
|
const listing = yield* baoRead(`${METHODS_PATH}?list=true`);
|
|
2388
2434
|
const info = record4(listing?.["key_info"]) ?? {};
|
|
2389
2435
|
const own = yield* ownNamespacePath;
|
|
@@ -2392,17 +2438,17 @@ var findTotp = (name) => Effect24.gen(function* () {
|
|
|
2392
2438
|
if (live === undefined || live["name"] !== name || live["namespace_path"] !== own)
|
|
2393
2439
|
continue;
|
|
2394
2440
|
if (live["type"] !== "totp") {
|
|
2395
|
-
return yield*
|
|
2441
|
+
return yield* Effect26.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.`));
|
|
2396
2442
|
}
|
|
2397
2443
|
return { id, live };
|
|
2398
2444
|
}
|
|
2399
2445
|
return;
|
|
2400
2446
|
});
|
|
2401
|
-
var writeTotp = (body) =>
|
|
2447
|
+
var writeTotp = (body) => Effect26.asVoid(baoCall("write", "POST", TOTP_PATH, body));
|
|
2402
2448
|
var deleteTotp = (id) => baoDelete(`${TOTP_PATH}/${id}`);
|
|
2403
2449
|
var readEnforcement = (name) => baoRead(enforcementPath(name));
|
|
2404
|
-
var writeEnforcement = (name, body) =>
|
|
2405
|
-
var authAccessors = (paths) =>
|
|
2450
|
+
var writeEnforcement = (name, body) => Effect26.asVoid(baoCall("write", "POST", enforcementPath(name), body));
|
|
2451
|
+
var authAccessors = (paths) => Effect26.gen(function* () {
|
|
2406
2452
|
if (paths.length === 0)
|
|
2407
2453
|
return { accessors: [], missing: [] };
|
|
2408
2454
|
const table = (yield* baoRead("sys/auth")) ?? {};
|
|
@@ -2423,20 +2469,20 @@ var BaoMfaLoginEnforcement = Resource7("Bao.MfaLoginEnforcement", {
|
|
|
2423
2469
|
defaultRemovalPolicy: "retain"
|
|
2424
2470
|
});
|
|
2425
2471
|
var IDENTITY6 = nameIdentity("Bao.MfaLoginEnforcement", enforcementPath);
|
|
2426
|
-
var refuse3 = (name, message) =>
|
|
2427
|
-
var resolveTargets = (props) =>
|
|
2472
|
+
var refuse3 = (name, message) => Effect27.die(new Error(`Bao.MfaLoginEnforcement ${name}: ${message}`));
|
|
2473
|
+
var resolveTargets = (props) => Effect27.map(authAccessors(props.authMethodPaths ?? []), ({ accessors, missing }) => ({
|
|
2428
2474
|
bad: problems4(props, missing),
|
|
2429
2475
|
resolved: accessors
|
|
2430
2476
|
}));
|
|
2431
|
-
var readLive = (name) =>
|
|
2432
|
-
var planEnforcement = (props) =>
|
|
2477
|
+
var readLive = (name) => Effect27.map(readEnforcement(name), (live) => live === undefined ? undefined : attributesOf8(name, live));
|
|
2478
|
+
var planEnforcement = (props) => Effect27.gen(function* () {
|
|
2433
2479
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2434
2480
|
if (bad.length > 0)
|
|
2435
2481
|
return "update";
|
|
2436
2482
|
const live = yield* readLive(props.name);
|
|
2437
2483
|
return live !== undefined && matches7(live, props, resolved) ? "noop" : "update";
|
|
2438
2484
|
});
|
|
2439
|
-
var reconcileEnforcement = (props, claim) =>
|
|
2485
|
+
var reconcileEnforcement = (props, claim) => Effect27.gen(function* () {
|
|
2440
2486
|
const { bad, resolved } = yield* resolveTargets(props);
|
|
2441
2487
|
if (bad.length > 0)
|
|
2442
2488
|
return yield* refuse3(props.name, bad.join("; "));
|
|
@@ -2445,7 +2491,7 @@ var reconcileEnforcement = (props, claim) => Effect25.gen(function* () {
|
|
|
2445
2491
|
yield* claim(`Bao.MfaLoginEnforcement ${props.name}`);
|
|
2446
2492
|
}
|
|
2447
2493
|
if (live === undefined || !matches7(live, props, resolved)) {
|
|
2448
|
-
yield* writeEnforcement(props.name,
|
|
2494
|
+
yield* writeEnforcement(props.name, writeBody5(canonicalFromProps4(props, resolved)));
|
|
2449
2495
|
}
|
|
2450
2496
|
const after = yield* readLive(props.name);
|
|
2451
2497
|
if (after === undefined)
|
|
@@ -2455,14 +2501,14 @@ var reconcileEnforcement = (props, claim) => Effect25.gen(function* () {
|
|
|
2455
2501
|
}
|
|
2456
2502
|
return after;
|
|
2457
2503
|
});
|
|
2458
|
-
var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforcement,
|
|
2459
|
-
list: () =>
|
|
2460
|
-
read:
|
|
2504
|
+
var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforcement, Effect27.succeed(BaoMfaLoginEnforcement.Provider.of({
|
|
2505
|
+
list: () => Effect27.succeed([]),
|
|
2506
|
+
read: Effect27.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2461
2507
|
const found = yield* readLive(olds.name);
|
|
2462
|
-
const ours =
|
|
2508
|
+
const ours = Effect27.map(planEnforcement(olds), (plan) => plan === "noop");
|
|
2463
2509
|
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2464
2510
|
}),
|
|
2465
|
-
diff:
|
|
2511
|
+
diff: Effect27.fn(function* ({ news, olds, output }) {
|
|
2466
2512
|
const move = yield* judgeRename(IDENTITY6, olds, news, output);
|
|
2467
2513
|
if (output === undefined)
|
|
2468
2514
|
return;
|
|
@@ -2472,19 +2518,19 @@ var BaoMfaLoginEnforcementProvider = () => Provider7.effect(BaoMfaLoginEnforceme
|
|
|
2472
2518
|
return;
|
|
2473
2519
|
return { action: yield* planEnforcement(news) };
|
|
2474
2520
|
}),
|
|
2475
|
-
reconcile:
|
|
2521
|
+
reconcile: Effect27.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2476
2522
|
yield* guardRename(IDENTITY6, news, output);
|
|
2477
2523
|
return yield* reconcileEnforcement(news, claimFor({ fqn, instanceId, output }));
|
|
2478
2524
|
}),
|
|
2479
|
-
delete:
|
|
2525
|
+
delete: Effect27.fn(function* ({ output }) {
|
|
2480
2526
|
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.");
|
|
2481
2527
|
})
|
|
2482
|
-
})).pipe(
|
|
2528
|
+
})).pipe(Effect27.map(provingResumes)));
|
|
2483
2529
|
// src/openbao/mfa-totp.ts
|
|
2484
2530
|
import { Resource as Resource8 } from "alchemy";
|
|
2485
2531
|
import { isResolved as isResolved8 } from "alchemy/Diff";
|
|
2486
2532
|
import * as Provider8 from "alchemy/Provider";
|
|
2487
|
-
import * as
|
|
2533
|
+
import * as Effect28 from "effect/Effect";
|
|
2488
2534
|
|
|
2489
2535
|
// src/openbao/mfa-totp-form.ts
|
|
2490
2536
|
var canonical6 = (input) => ({
|
|
@@ -2530,7 +2576,7 @@ var attributesOf9 = (methodId, live) => {
|
|
|
2530
2576
|
};
|
|
2531
2577
|
};
|
|
2532
2578
|
var matches8 = (attributes, props) => attributes.digest === sha256(JSON.stringify(canonicalFromProps5(props)));
|
|
2533
|
-
var
|
|
2579
|
+
var writeBody6 = (props) => {
|
|
2534
2580
|
const form = canonicalFromProps5(props);
|
|
2535
2581
|
return {
|
|
2536
2582
|
algorithm: form.algorithm,
|
|
@@ -2565,15 +2611,15 @@ var problems5 = (props) => {
|
|
|
2565
2611
|
var BaoMfaTotpMethod = Resource8("Bao.MfaTotpMethod", {
|
|
2566
2612
|
defaultRemovalPolicy: "retain"
|
|
2567
2613
|
});
|
|
2568
|
-
var refuse4 = (name, message) =>
|
|
2569
|
-
var readTotp = (props) =>
|
|
2570
|
-
var planTotp = (props) =>
|
|
2614
|
+
var refuse4 = (name, message) => Effect28.die(new Error(`Bao.MfaTotpMethod ${name}: ${message}`));
|
|
2615
|
+
var readTotp = (props) => Effect28.map(findTotp(props.name), (found) => found === undefined ? undefined : attributesOf9(found.id, found.live));
|
|
2616
|
+
var planTotp = (props) => Effect28.gen(function* () {
|
|
2571
2617
|
if (problems5(props).length > 0)
|
|
2572
2618
|
return "update";
|
|
2573
2619
|
const live = yield* readTotp(props);
|
|
2574
2620
|
return live !== undefined && matches8(live, props) ? "noop" : "update";
|
|
2575
2621
|
});
|
|
2576
|
-
var reconcileTotp = (props, claim) =>
|
|
2622
|
+
var reconcileTotp = (props, claim) => Effect28.gen(function* () {
|
|
2577
2623
|
const bad = problems5(props);
|
|
2578
2624
|
if (bad.length > 0)
|
|
2579
2625
|
return yield* refuse4(props.name, bad.join("; "));
|
|
@@ -2581,7 +2627,7 @@ var reconcileTotp = (props, claim) => Effect26.gen(function* () {
|
|
|
2581
2627
|
if (live !== undefined && claim !== undefined)
|
|
2582
2628
|
yield* claim(`Bao.MfaTotpMethod ${props.name}`);
|
|
2583
2629
|
if (live === undefined || !matches8(live, props))
|
|
2584
|
-
yield* writeTotp(
|
|
2630
|
+
yield* writeTotp(writeBody6(props));
|
|
2585
2631
|
const after = yield* readTotp(props);
|
|
2586
2632
|
if (after === undefined)
|
|
2587
2633
|
return yield* refuse4(props.name, "the write succeeded but no method has that name.");
|
|
@@ -2589,14 +2635,14 @@ var reconcileTotp = (props, claim) => Effect26.gen(function* () {
|
|
|
2589
2635
|
return yield* refuse4(props.name, "the method read back different.");
|
|
2590
2636
|
return after;
|
|
2591
2637
|
});
|
|
2592
|
-
var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod,
|
|
2593
|
-
list: () =>
|
|
2594
|
-
read:
|
|
2638
|
+
var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod, Effect28.succeed(BaoMfaTotpMethod.Provider.of({
|
|
2639
|
+
list: () => Effect28.succeed([]),
|
|
2640
|
+
read: Effect28.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2595
2641
|
const found = yield* readTotp(olds);
|
|
2596
|
-
const ours =
|
|
2642
|
+
const ours = Effect28.sync(() => found !== undefined && problems5(olds).length === 0 && matches8(found, olds));
|
|
2597
2643
|
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2598
2644
|
}),
|
|
2599
|
-
diff:
|
|
2645
|
+
diff: Effect28.fn(function* ({ news, output }) {
|
|
2600
2646
|
const name = declaredString(news, "name");
|
|
2601
2647
|
if (output !== undefined && name !== undefined) {
|
|
2602
2648
|
const rename = renameProblem(output.name, name);
|
|
@@ -2609,39 +2655,39 @@ var BaoMfaTotpMethodProvider = () => Provider8.effect(BaoMfaTotpMethod, Effect26
|
|
|
2609
2655
|
return;
|
|
2610
2656
|
return { action: yield* planTotp(news) };
|
|
2611
2657
|
}),
|
|
2612
|
-
reconcile:
|
|
2658
|
+
reconcile: Effect28.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2613
2659
|
const rename = output === undefined ? undefined : renameProblem(output.name, news.name);
|
|
2614
2660
|
if (rename !== undefined)
|
|
2615
2661
|
return yield* refuse4(news.name, rename);
|
|
2616
2662
|
return yield* reconcileTotp(news, claimFor({ fqn, instanceId, output }));
|
|
2617
2663
|
}),
|
|
2618
|
-
delete:
|
|
2664
|
+
delete: Effect28.fn(function* ({ output }) {
|
|
2619
2665
|
yield* deleteTotp(output.methodId);
|
|
2620
2666
|
return;
|
|
2621
2667
|
})
|
|
2622
|
-
})).pipe(
|
|
2668
|
+
})).pipe(Effect28.map(provingResumes)));
|
|
2623
2669
|
// src/openbao/mount.ts
|
|
2624
2670
|
import { Resource as Resource9 } from "alchemy";
|
|
2625
2671
|
import { isResolved as isResolved9 } from "alchemy/Diff";
|
|
2626
2672
|
import * as Provider9 from "alchemy/Provider";
|
|
2627
|
-
import * as
|
|
2673
|
+
import * as Effect31 from "effect/Effect";
|
|
2628
2674
|
|
|
2629
2675
|
// src/openbao/mount-reconcile.ts
|
|
2630
|
-
import * as
|
|
2676
|
+
import * as Effect30 from "effect/Effect";
|
|
2631
2677
|
|
|
2632
2678
|
// src/openbao/mount-wire.ts
|
|
2633
|
-
import * as
|
|
2634
|
-
var absentFromTable2 = (path, asked) => baoRead("sys/mounts").pipe(
|
|
2679
|
+
import * as Effect29 from "effect/Effect";
|
|
2680
|
+
var absentFromTable2 = (path, asked) => baoRead("sys/mounts").pipe(Effect29.mapError((listing) => new BaoError(asked.status, asked.method, asked.path, [
|
|
2635
2681
|
...asked.errors,
|
|
2636
2682
|
`sys/mounts could not confirm the mount is absent: ${listing.message}`
|
|
2637
|
-
])),
|
|
2638
|
-
var readMountData = (path) => baoRead(readPath(path)).pipe(
|
|
2683
|
+
])), Effect29.flatMap((table) => table !== undefined && !Object.hasOwn(table, `${mountPath(path)}/`) ? Effect29.succeed(undefined) : Effect29.fail(asked)));
|
|
2684
|
+
var readMountData = (path) => baoRead(readPath(path)).pipe(Effect29.catchIf((error) => error.status === 400, (error) => absentFromTable2(path, error)));
|
|
2639
2685
|
var enableMount = (props) => baoWrite("POST", readPath(props.path), enableBody(props));
|
|
2640
2686
|
var tuneMount = (props) => baoWrite("POST", tunePath(props.path), tuneBody(props));
|
|
2641
2687
|
var disableMount = (path) => baoDelete(readPath(path));
|
|
2642
2688
|
|
|
2643
2689
|
// src/openbao/mount-reconcile.ts
|
|
2644
|
-
var readMount = (props) =>
|
|
2690
|
+
var readMount = (props) => Effect30.gen(function* () {
|
|
2645
2691
|
const live = yield* readMountData(props.path);
|
|
2646
2692
|
if (live === undefined)
|
|
2647
2693
|
return;
|
|
@@ -2654,10 +2700,10 @@ var moveTarget2 = (props) => ({
|
|
|
2654
2700
|
type: props.type,
|
|
2655
2701
|
wire: mountPath
|
|
2656
2702
|
});
|
|
2657
|
-
var reconcileMount = (news, stated, options, claim) =>
|
|
2703
|
+
var reconcileMount = (news, stated, options, claim) => Effect30.gen(function* () {
|
|
2658
2704
|
const move = planMove("Bao.Mount", stated, news.path, news.remountFrom);
|
|
2659
2705
|
if (move.kind === "refuse")
|
|
2660
|
-
return yield*
|
|
2706
|
+
return yield* Effect30.die(new Error(move.message));
|
|
2661
2707
|
const first = stated === undefined ? claim : undefined;
|
|
2662
2708
|
if (first !== undefined && move.kind === "move") {
|
|
2663
2709
|
const source = yield* readMount({ ...news, path: move.from });
|
|
@@ -2673,7 +2719,7 @@ var reconcileMount = (news, stated, options, claim) => Effect28.gen(function* ()
|
|
|
2673
2719
|
yield* tuneMount(news);
|
|
2674
2720
|
} else {
|
|
2675
2721
|
if (live.type !== news.type) {
|
|
2676
|
-
return yield*
|
|
2722
|
+
return yield* Effect30.die(new Error(`Bao.Mount ${mountPath(news.path)}: live type ${live.type} != ${news.type}. ` + "Secrets engine type is immutable — replace manually."));
|
|
2677
2723
|
}
|
|
2678
2724
|
if (first !== undefined)
|
|
2679
2725
|
yield* first(`Bao.Mount ${mountPath(news.path)}`);
|
|
@@ -2682,7 +2728,7 @@ var reconcileMount = (news, stated, options, claim) => Effect28.gen(function* ()
|
|
|
2682
2728
|
}
|
|
2683
2729
|
live = yield* readMount(news);
|
|
2684
2730
|
if (live === undefined) {
|
|
2685
|
-
return yield*
|
|
2731
|
+
return yield* Effect30.die(new Error(`Bao.Mount ${mountPath(news.path)}: write returned no error but the mount is still absent.`));
|
|
2686
2732
|
}
|
|
2687
2733
|
return live;
|
|
2688
2734
|
});
|
|
@@ -2691,21 +2737,21 @@ var reconcileMount = (news, stated, options, claim) => Effect28.gen(function* ()
|
|
|
2691
2737
|
var BaoMount = Resource9("Bao.Mount", {
|
|
2692
2738
|
defaultRemovalPolicy: "retain"
|
|
2693
2739
|
});
|
|
2694
|
-
var BaoMountProvider = () => Provider9.effect(BaoMount,
|
|
2695
|
-
list: () =>
|
|
2696
|
-
read:
|
|
2740
|
+
var BaoMountProvider = () => Provider9.effect(BaoMount, Effect31.succeed(BaoMount.Provider.of({
|
|
2741
|
+
list: () => Effect31.succeed([]),
|
|
2742
|
+
read: Effect31.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2697
2743
|
const found = yield* readMount(olds);
|
|
2698
|
-
const ours =
|
|
2744
|
+
const ours = Effect31.sync(() => found !== undefined && matches(found, olds));
|
|
2699
2745
|
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2700
2746
|
}),
|
|
2701
|
-
diff:
|
|
2747
|
+
diff: Effect31.fn(function* ({ news, output }) {
|
|
2702
2748
|
if (output === undefined)
|
|
2703
2749
|
return;
|
|
2704
2750
|
if (!isResolved9(news))
|
|
2705
2751
|
return;
|
|
2706
2752
|
const move = planMove("Bao.Mount", output.path, news.path, news.remountFrom);
|
|
2707
2753
|
if (move.kind === "refuse")
|
|
2708
|
-
return yield*
|
|
2754
|
+
return yield* Effect31.die(new Error(move.message));
|
|
2709
2755
|
if (move.kind === "move")
|
|
2710
2756
|
return { action: "update" };
|
|
2711
2757
|
const live = yield* readMount(news);
|
|
@@ -2717,20 +2763,20 @@ var BaoMountProvider = () => Provider9.effect(BaoMount, Effect29.succeed(BaoMoun
|
|
|
2717
2763
|
return { action: "noop" };
|
|
2718
2764
|
return { action: "update" };
|
|
2719
2765
|
}),
|
|
2720
|
-
reconcile:
|
|
2766
|
+
reconcile: Effect31.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2721
2767
|
const claim = claimFor({ fqn, instanceId, output });
|
|
2722
2768
|
return yield* reconcileMount(news, output?.path, undefined, claim);
|
|
2723
2769
|
}),
|
|
2724
|
-
delete:
|
|
2770
|
+
delete: Effect31.fn(function* ({ output }) {
|
|
2725
2771
|
yield* disableMount(output.path);
|
|
2726
2772
|
return;
|
|
2727
2773
|
})
|
|
2728
|
-
})).pipe(
|
|
2774
|
+
})).pipe(Effect31.map(provingResumes)));
|
|
2729
2775
|
// src/openbao/pki-role.ts
|
|
2730
2776
|
import { Resource as Resource10 } from "alchemy";
|
|
2731
2777
|
import { isResolved as isResolved10 } from "alchemy/Diff";
|
|
2732
2778
|
import * as Provider10 from "alchemy/Provider";
|
|
2733
|
-
import * as
|
|
2779
|
+
import * as Effect32 from "effect/Effect";
|
|
2734
2780
|
|
|
2735
2781
|
// src/openbao/pki-role-canonical.ts
|
|
2736
2782
|
var DEFAULT_KEY_USAGE = [
|
|
@@ -2764,7 +2810,7 @@ var canonical7 = (input) => ({
|
|
|
2764
2810
|
signatureBits: input.signatureBits,
|
|
2765
2811
|
ttlSeconds: input.ttlSeconds
|
|
2766
2812
|
});
|
|
2767
|
-
var
|
|
2813
|
+
var seconds4 = (text10) => parseDuration(text10) ?? -1;
|
|
2768
2814
|
var canonicalFromProps6 = (props) => canonical7({
|
|
2769
2815
|
allowBareDomains: props.allowBareDomains ?? false,
|
|
2770
2816
|
allowGlobDomains: props.allowGlobDomains ?? false,
|
|
@@ -2782,12 +2828,12 @@ var canonicalFromProps6 = (props) => canonical7({
|
|
|
2782
2828
|
keyBits: props.keyBits ?? 0,
|
|
2783
2829
|
keyType: props.keyType ?? "rsa",
|
|
2784
2830
|
keyUsage: props.keyUsage ?? DEFAULT_KEY_USAGE,
|
|
2785
|
-
maxTtlSeconds:
|
|
2831
|
+
maxTtlSeconds: seconds4(props.maxTtl),
|
|
2786
2832
|
noStore: props.noStore ?? false,
|
|
2787
2833
|
requireCn: props.requireCn ?? true,
|
|
2788
2834
|
serverFlag: props.serverFlag ?? true,
|
|
2789
2835
|
signatureBits: props.signatureBits ?? 0,
|
|
2790
|
-
ttlSeconds:
|
|
2836
|
+
ttlSeconds: seconds4(props.ttl)
|
|
2791
2837
|
});
|
|
2792
2838
|
var bool2 = (value, fallback) => typeof value === "boolean" ? value : fallback;
|
|
2793
2839
|
var int2 = (value, fallback) => typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
@@ -2843,7 +2889,7 @@ var attributesOf10 = (props, live) => {
|
|
|
2843
2889
|
digest: digestOf(form)
|
|
2844
2890
|
};
|
|
2845
2891
|
};
|
|
2846
|
-
var
|
|
2892
|
+
var writeBody7 = (props) => {
|
|
2847
2893
|
const form = canonicalFromProps6(props);
|
|
2848
2894
|
const body = {
|
|
2849
2895
|
allowed_domains: form.allowedDomains.join(","),
|
|
@@ -2897,20 +2943,20 @@ var BaoPkiRole = Resource10("Bao.PkiRole", {
|
|
|
2897
2943
|
defaultRemovalPolicy: "retain"
|
|
2898
2944
|
});
|
|
2899
2945
|
var IDENTITY7 = roleIdentity("Bao.PkiRole", (mount, name) => rolePath4({ mount, name }), "pki");
|
|
2900
|
-
var readRole2 = (props) =>
|
|
2946
|
+
var readRole2 = (props) => Effect32.gen(function* () {
|
|
2901
2947
|
const live = yield* baoRead(rolePath4(props));
|
|
2902
2948
|
if (live === undefined)
|
|
2903
2949
|
return;
|
|
2904
2950
|
return attributesOf10(props, live);
|
|
2905
2951
|
});
|
|
2906
|
-
var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole,
|
|
2907
|
-
list: () =>
|
|
2908
|
-
read:
|
|
2952
|
+
var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect32.succeed(BaoPkiRole.Provider.of({
|
|
2953
|
+
list: () => Effect32.succeed([]),
|
|
2954
|
+
read: Effect32.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
2909
2955
|
const found = yield* readRole2(olds);
|
|
2910
|
-
const ours =
|
|
2956
|
+
const ours = Effect32.sync(() => found !== undefined && problems6(olds).length === 0 && matches9(found, olds));
|
|
2911
2957
|
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
2912
2958
|
}),
|
|
2913
|
-
diff:
|
|
2959
|
+
diff: Effect32.fn(function* ({ news, olds, output }) {
|
|
2914
2960
|
const move = yield* judgeRename(IDENTITY7, olds, news, output);
|
|
2915
2961
|
if (output === undefined)
|
|
2916
2962
|
return;
|
|
@@ -2925,38 +2971,38 @@ var BaoPkiRoleProvider = () => Provider10.effect(BaoPkiRole, Effect30.succeed(Ba
|
|
|
2925
2971
|
return { action: "update" };
|
|
2926
2972
|
return matches9(live, news) ? { action: "noop" } : { action: "update" };
|
|
2927
2973
|
}),
|
|
2928
|
-
reconcile:
|
|
2974
|
+
reconcile: Effect32.fn(function* ({ fqn, instanceId, news, output }) {
|
|
2929
2975
|
const path = rolePath4(news);
|
|
2930
2976
|
yield* guardRename(IDENTITY7, news, output);
|
|
2931
2977
|
const bad = problems6(news);
|
|
2932
2978
|
if (bad.length > 0) {
|
|
2933
|
-
return yield*
|
|
2979
|
+
return yield* Effect32.die(new Error(`Bao.PkiRole ${path}: ${bad.join(" ")}`));
|
|
2934
2980
|
}
|
|
2935
2981
|
const live = yield* readRole2(news);
|
|
2936
2982
|
if (live !== undefined)
|
|
2937
2983
|
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.PkiRole ${path}`);
|
|
2938
2984
|
if (live === undefined || !matches9(live, news)) {
|
|
2939
|
-
yield* baoWrite("PUT", path,
|
|
2985
|
+
yield* baoWrite("PUT", path, writeBody7(news));
|
|
2940
2986
|
}
|
|
2941
2987
|
const after = yield* readRole2(news);
|
|
2942
2988
|
if (after === undefined) {
|
|
2943
|
-
return yield*
|
|
2989
|
+
return yield* Effect32.die(new Error(`Bao.PkiRole ${path}: write reported success but the role is absent.`));
|
|
2944
2990
|
}
|
|
2945
2991
|
if (!matches9(after, news)) {
|
|
2946
|
-
return yield*
|
|
2992
|
+
return yield* Effect32.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.`));
|
|
2947
2993
|
}
|
|
2948
2994
|
return after;
|
|
2949
2995
|
}),
|
|
2950
|
-
delete:
|
|
2996
|
+
delete: Effect32.fn(function* ({ output }) {
|
|
2951
2997
|
yield* baoDelete(rolePath4(output));
|
|
2952
2998
|
return;
|
|
2953
2999
|
})
|
|
2954
|
-
})).pipe(
|
|
3000
|
+
})).pipe(Effect32.map(provingResumes)));
|
|
2955
3001
|
// src/openbao/plugin.ts
|
|
2956
3002
|
import { Resource as Resource11 } from "alchemy";
|
|
2957
3003
|
import { isResolved as isResolved11 } from "alchemy/Diff";
|
|
2958
3004
|
import * as Provider11 from "alchemy/Provider";
|
|
2959
|
-
import * as
|
|
3005
|
+
import * as Effect34 from "effect/Effect";
|
|
2960
3006
|
|
|
2961
3007
|
// src/openbao/plugin-form.ts
|
|
2962
3008
|
var resolve = (props) => ({
|
|
@@ -3012,7 +3058,7 @@ var sameArgs = (want, have) => want.length === have.length && want.every((entry,
|
|
|
3012
3058
|
var matches10 = (attributes, form) => !attributes.builtin && attributes.version === form.version && attributes.sha256 === form.sha256 && attributes.command === form.command && sameArgs(form.args, attributes.args);
|
|
3013
3059
|
|
|
3014
3060
|
// src/openbao/plugin-reconcile.ts
|
|
3015
|
-
import * as
|
|
3061
|
+
import * as Effect33 from "effect/Effect";
|
|
3016
3062
|
|
|
3017
3063
|
// src/openbao/plugin-wire.ts
|
|
3018
3064
|
var readPluginData = (form) => baoRead(versionedPath(form.type, form.name, form.version));
|
|
@@ -3020,10 +3066,10 @@ var registerPlugin = (form) => baoWrite("PUT", catalogPath(form.type, form.name)
|
|
|
3020
3066
|
var deregisterPlugin = (type, name, version) => baoDelete(versionedPath(type, name, version));
|
|
3021
3067
|
|
|
3022
3068
|
// src/openbao/plugin-reconcile.ts
|
|
3023
|
-
var readEntry = (form) =>
|
|
3024
|
-
var refuse5 = (form, message) =>
|
|
3069
|
+
var readEntry = (form) => Effect33.map(readPluginData(form), (live) => live === undefined ? undefined : { attributes: attributesOf11(form, live), live });
|
|
3070
|
+
var refuse5 = (form, message) => Effect33.die(new Error(`Bao.Plugin ${versionedPath(form.type, form.name, form.version)}: ${message}`));
|
|
3025
3071
|
var SELF_REPORTED = "the write succeeded but the read-back does not match. If the binary reports its own version, " + "OpenBao filed the registration under it (plugin_catalog.go setInternal) — declare `version` " + "as exactly the version the binary reports, and deploy once with --adopt: that adopts the " + "entry this write just made.";
|
|
3026
|
-
var reconcilePlugin = (props, claim) =>
|
|
3072
|
+
var reconcilePlugin = (props, claim) => Effect33.gen(function* () {
|
|
3027
3073
|
const form = resolve(props);
|
|
3028
3074
|
const bad = problems7(form);
|
|
3029
3075
|
if (bad.length > 0)
|
|
@@ -3065,15 +3111,15 @@ var IDENTITY8 = {
|
|
|
3065
3111
|
family: "Bao.Plugin",
|
|
3066
3112
|
recorded: (output) => versionedPath(output.type, output.name, output.version)
|
|
3067
3113
|
};
|
|
3068
|
-
var BaoPluginProvider = () => Provider11.effect(BaoPlugin,
|
|
3069
|
-
list: () =>
|
|
3070
|
-
read:
|
|
3114
|
+
var BaoPluginProvider = () => Provider11.effect(BaoPlugin, Effect34.succeed(BaoPlugin.Provider.of({
|
|
3115
|
+
list: () => Effect34.succeed([]),
|
|
3116
|
+
read: Effect34.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
3071
3117
|
const form = resolve(olds);
|
|
3072
3118
|
const found = yield* readEntry(form);
|
|
3073
|
-
const ours =
|
|
3119
|
+
const ours = Effect34.sync(() => found !== undefined && problems7(form).length === 0 && matches10(found.attributes, form));
|
|
3074
3120
|
return yield* ownedRead({ fqn, instanceId, output }, found?.attributes, ours);
|
|
3075
3121
|
}),
|
|
3076
|
-
diff:
|
|
3122
|
+
diff: Effect34.fn(function* ({ news, olds, output }) {
|
|
3077
3123
|
const move = yield* judgeRename(IDENTITY8, olds, news, output);
|
|
3078
3124
|
if (output === undefined)
|
|
3079
3125
|
return;
|
|
@@ -3087,20 +3133,20 @@ var BaoPluginProvider = () => Provider11.effect(BaoPlugin, Effect32.succeed(BaoP
|
|
|
3087
3133
|
return { action: "update" };
|
|
3088
3134
|
return matches10(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
3089
3135
|
}),
|
|
3090
|
-
reconcile:
|
|
3136
|
+
reconcile: Effect34.fn(function* ({ fqn, instanceId, news, output }) {
|
|
3091
3137
|
yield* guardRename(IDENTITY8, news, output);
|
|
3092
3138
|
return yield* reconcilePlugin(news, claimFor({ fqn, instanceId, output }));
|
|
3093
3139
|
}),
|
|
3094
|
-
delete:
|
|
3140
|
+
delete: Effect34.fn(function* ({ output }) {
|
|
3095
3141
|
yield* deregisterPlugin(output.type, output.name, output.version);
|
|
3096
3142
|
return;
|
|
3097
3143
|
})
|
|
3098
|
-
})).pipe(
|
|
3144
|
+
})).pipe(Effect34.map(provingResumes)));
|
|
3099
3145
|
// src/openbao/policy.ts
|
|
3100
3146
|
import { Resource as Resource12 } from "alchemy";
|
|
3101
3147
|
import { isResolved as isResolved12 } from "alchemy/Diff";
|
|
3102
3148
|
import * as Provider12 from "alchemy/Provider";
|
|
3103
|
-
import * as
|
|
3149
|
+
import * as Effect36 from "effect/Effect";
|
|
3104
3150
|
import * as FileSystem from "effect/FileSystem";
|
|
3105
3151
|
import * as Path from "effect/Path";
|
|
3106
3152
|
|
|
@@ -3108,22 +3154,29 @@ import * as Path from "effect/Path";
|
|
|
3108
3154
|
var isEmptyAssembly = (parts, joined) => parts === 0 || !/^\s*path\s+"/m.test(joined);
|
|
3109
3155
|
|
|
3110
3156
|
// src/openbao/policy-wire.ts
|
|
3111
|
-
import
|
|
3157
|
+
import {
|
|
3158
|
+
policiesDeleteAclPolicy,
|
|
3159
|
+
policiesReadAclPolicy,
|
|
3160
|
+
policiesWriteAclPolicy
|
|
3161
|
+
} from "@distilled.cloud/openbao/policies";
|
|
3162
|
+
import * as Effect35 from "effect/Effect";
|
|
3112
3163
|
var policyPath = (name) => `sys/policies/acl/${name}`;
|
|
3113
|
-
var readPolicy = (name) =>
|
|
3114
|
-
if (data === undefined)
|
|
3115
|
-
return Effect33.succeed("");
|
|
3164
|
+
var readPolicy = (name) => runBaoRead(policiesReadAclPolicy({ name })).pipe(Effect35.flatMap((data) => {
|
|
3116
3165
|
const text11 = data["policy"];
|
|
3117
|
-
return typeof text11 === "string" ?
|
|
3118
|
-
});
|
|
3119
|
-
var
|
|
3120
|
-
var
|
|
3166
|
+
return typeof text11 === "string" ? Effect35.succeed(text11) : Effect35.fail(new BaoError(200, "GET", policyPath(name), ["no data.policy in the response"]));
|
|
3167
|
+
}), Effect35.catchTag("PolicyNotFound", () => Effect35.succeed(undefined)));
|
|
3168
|
+
var policyExists = (name) => Effect35.map(readPolicy(name), (policy) => policy !== undefined);
|
|
3169
|
+
var writePolicy = (name, hcl) => runBaoWrite(policiesWriteAclPolicy({ name, policy: hcl })).pipe(Effect35.asVoid);
|
|
3170
|
+
var deletePolicy = (name) => runBao(policiesDeleteAclPolicy({ name })).pipe(Effect35.catchTag("NotFound", () => Effect35.void), Effect35.asVoid);
|
|
3171
|
+
|
|
3172
|
+
// src/openbao/policy-identity.ts
|
|
3173
|
+
var policyIdentity = nameIdentity("Bao.Policy", policyPath, policyKey);
|
|
3174
|
+
var judgePolicyRename = (olds, news, output) => judgeMoveWith("Bao.Policy", output === undefined ? declaredString(olds, "name") : output.name, declaredString(news, "name"), policyExists, policyKey);
|
|
3121
3175
|
|
|
3122
3176
|
// src/openbao/policy.ts
|
|
3123
3177
|
var BaoPolicy = Resource12("Bao.Policy", {
|
|
3124
3178
|
defaultRemovalPolicy: "retain"
|
|
3125
3179
|
});
|
|
3126
|
-
var IDENTITY9 = nameIdentity("Bao.Policy", policyPath, policyKey);
|
|
3127
3180
|
var grantsOf = (hcl) => (hcl.match(/^path /gm) ?? []).length;
|
|
3128
3181
|
var attributesOf12 = (name, hcl, parts) => ({
|
|
3129
3182
|
name,
|
|
@@ -3131,10 +3184,10 @@ var attributesOf12 = (name, hcl, parts) => ({
|
|
|
3131
3184
|
grants: grantsOf(hcl),
|
|
3132
3185
|
parts
|
|
3133
3186
|
});
|
|
3134
|
-
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy,
|
|
3187
|
+
var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect36.gen(function* () {
|
|
3135
3188
|
const fs = yield* FileSystem.FileSystem;
|
|
3136
3189
|
const path = yield* Path.Path;
|
|
3137
|
-
const assemble = (dir) =>
|
|
3190
|
+
const assemble = (dir) => Effect36.gen(function* () {
|
|
3138
3191
|
const entries2 = (yield* fs.readDirectory(dir)).filter((f) => f.endsWith(".hcl")).sort();
|
|
3139
3192
|
let joined = "";
|
|
3140
3193
|
for (const f of entries2)
|
|
@@ -3143,15 +3196,15 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect34.gen(function
|
|
|
3143
3196
|
return { joined, parts: entries2.length };
|
|
3144
3197
|
});
|
|
3145
3198
|
return BaoPolicy.Provider.of({
|
|
3146
|
-
list: () =>
|
|
3147
|
-
read:
|
|
3199
|
+
list: () => Effect36.succeed([]),
|
|
3200
|
+
read: Effect36.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
3148
3201
|
const live = yield* readPolicy(olds.name);
|
|
3149
|
-
const found = live
|
|
3150
|
-
const ours =
|
|
3202
|
+
const found = live === undefined ? undefined : attributesOf12(olds.name, live, 0);
|
|
3203
|
+
const ours = Effect36.map(assemble(olds.fragments), (a) => sha256(a.joined) === found?.digest);
|
|
3151
3204
|
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
3152
3205
|
}),
|
|
3153
|
-
diff:
|
|
3154
|
-
const move = yield*
|
|
3206
|
+
diff: Effect36.fn(function* ({ news, olds, output }) {
|
|
3207
|
+
const move = yield* judgePolicyRename(olds, news, output);
|
|
3155
3208
|
if (output === undefined)
|
|
3156
3209
|
return;
|
|
3157
3210
|
if (move !== undefined)
|
|
@@ -3160,47 +3213,47 @@ var BaoPolicyProvider = () => Provider12.effect(BaoPolicy, Effect34.gen(function
|
|
|
3160
3213
|
return;
|
|
3161
3214
|
const { joined } = yield* assemble(news.fragments);
|
|
3162
3215
|
const live = yield* readPolicy(news.name);
|
|
3163
|
-
return live
|
|
3216
|
+
return live !== undefined && sha256(live) === sha256(joined) ? { action: "noop" } : { action: "update" };
|
|
3164
3217
|
}),
|
|
3165
|
-
reconcile:
|
|
3218
|
+
reconcile: Effect36.fn(function* ({ fqn, instanceId, news, output }) {
|
|
3166
3219
|
const name = news.name;
|
|
3167
|
-
yield* guardRename(
|
|
3220
|
+
yield* guardRename(policyIdentity, news, output);
|
|
3168
3221
|
const { joined, parts } = yield* assemble(news.fragments);
|
|
3169
3222
|
if (isEmptyAssembly(parts, joined))
|
|
3170
|
-
return yield*
|
|
3223
|
+
return yield* Effect36.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.`));
|
|
3171
3224
|
const current = yield* readPolicy(name);
|
|
3172
|
-
if (current
|
|
3225
|
+
if (current !== undefined)
|
|
3173
3226
|
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.Policy ${name}`);
|
|
3174
|
-
if (current
|
|
3227
|
+
if (current !== undefined && sha256(current) === sha256(joined)) {
|
|
3175
3228
|
return attributesOf12(name, joined, parts);
|
|
3176
3229
|
}
|
|
3177
3230
|
yield* writePolicy(name, joined);
|
|
3178
3231
|
return attributesOf12(name, joined, parts);
|
|
3179
3232
|
}),
|
|
3180
|
-
delete:
|
|
3233
|
+
delete: Effect36.fn(function* ({ output }) {
|
|
3181
3234
|
yield* deletePolicy(output.name);
|
|
3182
3235
|
return;
|
|
3183
3236
|
})
|
|
3184
3237
|
});
|
|
3185
|
-
}).pipe(
|
|
3238
|
+
}).pipe(Effect36.map(provingResumes)));
|
|
3186
3239
|
// src/openbao/proxmox-role.ts
|
|
3187
3240
|
import { Resource as Resource13 } from "alchemy";
|
|
3188
3241
|
import { isResolved as isResolved13 } from "alchemy/Diff";
|
|
3189
3242
|
import * as Provider13 from "alchemy/Provider";
|
|
3190
|
-
import * as
|
|
3243
|
+
import * as Effect38 from "effect/Effect";
|
|
3191
3244
|
|
|
3192
3245
|
// src/openbao/proxmox-role-form.ts
|
|
3193
3246
|
var text11 = (value) => typeof value === "string" ? value : "";
|
|
3194
|
-
var ttlText3 = (
|
|
3195
|
-
if (
|
|
3247
|
+
var ttlText3 = (seconds5, fallback = "0") => {
|
|
3248
|
+
if (seconds5 === undefined)
|
|
3196
3249
|
return fallback;
|
|
3197
|
-
if (
|
|
3198
|
-
return `${String(
|
|
3199
|
-
if (
|
|
3200
|
-
return `${String(
|
|
3201
|
-
if (
|
|
3202
|
-
return `${String(
|
|
3203
|
-
return `${String(
|
|
3250
|
+
if (seconds5 % 86400 === 0)
|
|
3251
|
+
return `${String(seconds5 / 86400)}d`;
|
|
3252
|
+
if (seconds5 % 3600 === 0)
|
|
3253
|
+
return `${String(seconds5 / 3600)}h`;
|
|
3254
|
+
if (seconds5 % 60 === 0)
|
|
3255
|
+
return `${String(seconds5 / 60)}m`;
|
|
3256
|
+
return `${String(seconds5)}s`;
|
|
3204
3257
|
};
|
|
3205
3258
|
var rolePath5 = (mount, name) => `${mountPath(mount)}/roles/${name}`;
|
|
3206
3259
|
var attributesOf13 = (props, live) => {
|
|
@@ -3213,7 +3266,7 @@ var attributesOf13 = (props, live) => {
|
|
|
3213
3266
|
};
|
|
3214
3267
|
return { ...attrs, digest: sha256(JSON.stringify(attrs)) };
|
|
3215
3268
|
};
|
|
3216
|
-
var
|
|
3269
|
+
var writeBody8 = (props) => {
|
|
3217
3270
|
const ttl = parseDuration(props.ttl);
|
|
3218
3271
|
const maxTtl = parseDuration(props.maxTtl);
|
|
3219
3272
|
const bad = [];
|
|
@@ -3237,8 +3290,8 @@ var rescopeRefusal = (before, mintUser, allowMintUserChange) => before === mintU
|
|
|
3237
3290
|
var matches11 = (attributes, props) => attributes.mintUser === props.mintUser && sameTtl5(props.ttl, attributes.ttl) && sameTtl5(props.maxTtl, attributes.maxTtl);
|
|
3238
3291
|
|
|
3239
3292
|
// src/openbao/proxmox-role-wire.ts
|
|
3240
|
-
import * as
|
|
3241
|
-
var readRole3 = (props) =>
|
|
3293
|
+
import * as Effect37 from "effect/Effect";
|
|
3294
|
+
var readRole3 = (props) => Effect37.gen(function* () {
|
|
3242
3295
|
const live = yield* baoRead(rolePath5(props.mount, props.name));
|
|
3243
3296
|
if (live === undefined)
|
|
3244
3297
|
return;
|
|
@@ -3249,16 +3302,16 @@ var readRole3 = (props) => Effect35.gen(function* () {
|
|
|
3249
3302
|
var BaoProxmoxRole = Resource13("Bao.ProxmoxRole", {
|
|
3250
3303
|
defaultRemovalPolicy: "retain"
|
|
3251
3304
|
});
|
|
3252
|
-
var
|
|
3253
|
-
var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole,
|
|
3254
|
-
list: () =>
|
|
3255
|
-
read:
|
|
3305
|
+
var IDENTITY9 = roleIdentity("Bao.ProxmoxRole", rolePath5);
|
|
3306
|
+
var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect38.succeed(BaoProxmoxRole.Provider.of({
|
|
3307
|
+
list: () => Effect38.succeed([]),
|
|
3308
|
+
read: Effect38.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
3256
3309
|
const found = yield* readRole3(olds);
|
|
3257
|
-
const ours =
|
|
3310
|
+
const ours = Effect38.sync(() => found !== undefined && matches11(found, olds));
|
|
3258
3311
|
return yield* ownedRead({ fqn, instanceId, output }, found, ours);
|
|
3259
3312
|
}),
|
|
3260
|
-
diff:
|
|
3261
|
-
const move = yield* judgeRename(
|
|
3313
|
+
diff: Effect38.fn(function* ({ news, olds, output }) {
|
|
3314
|
+
const move = yield* judgeRename(IDENTITY9, olds, news, output);
|
|
3262
3315
|
if (output === undefined)
|
|
3263
3316
|
return;
|
|
3264
3317
|
if (move !== undefined) {
|
|
@@ -3270,7 +3323,7 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect36.su
|
|
|
3270
3323
|
const refusal2 = rescopeRefusal(from, mintUser, allow);
|
|
3271
3324
|
if (refusal2 === undefined)
|
|
3272
3325
|
return { action: "replace" };
|
|
3273
|
-
return yield*
|
|
3326
|
+
return yield* Effect38.die(new Error(`Bao.ProxmoxRole ${move.from} → ${move.to}: the rename ${refusal2}`));
|
|
3274
3327
|
}
|
|
3275
3328
|
if (!isResolved13(news))
|
|
3276
3329
|
return;
|
|
@@ -3281,39 +3334,39 @@ var BaoProxmoxRoleProvider = () => Provider13.effect(BaoProxmoxRole, Effect36.su
|
|
|
3281
3334
|
return { action: "noop" };
|
|
3282
3335
|
return { action: "update" };
|
|
3283
3336
|
}),
|
|
3284
|
-
reconcile:
|
|
3337
|
+
reconcile: Effect38.fn(function* ({ fqn, instanceId, news, output }) {
|
|
3285
3338
|
const path = rolePath5(news.mount, news.name);
|
|
3286
|
-
yield* guardRename(
|
|
3339
|
+
yield* guardRename(IDENTITY9, news, output);
|
|
3287
3340
|
const live = yield* readRole3(news);
|
|
3288
3341
|
if (live !== undefined)
|
|
3289
3342
|
yield* refuseTakeover({ fqn, instanceId, output }, `Bao.ProxmoxRole ${path}`);
|
|
3290
3343
|
const rescope = live === undefined ? undefined : rescopeRefusal(live.mintUser, news.mintUser, news.allowMintUserChange);
|
|
3291
3344
|
if (rescope !== undefined) {
|
|
3292
|
-
return yield*
|
|
3345
|
+
return yield* Effect38.die(new Error(`Bao.ProxmoxRole ${path}: ${rescope}`));
|
|
3293
3346
|
}
|
|
3294
3347
|
if (live === undefined || !matches11(live, news)) {
|
|
3295
|
-
const write =
|
|
3348
|
+
const write = writeBody8(news);
|
|
3296
3349
|
if (!write.ok) {
|
|
3297
|
-
return yield*
|
|
3350
|
+
return yield* Effect38.die(new Error(`Bao.ProxmoxRole ${path}: unparseable duration ` + `${write.bad.join(", ")}. Use 30s / 5m / 1h / 1d, or 0.`));
|
|
3298
3351
|
}
|
|
3299
3352
|
yield* baoWrite("PUT", path, write.body);
|
|
3300
3353
|
}
|
|
3301
3354
|
const after = yield* readRole3(news);
|
|
3302
3355
|
if (after === undefined) {
|
|
3303
|
-
return yield*
|
|
3356
|
+
return yield* Effect38.die(new Error(`Bao.ProxmoxRole ${path}: write returned no error ` + "but the role is still absent."));
|
|
3304
3357
|
}
|
|
3305
3358
|
return after;
|
|
3306
3359
|
}),
|
|
3307
|
-
delete:
|
|
3360
|
+
delete: Effect38.fn(function* ({ output }) {
|
|
3308
3361
|
yield* baoDelete(rolePath5(output.mount, output.name));
|
|
3309
3362
|
return;
|
|
3310
3363
|
})
|
|
3311
|
-
})).pipe(
|
|
3364
|
+
})).pipe(Effect38.map(provingResumes)));
|
|
3312
3365
|
// src/openbao/ssh-role.ts
|
|
3313
3366
|
import { Resource as Resource14 } from "alchemy";
|
|
3314
3367
|
import { isResolved as isResolved14 } from "alchemy/Diff";
|
|
3315
3368
|
import * as Provider14 from "alchemy/Provider";
|
|
3316
|
-
import * as
|
|
3369
|
+
import * as Effect39 from "effect/Effect";
|
|
3317
3370
|
|
|
3318
3371
|
// src/openbao/ssh-role-form.ts
|
|
3319
3372
|
var readPath4 = (mount, name) => `${sshMountOf(mount)}/roles/${name}`;
|
|
@@ -3374,8 +3427,8 @@ var attributesOf14 = (form, live) => {
|
|
|
3374
3427
|
};
|
|
3375
3428
|
return { ...attrs, digest: sha256(JSON.stringify(attrs)) };
|
|
3376
3429
|
};
|
|
3377
|
-
var mapValue = (
|
|
3378
|
-
var
|
|
3430
|
+
var mapValue = (map26) => extMap(map26);
|
|
3431
|
+
var writeBody9 = (form) => ({
|
|
3379
3432
|
key_type: "ca",
|
|
3380
3433
|
allowed_users: form.allowedUsers.join(","),
|
|
3381
3434
|
default_user: form.defaultUser,
|
|
@@ -3427,23 +3480,23 @@ var wouldErase2 = (live) => {
|
|
|
3427
3480
|
var BaoSshRole = Resource14("Bao.SshRole", {
|
|
3428
3481
|
defaultRemovalPolicy: "retain"
|
|
3429
3482
|
});
|
|
3430
|
-
var
|
|
3431
|
-
var readRole4 = (form) =>
|
|
3483
|
+
var IDENTITY10 = roleIdentity("Bao.SshRole", readPath4, "ssh");
|
|
3484
|
+
var readRole4 = (form) => Effect39.gen(function* () {
|
|
3432
3485
|
const live = yield* baoRead(readPath4(form.mount, form.name));
|
|
3433
3486
|
if (live === undefined)
|
|
3434
3487
|
return;
|
|
3435
3488
|
return { attributes: attributesOf14(form, live), live };
|
|
3436
3489
|
});
|
|
3437
|
-
var refuse6 = (message) =>
|
|
3438
|
-
var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole,
|
|
3439
|
-
list: () =>
|
|
3440
|
-
read:
|
|
3490
|
+
var refuse6 = (message) => Effect39.die(new Error(message));
|
|
3491
|
+
var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect39.succeed(BaoSshRole.Provider.of({
|
|
3492
|
+
list: () => Effect39.succeed([]),
|
|
3493
|
+
read: Effect39.fn(function* ({ fqn, instanceId, olds, output }) {
|
|
3441
3494
|
const found = yield* readRole4(resolve2(olds));
|
|
3442
|
-
const ours =
|
|
3495
|
+
const ours = Effect39.sync(() => found !== undefined && matches12(found.attributes, resolve2(olds)));
|
|
3443
3496
|
return yield* ownedRead({ fqn, instanceId, output }, found?.attributes, ours);
|
|
3444
3497
|
}),
|
|
3445
|
-
diff:
|
|
3446
|
-
const move = yield* judgeRename(
|
|
3498
|
+
diff: Effect39.fn(function* ({ news, olds, output }) {
|
|
3499
|
+
const move = yield* judgeRename(IDENTITY10, olds, news, output);
|
|
3447
3500
|
if (output === undefined)
|
|
3448
3501
|
return;
|
|
3449
3502
|
if (move !== undefined)
|
|
@@ -3456,10 +3509,10 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect37.succeed(Ba
|
|
|
3456
3509
|
return { action: "update" };
|
|
3457
3510
|
return matches12(found.attributes, form) ? { action: "noop" } : { action: "update" };
|
|
3458
3511
|
}),
|
|
3459
|
-
reconcile:
|
|
3512
|
+
reconcile: Effect39.fn(function* ({ fqn, instanceId, news, output }) {
|
|
3460
3513
|
const form = resolve2(news);
|
|
3461
3514
|
const path = readPath4(form.mount, form.name);
|
|
3462
|
-
yield* guardRename(
|
|
3515
|
+
yield* guardRename(IDENTITY10, news, output);
|
|
3463
3516
|
const bad = badDurations(form);
|
|
3464
3517
|
if (bad.length > 0) {
|
|
3465
3518
|
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.");
|
|
@@ -3477,7 +3530,7 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect37.succeed(Ba
|
|
|
3477
3530
|
return yield* refuse6(`Bao.SshRole ${path}: live role carries ${lost.join(", ")}, which this ` + "resource does not declare and the full-replace write would ERASE. " + "Fold those settings into the declaration, or clear them by hand first.");
|
|
3478
3531
|
}
|
|
3479
3532
|
}
|
|
3480
|
-
yield* baoWrite("PUT", path,
|
|
3533
|
+
yield* baoWrite("PUT", path, writeBody9(form));
|
|
3481
3534
|
}
|
|
3482
3535
|
const after = yield* readRole4(form);
|
|
3483
3536
|
if (after === undefined) {
|
|
@@ -3485,11 +3538,11 @@ var BaoSshRoleProvider = () => Provider14.effect(BaoSshRole, Effect37.succeed(Ba
|
|
|
3485
3538
|
}
|
|
3486
3539
|
return after.attributes;
|
|
3487
3540
|
}),
|
|
3488
|
-
delete:
|
|
3541
|
+
delete: Effect39.fn(function* ({ output }) {
|
|
3489
3542
|
yield* baoDelete(readPath4(output.mount, output.name));
|
|
3490
3543
|
return;
|
|
3491
3544
|
})
|
|
3492
|
-
})).pipe(
|
|
3545
|
+
})).pipe(Effect39.map(provingResumes)));
|
|
3493
3546
|
export {
|
|
3494
3547
|
BaoAuthMethod,
|
|
3495
3548
|
BaoAuthMethodProvider,
|
|
@@ -3539,5 +3592,5 @@ export {
|
|
|
3539
3592
|
revokeSelfEffect
|
|
3540
3593
|
};
|
|
3541
3594
|
|
|
3542
|
-
//# debugId=
|
|
3595
|
+
//# debugId=C687B72D0BAE7E8D64756E2164756E21
|
|
3543
3596
|
//# sourceMappingURL=index.js.map
|