@pikku/core 0.12.71 → 0.12.74
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/CHANGELOG.md +848 -0
- package/dist/crypto-utils.d.ts +30 -5
- package/dist/crypto-utils.js +146 -41
- package/dist/dev/hot-reload.js +11 -30
- package/dist/dev/module-runner.d.ts +3 -7
- package/dist/dev/module-runner.js +4 -10
- package/dist/dev/reload-meta.d.ts +8 -20
- package/dist/dev/reload-meta.js +9 -29
- package/dist/errors/error-handler.d.ts +5 -30
- package/dist/errors/error-handler.js +16 -32
- package/dist/errors/errors.d.ts +32 -151
- package/dist/errors/errors.js +55 -157
- package/dist/function/abort-scope.d.ts +47 -0
- package/dist/function/abort-scope.js +63 -0
- package/dist/function/function-runner.js +40 -30
- package/dist/function/functions.types.d.ts +44 -136
- package/dist/function/functions.types.js +0 -58
- package/dist/function/list.types.d.ts +12 -62
- package/dist/function/list.types.js +4 -25
- package/dist/handle-error.d.ts +0 -11
- package/dist/handle-error.js +6 -18
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/middleware/auth-apikey.d.ts +3 -18
- package/dist/middleware/auth-apikey.js +0 -17
- package/dist/middleware/auth-bearer.d.ts +6 -41
- package/dist/middleware/auth-bearer.js +3 -40
- package/dist/middleware/auth-cookie.d.ts +5 -27
- package/dist/middleware/auth-cookie.js +2 -26
- package/dist/middleware/cors.d.ts +7 -34
- package/dist/middleware/cors.js +7 -34
- package/dist/middleware/remote-auth.d.ts +3 -1
- package/dist/middleware/remote-auth.js +3 -2
- package/dist/middleware/telemetry.d.ts +8 -33
- package/dist/middleware/telemetry.js +2 -31
- package/dist/middleware-runner.d.ts +4 -55
- package/dist/middleware-runner.js +5 -74
- package/dist/permissions.d.ts +3 -44
- package/dist/permissions.js +19 -71
- package/dist/pikku-request.d.ts +0 -6
- package/dist/pikku-request.js +0 -6
- package/dist/pikku-state.d.ts +0 -26
- package/dist/pikku-state.js +2 -30
- package/dist/remote.d.ts +3 -5
- package/dist/remote.js +8 -7
- package/dist/schema.d.ts +7 -17
- package/dist/schema.js +30 -18
- package/dist/scopes.d.ts +4 -23
- package/dist/scopes.js +7 -48
- package/dist/services/ai-agent-runner-service.d.ts +20 -0
- package/dist/services/ai-embedding-service.d.ts +2 -25
- package/dist/services/audit-service.js +1 -2
- package/dist/services/content-service.d.ts +1 -46
- package/dist/services/credential-service.d.ts +3 -40
- package/dist/services/deployment-service.d.ts +3 -9
- package/dist/services/gateway-service.d.ts +0 -15
- package/dist/services/http-personas.d.ts +80 -0
- package/dist/services/http-personas.js +233 -0
- package/dist/services/in-memory-queue-service.d.ts +0 -14
- package/dist/services/in-memory-queue-service.js +1 -15
- package/dist/services/in-memory-trigger-service.d.ts +0 -18
- package/dist/services/in-memory-trigger-service.js +1 -18
- package/dist/services/in-memory-workflow-service.d.ts +0 -16
- package/dist/services/in-memory-workflow-service.js +4 -33
- package/dist/services/index.d.ts +5 -6
- package/dist/services/index.js +2 -5
- package/dist/services/istanbul-coverage-service.d.ts +1 -5
- package/dist/services/istanbul-coverage-service.js +2 -8
- package/dist/services/jwt-service.d.ts +1 -16
- package/dist/services/local-content.d.ts +13 -2
- package/dist/services/local-content.js +40 -13
- package/dist/services/local-gateway-service.d.ts +0 -16
- package/dist/services/local-gateway-service.js +2 -17
- package/dist/services/local-secrets.d.ts +0 -4
- package/dist/services/local-secrets.js +0 -4
- package/dist/services/logger-console.d.ts +3 -7
- package/dist/services/logger-console.js +3 -7
- package/dist/services/logger.d.ts +2 -37
- package/dist/services/meta-service.d.ts +23 -26
- package/dist/services/meta-service.js +22 -36
- package/dist/services/personas-service.d.ts +134 -0
- package/dist/services/personas-service.js +40 -0
- package/dist/services/pikku-user-id.js +0 -4
- package/dist/services/queue-webhook-service.d.ts +2 -36
- package/dist/services/queue-webhook-service.js +9 -41
- package/dist/services/scheduler-service.d.ts +1 -50
- package/dist/services/scheduler-service.js +0 -10
- package/dist/services/schema-service.d.ts +1 -24
- package/dist/services/scope-service.d.ts +49 -34
- package/dist/services/scoped-secret-service.d.ts +0 -4
- package/dist/services/scoped-secret-service.js +0 -4
- package/dist/services/secret-host-binding.d.ts +8 -0
- package/dist/services/secret-host-binding.js +36 -0
- package/dist/services/secret-service.d.ts +5 -33
- package/dist/services/secretless.d.ts +6 -0
- package/dist/services/secretless.js +21 -0
- package/dist/services/stub-tracker.d.ts +7 -18
- package/dist/services/stub-tracker.js +8 -18
- package/dist/services/system-role-guard.d.ts +33 -0
- package/dist/services/system-role-guard.js +38 -0
- package/dist/services/trigger-service.d.ts +0 -12
- package/dist/services/typed-secret-service.d.ts +0 -7
- package/dist/services/typed-secret-service.js +1 -7
- package/dist/services/v8-coverage-service.d.ts +2 -3
- package/dist/services/v8-coverage-service.js +1 -2
- package/dist/services/variables-service.d.ts +1 -8
- package/dist/services/webhook-service.d.ts +19 -63
- package/dist/services/webhook-service.js +6 -20
- package/dist/services/workflow-service.d.ts +3 -15
- package/dist/testing/service-tests.js +0 -17
- package/dist/time-utils.d.ts +0 -16
- package/dist/time-utils.js +1 -19
- package/dist/types/core.types.d.ts +99 -219
- package/dist/types/core.types.js +0 -42
- package/dist/types/state.types.d.ts +4 -9
- package/dist/utils/hmac.d.ts +4 -10
- package/dist/utils/hmac.js +4 -10
- package/dist/utils/safe-fetch.d.ts +7 -35
- package/dist/utils/safe-fetch.js +13 -53
- package/dist/utils.d.ts +1 -6
- package/dist/utils.js +6 -15
- package/dist/wirings/actor-flow/actor-flow.types.d.ts +1 -34
- package/dist/wirings/actor-flow/index.d.ts +0 -9
- package/dist/wirings/actor-flow/run-conversation.d.ts +5 -5
- package/dist/wirings/actor-flow/run-conversation.js +14 -7
- package/dist/wirings/ai-agent/ai-agent-agui.d.ts +0 -5
- package/dist/wirings/ai-agent/ai-agent-agui.js +34 -12
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +7 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.js +7 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.d.ts +153 -0
- package/dist/wirings/ai-agent/ai-agent-interrupt.js +256 -0
- package/dist/wirings/ai-agent/ai-agent-memory.js +0 -2
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +0 -9
- package/dist/wirings/ai-agent/ai-agent-model-config.js +1 -9
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +10 -99
- package/dist/wirings/ai-agent/ai-agent-prepare.js +58 -131
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +2 -1
- package/dist/wirings/ai-agent/ai-agent-registry.js +5 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +49 -20
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +25 -2
- package/dist/wirings/ai-agent/ai-agent-stream.js +153 -63
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +84 -4
- package/dist/wirings/ai-agent/index.d.ts +6 -4
- package/dist/wirings/ai-agent/index.js +5 -4
- package/dist/wirings/ai-agent/voice-input.d.ts +39 -1
- package/dist/wirings/ai-agent/voice-input.js +46 -3
- package/dist/wirings/ai-agent/voice-output.d.ts +54 -1
- package/dist/wirings/ai-agent/voice-output.js +153 -50
- package/dist/wirings/channel/channel-common.d.ts +7 -20
- package/dist/wirings/channel/channel-common.js +7 -21
- package/dist/wirings/channel/channel-handler.js +25 -6
- package/dist/wirings/channel/channel-host-rpc.d.ts +25 -0
- package/dist/wirings/channel/channel-host-rpc.js +38 -0
- package/dist/wirings/channel/channel-middleware-runner.d.ts +0 -12
- package/dist/wirings/channel/channel-middleware-runner.js +0 -12
- package/dist/wirings/channel/channel-rpc-registry.d.ts +31 -0
- package/dist/wirings/channel/channel-rpc-registry.js +89 -0
- package/dist/wirings/channel/channel-rpc-responder.d.ts +15 -0
- package/dist/wirings/channel/channel-rpc-responder.js +71 -0
- package/dist/wirings/channel/channel-rpc-service.d.ts +40 -0
- package/dist/wirings/channel/channel-rpc-service.js +106 -0
- package/dist/wirings/channel/channel-rpc-validators.d.ts +14 -0
- package/dist/wirings/channel/channel-rpc-validators.js +30 -0
- package/dist/wirings/channel/channel-rpc.d.ts +5 -0
- package/dist/wirings/channel/channel-rpc.js +5 -0
- package/dist/wirings/channel/channel-rpc.types.d.ts +90 -0
- package/dist/wirings/channel/channel-rpc.types.js +50 -0
- package/dist/wirings/channel/channel-runner.d.ts +0 -4
- package/dist/wirings/channel/channel-runner.js +0 -14
- package/dist/wirings/channel/channel-store.d.ts +0 -10
- package/dist/wirings/channel/channel.types.d.ts +12 -1
- package/dist/wirings/channel/define-channel-routes.d.ts +0 -20
- package/dist/wirings/channel/define-channel-routes.js +0 -20
- package/dist/wirings/channel/eventhub-service.d.ts +0 -18
- package/dist/wirings/channel/index.d.ts +4 -1
- package/dist/wirings/channel/index.js +2 -0
- package/dist/wirings/channel/local/local-channel-runner.js +3 -1
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +0 -33
- package/dist/wirings/channel/local/local-eventhub-service.js +2 -36
- package/dist/wirings/channel/log-channels.d.ts +0 -4
- package/dist/wirings/channel/log-channels.js +0 -4
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +6 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +2 -5
- package/dist/wirings/cli/channel/cli-approval.d.ts +41 -0
- package/dist/wirings/cli/channel/cli-approval.js +81 -0
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +0 -4
- package/dist/wirings/cli/channel/cli-channel-runner.js +3 -25
- package/dist/wirings/cli/channel/cli-raw-channel-runner.d.ts +47 -9
- package/dist/wirings/cli/channel/cli-raw-channel-runner.js +24 -16
- package/dist/wirings/cli/channel/cli-raw-client-runner.d.ts +20 -0
- package/dist/wirings/cli/channel/cli-raw-client-runner.js +121 -0
- package/dist/wirings/cli/channel/index.d.ts +4 -0
- package/dist/wirings/cli/channel/index.js +2 -0
- package/dist/wirings/cli/cli-runner.d.ts +20 -20
- package/dist/wirings/cli/cli-runner.js +28 -89
- package/dist/wirings/cli/cli.types.d.ts +14 -3
- package/dist/wirings/cli/command-parser.d.ts +1 -10
- package/dist/wirings/cli/command-parser.js +10 -87
- package/dist/wirings/cli/define-cli-commands.d.ts +1 -17
- package/dist/wirings/cli/define-cli-commands.js +1 -17
- package/dist/wirings/credential/credential.types.d.ts +0 -12
- package/dist/wirings/credential/define-credential.d.ts +48 -0
- package/dist/wirings/credential/define-credential.js +47 -0
- package/dist/wirings/credential/index.d.ts +1 -1
- package/dist/wirings/credential/index.js +1 -1
- package/dist/wirings/credential/validate-credential-definitions.d.ts +2 -4
- package/dist/wirings/gateway/gateway-runner.d.ts +1 -20
- package/dist/wirings/gateway/gateway-runner.js +8 -105
- package/dist/wirings/gateway/gateway.types.d.ts +7 -80
- package/dist/wirings/http/http-routes.d.ts +0 -63
- package/dist/wirings/http/http-routes.js +0 -63
- package/dist/wirings/http/http-runner.d.ts +1 -100
- package/dist/wirings/http/http-runner.js +12 -166
- package/dist/wirings/http/http.types.d.ts +16 -55
- package/dist/wirings/http/index.d.ts +2 -1
- package/dist/wirings/http/index.js +1 -1
- package/dist/wirings/http/log-http-routes.d.ts +0 -4
- package/dist/wirings/http/log-http-routes.js +0 -4
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +6 -36
- package/dist/wirings/http/pikku-fetch-http-request.js +56 -50
- package/dist/wirings/http/pikku-fetch-http-response.js +0 -3
- package/dist/wirings/http/routers/path-to-regex.js +2 -13
- package/dist/wirings/http/web-request.d.ts +0 -8
- package/dist/wirings/http/web-request.js +25 -17
- package/dist/wirings/mcp/mcp-runner.d.ts +2 -0
- package/dist/wirings/mcp/mcp-runner.js +6 -16
- package/dist/wirings/mcp/mcp.types.d.ts +2 -35
- package/dist/wirings/oauth2/oauth2.types.d.ts +0 -28
- package/dist/wirings/oauth2/oauth2.types.js +0 -3
- package/dist/wirings/persona/define-personas.d.ts +28 -0
- package/dist/wirings/persona/define-personas.js +27 -0
- package/dist/wirings/persona/index.d.ts +21 -0
- package/dist/wirings/persona/index.js +17 -0
- package/dist/wirings/persona/persona-email.d.ts +37 -0
- package/dist/wirings/persona/persona-email.js +69 -0
- package/dist/wirings/persona/persona-environments.d.ts +45 -0
- package/dist/wirings/persona/persona-environments.js +81 -0
- package/dist/wirings/persona/persona-mailbox.d.ts +101 -0
- package/dist/wirings/persona/persona-mailbox.js +53 -0
- package/dist/wirings/persona/persona.types.d.ts +125 -0
- package/dist/wirings/persona/persona.types.js +1 -0
- package/dist/wirings/persona/validate-personas.d.ts +53 -0
- package/dist/wirings/persona/validate-personas.js +94 -0
- package/dist/wirings/queue/index.d.ts +3 -0
- package/dist/wirings/queue/index.js +2 -3
- package/dist/wirings/queue/queue-identity.d.ts +28 -0
- package/dist/wirings/queue/queue-identity.js +102 -0
- package/dist/wirings/queue/queue-runner.d.ts +0 -19
- package/dist/wirings/queue/queue-runner.js +9 -30
- package/dist/wirings/queue/queue.types.d.ts +18 -89
- package/dist/wirings/queue/register-queue-helper.d.ts +0 -12
- package/dist/wirings/queue/register-queue-helper.js +0 -11
- package/dist/wirings/queue/signed-queue-service.d.ts +16 -0
- package/dist/wirings/queue/signed-queue-service.js +42 -0
- package/dist/wirings/queue/validate-worker-config.d.ts +2 -23
- package/dist/wirings/queue/validate-worker-config.js +0 -14
- package/dist/wirings/role/define-system-role.d.ts +32 -0
- package/dist/wirings/role/define-system-role.js +31 -0
- package/dist/wirings/role/index.d.ts +3 -0
- package/dist/wirings/role/index.js +2 -0
- package/dist/wirings/role/role.types.d.ts +43 -0
- package/dist/wirings/role/role.types.js +1 -0
- package/dist/wirings/role/validate-role-definitions.d.ts +21 -0
- package/dist/wirings/role/validate-role-definitions.js +71 -0
- package/dist/wirings/rpc/addon-runner.d.ts +0 -19
- package/dist/wirings/rpc/addon-runner.js +0 -51
- package/dist/wirings/rpc/remote-addon-auth.d.ts +1 -12
- package/dist/wirings/rpc/remote-addon-auth.js +1 -9
- package/dist/wirings/rpc/rpc-runner.d.ts +11 -18
- package/dist/wirings/rpc/rpc-runner.js +88 -105
- package/dist/wirings/rpc/rpc-types.d.ts +7 -6
- package/dist/wirings/rpc/wire-addon.d.ts +25 -0
- package/dist/wirings/rpc/wire-addon.js +62 -0
- package/dist/wirings/rpc/wire-remote-addon.d.ts +3 -28
- package/dist/wirings/rpc/wire-remote-addon.js +0 -8
- package/dist/wirings/scheduler/log-schedulers.d.ts +0 -4
- package/dist/wirings/scheduler/log-schedulers.js +0 -4
- package/dist/wirings/scheduler/scheduler-runner.d.ts +0 -1
- package/dist/wirings/scheduler/scheduler-runner.js +0 -1
- package/dist/wirings/scheduler/scheduler.types.d.ts +1 -14
- package/dist/wirings/scope/define-scope.d.ts +32 -0
- package/dist/wirings/scope/define-scope.js +31 -0
- package/dist/wirings/scope/index.d.ts +1 -1
- package/dist/wirings/scope/index.js +1 -1
- package/dist/wirings/scope/scope.types.d.ts +7 -9
- package/dist/wirings/scope/validate-scope-definitions.d.ts +2 -21
- package/dist/wirings/scope/validate-scope-definitions.js +3 -21
- package/dist/wirings/secret/index.d.ts +1 -1
- package/dist/wirings/secret/index.js +1 -1
- package/dist/wirings/secret/secret.types.d.ts +19 -15
- package/dist/wirings/secret/secret.types.js +1 -1
- package/dist/wirings/secret/validate-secret-definitions.d.ts +2 -4
- package/dist/wirings/trigger/trigger-runner.d.ts +0 -27
- package/dist/wirings/trigger/trigger-runner.js +1 -24
- package/dist/wirings/trigger/trigger.types.d.ts +1 -82
- package/dist/wirings/trigger/trigger.types.js +0 -34
- package/dist/wirings/variable/index.d.ts +1 -1
- package/dist/wirings/variable/index.js +1 -1
- package/dist/wirings/variable/validate-variable-definitions.d.ts +2 -4
- package/dist/wirings/variable/variable.types.d.ts +1 -13
- package/dist/wirings/variable/variable.types.js +1 -1
- package/dist/wirings/virtual-user/index.d.ts +27 -0
- package/dist/wirings/virtual-user/index.js +8 -0
- package/dist/wirings/virtual-user/run-virtual-user.d.ts +92 -0
- package/dist/wirings/virtual-user/run-virtual-user.js +478 -0
- package/dist/wirings/virtual-user/virtual-user-agents.d.ts +38 -0
- package/dist/wirings/virtual-user/virtual-user-agents.js +24 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.d.ts +92 -0
- package/dist/wirings/virtual-user/virtual-user-catalogue.js +134 -0
- package/dist/wirings/virtual-user/virtual-user-derive.d.ts +26 -0
- package/dist/wirings/virtual-user/virtual-user-derive.js +137 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.d.ts +79 -0
- package/dist/wirings/virtual-user/virtual-user-dispositions.js +128 -0
- package/dist/wirings/virtual-user/virtual-user-intents.d.ts +78 -0
- package/dist/wirings/virtual-user/virtual-user-intents.js +142 -0
- package/dist/wirings/virtual-user/virtual-user-rng.d.ts +24 -0
- package/dist/wirings/virtual-user/virtual-user-rng.js +44 -0
- package/dist/wirings/virtual-user/virtual-user-target.d.ts +21 -0
- package/dist/wirings/virtual-user/virtual-user-target.js +34 -0
- package/dist/wirings/virtual-user/virtual-user.types.d.ts +199 -0
- package/dist/wirings/virtual-user/virtual-user.types.js +8 -0
- package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +5 -5
- package/dist/wirings/workflow/dsl/workflow-runner.d.ts +0 -4
- package/dist/wirings/workflow/dsl/workflow-runner.js +0 -4
- package/dist/wirings/workflow/feature.d.ts +0 -19
- package/dist/wirings/workflow/feature.js +0 -19
- package/dist/wirings/workflow/graph/graph-node.d.ts +0 -98
- package/dist/wirings/workflow/graph/graph-node.js +0 -34
- package/dist/wirings/workflow/graph/graph-runner.js +6 -41
- package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +0 -4
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -58
- package/dist/wirings/workflow/graph/workflow-graph.types.js +0 -6
- package/dist/wirings/workflow/index.d.ts +5 -7
- package/dist/wirings/workflow/index.js +3 -17
- package/dist/wirings/workflow/pikku-scenario-service.d.ts +87 -5
- package/dist/wirings/workflow/pikku-scenario-service.js +204 -42
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +7 -459
- package/dist/wirings/workflow/pikku-workflow-service.js +58 -551
- package/dist/wirings/workflow/run-timeline.d.ts +0 -47
- package/dist/wirings/workflow/run-timeline.js +0 -22
- package/dist/wirings/workflow/scenario-cookie-jar.d.ts +0 -23
- package/dist/wirings/workflow/scenario-cookie-jar.js +0 -16
- package/dist/wirings/workflow/scenario-poll.d.ts +0 -15
- package/dist/wirings/workflow/scenario-poll.js +0 -12
- package/dist/wirings/workflow/scenario-prose.d.ts +0 -28
- package/dist/wirings/workflow/scenario-prose.js +0 -18
- package/dist/wirings/workflow/scenario-step-guards.d.ts +0 -13
- package/dist/wirings/workflow/scenario-step-guards.js +1 -14
- package/dist/wirings/workflow/scenario-step.types.d.ts +72 -6
- package/dist/wirings/workflow/scenario-step.types.js +5 -1
- package/dist/wirings/workflow/scenario-surface.d.ts +16 -0
- package/dist/wirings/workflow/scenario-surface.js +56 -0
- package/dist/wirings/workflow/workflow-invocation-id.d.ts +0 -18
- package/dist/wirings/workflow/workflow-invocation-id.js +2 -22
- package/dist/wirings/workflow/workflow-queue-workers.d.ts +0 -20
- package/dist/wirings/workflow/workflow-queue-workers.js +0 -19
- package/dist/wirings/workflow/workflow.types.d.ts +0 -197
- package/knowledge/decisions/index.md +19 -0
- package/knowledge/decisions/internals/a-secret-that-fails-to-decrypt-fails-the-whole-read.md +49 -0
- package/knowledge/decisions/internals/actor-flow-conversations-seed-a-hidden-kickoff-message.md +23 -0
- package/knowledge/decisions/internals/actor-flow-drives-the-target-through-a-transport-seam.md +24 -0
- package/knowledge/decisions/internals/actor-flow-verdicts-are-llm-self-evaluations.md +25 -0
- package/knowledge/decisions/internals/addon-package-roots-resolve-by-walking-node-module-search-paths.md +26 -0
- package/knowledge/decisions/internals/addon-singleton-services-are-cached-per-namespace-not-per-package.md +33 -0
- package/knowledge/decisions/internals/addon-workflow-names-are-prefixed-with-the-consumer-namespace.md +28 -0
- package/knowledge/decisions/internals/ai-agent-agui-bridge-obeys-the-client-ordering-contract.md +29 -0
- package/knowledge/decisions/internals/ai-agent-audio-chunks-carry-the-format-the-provider-returned.md +20 -0
- package/knowledge/decisions/internals/ai-agent-credential-suspensions-hide-the-tool-result.md +26 -0
- package/knowledge/decisions/internals/ai-agent-delegate-and-supervise-hide-different-text.md +26 -0
- package/knowledge/decisions/internals/ai-agent-llm-tool-arguments-have-nulls-stripped.md +23 -0
- package/knowledge/decisions/internals/ai-agent-model-config-stays-a-single-resolution-seam.md +25 -0
- package/knowledge/decisions/internals/ai-agent-onerror-hooks-cannot-change-the-failure.md +22 -0
- package/knowledge/decisions/internals/ai-agent-runner-methods-must-keep-their-receiver.md +22 -0
- package/knowledge/decisions/internals/ai-agent-stream-persistence-is-best-effort.md +27 -0
- package/knowledge/decisions/internals/ai-agent-sub-agents-inherit-the-parent-context-block.md +26 -0
- package/knowledge/decisions/internals/ai-agent-tool-execute-failures-are-logged-unconditionally.md +25 -0
- package/knowledge/decisions/internals/ai-agent-voice-input-transcribes-audio-parts-in-place.md +22 -0
- package/knowledge/decisions/internals/ai-agent-working-memory-is-persisted-only-when-valid.md +25 -0
- package/knowledge/decisions/internals/channel-message-handlers-accept-three-config-shapes.md +30 -0
- package/knowledge/decisions/internals/channel-middleware-caches-only-statically-resolved-middleware.md +31 -0
- package/knowledge/decisions/internals/channel-state-is-per-socket-session-state-is-per-user.md +29 -0
- package/knowledge/decisions/internals/channel-user-id-is-persisted-after-onconnect-middleware-runs.md +28 -0
- package/knowledge/decisions/internals/cli-option-names-are-camelcase-in-state-and-kebab-on-the-command-line.md +27 -0
- package/knowledge/decisions/internals/cli-parse-errors-are-routed-by-message-prefix.md +28 -0
- package/knowledge/decisions/internals/cli-stdout-is-reserved-for-machine-readable-output.md +34 -0
- package/knowledge/decisions/internals/cli-unknown-long-options-warn-instead-of-failing.md +29 -0
- package/knowledge/decisions/internals/core-data-classification-brand-is-an-optional-property.md +34 -0
- package/knowledge/decisions/internals/core-function-runner-restores-the-wire-fields-it-overwrites.md +44 -0
- package/knowledge/decisions/internals/core-hot-reload-merges-generated-meta-never-replaces-it.md +39 -0
- package/knowledge/decisions/internals/core-hot-reload-owns-its-module-registry.md +42 -0
- package/knowledge/decisions/internals/core-middleware-order-is-scope-then-priority.md +39 -0
- package/knowledge/decisions/internals/core-schema-defaults-apply-on-every-transport.md +43 -0
- package/knowledge/decisions/internals/core-scopes-are-an-and-gate-separate-from-permissions.md +38 -0
- package/knowledge/decisions/internals/core-state-is-a-global-map-written-only-at-registration-time.md +44 -0
- package/knowledge/decisions/internals/email-meta-is-read-uncached-because-codegen-rewrites-it-mid-session.md +27 -0
- package/knowledge/decisions/internals/gateway-adapters-resolve-lazily-and-are-promise-cached.md +32 -0
- package/knowledge/decisions/internals/gateway-webhook-challenges-echo-bytes-not-json.md +28 -0
- package/knowledge/decisions/internals/gateway-wiring-is-a-meta-wiring-over-http-and-channels.md +31 -0
- package/knowledge/decisions/internals/generated-src-paths-in-pikku-meta-are-absolute.md +26 -0
- package/knowledge/decisions/internals/http-request-bodies-are-read-once-and-shared.md +32 -0
- package/knowledge/decisions/internals/http-route-groups-cascade-config-in-a-fixed-order.md +28 -0
- package/knowledge/decisions/internals/http-router-matches-normalized-paths-but-returns-registered-ones.md +30 -0
- package/knowledge/decisions/internals/http-runner-logs-through-a-trace-scoped-logger-functions-do-not.md +26 -0
- package/knowledge/decisions/internals/http-set-cookie-headers-are-appended-never-joined.md +28 -0
- package/knowledge/decisions/internals/http-sse-streams-flush-headers-only-after-middleware.md +32 -0
- package/knowledge/decisions/internals/http-wiring-without-metadata-is-skipped-not-fatal.md +26 -0
- package/knowledge/decisions/internals/in-a-scenario-a-4xx-is-data-not-an-exception.md +25 -0
- package/knowledge/decisions/internals/in-memory-workflow-history-aliases-the-live-step-object.md +26 -0
- package/knowledge/decisions/internals/index.md +113 -0
- package/knowledge/decisions/internals/istanbul-statement-counts-attach-to-the-start-line-only.md +25 -0
- package/knowledge/decisions/internals/local-trigger-and-gateway-services-assume-a-single-process.md +26 -0
- package/knowledge/decisions/internals/node-only-builtins-are-imported-dynamically.md +24 -0
- package/knowledge/decisions/internals/queue-group-concurrency-keeps-one-shared-queue-fair.md +28 -0
- package/knowledge/decisions/internals/queue-jobs-always-carry-an-explicit-attempts-count.md +27 -0
- package/knowledge/decisions/internals/remote-addons-dispatch-over-http-instead-of-local-meta.md +31 -0
- package/knowledge/decisions/internals/rpc-names-resolve-through-package-scope-before-root.md +32 -0
- package/knowledge/decisions/internals/scenario-agent-calls-sign-in-on-401-only.md +27 -0
- package/knowledge/decisions/internals/scenario-meta-lives-apart-from-app-meta-but-merges-when-read-off-disk.md +26 -0
- package/knowledge/decisions/internals/scenario-steps-return-drained-response-records.md +27 -0
- package/knowledge/decisions/internals/scope-roots-may-be-co-declared-by-an-addon-and-its-host-app.md +30 -0
- package/knowledge/decisions/internals/serverless-channel-disconnect-must-tolerate-a-missing-channel.md +28 -0
- package/knowledge/decisions/internals/the-dev-queue-copies-prod-timing-and-serialization-semantics.md +30 -0
- package/knowledge/decisions/internals/the-embedding-model-is-pinned-per-service-and-doc-query-embedding-is-split.md +29 -0
- package/knowledge/decisions/internals/the-in-memory-workflow-service-is-inline-only-and-single-process.md +27 -0
- package/knowledge/decisions/internals/the-kek-salt-is-scoped-to-the-key-version.md +40 -0
- package/knowledge/decisions/internals/the-schema-service-is-never-stubbed.md +26 -0
- package/knowledge/decisions/internals/trigger-declaration-is-split-from-trigger-source.md +33 -0
- package/knowledge/decisions/internals/typed-secret-service-caches-for-the-process-lifetime.md +26 -0
- package/knowledge/decisions/internals/webhook-delivery-history-records-every-attempt-best-effort.md +26 -0
- package/knowledge/decisions/internals/webhook-service-collaborators-are-constructor-args-not-locator-lookups.md +25 -0
- package/knowledge/decisions/internals/whether-a-run-is-inline-is-read-from-the-run-record.md +58 -0
- package/knowledge/decisions/internals/workflow-approval-expiry-is-decided-from-a-recorded-deadline.md +34 -0
- package/knowledge/decisions/internals/workflow-core-never-imports-a-browser-driver.md +42 -0
- package/knowledge/decisions/internals/workflow-dsl-meta-separates-runtime-expressions-from-literals.md +38 -0
- package/knowledge/decisions/internals/workflow-features-resolve-scenarios-by-object-identity.md +29 -0
- package/knowledge/decisions/internals/workflow-graph-inline-and-queued-runs-share-one-planner.md +42 -0
- package/knowledge/decisions/internals/workflow-graph-node-notes-are-excluded-from-the-graph-hash.md +25 -0
- package/knowledge/decisions/internals/workflow-inline-runs-report-their-run-id-before-they-can-fail.md +29 -0
- package/knowledge/decisions/internals/workflow-invocation-id-is-the-dedupe-key-not-step-id.md +43 -0
- package/knowledge/decisions/internals/workflow-queued-step-dispatch-requires-an-explicit-opt-in.md +29 -0
- package/knowledge/decisions/internals/workflow-queues-are-per-workflow-by-default.md +42 -0
- package/knowledge/decisions/internals/workflow-repeated-step-names-get-an-ordinal-suffix.md +33 -0
- package/knowledge/decisions/internals/workflow-replay-reads-its-steps-once-and-caches-only-the-immutable-half.md +32 -0
- package/knowledge/decisions/internals/workflow-retries-are-owned-by-the-workflow-not-the-queue.md +31 -0
- package/knowledge/decisions/internals/workflow-run-capabilities-are-extensions-not-subclasses.md +39 -0
- package/knowledge/decisions/internals/workflow-run-mirror-is-never-a-source-of-truth.md +29 -0
- package/knowledge/decisions/internals/workflow-run-polling-backs-off-to-the-callers-ceiling.md +33 -0
- package/knowledge/decisions/internals/workflow-run-timeline-is-a-pure-fold-over-durable-history.md +37 -0
- package/knowledge/decisions/internals/workflow-scenario-assertions-never-retry-and-record-one-step.md +50 -0
- package/knowledge/decisions/internals/workflow-scenario-hooks-are-a-scenario-only-affordance.md +43 -0
- package/knowledge/decisions/internals/workflow-scenario-prose-is-rendered-from-typed-calls-not-parsed-from-english.md +32 -0
- package/knowledge/decisions/internals/workflow-scenario-quarantine-reason-lives-in-code.md +18 -0
- package/knowledge/decisions/internals/workflow-scenario-step-targets-are-string-literals-for-the-inspector.md +34 -0
- package/knowledge/decisions/internals/workflow-step-compensation-runs-as-its-own-durable-step.md +26 -0
- package/knowledge/decisions/internals/workflow-step-dispatch-failure-is-transient-not-a-run-failure.md +33 -0
- package/knowledge/decisions/internals/workflow-step-lock-is-held-only-to-claim-the-step.md +27 -0
- package/knowledge/decisions/internals/workflow-step-rpc-name-is-provenance-only.md +34 -0
- package/knowledge/decisions/internals/workflow-suspend-and-approval-reasons-are-durable-step-identities.md +38 -0
- package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md +30 -0
- package/knowledge/decisions/security/a-dropped-audit-write-is-always-logged.md +26 -0
- package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md +22 -0
- package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md +27 -0
- package/knowledge/decisions/security/actor-sign-in-only-works-for-actor-flagged-users.md +27 -0
- package/knowledge/decisions/security/addon-auth-and-tags-only-tighten.md +43 -0
- package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md +52 -0
- package/knowledge/decisions/security/addon-scopes-are-resolved-where-the-function-runs.md +46 -0
- package/knowledge/decisions/security/ai-agent-approval-forwarding-requires-a-symbol-brand.md +27 -0
- package/knowledge/decisions/security/ai-agent-credential-requests-are-symbol-branded.md +37 -0
- package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md +31 -0
- package/knowledge/decisions/security/ai-agent-ownership-failures-never-echo-the-resource.md +23 -0
- package/knowledge/decisions/security/ai-agent-resume-re-runs-the-authorization-gate.md +22 -0
- package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md +39 -0
- package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md +30 -0
- package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md +24 -0
- package/knowledge/decisions/security/an-empty-owners-constraint-matches-nothing.md +30 -0
- package/knowledge/decisions/security/an-exposed-ungated-function-is-a-codegen-warning.md +49 -0
- package/knowledge/decisions/security/console-addon-privileged-functions-gate-themselves.md +76 -0
- package/knowledge/decisions/security/core-safe-fetch-blocks-ssrf-by-host-literal-not-dns.md +39 -0
- package/knowledge/decisions/security/core-secrets-use-a-per-secret-dek-wrapped-by-a-kek.md +37 -0
- package/knowledge/decisions/security/gateway-handlers-run-through-the-function-runner-gate.md +31 -0
- package/knowledge/decisions/security/gateway-middleware-sessions-must-be-bridged-onto-the-wire.md +30 -0
- package/knowledge/decisions/security/global-permissions-and-function-permissions-are-independent-gates.md +40 -0
- package/knowledge/decisions/security/http-error-detail-is-withheld-from-clients-in-production.md +33 -0
- package/knowledge/decisions/security/http-request-bodies-are-bounded-before-they-are-buffered.md +46 -0
- package/knowledge/decisions/security/index.md +55 -0
- package/knowledge/decisions/security/mcp-internal-error-details-are-double-gated-on-production.md +27 -0
- package/knowledge/decisions/security/passphrases-are-stretched-key-material-is-expanded.md +40 -0
- package/knowledge/decisions/security/permission-auth-filtering-requires-live-permission-functions.md +31 -0
- package/knowledge/decisions/security/pikku-carries-actor-scopes-as-data-and-the-app-grants-them.md +26 -0
- package/knowledge/decisions/security/queue-job-identities-are-signed-at-enqueue.md +69 -0
- package/knowledge/decisions/security/queue-jobs-carry-the-producers-pikku-user-id.md +39 -0
- package/knowledge/decisions/security/remote-addon-tokens-are-client-credentials-not-mesh-trust.md +34 -0
- package/knowledge/decisions/security/scaffold-features-are-authenticated-unless-opted-out.md +49 -0
- package/knowledge/decisions/security/scenario-step-functions-are-never-externally-invocable.md +30 -0
- package/knowledge/decisions/security/scope-resolution-happens-at-the-session-boundary-and-sync-never-deletes.md +28 -0
- package/knowledge/decisions/security/self-authentication-is-declared-not-detected.md +34 -0
- package/knowledge/decisions/security/signed-content-urls-bind-the-request-path.md +37 -0
- package/knowledge/decisions/security/webhook-bodies-are-signed-before-they-are-enqueued.md +25 -0
- package/knowledge/decisions/security/workflow-actor-steps-always-use-the-real-transport.md +34 -0
- package/knowledge/decisions/security/workflow-approval-payloads-are-validated-on-replay-inside-the-workflow.md +40 -0
- package/knowledge/decisions/security/workflow-queued-steps-rehydrate-their-session-from-the-run-wire.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-sessions-are-isolated-per-actor-and-per-scenario.md +32 -0
- package/knowledge/decisions/security/workflow-scenario-steps-are-never-network-invocable.md +31 -0
- package/knowledge/index.md +24 -0
- package/knowledge/questions/index.md +15 -0
- package/package.json +4 -2
- package/run-tests.sh +0 -0
- package/src/crypto-utils.test.ts +460 -19
- package/src/crypto-utils.ts +283 -55
- package/src/data-classification.ts +1 -7
- package/src/dev/hot-reload.test.ts +0 -4
- package/src/dev/hot-reload.ts +11 -30
- package/src/dev/module-runner.ts +7 -32
- package/src/dev/reload-meta.ts +9 -29
- package/src/errors/error-handler.ts +20 -35
- package/src/errors/error.test.ts +30 -1
- package/src/errors/errors.ts +73 -157
- package/src/function/abort-scope.test.ts +97 -0
- package/src/function/abort-scope.ts +80 -0
- package/src/function/function-runner.test.ts +75 -7
- package/src/function/function-runner.ts +73 -30
- package/src/function/functions.types.ts +56 -136
- package/src/function/list.types.test.ts +3 -25
- package/src/function/list.types.ts +12 -62
- package/src/gopass-secrets-removed.test.ts +51 -0
- package/src/handle-error.test.ts +108 -1
- package/src/handle-error.ts +8 -18
- package/src/index.ts +60 -1
- package/src/middleware/auth-apikey.test.ts +0 -1
- package/src/middleware/auth-apikey.ts +0 -17
- package/src/middleware/auth-bearer.test.ts +0 -3
- package/src/middleware/auth-bearer.ts +3 -40
- package/src/middleware/auth-cookie.test.ts +0 -6
- package/src/middleware/auth-cookie.ts +2 -26
- package/src/middleware/cors.test.ts +34 -0
- package/src/middleware/cors.ts +12 -33
- package/src/middleware/remote-auth.test.ts +24 -9
- package/src/middleware/remote-auth.ts +10 -2
- package/src/middleware/telemetry.ts +2 -31
- package/src/middleware-runner.test.ts +0 -2
- package/src/middleware-runner.ts +5 -74
- package/src/permissions.test.ts +30 -0
- package/src/permissions.ts +24 -74
- package/src/pikku-request.ts +0 -6
- package/src/pikku-state.ts +2 -30
- package/src/production-barrels-stay-lean.test.ts +110 -0
- package/src/remote.test.ts +172 -0
- package/src/remote.ts +17 -7
- package/src/schema.test.ts +103 -0
- package/src/schema.ts +35 -18
- package/src/scopes.ts +7 -48
- package/src/services/ai-agent-runner-service.ts +20 -0
- package/src/services/ai-embedding-service.ts +3 -25
- package/src/services/audit-service.ts +1 -2
- package/src/services/content-service.ts +1 -46
- package/src/services/credential-service.ts +3 -40
- package/src/services/credential-wire-service.test.ts +0 -2
- package/src/services/deployment-service.ts +3 -9
- package/src/services/gateway-service.ts +0 -15
- package/src/services/{http-scenario-actors-converse.test.ts → http-personas-converse.test.ts} +38 -9
- package/src/services/{http-scenario-actors.test.ts → http-personas.test.ts} +39 -22
- package/src/services/{http-scenario-actors.ts → http-personas.ts} +85 -45
- package/src/services/in-memory-queue-service.ts +1 -15
- package/src/services/in-memory-trigger-service.ts +1 -18
- package/src/services/in-memory-workflow-service.test.ts +0 -13
- package/src/services/in-memory-workflow-service.ts +4 -38
- package/src/services/index.ts +20 -15
- package/src/services/istanbul-coverage-service.ts +2 -8
- package/src/services/jwt-service.ts +1 -16
- package/src/services/local-content.test.ts +159 -27
- package/src/services/local-content.ts +55 -23
- package/src/services/local-gateway-service.ts +2 -17
- package/src/services/local-secrets.ts +0 -4
- package/src/services/logger-console.test.ts +0 -1
- package/src/services/logger-console.ts +3 -7
- package/src/services/logger.ts +2 -37
- package/src/services/meta-service.test.ts +1 -5
- package/src/services/meta-service.ts +41 -61
- package/src/services/{scenario-actors-service.ts → personas-service.ts} +48 -43
- package/src/services/pikku-user-id.ts +0 -4
- package/src/services/queue-webhook-service.ts +9 -41
- package/src/services/scheduler-service.ts +1 -50
- package/src/services/schema-service.ts +1 -24
- package/src/services/scope-service.ts +50 -34
- package/src/services/scoped-secret-service.ts +0 -4
- package/src/services/secret-host-binding.test.ts +138 -0
- package/src/services/secret-host-binding.ts +51 -0
- package/src/services/secret-service.ts +5 -33
- package/src/services/secretless.test.ts +54 -0
- package/src/services/secretless.ts +29 -0
- package/src/services/stub-tracker.ts +8 -18
- package/src/services/system-role-guard.test.ts +93 -0
- package/src/services/system-role-guard.ts +71 -0
- package/src/services/trigger-service.ts +0 -12
- package/src/services/typed-secret-service.ts +1 -7
- package/src/services/v8-coverage-service.ts +3 -6
- package/src/services/variables-service.ts +1 -8
- package/src/services/webhook-service.ts +19 -63
- package/src/services/workflow-service.ts +3 -20
- package/src/testing/service-tests.ts +0 -26
- package/src/time-utils.ts +1 -19
- package/src/types/core.types.ts +116 -229
- package/src/types/state.types.ts +7 -9
- package/src/utils/hmac.ts +4 -10
- package/src/utils/safe-fetch.ts +13 -54
- package/src/utils.test.ts +11 -2
- package/src/utils.ts +6 -15
- package/src/wirings/actor-flow/actor-flow.types.ts +1 -34
- package/src/wirings/actor-flow/index.ts +0 -9
- package/src/wirings/actor-flow/run-conversation.test.ts +11 -6
- package/src/wirings/actor-flow/run-conversation.ts +19 -12
- package/src/wirings/ai-agent/ai-agent-agui.test.ts +75 -10
- package/src/wirings/ai-agent/ai-agent-agui.ts +36 -17
- package/src/wirings/ai-agent/ai-agent-helpers.ts +20 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.test.ts +842 -0
- package/src/wirings/ai-agent/ai-agent-interrupt.ts +399 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-model-config.ts +1 -9
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +202 -31
- package/src/wirings/ai-agent/ai-agent-prepare.ts +82 -138
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +191 -6
- package/src/wirings/ai-agent/ai-agent-registry.ts +18 -1
- package/src/wirings/ai-agent/ai-agent-resume-authorization.test.ts +0 -2
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +11 -9
- package/src/wirings/ai-agent/ai-agent-runner.ts +67 -33
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +205 -103
- package/src/wirings/ai-agent/ai-agent-stream.ts +192 -75
- package/src/wirings/ai-agent/ai-agent-thread-ownership.test.ts +301 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +85 -4
- package/src/wirings/ai-agent/index.ts +35 -3
- package/src/wirings/ai-agent/voice-input.test.ts +72 -7
- package/src/wirings/ai-agent/voice-input.ts +48 -3
- package/src/wirings/ai-agent/voice-output.test.ts +422 -0
- package/src/wirings/ai-agent/voice-output.ts +216 -56
- package/src/wirings/channel/channel-common.ts +15 -20
- package/src/wirings/channel/channel-handler.test.ts +50 -0
- package/src/wirings/channel/channel-handler.ts +32 -11
- package/src/wirings/channel/channel-host-rpc.test.ts +150 -0
- package/src/wirings/channel/channel-host-rpc.ts +69 -0
- package/src/wirings/channel/channel-middleware-runner.test.ts +0 -1
- package/src/wirings/channel/channel-middleware-runner.ts +0 -12
- package/src/wirings/channel/channel-rpc-registry.ts +116 -0
- package/src/wirings/channel/channel-rpc-responder.ts +117 -0
- package/src/wirings/channel/channel-rpc-service.ts +146 -0
- package/src/wirings/channel/channel-rpc-validators.ts +65 -0
- package/src/wirings/channel/channel-rpc.test.ts +820 -0
- package/src/wirings/channel/channel-rpc.ts +5 -0
- package/src/wirings/channel/channel-rpc.types.ts +150 -0
- package/src/wirings/channel/channel-runner.ts +0 -14
- package/src/wirings/channel/channel-store.ts +0 -10
- package/src/wirings/channel/channel.types.ts +19 -8
- package/src/wirings/channel/define-channel-routes.ts +0 -20
- package/src/wirings/channel/eventhub-service.ts +0 -18
- package/src/wirings/channel/index.ts +35 -0
- package/src/wirings/channel/local/local-channel-handler.ts +3 -1
- package/src/wirings/channel/local/local-channel-runner.test.ts +0 -10
- package/src/wirings/channel/local/local-channel-runner.ts +3 -1
- package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -13
- package/src/wirings/channel/local/local-eventhub-service.ts +2 -37
- package/src/wirings/channel/log-channels.ts +0 -4
- package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +83 -2
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +7 -0
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +2 -5
- package/src/wirings/cli/channel/cli-approval.test.ts +177 -0
- package/src/wirings/cli/channel/cli-approval.ts +135 -0
- package/src/wirings/cli/channel/cli-channel-runner.ts +4 -26
- package/src/wirings/cli/channel/cli-raw-channel-runner.test.ts +169 -0
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +59 -16
- package/src/wirings/cli/channel/cli-raw-client-runner.test.ts +480 -0
- package/src/wirings/cli/channel/cli-raw-client-runner.ts +155 -0
- package/src/wirings/cli/channel/index.ts +9 -0
- package/src/wirings/cli/cli-runner.test.ts +0 -1
- package/src/wirings/cli/cli-runner.ts +46 -88
- package/src/wirings/cli/cli.types.ts +14 -3
- package/src/wirings/cli/command-parser.test.ts +0 -4
- package/src/wirings/cli/command-parser.ts +11 -91
- package/src/wirings/cli/define-cli-commands.ts +1 -17
- package/src/wirings/credential/credential.types.ts +0 -12
- package/src/wirings/credential/{wire-credential.ts → define-credential.ts} +7 -7
- package/src/wirings/credential/index.ts +1 -1
- package/src/wirings/credential/validate-credential-definitions.ts +2 -4
- package/src/wirings/gateway/gateway-runner.test.ts +1 -21
- package/src/wirings/gateway/gateway-runner.ts +8 -110
- package/src/wirings/gateway/gateway.types.ts +7 -80
- package/src/wirings/http/http-routes.test.ts +0 -3
- package/src/wirings/http/http-routes.ts +0 -86
- package/src/wirings/http/http-runner.test.ts +0 -1
- package/src/wirings/http/http-runner.ts +12 -168
- package/src/wirings/http/http.types.ts +17 -62
- package/src/wirings/http/index.ts +5 -1
- package/src/wirings/http/log-http-routes.ts +0 -4
- package/src/wirings/http/pikku-fetch-http-request.test.ts +88 -7
- package/src/wirings/http/pikku-fetch-http-request.ts +74 -50
- package/src/wirings/http/pikku-fetch-http-response.test.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +0 -3
- package/src/wirings/http/routers/path-to-regex.test.ts +4 -17
- package/src/wirings/http/routers/path-to-regex.ts +2 -13
- package/src/wirings/http/web-request.test.ts +33 -2
- package/src/wirings/http/web-request.ts +30 -17
- package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -1
- package/src/wirings/mcp/mcp-runner.test.ts +40 -0
- package/src/wirings/mcp/mcp-runner.ts +9 -15
- package/src/wirings/mcp/mcp.types.ts +7 -42
- package/src/wirings/oauth2/oauth2.types.ts +0 -30
- package/src/wirings/persona/define-personas.ts +29 -0
- package/src/wirings/persona/index.ts +62 -0
- package/src/wirings/persona/persona-email.ts +87 -0
- package/src/wirings/persona/persona-environments.test.ts +183 -0
- package/src/wirings/persona/persona-environments.ts +138 -0
- package/src/wirings/persona/persona-mailbox.ts +156 -0
- package/src/wirings/persona/persona.test.ts +220 -0
- package/src/wirings/persona/persona.types.ts +131 -0
- package/src/wirings/persona/validate-personas.ts +133 -0
- package/src/wirings/queue/index.ts +13 -3
- package/src/wirings/queue/queue-identity.test.ts +453 -0
- package/src/wirings/queue/queue-identity.ts +173 -0
- package/src/wirings/queue/queue-runner.ts +12 -31
- package/src/wirings/queue/queue.types.ts +19 -89
- package/src/wirings/queue/register-queue-helper.ts +0 -14
- package/src/wirings/queue/signed-queue-service.ts +59 -0
- package/src/wirings/queue/validate-worker-config.ts +2 -28
- package/src/wirings/role/define-system-role.ts +33 -0
- package/src/wirings/role/index.ts +13 -0
- package/src/wirings/role/role.test.ts +104 -0
- package/src/wirings/role/role.types.ts +47 -0
- package/src/wirings/role/validate-role-definitions.ts +93 -0
- package/src/wirings/rpc/addon-auth-tags.test.ts +223 -0
- package/src/wirings/rpc/addon-runner.ts +0 -56
- package/src/wirings/rpc/addon-scopes.test.ts +225 -0
- package/src/wirings/rpc/remote-addon-auth.ts +1 -13
- package/src/wirings/rpc/rpc-runner.test.ts +186 -2
- package/src/wirings/rpc/rpc-runner.ts +145 -127
- package/src/wirings/rpc/rpc-types.ts +11 -6
- package/src/wirings/rpc/wire-addon.test.ts +43 -1
- package/src/wirings/rpc/wire-addon.ts +99 -0
- package/src/wirings/rpc/wire-remote-addon.ts +9 -29
- package/src/wirings/scheduler/log-schedulers.ts +0 -4
- package/src/wirings/scheduler/scheduler-runner.test.ts +1 -8
- package/src/wirings/scheduler/scheduler-runner.ts +0 -2
- package/src/wirings/scheduler/scheduler.types.ts +1 -14
- package/src/wirings/scope/{wire-scope.ts → define-scope.ts} +5 -6
- package/src/wirings/scope/index.ts +1 -1
- package/src/wirings/scope/scope.test.ts +1 -2
- package/src/wirings/scope/scope.types.ts +7 -9
- package/src/wirings/scope/validate-scope-definitions.ts +3 -21
- package/src/wirings/secret/index.ts +1 -1
- package/src/wirings/secret/secret.types.ts +19 -15
- package/src/wirings/secret/validate-secret-definitions.ts +2 -4
- package/src/wirings/trigger/trigger-runner.ts +1 -27
- package/src/wirings/trigger/trigger.types.ts +1 -82
- package/src/wirings/variable/index.ts +1 -1
- package/src/wirings/variable/validate-variable-definitions.ts +2 -4
- package/src/wirings/variable/variable.types.ts +1 -13
- package/src/wirings/virtual-user/index.ts +76 -0
- package/src/wirings/virtual-user/run-virtual-user.test.ts +765 -0
- package/src/wirings/virtual-user/run-virtual-user.ts +671 -0
- package/src/wirings/virtual-user/virtual-user-agents.test.ts +65 -0
- package/src/wirings/virtual-user/virtual-user-agents.ts +57 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.test.ts +215 -0
- package/src/wirings/virtual-user/virtual-user-catalogue.ts +184 -0
- package/src/wirings/virtual-user/virtual-user-derive.test.ts +398 -0
- package/src/wirings/virtual-user/virtual-user-derive.ts +173 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.test.ts +63 -0
- package/src/wirings/virtual-user/virtual-user-dispositions.ts +213 -0
- package/src/wirings/virtual-user/virtual-user-intents.test.ts +208 -0
- package/src/wirings/virtual-user/virtual-user-intents.ts +185 -0
- package/src/wirings/virtual-user/virtual-user-rng.test.ts +72 -0
- package/src/wirings/virtual-user/virtual-user-rng.ts +50 -0
- package/src/wirings/virtual-user/virtual-user-target.ts +47 -0
- package/src/wirings/virtual-user/virtual-user.types.ts +219 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +5 -4
- package/src/wirings/workflow/dsl/workflow-runner.ts +0 -4
- package/src/wirings/workflow/feature.ts +0 -19
- package/src/wirings/workflow/graph/graph-node.ts +0 -136
- package/src/wirings/workflow/graph/graph-runner.test.ts +20 -19
- package/src/wirings/workflow/graph/graph-runner.ts +6 -41
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -4
- package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -58
- package/src/wirings/workflow/index.ts +10 -44
- package/src/wirings/workflow/pikku-scenario-service.ts +235 -52
- package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -39
- package/src/wirings/workflow/pikku-workflow-service.ts +77 -674
- package/src/wirings/workflow/run-timeline.test.ts +7 -19
- package/src/wirings/workflow/run-timeline.ts +0 -56
- package/src/wirings/workflow/scenario-cookie-jar.test.ts +0 -1
- package/src/wirings/workflow/scenario-cookie-jar.ts +0 -25
- package/src/wirings/workflow/scenario-expectations.test.ts +2 -7
- package/src/wirings/workflow/scenario-hooks.test.ts +2 -7
- package/src/wirings/workflow/scenario-poll.test.ts +0 -2
- package/src/wirings/workflow/scenario-poll.ts +0 -15
- package/src/wirings/workflow/scenario-prose.ts +0 -28
- package/src/wirings/workflow/scenario-service.test.ts +2 -9
- package/src/wirings/workflow/scenario-step-guards.ts +1 -14
- package/src/wirings/workflow/scenario-step.test.ts +159 -14
- package/src/wirings/workflow/scenario-step.types.ts +82 -6
- package/src/wirings/workflow/scenario-surface.test.ts +145 -0
- package/src/wirings/workflow/scenario-surface.ts +71 -0
- package/src/wirings/workflow/workflow-dispatch-durability.test.ts +14 -15
- package/src/wirings/workflow/workflow-dispatch-payload.test.ts +0 -4
- package/src/wirings/workflow/workflow-inline-authority.test.ts +169 -0
- package/src/wirings/workflow/workflow-invocation-id.test.ts +0 -2
- package/src/wirings/workflow/workflow-invocation-id.ts +2 -22
- package/src/wirings/workflow/workflow-mirror.test.ts +0 -7
- package/src/wirings/workflow/workflow-on-error.test.ts +0 -9
- package/src/wirings/workflow/workflow-queue-workers.ts +0 -21
- package/src/wirings/workflow/workflow-replay-snapshot.test.ts +8 -7
- package/src/wirings/workflow/workflow-retry-policy.test.ts +0 -5
- package/src/wirings/workflow/workflow-run-context.test.ts +5 -10
- package/src/wirings/workflow/workflow-run-polling.test.ts +0 -5
- package/src/wirings/workflow/workflow-step-ordinal.test.ts +19 -4
- package/src/wirings/workflow/workflow-step-session.test.ts +0 -7
- package/src/wirings/workflow/workflow.types.ts +0 -203
- package/tsconfig.tsbuildinfo +1 -1
- package/src/middleware/timeout.ts +0 -22
- package/src/pikku-response.ts +0 -5
- package/src/services/gopass-secrets.ts +0 -78
- package/src/wirings/mcp/mcp-endpoint-registry.test.d.ts +0 -1
- package/src/wirings/workflow/dsl/index.ts +0 -36
- package/src/wirings/workflow/graph/index.ts +0 -15
package/knowledge/decisions/internals/workflow-suspended-runs-keep-their-in-process-context.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A suspended workflow run keeps its in-process context; only terminal runs release it
|
|
4
|
+
description: `suspended` is absent from the terminal set on purpose, and a context is dropped only when nothing is holding it open
|
|
5
|
+
tags: workflow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A suspended workflow run keeps its in-process context; only terminal runs release it
|
|
9
|
+
|
|
10
|
+
`WORKFLOW_TERMINAL_STATES` in `pikku-workflow-service.ts` is
|
|
11
|
+
`completed | failed | cancelled`. `suspended` is deliberately absent: a
|
|
12
|
+
suspended run stops a poll loop but can still be resumed, so anything the
|
|
13
|
+
process holds for it — the run context, an extension's per-run state such as a
|
|
14
|
+
scenario's live actor clients — has to survive. `WORKFLOW_END_STATES`, which
|
|
15
|
+
`awaitRunEnd` uses to stop reading, does include `suspended`, because a poller
|
|
16
|
+
should not wait on a run that needs an external nudge. The two sets are not
|
|
17
|
+
interchangeable.
|
|
18
|
+
|
|
19
|
+
`releaseContext` drops a `RunContext` only when neither `inline` nor `replay`
|
|
20
|
+
still holds it open, so an inline run mid-replay is never torn out from under
|
|
21
|
+
itself. `updateRunStatus` releases on a terminal status because queued runs
|
|
22
|
+
never pass through the inline path that would otherwise do it — without that,
|
|
23
|
+
their context would be held for the life of the process. A long-lived server
|
|
24
|
+
orchestrates many runs, so anything kept per run has to be released when that
|
|
25
|
+
run stops executing here (`workflow-run-context.test.ts`).
|
|
26
|
+
|
|
27
|
+
**What this rules out:** adding `suspended` to `WORKFLOW_TERMINAL_STATES`,
|
|
28
|
+
collapsing the two state sets into one, or making `releaseContext`
|
|
29
|
+
unconditional — the first two discard state a resume still needs, the third
|
|
30
|
+
frees a context that an in-flight replay is still walking.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: A dropped audit write is always logged
|
|
4
|
+
description: The no-op audit service falls back to the singleton logger when the wire carries none, so an unconfigured audit call is never silent
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# A dropped audit write is always logged
|
|
9
|
+
|
|
10
|
+
The no-op `AuditService` in `packages/core/src/services/audit-service.ts` is what
|
|
11
|
+
a function gets when it calls `audit.write()` without `audit: true` set on it.
|
|
12
|
+
Its `write` discards the event — but before it does, it warns once, and it looks
|
|
13
|
+
for a logger in two places: the wire's own, then the singleton passed to the
|
|
14
|
+
constructor.
|
|
15
|
+
|
|
16
|
+
The fallback is the point. Wires frequently do not carry a logger, and with only
|
|
17
|
+
`this.wire.logger` the warning would itself be dropped whenever the wire is bare.
|
|
18
|
+
An audit call that silently does nothing is the worst available outcome: the
|
|
19
|
+
function believes it is producing an audit trail, the trail does not exist, and
|
|
20
|
+
nothing anywhere says so. The warning names the function and the fix, and fires
|
|
21
|
+
once per instance so it cannot flood a hot path.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** narrowing the logger lookup to a single source,
|
|
24
|
+
downgrading the warning to `debug`, or removing it as noise from a service whose
|
|
25
|
+
whole job is to do nothing. If this class stops warning, an unconfigured audit
|
|
26
|
+
call becomes undetectable.
|
package/knowledge/decisions/security/actor-flow-missing-approval-decisions-default-to-denied.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: An actor's missing approval decision defaults to denied
|
|
4
|
+
description: Every pending tool call gets an explicit decision; an id the persona LLM omitted is denied, so a dropped field can never read as consent
|
|
5
|
+
tags: actor-flow
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# An actor's missing approval decision defaults to denied
|
|
9
|
+
|
|
10
|
+
`decideApprovals` in
|
|
11
|
+
`packages/core/src/wirings/actor-flow/run-conversation.ts` maps over the
|
|
12
|
+
target agent's `pendingApprovals`, not over the decisions the persona LLM
|
|
13
|
+
returned. Any `toolCallId` the model omitted, hallucinated, or renamed resolves
|
|
14
|
+
to `approved: false`.
|
|
15
|
+
|
|
16
|
+
The persona's decision comes from a structured LLM call, and structured output
|
|
17
|
+
is not guaranteed to be complete. Iterating the model's array instead would make
|
|
18
|
+
an omission indistinguishable from silence — and silence would let a scenario
|
|
19
|
+
approve a destructive tool call nobody decided on, then pass.
|
|
20
|
+
|
|
21
|
+
**What this rules out:** building the decision list from the LLM's `decisions`
|
|
22
|
+
array, and defaulting an unmatched call to `true` to keep a conversation moving.
|
package/knowledge/decisions/security/actor-sign-in-is-proven-by-set-cookie-not-a-non-empty-jar.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Actor sign-in is proven by Set-Cookie, not a non-empty jar
|
|
4
|
+
description: HttpScenarioActor tracks its own signedIn flag and requires the sign-in response itself to set a cookie, because a populated jar proves nothing
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Actor sign-in is proven by Set-Cookie, not a non-empty jar
|
|
9
|
+
|
|
10
|
+
`HttpScenarioActor` (`packages/core/src/services/http-scenario-actors.ts`) keeps
|
|
11
|
+
a private `signedIn` boolean rather than inferring the session from its cookie
|
|
12
|
+
jar, and `login()` throws when the sign-in response carries no `Set-Cookie`
|
|
13
|
+
header even though the response was a 2xx.
|
|
14
|
+
|
|
15
|
+
A cookie jar cannot answer "did sign-in happen". A target app may set a cookie on
|
|
16
|
+
any request — a CSRF token, an anonymous session, a locale — so a non-empty jar
|
|
17
|
+
after a failed or skipped sign-in looks exactly like a successful one. What
|
|
18
|
+
actually proves a session was established is *this* response setting a cookie. A
|
|
19
|
+
2xx alone is not enough either: an endpoint that returns 200 while quietly
|
|
20
|
+
declining to issue a session would leave the actor running every subsequent
|
|
21
|
+
request unauthenticated, and the scenario would report the resulting refusals as
|
|
22
|
+
genuine permission failures.
|
|
23
|
+
|
|
24
|
+
**What this rules out:** replacing `signedIn` with a `jar.isEmpty()` check,
|
|
25
|
+
dropping the `getSetCookie().length === 0` guard as redundant with `res.ok`, and
|
|
26
|
+
treating `signOut()` as jar-clearing only — it must reset the flag too, or the
|
|
27
|
+
next call proceeds believing it has a session.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Actor sign-in only works for actor-flagged users
|
|
4
|
+
description: The scenario actor secret mints sessions for user rows flagged actor and nothing else, so holding it never impersonates a real user
|
|
5
|
+
tags: services
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Actor sign-in only works for actor-flagged users
|
|
9
|
+
|
|
10
|
+
`HttpScenarioActorsConfig.secret`
|
|
11
|
+
(`packages/core/src/services/http-scenario-actors.ts`) is a shared impersonation
|
|
12
|
+
secret: `HttpScenarioActor.login` POSTs `{ email, name, secret }` to
|
|
13
|
+
`/auth/sign-in/actor` and gets back a session. That looks like a master key, and
|
|
14
|
+
it deliberately is not one.
|
|
15
|
+
|
|
16
|
+
The Better Auth actor plugin on the other end upserts and signs in only user rows
|
|
17
|
+
flagged `actor: true`. Presenting the secret with a real customer's email does not
|
|
18
|
+
mint that customer's session — it is refused. The `actor` flag also flows into the
|
|
19
|
+
minted session, so audits and analytics can tell scenario traffic from human
|
|
20
|
+
traffic after the fact. The blast radius of a leaked actor secret is therefore the
|
|
21
|
+
synthetic actor population, not the user table.
|
|
22
|
+
|
|
23
|
+
**What this rules out:** widening the sign-in endpoint to accept any email "so
|
|
24
|
+
scenarios can test as a real user", and treating the actor secret as equivalent to
|
|
25
|
+
a session-signing key. It also rules out dropping the `actor` flag from the minted
|
|
26
|
+
session — the audit trail's ability to separate synthetic from real activity
|
|
27
|
+
depends on it.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Addon auth and tags only tighten, and resolve where the function runs
|
|
4
|
+
description: wireAddon auth and tags are applied in runPikkuFunc like scopes, but auth:false is ignored and tags resolve against the consuming app's tag groups rather than the addon package's
|
|
5
|
+
tags: addon, auth, tags, authorization
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Addon auth and tags only tighten, and resolve where the function runs
|
|
9
|
+
|
|
10
|
+
`wireAddon({ auth, tags })` was read only by `resolveAddonFunction` in
|
|
11
|
+
`rpc-runner.ts`, which covers the `namespace:function` RPC form alone. Every
|
|
12
|
+
direct wiring — the inspector writes the addon's package name onto http,
|
|
13
|
+
channel, schedule, queue, cli, trigger, gateway and mcp wirings — reached
|
|
14
|
+
`runPikkuFunc` with a `packageName` and neither value. That is the same hole
|
|
15
|
+
[addon scopes](./addon-scopes-are-resolved-where-the-function-runs.md) had, and
|
|
16
|
+
it is closed the same way: `runPikkuFunc` resolves both from the addon config.
|
|
17
|
+
|
|
18
|
+
`auth` merges as an OR and `auth: false` is ignored. The RPC path treats it as a
|
|
19
|
+
default (`addonConfig?.auth ?? options.requiresAuth`) because there the addon
|
|
20
|
+
config is the only statement of intent. On a direct wiring the route already
|
|
21
|
+
carries its own `auth`, so honouring `false` would let an addon *weaken* a gate
|
|
22
|
+
the app wrote — the inverse of what a wiring-level declaration should be able to
|
|
23
|
+
do. An addon may require a session the wiring did not; it may never waive one
|
|
24
|
+
the wiring did.
|
|
25
|
+
|
|
26
|
+
Tags resolve against the **root** tag groups, not the addon package's. A tag on
|
|
27
|
+
`wireAddon` is written by the consuming app, and `addTagMiddleware('admin', …)`
|
|
28
|
+
in that app registers under the root package. `combineMiddleware` looks tag
|
|
29
|
+
metadata up under the `packageName` it is given, which for an addon function is
|
|
30
|
+
the addon's own namespace — where the app's middleware does not exist. Resolving
|
|
31
|
+
addon tags to concrete middleware before the call and passing them as
|
|
32
|
+
`wireMiddleware` is what keeps `wireAddon({ tags: ['admin'] })` from being
|
|
33
|
+
silently inert, which is the failure mode the whole gate exists to avoid.
|
|
34
|
+
|
|
35
|
+
A function's own tags are unaffected: the inspector already emits them as
|
|
36
|
+
`{ type: 'tag' }` entries on the function and wiring meta, resolved under the
|
|
37
|
+
package that declared them. The `tags` argument `runPikkuFunc` accepts is
|
|
38
|
+
separate and still unused on every path.
|
|
39
|
+
|
|
40
|
+
**What this rules out:** honouring `auth: false` from an addon on a direct
|
|
41
|
+
wiring; resolving addon tags under the addon's `packageName`; and folding addon
|
|
42
|
+
tags into `funcInheritedMiddleware`, which would resolve them in the wrong
|
|
43
|
+
namespace and double-apply the function's own tags.
|
package/knowledge/decisions/security/addon-config-gates-apply-only-at-the-namespaced-rpc-boundary.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Addon auth and tag gates apply wherever the function runs, including inside the addon
|
|
4
|
+
description: wireAddon's auth and tags moved from the namespaced RPC boundary into runPikkuFunc, so they also apply to direct wirings and to bare intra-addon calls
|
|
5
|
+
tags: rpc, addon, auth
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Addon auth and tag gates apply wherever the function runs, including inside the addon
|
|
9
|
+
|
|
10
|
+
`ContextAwareRPCService.invokeAddonFunction` used to be the only place that
|
|
11
|
+
applied an addon's `addonConfig.auth` and `addonConfig.tags`, making them a
|
|
12
|
+
perimeter control on `rpc('namespace:fn')`. That perimeter had a hole in it: the
|
|
13
|
+
inspector writes the addon's package name onto http, channel, schedule, queue,
|
|
14
|
+
cli, trigger, gateway and mcp wirings, and every one of those runners calls
|
|
15
|
+
`runPikkuFunc` directly without resolving a namespace. A consumer who wrote
|
|
16
|
+
`wireAddon({ auth: true })` and then wired an addon function to a route got no
|
|
17
|
+
gate at all.
|
|
18
|
+
|
|
19
|
+
Both values now resolve in `runPikkuFunc`, the one point every path shares —
|
|
20
|
+
the same move, for the same reason, as
|
|
21
|
+
[addon scopes](./addon-scopes-are-resolved-where-the-function-runs.md). See
|
|
22
|
+
[addon auth and tags only tighten](./addon-auth-and-tags-only-tighten.md) for
|
|
23
|
+
the merge rules.
|
|
24
|
+
|
|
25
|
+
This replaces a consequence an earlier decision accepted: a bare `rpc('fn')`
|
|
26
|
+
made from inside an addon now re-applies the gate, because it reaches
|
|
27
|
+
`runPikkuFunc` with the addon's `packageName` like any other call. The earlier
|
|
28
|
+
reasoning — that the perimeter had already been passed, so re-checking would
|
|
29
|
+
gate internal calls on a consumer-facing setting — held only while the perimeter
|
|
30
|
+
was real. Once a direct wiring could enter the addon without passing any gate,
|
|
31
|
+
"already inside" stopped being something the runtime could infer, and the choice
|
|
32
|
+
became re-checking or trusting an entry that may never have happened.
|
|
33
|
+
|
|
34
|
+
In practice an intra-addon call inherits the entry point's session, so the auth
|
|
35
|
+
check passes wherever the entry was itself authenticated. What it does break is
|
|
36
|
+
an addon that wires `auth: true` and also runs its own sessionless internal
|
|
37
|
+
work — a scheduled task or queue worker inside the addon calling a sibling. Such
|
|
38
|
+
an addon should carry authorization on the function via
|
|
39
|
+
`pikkuFunc({ permissions })`, which has always been enforced on every path,
|
|
40
|
+
rather than on the consumer-facing `wireAddon` setting.
|
|
41
|
+
|
|
42
|
+
Re-checking was chosen over provenance because the marker that would make
|
|
43
|
+
"already inside" knowable — set by the runtime, unsettable by any caller outside
|
|
44
|
+
the process, threaded through all eight runners — is a design problem of its
|
|
45
|
+
own, and shipping it inside a security fix would have meant landing an untested
|
|
46
|
+
trust signal alongside the gate that depends on it. Adding that marker is
|
|
47
|
+
tracked separately; until it exists, re-checking is the only option that does
|
|
48
|
+
not trust an entry which may never have happened.
|
|
49
|
+
|
|
50
|
+
**What this rules out:** treating `addonConfig.auth` as a perimeter-only
|
|
51
|
+
control; and inferring "already inside the addon" from the wire, which a direct
|
|
52
|
+
wiring does not set.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Addon scopes are resolved where the function runs
|
|
4
|
+
description: wireAddon scopes are merged inside runPikkuFunc rather than at namespace resolution, because most wirings reach an addon function without ever resolving a namespace
|
|
5
|
+
tags: addon, scopes, authorization
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Addon scopes are resolved where the function runs
|
|
9
|
+
|
|
10
|
+
`wireAddon({ scopes })` names scopes every function in the addon's package
|
|
11
|
+
requires. `runPikkuFunc` calls `resolveAddonScopes(packageName,
|
|
12
|
+
addonInstance?.namespace)` and unions the result with the function's own
|
|
13
|
+
`scopes` before `verifyScopes`.
|
|
14
|
+
|
|
15
|
+
The obvious home for this is `resolveAddonFunction` in `rpc-runner.ts`, next to
|
|
16
|
+
where `auth` and `tags` are already merged from the addon config — but that
|
|
17
|
+
covers only the `namespace:function` RPC form. An addon function is reachable
|
|
18
|
+
without any namespace resolution: the inspector's `resolveAddonName` writes the
|
|
19
|
+
addon's package name onto the wiring meta whenever a wiring's `func` is an
|
|
20
|
+
identifier imported from a wired addon, and every runner (`http-runner`,
|
|
21
|
+
`mcp-runner`, channel, scheduler, queue, cli, trigger, gateway) then passes that
|
|
22
|
+
`packageName` straight to `runPikkuFunc`. `refHTTP` / `refChannel` / `refCLI`
|
|
23
|
+
contracts do the same through `registerHTTPRouteMeta`. A gate at namespace
|
|
24
|
+
resolution would leave every one of those doors open while reading as complete,
|
|
25
|
+
which is worse than no gate. `runPikkuFunc` is the one point all of them share.
|
|
26
|
+
|
|
27
|
+
Merging is a union, not an override, because `firstUnsatisfied` in `scopes.ts`
|
|
28
|
+
requires every listed scope. An addon scope is therefore an additional
|
|
29
|
+
requirement and can only narrow access — an addon can never weaken a function
|
|
30
|
+
that declares stricter scopes of its own. `ref('namespace:fn')` routes are
|
|
31
|
+
gated for the same reason from the other direction: the generated wrapper is a
|
|
32
|
+
local function that calls `rpc.invoke`, so the addon's scopes attach on the
|
|
33
|
+
inner call rather than the route.
|
|
34
|
+
|
|
35
|
+
When the caller carries an `addonInstance`, its namespace selects that
|
|
36
|
+
instance's scopes exactly. The direct-wiring paths know only a package name, so
|
|
37
|
+
`resolveAddonScopes` unions the scopes of every namespace the package is wired
|
|
38
|
+
under. One package wired twice with different scopes is rare; taking the
|
|
39
|
+
stricter reading keeps the unnamed path from becoming the weak one.
|
|
40
|
+
|
|
41
|
+
**What this rules out:** gating addon functions in `resolveAddonFunction`,
|
|
42
|
+
`resolveNamespace`, or any per-wiring runner; treating addon scopes as a
|
|
43
|
+
default that a function's own `scopes` replaces; resolving a package's scopes
|
|
44
|
+
by first matching namespace, the way `findAddonNamespaceForPackage` resolves
|
|
45
|
+
services; and reusing this for `wireRemoteAddon`, whose functions execute on the
|
|
46
|
+
host and are gated there.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Only a Symbol-branded framework result can request tool approval
|
|
4
|
+
description: Approval markers are trusted from the APPROVAL_REQUIRED Symbol on a forwardsApproval tool, never from a JSON key an LLM could emit
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Only a Symbol-branded framework result can request tool approval
|
|
9
|
+
|
|
10
|
+
`checkForApprovals` in
|
|
11
|
+
`packages/core/src/wirings/ai-agent/ai-agent-stream.ts` honours a forwarded
|
|
12
|
+
approval only when both hold: the tool declares `forwardsApproval` (set solely by
|
|
13
|
+
framework code on the sub-agent delegating tools built in
|
|
14
|
+
`ai-agent-prepare.ts`), and its result carries the `APPROVAL_REQUIRED` unique
|
|
15
|
+
Symbol. The companion `__approvalRequired` string key exists for transport, but
|
|
16
|
+
is never what the decision reads.
|
|
17
|
+
|
|
18
|
+
A tool result is attacker-influenceable — a retrieved document, a third-party API
|
|
19
|
+
response, or a sub-agent's LLM-shaped `result.object`. All of those are plain
|
|
20
|
+
JSON, and plain JSON cannot carry a Symbol. Trusting the string key would let any
|
|
21
|
+
ordinary tool conjure a suspension and an approval prompt showing a tool name and
|
|
22
|
+
arguments of its choosing.
|
|
23
|
+
|
|
24
|
+
**What this rules out:** checking `'__approvalRequired' in result` as the
|
|
25
|
+
condition; replacing the Symbol with a string or numeric sentinel so results
|
|
26
|
+
survive JSON serialization; and setting `forwardsApproval` from user-supplied
|
|
27
|
+
tool configuration rather than from framework code.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Credential requests are trusted only when Symbol-branded
|
|
4
|
+
description: The string key is a wire field; the Symbol is the capability, and only core can mint it
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Credential requests are trusted only when Symbol-branded
|
|
9
|
+
|
|
10
|
+
A tool result asking the run to suspend and prompt for a credential is honoured
|
|
11
|
+
only when it carries the `CREDENTIAL_REQUIRED` Symbol minted in
|
|
12
|
+
`ai-agent-prepare.ts`. `checkForCredentialRequests` in `ai-agent-stream.ts`
|
|
13
|
+
tests for that Symbol, never for the `__credentialRequired` string key that
|
|
14
|
+
travels beside it on the wire.
|
|
15
|
+
|
|
16
|
+
The distinction is the whole security property. Tool results are frequently
|
|
17
|
+
attacker-influenceable — a retrieved document, an echo from a third-party API,
|
|
18
|
+
LLM-authored content round-tripping through a tool — and any of those can carry
|
|
19
|
+
a string key. None can carry a Symbol, because a Symbol has no literal form and
|
|
20
|
+
does not survive JSON. Without the brand, an influenced tool result could
|
|
21
|
+
suspend the run and push a `credential-request` event with an attacker-chosen
|
|
22
|
+
`connectUrl`, which the client renders as a "Connect" button: a phishing
|
|
23
|
+
primitive inside the product's own UI. This mirrors the `APPROVAL_REQUIRED`
|
|
24
|
+
brand, which exists for the identical reason one function over.
|
|
25
|
+
|
|
26
|
+
The brand survives because the object is passed by reference the whole way —
|
|
27
|
+
core's `buildToolDefs` wrapper returns it, the Vercel adapter's `aiTool` hands
|
|
28
|
+
it back verbatim, and the AI SDK puts the raw value on the stream part rather
|
|
29
|
+
than the JSON form it builds separately for the model.
|
|
30
|
+
|
|
31
|
+
**What this rules out:** widening the check to `'__credentialRequired' in
|
|
32
|
+
result` for convenience, or introducing any path where a credential request is
|
|
33
|
+
reconstructed from parsed JSON rather than passed by reference — either one
|
|
34
|
+
silently converts the gate into a formality. Note the inverse holds for the
|
|
35
|
+
`credentialFilteredChannel` suppression later in the same file: that one
|
|
36
|
+
deliberately matches the *string* key, because it hides tool results from the
|
|
37
|
+
client and a broader match leaks less, not more.
|
package/knowledge/decisions/security/ai-agent-gate-requires-a-session-only-when-auth-is-true.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: An agent requires a session only when auth is true, but always enforces scopes and permissions
|
|
4
|
+
description: Agents follow pikkuSessionlessFunc semantics so crons and queue workers can run them; scopes are an AND gate checked before any permission I/O
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# An agent requires a session only when auth is true, but always enforces scopes and permissions
|
|
9
|
+
|
|
10
|
+
`assertAgentAuthorized` in
|
|
11
|
+
`packages/core/src/wirings/ai-agent/ai-agent-prepare.ts` enforces, in order:
|
|
12
|
+
session presence (only when `CoreAIAgent.auth === true`), then `scopes`, then
|
|
13
|
+
`permissions`. The ordering mirrors the function runner — scopes AND together so
|
|
14
|
+
they can only narrow access, and a missing scope short-circuits before any
|
|
15
|
+
permission function does I/O. Declared `scopes` are narrowed to the generated
|
|
16
|
+
`ScopeId` union in a project's `pikku-types.gen.ts`, so an undeclared scope is a
|
|
17
|
+
compile error.
|
|
18
|
+
|
|
19
|
+
`auth` defaults to `false` (i.e. `pikkuSessionlessFunc`, not `pikkuFunc`) because
|
|
20
|
+
an agent is normally reached from a function that already enforced its own auth,
|
|
21
|
+
and is also run from genuinely sessionless contexts such as crons and queue
|
|
22
|
+
workers. Requiring a session by default would reject those without adding a real
|
|
23
|
+
gate. Global permissions are evaluated here too rather than assumed to have
|
|
24
|
+
already run, because an agent is reachable from entry points that never pass
|
|
25
|
+
through the function runner; re-evaluating an AND gate of side-effect-free
|
|
26
|
+
predicates is idempotent.
|
|
27
|
+
|
|
28
|
+
**What this rules out:** making `auth: true` the default; checking permissions
|
|
29
|
+
before scopes; skipping globals on the assumption a caller already ran them; and
|
|
30
|
+
moving the gate into the individual run/stream/resume entry points, where a new
|
|
31
|
+
entry point would silently miss it.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: An agent ownership failure never echoes the resource it refused
|
|
4
|
+
description: assertResourceOwner throws a bare ForbiddenError so the error cannot be used as an existence oracle, at the cost of thinner debugging output
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# An agent ownership failure never echoes the resource it refused
|
|
9
|
+
|
|
10
|
+
`assertResourceOwner` in
|
|
11
|
+
`packages/core/src/wirings/ai-agent/ai-agent-prepare.ts` compares a stored
|
|
12
|
+
thread/run `resourceId` against the caller's composed owner key and throws
|
|
13
|
+
`ForbiddenError('Not authorized to access this thread' | '… run')` on a
|
|
14
|
+
mismatch. The message deliberately carries no id.
|
|
15
|
+
|
|
16
|
+
Including the id would turn the endpoint into an existence oracle: a caller
|
|
17
|
+
enumerating thread ids could tell "exists but is not yours" apart from "does not
|
|
18
|
+
exist", which leaks the shape of other tenants' data even though no content is
|
|
19
|
+
returned.
|
|
20
|
+
|
|
21
|
+
**What this rules out:** improving the error message by interpolating the
|
|
22
|
+
`threadId`, `runId`, or owner key into it, and distinguishing not-found from
|
|
23
|
+
not-authorized on the read paths.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Resuming a suspended agent run re-runs the agent's authorization gate
|
|
4
|
+
description: Ownership of the run is not enough — a grant revoked while the run was suspended must block the approval
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Resuming a suspended agent run re-runs the agent's authorization gate
|
|
9
|
+
|
|
10
|
+
Both `resumeAIAgent` (`ai-agent-stream.ts`) and `resumeAIAgentSync`
|
|
11
|
+
(`ai-agent-runner.ts`) call `assertAgentAuthorized` after asserting run
|
|
12
|
+
ownership and before touching `aiRunState.resolveApproval`.
|
|
13
|
+
|
|
14
|
+
Ownership proves the run belongs to the caller, not that the caller may still
|
|
15
|
+
act on it: a suspension can outlive the permission that created it, and the whole
|
|
16
|
+
point of an approval gate is that the person approving is authorized at the
|
|
17
|
+
moment of approval. Resolving an approval is a persisted side effect, so the
|
|
18
|
+
gate must run before it, not after.
|
|
19
|
+
|
|
20
|
+
**What this rules out:** treating the ownership assertion as the complete
|
|
21
|
+
authorization check on the resume paths, and moving `assertAgentAuthorized`
|
|
22
|
+
below `resolveApproval` for convenience.
|
package/knowledge/decisions/security/ai-agent-sessionless-deployments-have-no-thread-ownership.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Agent thread ownership fails closed when there is no principal
|
|
4
|
+
description: A sessionless caller gets an ephemeral owner and reaches no stored thread, rather than reaching all of them
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Agent thread ownership fails closed when there is no principal
|
|
9
|
+
|
|
10
|
+
`canAccessThread` returns `false` and `threadOwnerConstraint` returns `[]` when
|
|
11
|
+
the session carries neither `userId` nor `orgId`
|
|
12
|
+
(`packages/core/src/wirings/ai-agent/ai-agent-prepare.ts`).
|
|
13
|
+
`resolveOwnerResourceId` never accepts the client-supplied `resourceId` as an
|
|
14
|
+
ownership key; without a principal it mints an ephemeral `anon-<uuid>` owner
|
|
15
|
+
memoized on the request's params object.
|
|
16
|
+
|
|
17
|
+
Agent wirings default to `auth: false`, so "no session" is the common case
|
|
18
|
+
rather than an exotic one. Treating it as "no ownership model to enforce" made
|
|
19
|
+
every ownership check vacuous: a caller named any `resourceId` and reached that
|
|
20
|
+
thread, and because `undefined` on `AgentRunService.listThreads` means *no
|
|
21
|
+
filter* rather than *no rows*, a sessionless `getAgentThreads` returned every
|
|
22
|
+
thread in the deployment. The ephemeral owner is what keeps one-shot
|
|
23
|
+
conversations working while denying continuity — it is unguessable, so nothing
|
|
24
|
+
stored can be reached, and it is stable within a request, so a sub-agent
|
|
25
|
+
re-entering `resolveOwnerResourceId` reuses its parent's thread.
|
|
26
|
+
|
|
27
|
+
Memoizing on the params object rather than a module-level Map is what keeps this
|
|
28
|
+
serverless-safe: the identity dies with the request and is never shared between
|
|
29
|
+
instances. `canAccessThread` stays a predicate rather than an assertion so it can
|
|
30
|
+
back a `pikkuPermission` — authorization belongs in a function's `permissions`
|
|
31
|
+
field, never in its body.
|
|
32
|
+
|
|
33
|
+
**What this rules out:** returning `undefined` from `threadOwnerConstraint` for
|
|
34
|
+
any caller; deriving `owners` from request input instead of the session; reading
|
|
35
|
+
`auth: false` as permission to skip ownership on a *stored* thread; and
|
|
36
|
+
persisting the anonymous owner anywhere, which would turn an ephemeral identity
|
|
37
|
+
into a forgeable one. Cross-request thread continuity without a session is not
|
|
38
|
+
available by design — wire a session to get it back. See
|
|
39
|
+
[[an-empty-owners-constraint-matches-nothing]].
|
package/knowledge/decisions/security/ai-agent-thread-ownership-composes-the-session-principal.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: An agent thread key is always prefixed with the trusted principal
|
|
4
|
+
description: Ownership keys are composed as principal:resourceId, so a client id can sub-divide its own boundary but never widen it
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# An agent thread key is always prefixed with the trusted principal
|
|
9
|
+
|
|
10
|
+
`resolveOwnerResourceId` in `packages/core/src/wirings/ai-agent/ai-agent-prepare.ts`
|
|
11
|
+
composes the ownership key for a thread or run as `principal:resourceId`. The
|
|
12
|
+
principal is the trusted one — `session.userId` for the default `'user'`
|
|
13
|
+
`SessionScope`, `session.orgId` for `'org'` — and the client-supplied
|
|
14
|
+
`resourceId` is only ever a sub-partition inside it. Composition is idempotent:
|
|
15
|
+
a value already inside the caller's namespace (top-level re-entry, sub-agent
|
|
16
|
+
recursion, resume — all of which pass an already-composite id) is returned
|
|
17
|
+
unchanged rather than composed twice.
|
|
18
|
+
|
|
19
|
+
`'org'` scope with no org on the session throws `ForbiddenError` instead of
|
|
20
|
+
falling back to a bare or shared key, because a shared key leaks threads across
|
|
21
|
+
organizations. A sessionless `'user'` wiring has no trusted principal at all and
|
|
22
|
+
falls back to the requested `resourceId` as a best-effort partition.
|
|
23
|
+
`isOwnedByPrincipal` requires the `:` separator when matching sub-partitions so
|
|
24
|
+
that a principal `alice` does not match a lookalike `alice-evil:…` key.
|
|
25
|
+
|
|
26
|
+
**What this rules out:** storing threads under the client's `resourceId`
|
|
27
|
+
directly; making the composition non-idempotent (resume and sub-agent recursion
|
|
28
|
+
would double-prefix and lose their own threads); testing ownership with a bare
|
|
29
|
+
`startsWith(principal)` that omits the separator; and letting `'org'` scope
|
|
30
|
+
degrade to a shared key when the session carries no organization.
|
package/knowledge/decisions/security/ai-agent-tool-filtering-reads-the-live-function-config.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: Agent tool permission filtering reads the live function config, not the metadata
|
|
4
|
+
description: The pikkuAuth brand survives only on live permission objects, so a metadata-driven check would silently admit every gated tool
|
|
5
|
+
tags: ai-agent
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Agent tool permission filtering reads the live function config, not the metadata
|
|
9
|
+
|
|
10
|
+
`buildToolDefs` in `packages/core/src/wirings/ai-agent/ai-agent-prepare.ts`
|
|
11
|
+
decides which tools and sub-agents to expose to the model by calling
|
|
12
|
+
`checkAuthPermissions` against the permission objects held in the live function
|
|
13
|
+
(or agent) config in `pikkuState`, using the metadata only to learn that a
|
|
14
|
+
permission exists at all.
|
|
15
|
+
|
|
16
|
+
The `pikkuAuth` brand that marks a permission as an authorization gate exists
|
|
17
|
+
only on those live objects. The metadata's by-name permission registry is never
|
|
18
|
+
populated, so resolving names through it collects no predicates — and a filter
|
|
19
|
+
that collects no predicates admits everything. The failure is silent: every gated
|
|
20
|
+
tool would be handed to the model for any session.
|
|
21
|
+
|
|
22
|
+
**What this rules out:** simplifying the filter to read
|
|
23
|
+
`fnMeta.permissions` / `subMeta.permissions` directly, and caching a
|
|
24
|
+
name-to-predicate map derived from metadata.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: An empty owners constraint matches nothing
|
|
4
|
+
description: owners is an authorization boundary, so every storage backend must treat [] as no rows rather than no filter
|
|
5
|
+
tags: ai-agent, storage
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# An empty owners constraint matches nothing
|
|
9
|
+
|
|
10
|
+
Every `AgentRunService.listThreads` implementation returns `[]` immediately when
|
|
11
|
+
`owners` is present and empty — `kysely-ai-agent-run-service.ts`,
|
|
12
|
+
`redis-agent-run-service.ts`, `mongodb-agent-run-service.ts`. The conformance
|
|
13
|
+
suite in `packages/core/src/testing/service-tests.ts` pins it, so a new backend
|
|
14
|
+
inherits the requirement instead of rediscovering it.
|
|
15
|
+
|
|
16
|
+
`owners` is an authorization boundary, not an optional filter. The natural way
|
|
17
|
+
to write a query builder is to skip a clause when its list is empty, which
|
|
18
|
+
silently converts "this caller may see nothing" into "this caller may see
|
|
19
|
+
everything" — the failure is invisible in review because the omitted clause
|
|
20
|
+
looks like an optimization. Placing the guard before the query is built, in
|
|
21
|
+
every backend, means the dangerous shape never exists.
|
|
22
|
+
|
|
23
|
+
This is what makes the sessionless `[]` from `threadOwnerConstraint` safe to
|
|
24
|
+
return; the two decisions only hold together.
|
|
25
|
+
|
|
26
|
+
**What this rules out:** folding the empty case into the query builder's normal
|
|
27
|
+
`if (owners)` path; treating `owners: []` as equivalent to `owners: undefined`
|
|
28
|
+
at any layer; and adding a backend without the conformance suite.
|
|
29
|
+
|
|
30
|
+
See [[ai-agent-sessionless-deployments-have-no-thread-ownership]].
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: decision
|
|
3
|
+
title: An exposed function with no gate is reported at codegen, not at boot
|
|
4
|
+
description: The check runs in the inspector where function meta and every wireAddon declaration are both in hand, because neither source alone can tell a gated function from an ungated one
|
|
5
|
+
tags: authorization, inspector, addon, rpc
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# An exposed function with no gate is reported at codegen, not at boot
|
|
9
|
+
|
|
10
|
+
The generated `POST /rpc/:rpcName` dispatcher forwards to `rpc.exposed`, which
|
|
11
|
+
refuses anything without `expose: true`. That makes the reachable set small and
|
|
12
|
+
deliberate — someone typed it. What it does not do is check whether the target
|
|
13
|
+
is gated, because a dispatcher cannot know what it is dispatching to. The
|
|
14
|
+
console shipped ~54 privileged functions through exactly this gap, and nothing
|
|
15
|
+
in the toolchain said so.
|
|
16
|
+
|
|
17
|
+
The check belongs next to `validateAuthSessionless`, in the inspector, for one
|
|
18
|
+
reason: it needs two sources that only meet there.
|
|
19
|
+
|
|
20
|
+
`sessionless` records the baseline — a `pikkuFunc` always requires a session —
|
|
21
|
+
but a `pikkuSessionlessFunc` may still tighten itself with `auth: true`, which
|
|
22
|
+
the inspector previously discarded. It is now recorded on function meta, so
|
|
23
|
+
"sessionless and ungated" is distinguishable from "sessionless and
|
|
24
|
+
self-gated" without running anything.
|
|
25
|
+
|
|
26
|
+
The second source is `wireAddon`. Its `scopes` and `auth` apply to every
|
|
27
|
+
function in the package on every wiring path (see
|
|
28
|
+
[addon scopes](./addon-scopes-are-resolved-where-the-function-runs.md)), so a
|
|
29
|
+
function with no gate of its own may still be fully covered. The inspector
|
|
30
|
+
already parsed `wireAddon` for its endpoint and its secret, variable and
|
|
31
|
+
credential overrides, and dropped `scopes`, `auth` and `tags` — the addon's
|
|
32
|
+
plumbing was recorded in full and its authorization was not. Reading function
|
|
33
|
+
meta alone would have reported every console function as open.
|
|
34
|
+
|
|
35
|
+
An addon whose gates are not statically knowable — a spread, a const reference —
|
|
36
|
+
is recorded as absent, and absent is read as **gated**. This is deliberately the
|
|
37
|
+
wrong way round from how a runtime gate fails: a false negative costs one
|
|
38
|
+
missing warning, while a false positive on a correctly-secured addon costs
|
|
39
|
+
confidence in every warning the tool emits, which is worth more than the one
|
|
40
|
+
case it would catch.
|
|
41
|
+
|
|
42
|
+
Severity is `warn`, not `critical`. `expose: true` on an ungated sessionless
|
|
43
|
+
function is legitimate for a genuinely public endpoint — a health check, a
|
|
44
|
+
sign-up — so this cannot block a build without breaking correct programs. It
|
|
45
|
+
fails a build only under `--fail-on-warn`.
|
|
46
|
+
|
|
47
|
+
**What this rules out:** checking at boot, where the report arrives after
|
|
48
|
+
deployment; checking in `pikku validate` from `.pikku` JSON, which does not
|
|
49
|
+
carry `wireAddon` at all; and treating an unparseable addon gate as no gate.
|