rcf-lite 0.24.0 → 0.25.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 (232) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/blueprints/application-account-settings/docs/topics.md +3 -0
  3. package/blueprints/application-admin-console/docs/topics.md +3 -0
  4. package/blueprints/application-api-rest/docs/topics.md +3 -0
  5. package/blueprints/application-charts/docs/topics.md +3 -0
  6. package/blueprints/application-dashboard/docs/topics.md +3 -0
  7. package/blueprints/application-datatable/docs/topics.md +3 -0
  8. package/blueprints/application-empty-error-states/docs/topics.md +3 -0
  9. package/blueprints/application-error-handling/docs/topics.md +3 -0
  10. package/blueprints/application-file-upload/docs/topics.md +3 -0
  11. package/blueprints/application-forms-wizard/docs/topics.md +3 -0
  12. package/blueprints/application-notifications-in-app/docs/topics.md +3 -0
  13. package/blueprints/application-onboarding-tour/docs/topics.md +3 -0
  14. package/blueprints/application-spa/docs/topics.md +3 -0
  15. package/blueprints/delivery-ci-workflows/docs/topics.md +3 -0
  16. package/blueprints/deploy-cloudflare-workers/docs/topics.md +3 -0
  17. package/blueprints/deploy-hetzner-server/CHANGELOG.md +34 -0
  18. package/blueprints/deploy-hetzner-server/README.md +202 -0
  19. package/blueprints/deploy-hetzner-server/blueprint.json +233 -0
  20. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3801-deploy-hetzner-server-cloud-host-contract.json +14 -0
  21. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3802-deploy-hetzner-server-snapshot-cadence.json +14 -0
  22. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3803-deploy-hetzner-server-provisioning-tool.json +20 -0
  23. package/blueprints/deploy-hetzner-server/contributions/adrs/adr-3804-deploy-hetzner-server-hardening-baseline.json +14 -0
  24. package/blueprints/deploy-hetzner-server/contributions/probes/cloud-init-render-lint.mjs +64 -0
  25. package/blueprints/deploy-hetzner-server/contributions/probes/hcloud-dry-run-mock.mjs +116 -0
  26. package/blueprints/deploy-hetzner-server/contributions/probes/manifest-schema-validate.mjs +180 -0
  27. package/blueprints/deploy-hetzner-server/contributions/probes/probe-utils.mjs +106 -0
  28. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-cloud-init-hardened.mjs +63 -0
  29. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-snapshot-on-demand.mjs +60 -0
  30. package/blueprints/deploy-hetzner-server/contributions/probes/real-account-throwaway-server-provision.mjs +58 -0
  31. package/blueprints/deploy-hetzner-server/contributions/probes/run-cloud-init-render-lint.mjs +9 -0
  32. package/blueprints/deploy-hetzner-server/contributions/probes/run-hcloud-dry-run-mock.mjs +9 -0
  33. package/blueprints/deploy-hetzner-server/contributions/probes/run-manifest-schema-validate.mjs +9 -0
  34. package/blueprints/deploy-hetzner-server/contributions/probes/run-real-account-cloud-init-hardened.mjs +9 -0
  35. package/blueprints/deploy-hetzner-server/contributions/probes/run-real-account-snapshot-on-demand.mjs +9 -0
  36. package/blueprints/deploy-hetzner-server/contributions/probes/run-real-account-throwaway-server-provision.mjs +9 -0
  37. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-001.json +18 -0
  38. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-002.json +18 -0
  39. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-003.json +18 -0
  40. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-004.json +18 -0
  41. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-005.json +18 -0
  42. package/blueprints/deploy-hetzner-server/contributions/requirements/deploy-hetzner-server-req-006.json +18 -0
  43. package/blueprints/deploy-hetzner-server/contributions/schemas/hetzner-server.schema.json +108 -0
  44. package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3801-deploy-hetzner-server-provisioner.json +27 -0
  45. package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3802-deploy-hetzner-server-manifest-schema.json +26 -0
  46. package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3803-deploy-hetzner-server-cloud-init-template.json +26 -0
  47. package/blueprints/deploy-hetzner-server/contributions/tacs/tac-3804-deploy-hetzner-server-firewall-shape.json +25 -0
  48. package/blueprints/deploy-hetzner-server/contributions/templates/cloud-init.yaml.tmpl +93 -0
  49. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37101.json +24 -0
  50. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37102.json +24 -0
  51. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37103.json +25 -0
  52. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37104.json +24 -0
  53. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37105.json +24 -0
  54. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37106.json +25 -0
  55. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37107.json +24 -0
  56. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37108.json +24 -0
  57. package/blueprints/deploy-hetzner-server/contributions/user-stories/deploy-hetzner-server-us-37109.json +24 -0
  58. package/blueprints/deploy-hetzner-server/docs/topics.md +48 -0
  59. package/blueprints/deploy-hetzner-server/guide/deploy-hetzner-server.md +180 -0
  60. package/blueprints/edge-cloudflare-access/docs/topics.md +3 -0
  61. package/blueprints/edge-cloudflare-rate-limiting/docs/topics.md +3 -0
  62. package/blueprints/edge-cloudflare-tunnel/CHANGELOG.md +13 -0
  63. package/blueprints/edge-cloudflare-tunnel/README.md +257 -0
  64. package/blueprints/edge-cloudflare-tunnel/blueprint.json +168 -0
  65. package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4001-edge-cloudflare-tunnel-ingress-bridge-contract.json +23 -0
  66. package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4002-edge-cloudflare-tunnel-connector-runtime.json +19 -0
  67. package/blueprints/edge-cloudflare-tunnel/contributions/adrs/adr-4003-edge-cloudflare-tunnel-hostname-mode.json +19 -0
  68. package/blueprints/edge-cloudflare-tunnel/contributions/probes/aud-presence-check.mjs +114 -0
  69. package/blueprints/edge-cloudflare-tunnel/contributions/probes/cloudflared-config-lint.mjs +80 -0
  70. package/blueprints/edge-cloudflare-tunnel/contributions/probes/manifest-schema-validate.mjs +234 -0
  71. package/blueprints/edge-cloudflare-tunnel/contributions/probes/probe-utils.mjs +231 -0
  72. package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-connector-healthy.mjs +54 -0
  73. package/blueprints/edge-cloudflare-tunnel/contributions/probes/real-account-tunnel-hostname-routes.mjs +73 -0
  74. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-aud-presence-check.mjs +4 -0
  75. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-cloudflared-config-lint.mjs +4 -0
  76. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-manifest-schema-validate.mjs +4 -0
  77. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-real-account-connector-healthy.mjs +4 -0
  78. package/blueprints/edge-cloudflare-tunnel/contributions/probes/run-real-account-tunnel-hostname-routes.mjs +4 -0
  79. package/blueprints/edge-cloudflare-tunnel/contributions/probes/tunnel-manifest.schema.json +55 -0
  80. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-001.json +18 -0
  81. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-002.json +18 -0
  82. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-003.json +18 -0
  83. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-004.json +18 -0
  84. package/blueprints/edge-cloudflare-tunnel/contributions/requirements/edge-cloudflare-tunnel-req-005.json +18 -0
  85. package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4001-edge-cloudflare-tunnel-connector-shape.json +26 -0
  86. package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4002-edge-cloudflare-tunnel-manifest-schema.json +26 -0
  87. package/blueprints/edge-cloudflare-tunnel/contributions/tacs/tac-4003-edge-cloudflare-tunnel-access-binding.json +25 -0
  88. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39101.json +24 -0
  89. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39102.json +24 -0
  90. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39103.json +24 -0
  91. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39104.json +24 -0
  92. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39105.json +24 -0
  93. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39106.json +24 -0
  94. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39107.json +24 -0
  95. package/blueprints/edge-cloudflare-tunnel/contributions/user-stories/edge-cloudflare-tunnel-us-39108.json +24 -0
  96. package/blueprints/edge-cloudflare-tunnel/docs/topics.md +72 -0
  97. package/blueprints/edge-cloudflare-tunnel/guide/edge-cloudflare-tunnel.md +204 -0
  98. package/blueprints/edge-cloudflare-turnstile/docs/topics.md +3 -0
  99. package/blueprints/email-smtp-resend/docs/topics.md +3 -0
  100. package/blueprints/jobs-background/docs/topics.md +3 -0
  101. package/blueprints/messaging-queue-cloudflare/docs/topics.md +3 -0
  102. package/blueprints/object-storage-s3/docs/topics.md +3 -0
  103. package/blueprints/observability-essentials/docs/topics.md +3 -0
  104. package/blueprints/observability-logging/docs/topics.md +3 -0
  105. package/blueprints/observability-probe-endpoints/docs/topics.md +3 -0
  106. package/blueprints/persistence-data-d1/docs/topics.md +3 -0
  107. package/blueprints/persistence-data-postgres/docs/topics.md +3 -0
  108. package/blueprints/persistence-data-sqlite/docs/topics.md +3 -0
  109. package/blueprints/platform-cloudflare-cron-triggers/docs/topics.md +3 -0
  110. package/blueprints/platform-cloudflare-durable-objects/docs/topics.md +3 -0
  111. package/blueprints/platform-cloudflare-kv/docs/topics.md +3 -0
  112. package/blueprints/platform-docker-compose-host/CHANGELOG.md +12 -0
  113. package/blueprints/platform-docker-compose-host/README.md +76 -0
  114. package/blueprints/platform-docker-compose-host/blueprint.json +209 -0
  115. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3901-platform-docker-compose-host-contract.json +14 -0
  116. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3902-platform-docker-compose-host-reverse-proxy.json +14 -0
  117. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3903-platform-docker-compose-host-reject-coolify.json +14 -0
  118. package/blueprints/platform-docker-compose-host/contributions/adrs/adr-3904-platform-docker-compose-host-log-driver.json +14 -0
  119. package/blueprints/platform-docker-compose-host/contributions/probes/caddyfile-validate.mjs +108 -0
  120. package/blueprints/platform-docker-compose-host/contributions/probes/compose-config-lint.mjs +231 -0
  121. package/blueprints/platform-docker-compose-host/contributions/probes/probe-utils.mjs +185 -0
  122. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-minimal-stack-up.mjs +41 -0
  123. package/blueprints/platform-docker-compose-host/contributions/probes/real-account-reload-burst.mjs +36 -0
  124. package/blueprints/platform-docker-compose-host/contributions/probes/run-caddyfile-validate.mjs +5 -0
  125. package/blueprints/platform-docker-compose-host/contributions/probes/run-compose-config-lint.mjs +5 -0
  126. package/blueprints/platform-docker-compose-host/contributions/probes/run-real-account-minimal-stack-up.mjs +5 -0
  127. package/blueprints/platform-docker-compose-host/contributions/probes/run-real-account-reload-burst.mjs +5 -0
  128. package/blueprints/platform-docker-compose-host/contributions/probes/run-secrets-as-files-scan.mjs +5 -0
  129. package/blueprints/platform-docker-compose-host/contributions/probes/secrets-as-files-scan.mjs +116 -0
  130. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-001.json +18 -0
  131. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-002.json +18 -0
  132. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-003.json +18 -0
  133. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-004.json +18 -0
  134. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-005.json +18 -0
  135. package/blueprints/platform-docker-compose-host/contributions/requirements/platform-docker-compose-host-req-006.json +18 -0
  136. package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3901-platform-docker-compose-host-compose-layout.json +26 -0
  137. package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3902-platform-docker-compose-host-secrets-mount.json +26 -0
  138. package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3903-platform-docker-compose-host-healthcheck-lint.json +26 -0
  139. package/blueprints/platform-docker-compose-host/contributions/tacs/tac-3904-platform-docker-compose-host-reverse-proxy-artefact.json +26 -0
  140. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38101.json +24 -0
  141. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38102.json +24 -0
  142. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38103.json +24 -0
  143. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38104.json +24 -0
  144. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38105.json +25 -0
  145. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38106.json +24 -0
  146. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38107.json +24 -0
  147. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38108.json +24 -0
  148. package/blueprints/platform-docker-compose-host/contributions/user-stories/platform-docker-compose-host-us-38109.json +24 -0
  149. package/blueprints/platform-docker-compose-host/docs/topics.md +71 -0
  150. package/blueprints/platform-docker-compose-host/guide/platform-docker-compose-host.md +94 -0
  151. package/blueprints/security-auth-clerk/docs/topics.md +3 -0
  152. package/blueprints/security-auth-keycloak/docs/topics.md +3 -0
  153. package/blueprints/security-auth-magic-link/docs/topics.md +3 -0
  154. package/blueprints/security-auth-oauth2/docs/topics.md +3 -0
  155. package/blueprints/security-secrets-management/docs/topics.md +3 -0
  156. package/fixtures/canary-manifest.json +9 -9
  157. package/package.json +1 -1
  158. package/rcf/adrs/adr-3801-deploy-hetzner-server-cloud-host-contract.json +13 -0
  159. package/rcf/adrs/adr-3802-deploy-hetzner-server-snapshot-cadence.json +13 -0
  160. package/rcf/adrs/adr-3803-deploy-hetzner-server-provisioning-tool.json +13 -0
  161. package/rcf/adrs/adr-3804-deploy-hetzner-server-hardening-baseline.json +13 -0
  162. package/rcf/adrs/adr-3901-platform-docker-compose-host-contract.json +13 -0
  163. package/rcf/adrs/adr-3902-platform-docker-compose-host-reverse-proxy.json +13 -0
  164. package/rcf/adrs/adr-3903-platform-docker-compose-host-reject-coolify.json +13 -0
  165. package/rcf/adrs/adr-3904-platform-docker-compose-host-log-driver.json +13 -0
  166. package/rcf/adrs/adr-4001-edge-cloudflare-tunnel-ingress-bridge-contract.json +13 -0
  167. package/rcf/adrs/adr-4002-edge-cloudflare-tunnel-connector-runtime.json +13 -0
  168. package/rcf/adrs/adr-4003-edge-cloudflare-tunnel-hostname-mode.json +13 -0
  169. package/rcf/code-nodes/cn-410.json +20 -0
  170. package/rcf/code-nodes/cn-440.json +20 -0
  171. package/rcf/code-nodes/cn-470.json +19 -0
  172. package/rcf/fbs/fbs-130.json +23 -0
  173. package/rcf/fbs/fbs-140.json +23 -0
  174. package/rcf/fbs/fbs-150.json +22 -0
  175. package/rcf/requirements/req-110.json +58 -0
  176. package/rcf/requirements/req-111.json +32 -0
  177. package/rcf/requirements/req-112.json +42 -0
  178. package/rcf/requirements/req-113.json +33 -0
  179. package/rcf/requirements/req-114.json +20 -0
  180. package/rcf/requirements/req-115.json +38 -0
  181. package/rcf/requirements/req-120.json +20 -0
  182. package/rcf/requirements/req-121.json +20 -0
  183. package/rcf/requirements/req-122.json +20 -0
  184. package/rcf/requirements/req-123.json +42 -0
  185. package/rcf/requirements/req-124.json +27 -0
  186. package/rcf/requirements/req-125.json +20 -0
  187. package/rcf/requirements/req-130.json +32 -0
  188. package/rcf/requirements/req-131.json +54 -0
  189. package/rcf/requirements/req-132.json +27 -0
  190. package/rcf/requirements/req-133.json +20 -0
  191. package/rcf/requirements/req-134.json +42 -0
  192. package/rcf/tacs/tac-3801-deploy-hetzner-server-provisioner.json +17 -0
  193. package/rcf/tacs/tac-3802-deploy-hetzner-server-manifest-schema.json +17 -0
  194. package/rcf/tacs/tac-3803-deploy-hetzner-server-cloud-init-template.json +17 -0
  195. package/rcf/tacs/tac-3804-deploy-hetzner-server-firewall-shape.json +16 -0
  196. package/rcf/tacs/tac-3901-platform-docker-compose-host-compose-layout.json +17 -0
  197. package/rcf/tacs/tac-3902-platform-docker-compose-host-secrets-mount.json +17 -0
  198. package/rcf/tacs/tac-3903-platform-docker-compose-host-healthcheck-lint.json +17 -0
  199. package/rcf/tacs/tac-3904-platform-docker-compose-host-reverse-proxy-artefact.json +17 -0
  200. package/rcf/tacs/tac-4001-edge-cloudflare-tunnel-connector-shape.json +17 -0
  201. package/rcf/tacs/tac-4002-edge-cloudflare-tunnel-manifest-schema.json +17 -0
  202. package/rcf/tacs/tac-4003-edge-cloudflare-tunnel-access-binding.json +16 -0
  203. package/rcf/test-suites/ts-140.json +86 -0
  204. package/rcf/test-suites/ts-150.json +86 -0
  205. package/rcf/test-suites/ts-160.json +78 -0
  206. package/rcf/user-stories/us-11001.json +23 -0
  207. package/rcf/user-stories/us-11101.json +23 -0
  208. package/rcf/user-stories/us-11102.json +24 -0
  209. package/rcf/user-stories/us-11201.json +23 -0
  210. package/rcf/user-stories/us-11202.json +23 -0
  211. package/rcf/user-stories/us-11301.json +24 -0
  212. package/rcf/user-stories/us-11401.json +23 -0
  213. package/rcf/user-stories/us-11402.json +23 -0
  214. package/rcf/user-stories/us-11501.json +23 -0
  215. package/rcf/user-stories/us-12001.json +23 -0
  216. package/rcf/user-stories/us-12101.json +23 -0
  217. package/rcf/user-stories/us-12102.json +23 -0
  218. package/rcf/user-stories/us-12201.json +23 -0
  219. package/rcf/user-stories/us-12202.json +24 -0
  220. package/rcf/user-stories/us-12301.json +23 -0
  221. package/rcf/user-stories/us-12401.json +23 -0
  222. package/rcf/user-stories/us-12402.json +23 -0
  223. package/rcf/user-stories/us-12501.json +23 -0
  224. package/rcf/user-stories/us-13001.json +23 -0
  225. package/rcf/user-stories/us-13002.json +23 -0
  226. package/rcf/user-stories/us-13101.json +23 -0
  227. package/rcf/user-stories/us-13102.json +23 -0
  228. package/rcf/user-stories/us-13201.json +23 -0
  229. package/rcf/user-stories/us-13301.json +23 -0
  230. package/rcf/user-stories/us-13302.json +23 -0
  231. package/rcf/user-stories/us-13401.json +23 -0
  232. package/releases/releases.yaml +11 -1
@@ -0,0 +1,78 @@
1
+ {
2
+ "createdAt": "2026-09-08T03:24:23.156Z",
3
+ "updatedAt": "2026-09-08T03:24:51.162Z",
4
+ "purpose": "Cover the T-3 chain ACs via the shipped anatomy test at test/blueprint/edge-cloudflare-tunnel-anatomy.test.js and via the three local probe modules driven from the shared throwaway-server fixture (which T-3 extends with cloudflared/compose-service and cloudflared/systemd-unit variants, each in both public-hostname and access-gated sidecar modes).",
5
+ "testLevel": "integration",
6
+ "acIds": [
7
+ "AC-13001-1",
8
+ "AC-13002-1",
9
+ "AC-13101-1",
10
+ "AC-13102-1",
11
+ "AC-13201-1",
12
+ "AC-13301-1",
13
+ "AC-13302-1",
14
+ "AC-13401-1"
15
+ ],
16
+ "id": "TS-160",
17
+ "usId": "US-13001",
18
+ "title": "T-3 edge-cloudflare-tunnel anatomy proof: probe modules and cloudflared connector fixture assertions",
19
+ "testCases": [
20
+ {
21
+ "id": "TC-160-connector-shape-variants-shipped",
22
+ "acId": "AC-13001-1",
23
+ "description": "Cover AC-13001-1 via anatomy test: the shared fixture ships both cloudflared/compose-service/ and cloudflared/systemd-unit/ variants and the compose-service variant defines a cloudflared service alongside T-2 web and caddy on the same web-net network with no host ports; the systemd-unit variant ships a cloudflared.service unit file per the vendor local-configuration-file docs.",
24
+ "status": "pending",
25
+ "testPointer": "test/blueprint/edge-cloudflare-tunnel-anatomy.test.js::T-3 edge-cloudflare-tunnel AC-13001-1 connector shape variants shipped (TC-160-connector-shape-variants-shipped)"
26
+ },
27
+ {
28
+ "id": "TC-160-real-account-connector-healthy-declared-and-skipped-shape",
29
+ "acId": "AC-13002-1",
30
+ "description": "Cover AC-13002-1 via anatomy test: real-account-connector-healthy probe declares accountBound true and records accountBoundSkipped when CI_HAS_CLOUDFLARE_ACCOUNT or CI_HAS_HETZNER_ACCOUNT is unset.",
31
+ "status": "pending",
32
+ "testPointer": "test/blueprint/edge-cloudflare-tunnel-anatomy.test.js::T-3 edge-cloudflare-tunnel AC-13002-1 real-account-connector-healthy declared and skipped shape (TC-160-real-account-connector-healthy-declared-and-skipped-shape)"
33
+ },
34
+ {
35
+ "id": "TC-160-manifest-schema-validate-refuses-invalid",
36
+ "acId": "AC-13101-1",
37
+ "description": "Cover AC-13101-1 via anatomy test: manifest-schema-validate probe passes on the canonical fixture manifests and fails under the three fixture-side mutations SIMULATE_MANIFEST_INVALID_TUNNEL_ID, SIMULATE_MANIFEST_CREDENTIALS_INLINE and SIMULATE_MANIFEST_MISSING_CATCHALL naming the offending field.",
38
+ "status": "pending",
39
+ "testPointer": "test/blueprint/edge-cloudflare-tunnel-anatomy.test.js::T-3 edge-cloudflare-tunnel AC-13101-1 manifest schema validate refuses invalid (TC-160-manifest-schema-validate-refuses-invalid)"
40
+ },
41
+ {
42
+ "id": "TC-160-cloudflared-config-lint-passes-and-refuses-invalid-ingress",
43
+ "acId": "AC-13102-1",
44
+ "description": "Cover AC-13102-1 via anatomy test: cloudflared-config-lint probe runs cloudflared tunnel ingress validate through the cloudflare/cloudflared container image and exits 0 on the canonical fixture; fails under SIMULATE_INGRESS_INVALID naming the offending line.",
45
+ "status": "pending",
46
+ "testPointer": "test/blueprint/edge-cloudflare-tunnel-anatomy.test.js::T-3 edge-cloudflare-tunnel AC-13102-1 cloudflared-config-lint passes and refuses invalid ingress (TC-160-cloudflared-config-lint-passes-and-refuses-invalid-ingress)"
47
+ },
48
+ {
49
+ "id": "TC-160-no-public-origin-port-refused",
50
+ "acId": "AC-13201-1",
51
+ "description": "Cover AC-13201-1 via anatomy test: manifest-schema-validate refuses under SIMULATE_ORIGIN_PORT_OPEN when an ingress rule service URL binds to a host public interface; the T-1 firewall on the ci-throwaway manifest stays 22 open plus 80/443 open only when a reverse proxy is applied.",
52
+ "status": "pending",
53
+ "testPointer": "test/blueprint/edge-cloudflare-tunnel-anatomy.test.js::T-3 edge-cloudflare-tunnel AC-13201-1 no public origin port refused (TC-160-no-public-origin-port-refused)"
54
+ },
55
+ {
56
+ "id": "TC-160-aud-presence-flip-on-both-fixture-variants",
57
+ "acId": "AC-13301-1",
58
+ "description": "Cover AC-13301-1 via anatomy test: aud-presence-check reads each variant sidecar and asserts the ingress rules attach originRequest.access.aud on the access-gated variant and omit the block on the public-hostname variant.",
59
+ "status": "pending",
60
+ "testPointer": "test/blueprint/edge-cloudflare-tunnel-anatomy.test.js::T-3 edge-cloudflare-tunnel AC-13301-1 aud-presence-check flips on both fixture variants (TC-160-aud-presence-flip-on-both-fixture-variants)"
61
+ },
62
+ {
63
+ "id": "TC-160-aud-presence-check-refuses-on-drift",
64
+ "acId": "AC-13302-1",
65
+ "description": "Cover AC-13302-1 via anatomy test: aud-presence-check FAILS under SIMULATE_AUD_DROP when the gated fixture ingress drifts to omit the originRequest.access block; the finding names the affected rule.",
66
+ "status": "pending",
67
+ "testPointer": "test/blueprint/edge-cloudflare-tunnel-anatomy.test.js::T-3 edge-cloudflare-tunnel AC-13302-1 aud-presence-check refuses on drift (TC-160-aud-presence-check-refuses-on-drift)"
68
+ },
69
+ {
70
+ "id": "TC-160-credentials-discipline-and-event-secrecy",
71
+ "acId": "AC-13401-1",
72
+ "description": "Cover AC-13401-1 via anatomy test: the fixture credentials placeholder documents the 0o400 host mode and secretRef discipline; the event-secrecy scan across lifecycle event bodies passes on canonical fixture and FAILS under SIMULATE_EVENT_SECRECY_LEAK naming the leaked field.",
73
+ "status": "pending",
74
+ "testPointer": "test/blueprint/edge-cloudflare-tunnel-anatomy.test.js::T-3 edge-cloudflare-tunnel AC-13401-1 credentials discipline and event-secrecy scan (TC-160-credentials-discipline-and-event-secrecy)"
75
+ }
76
+ ],
77
+ "status": "draft"
78
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-07T23:55:32.229Z",
3
+ "updatedAt": "2026-09-07T23:55:46.775Z",
4
+ "usId": "US-11001",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-110",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-1 provisioner opens on boot with sole HETZNER_ACCOUNT_API_KEY reader and emits provisionerReady with metadata-only payload",
10
+ "asA": "shelf consumer applying the deploy-hetzner-server v1.0.0 blueprint on a Node project that provisions a Hetzner Cloud VM",
11
+ "iWant": "the provisioner facade to be the sole reader of the Hetzner API token (via security-secrets-management) and to fire provisionerReady with a metadata-only payload when it opens on boot",
12
+ "soThat": "the applying project has one auditable seam for the token and the observability sink surfaces the ready event without a secret",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-11001-1",
16
+ "description": "On boot of the shared throwaway-Hetzner-server fixture the provisioner facade opens, and (a) only the provisioner module reads HETZNER_ACCOUNT_API_KEY (grep across the fixture source refuses any other reader), (b) the facade emits a provisionerReady event whose payload carries tool and apiHost only (no token, no ssh key, no user data body).",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3801-deploy-hetzner-server-provisioner"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-07T23:56:32.763Z",
3
+ "updatedAt": "2026-09-07T23:56:33.164Z",
4
+ "usId": "US-11101",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-111",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-1 server manifest schema at hetzner/servers/name.json validates and names type location image ssh-key ids firewall id network id cloud-init path labels",
10
+ "asA": "shelf consumer applying the deploy-hetzner-server v1.0.0 blueprint",
11
+ "iWant": "the applying project's hetzner/servers/name.json manifests to validate against a shipped JSON Schema naming type, location, image, sshKeyIds, firewallId, networkId, cloudInitPath, labels, snapshotCadence",
12
+ "soThat": "the operator has a stable declarative source of truth for every server",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-11101-1",
16
+ "description": "Every hetzner/servers/*.json under the shared throwaway-Hetzner-server fixture parses, validates against blueprints/deploy-hetzner-server/contributions/schemas/hetzner-server.schema.json, and carries the nine named fields with correct types; an induced defect (SIMULATE_MANIFEST_INVALID=true replaces location with an unknown token) fails schema validation naming the offending field.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3802-deploy-hetzner-server-manifest-schema"
22
+ ]
23
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "createdAt": "2026-09-07T23:56:33.351Z",
3
+ "updatedAt": "2026-09-07T23:56:33.765Z",
4
+ "usId": "US-11102",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-111",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-1 applying the provisioner reads each manifest and creates a matching live server, hetznerServerProvisioned event carries id primary IPv4 location server-type",
10
+ "asA": "shelf consumer applying the deploy-hetzner-server v1.0.0 blueprint against a Hetzner project",
11
+ "iWant": "applying the provisioner to read each manifest under hetzner/servers/, create a matching live Hetzner Cloud server, and emit hetznerServerProvisioned with id, primaryIpv4, location, serverType",
12
+ "soThat": "the manifest is the source of truth for what actually exists in the project",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-11102-1",
16
+ "description": "The real-account-throwaway-server-provision probe (accountBound: true, skipped without CI_HAS_HETZNER_ACCOUNT) applies the ci-throwaway.json manifest via provision.mjs, asserts (a) hcloud server list --output json shows the new server whose id is written to the fixture scratch file, (b) hetznerServerProvisioned fired with id, primaryIpv4, location=fsn1, serverType=cx23; teardown via destroy.mjs runs regardless of probe verdict.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3801-deploy-hetzner-server-provisioner",
22
+ "TAC-3802-deploy-hetzner-server-manifest-schema"
23
+ ]
24
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-07T23:56:33.951Z",
3
+ "updatedAt": "2026-09-07T23:57:58.302Z",
4
+ "usId": "US-11201",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-112",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-1 cloud-init template lands the six hardening baseline blocks in the rendered YAML for every provisioned server",
10
+ "asA": "shelf consumer applying the deploy-hetzner-server v1.0.0 blueprint",
11
+ "iWant": "the shipped cloud-init template to render YAML that lands SSH key-only, root disabled, UFW default-deny incoming, DOCKER-USER iptables chain, fail2ban SSH jail and unattended-upgrades on every server",
12
+ "soThat": "the operator inherits the six-block hardening baseline without hand-authoring per host",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-11201-1",
16
+ "description": "cloud-init-render-lint.mjs renders the template with the fixture manifest and asserts each of the six baseline blocks (SSH key-only, root disabled, UFW default-deny incoming, DOCKER-USER iptables chain, fail2ban SSH jail, unattended-upgrades) appears in the rendered YAML by grep; a mutation SIMULATE_HARDENING_DRIFT=true removes the unattended-upgrades block and the probe FAILS with a message naming the missing line.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3803-deploy-hetzner-server-cloud-init-template"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-07T23:56:34.564Z",
3
+ "updatedAt": "2026-09-07T23:57:58.489Z",
4
+ "usId": "US-11202",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-112",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-1 provisioned server is hardened at runtime: root ssh refused, password auth refused, UFW active default-deny, DOCKER-USER present, unattended-upgrades service active",
10
+ "asA": "shelf consumer applying the deploy-hetzner-server v1.0.0 blueprint on a real Hetzner account",
11
+ "iWant": "the provisioned server to be hardened at runtime as the rendered cloud-init promised: root ssh refused, password auth refused, UFW active default-deny incoming, DOCKER-USER present, unattended-upgrades service active",
12
+ "soThat": "the operator can trust the cloud-init contract without ssh-in-and-check for every server",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-11202-1",
16
+ "description": "real-account-cloud-init-hardened.mjs (accountBound: true, skipped without CI_HAS_HETZNER_ACCOUNT) waits for cloud-init status --wait on the throwaway server, then ssh-checks the six baseline blocks and asserts each check passes; failure names the missing block. Teardown via destroy.mjs runs regardless.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3803-deploy-hetzner-server-cloud-init-template"
22
+ ]
23
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "createdAt": "2026-09-07T23:56:35.165Z",
3
+ "updatedAt": "2026-09-07T23:56:35.601Z",
4
+ "usId": "US-11301",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-113",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-1 firewall rule shape: 22 from operator-nominated prefixes, 80 and 443 open, all other inbound denied, applied at provision time",
10
+ "asA": "shelf consumer applying the deploy-hetzner-server v1.0.0 blueprint",
11
+ "iWant": "the firewall rule set carried in hetzner/servers/name.json to permit 22 only from an operator-nominated set of source-prefix ranges, permit 80 and 443 from 0.0.0.0/0 for the reverse proxy, and deny all other inbound; the provisioner applies the rules at provision time",
12
+ "soThat": "the operator inherits a documented least-privilege firewall shape on every server without opening ssh to the world",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-11301-1",
16
+ "description": "manifest-schema-validate.mjs asserts every fixture manifest carries a firewall rule set matching the shape (22 permitted only from a nonempty list of source-prefix ranges; 80 and 443 permitted; no other inbound rule); an induced defect (a manifest that opens 22 to 0.0.0.0/0) fails schema validation with a message naming the offending rule.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3802-deploy-hetzner-server-manifest-schema",
22
+ "TAC-3804-deploy-hetzner-server-firewall-shape"
23
+ ]
24
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-07T23:56:35.790Z",
3
+ "updatedAt": "2026-09-07T23:56:36.205Z",
4
+ "usId": "US-11401",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-114",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-1 snapshot cadence file present under the manifest set, cadence value elicited (weekly default, daily and off alternatives) matches the schema",
10
+ "asA": "shelf consumer applying the deploy-hetzner-server v1.0.0 blueprint",
11
+ "iWant": "the elicited snapshot cadence value on hetzner/servers/name.json to match the shipped enum (weekly, daily, off), with weekly the recommended default per ADR-3802",
12
+ "soThat": "the operator has a single project-wide answer for how often each server snapshots",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-11401-1",
16
+ "description": "manifest-schema-validate.mjs asserts every fixture manifest carries snapshotCadence with a value in the shipped enum {weekly, daily, off}; a manifest missing the field fails schema validation naming the missing field.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3802-deploy-hetzner-server-manifest-schema"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-07T23:56:36.391Z",
3
+ "updatedAt": "2026-09-07T23:56:36.806Z",
4
+ "usId": "US-11402",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-114",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-1 snapshot-on-demand verb fires the hcloud snapshot verb, tags the snapshot with server name and wall-clock time, hetznerSnapshotTaken event fires with snapshot id",
10
+ "asA": "shelf consumer applying the deploy-hetzner-server v1.0.0 blueprint on a real Hetzner account",
11
+ "iWant": "the snapshot-on-demand verb on the provisioner to shell to hcloud image create-image (or the raw-api equivalent) and tag the snapshot with server name and wall-clock time; hetznerSnapshotTaken carries snapshot id and time",
12
+ "soThat": "the operator has a documented on-demand recovery point at any moment",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-11402-1",
16
+ "description": "real-account-snapshot-on-demand.mjs (accountBound: true, skipped without CI_HAS_HETZNER_ACCOUNT) fires the snapshot verb on the throwaway server, then asserts hcloud image list --type=snapshot --output json shows a snapshot tagged with the server name and current wall-clock time; hetznerSnapshotTaken event carries snapshot id and time. Teardown via destroy.mjs.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3801-deploy-hetzner-server-provisioner"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-07T23:56:36.993Z",
3
+ "updatedAt": "2026-09-07T23:56:37.410Z",
4
+ "usId": "US-11501",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-115",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-1 four lifecycle events fire with metadata-only payloads, no secret leaks through any event body",
10
+ "asA": "shelf consumer applying the deploy-hetzner-server v1.0.0 blueprint",
11
+ "iWant": "the provisioner facade to fire the four lifecycle events (provisionerReady, hetznerServerProvisioned, hetznerSnapshotTaken, hetznerServerDestroyed) with metadata-only payloads (id, primaryIpv4, location, serverType, snapshotId, wallClockTime) and no secret content",
12
+ "soThat": "the observability sink carries the operational trail without ever leaking a token or an ssh key",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-11501-1",
16
+ "description": "hcloud-dry-run-mock.mjs drives every lifecycle event through the facade against a mocked hcloud shim; the accumulated event stream carries only the metadata fields named; a mutation (event-secrecy leak: inject the token into the hetznerServerProvisioned payload) FAILS the probe with a defensive-fake finding.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3801-deploy-hetzner-server-provisioner"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T01:41:01.418Z",
3
+ "updatedAt": "2026-09-08T01:42:32.120Z",
4
+ "usId": "US-12001",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-120",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-2 compose.yaml at repo root is the single-source runtime topology (service-per-container, named networks and volumes, .env for non-secret config)",
10
+ "asA": "shelf consumer applying the platform-docker-compose-host v1.0.0 blueprint on a project that runs its stack on a Hetzner cloudHost",
11
+ "iWant": "a single compose.yaml at the repo root to declare every service as one container with explicit named networks, named volumes, and non-secret config in a .env file",
12
+ "soThat": "the runtime topology has one auditable seam and the container host can bring the stack up from the file alone",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-12001-1",
16
+ "description": "The shared throwaway-server fixture ships compose.yaml at the fixture root with (a) every service running exactly one container image (service-per-container), (b) at least one named network under the top-level networks key, (c) at least one named volume under the top-level volumes key, and (d) non-secret config values are read via a colocated .env file rather than inlined into service environment entries.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3901-platform-docker-compose-host-compose-layout"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T01:41:59.208Z",
3
+ "updatedAt": "2026-09-08T01:42:32.309Z",
4
+ "usId": "US-12101",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-121",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-2 secrets flow via docker compose secrets file mounts (no plaintext literal in compose.yaml)",
10
+ "asA": "shelf consumer applying the platform-docker-compose-host v1.0.0 blueprint on a project with secret material bound to a container",
11
+ "iWant": "every secret to be declared under the compose secrets top-level key and mounted into the service via secrets: rather than inlined as an environment literal",
12
+ "soThat": "the compose file is safe to read at review time and the mounted file inherits 0o400 inside the container",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-12101-1",
16
+ "description": "The fixture compose.yaml declares at least one secret under the top-level secrets key with a file: source, references it from the web service through the service-level secrets: array, and no plaintext value for that secret appears anywhere in compose.yaml (grep-refuses on the literal). The secret file mode is 0o400 inside the container.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3902-platform-docker-compose-host-secrets-mount"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T01:44:43.238Z",
3
+ "updatedAt": "2026-09-08T01:44:43.862Z",
4
+ "usId": "US-12102",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-121",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-2 cross-cutting secretsAreFiles: the source-tree scan refuses any plaintext secret literal in compose.yaml or a referenced service config",
10
+ "asA": "shelf consumer applying the platform-docker-compose-host v1.0.0 blueprint on a project with sensitive material",
11
+ "iWant": "the secrets-as-files probe to walk compose.yaml and every service config in the fixture and refuse on any plaintext secret literal, naming the file and line",
12
+ "soThat": "a secret accidentally inlined in a review is caught by the probe before docker compose up runs",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-12102-1",
16
+ "description": "The secrets-as-files-scan probe walks compose.yaml plus every referenced service config file in the fixture and asserts (a) no line contains a plaintext token pattern (the applied literal name plus the applied literal value), (b) every declared secret in the compose secrets: key has a file: source, and (c) SIMULATE_PLAINTEXT_SECRET=true writes a plaintext literal into compose.yaml and the probe FAILS naming the file and the literal.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3902-platform-docker-compose-host-secrets-mount"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T01:42:40.956Z",
3
+ "updatedAt": "2026-09-08T01:42:41.556Z",
4
+ "usId": "US-12201",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-122",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-2 healthcheck contract: docker compose config refuses when an HTTP-terminating service is missing a healthcheck block",
10
+ "asA": "shelf consumer applying the platform-docker-compose-host v1.0.0 blueprint on a project that terminates HTTP inside a container",
11
+ "iWant": "the compose config lint to refuse at gate time on any HTTP-terminating service that is missing a healthcheck block, naming the service",
12
+ "soThat": "the stack never comes up with a service the container host cannot know is ready",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-12201-1",
16
+ "description": "The compose-config-lint probe shells to docker compose config against the fixture compose.yaml, asserts exit 0, and additionally asserts every HTTP-terminating service declares a healthcheck: block. SIMULATE_MISSING_HEALTHCHECK=true strips the block from the web service and the probe FAILS naming the service.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3903-platform-docker-compose-host-healthcheck-lint"
22
+ ]
23
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "createdAt": "2026-09-08T01:42:41.742Z",
3
+ "updatedAt": "2026-09-08T01:42:42.341Z",
4
+ "usId": "US-12202",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-122",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-2 cross-cutting upClean: the stack comes up clean and every declared service reaches healthy",
10
+ "asA": "shelf consumer applying the platform-docker-compose-host v1.0.0 blueprint on a Hetzner cloudHost",
11
+ "iWant": "the real-account minimal-stack-up probe to scp the compose.yaml to the throwaway server, run docker compose up -d --wait, and assert every declared service reaches healthy inside the elicited timeout",
12
+ "soThat": "the composeStackReady claim is proven on real docker before the blueprint ships",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-12202-1",
16
+ "description": "The real-account-minimal-stack-up probe, when CI_HAS_HETZNER_ACCOUNT is set, provisions the throwaway server, scps the compose.yaml, runs docker compose up -d --wait, asserts every declared service reaches healthy inside the elicited timeout, and tears down the stack plus the server in always(). Without CI_HAS_HETZNER_ACCOUNT the probe records accountBoundSkipped: true and the aggregate flips to pass.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3901-platform-docker-compose-host-compose-layout",
22
+ "TAC-3903-platform-docker-compose-host-healthcheck-lint"
23
+ ]
24
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T01:42:42.527Z",
3
+ "updatedAt": "2026-09-08T01:42:43.125Z",
4
+ "usId": "US-12301",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-123",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-2 restart discipline: unless-stopped on long-running, on-failure on jobs; unclassified value refuses at lint",
10
+ "asA": "shelf consumer applying the platform-docker-compose-host v1.0.0 blueprint",
11
+ "iWant": "the compose config lint to enforce a restart policy on every service and refuse on any value outside the two allowed policies (unless-stopped for long-running, on-failure for jobs)",
12
+ "soThat": "the operator sees a wrong or missing restart policy at gate time rather than as a stuck container",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-12301-1",
16
+ "description": "The compose-config-lint probe asserts every service in the compose.yaml declares a restart policy AND every declared value is one of unless-stopped or on-failure. SIMULATE_UNCLASSIFIED_RESTART=true sets restart: always on the web service and the probe FAILS naming the service and the disallowed value.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3903-platform-docker-compose-host-healthcheck-lint"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T01:42:43.312Z",
3
+ "updatedAt": "2026-09-08T01:42:43.912Z",
4
+ "usId": "US-12401",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-124",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-2 reverse-proxy config as a first-class versioned artefact (caddy/Caddyfile) validated by the vendor validator",
10
+ "asA": "shelf consumer applying the platform-docker-compose-host v1.0.0 blueprint with reverseProxy=caddy",
11
+ "iWant": "a checked-in caddy/Caddyfile bind-mounted into the proxy service so the reload verb picks up an operator change, validated at gate time by caddy validate",
12
+ "soThat": "a broken Caddyfile is caught before the reload burst runs, and there is one place in the tree the operator edits to route hostnames",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-12401-1",
16
+ "description": "The fixture ships caddy/Caddyfile at the fixture root under a caddy/ directory, the compose file bind-mounts it read-only into the caddy service, and the caddyfile-validate probe shells to caddy validate against the file and asserts exit 0. SIMULATE_INVALID_CADDYFILE=true writes an invalid directive into a scratch copy and the probe FAILS naming the line. Skipped when the applied reverseProxy is not caddy.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3904-platform-docker-compose-host-reverse-proxy-artefact"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T01:42:44.098Z",
3
+ "updatedAt": "2026-09-08T01:42:44.701Z",
4
+ "usId": "US-12402",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-124",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-2 cross-cutting zeroDowntimeReload: a client burst against the proxy during a config reload sees no non-2xx and no dropped connection inside the elicited window",
10
+ "asA": "shelf consumer applying the platform-docker-compose-host v1.0.0 blueprint",
11
+ "iWant": "the real-account reload-burst probe to fire an undici burst against the reverse proxy while docker compose exec caddy caddy reload runs and assert no non-2xx or dropped connection inside the elicited window",
12
+ "soThat": "the zero-downtime reload claim is proven on real docker before the blueprint ships",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-12402-1",
16
+ "description": "The real-account-reload-burst probe, when CI_HAS_HETZNER_ACCOUNT is set, runs undici GETs against the proxy service on the throwaway server while docker compose exec caddy caddy reload runs, asserts every request returns a 2xx status inside the elicited window (10 s default), asserts no dropped connection, tears the stack down in always(). Without CI_HAS_HETZNER_ACCOUNT the probe records accountBoundSkipped: true and the aggregate flips to pass.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3904-platform-docker-compose-host-reverse-proxy-artefact"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T01:42:44.888Z",
3
+ "updatedAt": "2026-09-08T01:42:45.499Z",
4
+ "usId": "US-12501",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-125",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-2 log shipping to the elicited observability-logging sink (journald default; loki opt-in)",
10
+ "asA": "shelf consumer applying the platform-docker-compose-host v1.0.0 blueprint on a project that may run Grafana or the estate default",
11
+ "iWant": "the elicited log driver to be wired into every service in the compose file (journald default, loki opt-in) and the choice recorded on the log-driver ADR",
12
+ "soThat": "the container stdout and stderr reach the applied observability sink without a per-service edit",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-12501-1",
16
+ "description": "Every service in the fixture compose.yaml declares a logging: driver: block whose driver value matches the elicited log driver (default journald). The compose-config-lint probe asserts (a) every service declares logging: driver, (b) the value is one of journald or loki, and (c) SIMULATE_UNCLASSIFIED_LOG_DRIVER=true sets a disallowed driver and the probe FAILS naming the service and the disallowed value.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-3903-platform-docker-compose-host-healthcheck-lint"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T03:21:16.415Z",
3
+ "updatedAt": "2026-09-08T03:21:16.415Z",
4
+ "usId": "US-13001",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-130",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-3 cloudflared connector install shape switches on applied containerHost (compose-service default; systemd-unit fallback for bare cloudHost)",
10
+ "asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 alongside deploy-hetzner-server (and optionally platform-docker-compose-host)",
11
+ "iWant": "the cloudflared connector to install as a compose service when the containerHost capability is applied and as a systemd unit when the host runs bare",
12
+ "soThat": "the runtime shape matches the applied platform rather than forcing a container onto a bare host or a bare service into a compose-managed stack",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-13001-1",
16
+ "description": "The blueprint declares its connector runtime via ADR-4002 with elicited enum {compose-service, systemd-unit} and recommendedDefault compose-service. The shared fixture ships both variants under packages/rcf-lite/test/fixtures/hetzner-throwaway-server/cloudflared/{compose-service,systemd-unit}/; the compose-service variant defines a cloudflared service alongside the T-2 web and caddy services on the same web-net network with restart unless-stopped, no host ports and a healthcheck; the systemd-unit variant ships a cloudflared.service unit file per the vendor local-configuration-file docs.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-4001-edge-cloudflare-tunnel-connector-shape"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T03:21:16.655Z",
3
+ "updatedAt": "2026-09-08T03:21:16.655Z",
4
+ "usId": "US-13002",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-130",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-3 cloudflared connector reports healthy on boot (tunnelConnectorUp fires with connector id, region, version)",
10
+ "asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 on a cloudHost",
11
+ "iWant": "the connector to emit a tunnelConnectorUp event on boot with connector id, region and version metadata (metadata only)",
12
+ "soThat": "the observability sink proves the tunnel is up without a shell into the host",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-13002-1",
16
+ "description": "real-account-connector-healthy probe declares accountBound true (on CI_HAS_CLOUDFLARE_ACCOUNT AND CI_HAS_HETZNER_ACCOUNT) and records accountBoundSkipped when either env var is unset. When both are set the probe drives cloudflared tunnel info against the fixture tunnel and asserts at least one healthy connector plus a tunnelConnectorUp event with connector id, region and version.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-4001-edge-cloudflare-tunnel-connector-shape"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T03:21:16.885Z",
3
+ "updatedAt": "2026-09-08T03:21:16.885Z",
4
+ "usId": "US-13101",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-131",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-3 tunnel manifest schema at cloudflare/tunnels/<name>.yaml validates on shape (tunnel id, credentials secretRef, ingress rules with catch-all 404)",
10
+ "asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0",
11
+ "iWant": "the tunnel manifest at cloudflare/tunnels/<name>.yaml to validate against a shipped JSON schema (uuid-shaped tunnel id, secretRef credentials, ingress rules with a mandatory catch-all http_status 404)",
12
+ "soThat": "a mis-shaped manifest is caught at apply-time rather than at first inbound request",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-13101-1",
16
+ "description": "manifest-schema-validate probe passes on the canonical fixture at cloudflared/*/cloudflare/tunnels/probe.yaml and fails when the fixture is mutated: SIMULATE_MANIFEST_INVALID_TUNNEL_ID rewrites the tunnel-id field to a non-uuid literal; SIMULATE_MANIFEST_CREDENTIALS_INLINE writes the credentials JSON body inline (bypassing the secretRef); SIMULATE_MANIFEST_MISSING_CATCHALL removes the catch-all rule. Each mutation FAILS naming the offending field.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-4002-edge-cloudflare-tunnel-manifest-schema"
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "createdAt": "2026-09-08T03:21:17.114Z",
3
+ "updatedAt": "2026-09-08T03:21:17.114Z",
4
+ "usId": "US-13102",
5
+ "prdId": "PRD-001",
6
+ "reqId": "REQ-131",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "title": "T-3 ingress rules route the public hostname to an internal service URL and cloudflared config lint exits 0",
10
+ "asA": "shelf consumer applying edge-cloudflare-tunnel v1.0.0 with a compose service listening on an internal port",
11
+ "iWant": "the ingress rule mapping the public hostname to the internal service URL (e.g. http://web:8080) to pass cloudflared tunnel ingress validate cleanly",
12
+ "soThat": "a rule that would fail at boot fails at gate instead",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-13102-1",
16
+ "description": "cloudflared-config-lint probe runs cloudflared tunnel ingress validate through the cloudflare/cloudflared container image (when the binary is not on PATH) against the fixture manifest and exits 0 on the canonical fixture; SIMULATE_INGRESS_INVALID rewrites the ingress rule service URL to an unresolvable scheme and the probe FAILS naming the offending line.",
17
+ "testable": true
18
+ }
19
+ ],
20
+ "tacIds": [
21
+ "TAC-4002-edge-cloudflare-tunnel-manifest-schema"
22
+ ]
23
+ }