hecks 2.7.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.
- checksums.yaml +4 -4
- data/exe/hecks +11 -0
- data/lib/hecks/adapters/driven/claude_code.rb +4 -104
- data/lib/hecks/adapters/driven/d1.rb +44 -237
- data/lib/hecks/adapters/driven/folder.rb +17 -76
- data/lib/hecks/adapters/driven/google_authentication.rb +15 -49
- data/lib/hecks/adapters/driven/governance_authorization.rb +23 -70
- data/lib/hecks/adapters/driven/heki/journal.rb +8 -41
- data/lib/hecks/adapters/driven/heki/saga_store.rb +12 -54
- data/lib/hecks/adapters/driven/heki/snapshot.rb +4 -12
- data/lib/hecks/adapters/driven/heki.rb +13 -42
- data/lib/hecks/adapters/driven/identity_registry.rb +3 -14
- data/lib/hecks/adapters/driven/in_memory_ordering.rb +9 -26
- data/lib/hecks/adapters/driven/in_process_key_vault.rb +2 -14
- data/lib/hecks/adapters/driven/lambda/client.rb +10 -51
- data/lib/hecks/adapters/driven/lambda.rb +10 -84
- data/lib/hecks/adapters/driven/local_storage.rb +5 -40
- data/lib/hecks/adapters/driven/memory.rb +18 -99
- data/lib/hecks/adapters/driven/mock_stripe_adapter.rb +5 -21
- data/lib/hecks/adapters/driven/postgres/codec.rb +6 -28
- data/lib/hecks/adapters/driven/postgres/outbox.rb +3 -12
- data/lib/hecks/adapters/driven/postgres/reconnect.rb +4 -30
- data/lib/hecks/adapters/driven/postgres/schema_builder.rb +34 -108
- data/lib/hecks/adapters/driven/postgres.rb +145 -134
- data/lib/hecks/adapters/driven/postgres_era.adapter +4 -15
- data/lib/hecks/adapters/driven/prism.rb +7 -30
- data/lib/hecks/adapters/driven/sql_query_builder.rb +21 -121
- data/lib/hecks/adapters/driven/sqlite/codec.rb +8 -40
- data/lib/hecks/adapters/driven/sqlite/projection.rb +26 -82
- data/lib/hecks/adapters/driven/sqlite/schema_builder.rb +40 -84
- data/lib/hecks/adapters/driven/sqlite.rb +128 -65
- data/lib/hecks/adapters/driven/tenant_provisioner.rb +15 -37
- data/lib/hecks/adapters/driven.rb +5 -36
- data/lib/hecks/adapters/driving/github_webhook.rb +8 -76
- data/lib/hecks/behaviors/dsl.rb +7 -25
- data/lib/hecks/behaviors/expectations.rb +32 -142
- data/lib/hecks/behaviors/ir.rb +7 -20
- data/lib/hecks/behaviors/rspec.rb +6 -17
- data/lib/hecks/behaviors/runner.rb +10 -34
- data/lib/hecks/behaviors.rb +4 -8
- data/lib/hecks/bluebook/aggregate.rb +9 -75
- data/lib/hecks/bluebook/assembly/aggregate_assembly.rb +9 -38
- data/lib/hecks/bluebook/assembly/build.rb +4 -15
- data/lib/hecks/bluebook/assembly/contract.rb +15 -136
- data/lib/hecks/bluebook/assembly/contracts.rb +54 -174
- data/lib/hecks/bluebook/assembly/marks.rb +31 -223
- data/lib/hecks/bluebook/assembly/specializer.rb +6 -52
- data/lib/hecks/bluebook/assembly.rb +6 -45
- data/lib/hecks/bluebook/attribute.rb +12 -61
- data/lib/hecks/bluebook/behaviour/aggregate.rb +10 -39
- data/lib/hecks/bluebook/behaviour/attribute.rb +3 -14
- data/lib/hecks/bluebook/behaviour/chapter.rb +17 -42
- data/lib/hecks/bluebook/behaviour/command.rb +14 -66
- data/lib/hecks/bluebook/behaviour/domain_port.rb +4 -20
- data/lib/hecks/bluebook/behaviour/entity.rb +7 -27
- data/lib/hecks/bluebook/behaviour/hexagon.rb +23 -41
- data/lib/hecks/bluebook/behaviour/lifecycle.rb +15 -40
- data/lib/hecks/bluebook/behaviour/policy.rb +23 -52
- data/lib/hecks/bluebook/behaviour/process_manager.rb +30 -57
- data/lib/hecks/bluebook/behaviour/read_model.rb +38 -26
- data/lib/hecks/bluebook/behaviour/traits.rb +27 -64
- data/lib/hecks/bluebook/behaviour/value_object.rb +5 -24
- data/lib/hecks/bluebook/capabilities.rb +17 -49
- data/lib/hecks/bluebook/chapter.rb +10 -48
- data/lib/hecks/bluebook/command.rb +23 -81
- data/lib/hecks/bluebook/domain_port.rb +14 -63
- data/lib/hecks/bluebook/dsl/aggregate_builder/sealing.rb +50 -229
- data/lib/hecks/bluebook/dsl/aggregate_builder.rb +50 -377
- data/lib/hecks/bluebook/dsl/attribute_collector.rb +33 -204
- data/lib/hecks/bluebook/dsl/binding_proxy.rb +17 -65
- data/lib/hecks/bluebook/dsl/bluebook_builder/validation.rb +86 -708
- data/lib/hecks/bluebook/dsl/bluebook_builder.rb +56 -170
- data/lib/hecks/bluebook/dsl/bootstrap_table.rb +1 -0
- data/lib/hecks/bluebook/dsl/command_builder.rb +74 -546
- data/lib/hecks/bluebook/dsl/const_shim.rb +8 -41
- data/lib/hecks/bluebook/dsl/domain_port_builder.rb +12 -87
- data/lib/hecks/bluebook/dsl/entity_builder.rb +44 -330
- data/lib/hecks/bluebook/dsl/generic_dispatch.rb +20 -269
- data/lib/hecks/bluebook/dsl/hecksagon_builder.rb +26 -189
- data/lib/hecks/bluebook/dsl/identity_declaration.rb +13 -88
- data/lib/hecks/bluebook/dsl/lifecycle_builder.rb +6 -20
- data/lib/hecks/bluebook/dsl/policy_builder.rb +16 -88
- data/lib/hecks/bluebook/dsl/port_builder.rb +2 -6
- data/lib/hecks/bluebook/dsl/port_operation_builder.rb +22 -96
- data/lib/hecks/bluebook/dsl/process_manager_builder.rb +31 -184
- data/lib/hecks/bluebook/dsl/query_builder.rb +11 -42
- data/lib/hecks/bluebook/dsl/read_model_builder.rb +75 -201
- data/lib/hecks/bluebook/dsl/rule_reference.rb +22 -163
- data/lib/hecks/bluebook/dsl/translation_builder.rb +28 -114
- data/lib/hecks/bluebook/dsl/value_object_builder.rb +10 -124
- data/lib/hecks/bluebook/dsl/word_gate.rb +16 -162
- data/lib/hecks/bluebook/dsl/world_builder.rb +19 -106
- data/lib/hecks/bluebook/entity.rb +13 -71
- data/lib/hecks/bluebook/expression/ast_json.rb +24 -190
- data/lib/hecks/bluebook/expression/ast_reader.rb +12 -54
- data/lib/hecks/bluebook/expression/canonical_form.rb +11 -88
- data/lib/hecks/bluebook/expression/evaluator.rb +47 -295
- data/lib/hecks/bluebook/expression/resolver/block_predicates.rb +30 -147
- data/lib/hecks/bluebook/expression/resolver.rb +37 -660
- data/lib/hecks/bluebook/hexagon.rb +5 -28
- data/lib/hecks/bluebook/lifecycle.rb +5 -16
- data/lib/hecks/bluebook/meta_validator/adapter_judge.rb +1 -7
- data/lib/hecks/bluebook/meta_validator/judge.rb +111 -361
- data/lib/hecks/bluebook/meta_validator/plan.rb +33 -162
- data/lib/hecks/bluebook/meta_validator/port_judge.rb +2 -7
- data/lib/hecks/bluebook/meta_validator/readings.rb +56 -342
- data/lib/hecks/bluebook/meta_validator/reconstruction.rb +24 -176
- data/lib/hecks/bluebook/meta_validator/shapes.rb +54 -268
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +47 -308
- data/lib/hecks/bluebook/meta_validator/translation_judge.rb +7 -43
- data/lib/hecks/bluebook/meta_validator/world_judge.rb +6 -18
- data/lib/hecks/bluebook/meta_validator.rb +79 -349
- data/lib/hecks/bluebook/model_check/client_profile.rb +10 -91
- data/lib/hecks/bluebook/model_check.rb +102 -600
- data/lib/hecks/bluebook/pattern_subset.rb +11 -69
- data/lib/hecks/bluebook/process_manager.rb +13 -83
- data/lib/hecks/bluebook/project_loader.rb +3 -39
- data/lib/hecks/bluebook/project_register.rb +12 -60
- data/lib/hecks/bluebook/query.rb +9 -48
- data/lib/hecks/bluebook/read_model.rb +57 -81
- data/lib/hecks/bluebook/reference.rb +7 -41
- data/lib/hecks/bluebook/smoke_test.rb +8 -98
- data/lib/hecks/bluebook/synthesizer.rb +13 -62
- data/lib/hecks/bluebook/translation.rb +26 -62
- data/lib/hecks/bluebook/value_object.rb +11 -36
- data/lib/hecks/bluebook.rb +5 -22
- data/lib/hecks/cache_dir.rb +84 -0
- data/lib/hecks/cli/document.rb +86 -0
- data/lib/hecks/cli/ir.rb +45 -0
- data/lib/hecks/cli/mcp.rb +31 -0
- data/lib/hecks/cli/mcp_door.rb +366 -0
- data/lib/hecks/cli/model_check.rb +203 -0
- data/lib/hecks/cli/project_cli.rb +90 -0
- data/lib/hecks/cli/project_diagrams.rb +36 -0
- data/lib/hecks/cli/run.rb +173 -0
- data/lib/hecks/cli/smoke_test.rb +45 -0
- data/lib/hecks/cli/stores.rb +53 -0
- data/lib/hecks/cli.rb +160 -0
- data/lib/hecks/construct.rb +8 -34
- data/lib/hecks/deploy/bluebook/deploy.bluebook +33 -142
- data/lib/hecks/deploy/bluebook/deploy.hecksagon +2 -9
- data/lib/hecks/embryonaut_bluebook/lock.rb +3 -35
- data/lib/hecks/embryonaut_bluebook/shape.rb +1 -17
- data/lib/hecks/embryonaut_bluebook/vendor.rb +8 -53
- data/lib/hecks/embryonaut_bluebook/vendor_cli.rb +4 -19
- data/lib/hecks/embryonaut_bluebook.rb +4 -71
- data/lib/hecks/facade/cli_door.rb +24 -106
- data/lib/hecks/facade/cli_runner.rb +28 -172
- data/lib/hecks/facade/command_request.rb +13 -33
- data/lib/hecks/facade/handle.rb +34 -121
- data/lib/hecks/facade/json_door.rb +31 -146
- data/lib/hecks/facade/surface/aggregate_door.rb +39 -104
- data/lib/hecks/facade/surface/chapter.rb +10 -54
- data/lib/hecks/facade/surface.rb +8 -23
- data/lib/hecks/facade.rb +10 -25
- data/lib/hecks/forms/app.rb +15 -70
- data/lib/hecks/forms/command_form_renderer.rb +10 -29
- data/lib/hecks/forms/field_renderer.rb +17 -156
- data/lib/hecks/forms/field_shape.rb +30 -222
- data/lib/hecks/forms/html.rb +12 -47
- data/lib/hecks/forms/index_renderer.rb +1 -4
- data/lib/hecks/forms/page.rb +3 -9
- data/lib/hecks/forms/params.rb +14 -60
- data/lib/hecks/forms/port_argument.rb +2 -19
- data/lib/hecks/forms/query_form_renderer.rb +4 -79
- data/lib/hecks/forms/record_renderer.rb +8 -75
- data/lib/hecks/forms/record_table.rb +7 -50
- data/lib/hecks/forms/reference_options.rb +3 -30
- data/lib/hecks/forms/value_object_shape.rb +8 -35
- data/lib/hecks/forms.rb +5 -33
- data/lib/hecks/fqn.rb +5 -12
- data/lib/hecks/framework/bluebook/compliance.bluebook +16 -65
- data/lib/hecks/framework/bluebook/console_settings.bluebook +47 -134
- data/lib/hecks/framework/bluebook/framework.hecksagon +5 -14
- data/lib/hecks/framework/bluebook/governance.bluebook +13 -34
- data/lib/hecks/framework/bluebook/identity.bluebook +11 -26
- data/lib/hecks/framework/bluebook/privacy.bluebook +8 -33
- data/lib/hecks/framework.rb +11 -80
- data/lib/hecks/freezer.rb +5 -39
- data/lib/hecks/grammar/expression.bluebook +15 -40
- data/lib/hecks/grammar/translation.bluebook +3 -6
- data/lib/hecks/grammar.rb +16 -41
- data/lib/hecks/ir.rb +14 -83
- data/lib/hecks/language/adapter.bluebook +2 -7
- data/lib/hecks/language/bluebook/aggregate.bluebook +56 -221
- data/lib/hecks/language/bluebook/attaches/paging.bluebook +6 -15
- data/lib/hecks/language/bluebook/bluebook.bluebook +15 -83
- data/lib/hecks/language/bluebook/bluebook.hecksagon +3 -15
- data/lib/hecks/language/bluebook/command.bluebook +27 -144
- data/lib/hecks/language/bluebook/entity.bluebook +24 -97
- data/lib/hecks/language/bluebook/policy.bluebook +16 -67
- data/lib/hecks/language/bluebook/process_manager.bluebook +28 -151
- data/lib/hecks/language/bluebook/projection.bluebook +126 -60
- data/lib/hecks/language/bluebook/query.bluebook +12 -43
- data/lib/hecks/language/bluebook/shape.bluebook +23 -73
- data/lib/hecks/language/bluebook/syntax.bluebook +51 -262
- data/lib/hecks/language/bluebook/vocabulary.bluebook +98 -197
- data/lib/hecks/language/hecksagon/adapter_binding.bluebook +3 -10
- data/lib/hecks/language/hecksagon/domain_port.bluebook +4 -19
- data/lib/hecks/language/hecksagon/hecksagon.bluebook +6 -25
- data/lib/hecks/language/hecksagon/port_operation.bluebook +3 -14
- data/lib/hecks/language/oidc.json +35 -0
- data/lib/hecks/language/port.bluebook +4 -17
- data/lib/hecks/language/translation/translation.bluebook +3 -9
- data/lib/hecks/language/translation/translation_aggregate.bluebook +5 -24
- data/lib/hecks/language/world/wiring.bluebook +1 -3
- data/lib/hecks/language/world/world.bluebook +5 -7
- data/lib/hecks/literal.rb +8 -50
- data/lib/hecks/mcp_door_scope.rb +95 -0
- data/lib/hecks/mcp_stdio_guard.rb +4 -41
- data/lib/hecks/naming.rb +29 -137
- data/lib/hecks/ports/access_control.rb +7 -23
- data/lib/hecks/ports/agent/answers.rb +5 -23
- data/lib/hecks/ports/agent.rb +47 -172
- data/lib/hecks/ports/authentication.rb +12 -39
- data/lib/hecks/ports/authorization.rb +16 -43
- data/lib/hecks/ports/clock.rb +5 -45
- data/lib/hecks/ports/extraction.rb +7 -12
- data/lib/hecks/ports/identity_assignment.rb +8 -29
- data/lib/hecks/ports/identity_generation.rb +6 -29
- data/lib/hecks/ports/identity_resolution.rb +2 -10
- data/lib/hecks/ports/key_vault.rb +9 -45
- data/lib/hecks/ports/persistence/append_only.rb +62 -65
- data/lib/hecks/ports/persistence/binding_policy.rb +4 -14
- data/lib/hecks/ports/persistence/codec_boundary.rb +20 -80
- data/lib/hecks/ports/persistence/null_saga_store.rb +4 -20
- data/lib/hecks/ports/persistence/plugin.rb +13 -42
- data/lib/hecks/ports/persistence/plugins/era/era_check.rb +38 -141
- data/lib/hecks/ports/persistence/plugins/era/era_guard/shape_diff.rb +15 -115
- data/lib/hecks/ports/persistence/plugins/era/era_guard.rb +16 -84
- data/lib/hecks/ports/persistence/plugins/era/era_tamper.rb +7 -26
- data/lib/hecks/ports/persistence/plugins/era/expected_era.rb +3 -22
- data/lib/hecks/ports/persistence/plugins/era/lineage.rb +55 -181
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/events.rb +77 -0
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/era_store.rb +12 -122
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/field_cache.rb +28 -128
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/head_compiler.rb +73 -474
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/mint_transaction.rb +31 -124
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/provisioning.rb +45 -219
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/resumable_backfill.rb +13 -108
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/tail_merge.rb +18 -75
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage/transform_installer.rb +9 -49
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage.rb +6 -123
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/coverage_check.rb +23 -55
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/era_resolver.rb +14 -72
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/merge_coordinator.rb +7 -16
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager/minter.rb +14 -115
- data/lib/hecks/ports/persistence/plugins/era/postgres_era/lineage_manager.rb +13 -45
- data/lib/hecks/ports/persistence/plugins/era/postgres_era.rb +127 -554
- data/lib/hecks/ports/persistence/plugins/era/storage_shape.rb +13 -63
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/approval_digest.rb +2 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_one.rb +3 -14
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/layer_two.rb +13 -58
- data/lib/hecks/ports/persistence/plugins/era/translation/audit/unfed_report.rb +3 -17
- data/lib/hecks/ports/persistence/plugins/era/translation/audit.rb +9 -26
- data/lib/hecks/ports/persistence/plugins/era/translation/reattest.rb +9 -25
- data/lib/hecks/ports/persistence/plugins/era/translation/rule_compiler.rb +22 -122
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/differ.rb +34 -123
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/renderer.rb +5 -12
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold/writer.rb +3 -9
- data/lib/hecks/ports/persistence/plugins/era/translation/scaffold.rb +2 -14
- data/lib/hecks/ports/persistence/plugins/era.rb +4 -23
- data/lib/hecks/ports/persistence/postgres_dump/connection.rb +7 -23
- data/lib/hecks/ports/persistence/postgres_dump.rb +4 -35
- data/lib/hecks/ports/persistence/remote_runtime.rb +2 -24
- data/lib/hecks/ports/persistence/repository_factory.rb +8 -27
- data/lib/hecks/ports/persistence/state_codec.rb +23 -103
- data/lib/hecks/ports/persistence.rb +7 -14
- data/lib/hecks/ports/projection.rb +42 -84
- data/lib/hecks/ports/query/in_memory.rb +10 -58
- data/lib/hecks/ports/query/ordering.rb +11 -32
- data/lib/hecks/ports/query.rb +14 -37
- data/lib/hecks/ports.rb +2 -8
- data/lib/hecks/projections/bootstrap_table.rb +11 -43
- data/lib/hecks/projections/deploy/fargate/assembly.rb +2 -15
- data/lib/hecks/projections/deploy/fargate/cdn.rb +1 -48
- data/lib/hecks/projections/deploy/fargate/cdn_default.rb +2 -11
- data/lib/hecks/projections/deploy/fargate/check.rb +5 -14
- data/lib/hecks/projections/deploy/fargate/containers.rb +3 -78
- data/lib/hecks/projections/deploy/fargate/extras.rb +3 -44
- data/lib/hecks/projections/deploy/fargate/monitoring.rb +0 -44
- data/lib/hecks/projections/deploy/fargate/settings.rb +2 -54
- data/lib/hecks/projections/deploy/fargate/yaml.rb +13 -58
- data/lib/hecks/projections/deploy/fargate.rb +35 -202
- data/lib/hecks/projections/deploy/lambda.rb +151 -679
- data/lib/hecks/projections/deploy/preview/access_yaml.rb +1 -33
- data/lib/hecks/projections/deploy/preview/containers.rb +6 -111
- data/lib/hecks/projections/deploy/preview/routing_yaml.rb +4 -56
- data/lib/hecks/projections/deploy/preview/script.rb +2 -14
- data/lib/hecks/projections/deploy/preview/settings.rb +3 -33
- data/lib/hecks/projections/deploy/preview/task_yaml.rb +2 -38
- data/lib/hecks/projections/deploy/preview/template.rb +2 -58
- data/lib/hecks/projections/deploy/preview.rb +2 -67
- data/lib/hecks/projections/deploy/scripts/settings.rb +3 -25
- data/lib/hecks/projections/deploy/scripts.rb +4 -57
- data/lib/hecks/projections/deploy/shared.rb +47 -146
- data/lib/hecks/projections/deploy/smoke.rb +4 -61
- data/lib/hecks/projections/deploy/template_diff/comparer.rb +3 -25
- data/lib/hecks/projections/deploy/template_diff/loader.rb +2 -11
- data/lib/hecks/projections/deploy/template_diff.rb +5 -57
- data/lib/hecks/projections/diagrams.rb +20 -582
- data/lib/hecks/projections/glossary/html.rb +14 -130
- data/lib/hecks/projections/glossary/markdown.rb +8 -69
- data/lib/hecks/projections/glossary/mermaid.rb +9 -66
- data/lib/hecks/projections/glossary/sensitivity.rb +5 -34
- data/lib/hecks/projections/glossary/sentences.rb +14 -159
- data/lib/hecks/projections/glossary.rb +30 -222
- data/lib/hecks/projections/ir.rb +3 -10
- data/lib/hecks/projections/model/deviations.rb +15 -42
- data/lib/hecks/projections/model.rb +12 -51
- data/lib/hecks/projections/oidc.rb +12 -56
- data/lib/hecks/projections/parser_table.rb +9 -28
- data/lib/hecks/projections/reference.rb +9 -16
- data/lib/hecks/projections/rust_vocabulary.rb +12 -250
- data/lib/hecks/projections/shape.rb +3 -29
- data/lib/hecks/projections/statements.rb +7 -86
- data/lib/hecks/projections/vocabulary.rb +6 -22
- data/lib/hecks/projections.rb +2 -16
- data/lib/hecks/projector/cli_projector.rb +60 -375
- data/lib/hecks/projector/docs_projector.rb +10 -201
- data/lib/hecks/projector/exporter.rb +46 -138
- data/lib/hecks/projector/ir_projector.rb +2 -9
- data/lib/hecks/projector/narrate_projector.rb +15 -189
- data/lib/hecks/projector/target.rb +13 -76
- data/lib/hecks/projector.rb +30 -121
- data/lib/hecks/query_specification/common/comparators.rb +5 -26
- data/lib/hecks/query_specification/common/comparison.rb +35 -143
- data/lib/hecks/query_specification/common/dsl.rb +8 -24
- data/lib/hecks/query_specification/common/null_policy.rb +20 -70
- data/lib/hecks/query_specification/common/options.rb +2 -6
- data/lib/hecks/query_specification/common/where_clause.rb +2 -10
- data/lib/hecks/query_specification/field_path.rb +37 -77
- data/lib/hecks/query_specification/hop_path.rb +12 -76
- data/lib/hecks/release/gem_pin.rb +2 -26
- data/lib/hecks/release/runner/ci_publisher.rb +93 -0
- data/lib/hecks/release/runner/commands.rb +66 -0
- data/lib/hecks/release/runner/console.rb +52 -0
- data/lib/hecks/release/runner/gem_publisher.rb +43 -0
- data/lib/hecks/release/runner/git.rb +48 -0
- data/lib/hecks/release/runner/npm_publisher.rb +75 -0
- data/lib/hecks/release/runner/preflight.rb +104 -0
- data/lib/hecks/release/runner/published.rb +55 -0
- data/lib/hecks/release/runner/tagger.rb +80 -0
- data/lib/hecks/release/runner.rb +215 -0
- data/lib/hecks/rendering.rb +4 -26
- data/lib/hecks/router/namespace_installer.rb +12 -36
- data/lib/hecks/router.rb +4 -8
- data/lib/hecks/runtime/aggregate_lock.rb +8 -33
- data/lib/hecks/runtime/boot_gates.rb +3 -18
- data/lib/hecks/runtime/caller.rb +19 -59
- data/lib/hecks/runtime/capability_graph.rb +5 -21
- data/lib/hecks/runtime/command_interpreter/argument_gate.rb +16 -78
- data/lib/hecks/runtime/command_interpreter/mutation_applier.rb +23 -160
- data/lib/hecks/runtime/command_interpreter.rb +125 -307
- data/lib/hecks/runtime/command_rules/admissibility.rb +95 -366
- data/lib/hecks/runtime/command_rules/arithmetic.rb +66 -196
- data/lib/hecks/runtime/command_rules/authorization.rb +13 -45
- data/lib/hecks/runtime/command_rules/emission.rb +8 -21
- data/lib/hecks/runtime/command_rules/references.rb +23 -202
- data/lib/hecks/runtime/dependency_planning.rb +30 -102
- data/lib/hecks/runtime/dispatcher.rb +82 -241
- data/lib/hecks/runtime/entity_element.rb +40 -462
- data/lib/hecks/runtime/entity_interpreter.rb +65 -220
- data/lib/hecks/runtime/errors.rb +32 -115
- data/lib/hecks/runtime/event.rb +3 -25
- data/lib/hecks/runtime/identity.rb +18 -154
- data/lib/hecks/runtime/instance.rb +18 -150
- data/lib/hecks/runtime/interpreting.rb +11 -70
- data/lib/hecks/runtime/invocation.rb +28 -164
- data/lib/hecks/runtime/loader.rb +48 -186
- data/lib/hecks/runtime/outbox.rb +38 -261
- data/lib/hecks/runtime/policy_interpreter.rb +38 -200
- data/lib/hecks/runtime/port_operation_interpreter.rb +26 -87
- data/lib/hecks/runtime/query_interpreter.rb +45 -187
- data/lib/hecks/runtime/reaction_invocation.rb +36 -138
- data/lib/hecks/runtime/read_model_interpreter.rb +139 -208
- data/lib/hecks/runtime/rebuild_sweep.rb +8 -54
- data/lib/hecks/runtime/reference_hop.rb +8 -81
- data/lib/hecks/runtime/refusal_wording.rb +8 -89
- data/lib/hecks/runtime/registry/saga_persistence.rb +10 -102
- data/lib/hecks/runtime/registry/verification.rb +52 -225
- data/lib/hecks/runtime/registry/world_defaults.rb +4 -53
- data/lib/hecks/runtime/registry.rb +103 -244
- data/lib/hecks/runtime/remote_dispatcher.rb +37 -152
- data/lib/hecks/runtime/routing.rb +4 -15
- data/lib/hecks/runtime/saga_interpreter/correlation.rb +14 -61
- data/lib/hecks/runtime/saga_interpreter.rb +79 -263
- data/lib/hecks/runtime/saga_pending_dispatch.rb +2 -43
- data/lib/hecks/runtime/tenant_check.rb +6 -68
- data/lib/hecks/runtime/tenant_scope.rb +3 -28
- data/lib/hecks/runtime/value/admission.rb +16 -67
- data/lib/hecks/runtime/value/coercion.rb +155 -641
- data/lib/hecks/runtime/value/entity_list_coercion.rb +26 -219
- data/lib/hecks/runtime/value.rb +12 -84
- data/lib/hecks/runtime.rb +17 -65
- data/lib/hecks/storehouse.rb +146 -567
- data/lib/hecks/tenancy/bluebook/tenancy.bluebook +8 -32
- data/lib/hecks/tenancy/bluebook/tenancy.hecksagon +6 -23
- data/lib/hecks/vendoring/git_environment.rb +2 -8
- data/lib/hecks/vendoring/git_source.rb +4 -10
- data/lib/hecks/vendoring.rb +7 -46
- data/lib/hecks/version.rb +3 -14
- data/lib/hecks/vocabulary.rb +5 -0
- data/lib/hecks.rb +32 -82
- data/lib/rubocop/cop/hecks/fallback_hash_lookup.rb +8 -46
- data/lib/rubocop/cop/hecks/sequential_hash_rename_in_loop.rb +11 -80
- data/lib/rubocop/cop/hecks/thread_shared_ivar_mutation.rb +10 -99
- metadata +30 -59
- data/lib/hecks/bench/cli.rb +0 -74
- data/lib/hecks/bench/environment.rb +0 -100
- data/lib/hecks/bench/postgres_probe.rb +0 -41
- data/lib/hecks/bench/report.rb +0 -116
- data/lib/hecks/bench/ruby_runner.rb +0 -151
- data/lib/hecks/bench/run.rb +0 -55
- data/lib/hecks/bench/rust_runner.rb +0 -165
- data/lib/hecks/bench/stats.rb +0 -75
- data/lib/hecks/bench/suite.rb +0 -172
- data/lib/hecks/bench/workload.rb +0 -137
- data/lib/hecks/bench.rb +0 -28
- data/lib/hecks/codemod.rb +0 -443
- data/lib/hecks/corpus.rb +0 -479
- data/lib/hecks/doc/reference.rb +0 -585
- data/lib/hecks/fuzzing/bounded_exhaustive_expressions.rb +0 -684
- data/lib/hecks/fuzzing/combination_miner.rb +0 -178
- data/lib/hecks/fuzzing/concurrent_dispatch.rb +0 -469
- data/lib/hecks/fuzzing/coverage_campaign.rb +0 -161
- data/lib/hecks/fuzzing/differential.rb +0 -192
- data/lib/hecks/fuzzing/domain_generator.rb +0 -871
- data/lib/hecks/fuzzing/era_boundary.rb +0 -154
- data/lib/hecks/fuzzing/form_census.rb +0 -285
- data/lib/hecks/fuzzing/generated_domain_check.rb +0 -171
- data/lib/hecks/fuzzing/invalid_value_generator.rb +0 -125
- data/lib/hecks/fuzzing/isolated_boot.rb +0 -658
- data/lib/hecks/fuzzing/nondeterministic.rb +0 -79
- data/lib/hecks/fuzzing/persistence_parity.rb +0 -253
- data/lib/hecks/fuzzing/properties/corrections.rb +0 -125
- data/lib/hecks/fuzzing/properties/dispatch_and_mutations.rb +0 -688
- data/lib/hecks/fuzzing/properties/guards.rb +0 -398
- data/lib/hecks/fuzzing/properties/invariants_and_aggregation.rb +0 -399
- data/lib/hecks/fuzzing/properties/lifecycle_and_replay.rb +0 -137
- data/lib/hecks/fuzzing/properties/outbox.rb +0 -180
- data/lib/hecks/fuzzing/properties/querying.rb +0 -260
- data/lib/hecks/fuzzing/properties.rb +0 -267
- data/lib/hecks/fuzzing/qa_settings.rb +0 -164
- data/lib/hecks/fuzzing/replay.rb +0 -930
- data/lib/hecks/fuzzing/rotation_priority.rb +0 -114
- data/lib/hecks/fuzzing/rust_gap_manifest.rb +0 -139
- data/lib/hecks/fuzzing/self_consistency.rb +0 -825
- data/lib/hecks/fuzzing/sequence_generator/adversary.rb +0 -532
- data/lib/hecks/fuzzing/sequence_generator/catalog.rb +0 -171
- data/lib/hecks/fuzzing/sequence_generator/outcome_tracker.rb +0 -127
- data/lib/hecks/fuzzing/sequence_generator/picker.rb +0 -116
- data/lib/hecks/fuzzing/sequence_generator/query_binding.rb +0 -138
- data/lib/hecks/fuzzing/sequence_generator/step_builder.rb +0 -344
- data/lib/hecks/fuzzing/sequence_generator.rb +0 -311
- data/lib/hecks/fuzzing/shrinker.rb +0 -309
- data/lib/hecks/fuzzing/structural_skips.rb +0 -53
- data/lib/hecks/fuzzing/sweep_depth.rb +0 -61
- data/lib/hecks/fuzzing/target_capabilities.rb +0 -255
- data/lib/hecks/fuzzing/value_generator.rb +0 -340
- data/lib/hecks/fuzzing.rb +0 -23
- data/lib/hecks/grammar/evolve.rb +0 -524
- data/lib/hecks/query_ir.rb +0 -482
|
@@ -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
|
|
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
|
-
#
|
|
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
|
|
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
|
|
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
|
-
#
|
|
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
|