settld 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (483) hide show
  1. package/README.md +93 -3
  2. package/SETTLD_VERSION +1 -1
  3. package/bin/settld-mcp +2 -0
  4. package/bin/settld.js +71 -0
  5. package/conformance/kernel-v0/README.md +7 -0
  6. package/conformance/kernel-v0/run.mjs +292 -4
  7. package/docs/ACCESS.md +57 -0
  8. package/docs/ADOPTION_CHECKLIST.md +44 -0
  9. package/docs/ALERTS.md +198 -0
  10. package/docs/ARCHITECTURE.md +69 -0
  11. package/docs/ARCHITECTURE_FOUNDER_GUIDE.md +284 -0
  12. package/docs/ARTIFACTS.md +60 -0
  13. package/docs/CERTIFICATION_CHECKLIST.md +33 -0
  14. package/docs/CIRCLE_SANDBOX_E2E.md +152 -0
  15. package/docs/CONFIG.md +297 -0
  16. package/docs/CONTRACTS_APIS.md +23 -0
  17. package/docs/DEPRECATION.md +31 -0
  18. package/docs/DOMAIN_MODEL.md +92 -0
  19. package/docs/EVENT_ENVELOPE.md +53 -0
  20. package/docs/FINANCE_PACK_FORMAT.md +53 -0
  21. package/docs/INCIDENT_TAXONOMY.md +30 -0
  22. package/docs/JOB_STATE_MACHINE.md +66 -0
  23. package/docs/KERNEL_COMPATIBLE.md +60 -0
  24. package/docs/KERNEL_V0.md +40 -0
  25. package/docs/KEY_ROTATION.md +80 -0
  26. package/docs/LEDGER.md +82 -0
  27. package/docs/LIVENESS.md +76 -0
  28. package/docs/MVP_BUILD_ORDER.md +36 -0
  29. package/docs/ONCALL_PLAYBOOK.md +39 -0
  30. package/docs/OPERATIONS_SIGNING.md +20 -0
  31. package/docs/OVERVIEW.md +190 -0
  32. package/docs/PERF_BASELINE.md +85 -0
  33. package/docs/PRD.md +77 -0
  34. package/docs/QUICKSTART_KERNEL_V0.md +96 -0
  35. package/docs/QUICKSTART_MCP.md +377 -0
  36. package/docs/QUICKSTART_MCP_HOSTS.md +210 -0
  37. package/docs/QUICKSTART_POLICY_PACKS.md +65 -0
  38. package/docs/QUICKSTART_PRODUCE.md +61 -0
  39. package/docs/QUICKSTART_PROFILES.md +198 -0
  40. package/docs/QUICKSTART_RELEASE_VERIFY.md +39 -0
  41. package/docs/QUICKSTART_SDK.md +125 -0
  42. package/docs/QUICKSTART_SDK_PYTHON.md +111 -0
  43. package/docs/QUICKSTART_VERIFY.md +54 -0
  44. package/docs/QUICKSTART_X402_GATEWAY.md +317 -0
  45. package/docs/README.md +33 -0
  46. package/docs/RELEASE_CHECKLIST.md +182 -0
  47. package/docs/RELEASING.md +82 -0
  48. package/docs/REPO_SETTINGS.md +37 -0
  49. package/docs/RUNBOOK.md +86 -0
  50. package/docs/SKILLS.md +42 -0
  51. package/docs/SKILL_BUNDLE_FORMAT.md +48 -0
  52. package/docs/SLO.md +131 -0
  53. package/docs/SUMMARY.md +17 -0
  54. package/docs/SUPPORT.md +31 -0
  55. package/docs/THREAT_MODEL.md +36 -0
  56. package/docs/TRUST.md +59 -0
  57. package/docs/WORKFLOW.md +35 -0
  58. package/docs/X402_BATCH_SETTLEMENT.md +126 -0
  59. package/docs/blog/2026-02-14-your-ai-agent-just-spent-500-where-is-the-receipt.md +73 -0
  60. package/docs/examples/x402-provider-payout-registry.example.json +14 -0
  61. package/docs/gitbook/README.md +64 -0
  62. package/docs/gitbook/SETUP.md +25 -0
  63. package/docs/gitbook/SUMMARY.md +15 -0
  64. package/docs/gitbook/api-reference.md +73 -0
  65. package/docs/gitbook/closepacks.md +55 -0
  66. package/docs/gitbook/conformance.md +59 -0
  67. package/docs/gitbook/core-primitives.md +85 -0
  68. package/docs/gitbook/dispute-lifecycle.md +33 -0
  69. package/docs/gitbook/faq.md +21 -0
  70. package/docs/gitbook/guides.md +49 -0
  71. package/docs/gitbook/operations-runbook.md +36 -0
  72. package/docs/gitbook/quickstart.md +103 -0
  73. package/docs/gitbook/replay-and-audit.md +30 -0
  74. package/docs/gitbook/sdk-reference.md +35 -0
  75. package/docs/gitbook/security-model.md +58 -0
  76. package/docs/integrations/README.md +15 -0
  77. package/docs/integrations/github-actions-verify.yml +31 -0
  78. package/docs/integrations/github-actions.md +34 -0
  79. package/docs/integrations/openclaw/CLAWHUB_PUBLISH_CHECKLIST.md +65 -0
  80. package/docs/integrations/openclaw/PUBLIC_QUICKSTART.md +95 -0
  81. package/docs/integrations/openclaw/settld-mcp-skill/SKILL.md +69 -0
  82. package/docs/integrations/openclaw/settld-mcp-skill/mcp-server.example.json +12 -0
  83. package/docs/kernel-compatible/capabilities.json +36 -0
  84. package/docs/marketing/agent-commerce-substrate.md +78 -0
  85. package/docs/marketing/hn-repost-2026-02-17.md +102 -0
  86. package/docs/marketing/show-hn-post.md +45 -0
  87. package/docs/ops/ARTIFACT_VERIFICATION_STATUS.md +43 -0
  88. package/docs/ops/BILLING_WEBHOOK_REPLAY.md +105 -0
  89. package/docs/ops/CI_FLAKE_BUDGET.md +31 -0
  90. package/docs/ops/DISPUTE_FINANCE_RECONCILIATION_PACKET.md +56 -0
  91. package/docs/ops/GO_LIVE_GATE_S13.md +27 -0
  92. package/docs/ops/HOSTED_BASELINE_R2.md +129 -0
  93. package/docs/ops/KERNEL_V0_SHIP_GATE.md +69 -0
  94. package/docs/ops/LIGHTHOUSE_PRODUCTION_CLOSE.md +51 -0
  95. package/docs/ops/MCP_COMPATIBILITY_MATRIX.md +30 -0
  96. package/docs/ops/MINIMUM_PRODUCTION_TOPOLOGY.md +89 -0
  97. package/docs/ops/P0_BACKEND_PROGRESS.md +150 -0
  98. package/docs/ops/PAYMENTS_ALPHA_R5.md +105 -0
  99. package/docs/ops/PILOT_ONBOARDING_RUNBOOK.md +112 -0
  100. package/docs/ops/PRODUCTION_DEPLOYMENT_CHECKLIST.md +140 -0
  101. package/docs/ops/R1_SLOS.md +66 -0
  102. package/docs/ops/RELEASE_SIGNING_INCIDENT.md +58 -0
  103. package/docs/ops/SELF_SERVE_LAUNCH_AUTOMATION.md +89 -0
  104. package/docs/ops/THROUGHPUT_DRILL_10X.md +48 -0
  105. package/docs/ops/TRUST_CONFIG_WIZARD.md +60 -0
  106. package/docs/ops/X402_PILOT_WEEKLY_METRICS.md +76 -0
  107. package/docs/ops/tool-call-disputes-holdback.md +52 -0
  108. package/docs/pilot-kit/PILOT_PACKAGE_SCORECARD_X402.md +46 -0
  109. package/docs/pilot-kit/README.md +29 -0
  110. package/docs/pilot-kit/architecture-one-pager.md +48 -0
  111. package/docs/pilot-kit/buyer-email.txt +19 -0
  112. package/docs/pilot-kit/buyer-one-pager.md +31 -0
  113. package/docs/pilot-kit/gtm-pilot-playbook.md +182 -0
  114. package/docs/pilot-kit/offline-verify.md +33 -0
  115. package/docs/pilot-kit/procurement-one-pager.md +50 -0
  116. package/docs/pilot-kit/rfp-clause.md +46 -0
  117. package/docs/pilot-kit/roi-calculator-template.csv +2 -0
  118. package/docs/pilot-kit/security-qa.md +153 -0
  119. package/docs/pilot-kit/security-summary.md +35 -0
  120. package/docs/plans/2026-02-13-mcp-spike-design.md +113 -0
  121. package/docs/plans/2026-02-20-trust-os-v1-jira-backlog.md +348 -0
  122. package/docs/plans/2026-02-21-agent-economic-actor-operating-model.md +169 -0
  123. package/docs/plans/2026-02-21-trust-os-v1-strategy.md +241 -0
  124. package/docs/research/2026-02-21-agent-spend-host-landscape.md +57 -0
  125. package/docs/spec/AcceptanceCriteria.v1.md +17 -0
  126. package/docs/spec/AcceptanceEvaluation.v1.md +10 -0
  127. package/docs/spec/AgentEvent.v1.md +47 -0
  128. package/docs/spec/AgentIdentity.v1.md +62 -0
  129. package/docs/spec/AgentPassport.v1.md +95 -0
  130. package/docs/spec/AgentReputation.v1.md +59 -0
  131. package/docs/spec/AgentReputation.v2.md +52 -0
  132. package/docs/spec/AgentRun.v1.md +47 -0
  133. package/docs/spec/AgentRunSettlement.v1.md +52 -0
  134. package/docs/spec/AgentWallet.v1.md +43 -0
  135. package/docs/spec/AgreementDelegation.v1.md +109 -0
  136. package/docs/spec/ArbitrationCase.v1.md +67 -0
  137. package/docs/spec/ArbitrationOutcomeMapping.v1.md +62 -0
  138. package/docs/spec/ArbitrationVerdict.v1.md +60 -0
  139. package/docs/spec/BundleHeadAttestation.v1.md +32 -0
  140. package/docs/spec/CANONICAL_JSON.md +31 -0
  141. package/docs/spec/CRYPTOGRAPHY.md +61 -0
  142. package/docs/spec/ClosePack.v1.md +49 -0
  143. package/docs/spec/ClosePackManifest.v1.md +24 -0
  144. package/docs/spec/DelegationGrant.v1.md +90 -0
  145. package/docs/spec/DisputeCaseLifecycle.v1.md +51 -0
  146. package/docs/spec/DisputeOpenEnvelope.v1.md +43 -0
  147. package/docs/spec/ERRORS.md +76 -0
  148. package/docs/spec/ESCROW_NETTING_INVARIANTS.md +71 -0
  149. package/docs/spec/EvidenceIndex.v1.md +20 -0
  150. package/docs/spec/ExecutionIntent.v1.md +90 -0
  151. package/docs/spec/FinancePackBundleManifest.v1.md +24 -0
  152. package/docs/spec/FundingHold.v1.md +60 -0
  153. package/docs/spec/GovernancePolicy.v1.md +34 -0
  154. package/docs/spec/GovernancePolicy.v2.md +30 -0
  155. package/docs/spec/INVARIANTS.md +389 -0
  156. package/docs/spec/InteractionDirectionMatrix.v1.md +30 -0
  157. package/docs/spec/InvoiceBundleManifest.v1.md +24 -0
  158. package/docs/spec/InvoiceClaim.v1.md +11 -0
  159. package/docs/spec/MONEY_RAIL_STATE_MACHINE.md +58 -0
  160. package/docs/spec/MarketplaceAcceptance.v2.md +46 -0
  161. package/docs/spec/MarketplaceOffer.v2.md +54 -0
  162. package/docs/spec/MeteringReport.v1.md +18 -0
  163. package/docs/spec/OperatorAction.v1.md +90 -0
  164. package/docs/spec/PRODUCER_ERRORS.md +42 -0
  165. package/docs/spec/PolicyDecision.v1.md +83 -0
  166. package/docs/spec/PricingMatrix.v1.md +20 -0
  167. package/docs/spec/PricingMatrixSignatures.v1.md +30 -0
  168. package/docs/spec/PricingMatrixSignatures.v2.md +29 -0
  169. package/docs/spec/ProduceCliOutput.v1.md +46 -0
  170. package/docs/spec/ProofBundleManifest.v1.md +24 -0
  171. package/docs/spec/README.md +109 -0
  172. package/docs/spec/REFERENCE_IMPLEMENTATIONS.md +29 -0
  173. package/docs/spec/REFERENCE_VERIFIER_BEHAVIOR.md +68 -0
  174. package/docs/spec/REMOTE_SIGNER.md +66 -0
  175. package/docs/spec/ReleaseIndex.v1.md +32 -0
  176. package/docs/spec/ReleaseIndexSignatures.v1.md +17 -0
  177. package/docs/spec/ReleaseTrust.v1.md +13 -0
  178. package/docs/spec/ReleaseTrust.v2.md +26 -0
  179. package/docs/spec/RemoteSignerRequest.v1.md +21 -0
  180. package/docs/spec/RemoteSignerResponse.v1.md +16 -0
  181. package/docs/spec/ReputationEvent.v1.md +63 -0
  182. package/docs/spec/RevocationList.v1.md +28 -0
  183. package/docs/spec/SIGNER_PROVIDER_PLUGIN.md +32 -0
  184. package/docs/spec/STRICTNESS.md +68 -0
  185. package/docs/spec/SUPPLY_CHAIN.md +33 -0
  186. package/docs/spec/SettlementAdjustment.v1.md +45 -0
  187. package/docs/spec/SettlementDecisionRecord.v1.md +48 -0
  188. package/docs/spec/SettlementDecisionRecord.v2.md +53 -0
  189. package/docs/spec/SettlementDecisionReport.v1.md +44 -0
  190. package/docs/spec/SettlementKernel.v1.md +59 -0
  191. package/docs/spec/SettlementReceipt.v1.md +63 -0
  192. package/docs/spec/SlaDefinition.v1.md +24 -0
  193. package/docs/spec/SlaEvaluation.v1.md +12 -0
  194. package/docs/spec/THREAT_MODEL.md +113 -0
  195. package/docs/spec/TOOL_PROVENANCE.md +30 -0
  196. package/docs/spec/TRUST_ANCHORS.md +84 -0
  197. package/docs/spec/TenantSettings.v1.md +90 -0
  198. package/docs/spec/TenantSettings.v2.md +99 -0
  199. package/docs/spec/TimestampProof.v1.md +25 -0
  200. package/docs/spec/ToolCallAgreement.v1.md +34 -0
  201. package/docs/spec/ToolCallEvidence.v1.md +47 -0
  202. package/docs/spec/ToolManifest.v1.md +47 -0
  203. package/docs/spec/VERIFIER_ENVIRONMENT.md +38 -0
  204. package/docs/spec/VERSIONING.md +107 -0
  205. package/docs/spec/VerificationReport.v1.md +50 -0
  206. package/docs/spec/VerifyAboutOutput.v1.md +10 -0
  207. package/docs/spec/VerifyCliOutput.v1.md +28 -0
  208. package/docs/spec/WARNINGS.md +83 -0
  209. package/docs/spec/error-codes.v1.txt +285 -0
  210. package/docs/spec/examples/agreement_delegation_v1.example.json +21 -0
  211. package/docs/spec/examples/arbitration_case_v1.example.json +26 -0
  212. package/docs/spec/examples/arbitration_verdict_v1.example.json +32 -0
  213. package/docs/spec/examples/dispute_open_envelope_v1.example.json +18 -0
  214. package/docs/spec/examples/produce_cli_output_v1.example.json +32 -0
  215. package/docs/spec/examples/release_index_signature_v1.example.json +9 -0
  216. package/docs/spec/examples/release_index_signatures_v1.example.json +14 -0
  217. package/docs/spec/examples/release_index_v1.example.json +15 -0
  218. package/docs/spec/examples/release_trust_v1.example.json +7 -0
  219. package/docs/spec/examples/release_trust_v2.example.json +22 -0
  220. package/docs/spec/examples/remote_signer_request_v1.example.json +18 -0
  221. package/docs/spec/examples/remote_signer_response_v1.example.json +8 -0
  222. package/docs/spec/examples/reputation_event_v1.example.json +29 -0
  223. package/docs/spec/examples/verification_report_v1.example.json +24 -0
  224. package/docs/spec/examples/verify_about_output_v1.example.json +29 -0
  225. package/docs/spec/examples/verify_cli_output_v1.example.json +13 -0
  226. package/docs/spec/legacy/MarketplaceAcceptance.v1.md +48 -0
  227. package/docs/spec/legacy/MarketplaceOffer.v1.md +56 -0
  228. package/docs/spec/legacy/schemas/MarketplaceAcceptance.v1.schema.json +53 -0
  229. package/docs/spec/legacy/schemas/MarketplaceOffer.v1.schema.json +61 -0
  230. package/docs/spec/producer-error-codes.v1.txt +14 -0
  231. package/docs/spec/schemas/AcceptanceCriteria.v1.schema.json +24 -0
  232. package/docs/spec/schemas/AcceptanceEvaluation.v1.schema.json +26 -0
  233. package/docs/spec/schemas/AgentEvent.v1.schema.json +49 -0
  234. package/docs/spec/schemas/AgentIdentity.v1.schema.json +129 -0
  235. package/docs/spec/schemas/AgentPassport.v1.schema.json +112 -0
  236. package/docs/spec/schemas/AgentReputation.v1.schema.json +151 -0
  237. package/docs/spec/schemas/AgentReputation.v2.schema.json +120 -0
  238. package/docs/spec/schemas/AgentRun.v1.schema.json +71 -0
  239. package/docs/spec/schemas/AgentRunSettlement.v1.schema.json +75 -0
  240. package/docs/spec/schemas/AgentWallet.v1.schema.json +54 -0
  241. package/docs/spec/schemas/AgreementDelegation.v1.schema.json +50 -0
  242. package/docs/spec/schemas/ArbitrationCase.v1.schema.json +133 -0
  243. package/docs/spec/schemas/ArbitrationVerdict.v1.schema.json +149 -0
  244. package/docs/spec/schemas/BundleHeadAttestation.v1.schema.json +21 -0
  245. package/docs/spec/schemas/ClosePackManifest.v1.schema.json +38 -0
  246. package/docs/spec/schemas/DelegationGrant.v1.schema.json +102 -0
  247. package/docs/spec/schemas/DisputeOpenEnvelope.v1.schema.json +78 -0
  248. package/docs/spec/schemas/EvidenceIndex.v1.schema.json +41 -0
  249. package/docs/spec/schemas/ExecutionIntent.v1.schema.json +85 -0
  250. package/docs/spec/schemas/FinancePackBundleManifest.v1.schema.json +38 -0
  251. package/docs/spec/schemas/FundingHold.v1.schema.json +46 -0
  252. package/docs/spec/schemas/GovernancePolicy.v1.schema.json +45 -0
  253. package/docs/spec/schemas/GovernancePolicy.v2.schema.json +70 -0
  254. package/docs/spec/schemas/InteractionDirectionMatrix.v1.schema.json +43 -0
  255. package/docs/spec/schemas/InvoiceBundleManifest.v1.schema.json +38 -0
  256. package/docs/spec/schemas/InvoiceClaim.v1.schema.json +39 -0
  257. package/docs/spec/schemas/MarketplaceAcceptance.v2.schema.json +53 -0
  258. package/docs/spec/schemas/MarketplaceOffer.v2.schema.json +61 -0
  259. package/docs/spec/schemas/MeteringReport.v1.schema.json +45 -0
  260. package/docs/spec/schemas/OperatorAction.v1.schema.json +113 -0
  261. package/docs/spec/schemas/PolicyDecision.v1.schema.json +74 -0
  262. package/docs/spec/schemas/PricingMatrix.v1.schema.json +24 -0
  263. package/docs/spec/schemas/PricingMatrixSignatures.v1.schema.json +24 -0
  264. package/docs/spec/schemas/PricingMatrixSignatures.v2.schema.json +24 -0
  265. package/docs/spec/schemas/ProduceCliOutput.v1.schema.json +107 -0
  266. package/docs/spec/schemas/ProofBundleManifest.v1.schema.json +37 -0
  267. package/docs/spec/schemas/PublicKeys.v1.schema.json +33 -0
  268. package/docs/spec/schemas/ReleaseIndex.v1.schema.json +45 -0
  269. package/docs/spec/schemas/ReleaseIndexSignature.v1.schema.json +16 -0
  270. package/docs/spec/schemas/ReleaseIndexSignatures.v1.schema.json +16 -0
  271. package/docs/spec/schemas/ReleaseTrust.v1.schema.json +15 -0
  272. package/docs/spec/schemas/ReleaseTrust.v2.schema.json +37 -0
  273. package/docs/spec/schemas/RemoteSignerPublicKeyResponse.v1.schema.json +14 -0
  274. package/docs/spec/schemas/RemoteSignerRequest.v1.schema.json +24 -0
  275. package/docs/spec/schemas/RemoteSignerResponse.v1.schema.json +10 -0
  276. package/docs/spec/schemas/RemoteSignerSignRequest.v1.schema.json +27 -0
  277. package/docs/spec/schemas/RemoteSignerSignResponse.v1.schema.json +16 -0
  278. package/docs/spec/schemas/ReputationEvent.v1.schema.json +164 -0
  279. package/docs/spec/schemas/RevocationList.v1.schema.json +51 -0
  280. package/docs/spec/schemas/SettlementAdjustment.v1.schema.json +44 -0
  281. package/docs/spec/schemas/SettlementDecisionRecord.v1.schema.json +66 -0
  282. package/docs/spec/schemas/SettlementDecisionRecord.v2.schema.json +149 -0
  283. package/docs/spec/schemas/SettlementDecisionReport.v1.schema.json +61 -0
  284. package/docs/spec/schemas/SettlementReceipt.v1.schema.json +135 -0
  285. package/docs/spec/schemas/SlaDefinition.v1.schema.json +33 -0
  286. package/docs/spec/schemas/SlaEvaluation.v1.schema.json +26 -0
  287. package/docs/spec/schemas/TenantSettings.v1.schema.json +90 -0
  288. package/docs/spec/schemas/TenantSettings.v2.schema.json +161 -0
  289. package/docs/spec/schemas/TimestampProof.v1.schema.json +17 -0
  290. package/docs/spec/schemas/ToolCallAgreement.v1.schema.json +34 -0
  291. package/docs/spec/schemas/ToolCallEvidence.v1.schema.json +45 -0
  292. package/docs/spec/schemas/ToolManifest.v1.schema.json +54 -0
  293. package/docs/spec/schemas/VerificationReport.v1.schema.json +83 -0
  294. package/docs/spec/schemas/VerifyAboutOutput.v1.schema.json +54 -0
  295. package/docs/spec/schemas/VerifyCliOutput.v1.schema.json +75 -0
  296. package/docs/spec/schemas/VerifyReleaseOutput.v1.schema.json +47 -0
  297. package/docs/spec/x402-error-codes.v1.txt +35 -0
  298. package/docs/templates/buyer-email.txt +18 -0
  299. package/docs/templates/buyer-one-pager.md +24 -0
  300. package/package.json +53 -6
  301. package/scripts/acceptance/full-stack.mjs +734 -0
  302. package/scripts/acceptance/full-stack.sh +99 -0
  303. package/scripts/audit/build-audit-packet.mjs +242 -0
  304. package/scripts/backup-pg.sh +45 -0
  305. package/scripts/backup-restore/README.md +18 -0
  306. package/scripts/backup-restore/capture-state.mjs +130 -0
  307. package/scripts/backup-restore/client.mjs +97 -0
  308. package/scripts/backup-restore/seed-workload.mjs +235 -0
  309. package/scripts/backup-restore/verify-state.mjs +139 -0
  310. package/scripts/backup-restore-test.sh +217 -0
  311. package/scripts/chaos.js +221 -0
  312. package/scripts/ci/build-launch-cutover-packet.mjs +304 -0
  313. package/scripts/ci/build-self-serve-benchmark-report.mjs +122 -0
  314. package/scripts/ci/changelog-guard.mjs +145 -0
  315. package/scripts/ci/check-kernel-v0-launch-gate.mjs +233 -0
  316. package/scripts/ci/check-secret-hygiene.mjs +78 -0
  317. package/scripts/ci/check-version-consistency.mjs +42 -0
  318. package/scripts/ci/cli-pack-smoke.mjs +160 -0
  319. package/scripts/ci/flake-budget-guard.mjs +68 -0
  320. package/scripts/ci/generate-error-codes.mjs +54 -0
  321. package/scripts/ci/lib/lighthouse-tracker.mjs +90 -0
  322. package/scripts/ci/lib/self-serve-launch-gate.mjs +89 -0
  323. package/scripts/ci/npm-pack-smoke.mjs +454 -0
  324. package/scripts/ci/run-10x-throughput-drill.mjs +318 -0
  325. package/scripts/ci/run-10x-throughput-incident-rehearsal.mjs +368 -0
  326. package/scripts/ci/run-arbitration-workspace-browser-e2e.sh +22 -0
  327. package/scripts/ci/run-circle-sandbox-smoke.mjs +237 -0
  328. package/scripts/ci/run-go-live-gate.mjs +150 -0
  329. package/scripts/ci/run-kernel-v0-ship-gate.mjs +97 -0
  330. package/scripts/ci/run-mcp-host-cert-matrix.mjs +201 -0
  331. package/scripts/ci/run-mcp-host-smoke.mjs +473 -0
  332. package/scripts/ci/run-offline-verification-parity-gate.mjs +762 -0
  333. package/scripts/ci/run-onboarding-host-success-gate.mjs +516 -0
  334. package/scripts/ci/run-onboarding-policy-slo-gate.mjs +537 -0
  335. package/scripts/ci/run-production-cutover-gate.mjs +540 -0
  336. package/scripts/ci/run-public-openclaw-npx-smoke.mjs +148 -0
  337. package/scripts/ci/run-release-promotion-guard.mjs +756 -0
  338. package/scripts/ci/run-self-serve-launch-gate.mjs +56 -0
  339. package/scripts/ci/runtime-import-smoke.mjs +58 -0
  340. package/scripts/ci/update-lighthouse-tracker.mjs +112 -0
  341. package/scripts/closepack/lib.mjs +286 -0
  342. package/scripts/collect-debug.sh +263 -0
  343. package/scripts/demo/compositional-settlement-3hop.mjs +237 -0
  344. package/scripts/demo/delivery-robot/export-ui-fixture.mjs +188 -0
  345. package/scripts/demo/delivery-robot/generate.mjs +377 -0
  346. package/scripts/demo/kernel-agent-goes-shopping.mjs +202 -0
  347. package/scripts/demo/magic-link-first-green.mjs +118 -0
  348. package/scripts/demo/magic-link-kind-smoke.mjs +577 -0
  349. package/scripts/demo/mcp-paid-exa.mjs +1110 -0
  350. package/scripts/dev/billing-doctor.sh +145 -0
  351. package/scripts/dev/billing-smoke-prod.sh +219 -0
  352. package/scripts/dev/billing-webhook-replay.sh +161 -0
  353. package/scripts/dev/env.dev.example +29 -0
  354. package/scripts/dev/env.sh +37 -0
  355. package/scripts/dev/new-sdk-key.sh +81 -0
  356. package/scripts/dev/sdk-first-run.sh +21 -0
  357. package/scripts/dev/smoke-x402-gateway.sh +115 -0
  358. package/scripts/dev/start-api.sh +24 -0
  359. package/scripts/doctor/mcp-host.mjs +120 -0
  360. package/scripts/examples/produce-and-verify-jobproof.mjs +191 -0
  361. package/scripts/examples/sdk-first-paid-rfq.py +105 -0
  362. package/scripts/examples/sdk-first-verified-run.mjs +85 -0
  363. package/scripts/examples/sdk-first-verified-run.py +99 -0
  364. package/scripts/examples/sdk-tenant-analytics.mjs +103 -0
  365. package/scripts/examples/sdk-tenant-analytics.py +118 -0
  366. package/scripts/finance-pack/bundle.mjs +284 -0
  367. package/scripts/fixtures/generate-bundle-fixtures.mjs +877 -0
  368. package/scripts/governance/export.mjs +169 -0
  369. package/scripts/load/delivery-stress.k6.js +183 -0
  370. package/scripts/load/ingest-burst.k6.js +236 -0
  371. package/scripts/load/run-delivery-load.js +66 -0
  372. package/scripts/load/webhook-receiver.js +131 -0
  373. package/scripts/magic-link/migrate-run-records-to-db.mjs +35 -0
  374. package/scripts/mcp/probe.mjs +238 -0
  375. package/scripts/mcp/settld-mcp-http-gateway.mjs +178 -0
  376. package/scripts/mcp/settld-mcp-server.mjs +1511 -0
  377. package/scripts/openapi/write.mjs +13 -0
  378. package/scripts/ops/bootstrap-tenant-conformance.mjs +185 -0
  379. package/scripts/ops/build-x402-pilot-reliability-report.mjs +489 -0
  380. package/scripts/ops/check-x402-receipt-sample.mjs +181 -0
  381. package/scripts/ops/design-partner-run-packet.mjs +466 -0
  382. package/scripts/ops/dispute-finance-reconciliation-packet.mjs +313 -0
  383. package/scripts/ops/hosted-baseline-evidence.mjs +890 -0
  384. package/scripts/ops/money-rails-chargeback-evidence.mjs +509 -0
  385. package/scripts/ops/money-rails-reconcile-evidence.mjs +180 -0
  386. package/scripts/ops/p0-seed-money-rail-operation.mjs +432 -0
  387. package/scripts/ops/run-x402-hitl-smoke.mjs +607 -0
  388. package/scripts/pilot/finance-pack.mjs +495 -0
  389. package/scripts/pilot/fixtures/robot-keypair.json +4 -0
  390. package/scripts/pilot/fixtures/server-signer.json +4 -0
  391. package/scripts/policy/cli.mjs +600 -0
  392. package/scripts/profile/cli.mjs +1324 -0
  393. package/scripts/proof-bundle/job.mjs +109 -0
  394. package/scripts/proof-bundle/lib.mjs +92 -0
  395. package/scripts/proof-bundle/month.mjs +103 -0
  396. package/scripts/provider/conformance-run.mjs +159 -0
  397. package/scripts/provider/keys-generate.mjs +135 -0
  398. package/scripts/provider/publish.mjs +420 -0
  399. package/scripts/quickstart/x402.mjs +334 -0
  400. package/scripts/register-entity-secret.mjs +102 -0
  401. package/scripts/release/build-artifacts.mjs +181 -0
  402. package/scripts/release/generate-release-index.mjs +112 -0
  403. package/scripts/release/release-index-lib.mjs +232 -0
  404. package/scripts/release/sign-release-index.mjs +85 -0
  405. package/scripts/release/validate-release-assets.mjs +170 -0
  406. package/scripts/release/verify-release.mjs +261 -0
  407. package/scripts/restore-pg.sh +34 -0
  408. package/scripts/scaffold/create-settld-paid-tool.mjs +19 -0
  409. package/scripts/sdk/smoke-python.py +30 -0
  410. package/scripts/sdk/smoke.mjs +16 -0
  411. package/scripts/settlement/x402-batch-worker.mjs +1091 -0
  412. package/scripts/setup/circle-bootstrap.mjs +310 -0
  413. package/scripts/setup/host-config.mjs +617 -0
  414. package/scripts/setup/onboard.mjs +1337 -0
  415. package/scripts/setup/openclaw-onboard.mjs +423 -0
  416. package/scripts/setup/wizard.mjs +986 -0
  417. package/scripts/slo/check.mjs +239 -0
  418. package/scripts/smoke/k8s-smoke.mjs +214 -0
  419. package/scripts/spec/generate-protocol-vectors.mjs +1019 -0
  420. package/scripts/test/check-no-generated-artifacts.sh +12 -0
  421. package/scripts/test/run.sh +59 -0
  422. package/scripts/trust/validate-trust-file.mjs +57 -0
  423. package/scripts/trust-config/rotate-settld-pay.mjs +277 -0
  424. package/scripts/trust-config/wizard.mjs +161 -0
  425. package/scripts/vendor-contract-test-lib.mjs +182 -0
  426. package/scripts/vendor-contract-test.mjs +55 -0
  427. package/scripts/vercel/build-mkdocs.sh +9 -0
  428. package/scripts/vercel/ignore-mkdocs.sh +25 -0
  429. package/scripts/vercel/install-mkdocs.sh +6 -0
  430. package/scripts/verify-pg.js +217 -0
  431. package/scripts/x402/receipt-verify.mjs +289 -0
  432. package/services/finance-sink/src/dedupe-store.js +29 -6
  433. package/services/receiver/src/dedupe-store.js +29 -5
  434. package/services/x402-gateway/Dockerfile +13 -0
  435. package/services/x402-gateway/README.md +58 -0
  436. package/services/x402-gateway/examples/upstream-mock.js +337 -0
  437. package/services/x402-gateway/src/server.js +1058 -0
  438. package/src/api/app.js +34658 -16940
  439. package/src/api/maintenance.js +70 -0
  440. package/src/api/middleware/trust-kernel.js +114 -0
  441. package/src/api/openapi.js +1778 -70
  442. package/src/api/persistence.js +456 -0
  443. package/src/api/server.js +81 -5
  444. package/src/api/store.js +1581 -62
  445. package/src/api/workers/deliveries.js +99 -4
  446. package/src/api/workers/insolvency-sweep.js +159 -0
  447. package/src/core/agent-card.js +69 -0
  448. package/src/core/agent-wallets.js +231 -0
  449. package/src/core/agreement-delegation.js +549 -0
  450. package/src/core/billing-plans.js +40 -6
  451. package/src/core/circle-reserve-adapter.js +845 -0
  452. package/src/core/event-policy.js +21 -2
  453. package/src/core/maintenance-locks.js +1 -0
  454. package/src/core/operator-action.js +303 -0
  455. package/src/core/paid-tool-manifest.js +318 -0
  456. package/src/core/policy-decision.js +322 -0
  457. package/src/core/policy-packs.js +207 -0
  458. package/src/core/profile-fingerprint.js +27 -0
  459. package/src/core/profile-simulation-reasons.js +84 -0
  460. package/src/core/profile-templates.js +242 -0
  461. package/src/core/provider-publish-conformance.js +525 -0
  462. package/src/core/provider-publish-proof.js +396 -0
  463. package/src/core/provider-quote-signature.js +170 -0
  464. package/src/core/settld-keys.js +112 -0
  465. package/src/core/settld-pay-token.js +344 -0
  466. package/src/core/settlement-kernel.js +239 -2
  467. package/src/core/settlement-verifier.js +335 -0
  468. package/src/core/tool-call-agreement.js +112 -0
  469. package/src/core/tool-call-evidence.js +144 -0
  470. package/src/core/tool-provider-signature.js +98 -0
  471. package/src/core/wallet-assignment-resolver.js +129 -0
  472. package/src/core/wallet-provider-bootstrap.js +365 -0
  473. package/src/core/x402-escalation-override.js +258 -0
  474. package/src/core/x402-gate.js +118 -0
  475. package/src/core/x402-provider-refund-decision.js +220 -0
  476. package/src/core/x402-receipt-verifier.js +708 -0
  477. package/src/core/x402-reversal-command.js +251 -0
  478. package/src/core/x402-wallet-issuer-decision.js +252 -0
  479. package/src/core/zk-verifier.js +300 -0
  480. package/src/db/migrations/029_reputation_event_index.sql +54 -0
  481. package/src/db/migrations/030_artifacts_source_event_unique_job_only.sql +15 -0
  482. package/src/db/pg.js +18 -7
  483. package/src/db/store-pg.js +1508 -111
@@ -0,0 +1,112 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { spawnSync } from "node:child_process";
4
+
5
+ import { listFilesFlat, sha256FileHex, classifyArtifactKind, assertNoDuplicatePaths, writeCanonicalJsonFile } from "./release-index-lib.mjs";
6
+
7
+ function usage() {
8
+ // eslint-disable-next-line no-console
9
+ console.error(
10
+ "usage: node scripts/release/generate-release-index.mjs --dir <release-assets-dir> [--tag vX.Y.Z] [--version X.Y.Z] [--commit <sha>] [--out <path>]"
11
+ );
12
+ process.exit(2);
13
+ }
14
+
15
+ function parseArgs(argv) {
16
+ const out = { dir: null, tag: null, version: null, commit: null, outPath: null };
17
+ for (let i = 0; i < argv.length; i += 1) {
18
+ const a = argv[i];
19
+ if (a === "--dir") {
20
+ out.dir = String(argv[i + 1] ?? "");
21
+ i += 1;
22
+ continue;
23
+ }
24
+ if (a === "--tag") {
25
+ out.tag = String(argv[i + 1] ?? "");
26
+ i += 1;
27
+ continue;
28
+ }
29
+ if (a === "--version") {
30
+ out.version = String(argv[i + 1] ?? "");
31
+ i += 1;
32
+ continue;
33
+ }
34
+ if (a === "--commit") {
35
+ out.commit = String(argv[i + 1] ?? "");
36
+ i += 1;
37
+ continue;
38
+ }
39
+ if (a === "--out") {
40
+ out.outPath = String(argv[i + 1] ?? "");
41
+ i += 1;
42
+ continue;
43
+ }
44
+ if (a === "--help" || a === "-h") usage();
45
+ usage();
46
+ }
47
+ if (!out.dir) usage();
48
+ return out;
49
+ }
50
+
51
+ function gitCommit() {
52
+ const res = spawnSync("git", ["rev-parse", "HEAD"], { encoding: "utf8" });
53
+ if (res.status !== 0) return null;
54
+ return String(res.stdout ?? "").trim() || null;
55
+ }
56
+
57
+ function gitCommitEpochSeconds(commit) {
58
+ const sha = commit ?? "HEAD";
59
+ const res = spawnSync("git", ["show", "-s", "--format=%ct", sha], { encoding: "utf8" });
60
+ if (res.status !== 0) return null;
61
+ const raw = String(res.stdout ?? "").trim();
62
+ const n = Number.parseInt(raw, 10);
63
+ if (!Number.isInteger(n) || n < 0) return null;
64
+ return n;
65
+ }
66
+
67
+ async function main() {
68
+ const args = parseArgs(process.argv.slice(2));
69
+ const dir = path.resolve(process.cwd(), args.dir);
70
+ const outPath = args.outPath ? path.resolve(process.cwd(), args.outPath) : path.join(dir, "release_index_v1.json");
71
+
72
+ const commit = args.commit || process.env.GITHUB_SHA || process.env.SETTLD_COMMIT_SHA || gitCommit();
73
+ const epochEnv = process.env.SOURCE_DATE_EPOCH || process.env.SETTLD_RELEASE_EPOCH || null;
74
+ const buildEpochSeconds = epochEnv ? Number.parseInt(String(epochEnv), 10) : gitCommitEpochSeconds(commit);
75
+
76
+ const files = await listFilesFlat(dir);
77
+ const artifactNames = files
78
+ .filter((n) => !n.startsWith("."))
79
+ // Avoid circularity: never include ReleaseIndex itself or any sibling copies.
80
+ .filter((n) => !n.startsWith("release_index_v1"));
81
+
82
+ const artifacts = [];
83
+ for (const name of artifactNames) {
84
+ // eslint-disable-next-line no-await-in-loop
85
+ const st = await fs.stat(path.join(dir, name));
86
+ if (!st.isFile()) continue;
87
+ // eslint-disable-next-line no-await-in-loop
88
+ const sha256 = await sha256FileHex(path.join(dir, name));
89
+ artifacts.push({ path: name, sha256, sizeBytes: st.size, kind: classifyArtifactKind(name) });
90
+ }
91
+ artifacts.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
92
+ assertNoDuplicatePaths(artifacts);
93
+
94
+ const index = {
95
+ schemaVersion: "ReleaseIndex.v1",
96
+ release: {
97
+ tag: args.tag || process.env.GITHUB_REF_NAME || "unknown",
98
+ version: args.version || (args.tag ? String(args.tag).replace(/^v/, "") : process.env.SETTLD_VERSION || "unknown")
99
+ },
100
+ toolchain: {
101
+ commit: commit ?? null,
102
+ buildEpochSeconds: Number.isInteger(buildEpochSeconds) ? buildEpochSeconds : null,
103
+ canonicalJson: "RFC8785",
104
+ includedSchemas: ["VerifyCliOutput.v1", "ProduceCliOutput.v1", "ReleaseIndex.v1", "VerifyReleaseOutput.v1"]
105
+ },
106
+ artifacts
107
+ };
108
+
109
+ await writeCanonicalJsonFile(outPath, index);
110
+ }
111
+
112
+ await main();
@@ -0,0 +1,232 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+
5
+ import { canonicalJsonStringify } from "../../src/core/canonical-json.js";
6
+ import { keyIdFromPublicKeyPem } from "../../src/core/crypto.js";
7
+
8
+ export function sha256Hex(bytes) {
9
+ return crypto.createHash("sha256").update(bytes).digest("hex");
10
+ }
11
+
12
+ export async function sha256FileHex(fp) {
13
+ const h = crypto.createHash("sha256");
14
+ const f = await fs.open(fp, "r");
15
+ try {
16
+ const buf = Buffer.alloc(1024 * 1024);
17
+ while (true) {
18
+ // eslint-disable-next-line no-await-in-loop
19
+ const { bytesRead } = await f.read(buf, 0, buf.length, null);
20
+ if (bytesRead === 0) break;
21
+ h.update(buf.subarray(0, bytesRead));
22
+ }
23
+ } finally {
24
+ await f.close();
25
+ }
26
+ return h.digest("hex");
27
+ }
28
+
29
+ export async function listFilesFlat(dir) {
30
+ const entries = await fs.readdir(dir, { withFileTypes: true });
31
+ const out = [];
32
+ for (const e of entries) {
33
+ if (!e.isFile()) continue;
34
+ out.push(e.name);
35
+ }
36
+ return out.sort();
37
+ }
38
+
39
+ export function canonicalIndexBytes(indexJson) {
40
+ const canonical = canonicalJsonStringify(indexJson);
41
+ return Buffer.from(canonical, "utf8");
42
+ }
43
+
44
+ export function indexMessageSha256Hex(indexJson) {
45
+ return sha256Hex(canonicalIndexBytes(indexJson));
46
+ }
47
+
48
+ export function signIndex({ indexJson, privateKeyPem }) {
49
+ const messageSha256 = indexMessageSha256Hex(indexJson);
50
+ const messageBytes = Buffer.from(messageSha256, "hex");
51
+ const sig = crypto.sign(null, messageBytes, privateKeyPem).toString("base64");
52
+
53
+ const pub = crypto.createPublicKey(crypto.createPrivateKey(privateKeyPem)).export({ type: "spki", format: "pem" });
54
+ const publicKeyPem = String(pub);
55
+ const keyId = keyIdFromPublicKeyPem(publicKeyPem);
56
+
57
+ return {
58
+ schemaVersion: "ReleaseIndexSignature.v1",
59
+ algorithm: "ed25519-sha256",
60
+ keyId,
61
+ messageSha256,
62
+ publicKeyPem,
63
+ signatureBase64: sig
64
+ };
65
+ }
66
+
67
+ export function wrapSignaturesV1(signatures) {
68
+ const list = Array.isArray(signatures) ? signatures.filter(Boolean) : [];
69
+ return {
70
+ schemaVersion: "ReleaseIndexSignatures.v1",
71
+ signatures: list
72
+ };
73
+ }
74
+
75
+ export function unwrapSignaturesV1(sigJson) {
76
+ if (sigJson && typeof sigJson === "object" && !Array.isArray(sigJson)) {
77
+ if (sigJson.schemaVersion === "ReleaseIndexSignature.v1") return [sigJson];
78
+ if (sigJson.schemaVersion === "ReleaseIndexSignatures.v1") {
79
+ const arr = Array.isArray(sigJson.signatures) ? sigJson.signatures : [];
80
+ return arr.filter(Boolean);
81
+ }
82
+ }
83
+ return [];
84
+ }
85
+
86
+ export function verifyIndexSignature({ indexJson, signatureJson, trustedPublicKeyPem = null }) {
87
+ const errors = [];
88
+ const messageSha256 = indexMessageSha256Hex(indexJson);
89
+
90
+ if (!signatureJson || typeof signatureJson !== "object") {
91
+ errors.push({ code: "SIGNATURE_INVALID", message: "signature JSON missing/invalid", path: null });
92
+ return { ok: false, messageSha256, errors };
93
+ }
94
+ if (signatureJson.schemaVersion !== "ReleaseIndexSignature.v1") {
95
+ errors.push({ code: "SIGNATURE_INVALID", message: "unexpected signature schemaVersion", path: null });
96
+ return { ok: false, messageSha256, errors };
97
+ }
98
+ if (signatureJson.algorithm !== "ed25519-sha256") {
99
+ errors.push({ code: "SIGNATURE_UNSUPPORTED_ALGORITHM", message: "unsupported signature algorithm", path: null });
100
+ return { ok: false, messageSha256, errors };
101
+ }
102
+ if (typeof signatureJson.signatureBase64 !== "string" || !signatureJson.signatureBase64.trim()) {
103
+ errors.push({ code: "SIGNATURE_INVALID", message: "signatureBase64 missing", path: null });
104
+ return { ok: false, messageSha256, errors };
105
+ }
106
+
107
+ const publicKeyPem = trustedPublicKeyPem ? String(trustedPublicKeyPem) : String(signatureJson.publicKeyPem ?? "");
108
+ if (!publicKeyPem.trim()) {
109
+ errors.push({ code: "SIGNATURE_INVALID", message: "publicKeyPem missing", path: null });
110
+ return { ok: false, messageSha256, errors };
111
+ }
112
+
113
+ if (typeof signatureJson.messageSha256 === "string" && signatureJson.messageSha256.toLowerCase() !== messageSha256) {
114
+ errors.push({ code: "SIGNATURE_MISMATCH", message: "messageSha256 mismatch", path: null });
115
+ return { ok: false, messageSha256, errors };
116
+ }
117
+
118
+ try {
119
+ const ok = crypto.verify(
120
+ null,
121
+ Buffer.from(messageSha256, "hex"),
122
+ publicKeyPem,
123
+ Buffer.from(String(signatureJson.signatureBase64), "base64")
124
+ );
125
+ if (!ok) errors.push({ code: "SIGNATURE_INVALID", message: "signature verification failed", path: null });
126
+ } catch (e) {
127
+ errors.push({ code: "SIGNATURE_INVALID", message: `signature verification error: ${e?.message ?? String(e)}`, path: null });
128
+ }
129
+
130
+ return { ok: errors.length === 0, messageSha256, errors };
131
+ }
132
+
133
+ export function normalizeReleaseTrust(trustJson) {
134
+ if (!trustJson || typeof trustJson !== "object" || Array.isArray(trustJson)) {
135
+ throw new Error("release trust JSON missing/invalid");
136
+ }
137
+
138
+ if (trustJson.schemaVersion === "ReleaseTrust.v1") {
139
+ const roots = trustJson.releaseRoots ?? null;
140
+ if (!roots || typeof roots !== "object" || Array.isArray(roots)) throw new Error("ReleaseTrust.v1.releaseRoots missing/invalid");
141
+ const keys = [];
142
+ for (const [keyId, publicKeyPem] of Object.entries(roots)) {
143
+ if (typeof keyId !== "string" || !keyId.trim()) continue;
144
+ if (typeof publicKeyPem !== "string" || !publicKeyPem.trim()) continue;
145
+ keys.push({ keyId, publicKeyPem });
146
+ }
147
+ keys.sort((a, b) => (a.keyId < b.keyId ? -1 : a.keyId > b.keyId ? 1 : 0));
148
+ return { schemaVersion: "ReleaseTrust.v1", policy: { minSignatures: 1, requiredKeyIds: null }, keys };
149
+ }
150
+
151
+ if (trustJson.schemaVersion === "ReleaseTrust.v2") {
152
+ const policy = trustJson.policy ?? null;
153
+ if (!policy || typeof policy !== "object" || Array.isArray(policy)) throw new Error("ReleaseTrust.v2.policy missing/invalid");
154
+ const minSignatures = policy.minSignatures;
155
+ if (!Number.isInteger(minSignatures) || minSignatures < 1) throw new Error("ReleaseTrust.v2.policy.minSignatures missing/invalid");
156
+ const requiredKeyIds = Array.isArray(policy.requiredKeyIds)
157
+ ? policy.requiredKeyIds.filter((v) => typeof v === "string" && v.trim())
158
+ : null;
159
+
160
+ const arr = Array.isArray(trustJson.keys) ? trustJson.keys : null;
161
+ if (!arr) throw new Error("ReleaseTrust.v2.keys missing/invalid");
162
+ const keys = [];
163
+ for (const item of arr) {
164
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
165
+ const keyId = typeof item.keyId === "string" && item.keyId.trim() ? item.keyId.trim() : null;
166
+ const publicKeyPem = typeof item.publicKeyPem === "string" && item.publicKeyPem.trim() ? item.publicKeyPem : null;
167
+ if (!keyId || !publicKeyPem) continue;
168
+
169
+ const derived = keyIdFromPublicKeyPem(publicKeyPem);
170
+ if (derived !== keyId) throw new Error(`ReleaseTrust.v2 keyId mismatch: declared=${keyId} derived=${derived}`);
171
+
172
+ const notBeforeEpochSeconds = Number.isInteger(item.notBeforeEpochSeconds) && item.notBeforeEpochSeconds >= 0 ? item.notBeforeEpochSeconds : null;
173
+ const notAfterEpochSeconds = Number.isInteger(item.notAfterEpochSeconds) && item.notAfterEpochSeconds >= 0 ? item.notAfterEpochSeconds : null;
174
+ const revokedAtEpochSeconds = Number.isInteger(item.revokedAtEpochSeconds) && item.revokedAtEpochSeconds >= 0 ? item.revokedAtEpochSeconds : null;
175
+ const comment = typeof item.comment === "string" && item.comment.trim() ? item.comment : null;
176
+
177
+ keys.push({ keyId, publicKeyPem, notBeforeEpochSeconds, notAfterEpochSeconds, revokedAtEpochSeconds, comment });
178
+ }
179
+ keys.sort((a, b) => (a.keyId < b.keyId ? -1 : a.keyId > b.keyId ? 1 : 0));
180
+ return { schemaVersion: "ReleaseTrust.v2", policy: { minSignatures, requiredKeyIds }, keys };
181
+ }
182
+
183
+ throw new Error("release trust schemaVersion must be ReleaseTrust.v1 or ReleaseTrust.v2");
184
+ }
185
+
186
+ export async function loadReleaseTrustPublicKeyPem({ trustPath, keyId }) {
187
+ const raw = await fs.readFile(trustPath, "utf8");
188
+ const trust = normalizeReleaseTrust(JSON.parse(raw));
189
+ const pem = trust.keys.find((k) => k.keyId === keyId)?.publicKeyPem ?? null;
190
+ if (typeof pem !== "string" || !pem.trim()) throw new Error(`release trust missing keyId: ${keyId}`);
191
+ return String(pem);
192
+ }
193
+
194
+ export async function loadReleaseTrust({ trustPath }) {
195
+ const raw = await fs.readFile(trustPath, "utf8");
196
+ return normalizeReleaseTrust(JSON.parse(raw));
197
+ }
198
+
199
+ export function classifyArtifactKind(name) {
200
+ if (/^settld-[a-z0-9-]+-\d+\.\d+\.\d+.*\.tgz$/i.test(name)) return "npm-tgz";
201
+ if (/^settld-\d+\.\d+\.\d+.*\.tgz$/i.test(name)) return "helm-chart-tgz";
202
+ if (name.endsWith(".whl")) return "python-wheel";
203
+ if (/^settld_api_sdk_python-.*\.tar\.gz$/i.test(name)) return "python-sdist";
204
+ if (name.endsWith(".tgz")) return "tgz";
205
+ if (name.endsWith(".tar.gz")) return "tar.gz";
206
+ if (name.endsWith(".zip")) return "zip";
207
+ if (name.endsWith("SHA256SUMS") || name.endsWith(".sha256")) return "checksum";
208
+ if (name.endsWith(".spdx.json")) return "sbom";
209
+ return null;
210
+ }
211
+
212
+ export function assertNoDuplicatePaths(artifacts) {
213
+ const seen = new Set();
214
+ for (const a of artifacts) {
215
+ const p = String(a?.path ?? "");
216
+ if (!p) continue;
217
+ if (seen.has(p)) throw new Error(`duplicate artifact path: ${p}`);
218
+ seen.add(p);
219
+ }
220
+ }
221
+
222
+ export async function writeCanonicalJsonFile(fp, json) {
223
+ await fs.writeFile(fp, canonicalJsonStringify(json) + "\n", "utf8");
224
+ }
225
+
226
+ export function cmpString(a, b) {
227
+ const aa = String(a ?? "");
228
+ const bb = String(b ?? "");
229
+ if (aa < bb) return -1;
230
+ if (aa > bb) return 1;
231
+ return 0;
232
+ }
@@ -0,0 +1,85 @@
1
+ import fs from "node:fs/promises";
2
+ import fsSync from "node:fs";
3
+ import path from "node:path";
4
+
5
+ import { signIndex, unwrapSignaturesV1, wrapSignaturesV1, cmpString, writeCanonicalJsonFile } from "./release-index-lib.mjs";
6
+
7
+ function usage() {
8
+ // eslint-disable-next-line no-console
9
+ console.error(
10
+ "usage: node scripts/release/sign-release-index.mjs --index <release_index_v1.json> [--out <release_index_v1.sig>] [--append] (--private-key-env <ENV>|--private-key-file <path>)"
11
+ );
12
+ process.exit(2);
13
+ }
14
+
15
+ function parseArgs(argv) {
16
+ const out = { indexPath: null, outPath: null, privateKeyEnv: null, privateKeyFile: null, append: false };
17
+ for (let i = 0; i < argv.length; i += 1) {
18
+ const a = argv[i];
19
+ if (a === "--index") {
20
+ out.indexPath = String(argv[i + 1] ?? "");
21
+ i += 1;
22
+ continue;
23
+ }
24
+ if (a === "--out") {
25
+ out.outPath = String(argv[i + 1] ?? "");
26
+ i += 1;
27
+ continue;
28
+ }
29
+ if (a === "--private-key-env") {
30
+ out.privateKeyEnv = String(argv[i + 1] ?? "");
31
+ i += 1;
32
+ continue;
33
+ }
34
+ if (a === "--private-key-file") {
35
+ out.privateKeyFile = String(argv[i + 1] ?? "");
36
+ i += 1;
37
+ continue;
38
+ }
39
+ if (a === "--append") {
40
+ out.append = true;
41
+ continue;
42
+ }
43
+ if (a === "--help" || a === "-h") usage();
44
+ usage();
45
+ }
46
+ if (!out.indexPath) usage();
47
+ if (!out.privateKeyEnv && !out.privateKeyFile) usage();
48
+ return out;
49
+ }
50
+
51
+ async function main() {
52
+ const args = parseArgs(process.argv.slice(2));
53
+ const indexPath = path.resolve(process.cwd(), args.indexPath);
54
+ const outPath = args.outPath
55
+ ? path.resolve(process.cwd(), args.outPath)
56
+ : path.join(path.dirname(indexPath), "release_index_v1.sig");
57
+
58
+ const privateKeyPem = args.privateKeyFile
59
+ ? await fs.readFile(path.resolve(process.cwd(), args.privateKeyFile), "utf8")
60
+ : process.env[String(args.privateKeyEnv)] ?? "";
61
+ if (!String(privateKeyPem ?? "").trim()) throw new Error("missing release signing private key (env/file)");
62
+
63
+ const indexJson = JSON.parse(await fs.readFile(indexPath, "utf8"));
64
+ const sig = signIndex({ indexJson, privateKeyPem: String(privateKeyPem) });
65
+
66
+ let signatures = [sig];
67
+ if (args.append && fsSync.existsSync(outPath)) {
68
+ const existing = JSON.parse(await fs.readFile(outPath, "utf8"));
69
+ signatures = [...unwrapSignaturesV1(existing), sig];
70
+ }
71
+
72
+ const byKeyId = new Map();
73
+ for (const s of signatures) {
74
+ const keyId = typeof s?.keyId === "string" && s.keyId.trim() ? s.keyId.trim() : null;
75
+ if (!keyId) continue;
76
+ byKeyId.set(keyId, s);
77
+ }
78
+ const merged = Array.from(byKeyId.values());
79
+ merged.sort((a, b) => cmpString(a?.keyId ?? "", b?.keyId ?? ""));
80
+ const out = wrapSignaturesV1(merged);
81
+
82
+ await writeCanonicalJsonFile(outPath, out);
83
+ }
84
+
85
+ await main();
@@ -0,0 +1,170 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+
6
+ function usage() {
7
+ // eslint-disable-next-line no-console
8
+ console.error(
9
+ "usage: node scripts/release/validate-release-assets.mjs --dir <release-assets-dir> [--release-trust <ReleaseTrust.v1.json>]"
10
+ );
11
+ process.exit(2);
12
+ }
13
+
14
+ function parseArgs(argv) {
15
+ let dir = null;
16
+ let releaseTrust = null;
17
+ for (let i = 0; i < argv.length; i += 1) {
18
+ const a = argv[i];
19
+ if (a === "--dir") {
20
+ dir = String(argv[i + 1] ?? "");
21
+ i += 1;
22
+ continue;
23
+ }
24
+ if (a === "--release-trust") {
25
+ releaseTrust = String(argv[i + 1] ?? "");
26
+ i += 1;
27
+ continue;
28
+ }
29
+ if (a === "--help" || a === "-h") usage();
30
+ usage();
31
+ }
32
+ if (!dir) usage();
33
+ return { dir, releaseTrust };
34
+ }
35
+
36
+ function sha256Hex(buf) {
37
+ return crypto.createHash("sha256").update(buf).digest("hex");
38
+ }
39
+
40
+ async function fileExists(fp) {
41
+ try {
42
+ await fs.stat(fp);
43
+ return true;
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+
49
+ function parseSha256sumFile(text) {
50
+ // sha256sum format: "<hex> <filename>"
51
+ const out = new Map();
52
+ for (const line of String(text ?? "").split("\n")) {
53
+ const trimmed = line.trim();
54
+ if (!trimmed) continue;
55
+ const m = trimmed.match(/^([0-9a-f]{64})\s+(\S+)$/i);
56
+ if (!m) throw new Error(`invalid sha256sum line: ${JSON.stringify(line)}`);
57
+ const hex = m[1].toLowerCase();
58
+ const name = m[2];
59
+ out.set(name, hex);
60
+ }
61
+ return out;
62
+ }
63
+
64
+ function sh(cmd, args, { cwd } = {}) {
65
+ const res = spawnSync(cmd, args, { cwd, encoding: "utf8" });
66
+ if (res.status !== 0) {
67
+ throw new Error(`${cmd} ${args.join(" ")} failed (exit ${res.status})${res.stderr ? `: ${res.stderr.trim()}` : ""}`);
68
+ }
69
+ return String(res.stdout ?? "");
70
+ }
71
+
72
+ async function assertFileSha256({ dir, checksumFile, targetName }) {
73
+ const fp = path.join(dir, checksumFile);
74
+ const raw = await fs.readFile(fp, "utf8");
75
+ const map = parseSha256sumFile(raw);
76
+ if (!map.has(targetName)) throw new Error(`${checksumFile} missing entry for ${targetName}`);
77
+ const expected = map.get(targetName);
78
+ const actual = sha256Hex(await fs.readFile(path.join(dir, targetName)));
79
+ if (expected !== actual) throw new Error(`${targetName} sha256 mismatch expected=${expected} actual=${actual}`);
80
+ }
81
+
82
+ async function main() {
83
+ const { dir, releaseTrust } = parseArgs(process.argv.slice(2));
84
+
85
+ const required = [
86
+ "conformance-v1.tar.gz",
87
+ "conformance-v1-SHA256SUMS",
88
+ "release_index_v1.json",
89
+ "release_index_v1.sig",
90
+ "settld-audit-packet-v1.zip",
91
+ "settld-audit-packet-v1.zip.sha256",
92
+ "npm-SHA256SUMS",
93
+ "python-SHA256SUMS"
94
+ ];
95
+ for (const name of required) {
96
+ // eslint-disable-next-line no-await-in-loop
97
+ if (!(await fileExists(path.join(dir, name)))) throw new Error(`missing required release asset: ${name}`);
98
+ }
99
+
100
+ // Validate conformance checksum
101
+ await assertFileSha256({ dir, checksumFile: "conformance-v1-SHA256SUMS", targetName: "conformance-v1.tar.gz" });
102
+
103
+ // Validate audit packet checksum
104
+ await assertFileSha256({ dir, checksumFile: "settld-audit-packet-v1.zip.sha256", targetName: "settld-audit-packet-v1.zip" });
105
+
106
+ // Validate npm tgz checksums based on npm-SHA256SUMS entries.
107
+ const npmSumRaw = await fs.readFile(path.join(dir, "npm-SHA256SUMS"), "utf8");
108
+ const npmMap = parseSha256sumFile(npmSumRaw);
109
+ const npmNames = Array.from(npmMap.keys()).sort();
110
+ if (!npmNames.length) throw new Error("npm-SHA256SUMS has no entries");
111
+ for (const name of npmNames) {
112
+ if (!name.endsWith(".tgz")) throw new Error(`npm-SHA256SUMS contains non-tgz entry: ${name}`);
113
+ // eslint-disable-next-line no-await-in-loop
114
+ if (!(await fileExists(path.join(dir, name)))) throw new Error(`missing npm tarball listed in npm-SHA256SUMS: ${name}`);
115
+ // eslint-disable-next-line no-await-in-loop
116
+ const actual = sha256Hex(await fs.readFile(path.join(dir, name)));
117
+ const expected = npmMap.get(name);
118
+ if (expected !== actual) throw new Error(`${name} sha256 mismatch expected=${expected} actual=${actual}`);
119
+ }
120
+
121
+ // Validate Python distribution checksums.
122
+ const pythonSumRaw = await fs.readFile(path.join(dir, "python-SHA256SUMS"), "utf8");
123
+ const pythonMap = parseSha256sumFile(pythonSumRaw);
124
+ const pythonNames = Array.from(pythonMap.keys()).sort();
125
+ if (!pythonNames.length) throw new Error("python-SHA256SUMS has no entries");
126
+ const hasWheel = pythonNames.some((name) => name.endsWith(".whl"));
127
+ const hasSdist = pythonNames.some((name) => name.endsWith(".tar.gz"));
128
+ if (!hasWheel || !hasSdist) throw new Error("python-SHA256SUMS must include both .whl and .tar.gz artifacts");
129
+ for (const name of pythonNames) {
130
+ if (!(name.endsWith(".whl") || name.endsWith(".tar.gz"))) {
131
+ throw new Error(`python-SHA256SUMS contains unsupported artifact type: ${name}`);
132
+ }
133
+ // eslint-disable-next-line no-await-in-loop
134
+ if (!(await fileExists(path.join(dir, name)))) throw new Error(`missing python artifact listed in python-SHA256SUMS: ${name}`);
135
+ // eslint-disable-next-line no-await-in-loop
136
+ const actual = sha256Hex(await fs.readFile(path.join(dir, name)));
137
+ const expected = pythonMap.get(name);
138
+ if (expected !== actual) throw new Error(`${name} sha256 mismatch expected=${expected} actual=${actual}`);
139
+ }
140
+
141
+ // Light sanity check of archive contents (avoid surprises).
142
+ const conformanceListing = sh("tar", ["-tzf", "conformance-v1.tar.gz"], { cwd: dir });
143
+ for (const must of ["conformance-v1/README.md", "conformance-v1/cases.json", "conformance-v1/expected/"]) {
144
+ if (!conformanceListing.includes(must)) throw new Error(`conformance-v1.tar.gz missing expected entry: ${must}`);
145
+ }
146
+ const auditListing = sh("unzip", ["-l", "settld-audit-packet-v1.zip"], { cwd: dir });
147
+ const auditExpectedEntries = [
148
+ // Current audit packet layout (scripts/audit/build-audit-packet.mjs)
149
+ "spec/THREAT_MODEL.md",
150
+ "conformance/conformance-v1.tar.gz",
151
+ "conformance/conformance-v1-SHA256SUMS",
152
+ "protocol-vectors/v1.json",
153
+ "tool.json",
154
+ "SHA256SUMS"
155
+ ];
156
+ for (const must of auditExpectedEntries) {
157
+ if (!auditListing.includes(must)) throw new Error(`settld-audit-packet-v1.zip missing expected entry: ${must}`);
158
+ }
159
+
160
+ // Verify signed ReleaseIndex and ensure artifacts match its hashes.
161
+ const verifyArgs = ["scripts/release/verify-release.mjs", "--dir", dir, "--format", "json"];
162
+ if (releaseTrust) verifyArgs.push("--trust", releaseTrust);
163
+ const verifyRes = spawnSync(process.execPath, verifyArgs, { encoding: "utf8" });
164
+ if (verifyRes.status !== 0) {
165
+ const msg = (verifyRes.stdout || verifyRes.stderr || "").trim();
166
+ throw new Error(`verify-release failed${msg ? `: ${msg}` : ""}`);
167
+ }
168
+ }
169
+
170
+ await main();