@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,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-111 Phase 4 — Trust-graded firewall projection.
|
|
3
|
+
*
|
|
4
|
+
* Projects the WG_NETWORK_GATES table (defined in wg-mesh-service.ts) into
|
|
5
|
+
* concrete kernel-firewall rules. Two backends:
|
|
6
|
+
*
|
|
7
|
+
* - `nftables` for Linux — atomic `nft -f <file>` loader, family `inet`,
|
|
8
|
+
* hook `input` (interface-scoped to the WG iface).
|
|
9
|
+
* - `pf` for macOS — `pfctl -a ruflo-fed -f <file>`, anchor-scoped so
|
|
10
|
+
* ruflo's rules don't collide with the operator's main pf ruleset.
|
|
11
|
+
*
|
|
12
|
+
* Like Phase 2's WgMeshService this is a **pure-projection** service: it
|
|
13
|
+
* returns rule strings + the shell command the operator runs. It never
|
|
14
|
+
* shells out or modifies kernel state itself. Operator review is mandatory
|
|
15
|
+
* because `pf` / `nft` reloads atomically replace the active ruleset for
|
|
16
|
+
* the targeted scope — a typo here can drop ssh.
|
|
17
|
+
*
|
|
18
|
+
* v1 scope: the four trust levels VERIFIED/ATTESTED/TRUSTED/PRIVILEGED.
|
|
19
|
+
* UNTRUSTED peers are never in the mesh (excluded by WgMeshService) so
|
|
20
|
+
* they don't need a firewall rule either — implicit drop policy.
|
|
21
|
+
*/
|
|
22
|
+
import { TrustLevel } from '../entities/trust-level.js';
|
|
23
|
+
import { WG_NETWORK_GATES, WG_MIN_MESH_TRUST } from './wg-mesh-service.js';
|
|
24
|
+
const DEFAULT_INTERFACE = 'ruflo-fed';
|
|
25
|
+
const DEFAULT_PF_ANCHOR = 'ruflo-fed';
|
|
26
|
+
function autoDetectPlatform() {
|
|
27
|
+
switch (process.platform) {
|
|
28
|
+
case 'linux': return 'linux-nftables';
|
|
29
|
+
case 'darwin': return 'darwin-pf';
|
|
30
|
+
default:
|
|
31
|
+
// Other platforms (win32/freebsd) — fall back to linux-nftables since
|
|
32
|
+
// most production federation hosts are linux. The operator can
|
|
33
|
+
// override via config.platform.
|
|
34
|
+
return 'linux-nftables';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Defense-in-depth: every value spliced into a rule line goes through this
|
|
39
|
+
* filter. Allows the chars `nft`/`pf` syntax actually needs and refuses
|
|
40
|
+
* anything else — a poisoned manifest can't escape the rule string.
|
|
41
|
+
*/
|
|
42
|
+
function assertSafeRuleArg(s, label) {
|
|
43
|
+
if (!/^[A-Za-z0-9_./:-]+$/.test(s)) {
|
|
44
|
+
throw new Error(`WgFirewallService: refusing unsafe ${label}: ${JSON.stringify(s)}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function projectRuleNftables(rule, srcIP) {
|
|
48
|
+
if (rule.proto === 'all') {
|
|
49
|
+
return ` ip saddr ${srcIP} accept`;
|
|
50
|
+
}
|
|
51
|
+
if (rule.port !== undefined) {
|
|
52
|
+
return ` ip saddr ${srcIP} ${rule.proto} dport ${rule.port} accept`;
|
|
53
|
+
}
|
|
54
|
+
if (rule.portRange) {
|
|
55
|
+
const [lo, hi] = rule.portRange;
|
|
56
|
+
return ` ip saddr ${srcIP} ${rule.proto} dport ${lo}-${hi} accept`;
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`projectRuleNftables: rule missing port/portRange/all: ${JSON.stringify(rule)}`);
|
|
59
|
+
}
|
|
60
|
+
function projectRulePf(rule, iface, srcIP) {
|
|
61
|
+
if (rule.proto === 'all') {
|
|
62
|
+
return `pass in on ${iface} from ${srcIP} to any keep state`;
|
|
63
|
+
}
|
|
64
|
+
if (rule.port !== undefined) {
|
|
65
|
+
return `pass in on ${iface} proto ${rule.proto} from ${srcIP} to any port ${rule.port} keep state`;
|
|
66
|
+
}
|
|
67
|
+
if (rule.portRange) {
|
|
68
|
+
const [lo, hi] = rule.portRange;
|
|
69
|
+
return `pass in on ${iface} proto ${rule.proto} from ${srcIP} to any port ${lo}:${hi} keep state`;
|
|
70
|
+
}
|
|
71
|
+
throw new Error(`projectRulePf: rule missing port/portRange/all: ${JSON.stringify(rule)}`);
|
|
72
|
+
}
|
|
73
|
+
export class WgFirewallService {
|
|
74
|
+
platform;
|
|
75
|
+
interfaceName;
|
|
76
|
+
rulePath;
|
|
77
|
+
pfAnchor;
|
|
78
|
+
constructor(config = {}) {
|
|
79
|
+
this.platform = config.platform ?? autoDetectPlatform();
|
|
80
|
+
this.interfaceName = config.interfaceName ?? DEFAULT_INTERFACE;
|
|
81
|
+
assertSafeRuleArg(this.interfaceName, 'interfaceName');
|
|
82
|
+
this.pfAnchor = config.pfAnchor ?? DEFAULT_PF_ANCHOR;
|
|
83
|
+
assertSafeRuleArg(this.pfAnchor, 'pfAnchor');
|
|
84
|
+
this.rulePath = config.rulePath ?? this.defaultRulePath();
|
|
85
|
+
}
|
|
86
|
+
getPlatform() {
|
|
87
|
+
return this.platform;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Project the current peer set into a complete rule file (nftables or pf)
|
|
91
|
+
* scoped to the WG interface.
|
|
92
|
+
*
|
|
93
|
+
* Peers below WG_MIN_MESH_TRUST (UNTRUSTED) are dropped — they have no
|
|
94
|
+
* mesh IP and shouldn't appear in firewall allow rules anyway. Peers
|
|
95
|
+
* without `metadata.wgMeshIP` are skipped (a stale manifest with no WG
|
|
96
|
+
* block; the mesh layer already excludes them).
|
|
97
|
+
*/
|
|
98
|
+
projectRules(peers) {
|
|
99
|
+
const eligible = peers.filter(p => {
|
|
100
|
+
if (p.trustLevel < WG_MIN_MESH_TRUST)
|
|
101
|
+
return false;
|
|
102
|
+
const meshIP = p.metadata.wgMeshIP;
|
|
103
|
+
return typeof meshIP === 'string' && meshIP.length > 0;
|
|
104
|
+
});
|
|
105
|
+
const peerProjections = eligible.map(peer => {
|
|
106
|
+
const meshIP = peer.metadata.wgMeshIP.replace(/\/32$/, '');
|
|
107
|
+
assertSafeRuleArg(meshIP, 'meshIP');
|
|
108
|
+
const ruleSpecs = WG_NETWORK_GATES[peer.trustLevel];
|
|
109
|
+
const rules = ruleSpecs.map(r => this.platform === 'linux-nftables'
|
|
110
|
+
? projectRuleNftables(r, meshIP)
|
|
111
|
+
: projectRulePf(r, this.interfaceName, meshIP));
|
|
112
|
+
return {
|
|
113
|
+
nodeId: peer.nodeId,
|
|
114
|
+
trustLabel: this.trustLabel(peer.trustLevel),
|
|
115
|
+
meshIP: peer.metadata.wgMeshIP,
|
|
116
|
+
rules,
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
const content = this.platform === 'linux-nftables'
|
|
120
|
+
? this.renderNftables(peerProjections)
|
|
121
|
+
: this.renderPf(peerProjections);
|
|
122
|
+
return {
|
|
123
|
+
content,
|
|
124
|
+
loadCmd: this.platform === 'linux-nftables'
|
|
125
|
+
? `nft -f ${this.rulePath}`
|
|
126
|
+
: `pfctl -a ${this.pfAnchor} -f ${this.rulePath}`,
|
|
127
|
+
rulePath: this.rulePath,
|
|
128
|
+
peerProjections,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
renderNftables(projections) {
|
|
132
|
+
// Atomic nft script. The `flush` clears existing rules in the table
|
|
133
|
+
// before reload — same atomicity property nft itself guarantees.
|
|
134
|
+
// Default policy DROP so anything not explicitly allowed is rejected.
|
|
135
|
+
const lines = [];
|
|
136
|
+
lines.push('#!/usr/sbin/nft -f');
|
|
137
|
+
lines.push('# Generated by ruflo federation plugin — ADR-111 Phase 4.');
|
|
138
|
+
lines.push('# Operator MUST review before `nft -f`. A typo here can drop ssh.');
|
|
139
|
+
lines.push('# This file is overwritten on every peer-set change; do not hand-edit.');
|
|
140
|
+
lines.push('');
|
|
141
|
+
lines.push('table inet ruflo_fed {');
|
|
142
|
+
lines.push(' chain wg_input {');
|
|
143
|
+
lines.push(` type filter hook input priority 0; policy drop;`);
|
|
144
|
+
lines.push(` iifname "${this.interfaceName}" jump wg_peer_rules`);
|
|
145
|
+
lines.push(' }');
|
|
146
|
+
lines.push(' chain wg_peer_rules {');
|
|
147
|
+
if (projections.length === 0) {
|
|
148
|
+
lines.push(' # No ATTESTED+ peers in mesh.');
|
|
149
|
+
}
|
|
150
|
+
for (const p of projections) {
|
|
151
|
+
lines.push(` # peer ${p.nodeId} — trust=${p.trustLabel} mesh=${p.meshIP}`);
|
|
152
|
+
for (const rule of p.rules) {
|
|
153
|
+
lines.push(rule);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
lines.push(' }');
|
|
157
|
+
lines.push('}');
|
|
158
|
+
return lines.join('\n');
|
|
159
|
+
}
|
|
160
|
+
renderPf(projections) {
|
|
161
|
+
const lines = [];
|
|
162
|
+
lines.push('# Generated by ruflo federation plugin — ADR-111 Phase 4.');
|
|
163
|
+
lines.push('# Operator MUST review before `pfctl -f`. A typo here can drop ssh.');
|
|
164
|
+
lines.push(`# This anchor is scoped to ${this.pfAnchor}; main pf ruleset stays untouched.`);
|
|
165
|
+
lines.push('');
|
|
166
|
+
// Default within the anchor: pass nothing not explicitly allowed.
|
|
167
|
+
// The main ruleset's policy still applies; the anchor only adds allows.
|
|
168
|
+
if (projections.length === 0) {
|
|
169
|
+
lines.push('# No ATTESTED+ peers in mesh.');
|
|
170
|
+
}
|
|
171
|
+
for (const p of projections) {
|
|
172
|
+
lines.push(`# peer ${p.nodeId} — trust=${p.trustLabel} mesh=${p.meshIP}`);
|
|
173
|
+
for (const rule of p.rules) {
|
|
174
|
+
lines.push(rule);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return lines.join('\n');
|
|
178
|
+
}
|
|
179
|
+
defaultRulePath() {
|
|
180
|
+
return this.platform === 'linux-nftables'
|
|
181
|
+
? '/etc/nftables.d/ruflo-fed.nft'
|
|
182
|
+
: `/etc/pf.anchors/${this.pfAnchor}`;
|
|
183
|
+
}
|
|
184
|
+
trustLabel(level) {
|
|
185
|
+
switch (level) {
|
|
186
|
+
case TrustLevel.UNTRUSTED: return 'UNTRUSTED';
|
|
187
|
+
case TrustLevel.VERIFIED: return 'VERIFIED';
|
|
188
|
+
case TrustLevel.ATTESTED: return 'ATTESTED';
|
|
189
|
+
case TrustLevel.TRUSTED: return 'TRUSTED';
|
|
190
|
+
case TrustLevel.PRIVILEGED: return 'PRIVILEGED';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=wg-firewall-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wg-firewall-service.js","sourceRoot":"","sources":["../../../src/domain/services/wg-firewall-service.ts"],"names":[],"mappings":"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"}
|
package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-mesh-service.d.ts
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-111 Phase 2 — WgMeshService.
|
|
3
|
+
*
|
|
4
|
+
* Pure-projection service: takes the federation peer registry + local
|
|
5
|
+
* WG identity and produces (a) a `wg-quick`-compatible config string,
|
|
6
|
+
* (b) per-peer `wg set` commands the operator runs to converge an
|
|
7
|
+
* already-running interface, and (c) the AllowedIPs slice that maps to
|
|
8
|
+
* each peer's trust level.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately does NOT shell out. Bringing up a network interface
|
|
11
|
+
* requires root and modifies system state — per CLAUDE.md's
|
|
12
|
+
* destructive-actions guidance the service emits the commands; the
|
|
13
|
+
* operator (or a thin shell wrapper they audit) runs them.
|
|
14
|
+
*
|
|
15
|
+
* Phase 3 (breaker integration) consumes this service: peer state
|
|
16
|
+
* transitions invoke removeAllowedIPs/removePeer/restoreAllowedIPs,
|
|
17
|
+
* which produce commands without side effects.
|
|
18
|
+
*/
|
|
19
|
+
import { TrustLevel } from '../entities/trust-level.js';
|
|
20
|
+
import { FederationNode } from '../entities/federation-node.js';
|
|
21
|
+
import type { WgLocalKey } from '../value-objects/wg-config.js';
|
|
22
|
+
export interface WgPortRule {
|
|
23
|
+
readonly proto: 'tcp' | 'udp' | 'all';
|
|
24
|
+
readonly port?: number;
|
|
25
|
+
readonly portRange?: readonly [number, number];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Trust-level → reachability. ADR-111's `WG_NETWORK_GATES`.
|
|
29
|
+
*
|
|
30
|
+
* Note: WireGuard's `AllowedIPs` is L3 routing, not L4 ACL — these port
|
|
31
|
+
* rules describe what the L4 firewall (Phase 4: nftables/pf) should
|
|
32
|
+
* enforce. v1 (this phase) only produces the rules; Phase 4 projects
|
|
33
|
+
* them into kernel firewall syntax. Until then, callers using v1
|
|
34
|
+
* fall back to the simpler "AllowedIPs = peer's mesh IP" model (option
|
|
35
|
+
* (b) in the ADR — app-layer auth carries the access decision).
|
|
36
|
+
*/
|
|
37
|
+
export declare const WG_NETWORK_GATES: Record<TrustLevel, readonly WgPortRule[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Minimum trust level whose peers get a `[Peer]` block in the WG config.
|
|
40
|
+
* UNTRUSTED stays out of the mesh entirely — it's the explicit drop bucket.
|
|
41
|
+
*/
|
|
42
|
+
export declare const WG_MIN_MESH_TRUST: TrustLevel;
|
|
43
|
+
export interface WgPeerFields {
|
|
44
|
+
readonly wgPublicKey: string;
|
|
45
|
+
readonly wgMeshIP: string;
|
|
46
|
+
readonly wgEndpoint: string;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Return the validated peer wg fields, or null if any is malformed or
|
|
50
|
+
* out-of-range. Callers treat null as "peer not eligible for mesh" — the
|
|
51
|
+
* peer stays in the federation discovery registry but is excluded from
|
|
52
|
+
* the wg config and any wg commands.
|
|
53
|
+
*/
|
|
54
|
+
export declare function readSafePeerWgFields(peer: FederationNode): WgPeerFields | null;
|
|
55
|
+
export interface WgMeshServiceConfig {
|
|
56
|
+
/** Local interface name. Defaults to `ruflo-fed`. */
|
|
57
|
+
readonly interfaceName?: string;
|
|
58
|
+
/** Local UDP listen port. WireGuard's standard is 51820. */
|
|
59
|
+
readonly listenPort?: number;
|
|
60
|
+
/** Mesh subnet for AllowedIPs filtering. Defaults to DEFAULT_MESH_SUBNET. */
|
|
61
|
+
readonly meshSubnet?: string;
|
|
62
|
+
}
|
|
63
|
+
export interface WgPeerSummary {
|
|
64
|
+
readonly nodeId: string;
|
|
65
|
+
readonly trustLevel: TrustLevel;
|
|
66
|
+
readonly trustLabel: string;
|
|
67
|
+
readonly meshIP: string;
|
|
68
|
+
readonly endpoint: string;
|
|
69
|
+
readonly publicKey: string;
|
|
70
|
+
readonly state: 'active' | 'suspended' | 'evicted';
|
|
71
|
+
readonly allowedIPs: readonly string[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* A planned `wg(8)` mutation. Service consumers either execute these or
|
|
75
|
+
* surface them to the operator. Strings are validated for shell metachars
|
|
76
|
+
* before being formatted into a command — callers should still review.
|
|
77
|
+
*/
|
|
78
|
+
export interface WgCommand {
|
|
79
|
+
readonly verb: 'set-allowed-ips' | 'remove-allowed-ips' | 'remove-peer' | 'add-peer';
|
|
80
|
+
/** Public key of the peer this command targets. */
|
|
81
|
+
readonly peerPublicKey: string;
|
|
82
|
+
/** Render to a `wg set <iface> peer <pk> ...` shell-ready string. */
|
|
83
|
+
readonly cmd: string;
|
|
84
|
+
/** Human-readable rationale for audit logs. */
|
|
85
|
+
readonly rationale: string;
|
|
86
|
+
}
|
|
87
|
+
export declare class WgMeshService {
|
|
88
|
+
private readonly interfaceName;
|
|
89
|
+
private readonly listenPort;
|
|
90
|
+
private readonly meshSubnet;
|
|
91
|
+
private localKey;
|
|
92
|
+
private localMeshIP;
|
|
93
|
+
/** Per-peer AllowedIPs after the last applyTrustLevelToAllowedIPs() call. Drives restore from breaker. */
|
|
94
|
+
private readonly lastAppliedAllowedIPs;
|
|
95
|
+
/** Peer-pubkey → suspended flag for breaker integration. */
|
|
96
|
+
private readonly suspended;
|
|
97
|
+
/** Peer-pubkey → evicted flag. */
|
|
98
|
+
private readonly evicted;
|
|
99
|
+
constructor(config?: WgMeshServiceConfig);
|
|
100
|
+
/** Bind the local WG identity. Required before buildInterfaceConfig(). */
|
|
101
|
+
setLocalIdentity(key: WgLocalKey, meshIP: string): void;
|
|
102
|
+
getInterfaceName(): string;
|
|
103
|
+
getMeshSubnet(): string;
|
|
104
|
+
/**
|
|
105
|
+
* Build a `wg-quick`-compatible config string from current peers.
|
|
106
|
+
*
|
|
107
|
+
* Peers below WG_MIN_MESH_TRUST (UNTRUSTED) are excluded entirely.
|
|
108
|
+
* Suspended peers stay in the config but with `AllowedIPs =` empty
|
|
109
|
+
* (soft-block). Evicted peers are dropped completely.
|
|
110
|
+
*
|
|
111
|
+
* Operator writes this to `/etc/wireguard/<interface>.conf` and runs
|
|
112
|
+
* `wg-quick up <interface>`.
|
|
113
|
+
*/
|
|
114
|
+
buildInterfaceConfig(peers: readonly FederationNode[]): string;
|
|
115
|
+
/**
|
|
116
|
+
* Compute the AllowedIPs slice for a peer at its current trust level.
|
|
117
|
+
* v1: each peer gets its own /32 mesh IP. Phase 4 will narrow this
|
|
118
|
+
* further via firewall rules; v1 keeps L3 broad and relies on the app
|
|
119
|
+
* layer + trust gates for access decisions.
|
|
120
|
+
*/
|
|
121
|
+
computeAllowedIPs(peer: FederationNode, meshIP: string): readonly string[];
|
|
122
|
+
/**
|
|
123
|
+
* Apply trust level → AllowedIPs as a `wg set` command for an
|
|
124
|
+
* already-running interface. Used when a peer joins or its trust level
|
|
125
|
+
* changes without needing a full config rewrite.
|
|
126
|
+
*/
|
|
127
|
+
applyTrustLevelToAllowedIPs(peer: FederationNode, meshIP: string, pubkey: string): WgCommand;
|
|
128
|
+
/**
|
|
129
|
+
* Phase 3 hook — peer SUSPENDED. Clear AllowedIPs (soft-block: keeps
|
|
130
|
+
* the peer's public key registered with the interface but blocks all
|
|
131
|
+
* routing to/from it).
|
|
132
|
+
*/
|
|
133
|
+
removeAllowedIPs(peer: FederationNode, pubkey: string, reason?: string): WgCommand;
|
|
134
|
+
/**
|
|
135
|
+
* Phase 3 hook — peer reactivated. Restore the AllowedIPs slice that
|
|
136
|
+
* was active before suspension. Returns null if the peer was never
|
|
137
|
+
* suspended (idempotent).
|
|
138
|
+
*/
|
|
139
|
+
restoreAllowedIPs(peer: FederationNode, meshIP: string, pubkey: string): WgCommand | null;
|
|
140
|
+
/**
|
|
141
|
+
* Phase 3 hook — peer EVICTED. Terminal removal from the mesh; the
|
|
142
|
+
* peer's `[Peer]` block is dropped on next config rebuild and an
|
|
143
|
+
* immediate `wg set <iface> peer <pk> remove` is emitted to flush
|
|
144
|
+
* runtime state without a config reload.
|
|
145
|
+
*/
|
|
146
|
+
removePeer(peer: FederationNode, pubkey: string, reason?: string): WgCommand;
|
|
147
|
+
/** Summarize the mesh state for `federation_wg_status` (Phase 6) and audit. */
|
|
148
|
+
summarize(peers: readonly FederationNode[]): readonly WgPeerSummary[];
|
|
149
|
+
/**
|
|
150
|
+
* Defense-in-depth: validate that all bits we splice into a shell
|
|
151
|
+
* command are alphanumeric / base64 / WG-allowed chars. Refuses the
|
|
152
|
+
* command rather than ship a substring that might escape its slot.
|
|
153
|
+
*/
|
|
154
|
+
private formatCmd;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=wg-mesh-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wg-mesh-service.d.ts","sourceRoot":"","sources":["../../../src/domain/services/wg-mesh-service.ts"],"names":[],"mappings":"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"}
|
package/node_modules/@claude-flow/plugin-agent-federation/dist/domain/services/wg-mesh-service.js
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR-111 Phase 2 — WgMeshService.
|
|
3
|
+
*
|
|
4
|
+
* Pure-projection service: takes the federation peer registry + local
|
|
5
|
+
* WG identity and produces (a) a `wg-quick`-compatible config string,
|
|
6
|
+
* (b) per-peer `wg set` commands the operator runs to converge an
|
|
7
|
+
* already-running interface, and (c) the AllowedIPs slice that maps to
|
|
8
|
+
* each peer's trust level.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately does NOT shell out. Bringing up a network interface
|
|
11
|
+
* requires root and modifies system state — per CLAUDE.md's
|
|
12
|
+
* destructive-actions guidance the service emits the commands; the
|
|
13
|
+
* operator (or a thin shell wrapper they audit) runs them.
|
|
14
|
+
*
|
|
15
|
+
* Phase 3 (breaker integration) consumes this service: peer state
|
|
16
|
+
* transitions invoke removeAllowedIPs/removePeer/restoreAllowedIPs,
|
|
17
|
+
* which produce commands without side effects.
|
|
18
|
+
*/
|
|
19
|
+
import { TrustLevel, getTrustLevelLabel } from '../entities/trust-level.js';
|
|
20
|
+
import { DEFAULT_MESH_SUBNET } from '../value-objects/wg-config.js';
|
|
21
|
+
/**
|
|
22
|
+
* Trust-level → reachability. ADR-111's `WG_NETWORK_GATES`.
|
|
23
|
+
*
|
|
24
|
+
* Note: WireGuard's `AllowedIPs` is L3 routing, not L4 ACL — these port
|
|
25
|
+
* rules describe what the L4 firewall (Phase 4: nftables/pf) should
|
|
26
|
+
* enforce. v1 (this phase) only produces the rules; Phase 4 projects
|
|
27
|
+
* them into kernel firewall syntax. Until then, callers using v1
|
|
28
|
+
* fall back to the simpler "AllowedIPs = peer's mesh IP" model (option
|
|
29
|
+
* (b) in the ADR — app-layer auth carries the access decision).
|
|
30
|
+
*/
|
|
31
|
+
export const WG_NETWORK_GATES = {
|
|
32
|
+
[TrustLevel.UNTRUSTED]: [],
|
|
33
|
+
[TrustLevel.VERIFIED]: [
|
|
34
|
+
{ proto: 'tcp', port: 9100 },
|
|
35
|
+
],
|
|
36
|
+
[TrustLevel.ATTESTED]: [
|
|
37
|
+
{ proto: 'tcp', port: 9100 },
|
|
38
|
+
{ proto: 'tcp', portRange: [9101, 9199] },
|
|
39
|
+
],
|
|
40
|
+
[TrustLevel.TRUSTED]: [
|
|
41
|
+
{ proto: 'tcp', port: 9100 },
|
|
42
|
+
{ proto: 'tcp', portRange: [9101, 9199] },
|
|
43
|
+
{ proto: 'tcp', port: 22 },
|
|
44
|
+
{ proto: 'tcp', portRange: [80, 443] },
|
|
45
|
+
],
|
|
46
|
+
[TrustLevel.PRIVILEGED]: [
|
|
47
|
+
{ proto: 'all' },
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Minimum trust level whose peers get a `[Peer]` block in the WG config.
|
|
52
|
+
* UNTRUSTED stays out of the mesh entirely — it's the explicit drop bucket.
|
|
53
|
+
*/
|
|
54
|
+
export const WG_MIN_MESH_TRUST = TrustLevel.VERIFIED;
|
|
55
|
+
/**
|
|
56
|
+
* Security: validate every field we splice into a wg-quick config string
|
|
57
|
+
* or shell command. The ADR's threat model explicitly includes "compromised
|
|
58
|
+
* federation peer with valid WG key" — that peer signs their own manifest,
|
|
59
|
+
* so the Ed25519 signature only proves origin, not content safety. A
|
|
60
|
+
* compromised peer could publish e.g. wgEndpoint = "host:51820\n[Peer]\n..."
|
|
61
|
+
* to inject extra peers into the config the operator runs via wg-quick.
|
|
62
|
+
*
|
|
63
|
+
* These regexes are intentionally narrow:
|
|
64
|
+
* - publicKey: base64 X25519, exactly 43 chars + '=' padding
|
|
65
|
+
* - meshIP: a.b.c.d/32, octets 0-255, no whitespace
|
|
66
|
+
* - endpoint: hostname-or-ipv4-or-bracketed-ipv6 + :port, no newlines/specials
|
|
67
|
+
*/
|
|
68
|
+
const WG_PUBKEY_REGEX = /^[A-Za-z0-9+/]{43}=$/;
|
|
69
|
+
const WG_MESH_IP_REGEX = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/32$/;
|
|
70
|
+
const WG_ENDPOINT_REGEX = /^(\[[0-9a-fA-F:]+\]|[a-zA-Z0-9][a-zA-Z0-9.-]*):\d{1,5}$/;
|
|
71
|
+
/**
|
|
72
|
+
* Return the validated peer wg fields, or null if any is malformed or
|
|
73
|
+
* out-of-range. Callers treat null as "peer not eligible for mesh" — the
|
|
74
|
+
* peer stays in the federation discovery registry but is excluded from
|
|
75
|
+
* the wg config and any wg commands.
|
|
76
|
+
*/
|
|
77
|
+
export function readSafePeerWgFields(peer) {
|
|
78
|
+
const pk = peer.metadata.wgPublicKey;
|
|
79
|
+
const ip = peer.metadata.wgMeshIP;
|
|
80
|
+
const ep = peer.metadata.wgEndpoint;
|
|
81
|
+
if (typeof pk !== 'string' || !WG_PUBKEY_REGEX.test(pk))
|
|
82
|
+
return null;
|
|
83
|
+
if (typeof ip !== 'string' || !WG_MESH_IP_REGEX.test(ip))
|
|
84
|
+
return null;
|
|
85
|
+
const ipMatch = ip.match(WG_MESH_IP_REGEX);
|
|
86
|
+
if (!ipMatch || [ipMatch[1], ipMatch[2], ipMatch[3], ipMatch[4]].some(o => Number(o) > 255))
|
|
87
|
+
return null;
|
|
88
|
+
if (typeof ep !== 'string' || !WG_ENDPOINT_REGEX.test(ep))
|
|
89
|
+
return null;
|
|
90
|
+
const port = Number(ep.split(':').pop());
|
|
91
|
+
if (port < 1 || port > 65535)
|
|
92
|
+
return null;
|
|
93
|
+
return { wgPublicKey: pk, wgMeshIP: ip, wgEndpoint: ep };
|
|
94
|
+
}
|
|
95
|
+
const DEFAULT_INTERFACE = 'ruflo-fed';
|
|
96
|
+
const DEFAULT_LISTEN_PORT = 51820;
|
|
97
|
+
export class WgMeshService {
|
|
98
|
+
interfaceName;
|
|
99
|
+
listenPort;
|
|
100
|
+
meshSubnet;
|
|
101
|
+
localKey = null;
|
|
102
|
+
localMeshIP = null;
|
|
103
|
+
/** Per-peer AllowedIPs after the last applyTrustLevelToAllowedIPs() call. Drives restore from breaker. */
|
|
104
|
+
lastAppliedAllowedIPs = new Map();
|
|
105
|
+
/** Peer-pubkey → suspended flag for breaker integration. */
|
|
106
|
+
suspended = new Set();
|
|
107
|
+
/** Peer-pubkey → evicted flag. */
|
|
108
|
+
evicted = new Set();
|
|
109
|
+
constructor(config = {}) {
|
|
110
|
+
this.interfaceName = config.interfaceName ?? DEFAULT_INTERFACE;
|
|
111
|
+
this.listenPort = config.listenPort ?? DEFAULT_LISTEN_PORT;
|
|
112
|
+
this.meshSubnet = config.meshSubnet ?? DEFAULT_MESH_SUBNET;
|
|
113
|
+
}
|
|
114
|
+
/** Bind the local WG identity. Required before buildInterfaceConfig(). */
|
|
115
|
+
setLocalIdentity(key, meshIP) {
|
|
116
|
+
this.localKey = key;
|
|
117
|
+
this.localMeshIP = meshIP;
|
|
118
|
+
}
|
|
119
|
+
getInterfaceName() {
|
|
120
|
+
return this.interfaceName;
|
|
121
|
+
}
|
|
122
|
+
getMeshSubnet() {
|
|
123
|
+
return this.meshSubnet;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Build a `wg-quick`-compatible config string from current peers.
|
|
127
|
+
*
|
|
128
|
+
* Peers below WG_MIN_MESH_TRUST (UNTRUSTED) are excluded entirely.
|
|
129
|
+
* Suspended peers stay in the config but with `AllowedIPs =` empty
|
|
130
|
+
* (soft-block). Evicted peers are dropped completely.
|
|
131
|
+
*
|
|
132
|
+
* Operator writes this to `/etc/wireguard/<interface>.conf` and runs
|
|
133
|
+
* `wg-quick up <interface>`.
|
|
134
|
+
*/
|
|
135
|
+
buildInterfaceConfig(peers) {
|
|
136
|
+
if (!this.localKey || !this.localMeshIP) {
|
|
137
|
+
throw new Error('WgMeshService.buildInterfaceConfig: local identity not set; call setLocalIdentity() first');
|
|
138
|
+
}
|
|
139
|
+
const lines = [];
|
|
140
|
+
lines.push('# Generated by ruflo federation plugin — ADR-111 Phase 2.');
|
|
141
|
+
lines.push('# Operator MUST review before `wg-quick up`. Trust-graded port');
|
|
142
|
+
lines.push('# rules (WG_NETWORK_GATES) are not enforced here — Phase 4 will');
|
|
143
|
+
lines.push('# project them into nftables/pf. v1 uses mesh-IP isolation only.');
|
|
144
|
+
lines.push('[Interface]');
|
|
145
|
+
lines.push(`PrivateKey = ${this.localKey.privateKey}`);
|
|
146
|
+
lines.push(`Address = ${this.localMeshIP}`);
|
|
147
|
+
lines.push(`ListenPort = ${this.listenPort}`);
|
|
148
|
+
lines.push('');
|
|
149
|
+
for (const peer of peers) {
|
|
150
|
+
if (peer.trustLevel < WG_MIN_MESH_TRUST)
|
|
151
|
+
continue;
|
|
152
|
+
// Security: validate every spliced field. A compromised but-signed
|
|
153
|
+
// peer can otherwise inject extra [Peer] blocks via newline-laden
|
|
154
|
+
// wgEndpoint. readSafePeerWgFields enforces base64/CIDR/host:port
|
|
155
|
+
// regexes; mismatches skip the peer entirely (safer than partial-write).
|
|
156
|
+
const safe = readSafePeerWgFields(peer);
|
|
157
|
+
if (!safe)
|
|
158
|
+
continue;
|
|
159
|
+
if (this.evicted.has(safe.wgPublicKey))
|
|
160
|
+
continue;
|
|
161
|
+
const allowed = this.suspended.has(safe.wgPublicKey)
|
|
162
|
+
? ''
|
|
163
|
+
: this.computeAllowedIPs(peer, safe.wgMeshIP).join(', ');
|
|
164
|
+
lines.push(`# Peer ${peer.nodeId} — trust=${getTrustLevelLabel(peer.trustLevel)}${this.suspended.has(safe.wgPublicKey) ? ' (SUSPENDED)' : ''}`);
|
|
165
|
+
lines.push('[Peer]');
|
|
166
|
+
lines.push(`PublicKey = ${safe.wgPublicKey}`);
|
|
167
|
+
lines.push(`Endpoint = ${safe.wgEndpoint}`);
|
|
168
|
+
lines.push(`AllowedIPs = ${allowed}`);
|
|
169
|
+
lines.push('');
|
|
170
|
+
}
|
|
171
|
+
return lines.join('\n');
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Compute the AllowedIPs slice for a peer at its current trust level.
|
|
175
|
+
* v1: each peer gets its own /32 mesh IP. Phase 4 will narrow this
|
|
176
|
+
* further via firewall rules; v1 keeps L3 broad and relies on the app
|
|
177
|
+
* layer + trust gates for access decisions.
|
|
178
|
+
*/
|
|
179
|
+
computeAllowedIPs(peer, meshIP) {
|
|
180
|
+
if (peer.trustLevel === TrustLevel.UNTRUSTED)
|
|
181
|
+
return [];
|
|
182
|
+
const ips = [meshIP];
|
|
183
|
+
this.lastAppliedAllowedIPs.set(peer.nodeId, ips);
|
|
184
|
+
return ips;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Apply trust level → AllowedIPs as a `wg set` command for an
|
|
188
|
+
* already-running interface. Used when a peer joins or its trust level
|
|
189
|
+
* changes without needing a full config rewrite.
|
|
190
|
+
*/
|
|
191
|
+
applyTrustLevelToAllowedIPs(peer, meshIP, pubkey) {
|
|
192
|
+
const ips = this.computeAllowedIPs(peer, meshIP);
|
|
193
|
+
return {
|
|
194
|
+
verb: 'set-allowed-ips',
|
|
195
|
+
peerPublicKey: pubkey,
|
|
196
|
+
cmd: this.formatCmd(`peer ${pubkey} allowed-ips ${ips.join(',')}`),
|
|
197
|
+
rationale: `apply AllowedIPs for ${peer.nodeId} at trust=${getTrustLevelLabel(peer.trustLevel)}`,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Phase 3 hook — peer SUSPENDED. Clear AllowedIPs (soft-block: keeps
|
|
202
|
+
* the peer's public key registered with the interface but blocks all
|
|
203
|
+
* routing to/from it).
|
|
204
|
+
*/
|
|
205
|
+
removeAllowedIPs(peer, pubkey, reason) {
|
|
206
|
+
this.suspended.add(pubkey);
|
|
207
|
+
return {
|
|
208
|
+
verb: 'remove-allowed-ips',
|
|
209
|
+
peerPublicKey: pubkey,
|
|
210
|
+
cmd: this.formatCmd(`peer ${pubkey} allowed-ips ""`),
|
|
211
|
+
rationale: `SUSPEND ${peer.nodeId}${reason ? ` (${reason})` : ''} — clear AllowedIPs (soft-block)`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Phase 3 hook — peer reactivated. Restore the AllowedIPs slice that
|
|
216
|
+
* was active before suspension. Returns null if the peer was never
|
|
217
|
+
* suspended (idempotent).
|
|
218
|
+
*/
|
|
219
|
+
restoreAllowedIPs(peer, meshIP, pubkey) {
|
|
220
|
+
if (!this.suspended.has(pubkey))
|
|
221
|
+
return null;
|
|
222
|
+
this.suspended.delete(pubkey);
|
|
223
|
+
const previous = this.lastAppliedAllowedIPs.get(peer.nodeId);
|
|
224
|
+
const ips = previous && previous.length > 0 ? previous : this.computeAllowedIPs(peer, meshIP);
|
|
225
|
+
return {
|
|
226
|
+
verb: 'set-allowed-ips',
|
|
227
|
+
peerPublicKey: pubkey,
|
|
228
|
+
cmd: this.formatCmd(`peer ${pubkey} allowed-ips ${ips.join(',')}`),
|
|
229
|
+
rationale: `REACTIVATE ${peer.nodeId} — restore AllowedIPs ${ips.join(',')}`,
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Phase 3 hook — peer EVICTED. Terminal removal from the mesh; the
|
|
234
|
+
* peer's `[Peer]` block is dropped on next config rebuild and an
|
|
235
|
+
* immediate `wg set <iface> peer <pk> remove` is emitted to flush
|
|
236
|
+
* runtime state without a config reload.
|
|
237
|
+
*/
|
|
238
|
+
removePeer(peer, pubkey, reason) {
|
|
239
|
+
this.evicted.add(pubkey);
|
|
240
|
+
this.suspended.delete(pubkey);
|
|
241
|
+
this.lastAppliedAllowedIPs.delete(peer.nodeId);
|
|
242
|
+
return {
|
|
243
|
+
verb: 'remove-peer',
|
|
244
|
+
peerPublicKey: pubkey,
|
|
245
|
+
cmd: this.formatCmd(`peer ${pubkey} remove`),
|
|
246
|
+
rationale: `EVICT ${peer.nodeId}${reason ? ` (${reason})` : ''} — drop from mesh`,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/** Summarize the mesh state for `federation_wg_status` (Phase 6) and audit. */
|
|
250
|
+
summarize(peers) {
|
|
251
|
+
return peers
|
|
252
|
+
.filter(p => p.trustLevel >= WG_MIN_MESH_TRUST)
|
|
253
|
+
.map(peer => {
|
|
254
|
+
// Security: same validation as buildInterfaceConfig. If a peer
|
|
255
|
+
// published unsafe wg fields they get reported with empty strings —
|
|
256
|
+
// visible in operator status without becoming an injection vector.
|
|
257
|
+
const safe = readSafePeerWgFields(peer);
|
|
258
|
+
const meshIP = safe?.wgMeshIP ?? '';
|
|
259
|
+
const pubkey = safe?.wgPublicKey ?? '';
|
|
260
|
+
const endpoint = safe?.wgEndpoint ?? '';
|
|
261
|
+
let state = 'active';
|
|
262
|
+
if (pubkey && this.evicted.has(pubkey))
|
|
263
|
+
state = 'evicted';
|
|
264
|
+
else if (pubkey && this.suspended.has(pubkey))
|
|
265
|
+
state = 'suspended';
|
|
266
|
+
return {
|
|
267
|
+
nodeId: peer.nodeId,
|
|
268
|
+
trustLevel: peer.trustLevel,
|
|
269
|
+
trustLabel: getTrustLevelLabel(peer.trustLevel),
|
|
270
|
+
meshIP,
|
|
271
|
+
endpoint,
|
|
272
|
+
publicKey: pubkey,
|
|
273
|
+
state,
|
|
274
|
+
allowedIPs: safe && state === 'active' ? this.computeAllowedIPs(peer, safe.wgMeshIP) : [],
|
|
275
|
+
};
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Defense-in-depth: validate that all bits we splice into a shell
|
|
280
|
+
* command are alphanumeric / base64 / WG-allowed chars. Refuses the
|
|
281
|
+
* command rather than ship a substring that might escape its slot.
|
|
282
|
+
*/
|
|
283
|
+
formatCmd(args) {
|
|
284
|
+
// Allow: base64 pubkey chars [A-Za-z0-9+/=], IPv4 mesh chars
|
|
285
|
+
// [0-9./], plus a handful of fixed verbs. Reject everything else.
|
|
286
|
+
if (!/^[A-Za-z0-9+/=., "/-]*$/.test(args)) {
|
|
287
|
+
throw new Error(`WgMeshService.formatCmd: refusing arg with unsafe chars: ${JSON.stringify(args)}`);
|
|
288
|
+
}
|
|
289
|
+
return `wg set ${this.interfaceName} ${args}`;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=wg-mesh-service.js.map
|