rcf-lite 0.27.0 → 0.28.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 (601) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +10 -0
  3. package/bin/rcf.js +2 -0
  4. package/blueprints/application-account-settings/CHANGELOG.md +35 -6
  5. package/blueprints/application-account-settings/README.md +1 -1
  6. package/blueprints/application-account-settings/blueprint.json +4 -2
  7. package/blueprints/application-account-settings/contributions/adrs/adr-2602-application-account-settings-security-surface-shape.json +1 -1
  8. package/blueprints/application-account-settings/contributions/probes/probe-utils.mjs +177 -0
  9. package/blueprints/application-account-settings/contributions/probes/profile-form-autocomplete.mjs +67 -0
  10. package/blueprints/application-account-settings/contributions/probes/run-profile-form-autocomplete.mjs +5 -0
  11. package/blueprints/application-account-settings/contributions/probes/run-sessions-adapter-uniform.mjs +5 -0
  12. package/blueprints/application-account-settings/contributions/probes/run-sessions-surface-shape.mjs +5 -0
  13. package/blueprints/application-account-settings/contributions/probes/run-shell-tablist-per-capability.mjs +5 -0
  14. package/blueprints/application-account-settings/contributions/probes/run-theme-radiogroup.mjs +5 -0
  15. package/blueprints/application-account-settings/contributions/probes/sessions-adapter-uniform.mjs +130 -0
  16. package/blueprints/application-account-settings/contributions/probes/sessions-surface-shape.mjs +70 -0
  17. package/blueprints/application-account-settings/contributions/probes/shell-tablist-per-capability.mjs +60 -0
  18. package/blueprints/application-account-settings/contributions/probes/theme-radiogroup.mjs +126 -0
  19. package/blueprints/application-admin-console/CHANGELOG.md +32 -6
  20. package/blueprints/application-admin-console/README.md +1 -1
  21. package/blueprints/application-admin-console/blueprint.json +4 -2
  22. package/blueprints/application-admin-console/contributions/adrs/adr-2201-application-admin-console-capability-vocabulary.json +1 -1
  23. package/blueprints/application-admin-console/contributions/probes/audit-log-surface.mjs +79 -0
  24. package/blueprints/application-admin-console/contributions/probes/org-switcher-surface.mjs +83 -0
  25. package/blueprints/application-admin-console/contributions/probes/permission-matrix-grid.mjs +67 -0
  26. package/blueprints/application-admin-console/contributions/probes/probe-utils.mjs +177 -0
  27. package/blueprints/application-admin-console/contributions/probes/run-audit-log-surface.mjs +5 -0
  28. package/blueprints/application-admin-console/contributions/probes/run-org-switcher-surface.mjs +5 -0
  29. package/blueprints/application-admin-console/contributions/probes/run-permission-matrix-grid.mjs +5 -0
  30. package/blueprints/application-admin-console/contributions/probes/run-sign-in-access-gated-surface.mjs +5 -0
  31. package/blueprints/application-admin-console/contributions/probes/run-users-directory-surface.mjs +5 -0
  32. package/blueprints/application-admin-console/contributions/probes/sign-in-access-gated-surface.mjs +117 -0
  33. package/blueprints/application-admin-console/contributions/probes/users-directory-surface.mjs +145 -0
  34. package/blueprints/application-api-rest/CHANGELOG.md +16 -8
  35. package/blueprints/application-api-rest/README.md +3 -3
  36. package/blueprints/application-api-rest/blueprint.json +3 -2
  37. package/blueprints/application-api-rest/contributions/adrs/adr-302-application-api-rest-auth-model.json +1 -1
  38. package/blueprints/application-api-rest/contributions/probes/cursor-pagination-round-trip.mjs +154 -0
  39. package/blueprints/application-api-rest/contributions/probes/health-probes-distinct.mjs +124 -0
  40. package/blueprints/application-api-rest/contributions/probes/probe-utils.mjs +177 -0
  41. package/blueprints/application-api-rest/contributions/probes/problem-details-on-error.mjs +77 -0
  42. package/blueprints/application-api-rest/contributions/probes/request-id-echoed.mjs +76 -0
  43. package/blueprints/application-api-rest/contributions/probes/run-cursor-pagination-round-trip.mjs +5 -0
  44. package/blueprints/application-api-rest/contributions/probes/run-health-probes-distinct.mjs +5 -0
  45. package/blueprints/application-api-rest/contributions/probes/run-problem-details-on-error.mjs +5 -0
  46. package/blueprints/application-api-rest/contributions/probes/run-request-id-echoed.mjs +5 -0
  47. package/blueprints/application-api-rest/docs/topics.md +1 -1
  48. package/blueprints/application-charts/CHANGELOG.md +35 -9
  49. package/blueprints/application-charts/README.md +6 -6
  50. package/blueprints/application-charts/blueprint.json +5 -3
  51. package/blueprints/application-charts/contributions/adrs/adr-1901-application-charts-engine-choice.json +1 -1
  52. package/blueprints/application-charts/contributions/probes/keyboard-traversal.mjs +151 -0
  53. package/blueprints/application-charts/contributions/probes/non-colour-distinction.mjs +67 -0
  54. package/blueprints/application-charts/contributions/probes/probe-utils.mjs +177 -0
  55. package/blueprints/application-charts/contributions/probes/run-keyboard-traversal.mjs +5 -0
  56. package/blueprints/application-charts/contributions/probes/run-non-colour-distinction.mjs +5 -0
  57. package/blueprints/application-charts/contributions/probes/run-text-alternative-table.mjs +5 -0
  58. package/blueprints/application-charts/contributions/probes/text-alternative-table.mjs +139 -0
  59. package/blueprints/application-charts/contributions/requirements/application-charts-req-001.json +1 -1
  60. package/blueprints/application-charts/contributions/requirements/application-charts-req-002.json +1 -1
  61. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18101.json +5 -5
  62. package/blueprints/application-charts/contributions/user-stories/application-charts-us-18106.json +1 -1
  63. package/blueprints/application-charts/guide/application-charts.md +1 -1
  64. package/blueprints/application-dashboard/CHANGELOG.md +20 -10
  65. package/blueprints/application-dashboard/README.md +6 -6
  66. package/blueprints/application-dashboard/assets/guidance/dashboard-design.md +2 -2
  67. package/blueprints/application-dashboard/blueprint.json +3 -2
  68. package/blueprints/application-dashboard/contributions/adrs/adr-2001-application-dashboard-primary-kpi-enum.json +1 -1
  69. package/blueprints/application-dashboard/contributions/adrs/adr-2002-application-dashboard-timeframe-presets.json +1 -1
  70. package/blueprints/application-dashboard/contributions/probes/export-handle-formats.mjs +75 -0
  71. package/blueprints/application-dashboard/contributions/probes/four-tile-states.mjs +75 -0
  72. package/blueprints/application-dashboard/contributions/probes/primary-kpi-top-left.mjs +58 -0
  73. package/blueprints/application-dashboard/contributions/probes/probe-utils.mjs +177 -0
  74. package/blueprints/application-dashboard/contributions/probes/run-export-handle-formats.mjs +4 -0
  75. package/blueprints/application-dashboard/contributions/probes/run-four-tile-states.mjs +4 -0
  76. package/blueprints/application-dashboard/contributions/probes/run-primary-kpi-top-left.mjs +4 -0
  77. package/blueprints/application-dashboard/contributions/probes/run-shell-five-regions.mjs +4 -0
  78. package/blueprints/application-dashboard/contributions/probes/shell-five-regions.mjs +93 -0
  79. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-002.json +1 -1
  80. package/blueprints/application-dashboard/contributions/requirements/application-dashboard-req-003.json +1 -1
  81. package/blueprints/application-dashboard/contributions/tacs/tac-2002-application-dashboard-filter-chrome.json +1 -1
  82. package/blueprints/application-dashboard/contributions/tacs/tac-2003-application-dashboard-export-handle.json +2 -2
  83. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19101.json +2 -2
  84. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19102.json +2 -2
  85. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19103.json +1 -1
  86. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19104.json +1 -1
  87. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19105.json +1 -1
  88. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19106.json +2 -2
  89. package/blueprints/application-dashboard/contributions/user-stories/application-dashboard-us-19107.json +5 -5
  90. package/blueprints/application-dashboard/docs/topics.md +2 -2
  91. package/blueprints/application-dashboard/guide/application-dashboard.md +2 -2
  92. package/blueprints/application-datatable/CHANGELOG.md +19 -9
  93. package/blueprints/application-datatable/README.md +2 -2
  94. package/blueprints/application-datatable/blueprint.json +3 -2
  95. package/blueprints/application-datatable/contributions/probes/apg-table-shape.mjs +57 -0
  96. package/blueprints/application-datatable/contributions/probes/four-states-regions.mjs +80 -0
  97. package/blueprints/application-datatable/contributions/probes/probe-utils.mjs +177 -0
  98. package/blueprints/application-datatable/contributions/probes/run-apg-table-shape.mjs +4 -0
  99. package/blueprints/application-datatable/contributions/probes/run-four-states-regions.mjs +4 -0
  100. package/blueprints/application-datatable/contributions/probes/run-search-adapter-round-trip.mjs +4 -0
  101. package/blueprints/application-datatable/contributions/probes/run-sort-adapter-round-trip.mjs +4 -0
  102. package/blueprints/application-datatable/contributions/probes/search-adapter-round-trip.mjs +58 -0
  103. package/blueprints/application-datatable/contributions/probes/sort-adapter-round-trip.mjs +60 -0
  104. package/blueprints/application-datatable/contributions/requirements/application-datatable-req-006.json +1 -1
  105. package/blueprints/application-datatable/docs/topics.md +1 -1
  106. package/blueprints/application-empty-error-states/CHANGELOG.md +33 -3
  107. package/blueprints/application-empty-error-states/blueprint.json +4 -2
  108. package/blueprints/application-empty-error-states/contributions/probes/empty-list-and-no-search.mjs +66 -0
  109. package/blueprints/application-empty-error-states/contributions/probes/error-boundary-alert.mjs +65 -0
  110. package/blueprints/application-empty-error-states/contributions/probes/forbidden-and-server-error.mjs +167 -0
  111. package/blueprints/application-empty-error-states/contributions/probes/not-found-and-recovery.mjs +61 -0
  112. package/blueprints/application-empty-error-states/contributions/probes/permission-denied-and-offline.mjs +155 -0
  113. package/blueprints/application-empty-error-states/contributions/probes/probe-utils.mjs +177 -0
  114. package/blueprints/application-empty-error-states/contributions/probes/run-empty-list-and-no-search.mjs +5 -0
  115. package/blueprints/application-empty-error-states/contributions/probes/run-error-boundary-alert.mjs +5 -0
  116. package/blueprints/application-empty-error-states/contributions/probes/run-forbidden-and-server-error.mjs +5 -0
  117. package/blueprints/application-empty-error-states/contributions/probes/run-not-found-and-recovery.mjs +5 -0
  118. package/blueprints/application-empty-error-states/contributions/probes/run-permission-denied-and-offline.mjs +5 -0
  119. package/blueprints/application-error-handling/CHANGELOG.md +45 -6
  120. package/blueprints/application-error-handling/blueprint.json +3 -2
  121. package/blueprints/application-error-handling/contributions/probes/category-vocabulary.mjs +90 -0
  122. package/blueprints/application-error-handling/contributions/probes/probe-utils.mjs +177 -0
  123. package/blueprints/application-error-handling/contributions/probes/record-shape-adr-1701.mjs +78 -0
  124. package/blueprints/application-error-handling/contributions/probes/run-category-vocabulary.mjs +5 -0
  125. package/blueprints/application-error-handling/contributions/probes/run-record-shape-adr-1701.mjs +5 -0
  126. package/blueprints/application-error-handling/contributions/probes/run-two-boundaries-registered.mjs +5 -0
  127. package/blueprints/application-error-handling/contributions/probes/two-boundaries-registered.mjs +343 -0
  128. package/blueprints/application-file-upload/CHANGELOG.md +28 -6
  129. package/blueprints/application-file-upload/README.md +1 -1
  130. package/blueprints/application-file-upload/blueprint.json +3 -2
  131. package/blueprints/application-file-upload/contributions/probes/assertive-completion-slot.mjs +78 -0
  132. package/blueprints/application-file-upload/contributions/probes/chunked-transport-endpoints.mjs +173 -0
  133. package/blueprints/application-file-upload/contributions/probes/per-file-progressbar.mjs +124 -0
  134. package/blueprints/application-file-upload/contributions/probes/probe-utils.mjs +177 -0
  135. package/blueprints/application-file-upload/contributions/probes/run-assertive-completion-slot.mjs +4 -0
  136. package/blueprints/application-file-upload/contributions/probes/run-chunked-transport-endpoints.mjs +4 -0
  137. package/blueprints/application-file-upload/contributions/probes/run-per-file-progressbar.mjs +4 -0
  138. package/blueprints/application-file-upload/contributions/probes/run-upload-surface-shape.mjs +4 -0
  139. package/blueprints/application-file-upload/contributions/probes/upload-surface-shape.mjs +55 -0
  140. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-001.json +1 -1
  141. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-002.json +1 -1
  142. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-003.json +1 -1
  143. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-004.json +1 -1
  144. package/blueprints/application-file-upload/contributions/requirements/application-file-upload-req-005.json +1 -1
  145. package/blueprints/application-file-upload/probe-packs/application-file-upload.pack.mjs +1 -1
  146. package/blueprints/application-forms-wizard/CHANGELOG.md +20 -6
  147. package/blueprints/application-forms-wizard/README.md +2 -2
  148. package/blueprints/application-forms-wizard/blueprint.json +3 -2
  149. package/blueprints/application-forms-wizard/contributions/probes/draft-persistence-round-trip.mjs +110 -0
  150. package/blueprints/application-forms-wizard/contributions/probes/probe-utils.mjs +177 -0
  151. package/blueprints/application-forms-wizard/contributions/probes/run-draft-persistence-round-trip.mjs +4 -0
  152. package/blueprints/application-forms-wizard/contributions/probes/run-step-page-shape.mjs +4 -0
  153. package/blueprints/application-forms-wizard/contributions/probes/run-task-list-surface.mjs +4 -0
  154. package/blueprints/application-forms-wizard/contributions/probes/step-page-shape.mjs +61 -0
  155. package/blueprints/application-forms-wizard/contributions/probes/task-list-surface.mjs +109 -0
  156. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-001.json +1 -1
  157. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-002.json +1 -1
  158. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-003.json +1 -1
  159. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-004.json +1 -1
  160. package/blueprints/application-forms-wizard/contributions/requirements/application-forms-wizard-req-005.json +1 -1
  161. package/blueprints/application-forms-wizard/probe-packs/application-forms-wizard.pack.mjs +1 -1
  162. package/blueprints/application-notifications-in-app/CHANGELOG.md +38 -5
  163. package/blueprints/application-notifications-in-app/README.md +4 -4
  164. package/blueprints/application-notifications-in-app/blueprint.json +4 -2
  165. package/blueprints/application-notifications-in-app/contributions/adrs/adr-2101-application-notifications-in-app-live-region-role-mapping.json +1 -1
  166. package/blueprints/application-notifications-in-app/contributions/probes/centre-acknowledge-round-trip.mjs +210 -0
  167. package/blueprints/application-notifications-in-app/contributions/probes/live-region-preseeding.mjs +93 -0
  168. package/blueprints/application-notifications-in-app/contributions/probes/probe-utils.mjs +177 -0
  169. package/blueprints/application-notifications-in-app/contributions/probes/run-centre-acknowledge-round-trip.mjs +5 -0
  170. package/blueprints/application-notifications-in-app/contributions/probes/run-live-region-preseeding.mjs +5 -0
  171. package/blueprints/application-notifications-in-app/contributions/probes/run-toast-contract.mjs +5 -0
  172. package/blueprints/application-notifications-in-app/contributions/probes/toast-contract.mjs +92 -0
  173. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2101-application-notifications-in-app-live-region.json +3 -3
  174. package/blueprints/application-notifications-in-app/contributions/tacs/tac-2102-application-notifications-in-app-centre.json +1 -1
  175. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20101.json +1 -1
  176. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20102.json +1 -1
  177. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20103.json +1 -1
  178. package/blueprints/application-notifications-in-app/contributions/user-stories/application-notifications-in-app-us-20105.json +1 -1
  179. package/blueprints/application-notifications-in-app/guide/application-notifications-in-app.md +3 -3
  180. package/blueprints/application-onboarding-tour/CHANGELOG.md +31 -5
  181. package/blueprints/application-onboarding-tour/README.md +1 -1
  182. package/blueprints/application-onboarding-tour/blueprint.json +5 -3
  183. package/blueprints/application-onboarding-tour/contributions/probes/checklist-anchor-open.mjs +81 -0
  184. package/blueprints/application-onboarding-tour/contributions/probes/completion-persistence.mjs +159 -0
  185. package/blueprints/application-onboarding-tour/contributions/probes/first-run-detection.mjs +67 -0
  186. package/blueprints/application-onboarding-tour/contributions/probes/probe-utils.mjs +177 -0
  187. package/blueprints/application-onboarding-tour/contributions/probes/run-checklist-anchor-open.mjs +5 -0
  188. package/blueprints/application-onboarding-tour/contributions/probes/run-completion-persistence.mjs +5 -0
  189. package/blueprints/application-onboarding-tour/contributions/probes/run-first-run-detection.mjs +5 -0
  190. package/blueprints/application-onboarding-tour/contributions/probes/run-stepper-role-dialog.mjs +5 -0
  191. package/blueprints/application-onboarding-tour/contributions/probes/stepper-role-dialog.mjs +45 -0
  192. package/blueprints/application-spa/CHANGELOG.md +20 -11
  193. package/blueprints/application-spa/README.md +9 -10
  194. package/blueprints/application-spa/blueprint.json +3 -2
  195. package/blueprints/application-spa/contributions/adrs/adr-202-application-spa-theming.json +1 -1
  196. package/blueprints/application-spa/contributions/adrs/adr-206-application-spa-iconography.json +1 -1
  197. package/blueprints/application-spa/contributions/probes/designed-empty-state.mjs +72 -0
  198. package/blueprints/application-spa/contributions/probes/probe-utils.mjs +177 -0
  199. package/blueprints/application-spa/contributions/probes/route-inventory-published.mjs +185 -0
  200. package/blueprints/application-spa/contributions/probes/run-designed-empty-state.mjs +5 -0
  201. package/blueprints/application-spa/contributions/probes/run-route-inventory-published.mjs +5 -0
  202. package/blueprints/application-spa/contributions/probes/run-shell-nav-present.mjs +5 -0
  203. package/blueprints/application-spa/contributions/probes/shell-nav-present.mjs +69 -0
  204. package/blueprints/application-spa/contributions/tacs/tac-207-application-spa-token-adherence-probe.json +1 -1
  205. package/blueprints/application-spa/contributions/tacs/tac-208-application-spa-icon-adherence-probe.json +2 -2
  206. package/blueprints/application-spa/contributions/tacs/tac-209-application-spa-csp-styled-adherence-probe.json +3 -3
  207. package/blueprints/application-spa/contributions/tacs/tac-210-application-spa-external-dependency-provisioning-probe.json +2 -2
  208. package/blueprints/application-spa/contributions/tacs/tac-211-application-spa-core-flow-e2e-probe.json +2 -2
  209. package/blueprints/application-spa/contributions/user-stories/application-spa-us-1131.json +1 -1
  210. package/blueprints/application-spa/docs/topics.md +1 -1
  211. package/blueprints/delivery-ci-workflows/CHANGELOG.md +31 -11
  212. package/blueprints/delivery-ci-workflows/README.md +3 -3
  213. package/blueprints/delivery-ci-workflows/blueprint.json +3 -2
  214. package/blueprints/delivery-ci-workflows/contributions/adrs/adr-702-delivery-ci-workflows-strict-coverage-gate.json +2 -2
  215. package/blueprints/delivery-ci-workflows/contributions/probes/node-gate-entrypoint.mjs +76 -0
  216. package/blueprints/delivery-ci-workflows/contributions/probes/probe-utils.mjs +56 -0
  217. package/blueprints/delivery-ci-workflows/contributions/probes/real-account-github-actions-run-record.mjs +139 -0
  218. package/blueprints/delivery-ci-workflows/contributions/probes/run-node-gate-entrypoint.mjs +3 -0
  219. package/blueprints/delivery-ci-workflows/contributions/probes/run-real-account-github-actions-run-record.mjs +3 -0
  220. package/blueprints/delivery-ci-workflows/contributions/probes/run-workflow-template-shape.mjs +3 -0
  221. package/blueprints/delivery-ci-workflows/contributions/probes/workflow-template-shape.mjs +94 -0
  222. package/blueprints/delivery-ci-workflows/contributions/requirements/delivery-ci-workflows-req-004.json +1 -1
  223. package/blueprints/delivery-ci-workflows/docs/topics.md +2 -3
  224. package/blueprints/deploy-cloudflare-workers/CHANGELOG.md +4 -4
  225. package/blueprints/deploy-cloudflare-workers/README.md +3 -3
  226. package/blueprints/deploy-cloudflare-workers/contributions/adrs/adr-1306-deploy-cloudflare-workers-spa-shape.json +2 -2
  227. package/blueprints/deploy-cloudflare-workers/docs/topics.md +2 -2
  228. package/blueprints/deploy-hetzner-server/CHANGELOG.md +98 -7
  229. package/blueprints/deploy-hetzner-server/blueprint.json +7 -6
  230. package/blueprints/deploy-hetzner-server/contributions/probes/cloud-init-render-lint.mjs +46 -21
  231. package/blueprints/deploy-hetzner-server/contributions/probes/hcloud-dry-run-mock.mjs +344 -83
  232. package/blueprints/deploy-hetzner-server/contributions/probes/manifest-schema-validate.mjs +211 -42
  233. package/blueprints/deploy-hetzner-server/contributions/probes/probe-utils.mjs +140 -22
  234. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-cloud-init-hardened.mjs +111 -30
  235. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-snapshot-on-demand.mjs +158 -30
  236. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-throwaway-server-provision.mjs +154 -32
  237. package/blueprints/edge-cloudflare-access/CHANGELOG.md +6 -5
  238. package/blueprints/edge-cloudflare-access/blueprint.json +1 -1
  239. package/blueprints/edge-cloudflare-access/contributions/probes/admin-console-gate-surface.mjs +9 -1
  240. package/blueprints/edge-cloudflare-access/docs/topics.md +1 -1
  241. package/blueprints/edge-cloudflare-rate-limiting/CHANGELOG.md +4 -7
  242. package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +1 -1
  243. package/blueprints/edge-cloudflare-tunnel/CHANGELOG.md +4 -6
  244. package/blueprints/edge-cloudflare-tunnel/README.md +1 -2
  245. package/blueprints/edge-cloudflare-tunnel/docs/topics.md +1 -1
  246. package/blueprints/edge-cloudflare-turnstile/CHANGELOG.md +2 -3
  247. package/blueprints/edge-cloudflare-turnstile/docs/topics.md +1 -1
  248. package/blueprints/email-smtp-resend/CHANGELOG.md +24 -8
  249. package/blueprints/email-smtp-resend/README.md +2 -2
  250. package/blueprints/email-smtp-resend/blueprint.json +3 -2
  251. package/blueprints/email-smtp-resend/contributions/probes/probe-utils.mjs +50 -0
  252. package/blueprints/email-smtp-resend/contributions/probes/real-account-resend-send.mjs +50 -0
  253. package/blueprints/email-smtp-resend/contributions/probes/run-real-account-resend-send.mjs +3 -0
  254. package/blueprints/email-smtp-resend/contributions/probes/run-smtp-round-trip.mjs +3 -0
  255. package/blueprints/email-smtp-resend/contributions/probes/run-unverified-sender-refusal.mjs +3 -0
  256. package/blueprints/email-smtp-resend/contributions/probes/smtp-round-trip.mjs +43 -0
  257. package/blueprints/email-smtp-resend/contributions/probes/unverified-sender-refusal.mjs +99 -0
  258. package/blueprints/email-smtp-resend/docs/topics.md +2 -3
  259. package/blueprints/jobs-background/CHANGELOG.md +66 -5
  260. package/blueprints/jobs-background/README.md +2 -2
  261. package/blueprints/jobs-background/blueprint.json +3 -2
  262. package/blueprints/jobs-background/contributions/probes/apply-time-override.mjs +38 -10
  263. package/blueprints/jobs-background/contributions/probes/apply-time-refusal.mjs +28 -6
  264. package/blueprints/jobs-background/contributions/probes/event-secrecy.mjs +16 -2
  265. package/blueprints/jobs-background/contributions/probes/fake-clock-cron.mjs +102 -21
  266. package/blueprints/jobs-background/contributions/probes/probe-utils.mjs +10 -2
  267. package/blueprints/jobs-background/contributions/probes/retry-and-fail-real-account.mjs +355 -0
  268. package/blueprints/jobs-background/contributions/probes/retry-and-fail.mjs +33 -2
  269. package/blueprints/jobs-background/contributions/probes/run-retry-and-fail-real-account.mjs +12 -0
  270. package/blueprints/jobs-background/docs/topics.md +1 -1
  271. package/blueprints/jobs-background/guide/jobs-background.md +1 -1
  272. package/blueprints/messaging-queue-cloudflare/CHANGELOG.md +25 -19
  273. package/blueprints/messaging-queue-cloudflare/README.md +12 -12
  274. package/blueprints/messaging-queue-cloudflare/blueprint.json +1 -1
  275. package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3001-messaging-queue-cloudflare-adapter.json +2 -2
  276. package/blueprints/messaging-queue-cloudflare/contributions/adrs/adr-3002-messaging-queue-cloudflare-delivery-semantics.json +1 -1
  277. package/blueprints/messaging-queue-cloudflare/contributions/probes/real-account-concurrency-smoke.mjs +180 -12
  278. package/blueprints/messaging-queue-cloudflare/contributions/requirements/messaging-queue-cloudflare-req-006.json +1 -1
  279. package/blueprints/messaging-queue-cloudflare/docs/topics.md +2 -2
  280. package/blueprints/messaging-queue-cloudflare/guide/messaging-queue-cloudflare.md +2 -2
  281. package/blueprints/object-storage-s3/CHANGELOG.md +75 -4
  282. package/blueprints/object-storage-s3/blueprint.json +3 -2
  283. package/blueprints/object-storage-s3/contributions/probes/event-secrecy.mjs +73 -12
  284. package/blueprints/object-storage-s3/contributions/probes/facade-round-trip.mjs +55 -7
  285. package/blueprints/object-storage-s3/contributions/probes/hetzner-object-storage-round-trip.mjs +102 -18
  286. package/blueprints/object-storage-s3/contributions/probes/multipart-upload.mjs +105 -36
  287. package/blueprints/object-storage-s3/contributions/probes/presigned-url.mjs +104 -55
  288. package/blueprints/object-storage-s3/contributions/probes/probe-utils.mjs +129 -7
  289. package/blueprints/object-storage-s3/contributions/probes/put-get-round-trip.mjs +80 -18
  290. package/blueprints/object-storage-s3/contributions/probes/r2-real-account-smoke.mjs +291 -37
  291. package/blueprints/object-storage-s3/contributions/probes/run-event-secrecy.mjs +8 -2
  292. package/blueprints/object-storage-s3/contributions/probes/run-facade-round-trip.mjs +5 -5
  293. package/blueprints/object-storage-s3/contributions/probes/run-hetzner-object-storage-round-trip.mjs +8 -5
  294. package/blueprints/object-storage-s3/contributions/probes/run-multipart-upload.mjs +8 -2
  295. package/blueprints/object-storage-s3/contributions/probes/run-presigned-url.mjs +8 -2
  296. package/blueprints/object-storage-s3/contributions/probes/run-put-get-round-trip.mjs +6 -3
  297. package/blueprints/object-storage-s3/contributions/probes/run-r2-real-account-smoke.mjs +10 -2
  298. package/blueprints/object-storage-s3/contributions/requirements/object-storage-s3-req-006.json +1 -1
  299. package/blueprints/object-storage-s3/docs/topics.md +1 -1
  300. package/blueprints/object-storage-s3/guide/object-storage-s3.md +1 -1
  301. package/blueprints/observability-essentials/CHANGELOG.md +23 -7
  302. package/blueprints/observability-essentials/README.md +2 -2
  303. package/blueprints/observability-essentials/assets/probe-samples/probe-response-baseline.v2.json +1 -1
  304. package/blueprints/observability-essentials/blueprint.json +3 -2
  305. package/blueprints/observability-essentials/contributions/probes/liveness-probe.mjs +84 -0
  306. package/blueprints/observability-essentials/contributions/probes/metrics-endpoint.mjs +96 -0
  307. package/blueprints/observability-essentials/contributions/probes/probe-utils.mjs +52 -0
  308. package/blueprints/observability-essentials/contributions/probes/readiness-probe.mjs +171 -0
  309. package/blueprints/observability-essentials/contributions/probes/run-liveness-probe.mjs +3 -0
  310. package/blueprints/observability-essentials/contributions/probes/run-metrics-endpoint.mjs +3 -0
  311. package/blueprints/observability-essentials/contributions/probes/run-readiness-probe.mjs +3 -0
  312. package/blueprints/observability-essentials/docs/topics.md +2 -3
  313. package/blueprints/observability-logging/CHANGELOG.md +29 -4
  314. package/blueprints/observability-logging/README.md +2 -2
  315. package/blueprints/observability-logging/blueprint.json +3 -2
  316. package/blueprints/observability-logging/contributions/probes/correlation-id-flow.mjs +173 -0
  317. package/blueprints/observability-logging/contributions/probes/line-shape-and-fields.mjs +82 -0
  318. package/blueprints/observability-logging/contributions/probes/probe-utils.mjs +47 -0
  319. package/blueprints/observability-logging/contributions/probes/redaction-boundary.mjs +130 -0
  320. package/blueprints/observability-logging/contributions/probes/run-correlation-id-flow.mjs +3 -0
  321. package/blueprints/observability-logging/contributions/probes/run-line-shape-and-fields.mjs +3 -0
  322. package/blueprints/observability-logging/contributions/probes/run-redaction-boundary.mjs +3 -0
  323. package/blueprints/observability-probe-endpoints/CHANGELOG.md +23 -8
  324. package/blueprints/observability-probe-endpoints/README.md +3 -3
  325. package/blueprints/observability-probe-endpoints/blueprint.json +3 -2
  326. package/blueprints/observability-probe-endpoints/contributions/probes/kubernetes-startup-enabled.mjs +80 -0
  327. package/blueprints/observability-probe-endpoints/contributions/probes/partial-profile-refusal.mjs +101 -0
  328. package/blueprints/observability-probe-endpoints/contributions/probes/probe-utils.mjs +49 -0
  329. package/blueprints/observability-probe-endpoints/contributions/probes/profile-boot-materialisation.mjs +69 -0
  330. package/blueprints/observability-probe-endpoints/contributions/probes/run-kubernetes-startup-enabled.mjs +3 -0
  331. package/blueprints/observability-probe-endpoints/contributions/probes/run-partial-profile-refusal.mjs +3 -0
  332. package/blueprints/observability-probe-endpoints/contributions/probes/run-profile-boot-materialisation.mjs +3 -0
  333. package/blueprints/observability-probe-endpoints/docs/topics.md +2 -2
  334. package/blueprints/persistence-data-d1/CHANGELOG.md +16 -3
  335. package/blueprints/persistence-data-d1/README.md +2 -2
  336. package/blueprints/persistence-data-d1/blueprint.json +3 -2
  337. package/blueprints/persistence-data-d1/contributions/adrs/adr-1404-persistence-data-d1-store-boundary.json +1 -1
  338. package/blueprints/persistence-data-d1/contributions/probes/facade-round-trip.mjs +140 -0
  339. package/blueprints/persistence-data-d1/contributions/probes/migrations-forward-only.mjs +66 -0
  340. package/blueprints/persistence-data-d1/contributions/probes/probe-utils.mjs +51 -0
  341. package/blueprints/persistence-data-d1/contributions/probes/real-account-d1-round-trip.mjs +133 -0
  342. package/blueprints/persistence-data-d1/contributions/probes/run-facade-round-trip.mjs +3 -0
  343. package/blueprints/persistence-data-d1/contributions/probes/run-migrations-forward-only.mjs +3 -0
  344. package/blueprints/persistence-data-d1/contributions/probes/run-real-account-d1-round-trip.mjs +3 -0
  345. package/blueprints/persistence-data-d1/docs/topics.md +2 -3
  346. package/blueprints/persistence-data-postgres/CHANGELOG.md +84 -4
  347. package/blueprints/persistence-data-postgres/README.md +2 -2
  348. package/blueprints/persistence-data-postgres/blueprint.json +3 -2
  349. package/blueprints/persistence-data-postgres/contributions/adrs/adr-2801-persistence-data-postgres-driver.json +1 -1
  350. package/blueprints/persistence-data-postgres/contributions/probes/facade-round-trip.mjs +87 -12
  351. package/blueprints/persistence-data-postgres/contributions/probes/migration-apply.mjs +245 -19
  352. package/blueprints/persistence-data-postgres/contributions/probes/pool-posture-smoke.mjs +109 -26
  353. package/blueprints/persistence-data-postgres/contributions/probes/prepared-statement-scan.mjs +151 -38
  354. package/blueprints/persistence-data-postgres/contributions/probes/probe-utils.mjs +24 -6
  355. package/blueprints/persistence-data-postgres/contributions/probes/recovery-restore-round-trip.mjs +261 -48
  356. package/blueprints/persistence-data-postgres/contributions/probes/transaction-atomicity.mjs +76 -20
  357. package/blueprints/persistence-data-postgres/contributions/requirements/persistence-data-postgres-req-003.json +1 -1
  358. package/blueprints/persistence-data-postgres/docs/topics.md +1 -1
  359. package/blueprints/persistence-data-sqlite/CHANGELOG.md +16 -2
  360. package/blueprints/persistence-data-sqlite/README.md +2 -2
  361. package/blueprints/persistence-data-sqlite/blueprint.json +3 -2
  362. package/blueprints/persistence-data-sqlite/contributions/probes/boot-open-migrate.mjs +90 -0
  363. package/blueprints/persistence-data-sqlite/contributions/probes/facade-round-trip.mjs +82 -0
  364. package/blueprints/persistence-data-sqlite/contributions/probes/probe-utils.mjs +83 -0
  365. package/blueprints/persistence-data-sqlite/contributions/probes/run-boot-open-migrate.mjs +5 -0
  366. package/blueprints/persistence-data-sqlite/contributions/probes/run-facade-round-trip.mjs +5 -0
  367. package/blueprints/persistence-data-sqlite/contributions/probes/run-wal-checkpoint.mjs +5 -0
  368. package/blueprints/persistence-data-sqlite/contributions/probes/wal-checkpoint.mjs +137 -0
  369. package/blueprints/persistence-data-sqlite/docs/topics.md +2 -3
  370. package/blueprints/platform-cloudflare-cron-triggers/CHANGELOG.md +5 -5
  371. package/blueprints/platform-cloudflare-cron-triggers/README.md +2 -3
  372. package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +1 -1
  373. package/blueprints/platform-cloudflare-durable-objects/CHANGELOG.md +6 -10
  374. package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +1 -1
  375. package/blueprints/platform-cloudflare-kv/CHANGELOG.md +16 -12
  376. package/blueprints/platform-cloudflare-kv/README.md +2 -4
  377. package/blueprints/platform-cloudflare-kv/blueprint.json +2 -2
  378. package/blueprints/platform-cloudflare-kv/docs/topics.md +1 -1
  379. package/blueprints/platform-docker-compose-host/CHANGELOG.md +92 -5
  380. package/blueprints/platform-docker-compose-host/blueprint.json +2 -2
  381. package/blueprints/platform-docker-compose-host/contributions/probes/caddyfile-validate.mjs +116 -29
  382. package/blueprints/platform-docker-compose-host/contributions/probes/compose-config-lint.mjs +181 -109
  383. package/blueprints/platform-docker-compose-host/contributions/probes/probe-utils.mjs +146 -26
  384. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-minimal-stack-up.mjs +238 -24
  385. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-reload-burst.mjs +207 -21
  386. package/blueprints/platform-docker-compose-host/contributions/probes/secrets-as-files-scan.mjs +246 -42
  387. package/blueprints/platform-docker-compose-host/docs/topics.md +1 -1
  388. package/blueprints/security-auth-clerk/CHANGELOG.md +18 -6
  389. package/blueprints/security-auth-clerk/README.md +3 -3
  390. package/blueprints/security-auth-clerk/assets/wiring/workers-wrangler-toml-shape.md +1 -1
  391. package/blueprints/security-auth-clerk/blueprint.json +3 -2
  392. package/blueprints/security-auth-clerk/contributions/probes/hosted-identity-ui-config.mjs +61 -0
  393. package/blueprints/security-auth-clerk/contributions/probes/probe-utils.mjs +188 -0
  394. package/blueprints/security-auth-clerk/contributions/probes/real-account-principal-directory-round-trip.mjs +216 -0
  395. package/blueprints/security-auth-clerk/contributions/probes/real-account-session-inventory.mjs +260 -0
  396. package/blueprints/security-auth-clerk/contributions/probes/role-model-adapter.mjs +53 -0
  397. package/blueprints/security-auth-clerk/contributions/probes/run-hosted-identity-ui-config.mjs +4 -0
  398. package/blueprints/security-auth-clerk/contributions/probes/run-real-account-principal-directory-round-trip.mjs +4 -0
  399. package/blueprints/security-auth-clerk/contributions/probes/run-real-account-session-inventory.mjs +4 -0
  400. package/blueprints/security-auth-clerk/contributions/probes/run-role-model-adapter.mjs +4 -0
  401. package/blueprints/security-auth-clerk/docs/topics.md +2 -3
  402. package/blueprints/security-auth-keycloak/CHANGELOG.md +18 -7
  403. package/blueprints/security-auth-keycloak/README.md +2 -2
  404. package/blueprints/security-auth-keycloak/blueprint.json +3 -2
  405. package/blueprints/security-auth-keycloak/contributions/probes/discovery-shape.mjs +68 -0
  406. package/blueprints/security-auth-keycloak/contributions/probes/introspection-shape.mjs +88 -0
  407. package/blueprints/security-auth-keycloak/contributions/probes/jwt-verifier-shape.mjs +86 -0
  408. package/blueprints/security-auth-keycloak/contributions/probes/probe-utils.mjs +180 -0
  409. package/blueprints/security-auth-keycloak/contributions/probes/real-account-realm-round-trip.mjs +91 -0
  410. package/blueprints/security-auth-keycloak/contributions/probes/role-adapter-shape.mjs +69 -0
  411. package/blueprints/security-auth-keycloak/contributions/probes/run-discovery-shape.mjs +4 -0
  412. package/blueprints/security-auth-keycloak/contributions/probes/run-introspection-shape.mjs +4 -0
  413. package/blueprints/security-auth-keycloak/contributions/probes/run-jwt-verifier-shape.mjs +4 -0
  414. package/blueprints/security-auth-keycloak/contributions/probes/run-real-account-realm-round-trip.mjs +4 -0
  415. package/blueprints/security-auth-keycloak/contributions/probes/run-role-adapter-shape.mjs +4 -0
  416. package/blueprints/security-auth-keycloak/docs/topics.md +1 -2
  417. package/blueprints/security-auth-magic-link/CHANGELOG.md +15 -4
  418. package/blueprints/security-auth-magic-link/README.md +2 -2
  419. package/blueprints/security-auth-magic-link/assets/principal-registry-samples/single-address.md +1 -1
  420. package/blueprints/security-auth-magic-link/blueprint.json +3 -2
  421. package/blueprints/security-auth-magic-link/contributions/probes/probe-utils.mjs +174 -0
  422. package/blueprints/security-auth-magic-link/contributions/probes/real-account-magic-link-send.mjs +139 -0
  423. package/blueprints/security-auth-magic-link/contributions/probes/run-real-account-magic-link-send.mjs +4 -0
  424. package/blueprints/security-auth-magic-link/contributions/probes/run-token-entropy-shape.mjs +4 -0
  425. package/blueprints/security-auth-magic-link/contributions/probes/run-token-issue-verify.mjs +4 -0
  426. package/blueprints/security-auth-magic-link/contributions/probes/token-entropy-shape.mjs +60 -0
  427. package/blueprints/security-auth-magic-link/contributions/probes/token-issue-verify.mjs +90 -0
  428. package/blueprints/security-auth-magic-link/docs/topics.md +1 -1
  429. package/blueprints/security-auth-oauth2/CHANGELOG.md +16 -5
  430. package/blueprints/security-auth-oauth2/README.md +2 -2
  431. package/blueprints/security-auth-oauth2/blueprint.json +3 -2
  432. package/blueprints/security-auth-oauth2/contributions/probes/authorisation-code-flow-shape.mjs +259 -0
  433. package/blueprints/security-auth-oauth2/contributions/probes/pkce-challenge-shape.mjs +58 -0
  434. package/blueprints/security-auth-oauth2/contributions/probes/probe-utils.mjs +190 -0
  435. package/blueprints/security-auth-oauth2/contributions/probes/provider-adapter-shape.mjs +64 -0
  436. package/blueprints/security-auth-oauth2/contributions/probes/real-account-authorisation-code-flow.mjs +93 -0
  437. package/blueprints/security-auth-oauth2/contributions/probes/run-authorisation-code-flow-shape.mjs +4 -0
  438. package/blueprints/security-auth-oauth2/contributions/probes/run-pkce-challenge-shape.mjs +4 -0
  439. package/blueprints/security-auth-oauth2/contributions/probes/run-provider-adapter-shape.mjs +4 -0
  440. package/blueprints/security-auth-oauth2/contributions/probes/run-real-account-authorisation-code-flow.mjs +4 -0
  441. package/blueprints/security-auth-oauth2/contributions/probes/run-session-bridge-shape.mjs +4 -0
  442. package/blueprints/security-auth-oauth2/contributions/probes/session-bridge-shape.mjs +78 -0
  443. package/blueprints/security-auth-oauth2/docs/topics.md +1 -2
  444. package/blueprints/security-secrets-management/CHANGELOG.md +15 -4
  445. package/blueprints/security-secrets-management/README.md +2 -2
  446. package/blueprints/security-secrets-management/blueprint.json +3 -2
  447. package/blueprints/security-secrets-management/contributions/probes/add-recipient-rotation.mjs +107 -0
  448. package/blueprints/security-secrets-management/contributions/probes/encrypt-decrypt-round-trip.mjs +122 -0
  449. package/blueprints/security-secrets-management/contributions/probes/key-rotation.mjs +93 -0
  450. package/blueprints/security-secrets-management/contributions/probes/mismatched-key-refusal.mjs +74 -0
  451. package/blueprints/security-secrets-management/contributions/probes/probe-utils.mjs +214 -0
  452. package/blueprints/security-secrets-management/contributions/probes/run-add-recipient-rotation.mjs +4 -0
  453. package/blueprints/security-secrets-management/contributions/probes/run-encrypt-decrypt-round-trip.mjs +4 -0
  454. package/blueprints/security-secrets-management/contributions/probes/run-key-rotation.mjs +4 -0
  455. package/blueprints/security-secrets-management/contributions/probes/run-mismatched-key-refusal.mjs +4 -0
  456. package/blueprints/security-secrets-management/docs/topics.md +2 -3
  457. package/fixtures/canary-manifest.json +9 -9
  458. package/guidance/harness-template.md +25 -0
  459. package/guidance/managed/agent-instructions-block.hash +1 -1
  460. package/guidance/managed/agent-instructions-block.md +25 -0
  461. package/package.json +2 -2
  462. package/rcf/adrs/adr-4101-feedback-store-gitignored.json +20 -0
  463. package/rcf/adrs/adr-4102-fingerprint-and-labels.json +25 -0
  464. package/rcf/adrs/adr-4103-redaction-rule-based.json +20 -0
  465. package/rcf/adrs/adr-4104-destination-on-library.json +25 -0
  466. package/rcf/adrs/adr-4105-gh-ambient-auth.json +20 -0
  467. package/rcf/adrs/adr-4106-bundled-entries-terminal.json +20 -0
  468. package/rcf/adrs/adr-4107-stop-is-ask-event.json +30 -0
  469. package/rcf/adrs/adr-4108-hooks-in-committed-config.json +25 -0
  470. package/rcf/adrs/adr-4109-referee-validate-adr-crosslinks.json +25 -0
  471. package/rcf/adrs/adr-4110-referee-coverage-strict-by-default.json +25 -0
  472. package/rcf/adrs/adr-4111-referee-finalise-refusals.json +20 -0
  473. package/rcf/adrs/adr-4112-referee-finalise-verified-invariant.json +30 -0
  474. package/rcf/code-nodes/cn-600.json +45 -0
  475. package/rcf/code-nodes/cn-601.json +18 -0
  476. package/rcf/code-nodes/cn-602.json +15 -0
  477. package/rcf/code-nodes/cn-603.json +12 -0
  478. package/rcf/code-nodes/cn-604.json +14 -0
  479. package/rcf/code-nodes/cn-605.json +17 -0
  480. package/rcf/code-nodes/cn-606.json +12 -0
  481. package/rcf/code-nodes/cn-607.json +12 -0
  482. package/rcf/code-nodes/cn-608.json +14 -0
  483. package/rcf/code-nodes/cn-609.json +17 -0
  484. package/rcf/code-nodes/cn-620.json +18 -0
  485. package/rcf/code-nodes/cn-621.json +14 -0
  486. package/rcf/code-nodes/cn-622.json +15 -0
  487. package/rcf/code-nodes/cn-623.json +16 -0
  488. package/rcf/code-nodes/cn-624.json +14 -0
  489. package/rcf/code-nodes/cn-625.json +15 -0
  490. package/rcf/code-nodes/cn-626.json +13 -0
  491. package/rcf/code-nodes/cn-627.json +13 -0
  492. package/rcf/code-nodes/cn-628.json +14 -0
  493. package/rcf/code-nodes/cn-629.json +12 -0
  494. package/rcf/code-nodes/cn-630.json +12 -0
  495. package/rcf/code-nodes/cn-631.json +13 -0
  496. package/rcf/code-nodes/cn-632.json +13 -0
  497. package/rcf/fbs/fbs-180.json +45 -0
  498. package/rcf/fbs/fbs-181.json +45 -0
  499. package/rcf/fbs/fbs-182.json +42 -0
  500. package/rcf/fbs/fbs-183.json +50 -0
  501. package/rcf/fbs/fbs-184.json +49 -0
  502. package/rcf/fbs/fbs-185.json +34 -0
  503. package/rcf/fbs/fbs-186.json +16 -0
  504. package/rcf/fbs/fbs-187.json +17 -0
  505. package/rcf/fbs/fbs-188.json +17 -0
  506. package/rcf/fbs/fbs-189.json +17 -0
  507. package/rcf/requirements/req-155.json +13 -0
  508. package/rcf/requirements/req-156.json +13 -0
  509. package/rcf/requirements/req-157.json +13 -0
  510. package/rcf/requirements/req-158.json +13 -0
  511. package/rcf/requirements/req-159.json +13 -0
  512. package/rcf/requirements/req-160.json +13 -0
  513. package/rcf/requirements/req-161.json +13 -0
  514. package/rcf/requirements/req-162.json +13 -0
  515. package/rcf/requirements/req-163.json +13 -0
  516. package/rcf/requirements/req-164.json +13 -0
  517. package/rcf/requirements/req-165.json +13 -0
  518. package/rcf/tacs/tac-4101-feedback-cli.json +77 -0
  519. package/rcf/tacs/tac-4102-feedback-store.json +50 -0
  520. package/rcf/tacs/tac-4103-feedback-redact.json +39 -0
  521. package/rcf/tacs/tac-4104-feedback-fingerprint.json +33 -0
  522. package/rcf/tacs/tac-4105-feedback-render.json +45 -0
  523. package/rcf/tacs/tac-4106-feedback-destination.json +39 -0
  524. package/rcf/tacs/tac-4107-feedback-gh.json +43 -0
  525. package/rcf/tacs/tac-4108-feedback-hook.json +46 -0
  526. package/rcf/tacs/tac-4109-referee-validate-adr-crosslinks.json +20 -0
  527. package/rcf/tacs/tac-4110-referee-coverage-mode-selector.json +21 -0
  528. package/rcf/tacs/tac-4111-referee-finalise-per-ac-refusals.json +21 -0
  529. package/rcf/tacs/tac-4112-referee-finalise-verified-invariant.json +22 -0
  530. package/rcf/test-suites/ts-140.json +9 -9
  531. package/rcf/test-suites/ts-150.json +9 -9
  532. package/rcf/test-suites/ts-185.json +54 -0
  533. package/rcf/test-suites/ts-186.json +58 -0
  534. package/rcf/test-suites/ts-187.json +44 -0
  535. package/rcf/test-suites/ts-188.json +166 -0
  536. package/rcf/test-suites/ts-189.json +38 -0
  537. package/rcf/test-suites/ts-190.json +30 -0
  538. package/rcf/test-suites/ts-191.json +51 -0
  539. package/rcf/test-suites/ts-192.json +37 -0
  540. package/rcf/test-suites/ts-193.json +60 -0
  541. package/rcf/test-suites/ts-194.json +67 -0
  542. package/rcf/test-suites/ts-195.json +52 -0
  543. package/rcf/test-suites/ts-196.json +58 -0
  544. package/rcf/test-suites/ts-197.json +66 -0
  545. package/rcf/test-suites/ts-198.json +87 -0
  546. package/rcf/test-suites/ts-199.json +51 -0
  547. package/rcf/test-suites/ts-200.json +30 -0
  548. package/rcf/test-suites/ts-201.json +38 -0
  549. package/rcf/test-suites/ts-202.json +38 -0
  550. package/rcf/test-suites/ts-203.json +38 -0
  551. package/rcf/user-stories/us-15501.json +60 -0
  552. package/rcf/user-stories/us-15502.json +33 -0
  553. package/rcf/user-stories/us-15503.json +33 -0
  554. package/rcf/user-stories/us-15601.json +51 -0
  555. package/rcf/user-stories/us-15701.json +42 -0
  556. package/rcf/user-stories/us-15801.json +42 -0
  557. package/rcf/user-stories/us-15802.json +33 -0
  558. package/rcf/user-stories/us-15901.json +33 -0
  559. package/rcf/user-stories/us-15902.json +51 -0
  560. package/rcf/user-stories/us-16001.json +51 -0
  561. package/rcf/user-stories/us-16101.json +42 -0
  562. package/rcf/user-stories/us-16102.json +33 -0
  563. package/rcf/user-stories/us-16103.json +42 -0
  564. package/rcf/user-stories/us-16104.json +42 -0
  565. package/rcf/user-stories/us-16201.json +33 -0
  566. package/rcf/user-stories/us-16301.json +36 -0
  567. package/rcf/user-stories/us-16401.json +45 -0
  568. package/rcf/user-stories/us-16501.json +45 -0
  569. package/rcf/user-stories/us-16502.json +45 -0
  570. package/releases/releases.yaml +11 -1
  571. package/src/blueprint/library-loader.js +48 -0
  572. package/src/blueprint/library-registry.js +13 -0
  573. package/src/browser-verify/pack-runner.js +7 -12
  574. package/src/build/mark.js +1 -1
  575. package/src/cli/blueprint-library.js +149 -0
  576. package/src/cli/coverage.js +49 -24
  577. package/src/cli/doctor.js +195 -7
  578. package/src/cli/feedback.js +2204 -0
  579. package/src/cli/finalise.js +158 -1
  580. package/src/cli/help.js +6 -0
  581. package/src/cli/init.js +63 -0
  582. package/src/cli/update.js +21 -1
  583. package/src/core/store/walker.js +33 -0
  584. package/src/core/store/writer.js +23 -0
  585. package/src/feedback/destination.js +361 -0
  586. package/src/feedback/fingerprint.js +132 -0
  587. package/src/feedback/gh.js +376 -0
  588. package/src/feedback/hook.js +183 -0
  589. package/src/feedback/labels.js +87 -0
  590. package/src/feedback/redact-allowlist.json +14 -0
  591. package/src/feedback/redact.js +1108 -0
  592. package/src/feedback/render.js +267 -0
  593. package/src/feedback/store.js +604 -0
  594. package/src/finalise/index.js +4 -0
  595. package/src/finalise/ingest.js +61 -0
  596. package/src/finalise/ship-without-eval.js +19 -7
  597. package/src/mcp/tools.js +8 -2
  598. package/src/setup/feedback-hooks.js +397 -0
  599. package/src/setup/managed-gitignore.js +3 -0
  600. package/src/view/html-page.js +5 -5
  601. package/src/view/style.css +2 -2
@@ -0,0 +1,53 @@
1
+ // Role-model adapter probe for security-auth-clerk.
2
+ // Conformance-only. Every row records anchorAcId=null with a
3
+ // limitation naming the shipped AC whose can/assert project-verb
4
+ // adapter behaviour the fixture-layer probe does not observe. The
5
+ // integration harness follow-up exercises the adapter against a
6
+ // verified session token.
7
+ //
8
+ // capability: roleModel. engine: fixture. accountBound: false.
9
+
10
+ import { pathToFileURL } from 'node:url';
11
+ import { resolve, dirname } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { deClaim } from './probe-utils.mjs';
14
+
15
+ const HERE = dirname(fileURLToPath(import.meta.url));
16
+ const FIXTURE_SRC = resolve(HERE, '..', '..', '..', '..', 'packages', 'rcf-lite', 'test', 'fixtures', 'security-auth-clerk', 'src');
17
+
18
+ export const anchorAcId = null;
19
+ export const capability = 'roleModel';
20
+ export const accountBound = false;
21
+
22
+ const LIM = 'security-auth-clerk-AC-9107-1: probe checks raw-role reduction only; the AC states the can/assert adapter refuses a role token absent from the project verb list against a verified session, which needs the integration harness (the auth integration harness follow-up).';
23
+
24
+ export default async function runProbe() {
25
+ const { mapRoles, knownRoles } = await import(pathToFileURL(resolve(FIXTURE_SRC, 'role-adapter.mjs')).href);
26
+ const results = [];
27
+
28
+ const good = mapRoles({ roles: ['viewer', 'admin'] });
29
+ results.push(deClaim({
30
+ capability,
31
+ verdict: good.ok && good.roles.join(',') === 'viewer,admin' ? 'pass' : 'fail',
32
+ detail: `known-role mapping: ok=${good.ok} roles=${JSON.stringify(good.roles)}; knownRoles=${JSON.stringify(knownRoles)}`,
33
+ evidence: { input: ['viewer', 'admin'], output: good.roles, adapterReturn: good },
34
+ }, { ac: 'security-auth-clerk-AC-9107-1', limitation: LIM }));
35
+
36
+ const bad = mapRoles({ roles: ['viewer', 'root-emperor'] });
37
+ results.push(deClaim({
38
+ capability,
39
+ verdict: !bad.ok && /root-emperor/.test(bad.error) ? 'pass' : 'fail',
40
+ detail: `unknown-role refusal: ok=${bad.ok} error=${JSON.stringify(bad.error)}`,
41
+ evidence: { input: ['viewer', 'root-emperor'], adapterReturn: bad },
42
+ }, { ac: 'security-auth-clerk-AC-9107-1', limitation: LIM }));
43
+
44
+ const bad2 = mapRoles({ roles: 'admin' });
45
+ results.push(deClaim({
46
+ capability,
47
+ verdict: !bad2.ok && /must be an array/.test(bad2.error) ? 'pass' : 'fail',
48
+ detail: `non-array-refusal: ok=${bad2.ok} error=${JSON.stringify(bad2.error)}`,
49
+ evidence: { input: 'admin', adapterReturn: bad2 },
50
+ }, { ac: 'security-auth-clerk-AC-9107-1', limitation: LIM }));
51
+
52
+ return { results, extra: {} };
53
+ }
@@ -0,0 +1,4 @@
1
+ import runProbe from './hosted-identity-ui-config.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+ const engine = { kind: 'fixture', image: 'fixture hosted-ui-config validator (local)', healthy: true };
4
+ runShim('hosted-identity-ui-config', engine, runProbe);
@@ -0,0 +1,4 @@
1
+ import runProbe from './real-account-principal-directory-round-trip.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+ const engine = { kind: 'clerk-backend-api', image: 'live Clerk Backend API via https (or skipped)', healthy: true };
4
+ runShim('real-account-principal-directory-round-trip', engine, runProbe);
@@ -0,0 +1,4 @@
1
+ import runProbe from './real-account-session-inventory.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+ const engine = { kind: 'clerk-backend-api', image: 'live Clerk Backend API sessions endpoint via https (or skipped)', healthy: true };
4
+ runShim('real-account-session-inventory', engine, runProbe);
@@ -0,0 +1,4 @@
1
+ import runProbe from './role-model-adapter.mjs';
2
+ import { runShim } from './probe-utils.mjs';
3
+ const engine = { kind: 'fixture', image: 'fixture role-adapter (local)', healthy: true };
4
+ runShim('role-model-adapter', engine, runProbe);
@@ -14,7 +14,7 @@ Rules for new topics (inherited from the application-spa, application-api-rest,
14
14
 
15
15
  ## Id number bands (registry bootstrap)
16
16
 
17
- AC ids (and therefore US numeric ids, which anchor them) are NOT namespaced by the 0.4.4 schema grammar; the band allocation IS the AC-collision enforcement mechanism. Composing blueprints take a fresh band rather than proposing namespaced AC ids. Band allocation is ratified policy (2026-08-19); this table is the shared registry-bootstrap replicated across every shipped and forthcoming blueprint's `docs/topics.md` until a mechanism-side central registry lands (v1.1 candidate).
17
+ AC ids (and therefore US numeric ids, which anchor them) are NOT namespaced by the 0.4.4 schema grammar; the band allocation IS the AC-collision enforcement mechanism. Composing blueprints take a fresh band rather than proposing namespaced AC ids. Band allocation is policy; this table is the shared registry-bootstrap replicated across every shipped and forthcoming blueprint's `docs/topics.md` until a mechanism-side central registry lands (v1.1 candidate).
18
18
 
19
19
  This table is maintained shelf-wide across every blueprint's `docs/topics.md`. Rows are recorded at ship, never predicted.
20
20
 
@@ -59,8 +59,7 @@ This table is maintained shelf-wide across every blueprint's `docs/topics.md`. R
59
59
  | platform-docker-compose-host | 38101-38899 | 39xx | shipped v1.0.0 | `containerHostContract` |
60
60
  | edge-cloudflare-tunnel | 39101-39899 | 40xx | shipped v1.0.0 | `edgeIngressBridge` |
61
61
 
62
- US 9101-9110 sit at the LOW end of the 9101-9899 band on purpose. A project-side story that mechanically derives from a security-auth-clerk REQ id into the number `9110` would collide against security-auth-clerk-US-9110 in this package; the band leaves headroom at the HIGH end (US 9181-9899) so a project's own stories anchored to security-auth-clerk REQs can allocate without conflict. The watchpost run4 lesson applies here too.
63
-
62
+ US 9101-9110 sit at the LOW end of the 9101-9899 band on purpose. A project-side story that mechanically derives from a security-auth-clerk REQ id into the number `9110` would collide against security-auth-clerk-US-9110 in this package; the band leaves headroom at the HIGH end (US 9181-9899) so a project's own stories anchored to security-auth-clerk REQs can allocate without conflict.
64
63
  ADR and TAC suffixes for this blueprint widen to four digits (1001-1099) because the three-digit space fills at 9xx (security-secrets-management). Sibling round-2 auth blueprints (security-auth-oauth2, security-auth-keycloak) will continue the widening at 1101-1199 and 1201-1299 respectively; the shipped shelf has not carried four-digit suffixes before this blueprint, so the fallback rule on this PR's cover note applies if the rcf-schemas grammar refuses that shape.
65
64
 
66
65
  ## Shared expectations for future composing blueprints
@@ -1,23 +1,34 @@
1
1
  # security-auth-keycloak CHANGELOG
2
2
 
3
- ## 1.4.1
3
+ ## 1.4.4 - 2026-09-11
4
+
5
+ - Criterion-e probe pack refinement: every conformance-only result row now records `anchorAcId: null` alongside a `limitation` that opens with a shipped AC id from the blueprint's user stories (introspection `REQ-004` rows move to `AC-11105-1`; JWT `REQ-003` row moves to `AC-11104-2`; role-adapter `REQ-006` row moves to `AC-11107-3`). The retained live-branch anchor on `real-account-realm-round-trip` (`AC-11112-2`) is unchanged and honest-skips on `CI_HAS_KEYCLOAK_ACCOUNT`; when skipped the row records `engine: keycloak`, not `engine: skip:...`. Detail strings on de-claimed rows describe only what was observed at the fixture-parser or fixture-verifier surface and no longer claim a REQ or AC as observed end to end. The anatomy helper enforces conformance-only rows to satisfy `anchorAcId === null`, requires limitations to open with an `AC-<n>-<n>` id that resolves to a shipped acceptance criterion on the blueprint's user stories (REQ-prefixed anchors are refused and fabricated ids are rejected), and does not count pre-delete presence as an absence observation on the inventory-diff shape.
6
+
7
+ ## 1.4.3 - 2026-09-11
8
+
9
+ - Every conformance-only anchor on the criterion-e probe pack is de-claimed to `conformanceOnly` with a limitation naming the shipped AC that is observable only in the integration harness follow-up; the retained live-branch anchor on `real-account-realm-round-trip` (`AC-11112-2`) is preserved and honest-skips on `CI_HAS_KEYCLOAK_ACCOUNT`. `discovery-shape`, `jwt-verifier-shape`, `introspection-shape` and `role-adapter-shape` rows keep their fixture-layer observations under the same shape.
4
10
 
5
- - Closure fix pass (F-8): rewrites the `README.md` shelf-latest line in neutral customer-facing voice with no spec-provenance label.
11
+ ## 1.4.2 - 2026-09-11
12
+
13
+ - Added a criterion-e probe pack (`contributions/probes/`) covering the four declared capabilities: `discovery-shape` (principalDirectory; OIDC discovery URL derivation and validator), `jwt-verifier-shape` (credentialSelfService; node:crypto RS256 sign+verify with alg/exp/iss/signature-tamper refusal paths on throwaway keys), `introspection-shape` (sessionInventory; RFC 7662 request/response shape), `role-adapter-shape` (roleModel; realm+resource-access role mapper). `real-account-realm-round-trip` (LIVE) honest-skips on `CI_HAS_KEYCLOAK_ACCOUNT` because this estate does not expose a Keycloak client to shelf probes. Fixture at `packages/rcf-lite/test/fixtures/security-auth-keycloak/` declares every env var the pack reads; anatomy test pins pack shape, fixture manifest and the account-bound skip contract.
14
+ - Iteration on the probe pack labelled every local-fixture row `engine: fixture`, redacted the placeholder client secret out of the introspection body evidence, and settled `aggregate([])` / null-result normalisation to `detail: 'no checks ran'` exactly. `real-account-realm-round-trip` honest-skips on `CI_HAS_KEYCLOAK_ACCOUNT`; when skipped the record's `engine.kind` remains `keycloak`. Slug reads AMBER on criterion e.
15
+
16
+ ## 1.4.1
6
17
 
7
18
  ## 1.4.0
8
19
 
9
20
  - Adds `US-11116`, `US-11117`, `US-11118`, `US-11119`, `US-11120` binding stories to the five audit-surface must requirements `REQ-015` (discovery and account-console), `REQ-016` (JWT), `REQ-017` (introspection), `REQ-018` (route and sessionInventory), and `REQ-019` (roles). Each story ships one AC per success, refusal, retry and boundary path on the delivering mechanism, with `ownerRef` at the owning TAC and its audit-emission responsibility. Rewrites `US-11115` `AC-1` to reference the local `TAC-1204-security-auth-keycloak-provider-router` `responsibilities.sessionInventory` and updates the sibling ACs to the same local owner (the interface shape remains owned by `TAC-1003-security-auth-clerk-session-verifier` `interfaces.sessionInventory` and is referenced by that owner id). Rewrites `REQ-005.description` to reference `TAC-1204-security-auth-keycloak-provider-router` `responsibilities.route` rather than restate the `{ realmSlug, verificationMode }` shape verbatim.
10
- - Closure fixes on the audit stories: extends `TAC-1201` with a named `discoveryAudit` responsibility and repoints `REQ-015.deliveredBy` and every `US-11116` `ownerRef` at it; tightens the refusal oracles on `AC-11116-2`, `AC-11117-2`, and `AC-11118-2` from a category or example to a specific input-to-reasonClass binding; adds an idempotency AC to `US-11116`, `US-11117`, `US-11118`, `US-11119`, `US-11120` naming the event count per repeat call; adds `AC-11118-5` (non-2xx `upstream_error` path), `AC-11119-5` (revoke-one), `AC-11119-6` (revoke-all-except-current) so every named `REQ-018` interaction is independently bound; adds a 7a inline note in each audit story's `description` documenting the credential and permission scenario-class mapping (bound to an AC, or not applicable with the reason).
11
- - Second closure fix pass: adds explicit credential and permission acceptance criteria on every audit-event story where they were previously carried as prose only. Adds `AC-11116-6` (credential: realm-config `realmSlug` is the credential the discovery fetch is bound to and the event records the realm principal in the `realmSlug` payload field) and `AC-11116-7` (permission: `accountConsoleUrl` origin that differs from the discovered issuer origin is refused with `reasonClass=account_console_malformed`). Adds `AC-11117-6` (permission: `audience_mismatch` binds the audience-scope refusal) and `AC-11117-7` (issuer_mismatch), so every `REQ-016` named refusal reason is bound to a concrete AC. Tightens `AC-11118-3` to name `reasonClass=upstream_error` as the concrete 503-retry oracle and adds `AC-11118-7` (permission: an upstream `401 Unauthorized` on the client credentials is refused with `reasonClass=client_forbidden`). Adds `AC-11120-6` (permission: an absent role-claim path is refused with `reasonClass=roles_absent`). Updates each story's `description` 7a inline note to reference the new ACs and removes every "not applicable" clause the ACs replace.
21
+ - On the audit stories: extends `TAC-1201` with a named `discoveryAudit` responsibility and repoints `REQ-015.deliveredBy` and every `US-11116` `ownerRef` at it; tightens the refusal oracles on `AC-11116-2`, `AC-11117-2`, and `AC-11118-2` from a category or example to a specific input-to-reasonClass binding; adds an idempotency AC to `US-11116`, `US-11117`, `US-11118`, `US-11119`, `US-11120` naming the event count per repeat call; adds `AC-11118-5` (non-2xx `upstream_error` path), `AC-11119-5` (revoke-one), `AC-11119-6` (revoke-all-except-current) so every named `REQ-018` interaction is independently bound; adds a 7a inline note in each audit story's `description` documenting the credential and permission scenario-class mapping (bound to an AC, or not applicable with the reason).
22
+ - Adds explicit credential and permission acceptance criteria on every audit-event story where they were previously carried as prose only. Adds `AC-11116-6` (credential: realm-config `realmSlug` is the credential the discovery fetch is bound to and the event records the realm principal in the `realmSlug` payload field) and `AC-11116-7` (permission: `accountConsoleUrl` origin that differs from the discovered issuer origin is refused with `reasonClass=account_console_malformed`). Adds `AC-11117-6` (permission: `audience_mismatch` binds the audience-scope refusal) and `AC-11117-7` (issuer_mismatch), so every `REQ-016` named refusal reason is bound to a concrete AC. Tightens `AC-11118-3` to name `reasonClass=upstream_error` as the concrete 503-retry oracle and adds `AC-11118-7` (permission: an upstream `401 Unauthorized` on the client credentials is refused with `reasonClass=client_forbidden`). Adds `AC-11120-6` (permission: an absent role-claim path is refused with `reasonClass=roles_absent`). Updates each story's `description` 7a inline note to reference the new ACs and removes every "not applicable" clause the ACs replace.
12
23
 
13
24
  ## 1.3.1 (register-sweep patch, 2026-09-10)
14
25
 
15
26
  - Register: neutral wording in shipped prose (no capability change).
16
27
 
17
- ## 1.3.0 (hardening pass, spec 2026-09-09 section 5.4.2)
28
+ ## 1.3.0 (2026-09-09)
18
29
 
19
- - Adds `REQ-013`/`US-11114` (credentialSelfService: realm-config `accountConsoleUrl`, boot-time verification, `getCredentialSelfServiceUrl` helper), `REQ-014`/`US-11115` (sessionInventory: list, revoke-one, revoke-all-except-current, unauthenticated refusal, unknown-session refusal), and `REQ-015` (cross-cutting audit surface with a fixed field allow-list, token exclusion, and sink-failure posture). Adds a composition clause on `REQ-001` naming `security-auth-oauth2` as the required flow-controller and session-bridge owner. Extends `TAC-1201` with the account-console verification responsibility and `TAC-1204` with the sessionInventory responsibility. Adds `elicits[]` for `bootPosture` (strict/deferred/standby) and `verificationMode` (jwks/introspection) already described in prose. Adds `deliveredBy` on every `must` requirement and `disposition` on every existing acceptance criterion; adds `ownerRef` on ACs that observe interfaces owned by other TACs. Names the `principalDirectory` and `roleModel` capabilities on the requirements that carry their runtime clauses. hardening pass (criteria a, b, c on the 2026-09-09 programme).
20
- - Review fix pass (PR #188 findings): moves the composition requirement from a REQ-level `requiresAppliedCapabilities` array (a level the apply gate never reads) to a `blueprint.json:requiresAppliedCapabilities` gate on `authorisationCodeFlow` with override `--allow-no-auth-yet` and stable id `security-auth-keycloak-flow-required`; `REQ-001` now points at that manifest gate. Narrows `REQ-015` to the discovery-client and account-console audit families (TAC-1201) and adds four must REQs (`REQ-016` JWT, `REQ-017` introspection, `REQ-018` route + sessionInventory, `REQ-019` roles), each with its own `deliveredBy` and a companion audit responsibility line on the target TAC. Rewrites `US-11115` `AC-1` to reference the `TAC-1003-security-auth-clerk-session-verifier.interfaces.sessionInventory` `SessionRow` shape rather than restating its fields.
30
+ - Adds `REQ-013`/`US-11114` (credentialSelfService: realm-config `accountConsoleUrl`, boot-time verification, `getCredentialSelfServiceUrl` helper), `REQ-014`/`US-11115` (sessionInventory: list, revoke-one, revoke-all-except-current, unauthenticated refusal, unknown-session refusal), and `REQ-015` (cross-cutting audit surface with a fixed field allow-list, token exclusion, and sink-failure posture). Adds a composition clause on `REQ-001` naming `security-auth-oauth2` as the required flow-controller and session-bridge owner. Extends `TAC-1201` with the account-console verification responsibility and `TAC-1204` with the sessionInventory responsibility. Adds `elicits[]` for `bootPosture` (strict/deferred/standby) and `verificationMode` (jwks/introspection) already described in prose. Adds `deliveredBy` on every `must` requirement and `disposition` on every existing acceptance criterion; adds `ownerRef` on ACs that observe interfaces owned by other TACs. Names the `principalDirectory` and `roleModel` capabilities on the requirements that carry their runtime clauses.
31
+ - Moves the composition requirement from a REQ-level `requiresAppliedCapabilities` array (a level the apply gate never reads) to a `blueprint.json:requiresAppliedCapabilities` gate on `authorisationCodeFlow` with override `--allow-no-auth-yet` and stable id `security-auth-keycloak-flow-required`; `REQ-001` now points at that manifest gate. Narrows `REQ-015` to the discovery-client and account-console audit families (TAC-1201) and adds four must REQs (`REQ-016` JWT, `REQ-017` introspection, `REQ-018` route + sessionInventory, `REQ-019` roles), each with its own `deliveredBy` and a companion audit responsibility line on the target TAC. Rewrites `US-11115` `AC-1` to reference the `TAC-1003-security-auth-clerk-session-verifier.interfaces.sessionInventory` `SessionRow` shape rather than restating its fields.
21
32
 
22
33
  ## 1.2.0 (visual round, spec 2026-09-06 section 5.4.2, operator Q2 default)
23
34
 
@@ -33,9 +33,9 @@ The doc set is contributions (copied into the project tree by `rcf define bluepr
33
33
 
34
34
  ## What it contributes, and what it deliberately does not
35
35
 
36
- Contributed kinds: REQ, US (with inline ACs), TAC, ADR. Adherence is expressed as ACs; the blueprint ships no test files (ratified decision 5) and no code.
36
+ Contributed kinds: REQ, US (with inline ACs), TAC, ADR. Adherence is expressed as ACs; the blueprint ships no test files (shipped policy 5) and no code.
37
37
 
38
- No FBS contributions, as a matter of principle (ratified policy 2026-08-19): FBSs are the work of the implementing agent, not the blueprint; project constraints have to be applied at the time of creation. The blueprint contributes the WHAT (the Keycloak realm as identity source, the OIDC discovery contract, the JWKS-with-rotation-cache verification path, the RFC 7662 introspection path, the provider-routing seam, the Keycloak client-roles / realm-roles claim shape, the refresh-and-sign-out posture inherited from the realm, the session-vs-token separation, the local-first stand-up shape, the fail-safe boot postures, the runtime-verify posture with accountBound cloud smokes); the implementing agent derives the HOW-tasks (FBS) in the host project.
38
+ No FBS contributions, as a matter of principle (policy): FBSs are the work of the implementing agent, not the blueprint; project constraints have to be applied at the time of creation. The blueprint contributes the WHAT (the Keycloak realm as identity source, the OIDC discovery contract, the JWKS-with-rotation-cache verification path, the RFC 7662 introspection path, the provider-routing seam, the Keycloak client-roles / realm-roles claim shape, the refresh-and-sign-out posture inherited from the realm, the session-vs-token separation, the local-first stand-up shape, the fail-safe boot postures, the runtime-verify posture with accountBound cloud smokes); the implementing agent derives the HOW-tasks (FBS) in the host project.
39
39
 
40
40
  Deliberately not contributed: the OAuth2 authorisation-code flow controller itself (a project either draws it from the sibling `security-auth-oauth2` blueprint or authors one above this blueprint's five TACs; the Keycloak-committed decisions here bind the flow controller's provider adapter to a Keycloak realm and no more); a specific HTTP framework adapter (the middleware wiring is framework-agnostic; framework adapters are a project responsibility); a specific session-record store (opaque-handle mode injects it; in-memory is the reference default; a persistence-composed project points at a table); MFA specifics (Keycloak owns MFA at the realm surface); real realm data (a placeholder `example` realm name is the shape; no lifted config); any specific second identity provider (the provider-routing seam is generic; the blueprint does not name a second issuer, per the ratified reshape ruling).
41
41
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "slug": "security-auth-keycloak",
3
- "version": "1.4.1",
3
+ "version": "1.4.4",
4
4
  "category": "security",
5
5
  "requiresAppliedCapabilities": {
6
6
  "capabilities": [
@@ -291,5 +291,6 @@
291
291
  "introspection"
292
292
  ]
293
293
  }
294
- ]
294
+ ],
295
+ "updatedAt": "2026-09-11T15:37:12.000Z"
295
296
  }
@@ -0,0 +1,68 @@
1
+ // OIDC discovery-URL derivation and document-shape probe for
2
+ // security-auth-keycloak. Conformance-only. Every row records
3
+ // anchorAcId=null with a limitation naming the shipped AC whose
4
+ // boot-time fetch/population/refusal property the fixture discovery
5
+ // client does not observe. The integration harness follow-up is
6
+ // the surface where the AC-level properties become observable.
7
+ //
8
+ // capability: principalDirectory. engine: fixture. accountBound: false.
9
+
10
+ import { pathToFileURL } from 'node:url';
11
+ import { resolve, dirname } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { deClaim } from './probe-utils.mjs';
14
+
15
+ const HERE = dirname(fileURLToPath(import.meta.url));
16
+ const FIXTURE_SRC = resolve(HERE, '..', '..', '..', '..', 'packages', 'rcf-lite', 'test', 'fixtures', 'security-auth-keycloak', 'src');
17
+
18
+ export const anchorAcId = null;
19
+ export const capability = 'principalDirectory';
20
+ export const accountBound = false;
21
+
22
+ const LIM_URL = 'security-auth-keycloak-AC-11102-1: probe checks URL derivation and doc-shape refusal only; the AC states the boot-time discovery fetch fills a cache read at request time, which needs a real Keycloak realm and boot lifecycle (auth integration harness follow-up).';
23
+ const LIM_REFUSAL = 'security-auth-keycloak-AC-11102-3: probe checks validator refusal only; the AC states the boot itself refuses when the discovery document is malformed, which needs the boot lifecycle (auth integration harness follow-up).';
24
+
25
+ export default async function runProbe() {
26
+ const { buildDiscoveryUrl, validateDiscoveryDocument } = await import(pathToFileURL(resolve(FIXTURE_SRC, 'discovery-client.mjs')).href);
27
+ const results = [];
28
+
29
+ const built = buildDiscoveryUrl({ baseUrl: 'https://keycloak.example.com/', realm: 'example-realm' });
30
+ const expected = 'https://keycloak.example.com/realms/example-realm/.well-known/openid-configuration';
31
+ results.push(deClaim({
32
+ capability,
33
+ verdict: built.ok && built.discoveryUrl === expected ? 'pass' : 'fail',
34
+ detail: `discovery URL construction (well-formed input): ok=${built.ok} url=${built.discoveryUrl}`,
35
+ evidence: { input: { baseUrl: 'https://keycloak.example.com/', realm: 'example-realm' }, adapterReturn: built },
36
+ }, { ac: 'security-auth-keycloak-AC-11102-1', limitation: LIM_URL }));
37
+
38
+ const insecure = buildDiscoveryUrl({ baseUrl: 'http://insecure.example.com', realm: 'example-realm' });
39
+ results.push(deClaim({
40
+ capability,
41
+ verdict: !insecure.ok && /must be https/.test(insecure.error) ? 'pass' : 'fail',
42
+ detail: `insecure baseUrl refusal: ok=${insecure.ok} error=${JSON.stringify(insecure.error)}`,
43
+ evidence: { adapterReturn: insecure },
44
+ }, { ac: 'security-auth-keycloak-AC-11102-1', limitation: LIM_URL }));
45
+
46
+ const missing = validateDiscoveryDocument({ issuer: 'x', authorization_endpoint: 'x' });
47
+ results.push(deClaim({
48
+ capability,
49
+ verdict: !missing.ok && /missing required fields/.test(missing.error) ? 'pass' : 'fail',
50
+ detail: `doc-shape missing-fields refusal: ok=${missing.ok} error=${JSON.stringify(missing.error)}`,
51
+ evidence: { validatorReturn: missing },
52
+ }, { ac: 'security-auth-keycloak-AC-11102-3', limitation: LIM_REFUSAL }));
53
+
54
+ const good = validateDiscoveryDocument({
55
+ issuer: 'https://kc.example.com/realms/dev',
56
+ authorization_endpoint: 'https://kc.example.com/realms/dev/protocol/openid-connect/auth',
57
+ token_endpoint: 'https://kc.example.com/realms/dev/protocol/openid-connect/token',
58
+ jwks_uri: 'https://kc.example.com/realms/dev/protocol/openid-connect/certs',
59
+ });
60
+ results.push(deClaim({
61
+ capability,
62
+ verdict: good.ok ? 'pass' : 'fail',
63
+ detail: `well-formed doc passes validation: ok=${good.ok} endpoints=${JSON.stringify(good.endpoints || good.error)}`,
64
+ evidence: { validatorReturn: good },
65
+ }, { ac: 'security-auth-keycloak-AC-11102-1', limitation: LIM_URL }));
66
+
67
+ return { results, extra: {} };
68
+ }
@@ -0,0 +1,88 @@
1
+ // RFC 7662 introspection request/response shape probe for
2
+ // security-auth-keycloak. Conformance-only. Every row records
3
+ // anchorAcId=null with a limitation naming the shipped AC whose
4
+ // HTTP introspection round-trip the fixture parser observation does
5
+ // not exercise. The integration harness follow-up is the surface
6
+ // where the AC-level properties become observable.
7
+ //
8
+ // capability: sessionInventory. engine: fixture. accountBound: false.
9
+
10
+ import { pathToFileURL } from 'node:url';
11
+ import { resolve, dirname } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { deClaim } from './probe-utils.mjs';
14
+
15
+ const HERE = dirname(fileURLToPath(import.meta.url));
16
+ const FIXTURE_SRC = resolve(HERE, '..', '..', '..', '..', 'packages', 'rcf-lite', 'test', 'fixtures', 'security-auth-keycloak', 'src');
17
+
18
+ export const anchorAcId = null;
19
+ export const capability = 'sessionInventory';
20
+ export const accountBound = false;
21
+
22
+ const LIM_REQ = 'security-auth-keycloak-AC-11105-1: probe builds an introspection form body against the fixture parser; the AC states the client issues a real POST to the introspection endpoint with HTTP Basic authentication and consumes the JSON body, which requires observing the deployed client through the integration harness follow-up.';
23
+ const LIM_PARSE = 'security-auth-keycloak-AC-11105-1: probe parses a fabricated introspection object; the AC states an opaque token round-trips through the introspection endpoint, needs the integration harness (the auth integration harness follow-up).';
24
+ const LIM_INACTIVE = 'security-auth-keycloak-AC-11105-2: probe observes fixture parser only; the AC requires the client-layer refusal (4xx + KEYCLOAK_INTROSPECTION_INACTIVE + no cookie + audit event), needs the integration harness (the auth integration harness follow-up).';
25
+ const LIM_MALFORMED = 'security-auth-keycloak-AC-11105-3: probe parses a malformed shape locally; the AC states the endpoint returns a non-2xx response with KEYCLOAK_INTROSPECTION_ENDPOINT_ERROR, needs the integration harness (the auth integration harness follow-up).';
26
+
27
+ export default async function runProbe() {
28
+ const { buildIntrospectionForm, parseIntrospectionResponse } = await import(pathToFileURL(resolve(FIXTURE_SRC, 'introspection-client.mjs')).href);
29
+ const results = [];
30
+
31
+ function redactedBody(req) {
32
+ if (!req || !req.body) return req;
33
+ const params = new URLSearchParams(req.body);
34
+ const keys = [...params.keys()].sort();
35
+ const redacted = {};
36
+ for (const k of keys) redacted[k] = k === 'client_secret' ? '[REDACTED]' : params.get(k);
37
+ return { ok: req.ok, error: req.error, bodyKeys: keys, bodyRedacted: redacted };
38
+ }
39
+
40
+ const req = buildIntrospectionForm({ token: 'tok-abc', clientId: 'client-x', clientSecret: 'PLACEHOLDER_SECRET' });
41
+ const reqEv = redactedBody(req);
42
+ const hasFields = req.ok
43
+ && reqEv.bodyKeys.includes('token')
44
+ && reqEv.bodyKeys.includes('client_id')
45
+ && reqEv.bodyKeys.includes('client_secret')
46
+ && reqEv.bodyRedacted.token === 'tok-abc'
47
+ && reqEv.bodyRedacted.client_id === 'client-x';
48
+ results.push(deClaim({
49
+ capability,
50
+ verdict: hasFields ? 'pass' : 'fail',
51
+ detail: `form built (client_secret redacted): ok=${req.ok} bodyKeys=${JSON.stringify(reqEv.bodyKeys)}`,
52
+ evidence: { adapterReturn: reqEv },
53
+ }, { ac: 'security-auth-keycloak-AC-11105-1', limitation: LIM_REQ }));
54
+
55
+ const badReq = buildIntrospectionForm({ token: '', clientId: 'x', clientSecret: 'PLACEHOLDER_SECRET_2' });
56
+ results.push(deClaim({
57
+ capability,
58
+ verdict: !badReq.ok && /token required/.test(badReq.error) ? 'pass' : 'fail',
59
+ detail: `empty-token refusal: ok=${badReq.ok} error=${JSON.stringify(badReq.error)}`,
60
+ evidence: { adapterReturn: { ok: badReq.ok, error: badReq.error } },
61
+ }, { ac: 'security-auth-keycloak-AC-11105-1', limitation: LIM_REQ }));
62
+
63
+ const active = parseIntrospectionResponse({ active: true, sub: 'user-1', scope: 'openid profile', username: 'alice' });
64
+ results.push(deClaim({
65
+ capability,
66
+ verdict: active.ok && active.active && active.principalId === 'user-1' ? 'pass' : 'fail',
67
+ detail: `active:true parses to claim record: ok=${active.ok} principalId=${active.principalId} scope=${active.scope}`,
68
+ evidence: { parserReturn: active },
69
+ }, { ac: 'security-auth-keycloak-AC-11105-1', limitation: LIM_PARSE }));
70
+
71
+ const inactive = parseIntrospectionResponse({ active: false });
72
+ results.push(deClaim({
73
+ capability,
74
+ verdict: inactive.ok && inactive.active === false ? 'pass' : 'fail',
75
+ detail: `active:false parses (parser only): ok=${inactive.ok} active=${inactive.active}`,
76
+ evidence: { parserReturn: inactive, notObservableAt: 'parser-layer' },
77
+ }, { ac: 'security-auth-keycloak-AC-11105-2', limitation: LIM_INACTIVE }));
78
+
79
+ const malformed = parseIntrospectionResponse({ status: 'unknown' });
80
+ results.push(deClaim({
81
+ capability,
82
+ verdict: !malformed.ok && /missing boolean/.test(malformed.error) ? 'pass' : 'fail',
83
+ detail: `malformed-payload refused (parser only): ok=${malformed.ok} error=${JSON.stringify(malformed.error)}`,
84
+ evidence: { parserReturn: malformed },
85
+ }, { ac: 'security-auth-keycloak-AC-11105-3', limitation: LIM_MALFORMED }));
86
+
87
+ return { results, extra: {} };
88
+ }
@@ -0,0 +1,86 @@
1
+ // JWT verifier shape probe for security-auth-keycloak.
2
+ // Conformance-only. Every row records anchorAcId=null with a
3
+ // limitation naming the shipped AC whose JWKS/handler/audit
4
+ // property the local RS256 sign+verify observation does not
5
+ // exercise. The integration harness follow-up is the surface where
6
+ // the AC-level properties become observable.
7
+ //
8
+ // capability: credentialSelfService. engine: fixture. accountBound: false.
9
+
10
+ import { pathToFileURL } from 'node:url';
11
+ import { resolve, dirname } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { deClaim } from './probe-utils.mjs';
14
+
15
+ const HERE = dirname(fileURLToPath(import.meta.url));
16
+ const FIXTURE_SRC = resolve(HERE, '..', '..', '..', '..', 'packages', 'rcf-lite', 'test', 'fixtures', 'security-auth-keycloak', 'src');
17
+
18
+ export const anchorAcId = null;
19
+ export const capability = 'credentialSelfService';
20
+ export const accountBound = false;
21
+
22
+ const LIM_KID = 'security-auth-keycloak-AC-11103-1: probe verifies against an in-process public key; the AC requires JWKS-cache resolution by kid, needs the integration harness (the auth integration harness follow-up).';
23
+ const LIM_SIG = 'security-auth-keycloak-AC-11104-2: probe verifies against a static public key; the AC requires refresh-then-refuse when the kid is unpublished, needs the integration harness (the auth integration harness follow-up).';
24
+ const LIM_EXP = 'security-auth-keycloak-AC-11104-1: probe checks expiry-refusal on a synthetic token; the AC requires session absence + 4xx + audit event at the request handler, needs the integration harness (the auth integration harness follow-up).';
25
+ const LIM_ISS = 'security-auth-keycloak-AC-11117-7: probe observes iss mismatch refusal; the AC states an audit event with reasonClass=issuer_mismatch is emitted at the handler, needs the integration harness (the auth integration harness follow-up).';
26
+ const LIM_ALG = 'security-auth-keycloak-AC-11104-2: probe observes alg=none refusal on the local verifier; the AC states the verifier refuses a token signed under an unpublished key with KEYCLOAK_JWT_SIGNATURE_INVALID after one JWKS refresh, which requires observing the deployed verifier through the integration harness follow-up.';
27
+
28
+ export default async function runProbe() {
29
+ const { generateThrowawayKeypair, signRs256, verifyRs256 } = await import(pathToFileURL(resolve(FIXTURE_SRC, 'jwt-verifier.mjs')).href);
30
+ const { privateKey, publicKey } = generateThrowawayKeypair();
31
+ const results = [];
32
+ const iss = 'https://kc.example.com/realms/example-realm';
33
+ const now = Math.floor(Date.now() / 1000);
34
+ const payload = { sub: 'user-abc', iss, exp: now + 300, iat: now };
35
+ const token = signRs256({ header: { alg: 'RS256', typ: 'JWT' }, payload, privateKey });
36
+
37
+ const good = verifyRs256({ token, publicKey, expectedIssuer: iss });
38
+ results.push(deClaim({
39
+ capability,
40
+ verdict: good.ok && good.payload && good.payload.sub === 'user-abc' ? 'pass' : 'fail',
41
+ detail: `well-formed RS256 verify against public key: ok=${good.ok} sub=${good.payload && good.payload.sub}`,
42
+ evidence: { verifierReturn: { ok: good.ok, sub: good.payload && good.payload.sub } },
43
+ }, { ac: 'security-auth-keycloak-AC-11103-1', limitation: LIM_KID }));
44
+
45
+ const parts = token.split('.');
46
+ const firstSigChar = parts[2].slice(0, 1);
47
+ const flipped = firstSigChar === 'A' ? 'B' : 'A';
48
+ const tampered = `${parts[0]}.${parts[1]}.${flipped}${parts[2].slice(1)}`;
49
+ const badSig = verifyRs256({ token: tampered, publicKey, expectedIssuer: iss });
50
+ results.push(deClaim({
51
+ capability,
52
+ verdict: !badSig.ok && /signature/.test(badSig.error) ? 'pass' : 'fail',
53
+ detail: `tampered-signature refused: ok=${badSig.ok} error=${JSON.stringify(badSig.error)}`,
54
+ evidence: { verifierReturn: badSig },
55
+ }, { ac: 'security-auth-keycloak-AC-11104-2', limitation: LIM_SIG }));
56
+
57
+ const expiredToken = signRs256({ header: { alg: 'RS256', typ: 'JWT' }, payload: { sub: 'x', iss, exp: now - 60 }, privateKey });
58
+ const badExp = verifyRs256({ token: expiredToken, publicKey, expectedIssuer: iss });
59
+ results.push(deClaim({
60
+ capability,
61
+ verdict: !badExp.ok && /expired/.test(badExp.error) ? 'pass' : 'fail',
62
+ detail: `past-exp refused: ok=${badExp.ok} error=${JSON.stringify(badExp.error)}`,
63
+ evidence: { verifierReturn: badExp },
64
+ }, { ac: 'security-auth-keycloak-AC-11104-1', limitation: LIM_EXP }));
65
+
66
+ const wrongIss = verifyRs256({ token, publicKey, expectedIssuer: 'https://kc.example.com/realms/other' });
67
+ results.push(deClaim({
68
+ capability,
69
+ verdict: !wrongIss.ok && /iss mismatch/.test(wrongIss.error) ? 'pass' : 'fail',
70
+ detail: `iss-mismatch refused: ok=${wrongIss.ok} error=${JSON.stringify(wrongIss.error)}`,
71
+ evidence: { verifierReturn: wrongIss },
72
+ }, { ac: 'security-auth-keycloak-AC-11117-7', limitation: LIM_ISS }));
73
+
74
+ const noneHeader = Buffer.from(JSON.stringify({ alg: 'none', typ: 'JWT' })).toString('base64url');
75
+ const nonePayload = Buffer.from(JSON.stringify({ sub: 'x', iss, exp: now + 300 })).toString('base64url');
76
+ const noneToken = `${noneHeader}.${nonePayload}.`;
77
+ const badAlg = verifyRs256({ token: noneToken, publicKey, expectedIssuer: iss });
78
+ results.push(deClaim({
79
+ capability,
80
+ verdict: !badAlg.ok && /alg must be RS256/.test(badAlg.error) ? 'pass' : 'fail',
81
+ detail: `alg=none refused: ok=${badAlg.ok} error=${JSON.stringify(badAlg.error)}`,
82
+ evidence: { verifierReturn: badAlg },
83
+ }, { ac: 'security-auth-keycloak-AC-11104-2', limitation: LIM_ALG }));
84
+
85
+ return { results, extra: {} };
86
+ }
@@ -0,0 +1,180 @@
1
+ // Shared helpers for security-auth-keycloak probes.
2
+ //
3
+ // Runtime-dependency posture:
4
+ // - Local probes drive shipped-shape checks against the fixture at
5
+ // packages/rcf-lite/test/fixtures/security-auth-keycloak/ without
6
+ // contacting a real Keycloak realm.
7
+ // - real-account-* probes call the Keycloak Admin REST API and
8
+ // OIDC endpoints against a live Keycloak realm when one is
9
+ // available. No live Keycloak client is available in this estate
10
+ // (no live realm is exposed to shelf probes in this estate), so the
11
+ // real-account probe honest-skips per rule 7d, recording
12
+ // accountBoundSkipped: true naming CI_HAS_KEYCLOAK_ACCOUNT.
13
+
14
+ import { mkdir, writeFile } from 'node:fs/promises';
15
+ import { dirname, resolve } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
17
+
18
+ const HERE = dirname(fileURLToPath(import.meta.url));
19
+ export const PROJECT_ROOT = resolve(HERE, '..', '..', '..', '..');
20
+ export const SLUG = 'security-auth-keycloak';
21
+ export const FIXTURE_DIR = resolve(PROJECT_ROOT, 'packages/rcf-lite/test/fixtures/security-auth-keycloak');
22
+ export const REPORT_DIR = resolve(PROJECT_ROOT, '.rcf/reports/blueprints/security-auth-keycloak');
23
+
24
+ export const DECLARED_ENV = Object.freeze([
25
+ 'CI_HAS_KEYCLOAK_ACCOUNT',
26
+ 'KEYCLOAK_BASE_URL',
27
+ 'KEYCLOAK_REALM',
28
+ 'KEYCLOAK_ADMIN_CLIENT_ID',
29
+ 'KEYCLOAK_ADMIN_CLIENT_SECRET',
30
+ 'KEYCLOAK_INTROSPECTION_TOKEN',
31
+ ]);
32
+
33
+ // First-8-words-of-anchor helper. Each result row's `detail` starts
34
+ // with the first eight words of the anchored AC's or REQ's
35
+ // description text. Anchor lookup walks contributions/user-stories/
36
+ // and contributions/requirements/ under the blueprint root and
37
+ // caches the map on first call. Null / unknown / missing anchors
38
+ // yield an empty prefix.
39
+ import { readFileSync as _rf } from 'node:fs';
40
+ import { readdirSync as _rd } from 'node:fs';
41
+ let _anchorMap = null;
42
+ function _loadAnchorMap() {
43
+ const map = new Map();
44
+ const dirs = [
45
+ { dir: resolve(PROJECT_ROOT, 'blueprints', SLUG, 'contributions', 'user-stories'), kind: 'ac' },
46
+ { dir: resolve(PROJECT_ROOT, 'blueprints', SLUG, 'contributions', 'requirements'), kind: 'req' },
47
+ ];
48
+ for (const { dir, kind } of dirs) {
49
+ let entries;
50
+ try { entries = _rd(dir); } catch { continue; }
51
+ for (const name of entries) {
52
+ if (!name.endsWith('.json')) continue;
53
+ let j;
54
+ try { j = JSON.parse(_rf(resolve(dir, name), 'utf8')); } catch { continue; }
55
+ if (kind === 'ac') {
56
+ const usId = j.usId;
57
+ for (const ac of (j.acceptanceCriteria || [])) {
58
+ // AC id in the shipped JSON is like "AC-9101-1"; the
59
+ // anchor form used by probes is "<slug>-AC-9101-1".
60
+ const key = `${SLUG}-${ac.id}`;
61
+ map.set(key, ac.description || '');
62
+ }
63
+ } else {
64
+ const key = j.reqId; // already "<slug>-REQ-###"
65
+ if (key) map.set(key, j.description || j.title || '');
66
+ }
67
+ }
68
+ }
69
+ return map;
70
+ }
71
+ export function first8Words(anchor) {
72
+ if (!anchor) return '';
73
+ if (!_anchorMap) _anchorMap = _loadAnchorMap();
74
+ const txt = _anchorMap.get(anchor) || '';
75
+ if (!txt) return '';
76
+ const words = txt.split(/\s+/).filter(Boolean).slice(0, 8).join(' ');
77
+ return words;
78
+ }
79
+ export function withAnchorPrefix(row) {
80
+ const prefix = first8Words(row.anchorAcId);
81
+ if (!prefix) return row;
82
+ const already = typeof row.detail === 'string' && row.detail.startsWith(prefix);
83
+ if (already) return row;
84
+ const oldDetail = row.detail || '';
85
+ return { ...row, detail: `${prefix} :: ${oldDetail}` };
86
+ }
87
+
88
+ export function aggregate(results) {
89
+ if (!Array.isArray(results) || results.length === 0) return 'fail';
90
+ if (results.some((r) => r.verdict === 'fail')) return 'fail';
91
+ if (results.some((r) => r.verdict === 'warn')) return 'warn';
92
+ return 'pass';
93
+ }
94
+
95
+ export function isSkipped(results) {
96
+ return results.length > 0 && results.every((r) => r.accountBoundSkipped === true);
97
+ }
98
+
99
+ export async function writeReport({ probeName, engine, results, extra }) {
100
+ await mkdir(REPORT_DIR, { recursive: true });
101
+ // Prefix every row's detail with the first eight words of its
102
+ // anchored AC or REQ description; unanchored rows are left alone.
103
+ const prefixedResults = (results || []).map(withAnchorPrefix);
104
+ const raw = aggregate(prefixedResults);
105
+ const aggregateVerdict = isSkipped(prefixedResults) ? 'pass' : raw;
106
+ const report = {
107
+ slug: 'security-auth-keycloak',
108
+ probeName,
109
+ runAt: new Date().toISOString(),
110
+ engine,
111
+ results: prefixedResults,
112
+ aggregateVerdict,
113
+ ...(extra ?? {}),
114
+ };
115
+ const path = resolve(REPORT_DIR, `${probeName}.json`);
116
+ await writeFile(path, JSON.stringify(report, null, 2) + '\n', 'utf8');
117
+ return { report, path };
118
+ }
119
+
120
+ export async function runShim(probeName, engine, mainFn) {
121
+ try {
122
+ const outcome = await mainFn();
123
+ if (!outcome || !Array.isArray(outcome.results) || outcome.results.length === 0) {
124
+ const results = [{
125
+ anchorAcId: 'unknown',
126
+ verdict: 'fail',
127
+ detail: 'no checks ran',
128
+ }];
129
+ const { report, path } = await writeReport({ probeName, engine, results });
130
+ process.stdout.write(JSON.stringify(report, null, 2) + '\n');
131
+ process.stderr.write(`no-checks-ran fail written to ${path}\n`);
132
+ process.exitCode = 1;
133
+ return;
134
+ }
135
+ const { results, extra } = outcome;
136
+ const { report, path } = await writeReport({ probeName, engine, results, extra });
137
+ process.stdout.write(JSON.stringify(report, null, 2) + '\n');
138
+ process.stdout.write(`report written to ${path}\n`);
139
+ if (report.aggregateVerdict === 'fail') process.exitCode = 1;
140
+ } catch (err) {
141
+ const results = [{ anchorAcId: 'unknown', verdict: 'fail', detail: `probe threw: ${err && err.message ? err.message : String(err)}` }];
142
+ const { report, path } = await writeReport({ probeName, engine, results });
143
+ process.stdout.write(JSON.stringify(report, null, 2) + '\n');
144
+ process.stderr.write(`probe error: ${err && err.stack ? err.stack : String(err)}\n`);
145
+ process.stderr.write(`report written to ${path}\n`);
146
+ process.exitCode = 1;
147
+ }
148
+ }
149
+
150
+ // De-claim helper. When the shipped AC does not observe what the probe observes, the row keeps its
151
+ // verdict, evidence and engine as they are, but the anchor drops to null and the
152
+ // row carries conformanceOnly:true plus a limitation string naming the AC that
153
+ // this probe does NOT observe and why. The integration-harness follow-up (the auth integration harness follow-up)
154
+ // is the surface where those AC-level properties become observable.
155
+ export function deClaim(row, { ac, limitation }) {
156
+ const acId = ac || 'unknown-AC';
157
+ const limText = (limitation || '').trim();
158
+ const finalLim = /^(security-[a-z0-9-]+-)?(AC|REQ)-/.test(limText) ? limText : (limText ? `${acId}: ${limText}` : `${acId}: not observable at this probe surface; needs the integration harness (the auth integration harness follow-up)`);
159
+ const out = { ...row };
160
+ out.anchorAcId = null;
161
+ if ('anchorReqId' in out) delete out.anchorReqId;
162
+ out.conformanceOnly = true;
163
+ out.limitation = finalLim;
164
+ const tag = ` :: conformance-only (${finalLim})`;
165
+ if (typeof out.detail === 'string' && !out.detail.includes('conformance-only')) {
166
+ out.detail = out.detail + tag;
167
+ }
168
+ return out;
169
+ }
170
+
171
+ export function accountBoundSkippedResult(anchorAcId, capability, reason) {
172
+ return {
173
+ anchorAcId,
174
+ capability,
175
+ verdict: 'pass',
176
+ accountBoundSkipped: true,
177
+ reason,
178
+ detail: `accountBoundSkipped: ${reason} unset; probe did not execute against a real Keycloak realm. Set the missing var and re-run.`,
179
+ };
180
+ }