@stigmer/server 3.24.0 → 3.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/authorization/authorizer.d.ts +10 -4
- package/dist/authorization/authorizer.d.ts.map +1 -1
- package/dist/authorization/authorizer.js +11 -4
- package/dist/authorization/authorizer.js.map +1 -1
- package/dist/authorization/model/index.d.ts +4 -4
- package/dist/authorization/model/index.d.ts.map +1 -1
- package/dist/authorization/model/index.js +2 -0
- package/dist/authorization/model/index.js.map +1 -1
- package/dist/authorization/model/oauth_app.d.ts.map +1 -1
- package/dist/authorization/model/oauth_app.js +3 -2
- package/dist/authorization/model/oauth_app.js.map +1 -1
- package/dist/authorization/model/platform_client.d.ts +2 -0
- package/dist/authorization/model/platform_client.d.ts.map +1 -0
- package/dist/authorization/model/platform_client.js +31 -0
- package/dist/authorization/model/platform_client.js.map +1 -0
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +99 -13
- package/dist/boot/compose.js.map +1 -1
- package/dist/boot/list-indexes.d.ts +3 -0
- package/dist/boot/list-indexes.d.ts.map +1 -0
- package/dist/boot/list-indexes.js +24 -0
- package/dist/boot/list-indexes.js.map +1 -0
- package/dist/boot/route-shadowing.d.ts +25 -0
- package/dist/boot/route-shadowing.d.ts.map +1 -0
- package/dist/boot/route-shadowing.js +17 -0
- package/dist/boot/route-shadowing.js.map +1 -0
- package/dist/domain/agentexecution/controller.d.ts.map +1 -1
- package/dist/domain/agentexecution/controller.js +6 -8
- package/dist/domain/agentexecution/controller.js.map +1 -1
- package/dist/domain/agentexecution/list-index.d.ts +2 -0
- package/dist/domain/agentexecution/list-index.d.ts.map +1 -0
- package/dist/domain/agentexecution/list-index.js +23 -0
- package/dist/domain/agentexecution/list-index.js.map +1 -0
- package/dist/domain/agentexecution/steps.d.ts +17 -33
- package/dist/domain/agentexecution/steps.d.ts.map +1 -1
- package/dist/domain/agentexecution/steps.js +94 -95
- package/dist/domain/agentexecution/steps.js.map +1 -1
- package/dist/domain/agentexecution/usage.d.ts.map +1 -1
- package/dist/domain/agentexecution/usage.js +37 -14
- package/dist/domain/agentexecution/usage.js.map +1 -1
- package/dist/domain/artifact/controller.d.ts.map +1 -1
- package/dist/domain/artifact/controller.js +27 -15
- package/dist/domain/artifact/controller.js.map +1 -1
- package/dist/domain/artifact/list-index.d.ts +2 -0
- package/dist/domain/artifact/list-index.d.ts.map +1 -0
- package/dist/domain/artifact/list-index.js +21 -0
- package/dist/domain/artifact/list-index.js.map +1 -0
- package/dist/domain/iampolicy/membership.d.ts +6 -1
- package/dist/domain/iampolicy/membership.d.ts.map +1 -1
- package/dist/domain/iampolicy/membership.js +8 -2
- package/dist/domain/iampolicy/membership.js.map +1 -1
- package/dist/domain/identityaccount/constants.d.ts +13 -0
- package/dist/domain/identityaccount/constants.d.ts.map +1 -1
- package/dist/domain/identityaccount/constants.js +17 -0
- package/dist/domain/identityaccount/constants.js.map +1 -1
- package/dist/domain/identityaccount/controller.d.ts +3 -1
- package/dist/domain/identityaccount/controller.d.ts.map +1 -1
- package/dist/domain/identityaccount/controller.js +15 -6
- package/dist/domain/identityaccount/controller.js.map +1 -1
- package/dist/domain/identityaccount/operator.d.ts.map +1 -1
- package/dist/domain/identityaccount/operator.js +1 -0
- package/dist/domain/identityaccount/operator.js.map +1 -1
- package/dist/domain/identityaccount/provisioning.d.ts +18 -0
- package/dist/domain/identityaccount/provisioning.d.ts.map +1 -1
- package/dist/domain/identityaccount/provisioning.js +1 -0
- package/dist/domain/identityaccount/provisioning.js.map +1 -1
- package/dist/domain/identityaccount/resource-store.js +9 -5
- package/dist/domain/identityaccount/resource-store.js.map +1 -1
- package/dist/domain/identityaccount/steps.d.ts +11 -2
- package/dist/domain/identityaccount/steps.d.ts.map +1 -1
- package/dist/domain/identityaccount/steps.js +42 -4
- package/dist/domain/identityaccount/steps.js.map +1 -1
- package/dist/domain/identityaccount/store-contract.d.ts.map +1 -1
- package/dist/domain/identityaccount/store-contract.js +33 -0
- package/dist/domain/identityaccount/store-contract.js.map +1 -1
- package/dist/domain/identityaccount/store.d.ts +7 -5
- package/dist/domain/identityaccount/store.d.ts.map +1 -1
- package/dist/domain/identityaccount/store.js.map +1 -1
- package/dist/domain/platform/controller.d.ts +10 -0
- package/dist/domain/platform/controller.d.ts.map +1 -1
- package/dist/domain/platform/controller.js +2 -1
- package/dist/domain/platform/controller.js.map +1 -1
- package/dist/domain/platformclient/constants.d.ts +60 -0
- package/dist/domain/platformclient/constants.d.ts.map +1 -0
- package/dist/domain/platformclient/constants.js +78 -0
- package/dist/domain/platformclient/constants.js.map +1 -0
- package/dist/domain/platformclient/controller.d.ts +59 -0
- package/dist/domain/platformclient/controller.d.ts.map +1 -0
- package/dist/domain/platformclient/controller.js +191 -0
- package/dist/domain/platformclient/controller.js.map +1 -0
- package/dist/domain/platformclient/credentials.d.ts +13 -0
- package/dist/domain/platformclient/credentials.d.ts.map +1 -0
- package/dist/domain/platformclient/credentials.js +56 -0
- package/dist/domain/platformclient/credentials.js.map +1 -0
- package/dist/domain/platformclient/mint.d.ts +23 -0
- package/dist/domain/platformclient/mint.d.ts.map +1 -0
- package/dist/domain/platformclient/mint.js +254 -0
- package/dist/domain/platformclient/mint.js.map +1 -0
- package/dist/domain/platformclient/origin-guard.d.ts +9 -0
- package/dist/domain/platformclient/origin-guard.d.ts.map +1 -0
- package/dist/domain/platformclient/origin-guard.js +81 -0
- package/dist/domain/platformclient/origin-guard.js.map +1 -0
- package/dist/domain/platformclient/resource-store.d.ts +4 -0
- package/dist/domain/platformclient/resource-store.d.ts.map +1 -0
- package/dist/domain/platformclient/resource-store.js +117 -0
- package/dist/domain/platformclient/resource-store.js.map +1 -0
- package/dist/domain/platformclient/steps.d.ts +51 -0
- package/dist/domain/platformclient/steps.d.ts.map +1 -0
- package/dist/domain/platformclient/steps.js +339 -0
- package/dist/domain/platformclient/steps.js.map +1 -0
- package/dist/domain/platformclient/store-contract.d.ts +8 -0
- package/dist/domain/platformclient/store-contract.d.ts.map +1 -0
- package/dist/domain/platformclient/store-contract.js +208 -0
- package/dist/domain/platformclient/store-contract.js.map +1 -0
- package/dist/domain/platformclient/store.d.ts +58 -0
- package/dist/domain/platformclient/store.d.ts.map +1 -0
- package/dist/domain/platformclient/store.js +13 -0
- package/dist/domain/platformclient/store.js.map +1 -0
- package/dist/domain/platformclient/system-managed.d.ts +18 -0
- package/dist/domain/platformclient/system-managed.d.ts.map +1 -0
- package/dist/domain/platformclient/system-managed.js +80 -0
- package/dist/domain/platformclient/system-managed.js.map +1 -0
- package/dist/domain/platformclient/token-controller.d.ts +11 -0
- package/dist/domain/platformclient/token-controller.d.ts.map +1 -0
- package/dist/domain/platformclient/token-controller.js +32 -0
- package/dist/domain/platformclient/token-controller.js.map +1 -0
- package/dist/domain/platformclient/verifier.d.ts +10 -0
- package/dist/domain/platformclient/verifier.d.ts.map +1 -0
- package/dist/domain/platformclient/verifier.js +76 -0
- package/dist/domain/platformclient/verifier.js.map +1 -0
- package/dist/domain/session/list-index.d.ts +4 -0
- package/dist/domain/session/list-index.d.ts.map +1 -0
- package/dist/domain/session/list-index.js +26 -0
- package/dist/domain/session/list-index.js.map +1 -0
- package/dist/domain/session/steps.d.ts +7 -8
- package/dist/domain/session/steps.d.ts.map +1 -1
- package/dist/domain/session/steps.js +76 -78
- package/dist/domain/session/steps.js.map +1 -1
- package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
- package/dist/domain/workflowexecution/controller.js +53 -55
- package/dist/domain/workflowexecution/controller.js.map +1 -1
- package/dist/domain/workflowexecution/execution-filter.d.ts +4 -0
- package/dist/domain/workflowexecution/execution-filter.d.ts.map +1 -1
- package/dist/domain/workflowexecution/execution-filter.js +11 -5
- package/dist/domain/workflowexecution/execution-filter.js.map +1 -1
- package/dist/domain/workflowexecution/get-execution-summary.d.ts.map +1 -1
- package/dist/domain/workflowexecution/get-execution-summary.js +23 -17
- package/dist/domain/workflowexecution/get-execution-summary.js.map +1 -1
- package/dist/domain/workflowexecution/list-index.d.ts +2 -0
- package/dist/domain/workflowexecution/list-index.d.ts.map +1 -0
- package/dist/domain/workflowexecution/list-index.js +21 -0
- package/dist/domain/workflowexecution/list-index.js.map +1 -0
- package/dist/domain/workflowexecution/list-pending-approvals.d.ts.map +1 -1
- package/dist/domain/workflowexecution/list-pending-approvals.js +69 -32
- package/dist/domain/workflowexecution/list-pending-approvals.js.map +1 -1
- package/dist/domain/workflowexecution/queries.d.ts +30 -4
- package/dist/domain/workflowexecution/queries.d.ts.map +1 -1
- package/dist/domain/workflowexecution/queries.js +76 -22
- package/dist/domain/workflowexecution/queries.js.map +1 -1
- package/dist/encryption/key-manager.d.ts +20 -3
- package/dist/encryption/key-manager.d.ts.map +1 -1
- package/dist/encryption/key-manager.js +64 -42
- package/dist/encryption/key-manager.js.map +1 -1
- package/dist/extensions/caller-guards.d.ts +8 -3
- package/dist/extensions/caller-guards.d.ts.map +1 -1
- package/dist/extensions/drivers.d.ts +37 -0
- package/dist/extensions/drivers.d.ts.map +1 -1
- package/dist/extensions/guest-token-minting.d.ts +26 -0
- package/dist/extensions/guest-token-minting.d.ts.map +1 -0
- package/dist/extensions/guest-token-minting.js +2 -0
- package/dist/extensions/guest-token-minting.js.map +1 -0
- package/dist/extensions/identity.d.ts +6 -4
- package/dist/extensions/identity.d.ts.map +1 -1
- package/dist/extensions/identity.js.map +1 -1
- package/dist/extensions/list-read-scope.d.ts +9 -12
- package/dist/extensions/list-read-scope.d.ts.map +1 -1
- package/dist/extensions/list-read-scope.js.map +1 -1
- package/dist/extensions/registry.d.ts +30 -1
- package/dist/extensions/registry.d.ts.map +1 -1
- package/dist/extensions/registry.js +34 -1
- package/dist/extensions/registry.js.map +1 -1
- package/dist/index.d.ts +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/pipeline/interceptors/auth.d.ts +14 -0
- package/dist/pipeline/interceptors/auth.d.ts.map +1 -1
- package/dist/pipeline/interceptors/auth.js +24 -0
- package/dist/pipeline/interceptors/auth.js.map +1 -1
- package/dist/pipeline/steps/build-update-state.d.ts +11 -1
- package/dist/pipeline/steps/build-update-state.d.ts.map +1 -1
- package/dist/pipeline/steps/build-update-state.js +5 -2
- package/dist/pipeline/steps/build-update-state.js.map +1 -1
- package/dist/pipeline/steps/list-page.d.ts +63 -0
- package/dist/pipeline/steps/list-page.d.ts.map +1 -0
- package/dist/pipeline/steps/list-page.js +187 -0
- package/dist/pipeline/steps/list-page.js.map +1 -0
- package/dist/platformtoken/envelope.d.ts +100 -0
- package/dist/platformtoken/envelope.d.ts.map +1 -0
- package/dist/platformtoken/envelope.js +184 -0
- package/dist/platformtoken/envelope.js.map +1 -0
- package/dist/platformtoken/key-ring.d.ts +85 -0
- package/dist/platformtoken/key-ring.d.ts.map +1 -0
- package/dist/platformtoken/key-ring.js +164 -0
- package/dist/platformtoken/key-ring.js.map +1 -0
- package/dist/query/activity/handler.d.ts +6 -7
- package/dist/query/activity/handler.d.ts.map +1 -1
- package/dist/query/activity/handler.js +42 -59
- package/dist/query/activity/handler.js.map +1 -1
- package/dist/store/interface.d.ts +29 -0
- package/dist/store/interface.d.ts.map +1 -1
- package/dist/store/interface.js.map +1 -1
- package/dist/store/list-index.d.ts +123 -0
- package/dist/store/list-index.d.ts.map +1 -0
- package/dist/store/list-index.js +277 -0
- package/dist/store/list-index.js.map +1 -0
- package/dist/store/logger.d.ts +3 -0
- package/dist/store/logger.d.ts.map +1 -1
- package/dist/store/logger.js +5 -1
- package/dist/store/logger.js.map +1 -1
- package/dist/store/postgres/migrations.d.ts +10 -6
- package/dist/store/postgres/migrations.d.ts.map +1 -1
- package/dist/store/postgres/migrations.js +64 -6
- package/dist/store/postgres/migrations.js.map +1 -1
- package/dist/store/postgres/store.d.ts +26 -5
- package/dist/store/postgres/store.d.ts.map +1 -1
- package/dist/store/postgres/store.js +377 -22
- package/dist/store/postgres/store.js.map +1 -1
- package/dist/store/sqlite/migrations.d.ts +11 -5
- package/dist/store/sqlite/migrations.d.ts.map +1 -1
- package/dist/store/sqlite/migrations.js +50 -4
- package/dist/store/sqlite/migrations.js.map +1 -1
- package/dist/store/sqlite/store.d.ts +18 -3
- package/dist/store/sqlite/store.d.ts.map +1 -1
- package/dist/store/sqlite/store.js +321 -15
- package/dist/store/sqlite/store.js.map +1 -1
- package/package.json +6 -6
- package/src/authorization/README.md +1 -1
- package/src/authorization/__tests__/authorizer.test.ts +6 -2
- package/src/authorization/__tests__/drivers.ts +6 -1
- package/src/authorization/__tests__/wire-permissions.test.ts +1 -0
- package/src/authorization/authorizer.ts +11 -4
- package/src/authorization/model/__tests__/registry.test.ts +8 -1
- package/src/authorization/model/index.ts +6 -4
- package/src/authorization/model/oauth_app.ts +3 -2
- package/src/authorization/model/platform_client.ts +43 -0
- package/src/boot/__tests__/auth-enabled-composition.test.ts +2 -1
- package/src/boot/__tests__/list-indexes.test.ts +65 -0
- package/src/boot/__tests__/route-shadowing.test.ts +67 -0
- package/src/boot/compose.ts +113 -18
- package/src/boot/list-indexes.ts +25 -0
- package/src/boot/route-shadowing.ts +47 -0
- package/src/domain/agentexecution/__tests__/agentexecution.test.ts +85 -3
- package/src/domain/agentexecution/controller.ts +8 -10
- package/src/domain/agentexecution/list-index.ts +24 -0
- package/src/domain/agentexecution/steps.ts +118 -115
- package/src/domain/agentexecution/usage.ts +38 -17
- package/src/domain/artifact/controller.ts +28 -18
- package/src/domain/artifact/list-index.ts +22 -0
- package/src/domain/iampolicy/__tests__/membership.test.ts +7 -0
- package/src/domain/iampolicy/membership.ts +8 -2
- package/src/domain/identityaccount/__tests__/platform-client-accounts.test.ts +124 -0
- package/src/domain/identityaccount/__tests__/resource-store.test.ts +1 -0
- package/src/domain/identityaccount/constants.ts +20 -0
- package/src/domain/identityaccount/controller.ts +16 -4
- package/src/domain/identityaccount/operator.ts +1 -0
- package/src/domain/identityaccount/provisioning.ts +17 -0
- package/src/domain/identityaccount/resource-store.ts +9 -5
- package/src/domain/identityaccount/steps.ts +58 -3
- package/src/domain/identityaccount/store-contract.ts +51 -0
- package/src/domain/identityaccount/store.ts +7 -5
- package/src/domain/platform/__tests__/platform.test.ts +7 -1
- package/src/domain/platform/controller.ts +12 -1
- package/src/domain/platformclient/__tests__/controller.test.ts +397 -0
- package/src/domain/platformclient/__tests__/credentials.test.ts +46 -0
- package/src/domain/platformclient/__tests__/mint.test.ts +415 -0
- package/src/domain/platformclient/__tests__/resource-store.test.ts +140 -0
- package/src/domain/platformclient/__tests__/system-managed.test.ts +101 -0
- package/src/domain/platformclient/__tests__/verifier-and-guard.test.ts +207 -0
- package/src/domain/platformclient/constants.ts +120 -0
- package/src/domain/platformclient/controller.ts +449 -0
- package/src/domain/platformclient/credentials.ts +68 -0
- package/src/domain/platformclient/mint.ts +412 -0
- package/src/domain/platformclient/origin-guard.ts +117 -0
- package/src/domain/platformclient/resource-store.ts +150 -0
- package/src/domain/platformclient/steps.ts +472 -0
- package/src/domain/platformclient/store-contract.ts +318 -0
- package/src/domain/platformclient/store.ts +63 -0
- package/src/domain/platformclient/system-managed.ts +115 -0
- package/src/domain/platformclient/token-controller.ts +49 -0
- package/src/domain/platformclient/verifier.ts +106 -0
- package/src/domain/session/list-index.ts +28 -0
- package/src/domain/session/steps.ts +108 -123
- package/src/domain/workflowexecution/__tests__/list-read-scope-summaries.test.ts +155 -99
- package/src/domain/workflowexecution/__tests__/workflowexecution.test.ts +193 -31
- package/src/domain/workflowexecution/controller.ts +54 -82
- package/src/domain/workflowexecution/execution-filter.ts +20 -7
- package/src/domain/workflowexecution/get-execution-summary.ts +31 -24
- package/src/domain/workflowexecution/list-index.ts +22 -0
- package/src/domain/workflowexecution/list-pending-approvals.ts +82 -25
- package/src/domain/workflowexecution/queries.ts +134 -23
- package/src/encryption/key-manager.ts +87 -44
- package/src/extensions/__tests__/extension-composition.test.ts +3 -2
- package/src/extensions/__tests__/platform-client-composed.test.ts +288 -0
- package/src/extensions/__tests__/registry.test.ts +4 -1
- package/src/extensions/__tests__/tier-truthfulness.test.ts +8 -0
- package/src/extensions/caller-guards.ts +8 -3
- package/src/extensions/drivers.ts +37 -0
- package/src/extensions/guest-token-minting.ts +32 -0
- package/src/extensions/identity.ts +6 -4
- package/src/extensions/list-read-scope.ts +9 -12
- package/src/extensions/registry.ts +77 -3
- package/src/index.ts +65 -1
- package/src/pipeline/interceptors/auth.ts +27 -0
- package/src/pipeline/steps/__tests__/list-page.test.ts +186 -0
- package/src/pipeline/steps/__tests__/references.test.ts +2 -0
- package/src/pipeline/steps/build-update-state.ts +5 -2
- package/src/pipeline/steps/list-page.ts +284 -0
- package/src/platformtoken/__tests__/envelope.test.ts +277 -0
- package/src/platformtoken/__tests__/key-ring.test.ts +205 -0
- package/src/platformtoken/envelope.ts +276 -0
- package/src/platformtoken/key-ring.ts +266 -0
- package/src/query/activity/handler.ts +57 -78
- package/src/runnerauth/__tests__/runner-subject-composed.test.ts +9 -3
- package/src/store/README.md +51 -32
- package/src/store/__tests__/list-index.measure.test.ts +293 -0
- package/src/store/__tests__/list-index.test.ts +328 -0
- package/src/store/__tests__/store-contract.ts +346 -3
- package/src/store/interface.ts +39 -0
- package/src/store/list-index.ts +465 -0
- package/src/store/logger.ts +8 -1
- package/src/store/postgres/__tests__/list-index-repair.test.ts +133 -0
- package/src/store/postgres/__tests__/migrations.test.ts +27 -19
- package/src/store/postgres/__tests__/store-contract.test.ts +50 -3
- package/src/store/postgres/migrations.ts +69 -7
- package/src/store/postgres/store.ts +485 -29
- package/src/store/sqlite/__tests__/migrations.test.ts +51 -7
- package/src/store/sqlite/__tests__/store-contract.test.ts +70 -16
- package/src/store/sqlite/__tests__/support.ts +12 -3
- package/src/store/sqlite/migrations.ts +57 -6
- package/src/store/sqlite/store.ts +462 -21
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins the platform-token envelope against the cloud verifier's semantics,
|
|
3
|
+
* which every token in the field was accepted under:
|
|
4
|
+
* - a signed token round-trips with the envelope's claims and the lane's;
|
|
5
|
+
* - a lane's own lifetime replaces the ring's default, and the expiry the
|
|
6
|
+
* signer returns is the instant the `exp` claim names;
|
|
7
|
+
* - a token signed by the previous key still verifies (the rotation
|
|
8
|
+
* window), and the header's kid never selects a key;
|
|
9
|
+
* - the forgeries a JWT verifier must refuse are refused as a bad
|
|
10
|
+
* signature: `alg: none`, and an HMAC token keyed with the public key;
|
|
11
|
+
* - expiry is strict (no leeway), a missing `aud` is tolerated, a wrong
|
|
12
|
+
* one refused, and a missing `sub` refused — each with its pinned copy;
|
|
13
|
+
* - anything that is not a three-part `iss: "stigmer"` JWT is foreign,
|
|
14
|
+
* never refused, so the next verifier judges it;
|
|
15
|
+
* - a lane cannot set a claim the envelope owns.
|
|
16
|
+
*/
|
|
17
|
+
import { createHmac, generateKeyPairSync } from "node:crypto";
|
|
18
|
+
|
|
19
|
+
import { Code } from "@connectrpc/connect";
|
|
20
|
+
import { describe, expect, it } from "vitest";
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
PLATFORM_TOKEN_REFUSAL_MESSAGES,
|
|
24
|
+
decodeVerifiedPlatformTokenPayload,
|
|
25
|
+
platformTokenRefusalError,
|
|
26
|
+
signPlatformToken,
|
|
27
|
+
verifyPlatformToken,
|
|
28
|
+
} from "../envelope.js";
|
|
29
|
+
import { platformTokenKeyRingFromPem } from "../key-ring.js";
|
|
30
|
+
import type { SigningPlatformTokenKeyRing } from "../key-ring.js";
|
|
31
|
+
|
|
32
|
+
function pemPair(): { privateKeyPem: string; publicKeyPem: string } {
|
|
33
|
+
const { privateKey, publicKey } = generateKeyPairSync("rsa", {
|
|
34
|
+
modulusLength: 2048,
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
privateKeyPem: privateKey
|
|
38
|
+
.export({ format: "pem", type: "pkcs8" })
|
|
39
|
+
.toString(),
|
|
40
|
+
publicKeyPem: publicKey.export({ format: "pem", type: "spki" }).toString(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const active = pemPair();
|
|
45
|
+
const previous = pemPair();
|
|
46
|
+
|
|
47
|
+
function signingRing(
|
|
48
|
+
options: {
|
|
49
|
+
pair?: { privateKeyPem: string; publicKeyPem: string };
|
|
50
|
+
audience?: string;
|
|
51
|
+
ttlSeconds?: number;
|
|
52
|
+
} = {},
|
|
53
|
+
): SigningPlatformTokenKeyRing {
|
|
54
|
+
const pair = options.pair ?? active;
|
|
55
|
+
const ring = platformTokenKeyRingFromPem({
|
|
56
|
+
privateKeyPem: pair.privateKeyPem,
|
|
57
|
+
kid: "stigmer-signing-key-1",
|
|
58
|
+
publicKeyPems: [pair.publicKeyPem],
|
|
59
|
+
audience: options.audience ?? "",
|
|
60
|
+
ttlSeconds: options.ttlSeconds ?? 900,
|
|
61
|
+
});
|
|
62
|
+
if (ring.signer === undefined) throw new Error("fixture ring must sign");
|
|
63
|
+
return { ...ring, signer: ring.signer };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const NOW = new Date("2026-09-23T10:00:00Z");
|
|
67
|
+
|
|
68
|
+
function base64UrlJson(value: object): string {
|
|
69
|
+
return Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
describe("the platform-token envelope", () => {
|
|
73
|
+
it("round-trips a signed token: the envelope's claims, then the lane's", () => {
|
|
74
|
+
const ring = signingRing({ audience: "https://api.stigmer.ai" });
|
|
75
|
+
const token = signPlatformToken(
|
|
76
|
+
ring,
|
|
77
|
+
{ sub: "ida_1", platform_client_id: "pcl_1" },
|
|
78
|
+
{ now: NOW },
|
|
79
|
+
).token;
|
|
80
|
+
|
|
81
|
+
const result = verifyPlatformToken(ring, token, NOW);
|
|
82
|
+
expect(result.outcome).toBe("verified");
|
|
83
|
+
if (result.outcome !== "verified") return;
|
|
84
|
+
expect(result.token.subject).toBe("ida_1");
|
|
85
|
+
expect(result.token.tokenType).toBeUndefined();
|
|
86
|
+
expect(result.token.payload).toMatchObject({
|
|
87
|
+
iss: "stigmer",
|
|
88
|
+
iat: NOW.getTime() / 1000,
|
|
89
|
+
exp: NOW.getTime() / 1000 + 900,
|
|
90
|
+
aud: "https://api.stigmer.ai",
|
|
91
|
+
platform_client_id: "pcl_1",
|
|
92
|
+
});
|
|
93
|
+
const header = JSON.parse(
|
|
94
|
+
Buffer.from(token.split(".")[0] ?? "", "base64url").toString(),
|
|
95
|
+
);
|
|
96
|
+
expect(header).toEqual({
|
|
97
|
+
alg: "RS256",
|
|
98
|
+
typ: "JWT",
|
|
99
|
+
kid: "stigmer-signing-key-1",
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("signs with the lane's own lifetime when it names one, and returns the expiry the token carries", () => {
|
|
104
|
+
const ring = signingRing({ ttlSeconds: 900 });
|
|
105
|
+
|
|
106
|
+
const byDefault = signPlatformToken(ring, { sub: "ida_1" }, { now: NOW });
|
|
107
|
+
expect(byDefault.expiresAt).toEqual(new Date(NOW.getTime() + 900_000));
|
|
108
|
+
|
|
109
|
+
const sandbox = signPlatformToken(
|
|
110
|
+
ring,
|
|
111
|
+
{ sub: "ida_1", token_type: "sandbox" },
|
|
112
|
+
{ now: NOW, ttlSeconds: 14_400 },
|
|
113
|
+
);
|
|
114
|
+
expect(sandbox.expiresAt).toEqual(new Date(NOW.getTime() + 14_400_000));
|
|
115
|
+
const verified = verifyPlatformToken(ring, sandbox.token, NOW);
|
|
116
|
+
expect(verified.outcome === "verified" && verified.token.payload.exp).toBe(
|
|
117
|
+
sandbox.expiresAt.getTime() / 1000,
|
|
118
|
+
);
|
|
119
|
+
expect(
|
|
120
|
+
verifyPlatformToken(
|
|
121
|
+
ring,
|
|
122
|
+
sandbox.token,
|
|
123
|
+
new Date(NOW.getTime() + 900_000),
|
|
124
|
+
).outcome,
|
|
125
|
+
).toBe("verified");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("refuses a lifetime that is not a positive whole number of seconds", () => {
|
|
129
|
+
for (const ttlSeconds of [0, -1, 1.5, Number.NaN]) {
|
|
130
|
+
expect(() =>
|
|
131
|
+
signPlatformToken(signingRing(), { sub: "ida_1" }, { ttlSeconds }),
|
|
132
|
+
).toThrow(/positive integer number of seconds/);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("reads token_type as the lane discriminator", () => {
|
|
137
|
+
const ring = signingRing();
|
|
138
|
+
const token = signPlatformToken(
|
|
139
|
+
ring,
|
|
140
|
+
{ sub: "ida_guest", token_type: "guest" },
|
|
141
|
+
{ now: NOW },
|
|
142
|
+
).token;
|
|
143
|
+
const result = verifyPlatformToken(ring, token, NOW);
|
|
144
|
+
expect(result.outcome === "verified" && result.token.tokenType).toBe(
|
|
145
|
+
"guest",
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("verifies a token signed by the previous key while it is still accepted, whatever the kid says", () => {
|
|
150
|
+
const old = signPlatformToken(
|
|
151
|
+
signingRing({ pair: previous }),
|
|
152
|
+
{ sub: "ida_1" },
|
|
153
|
+
{ now: NOW },
|
|
154
|
+
).token;
|
|
155
|
+
const ring = platformTokenKeyRingFromPem({
|
|
156
|
+
privateKeyPem: active.privateKeyPem,
|
|
157
|
+
kid: "stigmer-signing-key-1",
|
|
158
|
+
publicKeyPems: [active.publicKeyPem, previous.publicKeyPem],
|
|
159
|
+
});
|
|
160
|
+
expect(verifyPlatformToken(ring, old, NOW).outcome).toBe("verified");
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("refuses `alg: none` and an HMAC token keyed with the public key as a bad signature", () => {
|
|
164
|
+
const ring = signingRing();
|
|
165
|
+
const payload = base64UrlJson({
|
|
166
|
+
iss: "stigmer",
|
|
167
|
+
sub: "ida_1",
|
|
168
|
+
exp: NOW.getTime() / 1000 + 60,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const unsigned = `${base64UrlJson({ alg: "none", typ: "JWT" })}.${payload}.`;
|
|
172
|
+
expect(verifyPlatformToken(ring, unsigned, NOW)).toEqual({
|
|
173
|
+
outcome: "refused",
|
|
174
|
+
refusal: "signature",
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const hmacHeader = base64UrlJson({ alg: "HS256", typ: "JWT" });
|
|
178
|
+
const forged = createHmac("sha256", active.publicKeyPem)
|
|
179
|
+
.update(`${hmacHeader}.${payload}`)
|
|
180
|
+
.digest("base64url");
|
|
181
|
+
expect(
|
|
182
|
+
verifyPlatformToken(ring, `${hmacHeader}.${payload}.${forged}`, NOW),
|
|
183
|
+
).toEqual({
|
|
184
|
+
outcome: "refused",
|
|
185
|
+
refusal: "signature",
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it("refuses a token signed by a key the ring does not hold", () => {
|
|
190
|
+
const stranger = signPlatformToken(
|
|
191
|
+
signingRing({ pair: pemPair() }),
|
|
192
|
+
{ sub: "ida_1" },
|
|
193
|
+
{ now: NOW },
|
|
194
|
+
).token;
|
|
195
|
+
expect(verifyPlatformToken(signingRing(), stranger, NOW)).toEqual({
|
|
196
|
+
outcome: "refused",
|
|
197
|
+
refusal: "signature",
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("refuses an expired token strictly, with no leeway", () => {
|
|
202
|
+
const ring = signingRing({ ttlSeconds: 60 });
|
|
203
|
+
const token = signPlatformToken(ring, { sub: "ida_1" }, { now: NOW }).token;
|
|
204
|
+
const atExpiry = new Date(NOW.getTime() + 60_000);
|
|
205
|
+
expect(verifyPlatformToken(ring, token, atExpiry)).toEqual({
|
|
206
|
+
outcome: "refused",
|
|
207
|
+
refusal: "expired",
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("tolerates a missing aud and refuses one that names another audience", () => {
|
|
212
|
+
const noAudience = signPlatformToken(
|
|
213
|
+
signingRing(),
|
|
214
|
+
{ sub: "ida_1" },
|
|
215
|
+
{ now: NOW },
|
|
216
|
+
).token;
|
|
217
|
+
const expecting = signingRing({ audience: "https://api.stigmer.ai" });
|
|
218
|
+
expect(verifyPlatformToken(expecting, noAudience, NOW).outcome).toBe(
|
|
219
|
+
"verified",
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
const elsewhere = signPlatformToken(
|
|
223
|
+
signingRing({ audience: "https://staging.stigmer.ai" }),
|
|
224
|
+
{ sub: "ida_1" },
|
|
225
|
+
{ now: NOW },
|
|
226
|
+
).token;
|
|
227
|
+
expect(verifyPlatformToken(expecting, elsewhere, NOW)).toEqual({
|
|
228
|
+
outcome: "refused",
|
|
229
|
+
refusal: "audience",
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("refuses a token with no subject", () => {
|
|
234
|
+
const ring = signingRing();
|
|
235
|
+
const token = signPlatformToken(
|
|
236
|
+
ring,
|
|
237
|
+
{ platform_client_id: "pcl_1" },
|
|
238
|
+
{ now: NOW },
|
|
239
|
+
).token;
|
|
240
|
+
expect(verifyPlatformToken(ring, token, NOW)).toEqual({
|
|
241
|
+
outcome: "refused",
|
|
242
|
+
refusal: "subject",
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("answers foreign for anything that is not a stigmer-issued three-part JWT", () => {
|
|
247
|
+
const ring = signingRing();
|
|
248
|
+
expect(verifyPlatformToken(ring, "stk_an_api_key", NOW).outcome).toBe(
|
|
249
|
+
"foreign",
|
|
250
|
+
);
|
|
251
|
+
expect(verifyPlatformToken(ring, "a.b", NOW).outcome).toBe("foreign");
|
|
252
|
+
const otherIssuer = `${base64UrlJson({ alg: "RS256" })}.${base64UrlJson({ iss: "https://issuer.example", sub: "x" })}.sig`;
|
|
253
|
+
expect(verifyPlatformToken(ring, otherIssuer, NOW).outcome).toBe("foreign");
|
|
254
|
+
expect(decodeVerifiedPlatformTokenPayload(otherIssuer)).toBeUndefined();
|
|
255
|
+
expect(decodeVerifiedPlatformTokenPayload("")).toBeUndefined();
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("refuses a lane claim that collides with an envelope claim", () => {
|
|
259
|
+
expect(
|
|
260
|
+
() =>
|
|
261
|
+
signPlatformToken(signingRing(), { sub: "ida_1", exp: 1 }, { now: NOW })
|
|
262
|
+
.token,
|
|
263
|
+
).toThrow(/belongs to the envelope/);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("maps every refusal to UNAUTHENTICATED with the cloud verifier's copy", () => {
|
|
267
|
+
expect(PLATFORM_TOKEN_REFUSAL_MESSAGES).toEqual({
|
|
268
|
+
signature: "platform token signature verification failed",
|
|
269
|
+
expired: "platform token is expired",
|
|
270
|
+
audience: "platform token was minted for another environment",
|
|
271
|
+
subject: "platform token carries no subject",
|
|
272
|
+
});
|
|
273
|
+
const error = platformTokenRefusalError("expired");
|
|
274
|
+
expect(error.code).toBe(Code.Unauthenticated);
|
|
275
|
+
expect(error.rawMessage).toBe("platform token is expired");
|
|
276
|
+
});
|
|
277
|
+
});
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins the platform-token key ring:
|
|
3
|
+
* - a composition's ring from PEM refuses at build time what would fail
|
|
4
|
+
* quietly later: no public key, a non-RSA or undersized key, a private
|
|
5
|
+
* key whose public half no verification key matches, a bad TTL; a ring
|
|
6
|
+
* without a private key verifies and never signs;
|
|
7
|
+
* - open source's ring rides the key-manager ladder under its rules: the
|
|
8
|
+
* env key wins, an unusable env key is a throw, a generated key is
|
|
9
|
+
* persisted 0600 and reused, a file the codec refuses is replaced;
|
|
10
|
+
* - the four arms of resolvePlatformTokenKeys: no posture, a supplied
|
|
11
|
+
* ring, open source's own, and the refusal for any other edition.
|
|
12
|
+
*/
|
|
13
|
+
import { generateKeyPairSync } from "node:crypto";
|
|
14
|
+
import fs from "node:fs";
|
|
15
|
+
import os from "node:os";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
|
|
18
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
19
|
+
|
|
20
|
+
import { ServerEdition } from "@stigmer/protos/ai/stigmer/platform/v1/server_info_pb";
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
PLATFORM_TOKEN_KEY_ENV_VAR,
|
|
24
|
+
PLATFORM_TOKEN_KEY_FILE_NAME,
|
|
25
|
+
canSign,
|
|
26
|
+
openSourcePlatformTokenKeyRing,
|
|
27
|
+
platformTokenKeyRingFromPem,
|
|
28
|
+
resolvePlatformTokenKeys,
|
|
29
|
+
} from "../key-ring.js";
|
|
30
|
+
import { signPlatformToken, verifyPlatformToken } from "../envelope.js";
|
|
31
|
+
|
|
32
|
+
function rsaPem(bits = 2048): { privateKeyPem: string; publicKeyPem: string } {
|
|
33
|
+
const { privateKey, publicKey } = generateKeyPairSync("rsa", {
|
|
34
|
+
modulusLength: bits,
|
|
35
|
+
});
|
|
36
|
+
return {
|
|
37
|
+
privateKeyPem: privateKey
|
|
38
|
+
.export({ format: "pem", type: "pkcs8" })
|
|
39
|
+
.toString(),
|
|
40
|
+
publicKeyPem: publicKey.export({ format: "pem", type: "spki" }).toString(),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const pair = rsaPem();
|
|
45
|
+
const homes: string[] = [];
|
|
46
|
+
|
|
47
|
+
function tempHome(): string {
|
|
48
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), "platform-token-"));
|
|
49
|
+
homes.push(home);
|
|
50
|
+
return home;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
afterEach(() => {
|
|
54
|
+
for (const home of homes.splice(0)) {
|
|
55
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("platformTokenKeyRingFromPem", () => {
|
|
60
|
+
it("builds a signing ring whose tokens verify, and a verify-only ring without a private key", () => {
|
|
61
|
+
const ring = platformTokenKeyRingFromPem({
|
|
62
|
+
privateKeyPem: pair.privateKeyPem,
|
|
63
|
+
publicKeyPems: [pair.publicKeyPem],
|
|
64
|
+
});
|
|
65
|
+
expect(canSign(ring)).toBe(true);
|
|
66
|
+
if (!canSign(ring)) return;
|
|
67
|
+
const token = signPlatformToken(ring, { sub: "ida_1" }).token;
|
|
68
|
+
|
|
69
|
+
const verifyOnly = platformTokenKeyRingFromPem({
|
|
70
|
+
publicKeyPems: [pair.publicKeyPem],
|
|
71
|
+
});
|
|
72
|
+
expect(canSign(verifyOnly)).toBe(false);
|
|
73
|
+
expect(verifyPlatformToken(verifyOnly, token).outcome).toBe("verified");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("refuses an empty verification set, a non-RSA key, an undersized key and a bad TTL", () => {
|
|
77
|
+
expect(() => platformTokenKeyRingFromPem({ publicKeyPems: [] })).toThrow(
|
|
78
|
+
/at least one public key/,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const ec = generateKeyPairSync("ec", { namedCurve: "P-256" })
|
|
82
|
+
.publicKey.export({ format: "pem", type: "spki" })
|
|
83
|
+
.toString();
|
|
84
|
+
expect(() => platformTokenKeyRingFromPem({ publicKeyPems: [ec] })).toThrow(
|
|
85
|
+
/must be an RSA key/,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
const small = rsaPem(1024);
|
|
89
|
+
expect(() =>
|
|
90
|
+
platformTokenKeyRingFromPem({ publicKeyPems: [small.publicKeyPem] }),
|
|
91
|
+
).toThrow(/at least 2048 bits/);
|
|
92
|
+
|
|
93
|
+
expect(() =>
|
|
94
|
+
platformTokenKeyRingFromPem({
|
|
95
|
+
publicKeyPems: [pair.publicKeyPem],
|
|
96
|
+
ttlSeconds: 0,
|
|
97
|
+
}),
|
|
98
|
+
).toThrow(/positive integer/);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("refuses a private key whose public half is not among the verification keys", () => {
|
|
102
|
+
expect(() =>
|
|
103
|
+
platformTokenKeyRingFromPem({
|
|
104
|
+
privateKeyPem: pair.privateKeyPem,
|
|
105
|
+
publicKeyPems: [rsaPem().publicKeyPem],
|
|
106
|
+
}),
|
|
107
|
+
).toThrow(/would verify nowhere/);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe("openSourcePlatformTokenKeyRing (the key-manager ladder)", () => {
|
|
112
|
+
it("uses the env key when set, and refuses an env value that is not an RSA private key", () => {
|
|
113
|
+
const env = {
|
|
114
|
+
[PLATFORM_TOKEN_KEY_ENV_VAR]: Buffer.from(pair.privateKeyPem).toString(
|
|
115
|
+
"base64",
|
|
116
|
+
),
|
|
117
|
+
};
|
|
118
|
+
const ring = openSourcePlatformTokenKeyRing({ env, homeDir: tempHome() });
|
|
119
|
+
const token = signPlatformToken(ring, { sub: "ida_1" }).token;
|
|
120
|
+
const expected = platformTokenKeyRingFromPem({
|
|
121
|
+
publicKeyPems: [pair.publicKeyPem],
|
|
122
|
+
});
|
|
123
|
+
expect(verifyPlatformToken(expected, token).outcome).toBe("verified");
|
|
124
|
+
|
|
125
|
+
expect(() =>
|
|
126
|
+
openSourcePlatformTokenKeyRing({
|
|
127
|
+
env: {
|
|
128
|
+
[PLATFORM_TOKEN_KEY_ENV_VAR]:
|
|
129
|
+
Buffer.from("not a key").toString("base64"),
|
|
130
|
+
},
|
|
131
|
+
homeDir: tempHome(),
|
|
132
|
+
}),
|
|
133
|
+
).toThrow(PLATFORM_TOKEN_KEY_ENV_VAR);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it("generates a key once, persists it 0600, and signs with the same key on the next boot", () => {
|
|
137
|
+
const home = tempHome();
|
|
138
|
+
const first = openSourcePlatformTokenKeyRing({ env: {}, homeDir: home });
|
|
139
|
+
const file = path.join(home, ".stigmer", PLATFORM_TOKEN_KEY_FILE_NAME);
|
|
140
|
+
expect(fs.existsSync(file)).toBe(true);
|
|
141
|
+
if (process.platform !== "win32") {
|
|
142
|
+
expect(fs.statSync(file).mode & 0o777).toBe(0o600);
|
|
143
|
+
}
|
|
144
|
+
const second = openSourcePlatformTokenKeyRing({ env: {}, homeDir: home });
|
|
145
|
+
expect(second.signer.kid).toBe(first.signer.kid);
|
|
146
|
+
const token = signPlatformToken(first, { sub: "ida_1" }).token;
|
|
147
|
+
expect(verifyPlatformToken(second, token).outcome).toBe("verified");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("replaces a key file the codec does not accept, as the ladder does for every key", () => {
|
|
151
|
+
const home = tempHome();
|
|
152
|
+
const file = path.join(home, ".stigmer", PLATFORM_TOKEN_KEY_FILE_NAME);
|
|
153
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
154
|
+
fs.writeFileSync(file, "garbage", { mode: 0o600 });
|
|
155
|
+
const ring = openSourcePlatformTokenKeyRing({ env: {}, homeDir: home });
|
|
156
|
+
expect(ring.signer.key.asymmetricKeyType).toBe("rsa");
|
|
157
|
+
expect(fs.readFileSync(file, "utf8")).toContain("BEGIN PRIVATE KEY");
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe("resolvePlatformTokenKeys", () => {
|
|
162
|
+
const supplied = platformTokenKeyRingFromPem({
|
|
163
|
+
publicKeyPems: [pair.publicKeyPem],
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("composes no ring without an authentication posture, whatever is supplied", () => {
|
|
167
|
+
expect(
|
|
168
|
+
resolvePlatformTokenKeys({
|
|
169
|
+
requireAuthentication: false,
|
|
170
|
+
supplied,
|
|
171
|
+
edition: ServerEdition.cloud,
|
|
172
|
+
}),
|
|
173
|
+
).toBeUndefined();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("uses a supplied ring under the posture", () => {
|
|
177
|
+
expect(
|
|
178
|
+
resolvePlatformTokenKeys({
|
|
179
|
+
requireAuthentication: true,
|
|
180
|
+
supplied,
|
|
181
|
+
edition: ServerEdition.cloud,
|
|
182
|
+
}),
|
|
183
|
+
).toBe(supplied);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it("composes open source's own ring when open source supplies none", () => {
|
|
187
|
+
const ring = resolvePlatformTokenKeys({
|
|
188
|
+
requireAuthentication: true,
|
|
189
|
+
supplied: undefined,
|
|
190
|
+
edition: ServerEdition.oss,
|
|
191
|
+
options: { env: {}, homeDir: tempHome() },
|
|
192
|
+
});
|
|
193
|
+
expect(ring !== undefined && canSign(ring)).toBe(true);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("refuses to boot any other edition that supplies no ring", () => {
|
|
197
|
+
expect(() =>
|
|
198
|
+
resolvePlatformTokenKeys({
|
|
199
|
+
requireAuthentication: true,
|
|
200
|
+
supplied: undefined,
|
|
201
|
+
edition: ServerEdition.cloud,
|
|
202
|
+
}),
|
|
203
|
+
).toThrow(/registers no platform-token key ring/);
|
|
204
|
+
});
|
|
205
|
+
});
|