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.
- checksums.yaml +4 -4
- data/exe/hecks +4 -6
- 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 +17 -98
- 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 +5 -48
- 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 +31 -141
- 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 +14 -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 +25 -31
- 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 +16 -69
- 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 -194
- 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 -111
- 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 +53 -267
- data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +43 -305
- 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 +6 -21
- data/lib/hecks/bluebook/model_check.rb +100 -597
- 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 +4 -23
- data/lib/hecks/cli/document.rb +3 -21
- data/lib/hecks/cli/ir.rb +3 -5
- data/lib/hecks/cli/mcp.rb +2 -3
- data/lib/hecks/cli/mcp_door.rb +19 -114
- data/lib/hecks/cli/model_check.rb +18 -85
- data/lib/hecks/cli/project_cli.rb +7 -40
- data/lib/hecks/cli/project_diagrams.rb +0 -7
- data/lib/hecks/cli/run.rb +12 -58
- data/lib/hecks/cli/smoke_test.rb +2 -16
- data/lib/hecks/cli/stores.rb +1 -2
- data/lib/hecks/cli.rb +18 -24
- 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 +82 -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 +9 -90
- 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 +61 -64
- 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 +6 -25
- 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 +18 -124
- 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 +150 -678
- 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 +2 -15
- 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 +42 -134
- 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 +3 -6
- data/lib/hecks/release/runner/commands.rb +2 -4
- data/lib/hecks/release/runner/gem_publisher.rb +2 -3
- data/lib/hecks/release/runner/npm_publisher.rb +6 -20
- data/lib/hecks/release/runner/preflight.rb +4 -19
- data/lib/hecks/release/runner/tagger.rb +2 -9
- data/lib/hecks/release/runner.rb +3 -32
- 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 +124 -306
- 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 +64 -219
- 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 +117 -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 +99 -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 +141 -568
- 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.rb +26 -81
- 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 +3 -2
|
@@ -4,29 +4,16 @@ module Hecks
|
|
|
4
4
|
module Projections
|
|
5
5
|
module Deploy
|
|
6
6
|
module Preview
|
|
7
|
-
# The secrets and IAM roles of a preview stack.
|
|
8
|
-
#
|
|
9
|
-
# The task role reads the shared database secret and this preview's own
|
|
10
|
-
# secrets and nothing owned by the main stack. The execution role also reads
|
|
11
|
-
# the database secret, only so the one-shot task can receive the credentials
|
|
12
|
-
# as container secrets.
|
|
7
|
+
# The secrets and IAM roles of a preview stack, scoped away from the main stack.
|
|
13
8
|
module AccessYaml
|
|
14
9
|
extend YamlText
|
|
15
10
|
|
|
16
11
|
module_function
|
|
17
12
|
|
|
18
|
-
# Renders the secrets a preview generates: its session secret and the ones
|
|
19
|
-
# containers declare.
|
|
20
|
-
#
|
|
21
|
-
# @param settings [Settings] the resolved preview settings
|
|
22
|
-
# @return [Array<String>] one YAML resource block per secret
|
|
23
13
|
def secrets(settings)
|
|
24
14
|
[session_secret, *settings.containers.flat_map { |c| container_secrets(c) }]
|
|
25
15
|
end
|
|
26
16
|
|
|
27
|
-
# Renders the per-branch session secret the host reads at start.
|
|
28
|
-
#
|
|
29
|
-
# @return [String] the secret's resource block
|
|
30
17
|
def session_secret
|
|
31
18
|
<<~YAML.chomp
|
|
32
19
|
# No explicit Name: Secrets Manager keeps a deleted secret through its recovery window,
|
|
@@ -43,10 +30,6 @@ module Hecks
|
|
|
43
30
|
YAML
|
|
44
31
|
end
|
|
45
32
|
|
|
46
|
-
# Renders one generated secret per name a container declares.
|
|
47
|
-
#
|
|
48
|
-
# @param container [Containers::Entry] the container
|
|
49
|
-
# @return [Array<String>] one resource block per declared secret name
|
|
50
33
|
def container_secrets(container)
|
|
51
34
|
container.secrets.map do |name|
|
|
52
35
|
<<~YAML.chomp
|
|
@@ -63,10 +46,6 @@ module Hecks
|
|
|
63
46
|
end
|
|
64
47
|
end
|
|
65
48
|
|
|
66
|
-
# Renders the task execution role and the task role.
|
|
67
|
-
#
|
|
68
|
-
# @param settings [Settings] the resolved preview settings
|
|
69
|
-
# @return [Array<String>] the two role resource blocks
|
|
70
49
|
def roles(settings)
|
|
71
50
|
assume = <<~YAML.chomp
|
|
72
51
|
AssumeRolePolicyDocument:
|
|
@@ -79,11 +58,6 @@ module Hecks
|
|
|
79
58
|
[execution_role(assume), task_role(assume, settings)]
|
|
80
59
|
end
|
|
81
60
|
|
|
82
|
-
# Renders the execution role, which pulls images and hands the one-shot task
|
|
83
|
-
# its credentials.
|
|
84
|
-
#
|
|
85
|
-
# @param assume [String] the shared trust policy block
|
|
86
|
-
# @return [String] the role's resource block
|
|
87
61
|
def execution_role(assume)
|
|
88
62
|
<<~YAML.chomp
|
|
89
63
|
# The execution role reads the database secret only so the one-shot task can be given
|
|
@@ -105,12 +79,6 @@ module Hecks
|
|
|
105
79
|
YAML
|
|
106
80
|
end
|
|
107
81
|
|
|
108
|
-
# Renders the task role: read access to the shared database secret and this
|
|
109
|
-
# preview's own secrets.
|
|
110
|
-
#
|
|
111
|
-
# @param assume [String] the shared trust policy block
|
|
112
|
-
# @param settings [Settings] the resolved preview settings
|
|
113
|
-
# @return [String] the role's resource block
|
|
114
82
|
def task_role(assume, settings)
|
|
115
83
|
readable = ["SessionSecret", *settings.containers.flat_map { |c| c.secrets.map { |n| secret_id(c, n) } }]
|
|
116
84
|
<<~YAML.chomp
|
|
@@ -2,54 +2,15 @@ module Hecks
|
|
|
2
2
|
module Projections
|
|
3
3
|
module Deploy
|
|
4
4
|
module Preview
|
|
5
|
-
# The containers one preview task runs,
|
|
6
|
-
#
|
|
7
|
-
# A preview task runs the same containers as the stack it previews.
|
|
8
|
-
# This module is the single place that decides which containers those
|
|
9
|
-
# are, so the rest of `Preview` never asks where the list came from.
|
|
10
|
-
#
|
|
11
|
-
# ## One adapter to the shared setting
|
|
12
|
-
#
|
|
13
|
-
# The main Fargate stack is growing a multi-container setting.
|
|
14
|
-
# `shared_setting` is the only method that reads it; every other
|
|
15
|
-
# method here works on the normalized entries described below. When
|
|
16
|
-
# that setting lands with a different shape, translate it inside
|
|
17
|
-
# `shared_setting` and nothing else changes.
|
|
18
|
-
#
|
|
19
|
-
# ## Entry keys
|
|
20
|
-
#
|
|
21
|
-
# Each entry is a Hash with Symbol keys:
|
|
22
|
-
#
|
|
23
|
-
# - `name` (required): lowercase letters, digits and hyphens; also the
|
|
24
|
-
# container name and the suffix of its ECR repository.
|
|
25
|
-
# - `port` (required): the port the container listens on. Unique
|
|
26
|
-
# across the task, since all containers share one network namespace.
|
|
27
|
-
# - `health_check_path`: target group health check path, default `"/"`.
|
|
28
|
-
# - `paths`: load balancer path patterns forwarded to this container.
|
|
29
|
-
# - `default`: `true` sends every unmatched request here. When no
|
|
30
|
-
# entry says so, the `host` entry is the default, else the first.
|
|
31
|
-
# - `host`: `true` marks the Hecks host container. It gets the domain,
|
|
32
|
-
# session and database environment, and the signup path.
|
|
33
|
-
# - `database`: `true` gives a non-host container the database
|
|
34
|
-
# environment as well. The host always has it.
|
|
35
|
-
# - `environment`: extra environment, name to value. `{{preview_url}}`
|
|
36
|
-
# inside a value becomes the preview's public https URL.
|
|
37
|
-
# - `secrets`: environment variable names. Each becomes a per-branch
|
|
38
|
-
# generated secret whose ARN is that variable's value.
|
|
39
|
-
# - `image`: the local docker image `preview.sh` pushes for this
|
|
40
|
-
# container, default `"<name>:latest"`.
|
|
5
|
+
# The containers one preview task runs, normalized via `resolve`; `shared_setting`
|
|
6
|
+
# is the one hook into the main stack's own (still-growing) multi-container setting.
|
|
41
7
|
module Containers
|
|
42
8
|
# One normalized container of the preview task.
|
|
43
9
|
Entry = Data.define(:name, :port, :health_check_path, :paths, :default, :host, :database,
|
|
44
10
|
:environment, :secrets, :image) do
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
# @return [String] `name` in CamelCase, such as `"MySite"` for `"my-site"`
|
|
11
|
+
# CamelCases `name`, e.g. `"my-site"` becomes `"MySite"`.
|
|
48
12
|
def logical = name.split("-").map(&:capitalize).join
|
|
49
13
|
|
|
50
|
-
# Answers whether the container is reachable through the load balancer.
|
|
51
|
-
#
|
|
52
|
-
# @return [Boolean] true when it is the default or owns any path
|
|
53
14
|
def routed? = default || !paths.empty?
|
|
54
15
|
end
|
|
55
16
|
|
|
@@ -60,17 +21,8 @@ module Hecks
|
|
|
60
21
|
|
|
61
22
|
module_function
|
|
62
23
|
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# @param preview [Hash{Symbol => Object}] the preview settings; `:containers` wins
|
|
66
|
-
# @param deploy_settings [Hash{Symbol => Object}] the `deployed_to` settings, read
|
|
67
|
-
# by `shared_setting`
|
|
68
|
-
# @param main [Hash{Symbol => Object}] the main stack's own facts; `:name`, `:port`,
|
|
69
|
-
# `:image` describe the single container used when neither list is given
|
|
70
|
-
# @param signup_path [String, nil] path forwarded to the host container, or nil
|
|
71
|
-
# @return [Array<Entry>] at least one entry, exactly one of them the default
|
|
72
|
-
# @raise [ArgumentError] if an entry is malformed, a name or port repeats, or two
|
|
73
|
-
# entries claim to be the default or the host
|
|
24
|
+
# `preview[:containers]` wins over the main stack's own multi-container setting,
|
|
25
|
+
# which wins over a single entry built from the main stack's own container.
|
|
74
26
|
def resolve(preview:, deploy_settings:, main:, signup_path: nil)
|
|
75
27
|
raw = preview[:containers] || shared_setting(deploy_settings) || [single(main)]
|
|
76
28
|
entries = Array(raw).map { |item| normalize(item) }
|
|
@@ -78,31 +30,15 @@ module Hecks
|
|
|
78
30
|
with_default(with_signup(entries, signup_path))
|
|
79
31
|
end
|
|
80
32
|
|
|
81
|
-
# Reads the main stack's own container list, when it declares one.
|
|
82
|
-
#
|
|
83
|
-
# This is the one hook to the multi-container setting shared with the
|
|
84
|
-
# main template; it answers entries in the shape documented above.
|
|
85
|
-
#
|
|
86
|
-
# @param deploy_settings [Hash{Symbol => Object}] the `deployed_to` settings
|
|
87
|
-
# @return [Array<Hash>, nil] the list, or nil when the stack runs one container
|
|
88
33
|
def shared_setting(deploy_settings)
|
|
89
34
|
deploy_settings[:containers]
|
|
90
35
|
end
|
|
91
36
|
|
|
92
|
-
# Builds the single-container entry a one-container stack previews as.
|
|
93
|
-
#
|
|
94
|
-
# @param main [Hash{Symbol => Object}] the main stack's facts, see `resolve`
|
|
95
|
-
# @return [Hash{Symbol => Object}] the entry, always the host and the default
|
|
96
37
|
def single(main)
|
|
97
38
|
name = main.fetch(:name).to_s.downcase.gsub(/[^a-z0-9]+/, "-").sub(/\A[^a-z]+/, "")[0, 30].sub(/-+\z/, "")
|
|
98
39
|
{ name: name, port: main.fetch(:port), host: true, default: true, image: main[:image] }
|
|
99
40
|
end
|
|
100
41
|
|
|
101
|
-
# Turns one raw entry into an `Entry`, filling every default.
|
|
102
|
-
#
|
|
103
|
-
# @param item [Hash{Symbol => Object}] the raw entry, string keys accepted
|
|
104
|
-
# @return [Entry] the normalized entry
|
|
105
|
-
# @raise [ArgumentError] if the entry is not a Hash or lacks a valid `name` or `port`
|
|
106
42
|
def normalize(item)
|
|
107
43
|
raise ArgumentError, "preview container #{item.inspect} must be a Hash" unless item.is_a?(Hash)
|
|
108
44
|
|
|
@@ -117,13 +53,6 @@ module Hecks
|
|
|
117
53
|
)
|
|
118
54
|
end
|
|
119
55
|
|
|
120
|
-
# Answers a value as a String, refusing one that does not match a pattern.
|
|
121
|
-
#
|
|
122
|
-
# @param value [Object] the raw value
|
|
123
|
-
# @param pattern [Regexp] what the string must match
|
|
124
|
-
# @param label [String] what the value is, for the message
|
|
125
|
-
# @return [String] the value as a String
|
|
126
|
-
# @raise [ArgumentError] if the string does not match
|
|
127
56
|
def matching(value, pattern, label)
|
|
128
57
|
text = value.to_s
|
|
129
58
|
raise ArgumentError, "#{label} #{text.inspect} must match #{pattern.inspect}" unless text.match?(pattern)
|
|
@@ -131,19 +60,8 @@ module Hecks
|
|
|
131
60
|
text
|
|
132
61
|
end
|
|
133
62
|
|
|
134
|
-
# Answers one path pattern, refusing one the template could not quote safely.
|
|
135
|
-
#
|
|
136
|
-
# @param path [Object] the raw path
|
|
137
|
-
# @return [String] the path
|
|
138
|
-
# @raise [ArgumentError] if it does not start with `/` or holds an unexpected character
|
|
139
63
|
def path_of(path) = matching(path, PATH_PATTERN, "preview container path")
|
|
140
64
|
|
|
141
|
-
# Reads and range-checks one entry's port.
|
|
142
|
-
#
|
|
143
|
-
# @param item [Hash{Symbol => Object}] the raw entry
|
|
144
|
-
# @param name [String] the entry's name, for the message
|
|
145
|
-
# @return [Integer] the port
|
|
146
|
-
# @raise [ArgumentError] if the port is missing or outside 1..65535
|
|
147
65
|
def port_of(item, name)
|
|
148
66
|
port = Integer(item[:port], exception: false)
|
|
149
67
|
raise ArgumentError, "preview container #{name} needs a port between 1 and 65535" unless port&.between?(1, 65_535)
|
|
@@ -151,20 +69,10 @@ module Hecks
|
|
|
151
69
|
port
|
|
152
70
|
end
|
|
153
71
|
|
|
154
|
-
# Stringifies an entry's environment, keeping declaration order.
|
|
155
|
-
#
|
|
156
|
-
# @param environment [Hash{Symbol, String => Object}, nil] the raw environment
|
|
157
|
-
# @return [Hash{String => String}] name to value
|
|
158
72
|
def environment_of(environment)
|
|
159
73
|
(environment || {}).to_h { |name, value| [name.to_s, value.to_s] }
|
|
160
74
|
end
|
|
161
75
|
|
|
162
|
-
# Refuses a list that cannot be one task.
|
|
163
|
-
#
|
|
164
|
-
# @param entries [Array<Entry>] the normalized entries
|
|
165
|
-
# @return [void]
|
|
166
|
-
# @raise [ArgumentError] on an empty list, a repeated name or port, more than one
|
|
167
|
-
# default or host, or a secret name that is not an environment variable name
|
|
168
76
|
def check!(entries)
|
|
169
77
|
raise ArgumentError, "preview containers must not be empty" if entries.empty?
|
|
170
78
|
|
|
@@ -175,11 +83,6 @@ module Hecks
|
|
|
175
83
|
check_roles!(entries)
|
|
176
84
|
end
|
|
177
85
|
|
|
178
|
-
# Refuses a second default or host, and a secret that is not an environment variable name.
|
|
179
|
-
#
|
|
180
|
-
# @param entries [Array<Entry>] the normalized entries
|
|
181
|
-
# @return [void]
|
|
182
|
-
# @raise [ArgumentError] on a second default or host, or a malformed secret name
|
|
183
86
|
def check_roles!(entries)
|
|
184
87
|
raise ArgumentError, "at most one preview container may be the default" if entries.count(&:default) > 1
|
|
185
88
|
raise ArgumentError, "at most one preview container may be the host" if entries.count(&:host) > 1
|
|
@@ -188,11 +91,7 @@ module Hecks
|
|
|
188
91
|
raise ArgumentError, "preview secret name #{bad.inspect} must be an environment variable name" if bad
|
|
189
92
|
end
|
|
190
93
|
|
|
191
|
-
#
|
|
192
|
-
#
|
|
193
|
-
# @param entries [Array<Entry>] the normalized entries
|
|
194
|
-
# @param signup_path [String, nil] the path, or nil for none
|
|
195
|
-
# @return [Array<Entry>] the entries, the host's paths extended when it needs a rule
|
|
94
|
+
# Skipped when the host is already the default: it gets unmatched traffic anyway.
|
|
196
95
|
def with_signup(entries, signup_path)
|
|
197
96
|
return entries unless signup_path
|
|
198
97
|
|
|
@@ -201,10 +100,6 @@ module Hecks
|
|
|
201
100
|
end
|
|
202
101
|
end
|
|
203
102
|
|
|
204
|
-
# Marks the default container when no entry does.
|
|
205
|
-
#
|
|
206
|
-
# @param entries [Array<Entry>] the normalized entries
|
|
207
|
-
# @return [Array<Entry>] the entries with exactly one default
|
|
208
103
|
def with_default(entries)
|
|
209
104
|
return entries if entries.any?(&:default)
|
|
210
105
|
|
|
@@ -5,11 +5,8 @@ module Hecks
|
|
|
5
5
|
module Projections
|
|
6
6
|
module Deploy
|
|
7
7
|
module Preview
|
|
8
|
-
# The network edge of a preview stack: security groups,
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
# A container is reachable when it is the default or owns a path. Paths are
|
|
12
|
-
# split into rules of at most five, the most a load balancer condition holds.
|
|
8
|
+
# The network edge of a preview stack: security groups, load balancer and service.
|
|
9
|
+
# Paths are sliced into rules of at most five, the most a condition holds.
|
|
13
10
|
module RoutingYaml
|
|
14
11
|
CLOUDFRONT_PREFIX_LIST = "pl-3b927c52".freeze
|
|
15
12
|
PATHS_PER_RULE = 5
|
|
@@ -22,10 +19,6 @@ module Hecks
|
|
|
22
19
|
|
|
23
20
|
module_function
|
|
24
21
|
|
|
25
|
-
# Renders the load balancer's security group and one ingress rule per routed container.
|
|
26
|
-
#
|
|
27
|
-
# @param settings [Settings] the resolved preview settings
|
|
28
|
-
# @return [Array<String>] the resource blocks
|
|
29
22
|
def networking(settings)
|
|
30
23
|
ingress = settings.containers.select(&:routed?).map do |c|
|
|
31
24
|
<<~YAML.chomp
|
|
@@ -42,10 +35,6 @@ module Hecks
|
|
|
42
35
|
[alb_security_group(settings), "#{INGRESS_NOTE}\n#{ingress.join("\n\n")}"]
|
|
43
36
|
end
|
|
44
37
|
|
|
45
|
-
# Renders the load balancer's security group, open to CloudFront's prefix list only.
|
|
46
|
-
#
|
|
47
|
-
# @param settings [Settings] the resolved preview settings
|
|
48
|
-
# @return [String] the resource block
|
|
49
38
|
def alb_security_group(settings)
|
|
50
39
|
<<~YAML.chomp
|
|
51
40
|
AlbSecurityGroup:
|
|
@@ -62,19 +51,11 @@ module Hecks
|
|
|
62
51
|
YAML
|
|
63
52
|
end
|
|
64
53
|
|
|
65
|
-
# Renders the target groups, the load balancer, its listener and the path rules.
|
|
66
|
-
#
|
|
67
|
-
# @param settings [Settings] the resolved preview settings
|
|
68
|
-
# @return [Array<String>] the resource blocks
|
|
69
54
|
def load_balancing(settings)
|
|
70
55
|
routed = settings.containers.select(&:routed?)
|
|
71
56
|
[*routed.map { |c| target_group(c) }, alb(settings), listener(settings), *listener_rules(settings)]
|
|
72
57
|
end
|
|
73
58
|
|
|
74
|
-
# Renders the target group of one routed container.
|
|
75
|
-
#
|
|
76
|
-
# @param container [Containers::Entry] the container
|
|
77
|
-
# @return [String] the resource block
|
|
78
59
|
def target_group(container)
|
|
79
60
|
<<~YAML.chomp
|
|
80
61
|
#{container.logical}TargetGroup:
|
|
@@ -89,10 +70,6 @@ module Hecks
|
|
|
89
70
|
YAML
|
|
90
71
|
end
|
|
91
72
|
|
|
92
|
-
# Renders the internet-facing application load balancer.
|
|
93
|
-
#
|
|
94
|
-
# @param settings [Settings] the resolved preview settings
|
|
95
|
-
# @return [String] the resource block
|
|
96
73
|
def alb(settings)
|
|
97
74
|
<<~YAML.chomp
|
|
98
75
|
Alb:
|
|
@@ -106,10 +83,7 @@ module Hecks
|
|
|
106
83
|
YAML
|
|
107
84
|
end
|
|
108
85
|
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
# @param settings [Settings] the resolved preview settings
|
|
112
|
-
# @return [String] the resource block
|
|
86
|
+
# The default action goes to the default container.
|
|
113
87
|
def listener(settings)
|
|
114
88
|
<<~YAML.chomp
|
|
115
89
|
Listener:
|
|
@@ -124,11 +98,6 @@ module Hecks
|
|
|
124
98
|
YAML
|
|
125
99
|
end
|
|
126
100
|
|
|
127
|
-
# Lists the listener rules to render: a non-default container's paths, sliced to
|
|
128
|
-
# fit one condition.
|
|
129
|
-
#
|
|
130
|
-
# @param settings [Settings] the resolved preview settings
|
|
131
|
-
# @return [Array<Hash{Symbol => Object}>] entries with `:container`, `:paths` and `:id`
|
|
132
101
|
def rule_specs(settings)
|
|
133
102
|
settings.containers.reject(&:default).select(&:routed?).flat_map do |c|
|
|
134
103
|
c.paths.each_slice(PATHS_PER_RULE).with_index.map do |slice, n|
|
|
@@ -137,19 +106,11 @@ module Hecks
|
|
|
137
106
|
end
|
|
138
107
|
end
|
|
139
108
|
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
# @param settings [Settings] the resolved preview settings
|
|
143
|
-
# @return [Array<String>] the resource blocks
|
|
109
|
+
# Priorities count up in tens.
|
|
144
110
|
def listener_rules(settings)
|
|
145
111
|
rule_specs(settings).each_with_index.map { |spec, i| listener_rule(spec, (i + 1) * 10) }
|
|
146
112
|
end
|
|
147
113
|
|
|
148
|
-
# Renders one listener rule.
|
|
149
|
-
#
|
|
150
|
-
# @param spec [Hash{Symbol => Object}] one entry of `rule_specs`
|
|
151
|
-
# @param priority [Integer] the rule's listener priority
|
|
152
|
-
# @return [String] the resource block
|
|
153
114
|
def listener_rule(spec, priority)
|
|
154
115
|
<<~YAML.chomp
|
|
155
116
|
#{spec[:id]}:
|
|
@@ -166,17 +127,8 @@ module Hecks
|
|
|
166
127
|
YAML
|
|
167
128
|
end
|
|
168
129
|
|
|
169
|
-
# Names one listener rule's logical id.
|
|
170
|
-
#
|
|
171
|
-
# @param container [Containers::Entry] the container the rule forwards to
|
|
172
|
-
# @param slice [Integer] the zero-based index of the rule among that container's rules
|
|
173
|
-
# @return [String] the logical id
|
|
174
130
|
def rule_id(container, slice) = "ListenerRule#{container.logical}#{slice + 1}"
|
|
175
131
|
|
|
176
|
-
# Renders the service, which registers every routed container with its target group.
|
|
177
|
-
#
|
|
178
|
-
# @param settings [Settings] the resolved preview settings
|
|
179
|
-
# @return [String] the resource block
|
|
180
132
|
def service(settings)
|
|
181
133
|
rule_ids = rule_specs(settings).map { |spec| spec[:id] }
|
|
182
134
|
<<~YAML.chomp
|
|
@@ -200,10 +152,6 @@ module Hecks
|
|
|
200
152
|
YAML
|
|
201
153
|
end
|
|
202
154
|
|
|
203
|
-
# Renders the service's load balancer registrations.
|
|
204
|
-
#
|
|
205
|
-
# @param settings [Settings] the resolved preview settings
|
|
206
|
-
# @return [String] one list entry per routed container
|
|
207
155
|
def service_load_balancers(settings)
|
|
208
156
|
settings.containers.select(&:routed?).map do |c|
|
|
209
157
|
"- ContainerName: #{c.name}\n ContainerPort: #{c.port}\n TargetGroupArn: !Ref #{c.logical}TargetGroup"
|
|
@@ -4,22 +4,13 @@ module Hecks
|
|
|
4
4
|
module Projections
|
|
5
5
|
module Deploy
|
|
6
6
|
module Preview
|
|
7
|
-
# Renders `preview.sh`,
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# The script text lives in `preview.sh.erb` beside this file because it
|
|
11
|
-
# is a shell program, not Ruby: keeping it as a file lets `bash -n` and
|
|
12
|
-
# `shellcheck` read it as one. Every value baked into it has already
|
|
13
|
-
# passed `Settings`' patterns, so the template never quotes defensively.
|
|
7
|
+
# Renders `preview.sh` from `preview.sh.erb`, kept as a separate file so `bash -n`
|
|
8
|
+
# and `shellcheck` can read it; every baked-in value already passed `Settings`.
|
|
14
9
|
module Script
|
|
15
10
|
TEMPLATE = File.join(__dir__, "preview.sh.erb").freeze
|
|
16
11
|
|
|
17
12
|
module_function
|
|
18
13
|
|
|
19
|
-
# Renders the script.
|
|
20
|
-
#
|
|
21
|
-
# @param settings [Settings] the resolved preview settings
|
|
22
|
-
# @return [String] the bash script, ending in one newline
|
|
23
14
|
def render(settings)
|
|
24
15
|
ERB.new(File.read(TEMPLATE), trim_mode: "-").result_with_hash(
|
|
25
16
|
s: settings, image_hint: image_hint(settings)
|
|
@@ -27,9 +18,6 @@ module Hecks
|
|
|
27
18
|
end
|
|
28
19
|
|
|
29
20
|
# Names the local images `deploy` expects, for the script's header.
|
|
30
|
-
#
|
|
31
|
-
# @param settings [Settings] the resolved preview settings
|
|
32
|
-
# @return [String] the image references, comma separated
|
|
33
21
|
def image_hint(settings)
|
|
34
22
|
settings.containers.map(&:image).join(", ")
|
|
35
23
|
end
|
|
@@ -4,18 +4,8 @@ module Hecks
|
|
|
4
4
|
module Projections
|
|
5
5
|
module Deploy
|
|
6
6
|
module Preview
|
|
7
|
-
# The resolved, validated settings of one preview stack
|
|
8
|
-
#
|
|
9
|
-
# `Settings.build` is the only place a raw `preview` block meets the
|
|
10
|
-
# main stack's own facts, so every default lives here and the two
|
|
11
|
-
# renderers (`Template`, `Script`) read plain values.
|
|
12
|
-
#
|
|
13
|
-
# ## Why validation is this strict
|
|
14
|
-
#
|
|
15
|
-
# Every value ends up in a CloudFormation name, a Postgres database
|
|
16
|
-
# name that `CREATE DATABASE` cannot parameterize, or a shell script
|
|
17
|
-
# baked with the value. Patterns are checked once here, so neither
|
|
18
|
-
# renderer has to quote defensively.
|
|
7
|
+
# The resolved, validated settings of one preview stack, built once by `build`.
|
|
8
|
+
# Checked strictly: values feed CloudFormation names and a baked shell script.
|
|
19
9
|
class Settings
|
|
20
10
|
KEYS = %i[prefix alb_prefix owner_stack database_stack database_endpoint_output database_secret_output
|
|
21
11
|
db_prefix protected_databases protected_branches cpu memory log_retention_days session_cookie
|
|
@@ -34,18 +24,7 @@ module Hecks
|
|
|
34
24
|
|
|
35
25
|
attr_reader(*KEYS, :region, :stack_name, :infra_name, :main)
|
|
36
26
|
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
# @param raw [Hash{Symbol => Object}, true] the `preview` block; `true` accepts
|
|
40
|
-
# every default
|
|
41
|
-
# @param deploy_settings [Hash{Symbol => Object}] the `deployed_to` settings
|
|
42
|
-
# @param main [Hash{Symbol => Object}] the main stack's facts: `:infra_name`,
|
|
43
|
-
# `:stack_name`,
|
|
44
|
-
# `:stack_prefix`, `:region`, `:cpu`, `:memory`, `:db_name`, `:owner_stack` (nil unless
|
|
45
|
-
# the main stack borrows a database), `:name`, `:port`, `:image`, `:domain`, `:web`,
|
|
46
|
-
# `:wasm_path`, `:ir_path`, `:schema`
|
|
47
|
-
# @return [Settings] the validated settings
|
|
48
|
-
# @raise [ArgumentError] if a key is unknown or a value breaks its pattern
|
|
27
|
+
# `raw` may be `true`, accepting every default.
|
|
49
28
|
def self.build(raw, deploy_settings:, main:)
|
|
50
29
|
raw = raw.is_a?(Hash) ? raw.transform_keys(&:to_sym) : {}
|
|
51
30
|
unknown = raw.keys - KEYS
|
|
@@ -56,9 +35,6 @@ module Hecks
|
|
|
56
35
|
new(raw, deploy_settings, main)
|
|
57
36
|
end
|
|
58
37
|
|
|
59
|
-
# @param raw [Hash{Symbol => Object}] the symbolized `preview` settings
|
|
60
|
-
# @param deploy_settings [Hash{Symbol => Object}] the `deployed_to` settings
|
|
61
|
-
# @param main [Hash{Symbol => Object}] the main stack's facts, see `build`
|
|
62
38
|
def initialize(raw, deploy_settings, main)
|
|
63
39
|
@main = main
|
|
64
40
|
@region = main.fetch(:region)
|
|
@@ -72,14 +48,8 @@ module Hecks
|
|
|
72
48
|
signup_path: (signup_path if first_admin))
|
|
73
49
|
end
|
|
74
50
|
|
|
75
|
-
# Answers the host container, when the task has one.
|
|
76
|
-
#
|
|
77
|
-
# @return [Containers::Entry, nil] the entry flagged `host`
|
|
78
51
|
def host = containers.find(&:host)
|
|
79
52
|
|
|
80
|
-
# Answers the container that receives unmatched requests.
|
|
81
|
-
#
|
|
82
|
-
# @return [Containers::Entry] the default entry
|
|
83
53
|
def default_container = containers.find(&:default)
|
|
84
54
|
|
|
85
55
|
private
|
|
@@ -7,9 +7,6 @@ module Hecks
|
|
|
7
7
|
module Preview
|
|
8
8
|
# The task definitions of a preview stack: the containers it runs and the
|
|
9
9
|
# one-shot task that creates its database.
|
|
10
|
-
#
|
|
11
|
-
# The host container gets the domain, session and database environment; a
|
|
12
|
-
# container's own `environment` wins over a generated entry of the same name.
|
|
13
10
|
module TaskYaml
|
|
14
11
|
# The one-shot task's script. Idempotent, and refuses names the preview must never touch.
|
|
15
12
|
DB_INIT_SCRIPT = <<~SH.freeze
|
|
@@ -52,10 +49,7 @@ module Hecks
|
|
|
52
49
|
|
|
53
50
|
module_function
|
|
54
51
|
|
|
55
|
-
#
|
|
56
|
-
#
|
|
57
|
-
# @param settings [Settings] the resolved preview settings
|
|
58
|
-
# @return [String] the task definition's resource block
|
|
52
|
+
# Also renders the drop path, taken when `ACTION` is `drop`.
|
|
59
53
|
def db_init_task(settings)
|
|
60
54
|
<<~YAML.chomp
|
|
61
55
|
# Run by preview.sh (`aws ecs run-task`) after the images are pushed and before the
|
|
@@ -100,10 +94,6 @@ module Hecks
|
|
|
100
94
|
YAML
|
|
101
95
|
end
|
|
102
96
|
|
|
103
|
-
# Renders the preview's task definition, one container per entry of the container list.
|
|
104
|
-
#
|
|
105
|
-
# @param settings [Settings] the resolved preview settings
|
|
106
|
-
# @return [String] the task definition's resource block
|
|
107
97
|
def task_definition(settings)
|
|
108
98
|
<<~YAML.chomp
|
|
109
99
|
TaskDefinition:
|
|
@@ -124,11 +114,6 @@ module Hecks
|
|
|
124
114
|
YAML
|
|
125
115
|
end
|
|
126
116
|
|
|
127
|
-
# Renders one container of the task definition.
|
|
128
|
-
#
|
|
129
|
-
# @param settings [Settings] the resolved preview settings
|
|
130
|
-
# @param container [Containers::Entry] the container
|
|
131
|
-
# @return [String] the list entry
|
|
132
117
|
def container_definition(settings, container)
|
|
133
118
|
lines = [
|
|
134
119
|
"- Name: #{container.name}",
|
|
@@ -141,10 +126,6 @@ module Hecks
|
|
|
141
126
|
lines.join("\n")
|
|
142
127
|
end
|
|
143
128
|
|
|
144
|
-
# Renders the log driver settings of one container.
|
|
145
|
-
#
|
|
146
|
-
# @param container [Containers::Entry] the container
|
|
147
|
-
# @return [String] the settings, ending in a newline
|
|
148
129
|
def log_options(container)
|
|
149
130
|
<<~YAML
|
|
150
131
|
LogDriver: awslogs
|
|
@@ -155,23 +136,13 @@ module Hecks
|
|
|
155
136
|
YAML
|
|
156
137
|
end
|
|
157
138
|
|
|
158
|
-
# Renders one container's environment as a list.
|
|
159
|
-
#
|
|
160
|
-
# @param settings [Settings] the resolved preview settings
|
|
161
|
-
# @param container [Containers::Entry] the container
|
|
162
|
-
# @return [String] the list entries
|
|
163
139
|
def environment_yaml(settings, container)
|
|
164
140
|
environment_pairs(settings, container).map do |name, value|
|
|
165
141
|
"- Name: #{name}\n Value: #{value}"
|
|
166
142
|
end.join("\n")
|
|
167
143
|
end
|
|
168
144
|
|
|
169
|
-
#
|
|
170
|
-
# `environment` wins over a generated entry of the same name.
|
|
171
|
-
#
|
|
172
|
-
# @param settings [Settings] the resolved preview settings
|
|
173
|
-
# @param container [Containers::Entry] the container
|
|
174
|
-
# @return [Array<Array(String, String)>] the pairs, each value already rendered as YAML
|
|
145
|
+
# The container's own `environment` wins over a generated entry of the same name.
|
|
175
146
|
def environment_pairs(settings, container)
|
|
176
147
|
pairs = { "PORT" => scalar(container.port.to_s) }
|
|
177
148
|
pairs.merge!(host_environment(settings)) if container.host
|
|
@@ -181,10 +152,6 @@ module Hecks
|
|
|
181
152
|
pairs.to_a
|
|
182
153
|
end
|
|
183
154
|
|
|
184
|
-
# Answers the environment only the Hecks host container gets.
|
|
185
|
-
#
|
|
186
|
-
# @param settings [Settings] the resolved preview settings
|
|
187
|
-
# @return [Hash{String => String}] name to rendered value
|
|
188
155
|
def host_environment(settings)
|
|
189
156
|
main = settings.main
|
|
190
157
|
pairs = {
|
|
@@ -199,9 +166,6 @@ module Hecks
|
|
|
199
166
|
pairs
|
|
200
167
|
end
|
|
201
168
|
|
|
202
|
-
# Answers the environment that points a container at this preview's database.
|
|
203
|
-
#
|
|
204
|
-
# @return [Hash{String => String}] name to rendered value
|
|
205
169
|
def database_environment
|
|
206
170
|
{
|
|
207
171
|
"DB_HOST" => "!Ref OwningDatabaseEndpoint", "DB_NAME" => "!Ref DbName",
|