@claude-flow/cli 3.32.29 → 3.32.32
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/.claude/helpers/helpers.manifest.json +2 -2
- package/catalog-manifest.json +2 -2
- package/dist/src/autopilot-state.d.ts +10 -0
- package/dist/src/autopilot-state.js +16 -0
- package/dist/src/commands/autopilot.js +10 -4
- package/dist/src/init/claudemd-generator.js +53 -2
- package/dist/src/mcp-tools/autopilot-tools.js +18 -3
- package/dist/src/mcp-tools/capability-brain.js +22 -22
- package/dist/src/mcp-tools/guidance-tools.js +1 -1
- package/dist/src/services/harness-flywheel-runtime.d.ts +21 -1
- package/dist/src/services/harness-flywheel-runtime.js +46 -24
- package/node_modules/@claude-flow/codex/.agents/skills/memory-management/SKILL.md +45 -0
- package/node_modules/@claude-flow/codex/.agents/skills/security-audit/SKILL.md +46 -0
- package/node_modules/@claude-flow/codex/.agents/skills/sparc-methodology/SKILL.md +46 -0
- package/node_modules/@claude-flow/codex/.agents/skills/swarm-orchestration/SKILL.md +53 -0
- package/node_modules/@claude-flow/codex/README.md +1044 -0
- package/node_modules/@claude-flow/codex/dist/cli.d.ts +9 -0
- package/node_modules/@claude-flow/codex/dist/cli.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/cli.js +686 -0
- package/node_modules/@claude-flow/codex/dist/cli.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/cli.d.ts +17 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/cli.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/cli.js +278 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/cli.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/index.d.ts +8 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/index.js +7 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/index.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/orchestrator.d.ts +143 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/orchestrator.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/orchestrator.js +621 -0
- package/node_modules/@claude-flow/codex/dist/dual-mode/orchestrator.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/generators/agents-md.d.ts +12 -0
- package/node_modules/@claude-flow/codex/dist/generators/agents-md.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/generators/agents-md.js +730 -0
- package/node_modules/@claude-flow/codex/dist/generators/agents-md.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/generators/config-toml.d.ts +74 -0
- package/node_modules/@claude-flow/codex/dist/generators/config-toml.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/generators/config-toml.js +922 -0
- package/node_modules/@claude-flow/codex/dist/generators/config-toml.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/generators/index.d.ts +9 -0
- package/node_modules/@claude-flow/codex/dist/generators/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/generators/index.js +9 -0
- package/node_modules/@claude-flow/codex/dist/generators/index.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/generators/skill-md.d.ts +20 -0
- package/node_modules/@claude-flow/codex/dist/generators/skill-md.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/generators/skill-md.js +951 -0
- package/node_modules/@claude-flow/codex/dist/generators/skill-md.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/build-evidence.d.ts +46 -0
- package/node_modules/@claude-flow/codex/dist/harness/build-evidence.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/build-evidence.js +126 -0
- package/node_modules/@claude-flow/codex/dist/harness/build-evidence.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/contract.d.ts +153 -0
- package/node_modules/@claude-flow/codex/dist/harness/contract.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/contract.js +44 -0
- package/node_modules/@claude-flow/codex/dist/harness/contract.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-fenced-lease-reference.d.ts +33 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-fenced-lease-reference.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-fenced-lease-reference.js +175 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-fenced-lease-reference.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-inbox-reference.d.ts +42 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-inbox-reference.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-inbox-reference.js +140 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-inbox-reference.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-run-receipt-reference.d.ts +19 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-run-receipt-reference.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-run-receipt-reference.js +79 -0
- package/node_modules/@claude-flow/codex/dist/harness/in-memory-run-receipt-reference.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/index.d.ts +9 -0
- package/node_modules/@claude-flow/codex/dist/harness/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/index.js +9 -0
- package/node_modules/@claude-flow/codex/dist/harness/index.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/portable-case-fold.d.ts +8 -0
- package/node_modules/@claude-flow/codex/dist/harness/portable-case-fold.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/portable-case-fold.js +10 -0
- package/node_modules/@claude-flow/codex/dist/harness/portable-case-fold.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/repository-state.d.ts +68 -0
- package/node_modules/@claude-flow/codex/dist/harness/repository-state.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/repository-state.js +403 -0
- package/node_modules/@claude-flow/codex/dist/harness/repository-state.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/unsigned-integer.d.ts +3 -0
- package/node_modules/@claude-flow/codex/dist/harness/unsigned-integer.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/harness/unsigned-integer.js +14 -0
- package/node_modules/@claude-flow/codex/dist/harness/unsigned-integer.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/index.d.ts +53 -0
- package/node_modules/@claude-flow/codex/dist/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/index.js +54 -0
- package/node_modules/@claude-flow/codex/dist/index.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/initializer.d.ts +98 -0
- package/node_modules/@claude-flow/codex/dist/initializer.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/initializer.js +795 -0
- package/node_modules/@claude-flow/codex/dist/initializer.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/loop/cli.d.ts +3 -0
- package/node_modules/@claude-flow/codex/dist/loop/cli.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/loop/cli.js +123 -0
- package/node_modules/@claude-flow/codex/dist/loop/cli.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/loop/index.d.ts +58 -0
- package/node_modules/@claude-flow/codex/dist/loop/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/loop/index.js +230 -0
- package/node_modules/@claude-flow/codex/dist/loop/index.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/mcp-config.d.ts +28 -0
- package/node_modules/@claude-flow/codex/dist/mcp-config.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/mcp-config.js +121 -0
- package/node_modules/@claude-flow/codex/dist/mcp-config.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/migrations/index.d.ts +114 -0
- package/node_modules/@claude-flow/codex/dist/migrations/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/migrations/index.js +880 -0
- package/node_modules/@claude-flow/codex/dist/migrations/index.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/templates/index.d.ts +92 -0
- package/node_modules/@claude-flow/codex/dist/templates/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/templates/index.js +284 -0
- package/node_modules/@claude-flow/codex/dist/templates/index.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/types.d.ts +240 -0
- package/node_modules/@claude-flow/codex/dist/types.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/types.js +8 -0
- package/node_modules/@claude-flow/codex/dist/types.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/validators/index.d.ts +42 -0
- package/node_modules/@claude-flow/codex/dist/validators/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/validators/index.js +929 -0
- package/node_modules/@claude-flow/codex/dist/validators/index.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/worktrees/coordinator.d.ts +37 -0
- package/node_modules/@claude-flow/codex/dist/worktrees/coordinator.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/worktrees/coordinator.js +137 -0
- package/node_modules/@claude-flow/codex/dist/worktrees/coordinator.js.map +1 -0
- package/node_modules/@claude-flow/codex/dist/worktrees/index.d.ts +2 -0
- package/node_modules/@claude-flow/codex/dist/worktrees/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/codex/dist/worktrees/index.js +2 -0
- package/node_modules/@claude-flow/codex/dist/worktrees/index.js.map +1 -0
- package/node_modules/@claude-flow/codex/package.json +122 -0
- package/node_modules/@claude-flow/plugin-agent-federation/README.md +49 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/agent-card.d.ts +130 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/agent-card.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/agent-card.js +239 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/agent-card.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/consume.d.ts +34 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/consume.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/consume.js +69 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/consume.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/well-known.d.ts +46 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/well-known.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/well-known.js +84 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/a2a/well-known.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/claim-checker.d.ts +27 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/claim-checker.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/claim-checker.js +46 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/claim-checker.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-breaker-service.d.ts +192 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-breaker-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-breaker-service.js +253 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-breaker-service.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-coordinator.d.ts +211 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-coordinator.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-coordinator.js +501 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/federation-coordinator.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/inbound-dispatcher.d.ts +114 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/inbound-dispatcher.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/inbound-dispatcher.js +356 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/inbound-dispatcher.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/policy-engine.d.ts +41 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/policy-engine.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/policy-engine.js +184 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/policy-engine.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/spend-reporter.d.ts +150 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/spend-reporter.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/spend-reporter.js +128 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/spend-reporter.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/trust-evaluator.d.ts +74 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/trust-evaluator.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/trust-evaluator.js +179 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/application/trust-evaluator.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.d.ts +13 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +189 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/cli-commands.d.ts +7 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/cli-commands.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/cli-commands.js +317 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/cli-commands.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-envelope.d.ts +45 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-envelope.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-envelope.js +71 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-envelope.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-node.d.ts +104 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-node.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-node.js +152 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-node.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-session.d.ts +55 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-session.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-session.js +105 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/federation-session.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/trust-level.d.ts +17 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/trust-level.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/trust-level.js +35 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/entities/trust-level.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/audit-service.d.ts +69 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/audit-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/audit-service.js +149 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/audit-service.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/discovery-service.d.ts +68 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/discovery-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/discovery-service.js +161 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/discovery-service.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/handshake-service.d.ts +58 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/handshake-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/handshake-service.js +122 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/handshake-service.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/pii-pipeline-service.d.ts +65 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/pii-pipeline-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/pii-pipeline-service.js +208 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/pii-pipeline-service.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.d.ts +51 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.js +147 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/routing-service.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-firewall-service.d.ts +71 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-firewall-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-firewall-service.js +194 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-firewall-service.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-mesh-service.d.ts +156 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-mesh-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-mesh-service.js +292 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-mesh-service.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-witness-service.d.ts +98 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-witness-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-witness-service.js +122 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-witness-service.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/federation-budget.d.ts +89 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/federation-budget.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/federation-budget.js +165 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/federation-budget.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/federation-node-state.d.ts +92 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/federation-node-state.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/federation-node-state.js +100 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/federation-node-state.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/wg-config.d.ts +70 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/wg-config.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/wg-config.js +104 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/value-objects/wg-config.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/index.d.ts +23 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/index.js +24 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/index.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/mcp-tools.d.ts +10 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/mcp-tools.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/mcp-tools.js +439 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/mcp-tools.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.d.ts +19 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.js +515 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/plugin.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/transport/midstream-aware-loader.d.ts +72 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/transport/midstream-aware-loader.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/transport/midstream-aware-loader.js +269 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/transport/midstream-aware-loader.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/version.d.ts +3 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/version.d.ts.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/version.js +3 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/version.js.map +1 -0
- package/node_modules/@claude-flow/plugin-agent-federation/package.json +64 -0
- package/node_modules/@claude-flow/security/README.md +292 -0
- package/node_modules/@claude-flow/security/dist/CVE-REMEDIATION.d.ts +97 -0
- package/node_modules/@claude-flow/security/dist/CVE-REMEDIATION.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/CVE-REMEDIATION.js +537 -0
- package/node_modules/@claude-flow/security/dist/CVE-REMEDIATION.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/application/index.d.ts +7 -0
- package/node_modules/@claude-flow/security/dist/application/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/application/index.js +7 -0
- package/node_modules/@claude-flow/security/dist/application/index.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/application/services/security-application-service.d.ts +71 -0
- package/node_modules/@claude-flow/security/dist/application/services/security-application-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/application/services/security-application-service.js +153 -0
- package/node_modules/@claude-flow/security/dist/application/services/security-application-service.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/authorization/propagator.d.ts +148 -0
- package/node_modules/@claude-flow/security/dist/authorization/propagator.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/authorization/propagator.js +182 -0
- package/node_modules/@claude-flow/security/dist/authorization/propagator.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/credential-generator.d.ts +176 -0
- package/node_modules/@claude-flow/security/dist/credential-generator.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/credential-generator.js +272 -0
- package/node_modules/@claude-flow/security/dist/credential-generator.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/domain/entities/security-context.d.ts +68 -0
- package/node_modules/@claude-flow/security/dist/domain/entities/security-context.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/domain/entities/security-context.js +132 -0
- package/node_modules/@claude-flow/security/dist/domain/entities/security-context.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/domain/index.d.ts +8 -0
- package/node_modules/@claude-flow/security/dist/domain/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/domain/index.js +8 -0
- package/node_modules/@claude-flow/security/dist/domain/index.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/domain/services/security-domain-service.d.ts +71 -0
- package/node_modules/@claude-flow/security/dist/domain/services/security-domain-service.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/domain/services/security-domain-service.js +237 -0
- package/node_modules/@claude-flow/security/dist/domain/services/security-domain-service.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/index.d.ts +129 -0
- package/node_modules/@claude-flow/security/dist/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/index.js +176 -0
- package/node_modules/@claude-flow/security/dist/index.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/input-validator.d.ts +306 -0
- package/node_modules/@claude-flow/security/dist/input-validator.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/input-validator.js +393 -0
- package/node_modules/@claude-flow/security/dist/input-validator.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/keychain-adapter.d.ts +48 -0
- package/node_modules/@claude-flow/security/dist/keychain-adapter.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/keychain-adapter.js +0 -0
- package/node_modules/@claude-flow/security/dist/keychain-adapter.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/mcp-composition-inspector.d.ts +133 -0
- package/node_modules/@claude-flow/security/dist/mcp-composition-inspector.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/mcp-composition-inspector.js +254 -0
- package/node_modules/@claude-flow/security/dist/mcp-composition-inspector.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/oauth/browser.d.ts +31 -0
- package/node_modules/@claude-flow/security/dist/oauth/browser.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/oauth/browser.js +55 -0
- package/node_modules/@claude-flow/security/dist/oauth/browser.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/oauth/callback-server.d.ts +37 -0
- package/node_modules/@claude-flow/security/dist/oauth/callback-server.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/oauth/callback-server.js +86 -0
- package/node_modules/@claude-flow/security/dist/oauth/callback-server.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/oauth/client.d.ts +57 -0
- package/node_modules/@claude-flow/security/dist/oauth/client.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/oauth/client.js +120 -0
- package/node_modules/@claude-flow/security/dist/oauth/client.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/oauth/pkce.d.ts +25 -0
- package/node_modules/@claude-flow/security/dist/oauth/pkce.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/oauth/pkce.js +36 -0
- package/node_modules/@claude-flow/security/dist/oauth/pkce.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/password-hasher.d.ts +128 -0
- package/node_modules/@claude-flow/security/dist/password-hasher.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/password-hasher.js +190 -0
- package/node_modules/@claude-flow/security/dist/password-hasher.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/path-validator.d.ts +148 -0
- package/node_modules/@claude-flow/security/dist/path-validator.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/path-validator.js +421 -0
- package/node_modules/@claude-flow/security/dist/path-validator.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/plugins/integrity-verifier.d.ts +125 -0
- package/node_modules/@claude-flow/security/dist/plugins/integrity-verifier.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/plugins/integrity-verifier.js +186 -0
- package/node_modules/@claude-flow/security/dist/plugins/integrity-verifier.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/canonical.d.ts +5 -0
- package/node_modules/@claude-flow/security/dist/policy/canonical.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/canonical.js +30 -0
- package/node_modules/@claude-flow/security/dist/policy/canonical.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/engine.d.ts +34 -0
- package/node_modules/@claude-flow/security/dist/policy/engine.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/engine.js +285 -0
- package/node_modules/@claude-flow/security/dist/policy/engine.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/envelope.d.ts +9 -0
- package/node_modules/@claude-flow/security/dist/policy/envelope.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/envelope.js +90 -0
- package/node_modules/@claude-flow/security/dist/policy/envelope.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/evaluator.d.ts +4 -0
- package/node_modules/@claude-flow/security/dist/policy/evaluator.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/evaluator.js +119 -0
- package/node_modules/@claude-flow/security/dist/policy/evaluator.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/index.d.ts +7 -0
- package/node_modules/@claude-flow/security/dist/policy/index.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/index.js +7 -0
- package/node_modules/@claude-flow/security/dist/policy/index.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/product-plane.d.ts +238 -0
- package/node_modules/@claude-flow/security/dist/policy/product-plane.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/product-plane.js +1022 -0
- package/node_modules/@claude-flow/security/dist/policy/product-plane.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/types.d.ts +169 -0
- package/node_modules/@claude-flow/security/dist/policy/types.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/policy/types.js +2 -0
- package/node_modules/@claude-flow/security/dist/policy/types.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/safe-executor.d.ts +180 -0
- package/node_modules/@claude-flow/security/dist/safe-executor.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/safe-executor.js +390 -0
- package/node_modules/@claude-flow/security/dist/safe-executor.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/token-generator.d.ts +224 -0
- package/node_modules/@claude-flow/security/dist/token-generator.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/token-generator.js +351 -0
- package/node_modules/@claude-flow/security/dist/token-generator.js.map +1 -0
- package/node_modules/@claude-flow/security/dist/tool-output-guardrail.d.ts +126 -0
- package/node_modules/@claude-flow/security/dist/tool-output-guardrail.d.ts.map +1 -0
- package/node_modules/@claude-flow/security/dist/tool-output-guardrail.js +257 -0
- package/node_modules/@claude-flow/security/dist/tool-output-guardrail.js.map +1 -0
- package/node_modules/@claude-flow/security/package.json +44 -0
- package/package.json +24 -8
|
@@ -0,0 +1,1022 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cognitum product-plane claim federation primitives.
|
|
3
|
+
*
|
|
4
|
+
* This module intentionally contains no grant-verification or domain mutation
|
|
5
|
+
* logic. It validates the portable, reference-only envelope that a local
|
|
6
|
+
* policy enforcement point can evaluate before consulting its authoritative
|
|
7
|
+
* identity, tenancy, and permission stores.
|
|
8
|
+
*/
|
|
9
|
+
import { createHash, verify as verifyCryptoSignature } from 'node:crypto';
|
|
10
|
+
export const PRODUCT_ACTION_ENVELOPE_VERSION = 'cognitum.action.v1';
|
|
11
|
+
export const PRODUCT_ACTIONS = [
|
|
12
|
+
'dashboard.read',
|
|
13
|
+
'dashboard.status.read',
|
|
14
|
+
'inference.invoke',
|
|
15
|
+
'inference.stream',
|
|
16
|
+
'usage.read',
|
|
17
|
+
'pod.spawn',
|
|
18
|
+
'benchmark.run',
|
|
19
|
+
'evolution.propose',
|
|
20
|
+
'evolution.promote',
|
|
21
|
+
'comms.thread.read',
|
|
22
|
+
'comms.thread.post',
|
|
23
|
+
'comms.projection.read',
|
|
24
|
+
'comms.board.admin',
|
|
25
|
+
'cog.proposal.create',
|
|
26
|
+
'cog.proposal.review',
|
|
27
|
+
'cog.proposal.approve',
|
|
28
|
+
'cog.instance.acquire',
|
|
29
|
+
'cog.instance.operate',
|
|
30
|
+
'cog.deploy',
|
|
31
|
+
'cog.rollback',
|
|
32
|
+
'ruview.space.read',
|
|
33
|
+
'ruview.semantic.publish',
|
|
34
|
+
'ruview.automation.propose',
|
|
35
|
+
'ruview.automation.approve',
|
|
36
|
+
'ruview.device.command',
|
|
37
|
+
'cognition.route',
|
|
38
|
+
'cognition.critique',
|
|
39
|
+
'memory.recall',
|
|
40
|
+
'memory.propose',
|
|
41
|
+
'evidence.read',
|
|
42
|
+
'memory.commit-validated',
|
|
43
|
+
];
|
|
44
|
+
export const PRODUCT_AUTHORITIES = [
|
|
45
|
+
'cognitum.control-plane',
|
|
46
|
+
'cognitum.cog',
|
|
47
|
+
'meta-llm',
|
|
48
|
+
'comms',
|
|
49
|
+
'agentbbs',
|
|
50
|
+
'ruview.edge',
|
|
51
|
+
'ruflo.policy',
|
|
52
|
+
'ruflo.memory',
|
|
53
|
+
];
|
|
54
|
+
export const IDENTITY_NAMESPACES = [
|
|
55
|
+
'cognitum-principal',
|
|
56
|
+
'firebase-subject',
|
|
57
|
+
'meta-llm-account',
|
|
58
|
+
'agentbbs-public-key',
|
|
59
|
+
'workload',
|
|
60
|
+
'ruflo-agent',
|
|
61
|
+
'legacy-principal',
|
|
62
|
+
];
|
|
63
|
+
export const TENANT_NAMESPACES = [
|
|
64
|
+
'cognitum-tenant',
|
|
65
|
+
'meta-llm-account',
|
|
66
|
+
'meta-llm-sub-tenant',
|
|
67
|
+
'comms-tenant',
|
|
68
|
+
'agentbbs-board',
|
|
69
|
+
'ruview-space',
|
|
70
|
+
];
|
|
71
|
+
export function classifyProductAvailability(dimensions) {
|
|
72
|
+
if (dimensions.authorized === 'no' || dimensions.identity === 'invalid')
|
|
73
|
+
return 'blocked';
|
|
74
|
+
if (dimensions.configured === 'no' || dimensions.reachable === 'no' || dimensions.healthy === 'no') {
|
|
75
|
+
return 'unavailable';
|
|
76
|
+
}
|
|
77
|
+
if (dimensions.identity === 'verified'
|
|
78
|
+
&& dimensions.configured === 'yes'
|
|
79
|
+
&& dimensions.reachable === 'yes'
|
|
80
|
+
&& dimensions.healthy === 'yes'
|
|
81
|
+
&& dimensions.authorized === 'yes') {
|
|
82
|
+
return 'available';
|
|
83
|
+
}
|
|
84
|
+
return 'degraded';
|
|
85
|
+
}
|
|
86
|
+
const ACTION_SET = new Set(PRODUCT_ACTIONS);
|
|
87
|
+
const AUTHORITY_SET = new Set(PRODUCT_AUTHORITIES);
|
|
88
|
+
const IDENTITY_NAMESPACE_SET = new Set(IDENTITY_NAMESPACES);
|
|
89
|
+
const TENANT_NAMESPACE_SET = new Set(TENANT_NAMESPACES);
|
|
90
|
+
const PRIVACY_CLASS_SET = new Set(['P0', 'P1', 'P2', 'P3']);
|
|
91
|
+
const SHA256_RE = /^sha256:[a-f0-9]{64}$/;
|
|
92
|
+
const UNSIGNED_DECIMAL_RE = /^(0|[1-9][0-9]*)$/;
|
|
93
|
+
const CANONICAL_TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
94
|
+
const SAFE_TOKEN_RE = /^[A-Za-z0-9][A-Za-z0-9._:/@+-]*$/;
|
|
95
|
+
const SOURCE_TYPE_RE = /^[a-z][a-z0-9.-]{1,63}\/[a-z][a-z0-9.-]{0,63}$/;
|
|
96
|
+
const BASE64_SHAPED_RE = /^(?:[A-Za-z0-9+/]{4}){7,}(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
97
|
+
const BASE64URL_SHAPED_RE = /^[A-Za-z0-9_-]{32,}$/;
|
|
98
|
+
const ENVELOPE_FIELDS = new Set([
|
|
99
|
+
'schemaVersion',
|
|
100
|
+
'eventId',
|
|
101
|
+
'issuer',
|
|
102
|
+
'audience',
|
|
103
|
+
'subject',
|
|
104
|
+
'actor',
|
|
105
|
+
'tenantRef',
|
|
106
|
+
'action',
|
|
107
|
+
'resourceRefs',
|
|
108
|
+
'requestDigest',
|
|
109
|
+
'contentDigest',
|
|
110
|
+
'idempotencyKey',
|
|
111
|
+
'correlationId',
|
|
112
|
+
'causationId',
|
|
113
|
+
'authoritativeSource',
|
|
114
|
+
'sequence',
|
|
115
|
+
'policyReceiptId',
|
|
116
|
+
'capabilityId',
|
|
117
|
+
'validationReceiptId',
|
|
118
|
+
'occurredAt',
|
|
119
|
+
'expiresAt',
|
|
120
|
+
'privacyClass',
|
|
121
|
+
]);
|
|
122
|
+
const AUTHORITY_FIELDS = new Set([
|
|
123
|
+
'authority',
|
|
124
|
+
'tenantRef',
|
|
125
|
+
'sourceType',
|
|
126
|
+
'sourceId',
|
|
127
|
+
'sourceVersion',
|
|
128
|
+
'sourceDigest',
|
|
129
|
+
]);
|
|
130
|
+
const IDENTITY_FIELDS = new Set(['namespace', 'id']);
|
|
131
|
+
const TENANT_FIELDS = new Set(['namespace', 'id']);
|
|
132
|
+
const RUVIEW_FIELDS = new Set([
|
|
133
|
+
'schemaVersion',
|
|
134
|
+
'spaceRef',
|
|
135
|
+
'observationType',
|
|
136
|
+
'value',
|
|
137
|
+
'confidence',
|
|
138
|
+
'uncertainty',
|
|
139
|
+
'abstained',
|
|
140
|
+
'modelDigest',
|
|
141
|
+
'calibrationDigest',
|
|
142
|
+
'hardwareRef',
|
|
143
|
+
'privacyClass',
|
|
144
|
+
'observedAt',
|
|
145
|
+
'expiresAt',
|
|
146
|
+
'sequence',
|
|
147
|
+
]);
|
|
148
|
+
/**
|
|
149
|
+
* Actions must be anchored in the product that owns their authoritative
|
|
150
|
+
* outcome. Read-model actions permit the explicitly listed source domains.
|
|
151
|
+
*/
|
|
152
|
+
export const ACTION_AUTHORITIES = {
|
|
153
|
+
'dashboard.read': ['cognitum.control-plane'],
|
|
154
|
+
'dashboard.status.read': [
|
|
155
|
+
'cognitum.control-plane',
|
|
156
|
+
'cognitum.cog',
|
|
157
|
+
'meta-llm',
|
|
158
|
+
'comms',
|
|
159
|
+
'agentbbs',
|
|
160
|
+
'ruview.edge',
|
|
161
|
+
'ruflo.policy',
|
|
162
|
+
],
|
|
163
|
+
'inference.invoke': ['meta-llm'],
|
|
164
|
+
'inference.stream': ['meta-llm'],
|
|
165
|
+
'usage.read': ['meta-llm'],
|
|
166
|
+
'pod.spawn': ['meta-llm'],
|
|
167
|
+
'benchmark.run': ['meta-llm'],
|
|
168
|
+
'evolution.propose': ['meta-llm'],
|
|
169
|
+
'evolution.promote': ['meta-llm'],
|
|
170
|
+
'comms.thread.read': ['agentbbs'],
|
|
171
|
+
'comms.thread.post': ['agentbbs'],
|
|
172
|
+
'comms.projection.read': [
|
|
173
|
+
'cognitum.cog',
|
|
174
|
+
'meta-llm',
|
|
175
|
+
'comms',
|
|
176
|
+
'agentbbs',
|
|
177
|
+
'ruview.edge',
|
|
178
|
+
],
|
|
179
|
+
'comms.board.admin': ['comms'],
|
|
180
|
+
'cog.proposal.create': ['cognitum.cog'],
|
|
181
|
+
'cog.proposal.review': ['cognitum.cog'],
|
|
182
|
+
'cog.proposal.approve': ['cognitum.cog'],
|
|
183
|
+
'cog.instance.acquire': ['cognitum.cog'],
|
|
184
|
+
'cog.instance.operate': ['cognitum.cog'],
|
|
185
|
+
'cog.deploy': ['cognitum.cog'],
|
|
186
|
+
'cog.rollback': ['cognitum.cog'],
|
|
187
|
+
'ruview.space.read': ['ruview.edge'],
|
|
188
|
+
'ruview.semantic.publish': ['ruview.edge'],
|
|
189
|
+
'ruview.automation.propose': ['ruview.edge'],
|
|
190
|
+
'ruview.automation.approve': ['ruview.edge'],
|
|
191
|
+
'ruview.device.command': ['ruview.edge'],
|
|
192
|
+
'cognition.route': ['ruflo.policy'],
|
|
193
|
+
'cognition.critique': ['ruflo.policy'],
|
|
194
|
+
'memory.recall': ['ruflo.memory'],
|
|
195
|
+
'memory.propose': ['ruflo.memory'],
|
|
196
|
+
'evidence.read': ['ruflo.memory'],
|
|
197
|
+
'memory.commit-validated': ['ruflo.memory'],
|
|
198
|
+
};
|
|
199
|
+
const NO_SIDE_EFFECT_REQUIREMENTS = {
|
|
200
|
+
requestDigest: false,
|
|
201
|
+
contentDigest: false,
|
|
202
|
+
idempotencyKey: false,
|
|
203
|
+
expiry: false,
|
|
204
|
+
capability: false,
|
|
205
|
+
validationReceipt: false,
|
|
206
|
+
};
|
|
207
|
+
const SCOPED_READ_REQUIREMENTS = {
|
|
208
|
+
requestDigest: true,
|
|
209
|
+
contentDigest: false,
|
|
210
|
+
idempotencyKey: false,
|
|
211
|
+
expiry: true,
|
|
212
|
+
capability: true,
|
|
213
|
+
validationReceipt: false,
|
|
214
|
+
};
|
|
215
|
+
const MUTATION_REQUIREMENTS = {
|
|
216
|
+
requestDigest: true,
|
|
217
|
+
contentDigest: false,
|
|
218
|
+
idempotencyKey: true,
|
|
219
|
+
expiry: true,
|
|
220
|
+
capability: true,
|
|
221
|
+
validationReceipt: false,
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* Explicit obligations avoid inference from action spelling. New actions do
|
|
225
|
+
* not become privileged merely because a caller supplies a valid signature.
|
|
226
|
+
*/
|
|
227
|
+
export const PRODUCT_ACTION_REQUIREMENTS = {
|
|
228
|
+
'dashboard.read': NO_SIDE_EFFECT_REQUIREMENTS,
|
|
229
|
+
'dashboard.status.read': NO_SIDE_EFFECT_REQUIREMENTS,
|
|
230
|
+
'inference.invoke': MUTATION_REQUIREMENTS,
|
|
231
|
+
'inference.stream': MUTATION_REQUIREMENTS,
|
|
232
|
+
'usage.read': SCOPED_READ_REQUIREMENTS,
|
|
233
|
+
'pod.spawn': MUTATION_REQUIREMENTS,
|
|
234
|
+
'benchmark.run': MUTATION_REQUIREMENTS,
|
|
235
|
+
'evolution.propose': MUTATION_REQUIREMENTS,
|
|
236
|
+
'evolution.promote': MUTATION_REQUIREMENTS,
|
|
237
|
+
'comms.thread.read': SCOPED_READ_REQUIREMENTS,
|
|
238
|
+
'comms.thread.post': MUTATION_REQUIREMENTS,
|
|
239
|
+
'comms.projection.read': SCOPED_READ_REQUIREMENTS,
|
|
240
|
+
'comms.board.admin': MUTATION_REQUIREMENTS,
|
|
241
|
+
'cog.proposal.create': MUTATION_REQUIREMENTS,
|
|
242
|
+
'cog.proposal.review': MUTATION_REQUIREMENTS,
|
|
243
|
+
'cog.proposal.approve': MUTATION_REQUIREMENTS,
|
|
244
|
+
'cog.instance.acquire': MUTATION_REQUIREMENTS,
|
|
245
|
+
'cog.instance.operate': MUTATION_REQUIREMENTS,
|
|
246
|
+
'cog.deploy': MUTATION_REQUIREMENTS,
|
|
247
|
+
'cog.rollback': MUTATION_REQUIREMENTS,
|
|
248
|
+
'ruview.space.read': SCOPED_READ_REQUIREMENTS,
|
|
249
|
+
'ruview.semantic.publish': MUTATION_REQUIREMENTS,
|
|
250
|
+
'ruview.automation.propose': MUTATION_REQUIREMENTS,
|
|
251
|
+
'ruview.automation.approve': MUTATION_REQUIREMENTS,
|
|
252
|
+
'ruview.device.command': MUTATION_REQUIREMENTS,
|
|
253
|
+
'cognition.route': MUTATION_REQUIREMENTS,
|
|
254
|
+
'cognition.critique': MUTATION_REQUIREMENTS,
|
|
255
|
+
'memory.recall': SCOPED_READ_REQUIREMENTS,
|
|
256
|
+
'memory.propose': MUTATION_REQUIREMENTS,
|
|
257
|
+
'evidence.read': SCOPED_READ_REQUIREMENTS,
|
|
258
|
+
'memory.commit-validated': {
|
|
259
|
+
requestDigest: true,
|
|
260
|
+
contentDigest: true,
|
|
261
|
+
idempotencyKey: true,
|
|
262
|
+
expiry: true,
|
|
263
|
+
capability: true,
|
|
264
|
+
validationReceipt: true,
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
function isRecord(value) {
|
|
268
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
269
|
+
return false;
|
|
270
|
+
const prototype = Object.getPrototypeOf(value);
|
|
271
|
+
return prototype === Object.prototype || prototype === null;
|
|
272
|
+
}
|
|
273
|
+
function issue(issues, path, code, message) {
|
|
274
|
+
issues.push({ path, code, message });
|
|
275
|
+
}
|
|
276
|
+
function rejectUnknownFields(value, allowed, path, issues) {
|
|
277
|
+
for (const key of Object.keys(value)) {
|
|
278
|
+
if (!allowed.has(key))
|
|
279
|
+
issue(issues, `${path}.${key}`, 'unknown_field', 'field is not in this schema version');
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
function requireString(value, key, path, issues, options = {}) {
|
|
283
|
+
const candidate = value[key];
|
|
284
|
+
if (candidate === undefined) {
|
|
285
|
+
if (!options.optional)
|
|
286
|
+
issue(issues, `${path}.${key}`, 'missing', 'required field is missing');
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
if (typeof candidate !== 'string') {
|
|
290
|
+
issue(issues, `${path}.${key}`, 'invalid_type', 'must be a string');
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
const max = options.max ?? 256;
|
|
294
|
+
if (candidate.length === 0 || candidate.length > max || /[\u0000-\u001f\u007f]/.test(candidate)) {
|
|
295
|
+
issue(issues, `${path}.${key}`, 'invalid_format', `must contain 1-${max} safe characters`);
|
|
296
|
+
return undefined;
|
|
297
|
+
}
|
|
298
|
+
if (options.pattern && !options.pattern.test(candidate)) {
|
|
299
|
+
issue(issues, `${path}.${key}`, 'invalid_format', 'has an invalid format');
|
|
300
|
+
return undefined;
|
|
301
|
+
}
|
|
302
|
+
return candidate;
|
|
303
|
+
}
|
|
304
|
+
function validateTimestamp(value, key, path, issues, optional = false) {
|
|
305
|
+
const timestamp = requireString(value, key, path, issues, { optional, max: 24 });
|
|
306
|
+
if (timestamp !== undefined) {
|
|
307
|
+
const milliseconds = Date.parse(timestamp);
|
|
308
|
+
if (!CANONICAL_TIMESTAMP_RE.test(timestamp)
|
|
309
|
+
|| !Number.isFinite(milliseconds)
|
|
310
|
+
|| new Date(milliseconds).toISOString() !== timestamp) {
|
|
311
|
+
issue(issues, `${path}.${key}`, 'invalid_format', 'must round-trip as a canonical UTC timestamp');
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return timestamp;
|
|
316
|
+
}
|
|
317
|
+
function validateDigest(value, key, path, issues, optional = false) {
|
|
318
|
+
return requireString(value, key, path, issues, {
|
|
319
|
+
optional,
|
|
320
|
+
max: 71,
|
|
321
|
+
pattern: SHA256_RE,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
function validateIdentity(input, path, issues) {
|
|
325
|
+
if (!isRecord(input)) {
|
|
326
|
+
issue(issues, path, 'invalid_type', 'must be a namespaced identity object');
|
|
327
|
+
return undefined;
|
|
328
|
+
}
|
|
329
|
+
rejectUnknownFields(input, IDENTITY_FIELDS, path, issues);
|
|
330
|
+
const namespace = requireString(input, 'namespace', path, issues, { max: 64 });
|
|
331
|
+
const id = requireString(input, 'id', path, issues, { max: 512 });
|
|
332
|
+
if (namespace !== undefined && !IDENTITY_NAMESPACE_SET.has(namespace)) {
|
|
333
|
+
issue(issues, `${path}.namespace`, 'identity_namespace_required', 'unknown identity namespace');
|
|
334
|
+
}
|
|
335
|
+
if (namespace === undefined || id === undefined || !IDENTITY_NAMESPACE_SET.has(namespace))
|
|
336
|
+
return undefined;
|
|
337
|
+
return { namespace: namespace, id };
|
|
338
|
+
}
|
|
339
|
+
function validateTenantRef(input, path, issues) {
|
|
340
|
+
if (!isRecord(input)) {
|
|
341
|
+
issue(issues, path, 'invalid_type', 'must be a namespaced tenant reference object');
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
rejectUnknownFields(input, TENANT_FIELDS, path, issues);
|
|
345
|
+
const namespace = requireString(input, 'namespace', path, issues, { max: 64 });
|
|
346
|
+
const id = requireString(input, 'id', path, issues, { max: 256 });
|
|
347
|
+
if (namespace !== undefined && !TENANT_NAMESPACE_SET.has(namespace)) {
|
|
348
|
+
issue(issues, `${path}.namespace`, 'identity_namespace_required', 'unknown tenant namespace');
|
|
349
|
+
}
|
|
350
|
+
if (namespace === undefined || id === undefined || !TENANT_NAMESPACE_SET.has(namespace))
|
|
351
|
+
return undefined;
|
|
352
|
+
return { namespace: namespace, id };
|
|
353
|
+
}
|
|
354
|
+
export function identityKey(identity) {
|
|
355
|
+
return `${identity.namespace.length}:${identity.namespace}${identity.id.length}:${identity.id}`;
|
|
356
|
+
}
|
|
357
|
+
export function sameIdentity(left, right) {
|
|
358
|
+
return identityKey(left) === identityKey(right);
|
|
359
|
+
}
|
|
360
|
+
export function tenantRefKey(tenant) {
|
|
361
|
+
return `${tenant.namespace.length}:${tenant.namespace}${tenant.id.length}:${tenant.id}`;
|
|
362
|
+
}
|
|
363
|
+
export function isProductAction(value) {
|
|
364
|
+
return typeof value === 'string' && ACTION_SET.has(value);
|
|
365
|
+
}
|
|
366
|
+
export function validateAuthoritativeReference(input, options = {}) {
|
|
367
|
+
const issues = [];
|
|
368
|
+
if (!isRecord(input)) {
|
|
369
|
+
return {
|
|
370
|
+
ok: false,
|
|
371
|
+
issues: [{ path: '$', code: 'invalid_type', message: 'authority reference must be an object' }],
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
rejectUnknownFields(input, AUTHORITY_FIELDS, '$', issues);
|
|
375
|
+
const authority = requireString(input, 'authority', '$', issues, { max: 64 });
|
|
376
|
+
const tenantRef = validateTenantRef(input.tenantRef, '$.tenantRef', issues);
|
|
377
|
+
const sourceType = requireString(input, 'sourceType', '$', issues, { max: 128, pattern: SOURCE_TYPE_RE });
|
|
378
|
+
const sourceId = requireString(input, 'sourceId', '$', issues, { max: 512 });
|
|
379
|
+
const sourceVersion = requireString(input, 'sourceVersion', '$', issues, {
|
|
380
|
+
max: 128,
|
|
381
|
+
pattern: SAFE_TOKEN_RE,
|
|
382
|
+
});
|
|
383
|
+
const sourceDigest = validateDigest(input, 'sourceDigest', '$', issues);
|
|
384
|
+
if (authority !== undefined && !AUTHORITY_SET.has(authority)) {
|
|
385
|
+
issue(issues, '$.authority', 'invalid_authority', 'unknown product authority');
|
|
386
|
+
}
|
|
387
|
+
if (authority !== undefined
|
|
388
|
+
&& AUTHORITY_SET.has(authority)
|
|
389
|
+
&& sourceType !== undefined
|
|
390
|
+
&& !sourceType.startsWith(`${authority}/`)) {
|
|
391
|
+
issue(issues, '$.sourceType', 'invalid_authority', 'source type is not owned by the declared authority');
|
|
392
|
+
}
|
|
393
|
+
if (options.action
|
|
394
|
+
&& authority !== undefined
|
|
395
|
+
&& AUTHORITY_SET.has(authority)
|
|
396
|
+
&& !ACTION_AUTHORITIES[options.action].includes(authority)) {
|
|
397
|
+
issue(issues, '$.authority', 'invalid_authority', 'authority does not own the action outcome');
|
|
398
|
+
}
|
|
399
|
+
if (options.tenantRef
|
|
400
|
+
&& tenantRef
|
|
401
|
+
&& tenantRefKey(options.tenantRef) !== tenantRefKey(tenantRef)) {
|
|
402
|
+
issue(issues, '$.tenantRef', 'tenant_mismatch', 'source tenant does not match envelope tenant');
|
|
403
|
+
}
|
|
404
|
+
if (issues.length > 0
|
|
405
|
+
|| authority === undefined
|
|
406
|
+
|| !AUTHORITY_SET.has(authority)
|
|
407
|
+
|| tenantRef === undefined
|
|
408
|
+
|| sourceType === undefined
|
|
409
|
+
|| sourceId === undefined
|
|
410
|
+
|| sourceVersion === undefined
|
|
411
|
+
|| sourceDigest === undefined) {
|
|
412
|
+
return { ok: false, issues };
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
ok: true,
|
|
416
|
+
value: {
|
|
417
|
+
authority: authority,
|
|
418
|
+
tenantRef,
|
|
419
|
+
sourceType,
|
|
420
|
+
sourceId,
|
|
421
|
+
sourceVersion,
|
|
422
|
+
sourceDigest: sourceDigest,
|
|
423
|
+
},
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
export function validateProductActionEnvelope(input) {
|
|
427
|
+
const issues = [];
|
|
428
|
+
if (!isRecord(input)) {
|
|
429
|
+
return {
|
|
430
|
+
ok: false,
|
|
431
|
+
issues: [{ path: '$', code: 'invalid_type', message: 'action envelope must be an object' }],
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
rejectUnknownFields(input, ENVELOPE_FIELDS, '$', issues);
|
|
435
|
+
const schemaVersion = requireString(input, 'schemaVersion', '$', issues, { max: 64 });
|
|
436
|
+
if (schemaVersion !== undefined && schemaVersion !== PRODUCT_ACTION_ENVELOPE_VERSION) {
|
|
437
|
+
issue(issues, '$.schemaVersion', 'unsupported_value', 'unsupported action envelope version');
|
|
438
|
+
}
|
|
439
|
+
const eventId = requireString(input, 'eventId', '$', issues, { max: 256, pattern: SAFE_TOKEN_RE });
|
|
440
|
+
const issuer = requireString(input, 'issuer', '$', issues, { max: 64 });
|
|
441
|
+
const audience = requireString(input, 'audience', '$', issues, { max: 64 });
|
|
442
|
+
if (issuer !== undefined && !AUTHORITY_SET.has(issuer)) {
|
|
443
|
+
issue(issues, '$.issuer', 'invalid_authority', 'unknown issuer authority');
|
|
444
|
+
}
|
|
445
|
+
if (audience !== undefined && !AUTHORITY_SET.has(audience)) {
|
|
446
|
+
issue(issues, '$.audience', 'invalid_authority', 'unknown audience authority');
|
|
447
|
+
}
|
|
448
|
+
const subject = validateIdentity(input.subject, '$.subject', issues);
|
|
449
|
+
const actor = input.actor === undefined ? undefined : validateIdentity(input.actor, '$.actor', issues);
|
|
450
|
+
const tenantRef = validateTenantRef(input.tenantRef, '$.tenantRef', issues);
|
|
451
|
+
const actionValue = requireString(input, 'action', '$', issues, { max: 128 });
|
|
452
|
+
if (actionValue !== undefined && !isProductAction(actionValue)) {
|
|
453
|
+
issue(issues, '$.action', 'unsupported_value', 'action is outside the product action vocabulary');
|
|
454
|
+
}
|
|
455
|
+
const action = isProductAction(actionValue) ? actionValue : undefined;
|
|
456
|
+
let resourceRefs;
|
|
457
|
+
if (!Array.isArray(input.resourceRefs) || input.resourceRefs.length === 0 || input.resourceRefs.length > 32) {
|
|
458
|
+
issue(issues, '$.resourceRefs', 'invalid_type', 'must be an array of 1-32 resource references');
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
resourceRefs = [];
|
|
462
|
+
input.resourceRefs.forEach((resource, index) => {
|
|
463
|
+
if (typeof resource !== 'string'
|
|
464
|
+
|| resource.length === 0
|
|
465
|
+
|| resource.length > 512
|
|
466
|
+
|| !SAFE_TOKEN_RE.test(resource)) {
|
|
467
|
+
issue(issues, `$.resourceRefs[${index}]`, 'invalid_format', 'invalid resource reference');
|
|
468
|
+
}
|
|
469
|
+
else if (resourceRefs.includes(resource)) {
|
|
470
|
+
issue(issues, `$.resourceRefs[${index}]`, 'unsupported_value', 'duplicate resource reference');
|
|
471
|
+
}
|
|
472
|
+
else {
|
|
473
|
+
resourceRefs.push(resource);
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
const requestDigest = validateDigest(input, 'requestDigest', '$', issues, true);
|
|
478
|
+
const contentDigest = validateDigest(input, 'contentDigest', '$', issues, true);
|
|
479
|
+
const idempotencyKey = requireString(input, 'idempotencyKey', '$', issues, {
|
|
480
|
+
optional: true,
|
|
481
|
+
max: 256,
|
|
482
|
+
pattern: SAFE_TOKEN_RE,
|
|
483
|
+
});
|
|
484
|
+
const correlationId = requireString(input, 'correlationId', '$', issues, {
|
|
485
|
+
max: 256,
|
|
486
|
+
pattern: SAFE_TOKEN_RE,
|
|
487
|
+
});
|
|
488
|
+
const causationId = requireString(input, 'causationId', '$', issues, {
|
|
489
|
+
optional: true,
|
|
490
|
+
max: 256,
|
|
491
|
+
pattern: SAFE_TOKEN_RE,
|
|
492
|
+
});
|
|
493
|
+
const sequence = requireString(input, 'sequence', '$', issues, {
|
|
494
|
+
optional: true,
|
|
495
|
+
max: 40,
|
|
496
|
+
pattern: UNSIGNED_DECIMAL_RE,
|
|
497
|
+
});
|
|
498
|
+
const policyReceiptId = requireString(input, 'policyReceiptId', '$', issues, {
|
|
499
|
+
max: 256,
|
|
500
|
+
pattern: SAFE_TOKEN_RE,
|
|
501
|
+
});
|
|
502
|
+
const capabilityId = requireString(input, 'capabilityId', '$', issues, {
|
|
503
|
+
optional: true,
|
|
504
|
+
max: 256,
|
|
505
|
+
pattern: SAFE_TOKEN_RE,
|
|
506
|
+
});
|
|
507
|
+
const validationReceiptId = requireString(input, 'validationReceiptId', '$', issues, {
|
|
508
|
+
optional: true,
|
|
509
|
+
max: 256,
|
|
510
|
+
pattern: SAFE_TOKEN_RE,
|
|
511
|
+
});
|
|
512
|
+
const occurredAt = validateTimestamp(input, 'occurredAt', '$', issues);
|
|
513
|
+
const expiresAt = validateTimestamp(input, 'expiresAt', '$', issues, true);
|
|
514
|
+
if (occurredAt !== undefined
|
|
515
|
+
&& expiresAt !== undefined
|
|
516
|
+
&& Date.parse(expiresAt) <= Date.parse(occurredAt)) {
|
|
517
|
+
issue(issues, '$.expiresAt', 'unsupported_value', 'expiry must be after occurrence');
|
|
518
|
+
}
|
|
519
|
+
const privacyClass = requireString(input, 'privacyClass', '$', issues, { max: 2 });
|
|
520
|
+
if (privacyClass !== undefined && !PRIVACY_CLASS_SET.has(privacyClass)) {
|
|
521
|
+
issue(issues, '$.privacyClass', 'unsupported_value', 'unknown privacy class');
|
|
522
|
+
}
|
|
523
|
+
if (action === 'ruview.semantic.publish'
|
|
524
|
+
&& privacyClass !== undefined
|
|
525
|
+
&& privacyClass !== 'P2'
|
|
526
|
+
&& privacyClass !== 'P3') {
|
|
527
|
+
issue(issues, '$.privacyClass', 'privacy_ceiling_exceeded', 'RuView semantic events must be P2 or P3');
|
|
528
|
+
}
|
|
529
|
+
if (action) {
|
|
530
|
+
const requirements = PRODUCT_ACTION_REQUIREMENTS[action];
|
|
531
|
+
const required = [
|
|
532
|
+
[requirements.requestDigest, 'requestDigest', 'action requires a request digest'],
|
|
533
|
+
[requirements.contentDigest, 'contentDigest', 'validated memory commit requires a content digest'],
|
|
534
|
+
[requirements.idempotencyKey, 'idempotencyKey', 'action requires an idempotency key'],
|
|
535
|
+
[requirements.expiry, 'expiresAt', 'action requires a bounded expiry'],
|
|
536
|
+
[requirements.capability, 'capabilityId', 'action requires a narrow capability'],
|
|
537
|
+
[requirements.validationReceipt, 'validationReceiptId', 'validated memory commit requires a validation receipt'],
|
|
538
|
+
];
|
|
539
|
+
for (const [isRequired, field, message] of required) {
|
|
540
|
+
if (isRequired && input[field] === undefined)
|
|
541
|
+
issue(issues, `$.${field}`, 'missing', message);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
const sourceResult = validateAuthoritativeReference(input.authoritativeSource, { action, tenantRef });
|
|
545
|
+
if (!sourceResult.ok) {
|
|
546
|
+
for (const sourceIssue of sourceResult.issues) {
|
|
547
|
+
issues.push({
|
|
548
|
+
...sourceIssue,
|
|
549
|
+
path: sourceIssue.path === '$'
|
|
550
|
+
? '$.authoritativeSource'
|
|
551
|
+
: `$.authoritativeSource${sourceIssue.path.slice(1)}`,
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
if (issues.length > 0
|
|
556
|
+
|| schemaVersion !== PRODUCT_ACTION_ENVELOPE_VERSION
|
|
557
|
+
|| eventId === undefined
|
|
558
|
+
|| issuer === undefined
|
|
559
|
+
|| !AUTHORITY_SET.has(issuer)
|
|
560
|
+
|| audience === undefined
|
|
561
|
+
|| !AUTHORITY_SET.has(audience)
|
|
562
|
+
|| subject === undefined
|
|
563
|
+
|| tenantRef === undefined
|
|
564
|
+
|| action === undefined
|
|
565
|
+
|| resourceRefs === undefined
|
|
566
|
+
|| correlationId === undefined
|
|
567
|
+
|| policyReceiptId === undefined
|
|
568
|
+
|| occurredAt === undefined
|
|
569
|
+
|| privacyClass === undefined
|
|
570
|
+
|| !PRIVACY_CLASS_SET.has(privacyClass)
|
|
571
|
+
|| !sourceResult.ok) {
|
|
572
|
+
return { ok: false, issues };
|
|
573
|
+
}
|
|
574
|
+
return {
|
|
575
|
+
ok: true,
|
|
576
|
+
value: {
|
|
577
|
+
schemaVersion,
|
|
578
|
+
eventId,
|
|
579
|
+
issuer: issuer,
|
|
580
|
+
audience: audience,
|
|
581
|
+
subject,
|
|
582
|
+
...(actor ? { actor } : {}),
|
|
583
|
+
tenantRef,
|
|
584
|
+
action,
|
|
585
|
+
resourceRefs,
|
|
586
|
+
...(requestDigest ? { requestDigest: requestDigest } : {}),
|
|
587
|
+
...(contentDigest ? { contentDigest: contentDigest } : {}),
|
|
588
|
+
...(idempotencyKey ? { idempotencyKey } : {}),
|
|
589
|
+
correlationId,
|
|
590
|
+
...(causationId ? { causationId } : {}),
|
|
591
|
+
authoritativeSource: sourceResult.value,
|
|
592
|
+
...(sequence ? { sequence } : {}),
|
|
593
|
+
policyReceiptId,
|
|
594
|
+
...(capabilityId ? { capabilityId } : {}),
|
|
595
|
+
...(validationReceiptId ? { validationReceiptId } : {}),
|
|
596
|
+
occurredAt,
|
|
597
|
+
...(expiresAt ? { expiresAt } : {}),
|
|
598
|
+
privacyClass: privacyClass,
|
|
599
|
+
},
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* The default edge-export surface is deliberately small and semantic. A new
|
|
604
|
+
* observation type or field requires explicit schema registration; arbitrary
|
|
605
|
+
* keys are never accepted based on a deny-list alone.
|
|
606
|
+
*/
|
|
607
|
+
export const DEFAULT_RUVIEW_OBSERVATION_REGISTRY = Object.freeze({
|
|
608
|
+
'occupancy.state': {
|
|
609
|
+
privacyClasses: ['P2'],
|
|
610
|
+
fields: {
|
|
611
|
+
occupied: { kind: 'boolean', required: true },
|
|
612
|
+
zone: { kind: 'string', maxLength: 64 },
|
|
613
|
+
peopleEstimate: { kind: 'number', min: 0, max: 10_000 },
|
|
614
|
+
},
|
|
615
|
+
},
|
|
616
|
+
'presence.state': {
|
|
617
|
+
privacyClasses: ['P2'],
|
|
618
|
+
fields: {
|
|
619
|
+
present: { kind: 'boolean', required: true },
|
|
620
|
+
zone: { kind: 'string', maxLength: 64 },
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
'motion.state': {
|
|
624
|
+
privacyClasses: ['P2'],
|
|
625
|
+
fields: {
|
|
626
|
+
active: { kind: 'boolean', required: true },
|
|
627
|
+
intensity: { kind: 'number', min: 0, max: 1 },
|
|
628
|
+
},
|
|
629
|
+
},
|
|
630
|
+
'vital.summary': {
|
|
631
|
+
privacyClasses: ['P3'],
|
|
632
|
+
fields: {
|
|
633
|
+
state: {
|
|
634
|
+
kind: 'string',
|
|
635
|
+
required: true,
|
|
636
|
+
enum: ['normal', 'attention', 'critical', 'unknown'],
|
|
637
|
+
},
|
|
638
|
+
anomaly: { kind: 'boolean', required: true },
|
|
639
|
+
label: { kind: 'nullable-string', maxLength: 128 },
|
|
640
|
+
},
|
|
641
|
+
},
|
|
642
|
+
});
|
|
643
|
+
function looksLikeRawEncoding(value) {
|
|
644
|
+
return /^data:[^,]{1,128};base64,/i.test(value)
|
|
645
|
+
|| BASE64_SHAPED_RE.test(value)
|
|
646
|
+
|| BASE64URL_SHAPED_RE.test(value);
|
|
647
|
+
}
|
|
648
|
+
function validateSemanticValue(value, schema, privacyClass, issues) {
|
|
649
|
+
if (!schema) {
|
|
650
|
+
issue(issues, '$.observationType', 'unsupported_value', 'observation type is not registered for edge export');
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
if (privacyClass !== 'P2' && privacyClass !== 'P3')
|
|
654
|
+
return false;
|
|
655
|
+
if (!schema.privacyClasses.includes(privacyClass)) {
|
|
656
|
+
issue(issues, '$.privacyClass', 'privacy_ceiling_exceeded', 'privacy class is not permitted by the observation schema');
|
|
657
|
+
}
|
|
658
|
+
if (!isRecord(value)) {
|
|
659
|
+
issue(issues, '$.value', 'privacy_ceiling_exceeded', 'registered semantic observations require an object value');
|
|
660
|
+
return false;
|
|
661
|
+
}
|
|
662
|
+
let valid = true;
|
|
663
|
+
for (const key of Object.keys(value)) {
|
|
664
|
+
if (!Object.prototype.hasOwnProperty.call(schema.fields, key)) {
|
|
665
|
+
issue(issues, `$.value.${key}`, 'unknown_field', 'field is not registered for this observation type');
|
|
666
|
+
valid = false;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
for (const [key, fieldSchema] of Object.entries(schema.fields)) {
|
|
670
|
+
const field = value[key];
|
|
671
|
+
if (field === undefined) {
|
|
672
|
+
if (fieldSchema.required) {
|
|
673
|
+
issue(issues, `$.value.${key}`, 'missing', 'required semantic field is missing');
|
|
674
|
+
valid = false;
|
|
675
|
+
}
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
if (typeof field === 'string' && looksLikeRawEncoding(field)) {
|
|
679
|
+
issue(issues, `$.value.${key}`, 'privacy_ceiling_exceeded', 'base64-shaped or data-URL values cannot leave the edge');
|
|
680
|
+
valid = false;
|
|
681
|
+
continue;
|
|
682
|
+
}
|
|
683
|
+
if (fieldSchema.kind === 'boolean') {
|
|
684
|
+
if (typeof field !== 'boolean') {
|
|
685
|
+
issue(issues, `$.value.${key}`, 'invalid_type', 'must be a boolean');
|
|
686
|
+
valid = false;
|
|
687
|
+
}
|
|
688
|
+
continue;
|
|
689
|
+
}
|
|
690
|
+
if (fieldSchema.kind === 'number') {
|
|
691
|
+
if (typeof field !== 'number'
|
|
692
|
+
|| !Number.isFinite(field)
|
|
693
|
+
|| (fieldSchema.min !== undefined && field < fieldSchema.min)
|
|
694
|
+
|| (fieldSchema.max !== undefined && field > fieldSchema.max)) {
|
|
695
|
+
issue(issues, `$.value.${key}`, 'invalid_format', 'must be a finite number within the registered bounds');
|
|
696
|
+
valid = false;
|
|
697
|
+
}
|
|
698
|
+
continue;
|
|
699
|
+
}
|
|
700
|
+
if (fieldSchema.kind === 'nullable-string' && field === null)
|
|
701
|
+
continue;
|
|
702
|
+
if (typeof field !== 'string' || field.length > (fieldSchema.maxLength ?? 256)) {
|
|
703
|
+
issue(issues, `$.value.${key}`, 'invalid_type', 'must be a bounded string');
|
|
704
|
+
valid = false;
|
|
705
|
+
continue;
|
|
706
|
+
}
|
|
707
|
+
if (fieldSchema.enum && !fieldSchema.enum.includes(field)) {
|
|
708
|
+
issue(issues, `$.value.${key}`, 'unsupported_value', 'value is outside the registered semantic vocabulary');
|
|
709
|
+
valid = false;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return valid;
|
|
713
|
+
}
|
|
714
|
+
export function validateRuViewSemanticObservation(input, registry = DEFAULT_RUVIEW_OBSERVATION_REGISTRY) {
|
|
715
|
+
const issues = [];
|
|
716
|
+
if (!isRecord(input)) {
|
|
717
|
+
return {
|
|
718
|
+
ok: false,
|
|
719
|
+
issues: [{ path: '$', code: 'invalid_type', message: 'RuView observation must be an object' }],
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
rejectUnknownFields(input, RUVIEW_FIELDS, '$', issues);
|
|
723
|
+
const schemaVersion = requireString(input, 'schemaVersion', '$', issues, { max: 64 });
|
|
724
|
+
if (schemaVersion !== undefined && schemaVersion !== 'ruview.semantic-observation.v1') {
|
|
725
|
+
issue(issues, '$.schemaVersion', 'unsupported_value', 'unsupported RuView observation version');
|
|
726
|
+
}
|
|
727
|
+
const spaceRef = validateTenantRef(input.spaceRef, '$.spaceRef', issues);
|
|
728
|
+
if (spaceRef && spaceRef.namespace !== 'ruview-space') {
|
|
729
|
+
issue(issues, '$.spaceRef.namespace', 'identity_namespace_required', 'RuView observation requires a RuView space namespace');
|
|
730
|
+
}
|
|
731
|
+
const observationType = requireString(input, 'observationType', '$', issues, {
|
|
732
|
+
max: 128,
|
|
733
|
+
pattern: SAFE_TOKEN_RE,
|
|
734
|
+
});
|
|
735
|
+
const privacyClass = requireString(input, 'privacyClass', '$', issues, { max: 2 });
|
|
736
|
+
if (privacyClass !== undefined && privacyClass !== 'P2' && privacyClass !== 'P3') {
|
|
737
|
+
issue(issues, '$.privacyClass', 'privacy_ceiling_exceeded', 'RuView product-plane observations must be P2 or P3');
|
|
738
|
+
}
|
|
739
|
+
const valueValid = validateSemanticValue(input.value, observationType ? registry[observationType] : undefined, privacyClass, issues);
|
|
740
|
+
const confidence = input.confidence;
|
|
741
|
+
if (typeof confidence !== 'number' || !Number.isFinite(confidence) || confidence < 0 || confidence > 1) {
|
|
742
|
+
issue(issues, '$.confidence', 'invalid_format', 'confidence must be finite and between 0 and 1');
|
|
743
|
+
}
|
|
744
|
+
const uncertainty = input.uncertainty;
|
|
745
|
+
if (uncertainty !== undefined
|
|
746
|
+
&& (typeof uncertainty !== 'number' || !Number.isFinite(uncertainty) || uncertainty < 0 || uncertainty > 1)) {
|
|
747
|
+
issue(issues, '$.uncertainty', 'invalid_format', 'uncertainty must be finite and between 0 and 1');
|
|
748
|
+
}
|
|
749
|
+
if (typeof input.abstained !== 'boolean') {
|
|
750
|
+
issue(issues, '$.abstained', input.abstained === undefined ? 'missing' : 'invalid_type', 'abstained must be a boolean');
|
|
751
|
+
}
|
|
752
|
+
const modelDigest = validateDigest(input, 'modelDigest', '$', issues);
|
|
753
|
+
const calibrationDigest = validateDigest(input, 'calibrationDigest', '$', issues, true);
|
|
754
|
+
const hardwareRef = requireString(input, 'hardwareRef', '$', issues, {
|
|
755
|
+
optional: true,
|
|
756
|
+
max: 256,
|
|
757
|
+
pattern: SAFE_TOKEN_RE,
|
|
758
|
+
});
|
|
759
|
+
const observedAt = validateTimestamp(input, 'observedAt', '$', issues);
|
|
760
|
+
const expiresAt = validateTimestamp(input, 'expiresAt', '$', issues);
|
|
761
|
+
if (observedAt !== undefined
|
|
762
|
+
&& expiresAt !== undefined
|
|
763
|
+
&& Date.parse(expiresAt) <= Date.parse(observedAt)) {
|
|
764
|
+
issue(issues, '$.expiresAt', 'unsupported_value', 'observation expiry must be after observation time');
|
|
765
|
+
}
|
|
766
|
+
const sequence = requireString(input, 'sequence', '$', issues, {
|
|
767
|
+
max: 40,
|
|
768
|
+
pattern: UNSIGNED_DECIMAL_RE,
|
|
769
|
+
});
|
|
770
|
+
if (issues.length > 0
|
|
771
|
+
|| schemaVersion !== 'ruview.semantic-observation.v1'
|
|
772
|
+
|| spaceRef === undefined
|
|
773
|
+
|| spaceRef.namespace !== 'ruview-space'
|
|
774
|
+
|| observationType === undefined
|
|
775
|
+
|| registry[observationType] === undefined
|
|
776
|
+
|| !valueValid
|
|
777
|
+
|| typeof confidence !== 'number'
|
|
778
|
+
|| typeof input.abstained !== 'boolean'
|
|
779
|
+
|| modelDigest === undefined
|
|
780
|
+
|| (privacyClass !== 'P2' && privacyClass !== 'P3')
|
|
781
|
+
|| observedAt === undefined
|
|
782
|
+
|| expiresAt === undefined
|
|
783
|
+
|| sequence === undefined) {
|
|
784
|
+
return { ok: false, issues };
|
|
785
|
+
}
|
|
786
|
+
return {
|
|
787
|
+
ok: true,
|
|
788
|
+
value: {
|
|
789
|
+
schemaVersion,
|
|
790
|
+
spaceRef: { namespace: 'ruview-space', id: spaceRef.id },
|
|
791
|
+
observationType,
|
|
792
|
+
value: input.value,
|
|
793
|
+
confidence,
|
|
794
|
+
...(typeof uncertainty === 'number' ? { uncertainty } : {}),
|
|
795
|
+
abstained: input.abstained,
|
|
796
|
+
modelDigest: modelDigest,
|
|
797
|
+
...(calibrationDigest ? { calibrationDigest: calibrationDigest } : {}),
|
|
798
|
+
...(hardwareRef ? { hardwareRef } : {}),
|
|
799
|
+
privacyClass,
|
|
800
|
+
observedAt,
|
|
801
|
+
expiresAt,
|
|
802
|
+
sequence,
|
|
803
|
+
},
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
function assertUnicodeScalarString(value) {
|
|
807
|
+
for (let index = 0; index < value.length; index++) {
|
|
808
|
+
const code = value.charCodeAt(index);
|
|
809
|
+
if (code >= 0xd800 && code <= 0xdbff) {
|
|
810
|
+
const next = value.charCodeAt(index + 1);
|
|
811
|
+
if (!(next >= 0xdc00 && next <= 0xdfff)) {
|
|
812
|
+
throw new TypeError('JCS canonicalization rejects an unpaired high surrogate');
|
|
813
|
+
}
|
|
814
|
+
index++;
|
|
815
|
+
}
|
|
816
|
+
else if (code >= 0xdc00 && code <= 0xdfff) {
|
|
817
|
+
throw new TypeError('JCS canonicalization rejects an unpaired low surrogate');
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
/**
|
|
822
|
+
* RFC 8785/JCS-compatible canonical JSON for this I-JSON profile.
|
|
823
|
+
*
|
|
824
|
+
* ECMAScript's JSON number serialization supplies the JCS number rendering.
|
|
825
|
+
* Non-finite numbers, sparse arrays, undefined values, non-plain objects, and
|
|
826
|
+
* invalid Unicode are rejected instead of being silently coerced.
|
|
827
|
+
*/
|
|
828
|
+
export function canonicalizeProductPlane(value) {
|
|
829
|
+
if (value === null)
|
|
830
|
+
return 'null';
|
|
831
|
+
if (typeof value === 'boolean')
|
|
832
|
+
return value ? 'true' : 'false';
|
|
833
|
+
if (typeof value === 'string') {
|
|
834
|
+
assertUnicodeScalarString(value);
|
|
835
|
+
return JSON.stringify(value);
|
|
836
|
+
}
|
|
837
|
+
if (typeof value === 'number') {
|
|
838
|
+
if (!Number.isFinite(value))
|
|
839
|
+
throw new TypeError('JCS canonicalization rejects non-finite numbers');
|
|
840
|
+
return JSON.stringify(value);
|
|
841
|
+
}
|
|
842
|
+
if (Array.isArray(value)) {
|
|
843
|
+
const items = [];
|
|
844
|
+
for (let index = 0; index < value.length; index++) {
|
|
845
|
+
if (!Object.prototype.hasOwnProperty.call(value, index)) {
|
|
846
|
+
throw new TypeError('JCS canonicalization rejects sparse arrays');
|
|
847
|
+
}
|
|
848
|
+
items.push(canonicalizeProductPlane(value[index]));
|
|
849
|
+
}
|
|
850
|
+
return `[${items.join(',')}]`;
|
|
851
|
+
}
|
|
852
|
+
if (!isRecord(value)) {
|
|
853
|
+
throw new TypeError('JCS canonicalization accepts only JSON-compatible plain objects');
|
|
854
|
+
}
|
|
855
|
+
const entries = [];
|
|
856
|
+
for (const key of Object.keys(value).sort()) {
|
|
857
|
+
assertUnicodeScalarString(key);
|
|
858
|
+
if (value[key] === undefined) {
|
|
859
|
+
throw new TypeError('JCS canonicalization rejects undefined object values');
|
|
860
|
+
}
|
|
861
|
+
entries.push(`${JSON.stringify(key)}:${canonicalizeProductPlane(value[key])}`);
|
|
862
|
+
}
|
|
863
|
+
return `{${entries.join(',')}}`;
|
|
864
|
+
}
|
|
865
|
+
export function canonicalProductPlaneBytes(value) {
|
|
866
|
+
return Buffer.from(canonicalizeProductPlane(value), 'utf8');
|
|
867
|
+
}
|
|
868
|
+
export function canonicalProductPlaneDigest(value) {
|
|
869
|
+
return `sha256:${createHash('sha256').update(canonicalProductPlaneBytes(value)).digest('hex')}`;
|
|
870
|
+
}
|
|
871
|
+
const SIGNED_ENVELOPE_FIELDS = new Set(['envelope', 'algorithm', 'keyId', 'signature']);
|
|
872
|
+
const BASE64URL_RE = /^[A-Za-z0-9_-]+$/;
|
|
873
|
+
function deny(code, reason, issues) {
|
|
874
|
+
return { ok: false, code, reason, ...(issues ? { issues } : {}) };
|
|
875
|
+
}
|
|
876
|
+
function authorizationAllowed(decision) {
|
|
877
|
+
return typeof decision === 'boolean' ? decision : decision.allowed;
|
|
878
|
+
}
|
|
879
|
+
function authorizationReason(decision, fallback) {
|
|
880
|
+
return typeof decision === 'boolean' ? fallback : decision.reason ?? fallback;
|
|
881
|
+
}
|
|
882
|
+
function decodeBase64Url(value) {
|
|
883
|
+
if (!BASE64URL_RE.test(value))
|
|
884
|
+
return undefined;
|
|
885
|
+
const decoded = Buffer.from(value, 'base64url');
|
|
886
|
+
if (decoded.length === 0 || decoded.toString('base64url') !== value)
|
|
887
|
+
return undefined;
|
|
888
|
+
return decoded;
|
|
889
|
+
}
|
|
890
|
+
function replayKeyFor(envelope) {
|
|
891
|
+
const parts = [
|
|
892
|
+
envelope.issuer,
|
|
893
|
+
tenantRefKey(envelope.tenantRef),
|
|
894
|
+
identityKey(envelope.subject),
|
|
895
|
+
envelope.action,
|
|
896
|
+
envelope.idempotencyKey ?? envelope.eventId,
|
|
897
|
+
];
|
|
898
|
+
return parts.map((part) => `${part.length}:${part}`).join('');
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Verify a signed product action as an ingress policy-enforcement decision.
|
|
902
|
+
*
|
|
903
|
+
* Signature validity is necessary but insufficient: audience, tenant,
|
|
904
|
+
* freshness, replay state, local policy, and the action-bound capability are
|
|
905
|
+
* checked independently. Service availability is intentionally absent; a
|
|
906
|
+
* valid claim never implies that its target is configured, reachable, or
|
|
907
|
+
* healthy.
|
|
908
|
+
*/
|
|
909
|
+
export async function verifySignedProductActionEnvelope(input, options) {
|
|
910
|
+
if (!isRecord(input))
|
|
911
|
+
return deny('malformed_signed_envelope', 'signed envelope must be an object');
|
|
912
|
+
const wrapperIssues = [];
|
|
913
|
+
rejectUnknownFields(input, SIGNED_ENVELOPE_FIELDS, '$', wrapperIssues);
|
|
914
|
+
const algorithm = requireString(input, 'algorithm', '$', wrapperIssues, { max: 16 });
|
|
915
|
+
const keyId = requireString(input, 'keyId', '$', wrapperIssues, {
|
|
916
|
+
max: 256,
|
|
917
|
+
pattern: SAFE_TOKEN_RE,
|
|
918
|
+
});
|
|
919
|
+
const signatureText = requireString(input, 'signature', '$', wrapperIssues, { max: 128 });
|
|
920
|
+
if (algorithm !== undefined && algorithm !== 'Ed25519') {
|
|
921
|
+
issue(wrapperIssues, '$.algorithm', 'unsupported_value', 'only Ed25519 is supported');
|
|
922
|
+
}
|
|
923
|
+
const signature = signatureText ? decodeBase64Url(signatureText) : undefined;
|
|
924
|
+
if (signatureText && (!signature || signature.length !== 64)) {
|
|
925
|
+
issue(wrapperIssues, '$.signature', 'invalid_format', 'must be a canonical 64-byte base64url signature');
|
|
926
|
+
}
|
|
927
|
+
if (!Object.prototype.hasOwnProperty.call(input, 'envelope')) {
|
|
928
|
+
issue(wrapperIssues, '$.envelope', 'missing', 'signed envelope payload is missing');
|
|
929
|
+
}
|
|
930
|
+
if (wrapperIssues.length > 0 || algorithm !== 'Ed25519' || !keyId || !signature) {
|
|
931
|
+
return deny('malformed_signed_envelope', 'signed envelope wrapper is invalid', wrapperIssues);
|
|
932
|
+
}
|
|
933
|
+
const parsed = validateProductActionEnvelope(input.envelope);
|
|
934
|
+
if (!parsed.ok)
|
|
935
|
+
return deny('invalid_envelope', 'action envelope is invalid', parsed.issues);
|
|
936
|
+
const envelope = parsed.value;
|
|
937
|
+
if (envelope.audience !== options.expectedAudience) {
|
|
938
|
+
return deny('audience_mismatch', 'envelope audience does not match this service');
|
|
939
|
+
}
|
|
940
|
+
if (tenantRefKey(envelope.tenantRef) !== tenantRefKey(options.expectedTenantRef)) {
|
|
941
|
+
return deny('tenant_mismatch', 'envelope tenant does not match the authenticated local tenant');
|
|
942
|
+
}
|
|
943
|
+
const now = options.now?.() ?? Date.now();
|
|
944
|
+
const maxAgeMs = options.maxAgeMs ?? 5 * 60_000;
|
|
945
|
+
const maxFutureSkewMs = options.maxFutureSkewMs ?? 30_000;
|
|
946
|
+
if (!Number.isFinite(now)
|
|
947
|
+
|| !Number.isFinite(maxAgeMs)
|
|
948
|
+
|| maxAgeMs < 0
|
|
949
|
+
|| !Number.isFinite(maxFutureSkewMs)
|
|
950
|
+
|| maxFutureSkewMs < 0) {
|
|
951
|
+
return deny('verification_error', 'verifier clock configuration is invalid');
|
|
952
|
+
}
|
|
953
|
+
const occurredAt = Date.parse(envelope.occurredAt);
|
|
954
|
+
if (occurredAt > now + maxFutureSkewMs)
|
|
955
|
+
return deny('not_yet_valid', 'envelope occurrence is in the future');
|
|
956
|
+
if (now - occurredAt > maxAgeMs)
|
|
957
|
+
return deny('stale', 'envelope exceeds the accepted freshness window');
|
|
958
|
+
const expiresAt = envelope.expiresAt ? Date.parse(envelope.expiresAt) : occurredAt + maxAgeMs;
|
|
959
|
+
if (expiresAt <= now)
|
|
960
|
+
return deny('expired', 'envelope has expired');
|
|
961
|
+
let canonicalBytes;
|
|
962
|
+
let canonicalDigest;
|
|
963
|
+
try {
|
|
964
|
+
canonicalBytes = canonicalProductPlaneBytes(input.envelope);
|
|
965
|
+
canonicalDigest = canonicalProductPlaneDigest(input.envelope);
|
|
966
|
+
}
|
|
967
|
+
catch {
|
|
968
|
+
return deny('invalid_envelope', 'envelope cannot be canonically encoded');
|
|
969
|
+
}
|
|
970
|
+
try {
|
|
971
|
+
let signatureValid = false;
|
|
972
|
+
if (options.verifySignature) {
|
|
973
|
+
signatureValid = await options.verifySignature({
|
|
974
|
+
issuer: envelope.issuer,
|
|
975
|
+
keyId,
|
|
976
|
+
algorithm,
|
|
977
|
+
canonicalBytes,
|
|
978
|
+
signature,
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
else if (options.resolveKey) {
|
|
982
|
+
const key = await options.resolveKey(envelope.issuer, keyId);
|
|
983
|
+
if (!key)
|
|
984
|
+
return deny('key_not_found', 'issuer key is unavailable or untrusted');
|
|
985
|
+
signatureValid = verifyCryptoSignature(null, canonicalBytes, key, signature);
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
return deny('signature_configuration_missing', 'no authority key resolver or signature verifier is configured');
|
|
989
|
+
}
|
|
990
|
+
if (!signatureValid)
|
|
991
|
+
return deny('signature_invalid', 'envelope signature is invalid');
|
|
992
|
+
const policyDecision = await options.policyVerifier(envelope);
|
|
993
|
+
if (!authorizationAllowed(policyDecision)) {
|
|
994
|
+
return deny('policy_denied', authorizationReason(policyDecision, 'local policy denied the action'));
|
|
995
|
+
}
|
|
996
|
+
const requirements = PRODUCT_ACTION_REQUIREMENTS[envelope.action];
|
|
997
|
+
if (requirements.capability || envelope.capabilityId) {
|
|
998
|
+
const capabilityDecision = await options.capabilityVerifier(envelope);
|
|
999
|
+
if (!authorizationAllowed(capabilityDecision)) {
|
|
1000
|
+
return deny('capability_denied', authorizationReason(capabilityDecision, 'local capability verifier denied the action'));
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
const replayKey = replayKeyFor(envelope);
|
|
1004
|
+
const reservation = await options.replayStore.reserve({
|
|
1005
|
+
key: replayKey,
|
|
1006
|
+
bindingDigest: canonicalDigest,
|
|
1007
|
+
expiresAt,
|
|
1008
|
+
});
|
|
1009
|
+
if (reservation === 'replay')
|
|
1010
|
+
return deny('replay_detected', 'envelope was already accepted');
|
|
1011
|
+
if (reservation === 'conflict') {
|
|
1012
|
+
return deny('idempotency_conflict', 'idempotency identity is bound to different canonical bytes');
|
|
1013
|
+
}
|
|
1014
|
+
if (reservation !== 'reserved')
|
|
1015
|
+
return deny('verification_error', 'replay store returned an invalid result');
|
|
1016
|
+
return { ok: true, envelope, canonicalDigest, replayKey };
|
|
1017
|
+
}
|
|
1018
|
+
catch {
|
|
1019
|
+
return deny('verification_error', 'an authority, policy, capability, or replay verifier failed');
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
//# sourceMappingURL=product-plane.js.map
|