@pithy-sh/core 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/audit/auditEvent.js +1 -1
- package/dist/audit/chain.d.ts +289 -0
- package/dist/audit/chain.d.ts.map +1 -0
- package/dist/audit/chain.js +400 -0
- package/dist/audit/citations.d.ts +52 -0
- package/dist/audit/citations.d.ts.map +1 -0
- package/dist/audit/citations.js +13 -0
- package/dist/capability/bindings.d.ts +22 -0
- package/dist/capability/bindings.d.ts.map +1 -1
- package/dist/capability/bindings.js +32 -2
- package/dist/capability/capability.d.ts +123 -16
- package/dist/capability/capability.d.ts.map +1 -1
- package/dist/capability/capability.js +17 -2
- package/dist/capability/erasure.d.ts +75 -0
- package/dist/capability/erasure.d.ts.map +1 -0
- package/dist/capability/erasure.js +2 -0
- package/dist/capability/manifest.d.ts +5 -0
- package/dist/capability/manifest.d.ts.map +1 -1
- package/dist/capability/personColumns.d.ts +28 -0
- package/dist/capability/personColumns.d.ts.map +1 -0
- package/dist/capability/personColumns.js +66 -0
- package/dist/capability/personRows.d.ts +62 -0
- package/dist/capability/personRows.d.ts.map +1 -0
- package/dist/capability/personRows.js +59 -0
- package/dist/capability/purge.d.ts +86 -19
- package/dist/capability/purge.d.ts.map +1 -1
- package/dist/capability/purge.js +83 -5
- package/dist/capability/settings.d.ts +10 -0
- package/dist/capability/settings.d.ts.map +1 -1
- package/dist/capability/vectorIndex.d.ts +36 -0
- package/dist/capability/vectorIndex.d.ts.map +1 -0
- package/dist/capability/vectorIndex.js +25 -0
- package/dist/cli/commandCatalog.generated.d.ts +433 -3
- package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
- package/dist/cli/commandCatalog.generated.js +449 -2
- package/dist/cli/commandFacts.d.ts +8 -5
- package/dist/cli/commandFacts.d.ts.map +1 -1
- package/dist/cli/commandFacts.js +12 -3
- package/dist/consent/purpose.d.ts +70 -0
- package/dist/consent/purpose.d.ts.map +1 -0
- package/dist/consent/purpose.js +97 -0
- package/dist/consent/reader.d.ts +99 -0
- package/dist/consent/reader.d.ts.map +1 -0
- package/dist/consent/reader.js +33 -0
- package/dist/controlPlane/audit/actions.d.ts +15 -4
- package/dist/controlPlane/audit/actions.d.ts.map +1 -1
- package/dist/controlPlane/audit/actions.js +16 -5
- package/dist/controlPlane/capability.d.ts +10 -0
- package/dist/controlPlane/capability.d.ts.map +1 -1
- package/dist/controlPlane/capability.js +56 -8
- package/dist/controlPlane/context.d.ts +4 -0
- package/dist/controlPlane/context.d.ts.map +1 -1
- package/dist/controlPlane/context.js +3 -2
- package/dist/controlPlane/data/connection.d.ts +21 -2
- package/dist/controlPlane/data/connection.d.ts.map +1 -1
- package/dist/controlPlane/data/connection.js +13 -4
- package/dist/controlPlane/data/connections.d.ts +94 -0
- package/dist/controlPlane/data/connections.d.ts.map +1 -0
- package/dist/controlPlane/data/connections.js +151 -0
- package/dist/controlPlane/data/hold.d.ts +46 -0
- package/dist/controlPlane/data/hold.d.ts.map +1 -0
- package/dist/controlPlane/data/hold.js +36 -0
- package/dist/controlPlane/data/oidcTrust.d.ts +122 -0
- package/dist/controlPlane/data/oidcTrust.d.ts.map +1 -0
- package/dist/controlPlane/data/oidcTrust.js +173 -0
- package/dist/controlPlane/data/tables.d.ts +4 -0
- package/dist/controlPlane/data/tables.d.ts.map +1 -1
- package/dist/controlPlane/data/tables.js +9 -4
- package/dist/controlPlane/data/trustFirstCall.d.ts +16 -0
- package/dist/controlPlane/data/trustFirstCall.d.ts.map +1 -0
- package/dist/controlPlane/data/trustFirstCall.js +25 -0
- package/dist/controlPlane/discovery/adminRoute.d.ts +165 -2
- package/dist/controlPlane/discovery/adminRoute.d.ts.map +1 -1
- package/dist/controlPlane/discovery/adminRoute.js +32 -8
- package/dist/controlPlane/discovery/routeInput.d.ts +23 -0
- package/dist/controlPlane/discovery/routeInput.d.ts.map +1 -0
- package/dist/controlPlane/discovery/routeInput.js +80 -0
- package/dist/controlPlane/discovery/toolName.d.ts +21 -0
- package/dist/controlPlane/discovery/toolName.d.ts.map +1 -0
- package/dist/controlPlane/discovery/toolName.js +25 -0
- package/dist/controlPlane/erasure/attest.d.ts +78 -0
- package/dist/controlPlane/erasure/attest.d.ts.map +1 -0
- package/dist/controlPlane/erasure/attest.js +164 -0
- package/dist/controlPlane/erasure/read.d.ts +39 -0
- package/dist/controlPlane/erasure/read.d.ts.map +1 -0
- package/dist/controlPlane/erasure/read.js +140 -0
- package/dist/controlPlane/error/errors.d.ts +61 -2
- package/dist/controlPlane/error/errors.d.ts.map +1 -1
- package/dist/controlPlane/error/errors.js +13 -0
- package/dist/controlPlane/evidence/derive.d.ts +124 -0
- package/dist/controlPlane/evidence/derive.d.ts.map +1 -0
- package/dist/controlPlane/evidence/derive.js +343 -0
- package/dist/controlPlane/evidence/mapping.d.ts +85 -0
- package/dist/controlPlane/evidence/mapping.d.ts.map +1 -0
- package/dist/controlPlane/evidence/mapping.js +114 -0
- package/dist/controlPlane/evidence/pack.d.ts +46 -0
- package/dist/controlPlane/evidence/pack.d.ts.map +1 -0
- package/dist/controlPlane/evidence/pack.js +124 -0
- package/dist/controlPlane/http/connections.d.ts +96 -0
- package/dist/controlPlane/http/connections.d.ts.map +1 -0
- package/dist/controlPlane/http/connections.js +109 -0
- package/dist/controlPlane/http/guard.d.ts +23 -2
- package/dist/controlPlane/http/guard.d.ts.map +1 -1
- package/dist/controlPlane/http/guard.js +69 -12
- package/dist/controlPlane/http/handlers.d.ts +212 -10
- package/dist/controlPlane/http/handlers.d.ts.map +1 -1
- package/dist/controlPlane/http/handlers.js +117 -26
- package/dist/controlPlane/http/holds.d.ts +57 -0
- package/dist/controlPlane/http/holds.d.ts.map +1 -0
- package/dist/controlPlane/http/holds.js +98 -0
- package/dist/controlPlane/http/presence.d.ts +27 -0
- package/dist/controlPlane/http/presence.d.ts.map +1 -0
- package/dist/controlPlane/http/presence.js +67 -0
- package/dist/controlPlane/http/processing.d.ts +73 -0
- package/dist/controlPlane/http/processing.d.ts.map +1 -0
- package/dist/controlPlane/http/processing.js +17 -0
- package/dist/controlPlane/http/responses.d.ts +927 -3
- package/dist/controlPlane/http/responses.d.ts.map +1 -1
- package/dist/controlPlane/http/responses.js +283 -7
- package/dist/controlPlane/http/routes.d.ts +12 -2
- package/dist/controlPlane/http/routes.d.ts.map +1 -1
- package/dist/controlPlane/http/routes.js +182 -5
- package/dist/controlPlane/http/schemas.d.ts +63 -0
- package/dist/controlPlane/http/schemas.d.ts.map +1 -1
- package/dist/controlPlane/http/schemas.js +39 -1
- package/dist/controlPlane/http/verify.d.ts.map +1 -1
- package/dist/controlPlane/http/verify.js +13 -1
- package/dist/controlPlane/http/verifyTrust.d.ts +76 -0
- package/dist/controlPlane/http/verifyTrust.d.ts.map +1 -0
- package/dist/controlPlane/http/verifyTrust.js +75 -0
- package/dist/controlPlane/migrations/0004_connection_trusts.d.ts +15 -0
- package/dist/controlPlane/migrations/0004_connection_trusts.d.ts.map +1 -0
- package/dist/controlPlane/migrations/0004_connection_trusts.js +23 -0
- package/dist/controlPlane/migrations/0005_holds.d.ts +12 -0
- package/dist/controlPlane/migrations/0005_holds.d.ts.map +1 -0
- package/dist/controlPlane/migrations/0005_holds.js +26 -0
- package/dist/controlPlane/processing/derive.d.ts +77 -0
- package/dist/controlPlane/processing/derive.d.ts.map +1 -0
- package/dist/controlPlane/processing/derive.js +206 -0
- package/dist/controlPlane/processing/read.d.ts +10 -0
- package/dist/controlPlane/processing/read.d.ts.map +1 -0
- package/dist/controlPlane/processing/read.js +89 -0
- package/dist/controlPlane/scope/kind.d.ts +46 -0
- package/dist/controlPlane/scope/kind.d.ts.map +1 -0
- package/dist/controlPlane/scope/kind.js +52 -0
- package/dist/controlPlane/scope/scope.d.ts +58 -3
- package/dist/controlPlane/scope/scope.d.ts.map +1 -1
- package/dist/controlPlane/scope/scope.js +59 -4
- package/dist/controlPlane/token/jws.js +1 -1
- package/dist/controlPlane/token/mint.js +1 -1
- package/dist/controlPlane/wire.d.ts +23 -0
- package/dist/controlPlane/wire.d.ts.map +1 -1
- package/dist/controlPlane/wire.js +24 -1
- package/dist/createBackend.d.ts +13 -0
- package/dist/createBackend.d.ts.map +1 -1
- package/dist/createBackend.js +11 -3
- package/dist/createEntrypoint.d.ts +7 -0
- package/dist/createEntrypoint.d.ts.map +1 -1
- package/dist/createEntrypoint.js +4 -0
- package/dist/error/http.d.ts +168 -0
- package/dist/error/http.d.ts.map +1 -1
- package/dist/error/payload.d.ts +336 -0
- package/dist/error/payload.d.ts.map +1 -1
- package/dist/error/payload.js +112 -0
- package/dist/error/pithyError.d.ts +22 -0
- package/dist/error/pithyError.d.ts.map +1 -1
- package/dist/error/pithyError.js +31 -1
- package/dist/http/routeSpec.d.ts +46 -1
- package/dist/http/routeSpec.d.ts.map +1 -1
- package/dist/http/routeSpec.js +39 -5
- package/dist/http/verification.d.ts.map +1 -1
- package/dist/http/verification.js +1 -1
- package/dist/i18n/translator.d.ts +2 -1
- package/dist/i18n/translator.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/logger/record.d.ts +98 -0
- package/dist/logger/record.d.ts.map +1 -1
- package/dist/mcp/annotations.d.ts +20 -0
- package/dist/mcp/annotations.d.ts.map +1 -0
- package/dist/mcp/annotations.js +23 -0
- package/dist/mcp/tools.d.ts +75 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +118 -0
- package/dist/openapi/document.d.ts.map +1 -1
- package/dist/openapi/document.js +8 -26
- package/dist/openapi/operations.d.ts +35 -0
- package/dist/openapi/operations.d.ts.map +1 -0
- package/dist/openapi/operations.js +37 -0
- package/dist/presence/channel.d.ts +11 -0
- package/dist/presence/channel.d.ts.map +1 -0
- package/dist/presence/channel.js +65 -0
- package/dist/presence/declaration.d.ts +154 -0
- package/dist/presence/declaration.d.ts.map +1 -0
- package/dist/presence/declaration.js +164 -0
- package/dist/presence/durableObject.d.ts +61 -0
- package/dist/presence/durableObject.d.ts.map +1 -0
- package/dist/presence/durableObject.js +257 -0
- package/dist/presence/frames.d.ts +166 -0
- package/dist/presence/frames.d.ts.map +1 -0
- package/dist/presence/frames.js +90 -0
- package/dist/presence/http/guard.d.ts +11 -0
- package/dist/presence/http/guard.d.ts.map +1 -0
- package/dist/presence/http/guard.js +20 -0
- package/dist/presence/http/responses.d.ts +31 -0
- package/dist/presence/http/responses.d.ts.map +1 -0
- package/dist/presence/http/responses.js +34 -0
- package/dist/presence/http/routes.d.ts +24 -0
- package/dist/presence/http/routes.d.ts.map +1 -0
- package/dist/presence/http/routes.js +127 -0
- package/dist/presence/http/schemas.d.ts +29 -0
- package/dist/presence/http/schemas.d.ts.map +1 -0
- package/dist/presence/http/schemas.js +28 -0
- package/dist/presence/names.d.ts +23 -0
- package/dist/presence/names.d.ts.map +1 -0
- package/dist/presence/names.js +22 -0
- package/dist/presence/room.d.ts +95 -0
- package/dist/presence/room.d.ts.map +1 -0
- package/dist/presence/room.js +105 -0
- package/dist/presence/ticket.d.ts +55 -0
- package/dist/presence/ticket.d.ts.map +1 -0
- package/dist/presence/ticket.js +109 -0
- package/dist/privacy/classify.js +1 -1
- package/dist/privacy/encrypted.js +1 -1
- package/dist/processing/activity.d.ts +134 -0
- package/dist/processing/activity.d.ts.map +1 -0
- package/dist/processing/activity.js +161 -0
- package/dist/processing/composed.d.ts +18 -0
- package/dist/processing/composed.d.ts.map +1 -0
- package/dist/processing/composed.js +28 -0
- package/dist/processing/vocabulary.d.ts +26 -0
- package/dist/processing/vocabulary.d.ts.map +1 -0
- package/dist/processing/vocabulary.js +35 -0
- package/dist/queue/consumer.d.ts +59 -0
- package/dist/queue/consumer.d.ts.map +1 -0
- package/dist/queue/consumer.js +46 -0
- package/dist/retention/composed.d.ts +37 -0
- package/dist/retention/composed.d.ts.map +1 -0
- package/dist/retention/composed.js +66 -0
- package/dist/retention/holds.d.ts +61 -0
- package/dist/retention/holds.d.ts.map +1 -0
- package/dist/retention/holds.js +107 -0
- package/dist/retention/holdsPurge.d.ts +22 -0
- package/dist/retention/holdsPurge.d.ts.map +1 -0
- package/dist/retention/holdsPurge.js +50 -0
- package/dist/retention/policy.d.ts +132 -0
- package/dist/retention/policy.d.ts.map +1 -0
- package/dist/retention/policy.js +197 -0
- package/dist/session/rotated.d.ts +34 -0
- package/dist/session/rotated.d.ts.map +1 -0
- package/dist/session/rotated.js +25 -0
- package/dist/test-utils/connectionFixtures.d.ts +13 -0
- package/dist/test-utils/connectionFixtures.d.ts.map +1 -0
- package/dist/test-utils/connectionFixtures.js +58 -0
- package/dist/test-utils/interleave.d.ts +12 -0
- package/dist/test-utils/interleave.d.ts.map +1 -0
- package/dist/test-utils/interleave.js +26 -0
- package/dist/testWorker.d.ts +8 -0
- package/dist/testWorker.d.ts.map +1 -0
- package/dist/testWorker.js +9 -0
- package/dist/version.generated.d.ts +1 -1
- package/dist/version.generated.js +1 -1
- package/dist/workflow/dispatchRoute.js +1 -1
- package/package.json +1 -1
- package/src/audit/auditEvent.ts +1 -1
- package/src/audit/chain.ts +551 -0
- package/src/audit/citations.ts +63 -0
- package/src/capability/bindings.ts +61 -0
- package/src/capability/capability.ts +156 -19
- package/src/capability/erasure.ts +82 -0
- package/src/capability/personColumns.ts +83 -0
- package/src/capability/personRows.ts +125 -0
- package/src/capability/purge.ts +158 -21
- package/src/capability/settings.ts +7 -0
- package/src/capability/vectorIndex.ts +60 -0
- package/src/cli/commandCatalog.generated.ts +482 -2
- package/src/cli/commandFacts.ts +12 -3
- package/src/cloudflare-test.d.ts +3 -1
- package/src/consent/purpose.ts +160 -0
- package/src/consent/reader.ts +134 -0
- package/src/controlPlane/audit/actions.ts +15 -4
- package/src/controlPlane/capability.ts +99 -20
- package/src/controlPlane/context.ts +10 -2
- package/src/controlPlane/data/connection.ts +16 -2
- package/src/controlPlane/data/connections.ts +231 -0
- package/src/controlPlane/data/hold.ts +52 -0
- package/src/controlPlane/data/oidcTrust.ts +249 -0
- package/src/controlPlane/data/tables.ts +7 -0
- package/src/controlPlane/data/trustFirstCall.ts +37 -0
- package/src/controlPlane/discovery/adminRoute.ts +71 -9
- package/src/controlPlane/discovery/routeInput.ts +86 -0
- package/src/controlPlane/discovery/toolName.ts +23 -0
- package/src/controlPlane/erasure/attest.ts +205 -0
- package/src/controlPlane/erasure/read.ts +169 -0
- package/src/controlPlane/error/errors.ts +69 -2
- package/src/controlPlane/evidence/derive.ts +426 -0
- package/src/controlPlane/evidence/mapping.ts +118 -0
- package/src/controlPlane/evidence/pack.ts +190 -0
- package/src/controlPlane/http/connections.ts +129 -0
- package/src/controlPlane/http/guard.ts +118 -9
- package/src/controlPlane/http/handlers.ts +172 -40
- package/src/controlPlane/http/holds.ts +108 -0
- package/src/controlPlane/http/presence.ts +71 -0
- package/src/controlPlane/http/processing.ts +19 -0
- package/src/controlPlane/http/responses.ts +590 -7
- package/src/controlPlane/http/routes.ts +302 -3
- package/src/controlPlane/http/schemas.ts +126 -0
- package/src/controlPlane/http/verify.ts +19 -2
- package/src/controlPlane/http/verifyTrust.ts +176 -0
- package/src/controlPlane/migrations/0004_connection_trusts.ts +30 -0
- package/src/controlPlane/migrations/0005_holds.ts +40 -0
- package/src/controlPlane/processing/derive.ts +359 -0
- package/src/controlPlane/processing/read.ts +102 -0
- package/src/controlPlane/scope/kind.ts +63 -0
- package/src/controlPlane/scope/scope.ts +65 -3
- package/src/controlPlane/wire.ts +26 -0
- package/src/createBackend.ts +31 -6
- package/src/createEntrypoint.ts +17 -0
- package/src/error/payload.ts +234 -0
- package/src/error/pithyError.ts +42 -0
- package/src/http/routeSpec.ts +75 -5
- package/src/http/verification.ts +3 -1
- package/src/i18n/translator.ts +2 -1
- package/src/index.ts +2 -0
- package/src/mcp/annotations.ts +38 -0
- package/src/mcp/tools.ts +220 -0
- package/src/openapi/document.ts +8 -28
- package/src/openapi/operations.ts +62 -0
- package/src/presence/channel.ts +46 -0
- package/src/presence/declaration.ts +283 -0
- package/src/presence/durableObject.ts +287 -0
- package/src/presence/frames.ts +153 -0
- package/src/presence/http/guard.ts +23 -0
- package/src/presence/http/responses.ts +63 -0
- package/src/presence/http/routes.ts +165 -0
- package/src/presence/http/schemas.ts +39 -0
- package/src/presence/names.ts +45 -0
- package/src/presence/room.ts +145 -0
- package/src/presence/ticket.ts +145 -0
- package/src/processing/activity.ts +289 -0
- package/src/processing/composed.ts +33 -0
- package/src/processing/vocabulary.ts +43 -0
- package/src/queue/consumer.ts +104 -0
- package/src/retention/composed.ts +75 -0
- package/src/retention/holds.ts +175 -0
- package/src/retention/holdsPurge.ts +50 -0
- package/src/retention/policy.ts +305 -0
- package/src/session/rotated.ts +53 -0
- package/src/test-utils/connectionFixtures.ts +58 -0
- package/src/test-utils/interleave.ts +31 -0
- package/src/testWorker.ts +13 -0
- package/src/version.generated.ts +1 -1
|
@@ -38,7 +38,7 @@ export declare const RegisteredKey: z.ZodObject<{
|
|
|
38
38
|
}, z.core.$strip>;
|
|
39
39
|
export type RegisteredKey = z.output<typeof RegisteredKey>;
|
|
40
40
|
/**
|
|
41
|
-
* What kind of client a connection is for
|
|
41
|
+
* What kind of client a connection is for: `agent`, `dashboard` or `script`.
|
|
42
42
|
*
|
|
43
43
|
* The audit trail's `actorType: "control-plane"` names all three identically, and the questions asked
|
|
44
44
|
* after an incident are exactly the ones that tell them apart — was it a person at the dashboard, a
|
|
@@ -69,7 +69,7 @@ export type ConnectionPrincipal = z.output<typeof ConnectionPrincipal>;
|
|
|
69
69
|
/** The longest purpose a connection may carry. One line on a review screen, with room to say what it does. */
|
|
70
70
|
export declare const MAX_CONNECTION_PURPOSE = 200;
|
|
71
71
|
/**
|
|
72
|
-
* What a connection is for, in the words of whoever registered it
|
|
72
|
+
* What a connection is for, in the words of whoever registered it.
|
|
73
73
|
*
|
|
74
74
|
* **Required at registration, and refused when absent**, because a review listing credentials by key id
|
|
75
75
|
* cannot support the decision it exists for. **Untrusted input**: a customer writes it and something else
|
|
@@ -77,6 +77,14 @@ export declare const MAX_CONNECTION_PURPOSE = 200;
|
|
|
77
77
|
*/
|
|
78
78
|
export declare const ConnectionPurpose: z.ZodString;
|
|
79
79
|
export type ConnectionPurpose = z.output<typeof ConnectionPurpose>;
|
|
80
|
+
/** Which credential kinds a connection holds, live or not. */
|
|
81
|
+
export declare const ConnectionCredentialKind: z.ZodEnum<{
|
|
82
|
+
both: "both";
|
|
83
|
+
key: "key";
|
|
84
|
+
none: "none";
|
|
85
|
+
trust: "trust";
|
|
86
|
+
}>;
|
|
87
|
+
export type ConnectionCredentialKind = z.infer<typeof ConnectionCredentialKind>;
|
|
80
88
|
/**
|
|
81
89
|
* One management-client connection — the row in `pithy_controlplane_connections`.
|
|
82
90
|
*
|
|
@@ -111,6 +119,17 @@ export declare const ControlPlaneConnection: z.ZodObject<{
|
|
|
111
119
|
validUntil: z.ZodNullable<z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>>;
|
|
112
120
|
revokedAt: z.ZodNullable<z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>>;
|
|
113
121
|
}, z.core.$strip>>>;
|
|
122
|
+
trusts: z.ZodOptional<import("../../data/codecs").SqliteJson<z.ZodArray<z.ZodObject<{
|
|
123
|
+
trustId: z.ZodString;
|
|
124
|
+
issuer: z.ZodURL;
|
|
125
|
+
jwksUrl: z.ZodURL;
|
|
126
|
+
audience: z.ZodString;
|
|
127
|
+
claims: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
128
|
+
authorizedBy: z.ZodEmail;
|
|
129
|
+
validFrom: z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>;
|
|
130
|
+
revokedAt: z.ZodNullable<z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>>;
|
|
131
|
+
firstCallAt: z.ZodNullable<z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>>;
|
|
132
|
+
}, z.core.$strip>>>>;
|
|
114
133
|
createdAt: z.ZodCodec<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodDate]>, z.ZodDate>;
|
|
115
134
|
updatedAt: z.ZodCodec<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodDate]>, z.ZodDate>;
|
|
116
135
|
}, z.core.$strip>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/connection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/connection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;;;;GASG;AAEH,+EAA+E;AAC/E,eAAO,MAAM,gBAAgB;;;;iBAgBoF,CAAC;AAClH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEjE;;;;;;GAMG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;iBAoBoF,CAAC;AAC/G,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB;;;;EAI/B,CAAC;AACJ,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAE3E;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,YAK7B,CAAC;AACJ,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEvE,8GAA8G;AAC9G,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAiB1C;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,aAW3B,CAAC;AACJ,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEnE,8DAA8D;AAC9D,eAAO,MAAM,wBAAwB;;;;;EAIlC,CAAC;AACJ,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuEhC,CAAC;AACJ,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAC7E,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
|
-
import { JsonDate, SQLiteDate, sqliteJson } from "../../data/codecs.js";
|
|
4
3
|
import { ControlPlaneScope } from "../scope/scope.js";
|
|
4
|
+
import { JsonDate, SQLiteDate, sqliteJson } from "../../data/codecs.js";
|
|
5
|
+
import { OidcTrust } from "./oidcTrust.js";
|
|
5
6
|
import { z } from "zod";
|
|
6
7
|
//#region src/controlPlane/data/connection.ts
|
|
7
8
|
/**
|
|
@@ -35,7 +36,7 @@ const RegisteredKey = z.object({
|
|
|
35
36
|
revokedAt: JsonDate.nullable().describe("When this key was revoked outright, or null. Revocation ignores `validUntil` and takes effect immediately — it is the adopter's unilateral control, and it must not wait for a window to close.")
|
|
36
37
|
}).describe("One registered public key with its validity window. Two live at once during a rotation overlap.");
|
|
37
38
|
/**
|
|
38
|
-
* What kind of client a connection is for
|
|
39
|
+
* What kind of client a connection is for: `agent`, `dashboard` or `script`.
|
|
39
40
|
*
|
|
40
41
|
* The audit trail's `actorType: "control-plane"` names all three identically, and the questions asked
|
|
41
42
|
* after an incident are exactly the ones that tell them apart — was it a person at the dashboard, a
|
|
@@ -78,13 +79,20 @@ const MAX_CONNECTION_PURPOSE = 200;
|
|
|
78
79
|
*/
|
|
79
80
|
const UNRENDERABLE = /[\p{Cc}\p{Bidi_Control}\u2028\u2029\u200B\u2060\uFEFF]/u;
|
|
80
81
|
/**
|
|
81
|
-
* What a connection is for, in the words of whoever registered it
|
|
82
|
+
* What a connection is for, in the words of whoever registered it.
|
|
82
83
|
*
|
|
83
84
|
* **Required at registration, and refused when absent**, because a review listing credentials by key id
|
|
84
85
|
* cannot support the decision it exists for. **Untrusted input**: a customer writes it and something else
|
|
85
86
|
* renders it, so it is validated on the way in, and again on every read of the row.
|
|
86
87
|
*/
|
|
87
88
|
const ConnectionPurpose = z.string().trim().min(1, "Say what this client is for.").max(200, `A purpose is 200 characters at most.`).refine((purpose) => !UNRENDERABLE.test(purpose), "A purpose is one line of plain text: no control, bidi or invisible characters.").describe(`What this connection's client is for, in the registering operator's words — one line of plain text, 200 characters at most, with no control, bidi or invisible characters. Written by a customer and rendered elsewhere, so validated at the boundary.`);
|
|
89
|
+
/** Which credential kinds a connection holds, live or not. */
|
|
90
|
+
const ConnectionCredentialKind = z.enum([
|
|
91
|
+
"key",
|
|
92
|
+
"trust",
|
|
93
|
+
"both",
|
|
94
|
+
"none"
|
|
95
|
+
]).describe("Which credential kinds the connection holds, live or not: `key` (registered Ed25519 keys), `trust` (OIDC trusts), `both`, or `none`.");
|
|
88
96
|
/**
|
|
89
97
|
* One management-client connection — the row in `pithy_controlplane_connections`.
|
|
90
98
|
*
|
|
@@ -105,8 +113,9 @@ const ControlPlaneConnection = z.object({
|
|
|
105
113
|
purpose: ConnectionPurpose.nullable().default(null).describe("What this connection's client is for, in the registering operator's words. Required at registration and editable with `pithy dashboard connect --update --purpose`; null only for a connection registered before it was recorded."),
|
|
106
114
|
scopes: sqliteJson(z.array(ControlPlaneScope)).describe("The operations this connection was granted, stored and enforced on the adopter's side. Enforced only by the caller, a scope would not be a limit at all."),
|
|
107
115
|
keys: sqliteJson(z.array(RegisteredKey)).describe("Every key this connection may sign with, current and superseded. One JSON column rather than a child table, so a rotation is one atomic UPDATE and verification is one read."),
|
|
116
|
+
trusts: sqliteJson(z.array(OidcTrust)).optional().describe("Every OIDC trust this connection honors, live and revoked (#722) — the second credential kind beside `keys`, so a connection may hold a trust, a key, or both. Optional on the type, and absent reads as none: a connection value built before trusts existed still describes a connection, and the column itself defaults to an empty list."),
|
|
108
117
|
createdAt: SQLiteDate.describe("When the connection was registered. Ms-epoch in SQLite, a Date in TypeScript."),
|
|
109
118
|
updatedAt: SQLiteDate.describe("When the row last changed — a key registered or expired, or the Worker URL re-pointed.")
|
|
110
119
|
}).describe("One management-client connection: its identity, the environment and URL it is bound to, the operations it was granted, and its versioned public keys.");
|
|
111
120
|
//#endregion
|
|
112
|
-
export { ConnectionPrincipal, ConnectionPurpose, ControlPlaneActorKind, ControlPlaneConnection, Ed25519PublicJwk, MAX_CONNECTION_PURPOSE, RegisteredKey };
|
|
121
|
+
export { ConnectionCredentialKind, ConnectionPrincipal, ConnectionPurpose, ControlPlaneActorKind, ControlPlaneConnection, Ed25519PublicJwk, MAX_CONNECTION_PURPOSE, RegisteredKey };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { type ConnectionCredentialKind, ControlPlaneConnection, type RegisteredKey } from "./connection";
|
|
4
|
+
import { type OidcTrust } from "./oidcTrust";
|
|
5
|
+
import { type ControlPlaneDatabase } from "./tables";
|
|
6
|
+
/**
|
|
7
|
+
* Every connection in one database, read for a review: which person authorized each, and which still answer.
|
|
8
|
+
*
|
|
9
|
+
* `GET {basePath}/connections` and `pithy dashboard connections` both read through {@link listConnections}, so the
|
|
10
|
+
* Worker's answer and the CLI's cannot list different things.
|
|
11
|
+
*/
|
|
12
|
+
/** Which credential kinds a connection holds, live or not. */
|
|
13
|
+
export declare function connectionCredentialKind(connection: ControlPlaneConnection): ConnectionCredentialKind;
|
|
14
|
+
/** Whether any key or trust on the connection can verify a call at `now`. */
|
|
15
|
+
export declare function connectionLive(connection: ControlPlaneConnection, now: Date): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* When the connection was revoked: the latest revocation among its credentials, once none is live and every one of
|
|
18
|
+
* them was revoked. Null while anything is live, and for a connection whose keys merely expired.
|
|
19
|
+
*/
|
|
20
|
+
export declare function connectionRevokedAt(connection: ControlPlaneConnection, now: Date): Date | null;
|
|
21
|
+
/** What {@link revokeCredentials} changed. */
|
|
22
|
+
export interface RevokedCredentials {
|
|
23
|
+
/** The connection with every key and trust not yet revoked revoked at `now`. */
|
|
24
|
+
readonly connection: ControlPlaneConnection;
|
|
25
|
+
readonly revokedKeyIds: readonly string[];
|
|
26
|
+
readonly revokedTrustIds: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Revoke every key and trust not yet revoked, whatever its window. One that has not started will verify once its
|
|
30
|
+
* window opens, and the revoker's clock may run behind the Worker that stamped it, so it is revoked too. A credential
|
|
31
|
+
* already revoked keeps its instant.
|
|
32
|
+
*/
|
|
33
|
+
export declare function revokeCredentials(connection: ControlPlaneConnection, now: Date): RevokedCredentials;
|
|
34
|
+
/** Whether a connection was authorized by `principal`. An email, compared without regard to case. */
|
|
35
|
+
export declare function authorizedByPrincipal(connection: ControlPlaneConnection, principal: string): boolean;
|
|
36
|
+
/** Which connections {@link listConnections} reads. */
|
|
37
|
+
export interface ConnectionFilter {
|
|
38
|
+
/** Only connections this email authorized. Unattributed connections are listed apart either way. */
|
|
39
|
+
readonly principal?: string | undefined;
|
|
40
|
+
/** Only connections bound to this environment. */
|
|
41
|
+
readonly environment?: string | undefined;
|
|
42
|
+
}
|
|
43
|
+
/** The connections a filter selects, with the ones no principal was recorded for kept apart. */
|
|
44
|
+
export interface ConnectionListing {
|
|
45
|
+
/** Connections with a recorded principal, matching the filter, oldest first. */
|
|
46
|
+
readonly connections: readonly ControlPlaneConnection[];
|
|
47
|
+
/** Connections registered before principals were recorded, oldest first. Never matched by a principal. */
|
|
48
|
+
readonly unattributed: readonly ControlPlaneConnection[];
|
|
49
|
+
}
|
|
50
|
+
/** Every connection in the database, attributed ones matching the filter, unattributed ones apart. */
|
|
51
|
+
export declare function listConnections(db: ControlPlaneDatabase, filter?: ConnectionFilter): Promise<ConnectionListing>;
|
|
52
|
+
/** Read one connection by id, or null. */
|
|
53
|
+
export declare function readConnection(db: ControlPlaneDatabase, id: string): Promise<ControlPlaneConnection | null>;
|
|
54
|
+
/**
|
|
55
|
+
* A connection read for a write to its credential columns, with those columns exactly as stored. A write made from it
|
|
56
|
+
* lands only while they are unchanged, so a revocation landing in between is never overwritten.
|
|
57
|
+
*/
|
|
58
|
+
export interface ConnectionForWrite {
|
|
59
|
+
readonly connection: ControlPlaneConnection;
|
|
60
|
+
/** The keys column as stored, compared as stored. */
|
|
61
|
+
readonly storedKeys: unknown;
|
|
62
|
+
/** The trusts column as stored, compared as stored. */
|
|
63
|
+
readonly storedTrusts: unknown;
|
|
64
|
+
}
|
|
65
|
+
/** Read one connection by id for a write, or null. With `environment`, null for a connection bound to another. */
|
|
66
|
+
export declare function readConnectionForWrite(db: ControlPlaneDatabase, id: string, options?: {
|
|
67
|
+
readonly environment?: string | undefined;
|
|
68
|
+
}): Promise<ConnectionForWrite | null>;
|
|
69
|
+
/**
|
|
70
|
+
* Write a connection's keys and stamp `updatedAt`, only while its keys column still holds what `read` saw. False
|
|
71
|
+
* when it no longer does: another write, a revocation among them, landed in between and nothing was written.
|
|
72
|
+
*/
|
|
73
|
+
export declare function writeKeys(db: ControlPlaneDatabase, read: ConnectionForWrite, keys: readonly RegisteredKey[], now: Date): Promise<boolean>;
|
|
74
|
+
/** The credential columns a {@link writeCredentials} call replaces. A column left out is not written. */
|
|
75
|
+
export interface CredentialColumns {
|
|
76
|
+
readonly keys?: readonly RegisteredKey[] | undefined;
|
|
77
|
+
readonly trusts?: readonly OidcTrust[] | undefined;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Write the given credential columns and stamp `updatedAt`, only while both the keys and the trusts columns still hold
|
|
81
|
+
* what `read` saw. False when either changed in between, and nothing was written.
|
|
82
|
+
*/
|
|
83
|
+
export declare function writeCredentials(db: ControlPlaneDatabase, read: ConnectionForWrite, columns: CredentialColumns, now: Date): Promise<boolean>;
|
|
84
|
+
/**
|
|
85
|
+
* Revoke every key and trust of one connection not yet revoked, or answer null when no connection has that id. With
|
|
86
|
+
* `environment`, a connection bound to another environment answers null too.
|
|
87
|
+
*
|
|
88
|
+
* Writes the two credential columns and the stamp and nothing else on the row, and only while both columns still
|
|
89
|
+
* hold what it read; when another write landed in between, it reads again.
|
|
90
|
+
*/
|
|
91
|
+
export declare function revokeConnection(db: ControlPlaneDatabase, id: string, now: Date, options?: {
|
|
92
|
+
readonly environment?: string | undefined;
|
|
93
|
+
}): Promise<RevokedCredentials | null>;
|
|
94
|
+
//# sourceMappingURL=connections.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connections.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/connections.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,wBAAwB,EAAE,sBAAsB,EAAE,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAEzG,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAmC,KAAK,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAEtF;;;;;GAKG;AAEH,8DAA8D;AAC9D,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,sBAAsB,GAAG,wBAAwB,CAOrG;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,UAAU,EAAE,sBAAsB,EAAE,GAAG,EAAE,IAAI,GAAG,OAAO,CAErF;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,sBAAsB,EAAE,GAAG,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAU9F;AAED,8CAA8C;AAC9C,MAAM,WAAW,kBAAkB;IACjC,gFAAgF;IAChF,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAC5C,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,sBAAsB,EAAE,GAAG,EAAE,IAAI,GAAG,kBAAkB,CAenG;AAED,qGAAqG;AACrG,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEpG;AAED,uDAAuD;AACvD,MAAM,WAAW,gBAAgB;IAC/B,oGAAoG;IACpG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,kDAAkD;IAClD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,gGAAgG;AAChG,MAAM,WAAW,iBAAiB;IAChC,gFAAgF;IAChF,QAAQ,CAAC,WAAW,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACxD,0GAA0G;IAC1G,QAAQ,CAAC,YAAY,EAAE,SAAS,sBAAsB,EAAE,CAAC;CAC1D;AAED,sGAAsG;AACtG,wBAAsB,eAAe,CACnC,EAAE,EAAE,oBAAoB,EACxB,MAAM,GAAE,gBAAqB,GAC5B,OAAO,CAAC,iBAAiB,CAAC,CAW5B;AAED,0CAA0C;AAC1C,wBAAsB,cAAc,CAAC,EAAE,EAAE,oBAAoB,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,GAAG,IAAI,CAAC,CAGjH;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,sBAAsB,CAAC;IAC5C,qDAAqD;IACrD,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,uDAAuD;IACvD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC;AAED,kHAAkH;AAClH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,oBAAoB,EACxB,EAAE,EAAE,MAAM,EACV,OAAO,GAAE;IAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAO,GAC1D,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAMpC;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAC7B,EAAE,EAAE,oBAAoB,EACxB,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,SAAS,aAAa,EAAE,EAC9B,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,OAAO,CAAC,CAWlB;AAED,yGAAyG;AACzG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,aAAa,EAAE,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,CAAC;CACpD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,oBAAoB,EACxB,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,OAAO,CAAC,CAelB;AAKD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,oBAAoB,EACxB,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,IAAI,EACT,OAAO,GAAE;IAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAO,GAC1D,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAcpC"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { ConflictError } from "../../error/pithyError.js";
|
|
4
|
+
import { activeTrusts } from "./oidcTrust.js";
|
|
5
|
+
import { ControlPlaneConnection } from "./connection.js";
|
|
6
|
+
import { CONTROL_PLANE_CONNECTIONS_TABLE } from "./tables.js";
|
|
7
|
+
import { activeKeys } from "./keyLifecycle.js";
|
|
8
|
+
import { sql } from "kysely";
|
|
9
|
+
//#region src/controlPlane/data/connections.ts
|
|
10
|
+
/**
|
|
11
|
+
* Every connection in one database, read for a review: which person authorized each, and which still answer.
|
|
12
|
+
*
|
|
13
|
+
* `GET {basePath}/connections` and `pithy dashboard connections` both read through {@link listConnections}, so the
|
|
14
|
+
* Worker's answer and the CLI's cannot list different things.
|
|
15
|
+
*/
|
|
16
|
+
/** Which credential kinds a connection holds, live or not. */
|
|
17
|
+
function connectionCredentialKind(connection) {
|
|
18
|
+
const keys = connection.keys.length > 0;
|
|
19
|
+
const trusts = (connection.trusts ?? []).length > 0;
|
|
20
|
+
if (keys && trusts) return "both";
|
|
21
|
+
if (keys) return "key";
|
|
22
|
+
if (trusts) return "trust";
|
|
23
|
+
return "none";
|
|
24
|
+
}
|
|
25
|
+
/** Whether any key or trust on the connection can verify a call at `now`. */
|
|
26
|
+
function connectionLive(connection, now) {
|
|
27
|
+
return activeKeys(connection.keys, now).length > 0 || activeTrusts(connection.trusts ?? [], now).length > 0;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* When the connection was revoked: the latest revocation among its credentials, once none is live and every one of
|
|
31
|
+
* them was revoked. Null while anything is live, and for a connection whose keys merely expired.
|
|
32
|
+
*/
|
|
33
|
+
function connectionRevokedAt(connection, now) {
|
|
34
|
+
if (connectionLive(connection, now)) return null;
|
|
35
|
+
const credentials = [...connection.keys, ...connection.trusts ?? []];
|
|
36
|
+
if (credentials.length === 0) return null;
|
|
37
|
+
let latest = null;
|
|
38
|
+
for (const credential of credentials) {
|
|
39
|
+
if (credential.revokedAt === null) return null;
|
|
40
|
+
if (latest === null || credential.revokedAt.getTime() > latest.getTime()) latest = credential.revokedAt;
|
|
41
|
+
}
|
|
42
|
+
return latest;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Revoke every key and trust not yet revoked, whatever its window. One that has not started will verify once its
|
|
46
|
+
* window opens, and the revoker's clock may run behind the Worker that stamped it, so it is revoked too. A credential
|
|
47
|
+
* already revoked keeps its instant.
|
|
48
|
+
*/
|
|
49
|
+
function revokeCredentials(connection, now) {
|
|
50
|
+
const keyIds = connection.keys.filter((key) => key.revokedAt === null).map((key) => key.keyId);
|
|
51
|
+
const trustIds = (connection.trusts ?? []).filter((trust) => trust.revokedAt === null).map((trust) => trust.trustId);
|
|
52
|
+
return {
|
|
53
|
+
connection: {
|
|
54
|
+
...connection,
|
|
55
|
+
keys: connection.keys.map((key) => key.revokedAt === null ? {
|
|
56
|
+
...key,
|
|
57
|
+
revokedAt: now
|
|
58
|
+
} : key),
|
|
59
|
+
trusts: (connection.trusts ?? []).map((trust) => trust.revokedAt === null ? {
|
|
60
|
+
...trust,
|
|
61
|
+
revokedAt: now
|
|
62
|
+
} : trust),
|
|
63
|
+
updatedAt: keyIds.length + trustIds.length > 0 ? now : connection.updatedAt
|
|
64
|
+
},
|
|
65
|
+
revokedKeyIds: keyIds,
|
|
66
|
+
revokedTrustIds: trustIds
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/** Whether a connection was authorized by `principal`. An email, compared without regard to case. */
|
|
70
|
+
function authorizedByPrincipal(connection, principal) {
|
|
71
|
+
return connection.authorizedBy !== null && connection.authorizedBy.toLowerCase() === principal.toLowerCase();
|
|
72
|
+
}
|
|
73
|
+
/** Every connection in the database, attributed ones matching the filter, unattributed ones apart. */
|
|
74
|
+
async function listConnections(db, filter = {}) {
|
|
75
|
+
let query = db.selectFrom(CONTROL_PLANE_CONNECTIONS_TABLE).selectAll().orderBy("createdAt").orderBy("id");
|
|
76
|
+
if (filter.environment !== void 0) query = query.where("environment", "=", filter.environment);
|
|
77
|
+
const rows = (await query.execute()).map((row) => ControlPlaneConnection.parse(row));
|
|
78
|
+
const { principal } = filter;
|
|
79
|
+
return {
|
|
80
|
+
connections: rows.filter((row) => row.authorizedBy !== null && (principal === void 0 || authorizedByPrincipal(row, principal))),
|
|
81
|
+
unattributed: rows.filter((row) => row.authorizedBy === null)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** Read one connection by id, or null. */
|
|
85
|
+
async function readConnection(db, id) {
|
|
86
|
+
const row = await db.selectFrom(CONTROL_PLANE_CONNECTIONS_TABLE).selectAll().where("id", "=", id).executeTakeFirst();
|
|
87
|
+
return row ? ControlPlaneConnection.parse(row) : null;
|
|
88
|
+
}
|
|
89
|
+
/** Read one connection by id for a write, or null. With `environment`, null for a connection bound to another. */
|
|
90
|
+
async function readConnectionForWrite(db, id, options = {}) {
|
|
91
|
+
let query = db.selectFrom(CONTROL_PLANE_CONNECTIONS_TABLE).selectAll().where("id", "=", id);
|
|
92
|
+
if (options.environment !== void 0) query = query.where("environment", "=", options.environment);
|
|
93
|
+
const row = await query.executeTakeFirst();
|
|
94
|
+
if (!row) return null;
|
|
95
|
+
return {
|
|
96
|
+
connection: ControlPlaneConnection.parse(row),
|
|
97
|
+
storedKeys: row.keys,
|
|
98
|
+
storedTrusts: row.trusts
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Write a connection's keys and stamp `updatedAt`, only while its keys column still holds what `read` saw. False
|
|
103
|
+
* when it no longer does: another write, a revocation among them, landed in between and nothing was written.
|
|
104
|
+
*/
|
|
105
|
+
async function writeKeys(db, read, keys, now) {
|
|
106
|
+
const result = await db.updateTable(CONTROL_PLANE_CONNECTIONS_TABLE).set({
|
|
107
|
+
keys: ControlPlaneConnection.shape.keys.encode([...keys]),
|
|
108
|
+
updatedAt: ControlPlaneConnection.shape.updatedAt.encode(now)
|
|
109
|
+
}).where("id", "=", read.connection.id).where(sql`${sql.ref("keys")} = ${read.storedKeys}`).executeTakeFirst();
|
|
110
|
+
return Number(result.numUpdatedRows) > 0;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Write the given credential columns and stamp `updatedAt`, only while both the keys and the trusts columns still hold
|
|
114
|
+
* what `read` saw. False when either changed in between, and nothing was written.
|
|
115
|
+
*/
|
|
116
|
+
async function writeCredentials(db, read, columns, now) {
|
|
117
|
+
const result = await db.updateTable(CONTROL_PLANE_CONNECTIONS_TABLE).set({
|
|
118
|
+
...columns.keys === void 0 ? {} : { keys: ControlPlaneConnection.shape.keys.encode([...columns.keys]) },
|
|
119
|
+
...columns.trusts === void 0 ? {} : { trusts: ControlPlaneConnection.shape.trusts.encode([...columns.trusts]) },
|
|
120
|
+
updatedAt: ControlPlaneConnection.shape.updatedAt.encode(now)
|
|
121
|
+
}).where("id", "=", read.connection.id).where(sql`${sql.ref("keys")} = ${read.storedKeys}`).where(sql`${sql.ref("trusts")} = ${read.storedTrusts}`).executeTakeFirst();
|
|
122
|
+
return Number(result.numUpdatedRows) > 0;
|
|
123
|
+
}
|
|
124
|
+
/** How many times {@link revokeConnection} reads again after a write landed between its read and its own. */
|
|
125
|
+
const REVOKE_ATTEMPTS = 5;
|
|
126
|
+
/**
|
|
127
|
+
* Revoke every key and trust of one connection not yet revoked, or answer null when no connection has that id. With
|
|
128
|
+
* `environment`, a connection bound to another environment answers null too.
|
|
129
|
+
*
|
|
130
|
+
* Writes the two credential columns and the stamp and nothing else on the row, and only while both columns still
|
|
131
|
+
* hold what it read; when another write landed in between, it reads again.
|
|
132
|
+
*/
|
|
133
|
+
async function revokeConnection(db, id, now, options = {}) {
|
|
134
|
+
for (let attempt = 0; attempt < REVOKE_ATTEMPTS; attempt++) {
|
|
135
|
+
const read = await readConnectionForWrite(db, id, options);
|
|
136
|
+
if (read === null) return null;
|
|
137
|
+
const revoked = revokeCredentials(read.connection, now);
|
|
138
|
+
if (revoked.revokedKeyIds.length + revoked.revokedTrustIds.length === 0) return revoked;
|
|
139
|
+
if (await writeCredentials(db, read, {
|
|
140
|
+
keys: revoked.connection.keys,
|
|
141
|
+
trusts: revoked.connection.trusts ?? []
|
|
142
|
+
}, now)) return revoked;
|
|
143
|
+
}
|
|
144
|
+
throw new ConflictError({
|
|
145
|
+
message: "The connection kept changing while it was being revoked.",
|
|
146
|
+
action: "Revoke it again.",
|
|
147
|
+
detail: `connection ${id} changed between read and write ${REVOKE_ATTEMPTS} times`
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
//#endregion
|
|
151
|
+
export { authorizedByPrincipal, connectionCredentialKind, connectionLive, connectionRevokedAt, listConnections, readConnection, readConnectionForWrite, revokeConnection, revokeCredentials, writeCredentials, writeKeys };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/**
|
|
5
|
+
* **A legal hold: one subject preserved, with the reason it was placed and, once released, why.**
|
|
6
|
+
*
|
|
7
|
+
* Placed and released over the control plane, behind `retention:hold`, because a hold is operational and urgent:
|
|
8
|
+
* counsel says preserve everything about this customer, and the next scheduled purge is tonight. While a hold stands
|
|
9
|
+
* no purge, prune or inactivity deletion touches its subject. Released holds are kept — the row is the record that
|
|
10
|
+
* one stood, from when to when, and why it ended — so nothing here is ever deleted.
|
|
11
|
+
*/
|
|
12
|
+
/** What a hold preserves: one user, one organization, or one tenant's audit trail. */
|
|
13
|
+
export declare const HoldSubjectType: z.ZodEnum<{
|
|
14
|
+
audit: "audit";
|
|
15
|
+
organization: "organization";
|
|
16
|
+
user: "user";
|
|
17
|
+
}>;
|
|
18
|
+
export type HoldSubjectType = z.infer<typeof HoldSubjectType>;
|
|
19
|
+
/** Whether a hold is in force. */
|
|
20
|
+
export declare const HoldState: z.ZodEnum<{
|
|
21
|
+
active: "active";
|
|
22
|
+
released: "released";
|
|
23
|
+
}>;
|
|
24
|
+
export type HoldState = z.infer<typeof HoldState>;
|
|
25
|
+
/** One hold, as `pithy_controlplane_holds` stores it. */
|
|
26
|
+
export declare const LegalHold: z.ZodObject<{
|
|
27
|
+
id: z.ZodString;
|
|
28
|
+
subjectType: z.ZodEnum<{
|
|
29
|
+
audit: "audit";
|
|
30
|
+
organization: "organization";
|
|
31
|
+
user: "user";
|
|
32
|
+
}>;
|
|
33
|
+
subjectId: z.ZodNullable<z.ZodString>;
|
|
34
|
+
reason: z.ZodString;
|
|
35
|
+
placedBy: z.ZodString;
|
|
36
|
+
placedAt: z.ZodCodec<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodDate]>, z.ZodDate>;
|
|
37
|
+
state: z.ZodEnum<{
|
|
38
|
+
active: "active";
|
|
39
|
+
released: "released";
|
|
40
|
+
}>;
|
|
41
|
+
releasedAt: z.ZodNullable<z.ZodCodec<z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodDate]>, z.ZodDate>>;
|
|
42
|
+
releasedBy: z.ZodNullable<z.ZodString>;
|
|
43
|
+
releaseReason: z.ZodNullable<z.ZodString>;
|
|
44
|
+
}, z.core.$strip>;
|
|
45
|
+
export type LegalHold = z.output<typeof LegalHold>;
|
|
46
|
+
//# sourceMappingURL=hold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hold.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/hold.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;;GAOG;AAEH,sFAAsF;AACtF,eAAO,MAAM,eAAe;;;;EAIzB,CAAC;AACJ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,kCAAkC;AAClC,eAAO,MAAM,SAAS;;;EAE6E,CAAC;AACpG,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AAElD,yDAAyD;AACzD,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;iBAoBgE,CAAC;AACvF,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { SQLiteDate } from "../../data/codecs.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
//#region src/controlPlane/data/hold.ts
|
|
6
|
+
/**
|
|
7
|
+
* **A legal hold: one subject preserved, with the reason it was placed and, once released, why.**
|
|
8
|
+
*
|
|
9
|
+
* Placed and released over the control plane, behind `retention:hold`, because a hold is operational and urgent:
|
|
10
|
+
* counsel says preserve everything about this customer, and the next scheduled purge is tonight. While a hold stands
|
|
11
|
+
* no purge, prune or inactivity deletion touches its subject. Released holds are kept — the row is the record that
|
|
12
|
+
* one stood, from when to when, and why it ended — so nothing here is ever deleted.
|
|
13
|
+
*/
|
|
14
|
+
/** What a hold preserves: one user, one organization, or one tenant's audit trail. */
|
|
15
|
+
const HoldSubjectType = z.enum([
|
|
16
|
+
"user",
|
|
17
|
+
"organization",
|
|
18
|
+
"audit"
|
|
19
|
+
]).describe("What the hold preserves: `user`, one account and everything its purge would erase; `organization`, one tenant and everything its purge would erase; `audit`, one tenant's audit trail, which the prune then leaves whole.");
|
|
20
|
+
/** Whether a hold is in force. */
|
|
21
|
+
const HoldState = z.enum(["active", "released"]).describe("`active` while the hold stands; `released` once it has been lifted, with the reason.");
|
|
22
|
+
/** One hold, as `pithy_controlplane_holds` stores it. */
|
|
23
|
+
const LegalHold = z.object({
|
|
24
|
+
id: z.string().min(1).describe("The hold's id. Text, never a sequence: it is named on a release route."),
|
|
25
|
+
subjectType: HoldSubjectType,
|
|
26
|
+
subjectId: z.string().min(1).max(255).nullable().describe("The held user's or organization's id, or the tenant whose audit trail is held. Null only for an `audit` hold on the untenanted trail."),
|
|
27
|
+
reason: z.string().min(1).max(500).describe("Why the hold was placed, in whoever placed it's words."),
|
|
28
|
+
placedBy: z.string().describe("The management client's own user id that placed it — the token's `sub`."),
|
|
29
|
+
placedAt: SQLiteDate.describe("When the hold was placed. Ms-epoch in SQLite."),
|
|
30
|
+
state: HoldState,
|
|
31
|
+
releasedAt: SQLiteDate.nullable().describe("When the hold was released, or null while it stands."),
|
|
32
|
+
releasedBy: z.string().nullable().describe("Who released it, or null while it stands."),
|
|
33
|
+
releaseReason: z.string().max(500).nullable().describe("Why it was released, or null while it stands.")
|
|
34
|
+
}).describe("A legal hold on one user, one organization or one tenant's audit trail.");
|
|
35
|
+
//#endregion
|
|
36
|
+
export { HoldState, HoldSubjectType, LegalHold };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/**
|
|
5
|
+
* An OIDC trust: the second credential kind a connection may hold, beside a registered key
|
|
6
|
+
* (`docs/AGENT-ACCESS.md` §6.2, #722).
|
|
7
|
+
*
|
|
8
|
+
* A key is a bearer: one client holds the private half. A trust is a **policy**: a trusted issuer, the
|
|
9
|
+
* audience its tokens must name, and a matcher over the claims that say which workload a token was minted
|
|
10
|
+
* for. Nobody holds a secret. The workload asks its own identity provider for a short-lived token, and the
|
|
11
|
+
* Worker checks it against the issuer's published keys with the verifier the webhooks already use,
|
|
12
|
+
* `core/src/http/oidcWebhook.ts`.
|
|
13
|
+
*
|
|
14
|
+
* ## The claims become data here, and that is a deliberate departure
|
|
15
|
+
*
|
|
16
|
+
* In a webhook the claims check is a predicate the **route** holds, because whoever wrote the route knows
|
|
17
|
+
* the legitimate sender. A connection's trust is per adopter, decided at registration by the same person who
|
|
18
|
+
* grants the scopes, so the matcher is stored with the trust and validated on the way in. That is the whole
|
|
19
|
+
* reason {@link OidcClaimMatch} exists rather than a function.
|
|
20
|
+
*
|
|
21
|
+
* ## The claims check is the boundary, not the signature
|
|
22
|
+
*
|
|
23
|
+
* An identity provider signs for everybody with the same keys. GitHub signs a token for every repository on
|
|
24
|
+
* the planet. A trust whose matcher constrains nothing accepts all of them, so {@link OidcClaimMatch} refuses
|
|
25
|
+
* one at registration — structurally, not as a warning — and refuses the claims that name the token rather
|
|
26
|
+
* than the workload ({@link RESERVED_OIDC_CLAIMS}), since a matcher made of those constrains nothing either.
|
|
27
|
+
*
|
|
28
|
+
* ## Named claims, not the `sub` string
|
|
29
|
+
*
|
|
30
|
+
* A `sub` is a concatenation whose composition belongs to the provider and to the adopter's own template.
|
|
31
|
+
* The claims beneath it — GitHub's `repository_id`, `environment`, `ref`; GitLab's `project_id` — are
|
|
32
|
+
* published individually and are stable. So the matcher is a map of claim names to values, and `sub` is one
|
|
33
|
+
* claim among the others rather than a special case.
|
|
34
|
+
*
|
|
35
|
+
* ## No rotation, and revocation changes shape
|
|
36
|
+
*
|
|
37
|
+
* There is no key to append, prove and expire. A token cannot be revoked; the trust is, and every token
|
|
38
|
+
* already minted stays live until it expires — {@link TRUST_REVOCATION_LATENCY} is the sentence that says
|
|
39
|
+
* so at the moment it matters.
|
|
40
|
+
*
|
|
41
|
+
* Nothing in this module reads a clock, a binding or D1. `now` is injected wherever time matters.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Claims that name the token rather than the workload: who minted it, for whom, and when. A matcher built
|
|
45
|
+
* from these alone would accept every workload the issuer serves, so none of them may be registered.
|
|
46
|
+
* `iss` and `aud` are checked anyway, by the trust's own issuer and audience.
|
|
47
|
+
*/
|
|
48
|
+
export declare const RESERVED_OIDC_CLAIMS: readonly ["iss", "aud", "exp", "nbf", "iat", "jti"];
|
|
49
|
+
/** The most claims one trust may match on. Far above any real constraint; a bound on a stored row. */
|
|
50
|
+
export declare const MAX_TRUST_CLAIMS = 16;
|
|
51
|
+
/** The most claims a refusal records, so a token carrying a hundred cannot fill the audit trail. */
|
|
52
|
+
export declare const MAX_OBSERVED_CLAIMS = 32;
|
|
53
|
+
/** The longest claim value a matcher stores or a refusal records. */
|
|
54
|
+
export declare const MAX_CLAIM_VALUE = 256;
|
|
55
|
+
/**
|
|
56
|
+
* One claim name in a matcher. A name, not a path: nested claims are not matched, because a matcher that
|
|
57
|
+
* walks a structure is a matcher with more ways to be wrong on the check the whole trust rests on.
|
|
58
|
+
*/
|
|
59
|
+
export declare const OidcClaimName: z.ZodString;
|
|
60
|
+
export type OidcClaimName = z.infer<typeof OidcClaimName>;
|
|
61
|
+
/** One claim value in a matcher: compared as a string against the token's claim of the same name. */
|
|
62
|
+
export declare const OidcClaimValue: z.ZodString;
|
|
63
|
+
export type OidcClaimValue = z.infer<typeof OidcClaimValue>;
|
|
64
|
+
/**
|
|
65
|
+
* Which workloads a trust accepts: every named claim must equal its value.
|
|
66
|
+
*
|
|
67
|
+
* **At least one, and that is the refusal the whole credential kind rests on.** An issuer with no claim
|
|
68
|
+
* constraint accepts every workload it serves.
|
|
69
|
+
*/
|
|
70
|
+
export declare const OidcClaimMatch: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
71
|
+
export type OidcClaimMatch = z.infer<typeof OidcClaimMatch>;
|
|
72
|
+
/**
|
|
73
|
+
* One registered OIDC trust, an element of the connection's `trusts` column.
|
|
74
|
+
*
|
|
75
|
+
* Stored beside `keys` rather than inside it: the two kinds share nothing but the connection they grant
|
|
76
|
+
* through, and a union array would make every key reader learn about trusts.
|
|
77
|
+
*/
|
|
78
|
+
export declare const OidcTrust: z.ZodObject<{
|
|
79
|
+
trustId: z.ZodString;
|
|
80
|
+
issuer: z.ZodURL;
|
|
81
|
+
jwksUrl: z.ZodURL;
|
|
82
|
+
audience: z.ZodString;
|
|
83
|
+
claims: z.ZodRecord<z.ZodString, z.ZodString>;
|
|
84
|
+
authorizedBy: z.ZodEmail;
|
|
85
|
+
validFrom: z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>;
|
|
86
|
+
revokedAt: z.ZodNullable<z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>>;
|
|
87
|
+
firstCallAt: z.ZodNullable<z.ZodCodec<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodDate]>, z.ZodDate>>;
|
|
88
|
+
}, z.core.$strip>;
|
|
89
|
+
export type OidcTrust = z.output<typeof OidcTrust>;
|
|
90
|
+
/**
|
|
91
|
+
* What a caller should expect after a trust is revoked, said at the moment it is revoked rather than
|
|
92
|
+
* discovered afterwards.
|
|
93
|
+
*/
|
|
94
|
+
export declare const TRUST_REVOCATION_LATENCY = "A token cannot be revoked, only the trust. Every call naming this trust is refused from now on, but a token already minted stays in its holder's hands until it expires \u2014 the issuer's own lifetime, typically minutes.";
|
|
95
|
+
/** Every trust that may verify a call at `now`: not revoked, and started. */
|
|
96
|
+
export declare function activeTrusts(trusts: readonly OidcTrust[], now: Date): OidcTrust[];
|
|
97
|
+
/** The trust a call names, if it is live at `now`, or null. The revocation check lives here so no caller forgets it. */
|
|
98
|
+
export declare function findVerifyingTrust(trusts: readonly OidcTrust[], trustId: string, now: Date): OidcTrust | null;
|
|
99
|
+
/** Register a trust beside the others. A duplicate id is refused: the id is what a call addresses. */
|
|
100
|
+
export declare function appendTrust(trusts: readonly OidcTrust[], trust: OidcTrust): OidcTrust[];
|
|
101
|
+
/**
|
|
102
|
+
* Revoke one trust at `now`, or answer null when no trust answers to that id. A trust already revoked keeps
|
|
103
|
+
* the instant it was first revoked: the window a call was refused under must not move.
|
|
104
|
+
*/
|
|
105
|
+
export declare function revokeTrust(trusts: readonly OidcTrust[], trustId: string, now: Date): OidcTrust[] | null;
|
|
106
|
+
/**
|
|
107
|
+
* Whether a token's claims satisfy a trust's matcher: every registered claim present and equal.
|
|
108
|
+
*
|
|
109
|
+
* An empty matcher matches nothing. Registration refuses one, and this refuses it again rather than letting
|
|
110
|
+
* a hand-edited row vacuously admit every workload.
|
|
111
|
+
*/
|
|
112
|
+
export declare function claimsMatch(match: Readonly<Record<string, string>>, claims: Readonly<Record<string, unknown>>): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* The claims a refused token carried, as a refusal records them: the workload's claims, as strings, capped.
|
|
115
|
+
*
|
|
116
|
+
* This is what makes a custom issuer workable and a profiled one self-correcting — register, let the
|
|
117
|
+
* workload run once, read what it actually sent. Only ever called once the signature, issuer and audience
|
|
118
|
+
* have verified, so the caller demonstrably holds a genuine token for this audience and naming its claims
|
|
119
|
+
* leaks nothing it does not already hold.
|
|
120
|
+
*/
|
|
121
|
+
export declare function observedClaims(claims: Readonly<Record<string, unknown>>): Record<string, string>;
|
|
122
|
+
//# sourceMappingURL=oidcTrust.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidcTrust.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/data/oidcTrust.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,YAAI,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC;AAExF,sGAAsG;AACtG,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,oGAAoG;AACpG,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,qEAAqE;AACrE,eAAO,MAAM,eAAe,MAAM,CAAC;AAUnC;;;GAGG;AACH,eAAO,MAAM,aAAa,aAQvB,CAAC;AACJ,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC;AAE1D,qGAAqG;AACrG,eAAO,MAAM,cAAc,aAOxB,CAAC;AACJ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,cAAc,uCAUxB,CAAC;AACJ,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAK5D;;;;;GAKG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;iBAuCnB,CAAC;AACJ,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,SAAS,CAAC,CAAC;AAEnD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,iOACsL,CAAC;AAE5N,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,GAAG,EAAE,IAAI,GAAG,SAAS,EAAE,CAEjF;AAED,wHAAwH;AACxH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,SAAS,GAAG,IAAI,CAE7G;AAED,sGAAsG;AACtG,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS,EAAE,CASvF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,GAAG,SAAS,EAAE,GAAG,IAAI,CAKxG;AAUD;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACvC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxC,OAAO,CAIT;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUhG"}
|