@pithy-sh/core 0.13.0 → 0.15.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 +438 -3
- package/dist/cli/commandCatalog.generated.d.ts.map +1 -1
- package/dist/cli/commandCatalog.generated.js +454 -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 +487 -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
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
import type { Context } from "hono";
|
|
4
|
-
import type { PithyHonoEnv } from "../../capability/capability";
|
|
4
|
+
import type { Capability, PithyHonoEnv } from "../../capability/capability";
|
|
5
|
+
import type { RouteGroup } from "../../openapi/document";
|
|
6
|
+
import type { PresenceDeclaration } from "../../presence/declaration";
|
|
5
7
|
import type { PrivacyInventory } from "../../privacy/report";
|
|
6
8
|
import type { RetirementVerdict } from "../../privacy/retirement";
|
|
9
|
+
import type { EffectiveRetention } from "../../retention/policy";
|
|
7
10
|
import type { ControlPlaneConfig } from "../config/config";
|
|
8
|
-
import {
|
|
11
|
+
import type { ControlPlaneContext } from "../context";
|
|
12
|
+
import type { ControlPlaneDatabase } from "../data/tables";
|
|
9
13
|
import type { CapabilityDeclaration } from "../discovery/adminRoute";
|
|
10
14
|
import { type CapabilityHealthSource } from "../discovery/health";
|
|
11
15
|
import { type ComposedMigrationDatabase } from "../migrationState/migrationState";
|
|
12
|
-
import type { ExpireKeyParams, ExpireKeyRequest, RegisterKeyRequest } from "./schemas";
|
|
16
|
+
import type { ErasurePeriodQuery, ErasureSubjectParams, ExpireKeyParams, ExpireKeyRequest, RegisterKeyRequest } from "./schemas";
|
|
13
17
|
/** The pieces of the composed capability a handler needs. Passed in, so nothing reaches for a global. */
|
|
14
18
|
export interface ControlPlaneHandlerDeps {
|
|
15
19
|
/** The resolved seam config — pruning bounds, mostly. */
|
|
@@ -36,22 +40,44 @@ export interface ControlPlaneHandlerDeps {
|
|
|
36
40
|
composedHealth: () => ReadonlyMap<string, CapabilityHealthSource>;
|
|
37
41
|
/**
|
|
38
42
|
* Every database this Worker binds, with the provider this build composes for it — captured by the same
|
|
39
|
-
* `compose` hook through `collectMigrationSets`, the function `pithy migrate` composes with
|
|
43
|
+
* `compose` hook through `collectMigrationSets`, the function `pithy migrate` composes with.
|
|
40
44
|
*/
|
|
41
45
|
composedMigrations: () => readonly ComposedMigrationDatabase[];
|
|
42
46
|
/**
|
|
43
|
-
* The privacy inventory of every storage schema this Worker composed
|
|
47
|
+
* The privacy inventory of every storage schema this Worker composed, walked on the first call and
|
|
44
48
|
* cached for the isolate. A thunk, so a Worker whose control plane is never called never walks.
|
|
45
49
|
*/
|
|
46
50
|
privacyInventory: () => PrivacyInventory;
|
|
47
51
|
/**
|
|
48
|
-
* The field key's retirement verdict
|
|
52
|
+
* The field key's retirement verdict: the guard over this Worker's encrypted columns, read through its own
|
|
49
53
|
* bindings. Never throws: whatever it cannot read is incomplete coverage.
|
|
50
54
|
*/
|
|
51
55
|
retirement: (env: Record<string, unknown>) => Promise<RetirementVerdict>;
|
|
56
|
+
/**
|
|
57
|
+
* Every presence room kind this Worker composed, by kind, with the declaration that serves it — captured
|
|
58
|
+
* by the same `compose` hook. A thunk for the same reason as {@link composedCapabilities}.
|
|
59
|
+
*/
|
|
60
|
+
composedPresence: () => ReadonlyMap<string, PresenceDeclaration>;
|
|
61
|
+
/**
|
|
62
|
+
* Every capability this Worker composed, as the objects themselves — the evidence pack reads which one records
|
|
63
|
+
* audit events and the bindings it writes through. A thunk for the same reason as the rest.
|
|
64
|
+
*/
|
|
65
|
+
composition: () => readonly Capability[];
|
|
66
|
+
/**
|
|
67
|
+
* The route table `createBackend` recorded for the app these routes mounted on, or `undefined` for an app it did
|
|
68
|
+
* not assemble. Read per call, after every capability's routes have mounted, so the evidence pack sees them all.
|
|
69
|
+
*/
|
|
70
|
+
routeGroups: () => readonly RouteGroup[] | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* The retention block as this Worker resolved it at assembly, or null when no backend recorded one. The
|
|
73
|
+
* manifest reports it.
|
|
74
|
+
*/
|
|
75
|
+
retention?: () => EffectiveRetention | null;
|
|
52
76
|
/** The clock, injected so a test can stand at any instant. */
|
|
53
77
|
now: () => Date;
|
|
54
78
|
}
|
|
79
|
+
/** The verified caller. Never null here — `requireControlPlane` ran first, or this code is unreachable. */
|
|
80
|
+
export declare function caller(c: Context<PithyHonoEnv>): ControlPlaneContext;
|
|
55
81
|
/**
|
|
56
82
|
* `GET /control-plane/ping` — connectivity and key proof.
|
|
57
83
|
*
|
|
@@ -76,11 +102,11 @@ export declare function pingHandler(deps: ControlPlaneHandlerDeps): (c: Context<
|
|
|
76
102
|
* Discovery over configuration. A client builds its navigation from this rather than from settings
|
|
77
103
|
* someone maintains, so a Worker with no payments capability has no purchases pane as a matter of fact.
|
|
78
104
|
*
|
|
79
|
-
* **And the numbers a client would otherwise pay a second round trip for
|
|
105
|
+
* **And the numbers a client would otherwise pay a second round trip for**. Each capability's
|
|
80
106
|
* bounded summary is resolved here, behind the scope that capability's own read is behind: a connection
|
|
81
107
|
* without it gets no number rather than a zero, and never costs the adopter's Worker the query.
|
|
82
108
|
*
|
|
83
|
-
* **One capability's failure costs one capability's number
|
|
109
|
+
* **One capability's failure costs one capability's number**. A producer that throws, or that
|
|
84
110
|
* reports something its declaration cannot name, lands on `unavailable` for that entry alone —
|
|
85
111
|
* `readCapabilityHealth` catches it, so nothing rejects, so `Promise.all` still resolves and every
|
|
86
112
|
* sibling still reports. This route is what the whole management surface is built from; a manifest that
|
|
@@ -121,6 +147,11 @@ export declare function manifestHandler(deps: ControlPlaneHandlerDeps): (c: Cont
|
|
|
121
147
|
path: string;
|
|
122
148
|
scope: string | null;
|
|
123
149
|
summary: string;
|
|
150
|
+
kind?: "charges" | "credentials" | "deletes" | "reads" | "sends" | "writes" | undefined;
|
|
151
|
+
operation?: string | undefined;
|
|
152
|
+
input?: {
|
|
153
|
+
[x: string]: import("hono/utils/types").JSONValue;
|
|
154
|
+
} | undefined;
|
|
124
155
|
}[];
|
|
125
156
|
healthKeys: {
|
|
126
157
|
key: string;
|
|
@@ -142,11 +173,40 @@ export declare function manifestHandler(deps: ControlPlaneHandlerDeps): (c: Cont
|
|
|
142
173
|
config: {
|
|
143
174
|
[x: string]: string | number | boolean;
|
|
144
175
|
};
|
|
176
|
+
presenceRooms?: {
|
|
177
|
+
kind: string;
|
|
178
|
+
scope: string;
|
|
179
|
+
activities: string[];
|
|
180
|
+
maxParticipants: number;
|
|
181
|
+
sessionTicketPath: string | null;
|
|
182
|
+
socketPath: string;
|
|
183
|
+
}[] | undefined;
|
|
145
184
|
}[];
|
|
146
185
|
grantedScopes: string[];
|
|
186
|
+
retention?: {
|
|
187
|
+
purgeWindows: {
|
|
188
|
+
subject: "organization" | "user";
|
|
189
|
+
days: number;
|
|
190
|
+
source: "capability" | "floor" | "policy";
|
|
191
|
+
}[];
|
|
192
|
+
audit: {
|
|
193
|
+
defaultDays: number | null;
|
|
194
|
+
floorDays: number;
|
|
195
|
+
rules: {
|
|
196
|
+
prefix: string;
|
|
197
|
+
days: number;
|
|
198
|
+
source: "capability" | "floor" | "policy";
|
|
199
|
+
}[];
|
|
200
|
+
floored: string[];
|
|
201
|
+
};
|
|
202
|
+
classAges: {
|
|
203
|
+
class: string;
|
|
204
|
+
days: number;
|
|
205
|
+
}[];
|
|
206
|
+
} | undefined;
|
|
147
207
|
}, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
|
|
148
208
|
/**
|
|
149
|
-
* `GET /control-plane/migrations` — where each database this Worker binds stands
|
|
209
|
+
* `GET /control-plane/migrations` — where each database this Worker binds stands.
|
|
150
210
|
*
|
|
151
211
|
* Read-only: it reports, and nothing over the seam runs, reverses or resets a migration.
|
|
152
212
|
*
|
|
@@ -214,6 +274,18 @@ export declare function listKeysHandler(deps: ControlPlaneHandlerDeps): (c: Cont
|
|
|
214
274
|
authorizedBy: string | null;
|
|
215
275
|
actorKind: "agent" | "dashboard" | "script" | null;
|
|
216
276
|
purpose: string | null;
|
|
277
|
+
trusts: {
|
|
278
|
+
trustId: string;
|
|
279
|
+
issuer: string;
|
|
280
|
+
audience: string;
|
|
281
|
+
claims: {
|
|
282
|
+
[x: string]: string;
|
|
283
|
+
};
|
|
284
|
+
authorizedBy: string;
|
|
285
|
+
validFrom: string;
|
|
286
|
+
revokedAt: string | null;
|
|
287
|
+
firstCallAt: string | null;
|
|
288
|
+
}[];
|
|
217
289
|
}, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
|
|
218
290
|
/**
|
|
219
291
|
* `POST /control-plane/keys` — register a new public key, authenticated by the key it succeeds.
|
|
@@ -271,7 +343,7 @@ export declare function expireKeyHandler(deps: ControlPlaneHandlerDeps): (c: Con
|
|
|
271
343
|
}[];
|
|
272
344
|
}, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
|
|
273
345
|
/**
|
|
274
|
-
* `GET /control-plane/privacy` — the full privacy inventory
|
|
346
|
+
* `GET /control-plane/privacy` — the full privacy inventory.
|
|
275
347
|
*
|
|
276
348
|
* Every storage schema this Worker composed that holds a marked field, each field's path and class, and where it
|
|
277
349
|
* is stored — derived from the running code, so unmarking a field removes it on the next deploy with nothing in
|
|
@@ -318,4 +390,134 @@ export declare function privacyHandler(deps: ControlPlaneHandlerDeps): (c: Conte
|
|
|
318
390
|
}[];
|
|
319
391
|
}[];
|
|
320
392
|
}, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
|
|
393
|
+
/**
|
|
394
|
+
* `GET /control-plane/evidence` — the evidence pack.
|
|
395
|
+
*
|
|
396
|
+
* SOC 2 and ISO 27001 evidence derived from what this Worker composes, records and declares: each control's
|
|
397
|
+
* references, the facts read and their sources, and `evidenced`, `gap` or `not-derivable` with the reason. It
|
|
398
|
+
* proves controls present and performs nothing. Behind `evidence:read`, and it never widens another scope: what
|
|
399
|
+
* a capability keeps behind its own read stays there. Read-only.
|
|
400
|
+
*/
|
|
401
|
+
export declare function evidenceHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>) => Promise<Response & import("hono").TypedResponse<{
|
|
402
|
+
environment: string;
|
|
403
|
+
generatedAt: string;
|
|
404
|
+
version: string | null;
|
|
405
|
+
mappingVersion: number;
|
|
406
|
+
controls: {
|
|
407
|
+
control: "audit-logging" | "change-history" | "csrf" | "data-protection" | "key-rotation" | "management-access" | "route-verification";
|
|
408
|
+
title: string;
|
|
409
|
+
soc2: string[];
|
|
410
|
+
iso27001: string[];
|
|
411
|
+
state: "evidenced" | "gap" | "not-derivable";
|
|
412
|
+
reasons: string[];
|
|
413
|
+
facts: {
|
|
414
|
+
fact: string;
|
|
415
|
+
subject?: string | undefined;
|
|
416
|
+
value: string | number | boolean | string[] | null;
|
|
417
|
+
source: "auditRecorder" | "bindings" | "capabilityHealth" | "composition" | "connection" | "connectionKeys" | "encryptedMarkers" | "fieldKeyRetirement" | "migrationLedger" | "privacyAttestation" | "privacyMarkers" | "routeSpec" | "sameOriginGate";
|
|
418
|
+
}[];
|
|
419
|
+
}[];
|
|
420
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
|
|
421
|
+
/**
|
|
422
|
+
* `GET /control-plane/erasure/:subjectType/:subjectId` — one subject's erasure, attested.
|
|
423
|
+
*
|
|
424
|
+
* Read from the purge's own lifecycle rows, through the capability that owns the subject, and cited in the audit
|
|
425
|
+
* chain through the composed audit. A subject with no deletion in force is a 404. Read-only.
|
|
426
|
+
*/
|
|
427
|
+
export declare function erasureSubjectHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>, params: ErasureSubjectParams) => Promise<Response & import("hono").TypedResponse<{
|
|
428
|
+
generatedAt: string;
|
|
429
|
+
attestation: {
|
|
430
|
+
subject: {
|
|
431
|
+
type: "organization" | "user";
|
|
432
|
+
id: string;
|
|
433
|
+
};
|
|
434
|
+
deletion: {
|
|
435
|
+
at: string;
|
|
436
|
+
actorType: string;
|
|
437
|
+
reason: string | null;
|
|
438
|
+
mode: "hard" | "soft" | null;
|
|
439
|
+
purgeAfter: string | null;
|
|
440
|
+
audit: {
|
|
441
|
+
eventId: string;
|
|
442
|
+
action: string;
|
|
443
|
+
occurredAt: string;
|
|
444
|
+
tenant: string | null;
|
|
445
|
+
seq: number | null;
|
|
446
|
+
hash: string | null;
|
|
447
|
+
} | null;
|
|
448
|
+
};
|
|
449
|
+
state: "complete" | "failed" | "in_progress" | "scheduled";
|
|
450
|
+
overdue: boolean;
|
|
451
|
+
stoppedAt: string | null;
|
|
452
|
+
steps: {
|
|
453
|
+
capability: string;
|
|
454
|
+
disposition: "erased" | "retained";
|
|
455
|
+
reason: string | null;
|
|
456
|
+
summary: string | null;
|
|
457
|
+
completedAt: string;
|
|
458
|
+
audit: {
|
|
459
|
+
eventId: string;
|
|
460
|
+
action: string;
|
|
461
|
+
occurredAt: string;
|
|
462
|
+
tenant: string | null;
|
|
463
|
+
seq: number | null;
|
|
464
|
+
hash: string | null;
|
|
465
|
+
} | null;
|
|
466
|
+
}[];
|
|
467
|
+
completedAt: string | null;
|
|
468
|
+
completion: {
|
|
469
|
+
eventId: string;
|
|
470
|
+
action: string;
|
|
471
|
+
occurredAt: string;
|
|
472
|
+
tenant: string | null;
|
|
473
|
+
seq: number | null;
|
|
474
|
+
hash: string | null;
|
|
475
|
+
} | null;
|
|
476
|
+
failure: {
|
|
477
|
+
eventId: string;
|
|
478
|
+
action: string;
|
|
479
|
+
occurredAt: string;
|
|
480
|
+
tenant: string | null;
|
|
481
|
+
seq: number | null;
|
|
482
|
+
hash: string | null;
|
|
483
|
+
} | null;
|
|
484
|
+
trail: "absent" | "recorded";
|
|
485
|
+
};
|
|
486
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
|
|
487
|
+
/** `GET /control-plane/erasure?since&until` — every purge in a period, counted. Read-only. */
|
|
488
|
+
export declare function erasurePeriodHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>, query: ErasurePeriodQuery) => Promise<Response & import("hono").TypedResponse<{
|
|
489
|
+
generatedAt: string;
|
|
490
|
+
since: string;
|
|
491
|
+
until: string;
|
|
492
|
+
subjects: ("organization" | "user")[];
|
|
493
|
+
counts: {
|
|
494
|
+
scheduled: number;
|
|
495
|
+
inProgress: number;
|
|
496
|
+
complete: number;
|
|
497
|
+
failed: number;
|
|
498
|
+
overdue: number;
|
|
499
|
+
};
|
|
500
|
+
attention: {
|
|
501
|
+
subject: {
|
|
502
|
+
type: "organization" | "user";
|
|
503
|
+
id: string;
|
|
504
|
+
};
|
|
505
|
+
state: "complete" | "failed" | "in_progress" | "scheduled";
|
|
506
|
+
overdue: boolean;
|
|
507
|
+
purgeAfter: string | null;
|
|
508
|
+
completedAt: string | null;
|
|
509
|
+
stoppedAt: string | null;
|
|
510
|
+
}[];
|
|
511
|
+
purges: {
|
|
512
|
+
subject: {
|
|
513
|
+
type: "organization" | "user";
|
|
514
|
+
id: string;
|
|
515
|
+
};
|
|
516
|
+
state: "complete" | "failed" | "in_progress" | "scheduled";
|
|
517
|
+
overdue: boolean;
|
|
518
|
+
purgeAfter: string | null;
|
|
519
|
+
completedAt: string | null;
|
|
520
|
+
stoppedAt: string | null;
|
|
521
|
+
}[];
|
|
522
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
|
|
321
523
|
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/handlers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { commandName } from "../../cli/command.js";
|
|
4
|
+
import { ControlPlaneInvalidCredentialError, ControlPlaneKeyConflictError } from "../error/errors.js";
|
|
3
5
|
import { workerVersionMetadata } from "../../worker/identity.js";
|
|
4
|
-
import { ControlPlaneConnection } from "../data/connection.js";
|
|
5
|
-
import { CONTROL_PLANE_CONNECTIONS_TABLE } from "../data/tables.js";
|
|
6
6
|
import { healthWire } from "../discovery/healthSummary.js";
|
|
7
7
|
import { readCapabilityHealth } from "../discovery/health.js";
|
|
8
8
|
import { ControlPlaneAuditActions, safeEmit } from "../audit/actions.js";
|
|
9
|
-
import { ControlPlaneInvalidCredentialError, ControlPlaneKeyConflictError } from "../error/errors.js";
|
|
10
9
|
import { appendKey, expireKey, pruneKeys } from "../data/keyLifecycle.js";
|
|
11
10
|
import { privacyAttestation, privacyPosture } from "../../privacy/posture.js";
|
|
11
|
+
import { readConnectionForWrite, writeKeys } from "../data/connections.js";
|
|
12
12
|
import { causeMessage } from "../../error/cause.js";
|
|
13
|
+
import { routeInputs, withRouteInputs } from "../discovery/routeInput.js";
|
|
14
|
+
import { readErasurePeriod, readErasureSubject } from "../erasure/read.js";
|
|
13
15
|
import { readDatabaseMigrations } from "../migrationState/migrationState.js";
|
|
16
|
+
import { readEvidencePack } from "../evidence/pack.js";
|
|
14
17
|
//#region src/controlPlane/http/handlers.ts
|
|
15
18
|
/**
|
|
16
19
|
* The seam's own route handlers.
|
|
@@ -37,19 +40,23 @@ function caller(c) {
|
|
|
37
40
|
if (!context) throw new ControlPlaneInvalidCredentialError({ detail: "handler reached with no verified control-plane caller" });
|
|
38
41
|
return context;
|
|
39
42
|
}
|
|
40
|
-
/** Load the connection this call authenticated against. It verified moments ago
|
|
43
|
+
/** Load the connection this call authenticated against, as stored, for a key write. It verified moments ago. */
|
|
41
44
|
async function loadConnection(db, connectionId) {
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
return
|
|
45
|
+
const loaded = await readConnectionForWrite(db, connectionId);
|
|
46
|
+
if (loaded === null) throw new ControlPlaneInvalidCredentialError({ detail: `connection ${connectionId} disappeared mid-request` });
|
|
47
|
+
return loaded;
|
|
45
48
|
}
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Write a connection's key array back, stamping `updatedAt`. One UPDATE, so a rotation cannot half-apply, and only
|
|
51
|
+
* while the keys are still what `loaded` read: a revocation landing between the read and this write is never undone.
|
|
52
|
+
*/
|
|
53
|
+
async function saveKeys(db, loaded, keys, now) {
|
|
54
|
+
if (await writeKeys(db, loaded, keys, now)) return;
|
|
55
|
+
throw new ControlPlaneKeyConflictError({
|
|
56
|
+
message: "The connection's keys changed while this call ran.",
|
|
57
|
+
action: "Make the call again.",
|
|
58
|
+
detail: `connection ${loaded.connection.id} had its keys written between this call's read and its write`
|
|
59
|
+
});
|
|
53
60
|
}
|
|
54
61
|
/**
|
|
55
62
|
* The public view of one registered key. Windows and ages, never anything secret.
|
|
@@ -67,6 +74,35 @@ function publicKeyView(key) {
|
|
|
67
74
|
revokedAt: key.revokedAt?.toISOString() ?? null
|
|
68
75
|
};
|
|
69
76
|
}
|
|
77
|
+
/** The public view of one OIDC trust: its issuer, audience and claims — the population it admits. */
|
|
78
|
+
function trustView(trust) {
|
|
79
|
+
return {
|
|
80
|
+
trustId: trust.trustId,
|
|
81
|
+
issuer: trust.issuer,
|
|
82
|
+
audience: trust.audience,
|
|
83
|
+
claims: { ...trust.claims },
|
|
84
|
+
authorizedBy: trust.authorizedBy,
|
|
85
|
+
validFrom: trust.validFrom.toISOString(),
|
|
86
|
+
revokedAt: trust.revokedAt?.toISOString() ?? null,
|
|
87
|
+
firstCallAt: trust.firstCallAt?.toISOString() ?? null
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Refuse a key write to a caller that verified under an OIDC trust.
|
|
92
|
+
*
|
|
93
|
+
* A trust exists so that no key is held on the workload's host. Letting a trust's caller register a key would
|
|
94
|
+
* turn a short-lived identity into a standing credential at the first call — an exchange by another name, and
|
|
95
|
+
* the custody the trust was registered to avoid. Granting `keys:rotate` to a connection is a statement about
|
|
96
|
+
* its keys, never a license for a workload to mint one.
|
|
97
|
+
*/
|
|
98
|
+
function refuseTrustCaller(context, what) {
|
|
99
|
+
if (context.credentialKind !== "trust") return;
|
|
100
|
+
throw new ControlPlaneKeyConflictError({
|
|
101
|
+
message: "A call under a workload trust cannot change this connection's keys.",
|
|
102
|
+
action: `Register or expire a key from a client that holds one, or with ${commandName("dashboard connect")}.`,
|
|
103
|
+
detail: `${what} refused: trust ${context.keyId} verified this call`
|
|
104
|
+
});
|
|
105
|
+
}
|
|
70
106
|
/**
|
|
71
107
|
* `GET /control-plane/ping` — connectivity and key proof.
|
|
72
108
|
*
|
|
@@ -96,11 +132,11 @@ function pingHandler(deps) {
|
|
|
96
132
|
* Discovery over configuration. A client builds its navigation from this rather than from settings
|
|
97
133
|
* someone maintains, so a Worker with no payments capability has no purchases pane as a matter of fact.
|
|
98
134
|
*
|
|
99
|
-
* **And the numbers a client would otherwise pay a second round trip for
|
|
135
|
+
* **And the numbers a client would otherwise pay a second round trip for**. Each capability's
|
|
100
136
|
* bounded summary is resolved here, behind the scope that capability's own read is behind: a connection
|
|
101
137
|
* without it gets no number rather than a zero, and never costs the adopter's Worker the query.
|
|
102
138
|
*
|
|
103
|
-
* **One capability's failure costs one capability's number
|
|
139
|
+
* **One capability's failure costs one capability's number**. A producer that throws, or that
|
|
104
140
|
* reports something its declaration cannot name, lands on `unavailable` for that entry alone —
|
|
105
141
|
* `readCapabilityHealth` catches it, so nothing rejects, so `Promise.all` still resolves and every
|
|
106
142
|
* sibling still reports. This route is what the whole management surface is built from; a manifest that
|
|
@@ -108,10 +144,19 @@ function pingHandler(deps) {
|
|
|
108
144
|
* name.
|
|
109
145
|
*/
|
|
110
146
|
function manifestHandler(deps) {
|
|
147
|
+
let converted;
|
|
148
|
+
const inputsFor = (groups) => {
|
|
149
|
+
if (groups === void 0) return void 0;
|
|
150
|
+
if (converted?.groups !== groups) converted = {
|
|
151
|
+
groups,
|
|
152
|
+
inputs: routeInputs(groups)
|
|
153
|
+
};
|
|
154
|
+
return converted.inputs;
|
|
155
|
+
};
|
|
111
156
|
return async (c) => {
|
|
112
157
|
const context = caller(c);
|
|
113
158
|
const sources = deps.composedHealth();
|
|
114
|
-
const capabilities = await Promise.all(deps.composedCapabilities().map(async (declaration) => ({
|
|
159
|
+
const capabilities = await Promise.all(withRouteInputs(deps.composedCapabilities(), inputsFor(deps.routeGroups())).map(async (declaration) => ({
|
|
115
160
|
...declaration,
|
|
116
161
|
...healthWire(await readCapabilityHealth(sources.get(declaration.name), context.grantedScopes, (source) => source.read(c)))
|
|
117
162
|
})));
|
|
@@ -126,12 +171,18 @@ function manifestHandler(deps) {
|
|
|
126
171
|
retirement: await deps.retirement(c.env)
|
|
127
172
|
},
|
|
128
173
|
capabilities,
|
|
129
|
-
grantedScopes: [...context.grantedScopes]
|
|
174
|
+
grantedScopes: [...context.grantedScopes],
|
|
175
|
+
...retentionOf(deps)
|
|
130
176
|
});
|
|
131
177
|
};
|
|
132
178
|
}
|
|
179
|
+
/** The resolved retention for the manifest, or nothing where this Worker recorded none. */
|
|
180
|
+
function retentionOf(deps) {
|
|
181
|
+
const retention = deps.retention?.() ?? null;
|
|
182
|
+
return retention === null ? {} : { retention };
|
|
183
|
+
}
|
|
133
184
|
/**
|
|
134
|
-
* `GET /control-plane/migrations` — where each database this Worker binds stands
|
|
185
|
+
* `GET /control-plane/migrations` — where each database this Worker binds stands.
|
|
135
186
|
*
|
|
136
187
|
* Read-only: it reports, and nothing over the seam runs, reverses or resets a migration.
|
|
137
188
|
*
|
|
@@ -165,7 +216,8 @@ function listKeysHandler(deps) {
|
|
|
165
216
|
keys: connection.keys.map(publicKeyView),
|
|
166
217
|
authorizedBy: connection.authorizedBy,
|
|
167
218
|
actorKind: connection.actorKind,
|
|
168
|
-
purpose: connection.purpose
|
|
219
|
+
purpose: connection.purpose,
|
|
220
|
+
trusts: (connection.trusts ?? []).map(trustView)
|
|
169
221
|
});
|
|
170
222
|
};
|
|
171
223
|
}
|
|
@@ -182,9 +234,11 @@ function listKeysHandler(deps) {
|
|
|
182
234
|
function registerKeyHandler(deps) {
|
|
183
235
|
return async (c, body) => {
|
|
184
236
|
const context = caller(c);
|
|
237
|
+
refuseTrustCaller(context, "key registration");
|
|
185
238
|
const db = deps.database(c);
|
|
186
239
|
const now = deps.now();
|
|
187
|
-
const
|
|
240
|
+
const loaded = await loadConnection(db, context.connectionId);
|
|
241
|
+
const { connection } = loaded;
|
|
188
242
|
const appended = appendKey(connection.keys, {
|
|
189
243
|
keyId: body.keyId,
|
|
190
244
|
publicKey: body.publicKey,
|
|
@@ -197,7 +251,7 @@ function registerKeyHandler(deps) {
|
|
|
197
251
|
retentionMs: deps.config.keyRetentionDays * MS_PER_DAY,
|
|
198
252
|
maxKeys: deps.config.maxKeys
|
|
199
253
|
});
|
|
200
|
-
await saveKeys(db,
|
|
254
|
+
await saveKeys(db, loaded, pruned, now);
|
|
201
255
|
await safeEmit(c.var.emit, {
|
|
202
256
|
action: ControlPlaneAuditActions.keyRegistered,
|
|
203
257
|
outcome: "success",
|
|
@@ -241,9 +295,11 @@ function registerKeyHandler(deps) {
|
|
|
241
295
|
function expireKeyHandler(deps) {
|
|
242
296
|
return async (c, params, body) => {
|
|
243
297
|
const context = caller(c);
|
|
298
|
+
refuseTrustCaller(context, "key expiry");
|
|
244
299
|
const db = deps.database(c);
|
|
245
300
|
const now = deps.now();
|
|
246
|
-
const
|
|
301
|
+
const loaded = await loadConnection(db, context.connectionId);
|
|
302
|
+
const { connection } = loaded;
|
|
247
303
|
if (body.provenKeyId !== context.keyId) throw new ControlPlaneKeyConflictError({
|
|
248
304
|
message: "Sign this request with the replacement key you are naming as proven.",
|
|
249
305
|
action: "Rotate to the new key, make a call with it, then expire the old one in that same call.",
|
|
@@ -253,7 +309,7 @@ function expireKeyHandler(deps) {
|
|
|
253
309
|
provenKeyId: body.provenKeyId,
|
|
254
310
|
now
|
|
255
311
|
});
|
|
256
|
-
await saveKeys(db,
|
|
312
|
+
await saveKeys(db, loaded, expired, now);
|
|
257
313
|
await safeEmit(c.var.emit, {
|
|
258
314
|
action: ControlPlaneAuditActions.keyExpired,
|
|
259
315
|
outcome: "success",
|
|
@@ -280,7 +336,7 @@ function expireKeyHandler(deps) {
|
|
|
280
336
|
};
|
|
281
337
|
}
|
|
282
338
|
/**
|
|
283
|
-
* `GET /control-plane/privacy` — the full privacy inventory
|
|
339
|
+
* `GET /control-plane/privacy` — the full privacy inventory.
|
|
284
340
|
*
|
|
285
341
|
* Every storage schema this Worker composed that holds a marked field, each field's path and class, and where it
|
|
286
342
|
* is stored — derived from the running code, so unmarking a field removes it on the next deploy with nothing in
|
|
@@ -306,5 +362,40 @@ function privacyHandler(deps) {
|
|
|
306
362
|
});
|
|
307
363
|
};
|
|
308
364
|
}
|
|
365
|
+
/**
|
|
366
|
+
* `GET /control-plane/evidence` — the evidence pack.
|
|
367
|
+
*
|
|
368
|
+
* SOC 2 and ISO 27001 evidence derived from what this Worker composes, records and declares: each control's
|
|
369
|
+
* references, the facts read and their sources, and `evidenced`, `gap` or `not-derivable` with the reason. It
|
|
370
|
+
* proves controls present and performs nothing. Behind `evidence:read`, and it never widens another scope: what
|
|
371
|
+
* a capability keeps behind its own read stays there. Read-only.
|
|
372
|
+
*/
|
|
373
|
+
function evidenceHandler(deps) {
|
|
374
|
+
return async (c) => {
|
|
375
|
+
const context = caller(c);
|
|
376
|
+
return c.json(await readEvidencePack(c, deps, context));
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* `GET /control-plane/erasure/:subjectType/:subjectId` — one subject's erasure, attested.
|
|
381
|
+
*
|
|
382
|
+
* Read from the purge's own lifecycle rows, through the capability that owns the subject, and cited in the audit
|
|
383
|
+
* chain through the composed audit. A subject with no deletion in force is a 404. Read-only.
|
|
384
|
+
*/
|
|
385
|
+
function erasureSubjectHandler(deps) {
|
|
386
|
+
return async (c, params) => {
|
|
387
|
+
caller(c);
|
|
388
|
+
const env = c.env ?? {};
|
|
389
|
+
return c.json(await readErasureSubject(env, deps, params.subjectType, params.subjectId));
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
/** `GET /control-plane/erasure?since&until` — every purge in a period, counted. Read-only. */
|
|
393
|
+
function erasurePeriodHandler(deps) {
|
|
394
|
+
return async (c, query) => {
|
|
395
|
+
caller(c);
|
|
396
|
+
const env = c.env ?? {};
|
|
397
|
+
return c.json(await readErasurePeriod(env, deps, query));
|
|
398
|
+
};
|
|
399
|
+
}
|
|
309
400
|
//#endregion
|
|
310
|
-
export { expireKeyHandler, listKeysHandler, manifestHandler, migrationsHandler, pingHandler, privacyHandler, registerKeyHandler };
|
|
401
|
+
export { caller, erasurePeriodHandler, erasureSubjectHandler, evidenceHandler, expireKeyHandler, listKeysHandler, manifestHandler, migrationsHandler, pingHandler, privacyHandler, registerKeyHandler };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 Pithy
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
import type { Context } from "hono";
|
|
4
|
+
import type { PithyHonoEnv } from "../../capability/capability";
|
|
5
|
+
import type { LegalHold } from "../data/hold";
|
|
6
|
+
import { type ControlPlaneHandlerDeps } from "./handlers";
|
|
7
|
+
import type { LegalHoldView } from "./responses";
|
|
8
|
+
import type { HoldListQuery, HoldParams, PlaceHoldRequest, ReleaseHoldRequest } from "./schemas";
|
|
9
|
+
/** A hold, as the routes answer it. */
|
|
10
|
+
export declare function holdView(hold: LegalHold): LegalHoldView;
|
|
11
|
+
/** `POST /control-plane/holds` — place a hold. */
|
|
12
|
+
export declare function placeHoldHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>, body: PlaceHoldRequest) => Promise<Response & import("hono").TypedResponse<{
|
|
13
|
+
hold: {
|
|
14
|
+
id: string;
|
|
15
|
+
subjectType: "audit" | "organization" | "user";
|
|
16
|
+
subjectId: string | null;
|
|
17
|
+
reason: string;
|
|
18
|
+
placedBy: string;
|
|
19
|
+
placedAt: string;
|
|
20
|
+
state: "active" | "released";
|
|
21
|
+
releasedAt: string | null;
|
|
22
|
+
releasedBy: string | null;
|
|
23
|
+
releaseReason: string | null;
|
|
24
|
+
};
|
|
25
|
+
}, 201, "json">>;
|
|
26
|
+
/** `POST /control-plane/holds/:holdId/release` — release a hold, with a reason. */
|
|
27
|
+
export declare function releaseHoldHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>, params: HoldParams, body: ReleaseHoldRequest) => Promise<Response & import("hono").TypedResponse<{
|
|
28
|
+
hold: {
|
|
29
|
+
id: string;
|
|
30
|
+
subjectType: "audit" | "organization" | "user";
|
|
31
|
+
subjectId: string | null;
|
|
32
|
+
reason: string;
|
|
33
|
+
placedBy: string;
|
|
34
|
+
placedAt: string;
|
|
35
|
+
state: "active" | "released";
|
|
36
|
+
releasedAt: string | null;
|
|
37
|
+
releasedBy: string | null;
|
|
38
|
+
releaseReason: string | null;
|
|
39
|
+
};
|
|
40
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
|
|
41
|
+
/** `GET /control-plane/holds` — every hold, standing first. Read-only. */
|
|
42
|
+
export declare function listHoldsHandler(deps: ControlPlaneHandlerDeps): (c: Context<PithyHonoEnv>, query: HoldListQuery) => Promise<Response & import("hono").TypedResponse<{
|
|
43
|
+
active: number;
|
|
44
|
+
holds: {
|
|
45
|
+
id: string;
|
|
46
|
+
subjectType: "audit" | "organization" | "user";
|
|
47
|
+
subjectId: string | null;
|
|
48
|
+
reason: string;
|
|
49
|
+
placedBy: string;
|
|
50
|
+
placedAt: string;
|
|
51
|
+
state: "active" | "released";
|
|
52
|
+
releasedAt: string | null;
|
|
53
|
+
releasedBy: string | null;
|
|
54
|
+
releaseReason: string | null;
|
|
55
|
+
}[];
|
|
56
|
+
}, import("hono/utils/http-status").ContentfulStatusCode, "json">>;
|
|
57
|
+
//# sourceMappingURL=holds.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"holds.d.ts","sourceRoot":"","sources":["../../../src/controlPlane/http/holds.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,KAAK,uBAAuB,EAAU,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAuD,aAAa,EAAE,MAAM,aAAa,CAAC;AACtG,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAcjG,uCAAuC;AACvC,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,aAAa,CAavD;AAwBD,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,OAC3C,OAAO,CAAC,YAAY,CAAC,QAAQ,gBAAgB;;;;;;;;;;;;;iBAY/D;AAED,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,uBAAuB,OAC7C,OAAO,CAAC,YAAY,CAAC,UAAU,UAAU,QAAQ,kBAAkB;;;;;;;;;;;;;mEAWrF;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,OAC3C,OAAO,CAAC,YAAY,CAAC,SAAS,aAAa;;;;;;;;;;;;;;mEAY7D"}
|