rcf-lite 0.23.0 → 0.24.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 (474) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/blueprints/application-account-settings/docs/topics.md +7 -1
  3. package/blueprints/application-admin-console/CHANGELOG.md +12 -0
  4. package/blueprints/application-admin-console/blueprint.json +34 -1
  5. package/blueprints/application-admin-console/contributions/adrs/adr-2214-application-admin-console-consume-zero-trust-gate.json +25 -0
  6. package/blueprints/application-admin-console/contributions/requirements/application-admin-console-req-014.json +17 -0
  7. package/blueprints/application-admin-console/contributions/tacs/tac-2214-application-admin-console-access-gated-signin-surface.json +32 -0
  8. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21815.json +27 -0
  9. package/blueprints/application-admin-console/contributions/user-stories/application-admin-console-us-21816.json +27 -0
  10. package/blueprints/application-admin-console/docs/topics.md +7 -1
  11. package/blueprints/application-admin-console/guide/application-admin-console.md +24 -0
  12. package/blueprints/application-admin-console/probe-packs/application-admin-console.pack.mjs +26 -1
  13. package/blueprints/application-api-rest/docs/topics.md +7 -1
  14. package/blueprints/application-charts/docs/topics.md +7 -1
  15. package/blueprints/application-dashboard/docs/topics.md +7 -1
  16. package/blueprints/application-datatable/docs/topics.md +7 -1
  17. package/blueprints/application-empty-error-states/docs/topics.md +7 -1
  18. package/blueprints/application-error-handling/docs/topics.md +7 -1
  19. package/blueprints/application-file-upload/docs/topics.md +7 -1
  20. package/blueprints/application-forms-wizard/docs/topics.md +7 -1
  21. package/blueprints/application-notifications-in-app/docs/topics.md +7 -1
  22. package/blueprints/application-onboarding-tour/docs/topics.md +7 -1
  23. package/blueprints/application-spa/docs/topics.md +7 -1
  24. package/blueprints/delivery-ci-workflows/docs/topics.md +7 -1
  25. package/blueprints/deploy-cloudflare-workers/docs/topics.md +7 -1
  26. package/blueprints/edge-cloudflare-access/CHANGELOG.md +23 -0
  27. package/blueprints/edge-cloudflare-access/README.md +141 -0
  28. package/blueprints/edge-cloudflare-access/blueprint.json +197 -0
  29. package/blueprints/edge-cloudflare-access/contributions/adrs/adr-3501-edge-cloudflare-access-jwt-gate.json +14 -0
  30. package/blueprints/edge-cloudflare-access/contributions/adrs/adr-3502-edge-cloudflare-access-identity-provider.json +25 -0
  31. package/blueprints/edge-cloudflare-access/contributions/adrs/adr-3503-edge-cloudflare-access-policy-scope.json +12 -0
  32. package/blueprints/edge-cloudflare-access/contributions/adrs/adr-3504-edge-cloudflare-access-audit-retention.json +12 -0
  33. package/blueprints/edge-cloudflare-access/contributions/probes/admin-console-gate-surface.mjs +100 -0
  34. package/blueprints/edge-cloudflare-access/contributions/probes/audit-event-secrecy.mjs +70 -0
  35. package/blueprints/edge-cloudflare-access/contributions/probes/jwt-validator-fixture.mjs +63 -0
  36. package/blueprints/edge-cloudflare-access/contributions/probes/jwt-validator-reject.mjs +95 -0
  37. package/blueprints/edge-cloudflare-access/contributions/probes/probe-utils.mjs +90 -0
  38. package/blueprints/edge-cloudflare-access/contributions/probes/real-account-gated-url.mjs +65 -0
  39. package/blueprints/edge-cloudflare-access/contributions/probes/run-admin-console-gate-surface.mjs +5 -0
  40. package/blueprints/edge-cloudflare-access/contributions/probes/run-audit-event-secrecy.mjs +5 -0
  41. package/blueprints/edge-cloudflare-access/contributions/probes/run-jwt-validator-fixture.mjs +5 -0
  42. package/blueprints/edge-cloudflare-access/contributions/probes/run-jwt-validator-reject.mjs +5 -0
  43. package/blueprints/edge-cloudflare-access/contributions/probes/run-real-account-gated-url.mjs +5 -0
  44. package/blueprints/edge-cloudflare-access/contributions/probes/run-wrangler-seam.mjs +5 -0
  45. package/blueprints/edge-cloudflare-access/contributions/probes/wrangler-seam.mjs +203 -0
  46. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-001.json +17 -0
  47. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-002.json +17 -0
  48. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-003.json +17 -0
  49. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-004.json +17 -0
  50. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-005.json +17 -0
  51. package/blueprints/edge-cloudflare-access/contributions/requirements/edge-cloudflare-access-req-006.json +18 -0
  52. package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3501-edge-cloudflare-access-jwt-validator.json +31 -0
  53. package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3502-edge-cloudflare-access-application-declaration.json +33 -0
  54. package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3503-edge-cloudflare-access-policy-shape.json +25 -0
  55. package/blueprints/edge-cloudflare-access/contributions/tacs/tac-3504-edge-cloudflare-access-audit-sink.json +25 -0
  56. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34101.json +27 -0
  57. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34102.json +28 -0
  58. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34103.json +27 -0
  59. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34104.json +27 -0
  60. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34105.json +27 -0
  61. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34106.json +27 -0
  62. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34107.json +27 -0
  63. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34108.json +27 -0
  64. package/blueprints/edge-cloudflare-access/contributions/user-stories/edge-cloudflare-access-us-34109.json +27 -0
  65. package/blueprints/edge-cloudflare-access/docs/topics.md +68 -0
  66. package/blueprints/edge-cloudflare-access/guide/edge-cloudflare-access.md +180 -0
  67. package/blueprints/edge-cloudflare-rate-limiting/CHANGELOG.md +10 -0
  68. package/blueprints/edge-cloudflare-rate-limiting/README.md +73 -0
  69. package/blueprints/edge-cloudflare-rate-limiting/blueprint.json +174 -0
  70. package/blueprints/edge-cloudflare-rate-limiting/contributions/adrs/adr-3701-edge-cloudflare-rate-limiting-throttle-contract.json +14 -0
  71. package/blueprints/edge-cloudflare-rate-limiting/contributions/adrs/adr-3702-edge-cloudflare-rate-limiting-layering.json +14 -0
  72. package/blueprints/edge-cloudflare-rate-limiting/contributions/adrs/adr-3703-edge-cloudflare-rate-limiting-manifest-shape.json +14 -0
  73. package/blueprints/edge-cloudflare-rate-limiting/contributions/adrs/adr-3704-edge-cloudflare-rate-limiting-drift-audit-cadence.json +14 -0
  74. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/event-secrecy.mjs +104 -0
  75. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/manifest-presence.mjs +95 -0
  76. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/manifest-schema-validate.mjs +130 -0
  77. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/probe-utils.mjs +111 -0
  78. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/real-account-burst-and-429.mjs +104 -0
  79. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/run-event-secrecy.mjs +5 -0
  80. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/run-manifest-presence.mjs +5 -0
  81. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/run-manifest-schema-validate.mjs +5 -0
  82. package/blueprints/edge-cloudflare-rate-limiting/contributions/probes/run-real-account-burst-and-429.mjs +5 -0
  83. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-001.json +17 -0
  84. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-002.json +17 -0
  85. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-003.json +17 -0
  86. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-004.json +17 -0
  87. package/blueprints/edge-cloudflare-rate-limiting/contributions/requirements/edge-cloudflare-rate-limiting-req-005.json +17 -0
  88. package/blueprints/edge-cloudflare-rate-limiting/contributions/schemas/rate-limit-rule.schema.json +67 -0
  89. package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3701-edge-cloudflare-rate-limiting-manifest-schema.json +31 -0
  90. package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3702-edge-cloudflare-rate-limiting-management-surface-doc.json +25 -0
  91. package/blueprints/edge-cloudflare-rate-limiting/contributions/tacs/tac-3703-edge-cloudflare-rate-limiting-drift-audit-runner.json +26 -0
  92. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36101.json +27 -0
  93. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36102.json +27 -0
  94. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36103.json +27 -0
  95. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36104.json +27 -0
  96. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36105.json +27 -0
  97. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36106.json +27 -0
  98. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36107.json +27 -0
  99. package/blueprints/edge-cloudflare-rate-limiting/contributions/user-stories/edge-cloudflare-rate-limiting-us-36108.json +27 -0
  100. package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +68 -0
  101. package/blueprints/edge-cloudflare-rate-limiting/guide/edge-cloudflare-rate-limiting.md +88 -0
  102. package/blueprints/edge-cloudflare-turnstile/CHANGELOG.md +20 -0
  103. package/blueprints/edge-cloudflare-turnstile/README.md +95 -0
  104. package/blueprints/edge-cloudflare-turnstile/blueprint.json +161 -0
  105. package/blueprints/edge-cloudflare-turnstile/contributions/adrs/adr-3601-edge-cloudflare-turnstile-verifier-contract.json +14 -0
  106. package/blueprints/edge-cloudflare-turnstile/contributions/adrs/adr-3602-edge-cloudflare-turnstile-widget-mode.json +14 -0
  107. package/blueprints/edge-cloudflare-turnstile/contributions/adrs/adr-3603-edge-cloudflare-turnstile-refuse-shape.json +14 -0
  108. package/blueprints/edge-cloudflare-turnstile/contributions/probes/event-secrecy.mjs +51 -0
  109. package/blueprints/edge-cloudflare-turnstile/contributions/probes/guard-shape-scan.mjs +48 -0
  110. package/blueprints/edge-cloudflare-turnstile/contributions/probes/probe-utils.mjs +139 -0
  111. package/blueprints/edge-cloudflare-turnstile/contributions/probes/run-event-secrecy.mjs +5 -0
  112. package/blueprints/edge-cloudflare-turnstile/contributions/probes/run-guard-shape-scan.mjs +5 -0
  113. package/blueprints/edge-cloudflare-turnstile/contributions/probes/run-secret-shape-scan.mjs +5 -0
  114. package/blueprints/edge-cloudflare-turnstile/contributions/probes/run-siteverify-fixture.mjs +5 -0
  115. package/blueprints/edge-cloudflare-turnstile/contributions/probes/secret-shape-scan.mjs +77 -0
  116. package/blueprints/edge-cloudflare-turnstile/contributions/probes/siteverify-fixture.mjs +53 -0
  117. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-001.json +17 -0
  118. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-002.json +17 -0
  119. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-003.json +17 -0
  120. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-004.json +17 -0
  121. package/blueprints/edge-cloudflare-turnstile/contributions/requirements/edge-cloudflare-turnstile-req-005.json +17 -0
  122. package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3601-edge-cloudflare-turnstile-widget-mount.json +26 -0
  123. package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3602-edge-cloudflare-turnstile-server-verifier.json +36 -0
  124. package/blueprints/edge-cloudflare-turnstile/contributions/tacs/tac-3603-edge-cloudflare-turnstile-magic-link-hook.json +25 -0
  125. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35101.json +27 -0
  126. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35102.json +27 -0
  127. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35103.json +27 -0
  128. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35104.json +27 -0
  129. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35105.json +36 -0
  130. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35106.json +27 -0
  131. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35107.json +27 -0
  132. package/blueprints/edge-cloudflare-turnstile/contributions/user-stories/edge-cloudflare-turnstile-us-35108.json +27 -0
  133. package/blueprints/edge-cloudflare-turnstile/docs/topics.md +68 -0
  134. package/blueprints/edge-cloudflare-turnstile/guide/edge-cloudflare-turnstile.md +104 -0
  135. package/blueprints/edge-cloudflare-turnstile/probe-packs/edge-cloudflare-turnstile.pack.mjs +146 -0
  136. package/blueprints/email-smtp-resend/docs/topics.md +7 -1
  137. package/blueprints/jobs-background/docs/topics.md +7 -1
  138. package/blueprints/messaging-queue-cloudflare/docs/topics.md +7 -1
  139. package/blueprints/object-storage-s3/docs/topics.md +7 -1
  140. package/blueprints/observability-essentials/docs/topics.md +7 -1
  141. package/blueprints/observability-logging/docs/topics.md +7 -1
  142. package/blueprints/observability-probe-endpoints/docs/topics.md +7 -1
  143. package/blueprints/persistence-data-d1/docs/topics.md +7 -1
  144. package/blueprints/persistence-data-postgres/docs/topics.md +7 -1
  145. package/blueprints/persistence-data-sqlite/docs/topics.md +7 -1
  146. package/blueprints/platform-cloudflare-cron-triggers/CHANGELOG.md +22 -0
  147. package/blueprints/platform-cloudflare-cron-triggers/README.md +117 -0
  148. package/blueprints/platform-cloudflare-cron-triggers/blueprint.json +85 -0
  149. package/blueprints/platform-cloudflare-cron-triggers/contributions/adrs/adr-3301-platform-cloudflare-cron-triggers-scheduled-trigger-contract.json +14 -0
  150. package/blueprints/platform-cloudflare-cron-triggers/contributions/adrs/adr-3302-platform-cloudflare-cron-triggers-dispatcher-mode.json +14 -0
  151. package/blueprints/platform-cloudflare-cron-triggers/contributions/adrs/adr-3303-platform-cloudflare-cron-triggers-skew-tolerance-default.json +14 -0
  152. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/dispatcher-routing.mjs +64 -0
  153. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/event-secrecy.mjs +100 -0
  154. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/probe-utils.mjs +70 -0
  155. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/real-account-scheduled-smoke.mjs +100 -0
  156. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-dispatcher-routing.mjs +5 -0
  157. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-event-secrecy.mjs +5 -0
  158. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-real-account-scheduled-smoke.mjs +5 -0
  159. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-skew-tolerance.mjs +5 -0
  160. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/run-wrangler-test-scheduled.mjs +5 -0
  161. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/skew-tolerance.mjs +130 -0
  162. package/blueprints/platform-cloudflare-cron-triggers/contributions/probes/wrangler-test-scheduled.mjs +129 -0
  163. package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-001.json +17 -0
  164. package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-002.json +17 -0
  165. package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-003.json +17 -0
  166. package/blueprints/platform-cloudflare-cron-triggers/contributions/requirements/platform-cloudflare-cron-triggers-req-004.json +17 -0
  167. package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3301-platform-cloudflare-cron-triggers-scheduled-handler.json +22 -0
  168. package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3302-platform-cloudflare-cron-triggers-expression-router.json +22 -0
  169. package/blueprints/platform-cloudflare-cron-triggers/contributions/tacs/tac-3303-platform-cloudflare-cron-triggers-event-sink.json +21 -0
  170. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32101.json +25 -0
  171. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32102.json +34 -0
  172. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32103.json +34 -0
  173. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32104.json +34 -0
  174. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32105.json +25 -0
  175. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32106.json +25 -0
  176. package/blueprints/platform-cloudflare-cron-triggers/contributions/user-stories/platform-cloudflare-cron-triggers-us-32107.json +25 -0
  177. package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +71 -0
  178. package/blueprints/platform-cloudflare-cron-triggers/guide/platform-cloudflare-cron-triggers.md +119 -0
  179. package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +23 -0
  180. package/blueprints/platform-cloudflare-durable-objects/README.md +200 -0
  181. package/blueprints/platform-cloudflare-durable-objects/blueprint.json +243 -0
  182. package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3401-platform-cloudflare-durable-objects-single-cell-contract.json +14 -0
  183. package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3402-platform-cloudflare-durable-objects-websocket-hub-contract.json +14 -0
  184. package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3403-platform-cloudflare-durable-objects-storage-backend.json +14 -0
  185. package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3404-platform-cloudflare-durable-objects-migrations-shape.json +14 -0
  186. package/blueprints/platform-cloudflare-durable-objects/contributions/adrs/adr-3405-platform-cloudflare-durable-objects-hibernation-posture.json +14 -0
  187. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/alarm-fires-once.mjs +63 -0
  188. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/namespace-facade-ready.mjs +60 -0
  189. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/probe-utils.mjs +105 -0
  190. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/real-account-storage-smoke.mjs +58 -0
  191. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-alarm-fires-once.mjs +5 -0
  192. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-namespace-facade-ready.mjs +5 -0
  193. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-real-account-storage-smoke.mjs +5 -0
  194. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-single-cell-concurrent-increment.mjs +5 -0
  195. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-sole-reader-scan.mjs +5 -0
  196. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-storage-round-trip.mjs +5 -0
  197. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-websocket-hub-broadcast.mjs +5 -0
  198. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/run-wrangler-seam.mjs +5 -0
  199. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/single-cell-concurrent-increment.mjs +56 -0
  200. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/sole-reader-scan.mjs +117 -0
  201. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/storage-round-trip.mjs +87 -0
  202. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/websocket-hub-broadcast.mjs +112 -0
  203. package/blueprints/platform-cloudflare-durable-objects/contributions/probes/wrangler-seam.mjs +257 -0
  204. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-001.json +17 -0
  205. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-002.json +17 -0
  206. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-003.json +17 -0
  207. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-004.json +17 -0
  208. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-005.json +17 -0
  209. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-006.json +17 -0
  210. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-007.json +17 -0
  211. package/blueprints/platform-cloudflare-durable-objects/contributions/requirements/platform-cloudflare-durable-objects-req-008.json +17 -0
  212. package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3401-platform-cloudflare-durable-objects-namespace-facade.json +31 -0
  213. package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3402-platform-cloudflare-durable-objects-single-cell-shape.json +30 -0
  214. package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3403-platform-cloudflare-durable-objects-alarm-handler.json +29 -0
  215. package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3404-platform-cloudflare-durable-objects-websocket-hub.json +31 -0
  216. package/blueprints/platform-cloudflare-durable-objects/contributions/tacs/tac-3405-platform-cloudflare-durable-objects-event-sink.json +24 -0
  217. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33101.json +27 -0
  218. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33102.json +27 -0
  219. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33103.json +27 -0
  220. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33104.json +27 -0
  221. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33105.json +27 -0
  222. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33106.json +27 -0
  223. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33107.json +27 -0
  224. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33108.json +27 -0
  225. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33109.json +27 -0
  226. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33110.json +27 -0
  227. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33111.json +27 -0
  228. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33112.json +27 -0
  229. package/blueprints/platform-cloudflare-durable-objects/contributions/user-stories/platform-cloudflare-durable-objects-us-33113.json +25 -0
  230. package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +73 -0
  231. package/blueprints/platform-cloudflare-durable-objects/guide/platform-cloudflare-durable-objects.md +237 -0
  232. package/blueprints/platform-cloudflare-kv/CHANGELOG.md +21 -0
  233. package/blueprints/platform-cloudflare-kv/README.md +159 -0
  234. package/blueprints/platform-cloudflare-kv/blueprint.json +87 -0
  235. package/blueprints/platform-cloudflare-kv/contributions/adrs/adr-3201-platform-cloudflare-kv-key-value-store-contract.json +14 -0
  236. package/blueprints/platform-cloudflare-kv/contributions/adrs/adr-3202-platform-cloudflare-kv-default-cache-ttl.json +14 -0
  237. package/blueprints/platform-cloudflare-kv/contributions/adrs/adr-3203-platform-cloudflare-kv-key-naming-convention.json +14 -0
  238. package/blueprints/platform-cloudflare-kv/contributions/probes/cache-aside-hit-then-miss.mjs +82 -0
  239. package/blueprints/platform-cloudflare-kv/contributions/probes/event-secrecy.mjs +102 -0
  240. package/blueprints/platform-cloudflare-kv/contributions/probes/facade-round-trip.mjs +92 -0
  241. package/blueprints/platform-cloudflare-kv/contributions/probes/list-with-prefix.mjs +52 -0
  242. package/blueprints/platform-cloudflare-kv/contributions/probes/probe-utils.mjs +73 -0
  243. package/blueprints/platform-cloudflare-kv/contributions/probes/real-account-eventual-consistency-smoke.mjs +102 -0
  244. package/blueprints/platform-cloudflare-kv/contributions/probes/run-cache-aside-hit-then-miss.mjs +5 -0
  245. package/blueprints/platform-cloudflare-kv/contributions/probes/run-event-secrecy.mjs +5 -0
  246. package/blueprints/platform-cloudflare-kv/contributions/probes/run-facade-round-trip.mjs +5 -0
  247. package/blueprints/platform-cloudflare-kv/contributions/probes/run-list-with-prefix.mjs +5 -0
  248. package/blueprints/platform-cloudflare-kv/contributions/probes/run-real-account-eventual-consistency-smoke.mjs +5 -0
  249. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-001.json +18 -0
  250. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-002.json +18 -0
  251. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-003.json +18 -0
  252. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-004.json +18 -0
  253. package/blueprints/platform-cloudflare-kv/contributions/requirements/platform-cloudflare-kv-req-005.json +18 -0
  254. package/blueprints/platform-cloudflare-kv/contributions/tacs/tac-3201-platform-cloudflare-kv-facade.json +27 -0
  255. package/blueprints/platform-cloudflare-kv/contributions/tacs/tac-3202-platform-cloudflare-kv-cache-aside.json +26 -0
  256. package/blueprints/platform-cloudflare-kv/contributions/tacs/tac-3203-platform-cloudflare-kv-event-sink.json +25 -0
  257. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31101.json +27 -0
  258. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31102.json +27 -0
  259. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31103.json +36 -0
  260. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31104.json +27 -0
  261. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31105.json +27 -0
  262. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31106.json +27 -0
  263. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31107.json +27 -0
  264. package/blueprints/platform-cloudflare-kv/contributions/user-stories/platform-cloudflare-kv-us-31108.json +27 -0
  265. package/blueprints/platform-cloudflare-kv/docs/topics.md +71 -0
  266. package/blueprints/platform-cloudflare-kv/guide/platform-cloudflare-kv.md +138 -0
  267. package/blueprints/security-auth-clerk/docs/topics.md +7 -1
  268. package/blueprints/security-auth-keycloak/docs/topics.md +7 -1
  269. package/blueprints/security-auth-magic-link/docs/topics.md +7 -1
  270. package/blueprints/security-auth-oauth2/docs/topics.md +7 -1
  271. package/blueprints/security-secrets-management/docs/topics.md +7 -1
  272. package/fixtures/canary-manifest.json +6 -6
  273. package/package.json +1 -1
  274. package/rcf/adrs/adr-2214-application-admin-console-consume-zero-trust-gate.json +13 -0
  275. package/rcf/adrs/adr-3501-edge-cloudflare-access-jwt-gate.json +13 -0
  276. package/rcf/adrs/adr-3502-edge-cloudflare-access-identity-provider.json +13 -0
  277. package/rcf/adrs/adr-3503-edge-cloudflare-access-policy-scope.json +13 -0
  278. package/rcf/adrs/adr-3504-edge-cloudflare-access-audit-retention.json +13 -0
  279. package/rcf/adrs/adr-3601-edge-cloudflare-turnstile-verifier-contract.json +13 -0
  280. package/rcf/adrs/adr-3602-edge-cloudflare-turnstile-widget-mode.json +13 -0
  281. package/rcf/adrs/adr-3603-edge-cloudflare-turnstile-refuse-shape.json +13 -0
  282. package/rcf/adrs/adr-3701-edge-cloudflare-rate-limiting-throttle-contract.json +13 -0
  283. package/rcf/adrs/adr-3702-edge-cloudflare-rate-limiting-layering.json +13 -0
  284. package/rcf/adrs/adr-3703-edge-cloudflare-rate-limiting-manifest-shape.json +13 -0
  285. package/rcf/adrs/adr-3704-edge-cloudflare-rate-limiting-drift-audit-cadence.json +13 -0
  286. package/rcf/code-nodes/cn-230.json +13 -0
  287. package/rcf/code-nodes/cn-231.json +14 -0
  288. package/rcf/code-nodes/cn-232.json +13 -0
  289. package/rcf/code-nodes/cn-233.json +14 -0
  290. package/rcf/code-nodes/cn-234.json +13 -0
  291. package/rcf/code-nodes/cn-260.json +21 -0
  292. package/rcf/code-nodes/cn-261.json +14 -0
  293. package/rcf/code-nodes/cn-262.json +18 -0
  294. package/rcf/code-nodes/cn-263.json +12 -0
  295. package/rcf/code-nodes/cn-264.json +13 -0
  296. package/rcf/code-nodes/cn-265.json +15 -0
  297. package/rcf/code-nodes/cn-266.json +12 -0
  298. package/rcf/code-nodes/cn-267.json +12 -0
  299. package/rcf/code-nodes/cn-290.json +21 -0
  300. package/rcf/code-nodes/cn-291.json +12 -0
  301. package/rcf/code-nodes/cn-292.json +13 -0
  302. package/rcf/code-nodes/cn-293.json +13 -0
  303. package/rcf/code-nodes/cn-294.json +13 -0
  304. package/rcf/code-nodes/cn-295.json +12 -0
  305. package/rcf/code-nodes/cn-296.json +12 -0
  306. package/rcf/code-nodes/cn-297.json +12 -0
  307. package/rcf/code-nodes/cn-298.json +12 -0
  308. package/rcf/code-nodes/cn-299.json +12 -0
  309. package/rcf/code-nodes/cn-300.json +12 -0
  310. package/rcf/code-nodes/cn-301.json +14 -0
  311. package/rcf/code-nodes/cn-302.json +12 -0
  312. package/rcf/code-nodes/cn-303.json +12 -0
  313. package/rcf/code-nodes/cn-304.json +21 -0
  314. package/rcf/code-nodes/cn-320.json +20 -0
  315. package/rcf/code-nodes/cn-321.json +14 -0
  316. package/rcf/code-nodes/cn-350.json +19 -0
  317. package/rcf/code-nodes/cn-380.json +19 -0
  318. package/rcf/fbs/fbs-070.json +24 -0
  319. package/rcf/fbs/fbs-080.json +24 -0
  320. package/rcf/fbs/fbs-090.json +24 -0
  321. package/rcf/fbs/fbs-100.json +23 -0
  322. package/rcf/fbs/fbs-101.json +16 -0
  323. package/rcf/fbs/fbs-110.json +23 -0
  324. package/rcf/fbs/fbs-120.json +22 -0
  325. package/rcf/requirements/req-050.json +18 -0
  326. package/rcf/requirements/req-051.json +18 -0
  327. package/rcf/requirements/req-052.json +18 -0
  328. package/rcf/requirements/req-053.json +18 -0
  329. package/rcf/requirements/req-054.json +18 -0
  330. package/rcf/requirements/req-060.json +20 -0
  331. package/rcf/requirements/req-061.json +18 -0
  332. package/rcf/requirements/req-062.json +20 -0
  333. package/rcf/requirements/req-063.json +20 -0
  334. package/rcf/requirements/req-070.json +18 -0
  335. package/rcf/requirements/req-071.json +18 -0
  336. package/rcf/requirements/req-072.json +18 -0
  337. package/rcf/requirements/req-073.json +18 -0
  338. package/rcf/requirements/req-074.json +18 -0
  339. package/rcf/requirements/req-075.json +18 -0
  340. package/rcf/requirements/req-076.json +18 -0
  341. package/rcf/requirements/req-077.json +18 -0
  342. package/rcf/requirements/req-080.json +18 -0
  343. package/rcf/requirements/req-081.json +18 -0
  344. package/rcf/requirements/req-082.json +18 -0
  345. package/rcf/requirements/req-083.json +18 -0
  346. package/rcf/requirements/req-084.json +18 -0
  347. package/rcf/requirements/req-085.json +18 -0
  348. package/rcf/requirements/req-086.json +18 -0
  349. package/rcf/requirements/req-090.json +44 -0
  350. package/rcf/requirements/req-091.json +53 -0
  351. package/rcf/requirements/req-092.json +32 -0
  352. package/rcf/requirements/req-093.json +52 -0
  353. package/rcf/requirements/req-094.json +32 -0
  354. package/rcf/requirements/req-100.json +13 -0
  355. package/rcf/requirements/req-101.json +13 -0
  356. package/rcf/requirements/req-102.json +13 -0
  357. package/rcf/requirements/req-103.json +13 -0
  358. package/rcf/requirements/req-104.json +13 -0
  359. package/rcf/tacs/tac-2214-application-admin-console-access-gated-signin-surface.json +15 -0
  360. package/rcf/tacs/tac-3501-edge-cloudflare-access-jwt-validator.json +15 -0
  361. package/rcf/tacs/tac-3502-edge-cloudflare-access-application-declaration.json +15 -0
  362. package/rcf/tacs/tac-3503-edge-cloudflare-access-policy-shape.json +15 -0
  363. package/rcf/tacs/tac-3504-edge-cloudflare-access-audit-sink.json +15 -0
  364. package/rcf/tacs/tac-3601-edge-cloudflare-turnstile-widget-mount.json +15 -0
  365. package/rcf/tacs/tac-3602-edge-cloudflare-turnstile-server-verifier.json +15 -0
  366. package/rcf/tacs/tac-3603-edge-cloudflare-turnstile-magic-link-hook.json +15 -0
  367. package/rcf/tacs/tac-3701-edge-cloudflare-rate-limiting-manifest-schema.json +16 -0
  368. package/rcf/tacs/tac-3702-edge-cloudflare-rate-limiting-management-surface-doc.json +15 -0
  369. package/rcf/tacs/tac-3703-edge-cloudflare-rate-limiting-drift-audit-runner.json +16 -0
  370. package/rcf/test-suites/ts-052.json +58 -8
  371. package/rcf/test-suites/ts-080.json +22 -0
  372. package/rcf/test-suites/ts-081.json +22 -0
  373. package/rcf/test-suites/ts-082.json +30 -0
  374. package/rcf/test-suites/ts-083.json +22 -0
  375. package/rcf/test-suites/ts-084.json +30 -0
  376. package/rcf/test-suites/ts-085.json +22 -0
  377. package/rcf/test-suites/ts-086.json +22 -0
  378. package/rcf/test-suites/ts-087.json +22 -0
  379. package/rcf/test-suites/ts-090.json +22 -0
  380. package/rcf/test-suites/ts-091.json +22 -0
  381. package/rcf/test-suites/ts-092.json +22 -0
  382. package/rcf/test-suites/ts-093.json +30 -0
  383. package/rcf/test-suites/ts-094.json +30 -0
  384. package/rcf/test-suites/ts-095.json +30 -0
  385. package/rcf/test-suites/ts-096.json +22 -0
  386. package/rcf/test-suites/ts-100.json +22 -0
  387. package/rcf/test-suites/ts-101.json +22 -0
  388. package/rcf/test-suites/ts-102.json +22 -0
  389. package/rcf/test-suites/ts-103.json +22 -0
  390. package/rcf/test-suites/ts-104.json +22 -0
  391. package/rcf/test-suites/ts-105.json +22 -0
  392. package/rcf/test-suites/ts-106.json +22 -0
  393. package/rcf/test-suites/ts-107.json +22 -0
  394. package/rcf/test-suites/ts-108.json +22 -0
  395. package/rcf/test-suites/ts-109.json +22 -0
  396. package/rcf/test-suites/ts-110.json +22 -0
  397. package/rcf/test-suites/ts-111.json +22 -0
  398. package/rcf/test-suites/ts-112.json +22 -0
  399. package/rcf/test-suites/ts-113.json +22 -0
  400. package/rcf/test-suites/ts-114.json +22 -0
  401. package/rcf/test-suites/ts-115.json +22 -0
  402. package/rcf/test-suites/ts-116.json +22 -0
  403. package/rcf/test-suites/ts-117.json +22 -0
  404. package/rcf/test-suites/ts-118.json +22 -0
  405. package/rcf/test-suites/ts-119.json +30 -0
  406. package/rcf/test-suites/ts-120.json +22 -0
  407. package/rcf/test-suites/ts-121.json +22 -0
  408. package/rcf/test-suites/ts-122.json +22 -0
  409. package/rcf/test-suites/ts-123.json +22 -0
  410. package/rcf/test-suites/ts-124.json +22 -0
  411. package/rcf/test-suites/ts-125.json +22 -0
  412. package/rcf/test-suites/ts-126.json +22 -0
  413. package/rcf/test-suites/ts-127.json +22 -0
  414. package/rcf/test-suites/ts-130.json +22 -0
  415. package/rcf/test-suites/ts-131.json +22 -0
  416. package/rcf/test-suites/ts-132.json +22 -0
  417. package/rcf/test-suites/ts-133.json +22 -0
  418. package/rcf/test-suites/ts-134.json +22 -0
  419. package/rcf/test-suites/ts-135.json +22 -0
  420. package/rcf/test-suites/ts-136.json +22 -0
  421. package/rcf/test-suites/ts-137.json +22 -0
  422. package/rcf/user-stories/us-10001.json +23 -0
  423. package/rcf/user-stories/us-10101.json +23 -0
  424. package/rcf/user-stories/us-10201.json +23 -0
  425. package/rcf/user-stories/us-10301.json +23 -0
  426. package/rcf/user-stories/us-10401.json +23 -0
  427. package/rcf/user-stories/us-10601.json +23 -0
  428. package/rcf/user-stories/us-10701.json +23 -0
  429. package/rcf/user-stories/us-10801.json +23 -0
  430. package/rcf/user-stories/us-5001.json +27 -0
  431. package/rcf/user-stories/us-5002.json +27 -0
  432. package/rcf/user-stories/us-5101.json +36 -0
  433. package/rcf/user-stories/us-5102.json +27 -0
  434. package/rcf/user-stories/us-5201.json +36 -0
  435. package/rcf/user-stories/us-5301.json +27 -0
  436. package/rcf/user-stories/us-5302.json +27 -0
  437. package/rcf/user-stories/us-5401.json +27 -0
  438. package/rcf/user-stories/us-6001.json +27 -0
  439. package/rcf/user-stories/us-6002.json +27 -0
  440. package/rcf/user-stories/us-6003.json +27 -0
  441. package/rcf/user-stories/us-6101.json +36 -0
  442. package/rcf/user-stories/us-6201.json +36 -0
  443. package/rcf/user-stories/us-6301.json +36 -0
  444. package/rcf/user-stories/us-6302.json +27 -0
  445. package/rcf/user-stories/us-7001.json +27 -0
  446. package/rcf/user-stories/us-7002.json +27 -0
  447. package/rcf/user-stories/us-7101.json +27 -0
  448. package/rcf/user-stories/us-7201.json +27 -0
  449. package/rcf/user-stories/us-7301.json +27 -0
  450. package/rcf/user-stories/us-7401.json +27 -0
  451. package/rcf/user-stories/us-7402.json +27 -0
  452. package/rcf/user-stories/us-7501.json +27 -0
  453. package/rcf/user-stories/us-7601.json +27 -0
  454. package/rcf/user-stories/us-7701.json +27 -0
  455. package/rcf/user-stories/us-8001.json +24 -0
  456. package/rcf/user-stories/us-8002.json +24 -0
  457. package/rcf/user-stories/us-8003.json +24 -0
  458. package/rcf/user-stories/us-8101.json +24 -0
  459. package/rcf/user-stories/us-8201.json +24 -0
  460. package/rcf/user-stories/us-8301.json +24 -0
  461. package/rcf/user-stories/us-8401.json +24 -0
  462. package/rcf/user-stories/us-8501.json +24 -0
  463. package/rcf/user-stories/us-8502.json +24 -0
  464. package/rcf/user-stories/us-8601.json +24 -0
  465. package/rcf/user-stories/us-8602.json +24 -0
  466. package/rcf/user-stories/us-9001.json +27 -0
  467. package/rcf/user-stories/us-9002.json +27 -0
  468. package/rcf/user-stories/us-9101.json +27 -0
  469. package/rcf/user-stories/us-9102.json +27 -0
  470. package/rcf/user-stories/us-9201.json +27 -0
  471. package/rcf/user-stories/us-9301.json +27 -0
  472. package/rcf/user-stories/us-9302.json +27 -0
  473. package/rcf/user-stories/us-9401.json +27 -0
  474. package/releases/releases.yaml +11 -1
@@ -0,0 +1,70 @@
1
+ // Probe: audit event secrecy - 10 records after 5 pass + 5 reject, no forbidden substrings.
2
+ // anchorAcId: AC-34106-1. accountBound: false.
3
+
4
+ export const anchorAcId = 'AC-34106-1';
5
+ export const accountBound = false;
6
+
7
+ export default async function runProbe() {
8
+ const { bootFixtureJwks, loadValidator, fixtureEnv, FIXTURE_AUDIENCE, FIXTURE_ISSUER } = await import('./probe-utils.mjs');
9
+
10
+ const boot = await bootFixtureJwks();
11
+ const createAccessValidator = await loadValidator();
12
+
13
+ const sink = [];
14
+ const validator = createAccessValidator({ env: fixtureEnv(boot.jwksUrl), eventSink: (r) => sink.push(r) });
15
+
16
+ const tokens = [];
17
+ // 5 pass runs
18
+ for (let i = 0; i < 5; i++) {
19
+ const jwt = boot.signerMod.fixtureAccessJwt({
20
+ key: boot.key,
21
+ profile: { issuer: FIXTURE_ISSUER, audience: FIXTURE_AUDIENCE },
22
+ principal: { email: `user${i}@example.com`, sub: `user:u${i}`, groups: ['members'] },
23
+ ttlSec: 60,
24
+ });
25
+ tokens.push(jwt);
26
+ const req = new Request(`https://cf-edge.fixture/pass/${i}`, { headers: { 'Cf-Access-Jwt-Assertion': jwt } });
27
+ await validator.middleware(req);
28
+ }
29
+ // 5 reject runs (missing header)
30
+ for (let i = 0; i < 5; i++) {
31
+ const req = new Request(`https://cf-edge.fixture/reject/${i}`);
32
+ await validator.middleware(req);
33
+ }
34
+
35
+ const results = [];
36
+ const allowed = ['email', 'outcome', 'path', 'timestamp'];
37
+ const shapeOk = sink.length === 10 && sink.every((r) => Object.keys(r).sort().join(',') === allowed.join(','));
38
+ results.push({
39
+ anchorAcId: 'AC-34106-1',
40
+ verdict: shapeOk ? 'pass' : 'fail',
41
+ detail: shapeOk
42
+ ? `10 audit records, allowed keys only (${allowed.join(',')})`
43
+ : `unexpected sink shape; count=${sink.length} sample=${JSON.stringify(sink[0] ?? null)}`,
44
+ });
45
+
46
+ // No forbidden substrings across the serialised sink.
47
+ const serialised = JSON.stringify(sink);
48
+ const forbidden = [];
49
+ for (const jwt of tokens) {
50
+ const parts = jwt.split('.');
51
+ // Include full JWT, header segment, payload segment and signature segment individually.
52
+ for (const seg of [jwt, parts[0], parts[1], parts[2]]) {
53
+ if (seg && serialised.includes(seg)) forbidden.push(`token-segment len=${seg.length}`);
54
+ }
55
+ }
56
+ for (const header of ['Cf-Access-Jwt-Assertion', 'Authorization', 'CF-Access-Client-Id', 'CF-Access-Client-Secret']) {
57
+ if (serialised.includes(header)) forbidden.push(`header-name ${header}`);
58
+ }
59
+ const secrecyOk = forbidden.length === 0;
60
+ results.push({
61
+ anchorAcId: 'AC-34106-1',
62
+ verdict: secrecyOk ? 'pass' : 'fail',
63
+ detail: secrecyOk
64
+ ? `no forbidden substrings in the serialised sink; ran 5 pass + 5 reject; sink JSON bytes=${serialised.length}`
65
+ : `forbidden substrings found: ${JSON.stringify(forbidden)}`,
66
+ });
67
+
68
+ await boot.stop();
69
+ return { results };
70
+ }
@@ -0,0 +1,63 @@
1
+ // Probe: JWT validator - fixture-signed JWT validates and principal reduces onto request.auth.
2
+ // anchorAcId: AC-34101-1. accountBound: false.
3
+
4
+ export const anchorAcId = 'AC-34101-1';
5
+ export const accountBound = false;
6
+
7
+ export default async function runProbe() {
8
+ const { bootFixtureJwks, loadValidator, fixtureEnv, FIXTURE_AUDIENCE, FIXTURE_ISSUER } = await import('./probe-utils.mjs');
9
+
10
+ const boot = await bootFixtureJwks();
11
+ const createAccessValidator = await loadValidator();
12
+
13
+ const sink = [];
14
+ const validator = createAccessValidator({ env: fixtureEnv(boot.jwksUrl), eventSink: (r) => sink.push(r) });
15
+
16
+ const jwt = boot.signerMod.fixtureAccessJwt({
17
+ key: boot.key,
18
+ profile: { issuer: FIXTURE_ISSUER, audience: FIXTURE_AUDIENCE },
19
+ principal: { email: 'ada@example.com', sub: 'user:ada', groups: ['admins', 'shipping'] },
20
+ ttlSec: 60,
21
+ });
22
+
23
+ const req = new Request('https://cf-edge.fixture/protected', {
24
+ headers: { 'Cf-Access-Jwt-Assertion': jwt },
25
+ });
26
+ const outcome = await validator.middleware(req);
27
+ const results = [];
28
+
29
+ const principal = outcome.outcome?.principal;
30
+ const okShape =
31
+ outcome.rejected === false &&
32
+ principal &&
33
+ principal.email === 'ada@example.com' &&
34
+ principal.sub === 'user:ada' &&
35
+ Array.isArray(principal.groups) &&
36
+ principal.groups.length === 2 &&
37
+ req.auth &&
38
+ req.auth.email === 'ada@example.com';
39
+
40
+ results.push({
41
+ anchorAcId: 'AC-34101-1',
42
+ verdict: okShape ? 'pass' : 'fail',
43
+ detail: okShape
44
+ ? `validator resolved; principal reduces to {email:${principal.email}, sub:${principal.sub}, groups:${JSON.stringify(principal.groups)}}; request.auth attached; audit outcome=validated`
45
+ : `validator did not resolve as expected; outcome=${JSON.stringify(outcome)} request.auth=${JSON.stringify(req.auth ?? null)}`,
46
+ });
47
+
48
+ // Audit sink should hold one record, allowed keys only, outcome=validated.
49
+ const record = sink[sink.length - 1];
50
+ const allowed = new Set(['email', 'outcome', 'timestamp', 'path']);
51
+ const extraKeys = record ? Object.keys(record).filter((k) => !allowed.has(k)) : ['(no record)'];
52
+ const auditOk = sink.length === 1 && record && record.outcome === 'validated' && record.email === 'ada@example.com' && record.path === '/protected' && extraKeys.length === 0;
53
+ results.push({
54
+ anchorAcId: 'AC-34101-1',
55
+ verdict: auditOk ? 'pass' : 'fail',
56
+ detail: auditOk
57
+ ? `one audit record with allowed keys only; outcome=validated email=${record.email} path=${record.path}`
58
+ : `unexpected audit shape; count=${sink.length} record=${JSON.stringify(record ?? null)} extraKeys=${JSON.stringify(extraKeys)}`,
59
+ });
60
+
61
+ await boot.stop();
62
+ return { results };
63
+ }
@@ -0,0 +1,95 @@
1
+ // Probe: JWT validator reject cases - missing, expired, mis-signed each return 401 with metadata-only audit event.
2
+ // anchorAcId: AC-34102-1. accountBound: false.
3
+
4
+ export const anchorAcId = 'AC-34102-1';
5
+ export const accountBound = false;
6
+
7
+ export default async function runProbe() {
8
+ const { bootFixtureJwks, loadValidator, fixtureEnv, FIXTURE_AUDIENCE, FIXTURE_ISSUER } = await import('./probe-utils.mjs');
9
+
10
+ const boot = await bootFixtureJwks();
11
+ const createAccessValidator = await loadValidator();
12
+
13
+ const results = [];
14
+ const subcases = [];
15
+
16
+ // 1. Missing header
17
+ {
18
+ const sink = [];
19
+ const validator = createAccessValidator({ env: fixtureEnv(boot.jwksUrl), eventSink: (r) => sink.push(r) });
20
+ const req = new Request('https://cf-edge.fixture/protected');
21
+ const outcome = await validator.middleware(req);
22
+ subcases.push({
23
+ name: 'missing',
24
+ rejected: outcome.rejected,
25
+ status: outcome.response?.status,
26
+ auditCount: sink.length,
27
+ auditOutcome: sink[0]?.outcome,
28
+ auditKeys: sink[0] ? Object.keys(sink[0]).sort() : null,
29
+ });
30
+ }
31
+
32
+ // 2. Expired (SIMULATE_EXPIRED_JWT flag forces the code path)
33
+ {
34
+ const sink = [];
35
+ const validator = createAccessValidator({ env: fixtureEnv(boot.jwksUrl), eventSink: (r) => sink.push(r) });
36
+ const jwt = boot.signerMod.fixtureAccessJwt({
37
+ key: boot.key,
38
+ profile: { issuer: FIXTURE_ISSUER, audience: FIXTURE_AUDIENCE },
39
+ principal: { email: 'grace@example.com', sub: 'user:grace' },
40
+ ttlSec: 60,
41
+ });
42
+ const req = new Request('https://cf-edge.fixture/protected', { headers: { 'Cf-Access-Jwt-Assertion': jwt } });
43
+ const outcome = await validator.middleware(req, { SIMULATE_EXPIRED_JWT: true });
44
+ subcases.push({
45
+ name: 'expired',
46
+ rejected: outcome.rejected,
47
+ status: outcome.response?.status,
48
+ auditCount: sink.length,
49
+ auditOutcome: sink[0]?.outcome,
50
+ auditKeys: sink[0] ? Object.keys(sink[0]).sort() : null,
51
+ });
52
+ }
53
+
54
+ // 3. Mis-signed: sign with a DIFFERENT key, JWKS only carries the fixture key.
55
+ {
56
+ const sink = [];
57
+ const validator = createAccessValidator({ env: fixtureEnv(boot.jwksUrl), eventSink: (r) => sink.push(r) });
58
+ const wrongKey = boot.signerMod.createFixtureKey(boot.key.kid); // same kid so JWKS lookup hits, but a different keypair
59
+ const jwt = boot.signerMod.fixtureAccessJwt({
60
+ key: wrongKey,
61
+ profile: { issuer: FIXTURE_ISSUER, audience: FIXTURE_AUDIENCE },
62
+ principal: { email: 'evil@example.com', sub: 'user:evil' },
63
+ ttlSec: 60,
64
+ });
65
+ const req = new Request('https://cf-edge.fixture/protected', { headers: { 'Cf-Access-Jwt-Assertion': jwt } });
66
+ const outcome = await validator.middleware(req);
67
+ subcases.push({
68
+ name: 'mis-signed',
69
+ rejected: outcome.rejected,
70
+ status: outcome.response?.status,
71
+ auditCount: sink.length,
72
+ auditOutcome: sink[0]?.outcome,
73
+ auditKeys: sink[0] ? Object.keys(sink[0]).sort() : null,
74
+ });
75
+ }
76
+
77
+ // Note the mutation-check pair for the negative fires:
78
+ // Fires on the shipped code path (no bypass): every rejected===true, status===401, auditCount===1, audit keys drawn from allowed set.
79
+ // A mutation that removes the sink.push()/early-return call in the missing branch would drop auditCount to 0 (subcase would fail).
80
+
81
+ const allowed = ['email', 'outcome', 'path', 'timestamp'];
82
+ for (const sc of subcases) {
83
+ const ok = sc.rejected === true && sc.status === 401 && sc.auditCount === 1 && sc.auditKeys && sc.auditKeys.join(',') === allowed.join(',');
84
+ results.push({
85
+ anchorAcId: 'AC-34102-1',
86
+ verdict: ok ? 'pass' : 'fail',
87
+ detail: ok
88
+ ? `subcase ${sc.name}: 401 with one audit event, allowed keys only (${sc.auditKeys.join(',')}), outcome=${sc.auditOutcome}`
89
+ : `subcase ${sc.name} broke: ${JSON.stringify(sc)}`,
90
+ });
91
+ }
92
+
93
+ await boot.stop();
94
+ return { results };
95
+ }
@@ -0,0 +1,90 @@
1
+ // Shared helpers for edge-cloudflare-access probes.
2
+ //
3
+ // Runtime-dependency posture: probes import the fixture's JWT
4
+ // validator, fixture-JWT signer and JWKS server from the cf-edge
5
+ // fixture src/ and test/ trees so rcf-lite itself gains no new
6
+ // runtime dependency. Four probes drive the shipped code path
7
+ // in-process; one probe (real-account-gated-url) opens a network
8
+ // fetch against the elicited hostname when CI_HAS_CLOUDFLARE_ACCOUNT
9
+ // and CF_ACCESS_HOST are set. Without both env vars it records
10
+ // accountBoundSkipped and aggregates to pass per spec section 3.5.
11
+ //
12
+ // The wrangler dev seam is documented in the fixture README under
13
+ // the "Two-line wrangler-seam boot" section; the wrangler-seam
14
+ // probe drives it under workerd.
15
+
16
+ import { mkdir, writeFile } from 'node:fs/promises';
17
+ import { dirname, resolve } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+
20
+ const HERE = dirname(fileURLToPath(import.meta.url));
21
+
22
+ export const PROJECT_ROOT = resolve(HERE, '..', '..', '..', '..');
23
+ export const FIXTURE_DIR = resolve(PROJECT_ROOT, 'packages/rcf-lite/test/fixtures/cf-edge');
24
+ export const REPORT_DIR = resolve(PROJECT_ROOT, '.rcf/reports/blueprints/edge-cloudflare-access');
25
+
26
+ export function aggregate(results) {
27
+ if (results.some((r) => r.verdict === 'fail')) return 'fail';
28
+ if (results.some((r) => r.verdict === 'warn')) return 'warn';
29
+ return 'pass';
30
+ }
31
+
32
+ export async function writeReport({ probeName, engine, results, extra }) {
33
+ await mkdir(REPORT_DIR, { recursive: true });
34
+ const report = {
35
+ slug: 'edge-cloudflare-access',
36
+ probeName,
37
+ runAt: new Date().toISOString(),
38
+ engine,
39
+ results,
40
+ aggregateVerdict: aggregate(results),
41
+ ...(extra ?? {}),
42
+ };
43
+ const path = resolve(REPORT_DIR, `${probeName}.json`);
44
+ await writeFile(path, JSON.stringify(report, null, 2) + '\n', 'utf8');
45
+ return { report, path };
46
+ }
47
+
48
+ // Wraps a probe's async main body and reports. Sets process.exitCode
49
+ // on fail; drains stdout naturally per shelf convention.
50
+ export async function runShim(probeName, engine, mainFn) {
51
+ try {
52
+ const { results, extra } = await mainFn();
53
+ const { report, path } = await writeReport({ probeName, engine, results, extra });
54
+ process.stdout.write(JSON.stringify(report, null, 2) + '\n');
55
+ process.stdout.write(`report written to ${path}\n`);
56
+ if (report.aggregateVerdict === 'fail') process.exitCode = 1;
57
+ } catch (err) {
58
+ const results = [{
59
+ anchorAcId: 'unknown',
60
+ verdict: 'fail',
61
+ detail: `probe threw: ${err && err.message ? err.message : String(err)}`,
62
+ }];
63
+ const { report, path } = await writeReport({ probeName, engine, results });
64
+ process.stdout.write(JSON.stringify(report, null, 2) + '\n');
65
+ process.stderr.write(`probe error: ${err && err.stack ? err.stack : String(err)}\n`);
66
+ process.stderr.write(`report written to ${path}\n`);
67
+ process.exitCode = 1;
68
+ }
69
+ }
70
+
71
+ // Boot a fixture JWT keypair + JWKS server on 127.0.0.1:0 and
72
+ // return {key, server, jwksUrl, stop}.
73
+ export async function bootFixtureJwks(kid = 'cf-edge-fixture-kid-1') {
74
+ const signerMod = await import(`${FIXTURE_DIR}/test/jwt-signer.mjs`);
75
+ const jwksMod = await import(`${FIXTURE_DIR}/test/jwks-server.mjs`);
76
+ const key = signerMod.createFixtureKey(kid);
77
+ const server = await jwksMod.startJwksServer({ port: 0, keys: [key] });
78
+ return { key, server, signerMod, jwksUrl: server.url, stop: () => server.stop() };
79
+ }
80
+
81
+ export async function loadValidator() {
82
+ return (await import(`${FIXTURE_DIR}/src/jwt-validator.mjs`)).createAccessValidator;
83
+ }
84
+
85
+ export function fixtureEnv(jwksUrl, audience = 'cf-edge-fixture-audience') {
86
+ return { ACCESS_JWKS_URL: jwksUrl, ACCESS_AUDIENCE: audience };
87
+ }
88
+
89
+ export const FIXTURE_AUDIENCE = 'cf-edge-fixture-audience';
90
+ export const FIXTURE_ISSUER = 'https://cf-edge-fixture.cloudflareaccess.test';
@@ -0,0 +1,65 @@
1
+ // Probe: real-account gated URL round-trip against a scheduled Access-configured hostname.
2
+ // anchorAcId: AC-34109-1. accountBound: true.
3
+ //
4
+ // When CI_HAS_CLOUDFLARE_ACCOUNT and CF_ACCESS_HOST are set, the probe fetches
5
+ // https://<host>/ with redirects disabled and walks up to five redirect hops,
6
+ // asserting the terminal Location points at https://<team>.cloudflareaccess.com/.
7
+ // Without either env var the probe records accountBoundSkipped: true and
8
+ // aggregates to pass per spec section 3.5 (pass-with-skip).
9
+
10
+ export const anchorAcId = 'AC-34109-1';
11
+ export const accountBound = true;
12
+
13
+ const MAX_HOPS = 5;
14
+
15
+ async function walkRedirects(url) {
16
+ const chain = [];
17
+ let current = url;
18
+ for (let hop = 0; hop < MAX_HOPS; hop++) {
19
+ const res = await fetch(current, { redirect: 'manual' });
20
+ const location = res.headers.get('location');
21
+ chain.push({ url: current, status: res.status, location });
22
+ if (res.status < 300 || res.status >= 400 || !location) break;
23
+ current = new URL(location, current).toString();
24
+ }
25
+ return { chain, terminal: chain[chain.length - 1] };
26
+ }
27
+
28
+ export default async function runProbe() {
29
+ const has = process.env.CI_HAS_CLOUDFLARE_ACCOUNT === 'true';
30
+ const host = process.env.CF_ACCESS_HOST || '';
31
+ if (!has || !host) {
32
+ return {
33
+ results: [{
34
+ anchorAcId: 'AC-34109-1',
35
+ verdict: 'pass',
36
+ accountBoundSkipped: true,
37
+ detail: `accountBoundSkipped: CI_HAS_CLOUDFLARE_ACCOUNT=${has} CF_ACCESS_HOST=${host ? 'set' : 'unset'}; per spec section 3.5 pass-with-skip.`,
38
+ }],
39
+ extra: { accountBoundSkipped: true },
40
+ };
41
+ }
42
+ try {
43
+ const { chain, terminal } = await walkRedirects(`https://${host}/`);
44
+ const terminalUrl = terminal.location ?? terminal.url;
45
+ const ok = /https?:\/\/[a-z0-9-]+\.cloudflareaccess\.com/i.test(terminalUrl);
46
+ return {
47
+ results: [{
48
+ anchorAcId: 'AC-34109-1',
49
+ verdict: ok ? 'pass' : 'fail',
50
+ detail: ok
51
+ ? `redirect chain terminated at cloudflareaccess.com; hops=${chain.length} terminal=${terminalUrl}`
52
+ : `redirect chain did not terminate at cloudflareaccess.com; chain=${JSON.stringify(chain)}`,
53
+ }],
54
+ extra: { accountBound: true, chainLength: chain.length },
55
+ };
56
+ } catch (err) {
57
+ return {
58
+ results: [{
59
+ anchorAcId: 'AC-34109-1',
60
+ verdict: 'fail',
61
+ detail: `real-account probe threw: ${err && err.message ? err.message : String(err)}`,
62
+ }],
63
+ };
64
+ }
65
+ }
@@ -0,0 +1,5 @@
1
+ import runProbe from './admin-console-gate-surface.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+
4
+ const engine = { kind: 'admin-console-fixture', image: 'node HTTP fixture (probe-pack-application-admin-console)', healthy: true };
5
+ runShim('admin-console-gate-surface', engine, runProbe);
@@ -0,0 +1,5 @@
1
+ import runProbe from './audit-event-secrecy.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+
4
+ const engine = { kind: 'in-process', image: 'in-process JWT validator on cf-edge fixture', healthy: true };
5
+ runShim('audit-event-secrecy', engine, runProbe);
@@ -0,0 +1,5 @@
1
+ import runProbe from './jwt-validator-fixture.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+
4
+ const engine = { kind: 'in-process', image: 'in-process JWT validator on cf-edge fixture', healthy: true };
5
+ runShim('jwt-validator-fixture', engine, runProbe);
@@ -0,0 +1,5 @@
1
+ import runProbe from './jwt-validator-reject.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+
4
+ const engine = { kind: 'in-process', image: 'in-process JWT validator on cf-edge fixture', healthy: true };
5
+ runShim('jwt-validator-reject', engine, runProbe);
@@ -0,0 +1,5 @@
1
+ import runProbe from './real-account-gated-url.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+
4
+ const engine = { kind: 'real-account', image: 'live fetch against Cloudflare Access-configured hostname', healthy: true };
5
+ runShim('real-account-gated-url', engine, runProbe);
@@ -0,0 +1,5 @@
1
+ import runProbe from './wrangler-seam.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+
4
+ const engine = { kind: 'wrangler-dev', image: 'wrangler dev (workerd) on cf-edge fixture', healthy: true };
5
+ runShim('wrangler-seam', engine, runProbe);
@@ -0,0 +1,203 @@
1
+ // Wrangler-seam probe for edge-cloudflare-access v1.0.0.
2
+ //
3
+ // Spawns `wrangler dev --local` on the cf-edge fixture and drives
4
+ // three requests to observe the JWT validator at the edge under
5
+ // workerd:
6
+ //
7
+ // (a) a missing-header request to /protected returns HTTP 401
8
+ // (the validator's reject path runs through the shipped Worker
9
+ // entry, not through the in-process probes).
10
+ // (b) a request to /protected carrying a fixture-signed JWT that
11
+ // the fixture JWKS server (booted by this probe on the fixed
12
+ // port from wrangler.toml [vars] ACCESS_JWKS_URL) validates
13
+ // returns HTTP 200 with request.auth reflected on the response
14
+ // body.
15
+ // (c) a request to /health returns HTTP 200 (the /health path is
16
+ // exempt from the validator so a load balancer can reach it).
17
+ //
18
+ // Warn semantics per spec section 3.1 pass-with-skip:
19
+ // - wrangler devDependency missing: aggregateVerdict warn (never fail);
20
+ // - wrangler CLI fails to bind within the cap: warn.
21
+ // - A handler thrown at the workerd boundary: fail (per round-6 T-3 gate).
22
+ //
23
+ // Mutation-check pair for the negative fires: removing the
24
+ // validator's early-return call on missing header would surface
25
+ // the /protected request as HTTP 200 with no request.auth (an
26
+ // unauthenticated request reaching the handler). The probe fails
27
+ // on that mutation: HTTP 401 is required. See PR body for the
28
+ // verbatim tails of the shipped-path pass and the mutation-run
29
+ // fail.
30
+
31
+ import { spawn } from 'node:child_process';
32
+ import { existsSync } from 'node:fs';
33
+ import { dirname, resolve } from 'node:path';
34
+ import { fileURLToPath, pathToFileURL } from 'node:url';
35
+
36
+ export const anchorAcId = 'AC-34101-1';
37
+ export const accountBound = false;
38
+
39
+ const BIND_CAP_MS = 60000;
40
+ const KILL_GRACE_MS = 2000;
41
+ // The fixture wrangler.toml [vars] ACCESS_JWKS_URL points at 127.0.0.1:8788
42
+ // per the shipped file. The wrangler-seam probe boots the JWKS server on
43
+ // exactly that port so the validator hits it under workerd.
44
+ const JWKS_PORT = 8788;
45
+ const FIXTURE_AUDIENCE = 'cf-edge-fixture-audience';
46
+ const FIXTURE_ISSUER = 'https://cf-edge-fixture.cloudflareaccess.test';
47
+
48
+ const HERE = dirname(fileURLToPath(import.meta.url));
49
+ const FIXTURE_DIR = resolve(HERE, '..', '..', '..', '..', 'packages', 'rcf-lite', 'test', 'fixtures', 'cf-edge');
50
+
51
+ function findWranglerBin() {
52
+ const candidate = resolve(FIXTURE_DIR, 'node_modules', '.bin', 'wrangler');
53
+ return existsSync(candidate) ? candidate : null;
54
+ }
55
+
56
+ async function killAndDrain(proc) {
57
+ if (!proc || proc.killed) return;
58
+ try { proc.kill('SIGTERM'); } catch (_e) {}
59
+ await new Promise((r) => setTimeout(r, KILL_GRACE_MS));
60
+ try { if (!proc.killed) proc.kill('SIGKILL'); } catch (_e) {}
61
+ }
62
+
63
+ export default async function runProbe() {
64
+ const results = [];
65
+ const bin = findWranglerBin();
66
+ if (!bin) {
67
+ results.push({
68
+ anchorAcId: 'AC-34101-1',
69
+ verdict: 'warn',
70
+ detail: `wrangler devDependency not installed under ${FIXTURE_DIR}/node_modules/.bin/wrangler; run pnpm install --ignore-workspace in the fixture directory. Mechanism-reach gap noted; the in-process probes carry the runtime evidence for the shipped validator. Warn (not fail) per section 3.1 pass-with-skip.`,
71
+ });
72
+ return { results, extra: { wranglerBinPresent: false } };
73
+ }
74
+
75
+ // Boot the fixture JWKS server on the fixed port from wrangler.toml.
76
+ const signerMod = await import(pathToFileURL(resolve(FIXTURE_DIR, 'test', 'jwt-signer.mjs')).href);
77
+ const jwksMod = await import(pathToFileURL(resolve(FIXTURE_DIR, 'test', 'jwks-server.mjs')).href);
78
+ const key = signerMod.createFixtureKey('cf-edge-wrangler-seam-kid');
79
+ let jwks;
80
+ try {
81
+ jwks = await jwksMod.startJwksServer({ port: JWKS_PORT, keys: [key] });
82
+ } catch (err) {
83
+ results.push({
84
+ anchorAcId: 'AC-34101-1',
85
+ verdict: 'warn',
86
+ detail: `local JWKS server could not bind port ${JWKS_PORT}: ${err && err.message ? err.message : String(err)}. Warn (not fail): the JWKS port is required for the wrangler-seam probe to observe the validator's positive path under workerd. Fix by freeing port ${JWKS_PORT} and re-running.`,
87
+ });
88
+ return { results, extra: { wranglerBinPresent: true, jwksBound: false } };
89
+ }
90
+
91
+ const proc = spawn(bin, ['dev', '--local', '--port', '0'], {
92
+ cwd: FIXTURE_DIR,
93
+ env: process.env,
94
+ stdio: ['ignore', 'pipe', 'pipe'],
95
+ });
96
+
97
+ let boundUrl = null;
98
+ let stderrTail = '';
99
+ let stdoutTail = '';
100
+ proc.stdout.on('data', (buf) => {
101
+ const s = buf.toString();
102
+ stdoutTail = (stdoutTail + s).slice(-2000);
103
+ const m = s.match(/Ready on http:\/\/(?:127\.0\.0\.1|localhost):(\d+)/i);
104
+ if (m && !boundUrl) boundUrl = `http://127.0.0.1:${m[1]}`;
105
+ });
106
+ proc.stderr.on('data', (b) => { stderrTail = (stderrTail + b.toString()).slice(-2000); });
107
+
108
+ const start = Date.now();
109
+ while (!boundUrl && Date.now() - start < BIND_CAP_MS) {
110
+ if (proc.exitCode !== null) break;
111
+ await new Promise((r) => setTimeout(r, 250));
112
+ }
113
+
114
+ if (!boundUrl) {
115
+ await killAndDrain(proc);
116
+ await jwks.stop();
117
+ results.push({
118
+ anchorAcId: 'AC-34101-1',
119
+ verdict: 'warn',
120
+ detail: `wrangler dev did not bind within ${BIND_CAP_MS}ms; stdoutTail: ${stdoutTail.slice(-400)} stderrTail: ${stderrTail.slice(-400)}. Warn (not fail) per section 3.1 pass-with-skip.`,
121
+ });
122
+ return { results, extra: { wranglerBinPresent: true, boundUrl: null } };
123
+ }
124
+
125
+ try {
126
+ // (a) missing header on /protected -> 401
127
+ let statusMissing = 0;
128
+ try {
129
+ const r = await fetch(`${boundUrl}/protected`);
130
+ statusMissing = r.status;
131
+ } catch (err) {
132
+ results.push({
133
+ anchorAcId: 'AC-34101-1',
134
+ verdict: 'fail',
135
+ detail: `handler thrown at the workerd boundary on /protected: ${err && err.message ? err.message : String(err)}`,
136
+ });
137
+ return { results, extra: { wranglerBinPresent: true, boundUrl } };
138
+ }
139
+ results.push({
140
+ anchorAcId: 'AC-34101-1',
141
+ verdict: statusMissing === 401 ? 'pass' : 'fail',
142
+ detail: statusMissing === 401
143
+ ? `workerd /protected (no header) returned HTTP 401 - the shipped validator's missing-header reject path fires at the edge`
144
+ : `workerd /protected (no header) returned HTTP ${statusMissing}; expected 401 on the shipped validator's missing-header reject path (a value other than 401 would surface an unauthenticated request to the handler - the exact mutation the probe guards against)`,
145
+ });
146
+
147
+ // (b) valid fixture-signed JWT on /protected -> 200 with request.auth
148
+ const jwt = signerMod.fixtureAccessJwt({
149
+ key,
150
+ profile: { issuer: FIXTURE_ISSUER, audience: FIXTURE_AUDIENCE },
151
+ principal: { email: 'ada@example.com', sub: 'user:ada', groups: ['admins'] },
152
+ ttlSec: 60,
153
+ });
154
+ let signedStatus = 0;
155
+ let signedBody = '';
156
+ try {
157
+ const r = await fetch(`${boundUrl}/protected`, { headers: { 'Cf-Access-Jwt-Assertion': jwt } });
158
+ signedStatus = r.status;
159
+ signedBody = await r.text();
160
+ } catch (err) {
161
+ results.push({
162
+ anchorAcId: 'AC-34101-1',
163
+ verdict: 'fail',
164
+ detail: `handler thrown at the workerd boundary on signed /protected: ${err && err.message ? err.message : String(err)}`,
165
+ });
166
+ return { results, extra: { wranglerBinPresent: true, boundUrl } };
167
+ }
168
+ const authLeaked = signedStatus === 200 && signedBody.includes('"auth"') && signedBody.includes('"email":"ada@example.com"');
169
+ results.push({
170
+ anchorAcId: 'AC-34101-1',
171
+ verdict: authLeaked ? 'pass' : 'fail',
172
+ detail: authLeaked
173
+ ? `workerd /protected (fixture-signed JWT) returned HTTP 200 with request.auth reflected on the body (email=ada@example.com)`
174
+ : `workerd /protected (fixture-signed JWT) failed: status=${signedStatus} body=${signedBody.slice(0, 200)}`,
175
+ });
176
+
177
+ // (c) /health -> 200
178
+ let healthStatus = 0;
179
+ try {
180
+ const r = await fetch(`${boundUrl}/health`);
181
+ healthStatus = r.status;
182
+ } catch (err) {
183
+ results.push({
184
+ anchorAcId: 'AC-34101-1',
185
+ verdict: 'fail',
186
+ detail: `handler thrown at the workerd boundary on /health: ${err && err.message ? err.message : String(err)}`,
187
+ });
188
+ return { results, extra: { wranglerBinPresent: true, boundUrl } };
189
+ }
190
+ results.push({
191
+ anchorAcId: 'AC-34101-1',
192
+ verdict: healthStatus === 200 ? 'pass' : 'fail',
193
+ detail: healthStatus === 200
194
+ ? `workerd /health returned HTTP 200 (health path exempt from the validator, LB-reachable)`
195
+ : `workerd /health returned HTTP ${healthStatus}; expected 200`,
196
+ });
197
+ } finally {
198
+ await killAndDrain(proc);
199
+ await jwks.stop();
200
+ }
201
+
202
+ return { results, extra: { wranglerBinPresent: true, boundUrl } };
203
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "reqId": "edge-cloudflare-access-REQ-001",
3
+ "prdId": "PRD-001",
4
+ "title": "The Access JWT validator is the sole reader of the Cf-Access-Jwt-Assertion header and reduces the principal onto request.auth",
5
+ "description": "The applying project reaches Cloudflare Access through a single JWT validator module (src/jwt-validator.mjs) that is the ONLY module dereferencing the Cf-Access-Jwt-Assertion header in the applied source tree per https://developers.cloudflare.com/cloudflare-one/policies/access/. The validator fetches the Access JWKS from the elicited endpoint, caches keys per-kid, verifies the JWT against the cached key matching the header's kid, and reduces the principal into request.auth as {email, sub, groups}. Every downstream handler reads request.auth only; no other module reaches the header.",
6
+ "category": "functional",
7
+ "domain": "edge",
8
+ "priority": "must",
9
+ "rationale": "Ratified in the Cloudflare round 6 spec (2026-09-06 section 5.4). Ships as v1.0.0 of edge-cloudflare-access.",
10
+ "tags": [
11
+ "blueprint:edge-cloudflare-access"
12
+ ],
13
+ "version": "1.0.0",
14
+ "status": "approved",
15
+ "createdAt": "2026-09-07T16:00:00.000Z",
16
+ "updatedAt": "2026-09-07T16:00:00.000Z"
17
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "reqId": "edge-cloudflare-access-REQ-002",
3
+ "prdId": "PRD-001",
4
+ "title": "An Access application is declared with an elicited hostname or self-hosted-app id and an elicited policy shape from the enum",
5
+ "description": "The blueprint elicits either an Access application hostname or a self-hosted-app id (one of the two) plus the JWT audience tag and JWKS URL, plus a policy shape from the enum (email-domain, service-token-only, service-token-plus-email-domain, group-membership). Applying the blueprint records the elicited values on rcf/blueprints/edge-cloudflare-access.applied.json; the shipped guide walks the operator through issuing the paired policy in the Cloudflare Zero Trust dashboard (screen-by-screen) and documents the alternative API path against api.cloudflare.com/client/v4/accounts/{account_id}/access/apps/{app_id}/policies.",
6
+ "category": "functional",
7
+ "domain": "edge",
8
+ "priority": "must",
9
+ "rationale": "Ratified in the Cloudflare round 6 spec (2026-09-06 section 5.4). Ships as v1.0.0 of edge-cloudflare-access.",
10
+ "tags": [
11
+ "blueprint:edge-cloudflare-access"
12
+ ],
13
+ "version": "1.0.0",
14
+ "status": "approved",
15
+ "createdAt": "2026-09-07T16:00:00.000Z",
16
+ "updatedAt": "2026-09-07T16:00:00.000Z"
17
+ }