hecks 2.8.0 → 2.9.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 (404) hide show
  1. checksums.yaml +4 -4
  2. data/exe/hecks +4 -6
  3. data/lib/hecks/adapters/driven/claude_code.rb +4 -104
  4. data/lib/hecks/adapters/driven/d1.rb +44 -237
  5. data/lib/hecks/adapters/driven/folder.rb +17 -76
  6. data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
  7. data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
  8. data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
  9. data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
  10. data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
  11. data/lib/hecks/adapters/driven/heki.rb +13 -42
  12. data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
  13. data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
  14. data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
  15. data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
  16. data/lib/hecks/adapters/driven/lambda.rb +10 -84
  17. data/lib/hecks/adapters/driven/local_storage.rb +5 -40
  18. data/lib/hecks/adapters/driven/memory.rb +17 -98
  19. data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
  20. data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
  21. data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
  22. data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
  23. data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
  24. data/lib/hecks/adapters/driven/postgres.rb +145 -134
  25. data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
  26. data/lib/hecks/adapters/driven/prism.rb +7 -30
  27. data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
  28. data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
  29. data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
  30. data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
  31. data/lib/hecks/adapters/driven/sqlite.rb +128 -65
  32. data/lib/hecks/adapters/driven/tenant_provisioner.rb +5 -48
  33. data/lib/hecks/adapters/driven.rb +5 -36
  34. data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
  35. data/lib/hecks/behaviors/dsl.rb +7 -25
  36. data/lib/hecks/behaviors/expectations.rb +31 -141
  37. data/lib/hecks/behaviors/ir.rb +7 -20
  38. data/lib/hecks/behaviors/rspec.rb +6 -17
  39. data/lib/hecks/behaviors/runner.rb +10 -34
  40. data/lib/hecks/behaviors.rb +4 -8
  41. data/lib/hecks/bluebook/aggregate.rb +9 -75
  42. data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
  43. data/lib/hecks/bluebook/assembly/build.rb +4 -15
  44. data/lib/hecks/bluebook/assembly/contract.rb +15 -136
  45. data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
  46. data/lib/hecks/bluebook/assembly/marks.rb +31 -223
  47. data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
  48. data/lib/hecks/bluebook/assembly.rb +6 -45
  49. data/lib/hecks/bluebook/attribute.rb +12 -61
  50. data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
  51. data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
  52. data/lib/hecks/bluebook/behaviour/chapter.rb +14 -42
  53. data/lib/hecks/bluebook/behaviour/command.rb +14 -66
  54. data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
  55. data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
  56. data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
  57. data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
  58. data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
  59. data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
  60. data/lib/hecks/bluebook/behaviour/read_model.rb +25 -31
  61. data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
  62. data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
  63. data/lib/hecks/bluebook/capabilities.rb +17 -49
  64. data/lib/hecks/bluebook/chapter.rb +10 -48
  65. data/lib/hecks/bluebook/command.rb +23 -81
  66. data/lib/hecks/bluebook/domain_port.rb +14 -63
  67. data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
  68. data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
  69. data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
  70. data/lib/hecks/bluebook/dsl/binding_proxy.rb +16 -69
  71. data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
  72. data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
  73. data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
  74. data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
  75. data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
  76. data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
  77. data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
  78. data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
  79. data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -194
  80. data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
  81. data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
  82. data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
  83. data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
  84. data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
  85. data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
  86. data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
  87. data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
  88. data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
  89. data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
  90. data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
  91. data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
  92. data/lib/hecks/bluebook/dsl/world_builder.rb +19 -111
  93. data/lib/hecks/bluebook/entity.rb +13 -71
  94. data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
  95. data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
  96. data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
  97. data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
  98. data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
  99. data/lib/hecks/bluebook/expression/resolver.rb +37 -660
  100. data/lib/hecks/bluebook/hexagon.rb +5 -28
  101. data/lib/hecks/bluebook/lifecycle.rb +5 -16
  102. data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
  103. data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
  104. data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
  105. data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
  106. data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
  107. data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
  108. data/lib/hecks/bluebook/meta_validator/shapes.rb +53 -267
  109. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +43 -305
  110. data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
  111. data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
  112. data/lib/hecks/bluebook/meta_validator.rb +79 -349
  113. data/lib/hecks/bluebook/model_check/client_profile.rb +6 -21
  114. data/lib/hecks/bluebook/model_check.rb +100 -597
  115. data/lib/hecks/bluebook/pattern_subset.rb +11 -69
  116. data/lib/hecks/bluebook/process_manager.rb +13 -83
  117. data/lib/hecks/bluebook/project_loader.rb +3 -39
  118. data/lib/hecks/bluebook/project_register.rb +12 -60
  119. data/lib/hecks/bluebook/query.rb +9 -48
  120. data/lib/hecks/bluebook/read_model.rb +57 -81
  121. data/lib/hecks/bluebook/reference.rb +7 -41
  122. data/lib/hecks/bluebook/smoke_test.rb +8 -98
  123. data/lib/hecks/bluebook/synthesizer.rb +13 -62
  124. data/lib/hecks/bluebook/translation.rb +26 -62
  125. data/lib/hecks/bluebook/value_object.rb +11 -36
  126. data/lib/hecks/bluebook.rb +5 -22
  127. data/lib/hecks/cache_dir.rb +4 -23
  128. data/lib/hecks/cli/document.rb +3 -21
  129. data/lib/hecks/cli/ir.rb +3 -5
  130. data/lib/hecks/cli/mcp.rb +2 -3
  131. data/lib/hecks/cli/mcp_door.rb +19 -114
  132. data/lib/hecks/cli/model_check.rb +18 -85
  133. data/lib/hecks/cli/project_cli.rb +7 -40
  134. data/lib/hecks/cli/project_diagrams.rb +0 -7
  135. data/lib/hecks/cli/run.rb +12 -58
  136. data/lib/hecks/cli/smoke_test.rb +2 -16
  137. data/lib/hecks/cli/stores.rb +1 -2
  138. data/lib/hecks/cli.rb +18 -24
  139. data/lib/hecks/construct.rb +8 -34
  140. data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
  141. data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
  142. data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
  143. data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
  144. data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
  145. data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
  146. data/lib/hecks/embryonaut_bluebook.rb +4 -71
  147. data/lib/hecks/facade/cli_door.rb +24 -106
  148. data/lib/hecks/facade/cli_runner.rb +28 -172
  149. data/lib/hecks/facade/command_request.rb +13 -33
  150. data/lib/hecks/facade/handle.rb +34 -121
  151. data/lib/hecks/facade/json_door.rb +31 -146
  152. data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
  153. data/lib/hecks/facade/surface/chapter.rb +10 -54
  154. data/lib/hecks/facade/surface.rb +8 -23
  155. data/lib/hecks/facade.rb +10 -25
  156. data/lib/hecks/forms/app.rb +15 -70
  157. data/lib/hecks/forms/command_form_renderer.rb +10 -29
  158. data/lib/hecks/forms/field_renderer.rb +17 -156
  159. data/lib/hecks/forms/field_shape.rb +30 -222
  160. data/lib/hecks/forms/html.rb +12 -47
  161. data/lib/hecks/forms/index_renderer.rb +1 -4
  162. data/lib/hecks/forms/page.rb +3 -9
  163. data/lib/hecks/forms/params.rb +14 -60
  164. data/lib/hecks/forms/port_argument.rb +2 -19
  165. data/lib/hecks/forms/query_form_renderer.rb +4 -79
  166. data/lib/hecks/forms/record_renderer.rb +8 -75
  167. data/lib/hecks/forms/record_table.rb +7 -50
  168. data/lib/hecks/forms/reference_options.rb +3 -30
  169. data/lib/hecks/forms/value_object_shape.rb +8 -35
  170. data/lib/hecks/forms.rb +5 -33
  171. data/lib/hecks/fqn.rb +5 -12
  172. data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
  173. data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
  174. data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
  175. data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
  176. data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
  177. data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
  178. data/lib/hecks/framework.rb +11 -80
  179. data/lib/hecks/freezer.rb +5 -39
  180. data/lib/hecks/grammar/expression.bluebook +15 -40
  181. data/lib/hecks/grammar/translation.bluebook +3 -6
  182. data/lib/hecks/grammar.rb +16 -41
  183. data/lib/hecks/ir.rb +14 -83
  184. data/lib/hecks/language/adapter.bluebook +2 -7
  185. data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
  186. data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
  187. data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
  188. data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
  189. data/lib/hecks/language/bluebook/command.bluebook +27 -144
  190. data/lib/hecks/language/bluebook/entity.bluebook +24 -97
  191. data/lib/hecks/language/bluebook/policy.bluebook +16 -67
  192. data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
  193. data/lib/hecks/language/bluebook/projection.bluebook +126 -60
  194. data/lib/hecks/language/bluebook/query.bluebook +12 -43
  195. data/lib/hecks/language/bluebook/shape.bluebook +23 -73
  196. data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
  197. data/lib/hecks/language/bluebook/vocabulary.bluebook +82 -197
  198. data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
  199. data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
  200. data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
  201. data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
  202. data/lib/hecks/language/oidc.json +35 -0
  203. data/lib/hecks/language/port.bluebook +4 -17
  204. data/lib/hecks/language/translation/translation.bluebook +3 -9
  205. data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
  206. data/lib/hecks/language/world/wiring.bluebook +1 -3
  207. data/lib/hecks/language/world/world.bluebook +5 -7
  208. data/lib/hecks/literal.rb +8 -50
  209. data/lib/hecks/mcp_door_scope.rb +9 -90
  210. data/lib/hecks/mcp_stdio_guard.rb +4 -41
  211. data/lib/hecks/naming.rb +29 -137
  212. data/lib/hecks/ports/access_control.rb +7 -23
  213. data/lib/hecks/ports/agent/answers.rb +5 -23
  214. data/lib/hecks/ports/agent.rb +47 -172
  215. data/lib/hecks/ports/authentication.rb +12 -39
  216. data/lib/hecks/ports/authorization.rb +16 -43
  217. data/lib/hecks/ports/clock.rb +5 -45
  218. data/lib/hecks/ports/extraction.rb +7 -12
  219. data/lib/hecks/ports/identity_assignment.rb +8 -29
  220. data/lib/hecks/ports/identity_generation.rb +6 -29
  221. data/lib/hecks/ports/identity_resolution.rb +2 -10
  222. data/lib/hecks/ports/key_vault.rb +9 -45
  223. data/lib/hecks/ports/persistence/append_only.rb +61 -64
  224. data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
  225. data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
  226. data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
  227. data/lib/hecks/ports/persistence/plugin.rb +13 -42
  228. data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
  229. data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
  230. data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
  231. data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +6 -25
  232. data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
  233. data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
  234. data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
  235. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
  236. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
  237. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
  238. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
  239. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
  240. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
  241. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
  242. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
  243. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
  244. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
  245. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
  246. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
  247. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
  248. data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
  249. data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
  250. data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
  251. data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
  252. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
  253. data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
  254. data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
  255. data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
  256. data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
  257. data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +18 -124
  258. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
  259. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
  260. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
  261. data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
  262. data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
  263. data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
  264. data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
  265. data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
  266. data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
  267. data/lib/hecks/ports/persistence/state_codec.rb +23 -103
  268. data/lib/hecks/ports/persistence.rb +7 -14
  269. data/lib/hecks/ports/projection.rb +42 -84
  270. data/lib/hecks/ports/query/in_memory.rb +10 -58
  271. data/lib/hecks/ports/query/ordering.rb +11 -32
  272. data/lib/hecks/ports/query.rb +14 -37
  273. data/lib/hecks/ports.rb +2 -8
  274. data/lib/hecks/projections/bootstrap_table.rb +11 -43
  275. data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
  276. data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
  277. data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
  278. data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
  279. data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
  280. data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
  281. data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
  282. data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
  283. data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
  284. data/lib/hecks/projections/deploy/fargate.rb +35 -202
  285. data/lib/hecks/projections/deploy/lambda.rb +150 -678
  286. data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
  287. data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
  288. data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
  289. data/lib/hecks/projections/deploy/preview/script.rb +2 -14
  290. data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
  291. data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
  292. data/lib/hecks/projections/deploy/preview/template.rb +2 -58
  293. data/lib/hecks/projections/deploy/preview.rb +2 -67
  294. data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
  295. data/lib/hecks/projections/deploy/scripts.rb +4 -57
  296. data/lib/hecks/projections/deploy/shared.rb +47 -146
  297. data/lib/hecks/projections/deploy/smoke.rb +4 -61
  298. data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
  299. data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
  300. data/lib/hecks/projections/deploy/template_diff.rb +5 -57
  301. data/lib/hecks/projections/diagrams.rb +20 -582
  302. data/lib/hecks/projections/glossary/html.rb +14 -130
  303. data/lib/hecks/projections/glossary/markdown.rb +8 -69
  304. data/lib/hecks/projections/glossary/mermaid.rb +9 -66
  305. data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
  306. data/lib/hecks/projections/glossary/sentences.rb +14 -159
  307. data/lib/hecks/projections/glossary.rb +30 -222
  308. data/lib/hecks/projections/ir.rb +3 -10
  309. data/lib/hecks/projections/model/deviations.rb +15 -42
  310. data/lib/hecks/projections/model.rb +12 -51
  311. data/lib/hecks/projections/oidc.rb +12 -56
  312. data/lib/hecks/projections/parser_table.rb +9 -28
  313. data/lib/hecks/projections/reference.rb +2 -15
  314. data/lib/hecks/projections/rust_vocabulary.rb +12 -250
  315. data/lib/hecks/projections/shape.rb +3 -29
  316. data/lib/hecks/projections/statements.rb +7 -86
  317. data/lib/hecks/projections/vocabulary.rb +6 -22
  318. data/lib/hecks/projections.rb +2 -16
  319. data/lib/hecks/projector/cli_projector.rb +60 -375
  320. data/lib/hecks/projector/docs_projector.rb +10 -201
  321. data/lib/hecks/projector/exporter.rb +42 -134
  322. data/lib/hecks/projector/ir_projector.rb +2 -9
  323. data/lib/hecks/projector/narrate_projector.rb +15 -189
  324. data/lib/hecks/projector/target.rb +13 -76
  325. data/lib/hecks/projector.rb +30 -121
  326. data/lib/hecks/query_specification/common/comparators.rb +5 -26
  327. data/lib/hecks/query_specification/common/comparison.rb +35 -143
  328. data/lib/hecks/query_specification/common/dsl.rb +8 -24
  329. data/lib/hecks/query_specification/common/null_policy.rb +20 -70
  330. data/lib/hecks/query_specification/common/options.rb +2 -6
  331. data/lib/hecks/query_specification/common/where_clause.rb +2 -10
  332. data/lib/hecks/query_specification/field_path.rb +37 -77
  333. data/lib/hecks/query_specification/hop_path.rb +12 -76
  334. data/lib/hecks/release/gem_pin.rb +2 -26
  335. data/lib/hecks/release/runner/ci_publisher.rb +3 -6
  336. data/lib/hecks/release/runner/commands.rb +2 -4
  337. data/lib/hecks/release/runner/gem_publisher.rb +2 -3
  338. data/lib/hecks/release/runner/npm_publisher.rb +6 -20
  339. data/lib/hecks/release/runner/preflight.rb +4 -19
  340. data/lib/hecks/release/runner/tagger.rb +2 -9
  341. data/lib/hecks/release/runner.rb +3 -32
  342. data/lib/hecks/rendering.rb +4 -26
  343. data/lib/hecks/router/namespace_installer.rb +12 -36
  344. data/lib/hecks/router.rb +4 -8
  345. data/lib/hecks/runtime/aggregate_lock.rb +8 -33
  346. data/lib/hecks/runtime/boot_gates.rb +3 -18
  347. data/lib/hecks/runtime/caller.rb +19 -59
  348. data/lib/hecks/runtime/capability_graph.rb +5 -21
  349. data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
  350. data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
  351. data/lib/hecks/runtime/command_interpreter.rb +124 -306
  352. data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
  353. data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
  354. data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
  355. data/lib/hecks/runtime/command_rules/emission.rb +8 -21
  356. data/lib/hecks/runtime/command_rules/references.rb +23 -202
  357. data/lib/hecks/runtime/dependency_planning.rb +30 -102
  358. data/lib/hecks/runtime/dispatcher.rb +82 -241
  359. data/lib/hecks/runtime/entity_element.rb +40 -462
  360. data/lib/hecks/runtime/entity_interpreter.rb +64 -219
  361. data/lib/hecks/runtime/errors.rb +32 -115
  362. data/lib/hecks/runtime/event.rb +3 -25
  363. data/lib/hecks/runtime/identity.rb +18 -154
  364. data/lib/hecks/runtime/instance.rb +18 -150
  365. data/lib/hecks/runtime/interpreting.rb +11 -70
  366. data/lib/hecks/runtime/invocation.rb +28 -164
  367. data/lib/hecks/runtime/loader.rb +48 -186
  368. data/lib/hecks/runtime/outbox.rb +38 -261
  369. data/lib/hecks/runtime/policy_interpreter.rb +38 -200
  370. data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
  371. data/lib/hecks/runtime/query_interpreter.rb +45 -187
  372. data/lib/hecks/runtime/reaction_invocation.rb +36 -138
  373. data/lib/hecks/runtime/read_model_interpreter.rb +117 -208
  374. data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
  375. data/lib/hecks/runtime/reference_hop.rb +8 -81
  376. data/lib/hecks/runtime/refusal_wording.rb +8 -89
  377. data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
  378. data/lib/hecks/runtime/registry/verification.rb +52 -225
  379. data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
  380. data/lib/hecks/runtime/registry.rb +99 -244
  381. data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
  382. data/lib/hecks/runtime/routing.rb +4 -15
  383. data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
  384. data/lib/hecks/runtime/saga_interpreter.rb +79 -263
  385. data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
  386. data/lib/hecks/runtime/tenant_check.rb +6 -68
  387. data/lib/hecks/runtime/tenant_scope.rb +3 -28
  388. data/lib/hecks/runtime/value/admission.rb +16 -67
  389. data/lib/hecks/runtime/value/coercion.rb +155 -641
  390. data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
  391. data/lib/hecks/runtime/value.rb +12 -84
  392. data/lib/hecks/runtime.rb +17 -65
  393. data/lib/hecks/storehouse.rb +141 -568
  394. data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
  395. data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
  396. data/lib/hecks/vendoring/git_environment.rb +2 -8
  397. data/lib/hecks/vendoring/git_source.rb +4 -10
  398. data/lib/hecks/vendoring.rb +7 -46
  399. data/lib/hecks/version.rb +3 -14
  400. data/lib/hecks.rb +26 -81
  401. data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
  402. data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
  403. data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
  404. metadata +3 -2
@@ -6,32 +6,7 @@ module Hecks
6
6
  module Deploy
7
7
  module Fargate
8
8
  # The containers of one Fargate task and how the load balancer reaches them.
9
- #
10
- # A stack always has the domain container: `rust/host` built from the
11
- # domain itself. The world's `containers` setting adds more containers
12
- # to the same task (a website, a content admin), each with its own ECR
13
- # repository, image-tag parameter, target group and health check.
14
- # `routes` sends URL path patterns to a container through listener
15
- # rules on the one load balancer, and `default_container` names the
16
- # container that answers everything else.
17
- #
18
- # ## Settings
19
- #
20
- # `domain_container` renames the domain container's own pieces:
21
- # `name`, `repository`, `image_tag_parameter` and `health_path`. Its `essential`
22
- # writes an explicit `Essential` flag; the container is essential either way,
23
- # since that is `ECS`'s default.
24
- #
25
- # Each `containers` entry takes `name` and `repository` (required),
26
- # and `port`, `health_path`, `env`, `secrets`, `image_tag_parameter`,
27
- # `essential`, `cpu`, `memory`, `repository_id` and `target_group_id`.
28
- # A container without a `port` receives no load-balancer traffic.
29
- # `env` values and `secrets` values may be CloudFormation intrinsics
30
- # written as strings (`"!Ref Name"`, `"!Sub \"...\""`).
31
- #
32
- # Each `routes` entry takes `container`, `paths` (one to five path
33
- # patterns, since a listener rule condition holds at most five),
34
- # `priority` and an optional `id`.
9
+ # The domain container (`rust/host`) is always present; more are added via `containers`.
35
10
  module Containers
36
11
  module_function
37
12
 
@@ -43,23 +18,15 @@ module Hecks
43
18
  Route = Struct.new(:id, :container, :paths, :priority, keyword_init: true)
44
19
  Layout = Struct.new(:domain, :extras, :routes, :default_container, keyword_init: true) do
45
20
  # Lists the domain container followed by every added container.
46
- #
47
- # @return [Array<Container>] every container of the task
48
21
  def all = [domain, *extras]
49
22
 
50
23
  # Lists the containers that receive load-balancer traffic.
51
- #
52
- # @return [Array<Container>] the containers with a port
53
24
  def balanced = all.select(&:port)
54
25
 
55
26
  # Tells whether the stack has any container besides the domain's own.
56
- #
57
- # @return [Boolean] true when `containers` added at least one
58
27
  def multi? = !extras.empty?
59
28
 
60
29
  # Finds the container the listener forwards to by default.
61
- #
62
- # @return [Container] the default container
63
30
  def default = all.find { |container| container.name == default_container }
64
31
  end
65
32
 
@@ -71,15 +38,6 @@ module Hecks
71
38
  ROUTE_KEYS = [:container, :paths, :priority, :id].freeze
72
39
 
73
40
  # Reads the container-related settings into a `Layout`.
74
- #
75
- # @param settings [Hash{Symbol => Object}] the world's `deployed_to("AwsFargate")`
76
- # settings
77
- # @param infra_name [String] the domain's own AWS-facing name, the default container name
78
- # @param port [Integer] the validated port of the domain container
79
- # @param ids [Hash{Symbol => String}] the resolved logical ids, for the domain container's
80
- # own
81
- # @return [Layout] the containers, routes and default container
82
- # @raise [ArgumentError] if a container, route or the default container is invalid
83
41
  def normalize(settings, infra_name:, port:, ids:)
84
42
  domain = domain_container(settings[:domain_container], infra_name: infra_name, port: port, ids: ids)
85
43
  extras = Check.hashes!(settings.fetch(:containers, []), "containers", allowed: CONTAINER_KEYS,
@@ -96,9 +54,6 @@ module Hecks
96
54
  end
97
55
 
98
56
  # Renders the ECR repository of every added container.
99
- #
100
- # @param layout [Layout] the stack's containers
101
- # @return [String] flush-left resources separated by blank lines, or empty
102
57
  def repositories_yaml(layout)
103
58
  layout.extras.map do |container|
104
59
  <<~REPOSITORY.rstrip
@@ -113,9 +68,6 @@ module Hecks
113
68
  end
114
69
 
115
70
  # Renders the image-tag parameter of every added container.
116
- #
117
- # @param layout [Layout] the stack's containers
118
- # @return [String] flush-left parameters, each ending in a newline, or empty
119
71
  def parameters_yaml(layout)
120
72
  layout.extras.map do |container|
121
73
  <<~PARAMETER
@@ -128,21 +80,11 @@ module Hecks
128
80
  end
129
81
 
130
82
  # Renders the added containers as `ContainerDefinitions` list entries.
131
- #
132
- # @param layout [Layout] the stack's containers
133
- # @param log_group_id [String] the logical id of the shared log group
134
- # @return [String] flush-left list entries separated by blank lines, or empty
135
83
  def definitions_yaml(layout, log_group_id)
136
84
  layout.extras.map { |container| definition_yaml(container, log_group_id) }.join("\n\n")
137
85
  end
138
86
 
139
87
  # Renders the target group of every added container.
140
- #
141
- # @param layout [Layout] the stack's containers
142
- # @param vpc_ref [String] the `!Ref` expression for the VPC the targets live in
143
- # @param deregistration_delay [Integer, nil] seconds the load balancer drains a target, or
144
- # nil for the default
145
- # @return [String] flush-left resources separated by blank lines, or empty
146
88
  def target_groups_yaml(layout, vpc_ref, deregistration_delay)
147
89
  layout.extras.select(&:port).map do |container|
148
90
  [
@@ -161,9 +103,6 @@ module Hecks
161
103
  end
162
104
 
163
105
  # Renders the `TargetGroupAttributes` property for a drain delay.
164
- #
165
- # @param deregistration_delay [Integer, nil] seconds the load balancer drains a target
166
- # @return [String] flush-left property lines ending in a newline, or empty for nil
167
106
  def target_group_attributes_yaml(deregistration_delay)
168
107
  return "" unless deregistration_delay
169
108
 
@@ -175,10 +114,6 @@ module Hecks
175
114
  end
176
115
 
177
116
  # Renders one listener rule per route.
178
- #
179
- # @param layout [Layout] the stack's containers and routes
180
- # @param listener_id [String] the logical id of the HTTP listener
181
- # @return [String] flush-left resources separated by blank lines, or empty
182
117
  def listener_rules_yaml(layout, listener_id)
183
118
  layout.routes.map do |route|
184
119
  target = layout.all.find { |container| container.name == route.container }
@@ -199,9 +134,6 @@ module Hecks
199
134
  end
200
135
 
201
136
  # Renders the service's `LoadBalancers` entries for the added containers.
202
- #
203
- # @param layout [Layout] the stack's containers
204
- # @return [String] flush-left list entries, or empty
205
137
  def load_balancers_yaml(layout)
206
138
  layout.extras.select(&:port).map do |container|
207
139
  <<~ENTRY
@@ -212,12 +144,8 @@ module Hecks
212
144
  end.join
213
145
  end
214
146
 
215
- # Writes the `DependsOn` value that holds the service until the listener and its rules
216
- # exist.
217
- #
218
- # @param layout [Layout] the stack's containers and routes
219
- # @param listener_id [String] the logical id of the HTTP listener
220
- # @return [String] a single id, or a flow list of ids
147
+ # Writes the `DependsOn` value that holds the service until the listener and its
148
+ # rules exist.
221
149
  def depends_on(layout, listener_id)
222
150
  return listener_id if layout.routes.empty?
223
151
 
@@ -225,9 +153,6 @@ module Hecks
225
153
  end
226
154
 
227
155
  # Finds the first and last container port the load balancer must reach.
228
- #
229
- # @param layout [Layout] the stack's containers
230
- # @return [Range<Integer>] the security-group ingress port range
231
156
  def port_range(layout)
232
157
  ports = layout.balanced.map(&:port)
233
158
  ports.min..ports.max
@@ -5,26 +5,8 @@ module Hecks
5
5
  module Projections
6
6
  module Deploy
7
7
  module Fargate
8
- # The extra resources, parameters, outputs and IAM grants a stack can
9
- # declare beyond the ones the generator always makes.
10
- #
11
- # ## Settings
12
- #
13
- # - `buckets`: S3 buckets, each `{id:, name_prefix:, public_read:, cors_origins:}`. The
14
- # bucket is named `<name_prefix>-<account id>`. `public_read` opens the bucket to
15
- # anonymous `GetObject`. `cors_origins` allows those origins to `GET` from a browser.
16
- # - `generated_secrets`: Secrets Manager secrets with a generated value, each
17
- # `{id:, name:, description:, key:, length:}`. `key` is the JSON field the value is
18
- # stored under (`secret`).
19
- # - `session_secret`: `{name:, description:}` names the always-created session secret
20
- # and describes it.
21
- # - `task_policies` and `execution_policies`: extra IAM policies for the task role (what
22
- # the containers may do) and the execution role (what `ECS` may do to start them).
23
- # Each is `{name:, statements: [{effect:, actions:, resources:}]}`; `effect` is `Allow`
24
- # by default and resources may be intrinsics.
25
- # - `parameters`: extra template parameters, a map of name to
26
- # `{type:, default:, description:, no_echo:}`.
27
- # - `outputs`: extra template outputs, a map of name to a value or intrinsic.
8
+ # The extra resources, parameters, outputs and IAM grants a stack can declare beyond
9
+ # what the generator always makes; settings are documented in the DSL reference.
28
10
  module Extras
29
11
  module_function
30
12
 
@@ -38,14 +20,6 @@ module Hecks
38
20
  ssmmessages:OpenControlChannel ssmmessages:OpenDataChannel].freeze
39
21
 
40
22
  # Reads and checks the resource-declaring settings.
41
- #
42
- # @param settings [Hash{Symbol => Object}] the world's `deployed_to("AwsFargate")`
43
- # settings
44
- # @return [Hash{Symbol => Object}] `:buckets`, `:secrets`, `:session_secret`,
45
- # `:task_policies`,
46
- # `:execution_policies`, `:parameters` and `:outputs`, each checked and defaulted to
47
- # empty
48
- # @raise [ArgumentError] if any of those settings is malformed
49
23
  def normalize(settings)
50
24
  {
51
25
  buckets: buckets(settings.fetch(:buckets, [])),
@@ -59,9 +33,6 @@ module Hecks
59
33
  end
60
34
 
61
35
  # Renders the buckets and generated secrets.
62
- #
63
- # @param extras [Hash] the checked settings from `normalize`
64
- # @return [String] flush-left resources separated by blank lines, or empty
65
36
  def resources_yaml(extras)
66
37
  (extras[:buckets].flat_map { |bucket| bucket_blocks(bucket) } + extras[:secrets].map do |secret|
67
38
  secret_yaml(secret)
@@ -69,16 +40,11 @@ module Hecks
69
40
  end
70
41
 
71
42
  # Renders extra policies as entries of a role's `Policies` list.
72
- #
73
- # @param policies [Array<Hash>] the checked policies
74
- # @return [String] flush-left list entries, or empty
75
43
  def policies_yaml(policies)
76
44
  policies.map { |policy| policy_yaml(policy) }.join
77
45
  end
78
46
 
79
47
  # Renders the policy that lets `aws ecs execute-command` open a session in a container.
80
- #
81
- # @return [String] one flush-left `Policies` list entry
82
48
  def execute_command_policy_yaml
83
49
  policy_yaml(
84
50
  name: "EcsExecDebug",
@@ -87,9 +53,6 @@ module Hecks
87
53
  end
88
54
 
89
55
  # Renders the extra template parameters.
90
- #
91
- # @param parameters [Hash{String => Hash}] the checked parameters
92
- # @return [String] flush-left parameters, or empty
93
56
  def parameters_yaml(parameters)
94
57
  parameters.map do |name, given|
95
58
  lines = ["#{name}:", " Type: #{given[:type]}"]
@@ -101,9 +64,6 @@ module Hecks
101
64
  end
102
65
 
103
66
  # Renders the extra template outputs.
104
- #
105
- # @param outputs [Hash{String => Object}] the checked outputs
106
- # @return [String] flush-left outputs, or empty
107
67
  def outputs_yaml(outputs)
108
68
  outputs.map { |name, value| "#{name}:\n Value: #{Yaml.string(value)}\n" }.join
109
69
  end
@@ -253,8 +213,7 @@ module Hecks
253
213
  end
254
214
  private_class_method :policy_yaml
255
215
 
256
- # One entry is written as a scalar, the form IAM policies are usually written in; more are
257
- # a list.
216
+ # One entry is written as a scalar, the form IAM policies usually take; more are a list.
258
217
  def statement_list(key, values)
259
218
  return [" #{key}: #{values.first}"] if values.one?
260
219
 
@@ -7,33 +7,6 @@ module Hecks
7
7
  module Fargate
8
8
  # Alerting for a Fargate stack: an `SNS` topic, CloudWatch alarms, and an
9
9
  # optional synthetic check.
10
- #
11
- # Every alarm reports to the topic on both alarm and recovery. An email
12
- # address subscribes to the topic, but `SNS` holds the subscription as
13
- # pending until the recipient follows the confirmation link it mails;
14
- # the stack cannot do that step.
15
- #
16
- # ## Settings
17
- #
18
- # `alerts` is a hash:
19
- #
20
- # - `topic`: the `SNS` topic name (required).
21
- # - `email`: an address to subscribe to the topic.
22
- # - `alarms`: a list of kinds, each a string or a hash `{kind:, container:, threshold:,
23
- # period:, evaluation_periods:, datapoints_to_alarm:, description:}`. The kinds are
24
- # `alb_5xx` (5xx responses from targets), `target_unhealthy` (an unhealthy target, for
25
- # one `container` or for every load-balanced one) and `cloudfront_5xx` (5xx responses
26
- # counted at the edge).
27
- # - `warmer`: `{paths:, namespace:, rate:}` adds a function that requests each path
28
- # through the CDN on a schedule and reports failures as a metric, with an alarm that
29
- # also fires when the metric goes silent. `code` replaces the function's inline source,
30
- # and `schedule_description` and `alarm_description` replace the schedule's and the
31
- # alarm's description text.
32
- #
33
- # The logical ids come from `logical_ids`: `alerts_topic`, `alerts_subscription`,
34
- # `alb_5xx_alarm`, `cloudfront_5xx_alarm`, `cloudfront_monitoring`, `synthetic_alarm`,
35
- # `warmer_role`, `warmer_function`, `scheduler_role` and `warmer_schedule`. A
36
- # per-container alarm is `<Container>TargetUnhealthyAlarm`.
37
10
  module Monitoring
38
11
  module_function
39
12
 
@@ -56,13 +29,6 @@ module Hecks
56
29
  synthetic: "The synthetic check found a non-200 response on a real path, or stopped reporting."
57
30
  }.freeze
58
31
 
59
- # Reads and checks the `alerts` setting.
60
- #
61
- # @param setting [Hash, nil] the world's `alerts` value, or nil when it sets none
62
- # @param containers [Array<String>] the names of the load-balanced containers
63
- # @return [Hash{Symbol => Object}, nil] the checked settings, or nil for none
64
- # @raise [ArgumentError] if a key is unknown or malformed, or an alarm names a container
65
- # that has no target group
66
32
  def normalize(setting, containers:)
67
33
  return nil if setting.nil?
68
34
 
@@ -76,20 +42,10 @@ module Hecks
76
42
  }
77
43
  end
78
44
 
79
- # Tells whether any alarm needs the CloudFront metrics subscription.
80
- #
81
- # @param alerts [Hash, nil] the checked settings from `normalize`
82
- # @return [Boolean] true when a `cloudfront_5xx` alarm is declared
83
45
  def cloudfront_metrics?(alerts)
84
46
  !alerts.nil? && alerts[:alarms].any? { |alarm| alarm[:kind] == "cloudfront_5xx" }
85
47
  end
86
48
 
87
- # Renders every alerting resource.
88
- #
89
- # @param alerts [Hash] the checked settings from `normalize`
90
- # @param context [Hash{Symbol => Object}] `:ids` (resolved logical ids), `:stack_name`,
91
- # `:alb_id`, `:distribution_id` and `:target_groups` (container name to target group id)
92
- # @return [String] flush-left resources separated by blank lines, ending in a blank line
93
49
  def yaml(alerts, context)
94
50
  blocks = [topic_yaml(alerts, context[:ids])]
95
51
  blocks << subscription_yaml(alerts, context[:ids]) if alerts[:email]
@@ -12,44 +12,7 @@ module Hecks
12
12
  # Everything a `deployed_to("AwsFargate")` block can say beyond its
13
13
  # required settings, read and checked into one `Plan`.
14
14
  #
15
- # A world that sets none of these keys resolves to a plan whose every
16
- # value is the generator's own default: the derived logical ids and
17
- # names, one container, no extra resources. That plan renders the same
18
- # template the generator has always produced.
19
- #
20
- # ## Settings owned here
21
- #
22
- # - `logical_ids`: a map of role to logical id that replaces the id derived from the
23
- # stack name, so an existing stack's ids can be reproduced. The roles are `service`,
24
- # `ecr_repository`, `cluster`, `task_definition`, `execution_role`, `task_role`,
25
- # `log_group`, `target_group`, `alb`, `alb_security_group`, `listener`, `distribution`,
26
- # `session_secret`, `ingress_from_alb`, `database_prefix` and `compute_prefix`, plus
27
- # the alerting roles `Monitoring` lists. `database_prefix` and `compute_prefix` are the
28
- # prefixes of the VPC and database ids and of the compute security-group ids.
29
- # - `names`: a map of role to the AWS name that replaces the derived one. The roles are
30
- # `cluster`, `log_group`, `service`, `alb` and `family`; `db_secret_policy`, the name of
31
- # the task role's database-secret policy (`DbSecretRead`); and
32
- # `alb_security_group_description`, the load balancer's security group description
33
- # (EC2 replaces the group when it changes).
34
- # - `execution_role_database_grant`: false leaves the database secret out of the
35
- # execution role. The host reads that secret itself with the task role, so the
36
- # execution role needs it only when a container's `ECS` `Secrets` names it;
37
- # `execution_policies` must then hold a policy.
38
- # - `execute_command`: true lets `aws ecs execute-command` open a session in a container.
39
- # - `health_check_grace_period`: seconds `ECS` ignores failing load-balancer health
40
- # checks after a task starts.
41
- # - `deregistration_delay`: seconds a target group drains a deregistered target.
42
- # - `desired_count_parameter`: makes the service's desired count a template parameter
43
- # with this name, defaulting to `desired_count`.
44
- # - `domain_env`: extra environment variables for the domain container, a map of name to
45
- # a value or intrinsic. A name the generator already sets replaces it; a `nil` value
46
- # removes it.
47
- # - `install_dir`: where the Dockerfile installs the host binary and its `.wasm` and
48
- # `.ir.json` files, and where `HECKS_WASM_PATH` and `HECKS_IR_PATH` point
49
- # (`/usr/local/bin`).
50
- # - `build_context_dir`: a directory prefix for the Dockerfile's `COPY` sources.
51
- # - `db_name_parameter`: for `database "Shared"`, a template parameter that names the
52
- # shared database, defaulting to the owner's name.
15
+ # A world that sets none of these keys resolves entirely to the generator's own defaults.
53
16
  module Settings
54
17
  module_function
55
18
 
@@ -75,16 +38,7 @@ module Hecks
75
38
  NAME_ROLES = [:cluster, :log_group, :service, :alb, :family, :alb_security_group_description, :db_secret_policy].freeze
76
39
  DEFAULT_INSTALL_DIR = "/usr/local/bin".freeze
77
40
 
78
- # Reads and checks every optional setting into a `Plan`.
79
- #
80
- # @param settings [Hash{Symbol => Object}] the world's `deployed_to("AwsFargate")`
81
- # settings
82
- # @param base [Hash{Symbol => Object}] facts the generator has already resolved:
83
- # `:infra_name`,
84
- # `:logical_id`, `:db_id`, `:stack_name`, `:port`, `:desired_count` and `:shared`
85
- # @return [Plan] the checked settings with every default applied
86
- # @raise [ArgumentError] if any setting is malformed, or two settings contradict each
87
- # other
41
+ # Reads and checks every optional setting into a frozen `Plan`, applying every default.
88
42
  def resolve(settings, base)
89
43
  ids = logical_ids(settings[:logical_ids], base)
90
44
  layout = Containers.normalize(settings, infra_name: base[:infra_name], port: base[:port], ids: ids)
@@ -98,12 +52,6 @@ module Hecks
98
52
  end
99
53
 
100
54
  # Lists every template parameter the plan declares beyond the generator's own.
101
- #
102
- # @param plan [Plan] the resolved plan
103
- # @param default_count [Integer] the service's `desired_count`, the default of its
104
- # parameter
105
- # @param shared_db_name [String, nil] the owning database's name, when `database "Shared"`
106
- # @return [String] flush-left parameter text separated by newlines, or empty
107
55
  def parameters_yaml(plan, default_count:, shared_db_name:)
108
56
  [
109
57
  Containers.parameters_yaml(plan.layout), Cdn.parameters_yaml(plan.cdn),
@@ -4,23 +4,13 @@ module Hecks
4
4
  module Fargate
5
5
  # Text helpers the Fargate template generator renders YAML with.
6
6
  #
7
- # The template is built as text, not as a data structure, so the
8
- # comments that explain each resource survive into the generated file.
9
- # These helpers cover the three things text rendering needs: writing a
10
- # setting's value as a YAML scalar, indenting a flush-left block, and
11
- # splicing a block into a marker line of the surrounding template.
7
+ # The template is built as text, not as a data structure, so the comments
8
+ # that explain each resource survive into the generated file.
12
9
  module Yaml
13
10
  module_function
14
11
 
15
- # Writes one value as a YAML scalar.
16
- #
17
- # A string that starts with `!` is a CloudFormation intrinsic
18
- # (`!Ref Name`, `!Sub "..."`, `!GetAtt Name.Arn`) and is written
19
- # verbatim. Any other string is double-quoted, so a value such as
20
- # `"1"` stays a string. Numbers and booleans are written bare.
21
- #
22
- # @param value [String, Integer, Float, true, false] the value to render
23
- # @return [String] the YAML text for the value, on one line
12
+ # Writes one value as a YAML scalar; a leading `!` marks a CloudFormation
13
+ # intrinsic (`!Ref`, `!Sub`, `!GetAtt`) and is left unquoted.
24
14
  def scalar(value)
25
15
  case value
26
16
  when true, false, Integer, Float then value.to_s
@@ -30,28 +20,15 @@ module Hecks
30
20
  end
31
21
  end
32
22
 
33
- # Writes a value as a scalar that must stay a string.
34
- #
35
- # Environment values and container settings such as a port are
36
- # strings to `ECS` however they are typed in the world file, so a
37
- # number is quoted here where `scalar` would leave it bare.
38
- #
39
- # @param value [Object] the value to render
40
- # @return [String] the YAML text for the value, on one line
23
+ # Writes a value as a scalar that must stay a string, quoting a number
24
+ # where `scalar` would leave it bare.
41
25
  def string(value)
42
26
  text = value.to_s
43
27
  text.start_with?("!") ? text : text.to_json
44
28
  end
45
29
 
46
- # Writes a list as a YAML flow sequence.
47
- #
48
- # A string made of a word (an id, an HTTP method) is left bare; any
49
- # other string is written with `scalar`, so a value YAML would read
50
- # as a number, a boolean or null stays a string.
51
- #
52
- # @param values [Array<Object>] the items, each rendered with `scalar` unless it is a
53
- # plain word
54
- # @return [String] the `[a, b]` text
30
+ # Writes a list as a YAML flow sequence, rendering each item with `scalar`
31
+ # unless it is a bare word, so a numeric-looking string stays quoted.
55
32
  def flow_list(values)
56
33
  "[#{values.map { |value| plain_word?(value) ? value : scalar(value) }.join(', ')}]"
57
34
  end
@@ -62,26 +39,13 @@ module Hecks
62
39
  end
63
40
  private_class_method :plain_word?
64
41
 
65
- # Indents every non-blank line of a block.
66
- #
67
- # @param text [String] the block to indent
68
- # @param base [String] the whitespace to put in front of each non-blank line
69
- # @return [String] the block, indented, with blank lines left empty
42
+ # Indents every non-blank line of a block; blank lines stay empty.
70
43
  def indent(text, base)
71
44
  text.each_line.map { |line| line.strip.empty? ? line : "#{base}#{line}" }.join
72
45
  end
73
46
 
74
- # Replaces one `# TMPL:<marker>` line of a template with a block.
75
- #
76
- # The block is written flush-left and takes the marker line's own
77
- # indentation. An empty block removes the marker line completely, so
78
- # a template that uses none of the optional sections renders exactly
79
- # as it did before those sections existed.
80
- #
81
- # @param template [String] the template holding the marker line
82
- # @param marker [String] the marker name, without the `# TMPL:` prefix
83
- # @param text [String] the flush-left block to splice in, ending in a newline or empty
84
- # @return [String] the template with the marker line replaced
47
+ # Replaces one `# TMPL:<marker>` line of a template with a block, indented
48
+ # to the marker's own level; an empty block removes the marker line.
85
49
  def splice(template, marker, text)
86
50
  template.sub(/^([ \t]*)# TMPL:#{Regexp.escape(marker)}\n/) do
87
51
  text.empty? ? "" : indent(text, Regexp.last_match(1))
@@ -90,21 +54,12 @@ module Hecks
90
54
 
91
55
  # Turns a name such as `mock-payments` into a CloudFormation-safe
92
56
  # logical id part: `MockPayments`.
93
- #
94
- # @param name [String] a name made of letters, digits, `_` and `-`
95
- # @return [String] the name in camel case, letters and digits only
96
57
  def camel(name)
97
58
  name.to_s.split(/[^a-zA-Z0-9]+/).reject(&:empty?).map { |part| part[0].upcase + part[1..] }.join
98
59
  end
99
60
 
100
- # Finds keys declared more than once at one indentation in a section.
101
- #
102
- # YAML loaders keep the last of a repeated key without complaint, so
103
- # two resources given the same logical id would silently drop one.
104
- #
105
- # @param section [String] the text of a `Resources:` or `Parameters:` section
106
- # @param indent [Integer] the indentation of the keys to check
107
- # @return [Array<String>] the keys that appear more than once
61
+ # Finds keys declared more than once at one indentation in a section, since
62
+ # YAML loaders silently keep the last and drop the others.
108
63
  def duplicate_keys(section, indent: 2)
109
64
  keys = section.scan(/^ {#{indent}}([A-Za-z0-9]+):(?:\s|$)/).flatten
110
65
  keys.tally.select { |_key, count| count > 1 }.keys