igniter-contracts 0.5.2
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 +7 -0
- data/README.md +239 -0
- data/lib/igniter/contracts/api.rb +92 -0
- data/lib/igniter/contracts/assembly/baseline_pack.rb +141 -0
- data/lib/igniter/contracts/assembly/const_pack.rb +29 -0
- data/lib/igniter/contracts/assembly/dsl_keyword.rb +21 -0
- data/lib/igniter/contracts/assembly/hook_result_policies.rb +47 -0
- data/lib/igniter/contracts/assembly/hook_spec.rb +73 -0
- data/lib/igniter/contracts/assembly/hook_specs.rb +74 -0
- data/lib/igniter/contracts/assembly/kernel.rb +220 -0
- data/lib/igniter/contracts/assembly/node_type.rb +26 -0
- data/lib/igniter/contracts/assembly/ordered_registry.rb +55 -0
- data/lib/igniter/contracts/assembly/pack.rb +13 -0
- data/lib/igniter/contracts/assembly/pack_manifest.rb +131 -0
- data/lib/igniter/contracts/assembly/path_access.rb +76 -0
- data/lib/igniter/contracts/assembly/profile.rb +133 -0
- data/lib/igniter/contracts/assembly/project_pack.rb +42 -0
- data/lib/igniter/contracts/assembly/registry.rb +57 -0
- data/lib/igniter/contracts/assembly/step_result_pack.rb +42 -0
- data/lib/igniter/contracts/assembly.rb +18 -0
- data/lib/igniter/contracts/contract.rb +135 -0
- data/lib/igniter/contracts/contractable.rb +288 -0
- data/lib/igniter/contracts/environment.rb +51 -0
- data/lib/igniter/contracts/errors.rb +47 -0
- data/lib/igniter/contracts/execution/baseline_normalizers.rb +23 -0
- data/lib/igniter/contracts/execution/baseline_runtime.rb +55 -0
- data/lib/igniter/contracts/execution/baseline_validators.rb +113 -0
- data/lib/igniter/contracts/execution/builder.rb +43 -0
- data/lib/igniter/contracts/execution/compilation_report.rb +46 -0
- data/lib/igniter/contracts/execution/compiled_graph.rb +21 -0
- data/lib/igniter/contracts/execution/compiler.rb +66 -0
- data/lib/igniter/contracts/execution/const_runtime.rb +15 -0
- data/lib/igniter/contracts/execution/diagnostics.rb +24 -0
- data/lib/igniter/contracts/execution/diagnostics_report.rb +40 -0
- data/lib/igniter/contracts/execution/diagnostics_section.rb +37 -0
- data/lib/igniter/contracts/execution/effect_invocation.rb +26 -0
- data/lib/igniter/contracts/execution/execution_request.rb +28 -0
- data/lib/igniter/contracts/execution/execution_result.rb +32 -0
- data/lib/igniter/contracts/execution/inline_executor.rb +19 -0
- data/lib/igniter/contracts/execution/mutable_named_values.rb +52 -0
- data/lib/igniter/contracts/execution/named_values.rb +48 -0
- data/lib/igniter/contracts/execution/operation.rb +42 -0
- data/lib/igniter/contracts/execution/runtime.rb +43 -0
- data/lib/igniter/contracts/execution/step_result.rb +51 -0
- data/lib/igniter/contracts/execution/step_result_diagnostics.rb +35 -0
- data/lib/igniter/contracts/execution/step_result_runtime.rb +51 -0
- data/lib/igniter/contracts/execution/step_result_validators.rb +44 -0
- data/lib/igniter/contracts/execution/structured_dump.rb +49 -0
- data/lib/igniter/contracts/execution/validation_finding.rb +28 -0
- data/lib/igniter/contracts/execution/validation_report.rb +46 -0
- data/lib/igniter/contracts/execution.rb +28 -0
- data/lib/igniter/contracts.rb +54 -0
- data/lib/igniter/lang/backend.rb +19 -0
- data/lib/igniter/lang/backends/ruby.rb +42 -0
- data/lib/igniter/lang/diagnostic_payload.rb +174 -0
- data/lib/igniter/lang/metadata_carrier_manifest.rb +112 -0
- data/lib/igniter/lang/metadata_manifest.rb +128 -0
- data/lib/igniter/lang/receipt_payload.rb +152 -0
- data/lib/igniter/lang/schema_compatibility_diagnostic.rb +300 -0
- data/lib/igniter/lang/types.rb +84 -0
- data/lib/igniter/lang/verification_report.rb +226 -0
- data/lib/igniter/lang.rb +27 -0
- data/lib/igniter-contracts.rb +3 -0
- metadata +103 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Igniter
|
|
4
|
+
module Lang
|
|
5
|
+
class ReceiptPayload
|
|
6
|
+
SEMANTICS = {
|
|
7
|
+
report_only: true,
|
|
8
|
+
runtime_enforced: false,
|
|
9
|
+
execution_authorized: false,
|
|
10
|
+
operation_execution_authorized: false,
|
|
11
|
+
external_bridge_authorized: false,
|
|
12
|
+
provider_call_authorized: false,
|
|
13
|
+
real_data_export_authorized: false,
|
|
14
|
+
ledger_core: false
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
DEFAULT_REDACTION_POLICY = {
|
|
18
|
+
raw_ref_export: false,
|
|
19
|
+
hash_source_refs: true,
|
|
20
|
+
redacted_ref_kinds: []
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
23
|
+
RAW_REF_KEYS = %i[raw_ref raw_refs raw_source_ref raw_source_refs].freeze
|
|
24
|
+
RAW_REF_PREFIX = "raw:"
|
|
25
|
+
|
|
26
|
+
attr_reader :receipt_id,
|
|
27
|
+
:profile,
|
|
28
|
+
:payload,
|
|
29
|
+
:evidence_links,
|
|
30
|
+
:redaction_policy,
|
|
31
|
+
:metadata
|
|
32
|
+
|
|
33
|
+
def initialize(
|
|
34
|
+
receipt_id:,
|
|
35
|
+
profile:,
|
|
36
|
+
payload: {},
|
|
37
|
+
evidence_links: {},
|
|
38
|
+
redaction_policy: {},
|
|
39
|
+
metadata: {}
|
|
40
|
+
)
|
|
41
|
+
@receipt_id = require_value(:receipt_id, receipt_id)
|
|
42
|
+
@profile = require_value(:profile, profile)
|
|
43
|
+
@payload = deep_freeze(normalize_hash(payload, :payload))
|
|
44
|
+
@evidence_links = deep_freeze(normalize_hash(evidence_links, :evidence_links))
|
|
45
|
+
@redaction_policy = deep_freeze(normalize_redaction_policy(redaction_policy))
|
|
46
|
+
@metadata = deep_freeze(normalize_hash(metadata, :metadata))
|
|
47
|
+
reject_raw_refs!
|
|
48
|
+
freeze
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def report_only?
|
|
52
|
+
true
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def runtime_enforced?
|
|
56
|
+
false
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def to_h
|
|
60
|
+
{
|
|
61
|
+
receipt_id: receipt_id,
|
|
62
|
+
profile: profile,
|
|
63
|
+
payload: payload,
|
|
64
|
+
evidence_links: evidence_links,
|
|
65
|
+
redaction_policy: redaction_policy,
|
|
66
|
+
semantics: SEMANTICS,
|
|
67
|
+
metadata: metadata
|
|
68
|
+
}
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def require_value(name, value)
|
|
74
|
+
raise ArgumentError, "#{name} is required" if value.nil?
|
|
75
|
+
|
|
76
|
+
value
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def normalize_redaction_policy(value)
|
|
80
|
+
policy = DEFAULT_REDACTION_POLICY.merge(normalize_hash(value, :redaction_policy))
|
|
81
|
+
raise ArgumentError, "redaction_policy.raw_ref_export must be true or false" unless [true, false].include?(policy[:raw_ref_export])
|
|
82
|
+
|
|
83
|
+
raise ArgumentError, "redaction_policy.raw_ref_export true is not supported in v0" if policy[:raw_ref_export]
|
|
84
|
+
|
|
85
|
+
policy[:redacted_ref_kinds] = Array(policy[:redacted_ref_kinds]).map(&:to_s)
|
|
86
|
+
policy
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def reject_raw_refs!
|
|
90
|
+
raw_path = find_raw_ref(
|
|
91
|
+
payload: payload,
|
|
92
|
+
evidence_links: evidence_links,
|
|
93
|
+
metadata: metadata
|
|
94
|
+
)
|
|
95
|
+
raise ArgumentError, "raw refs are not allowed in receipt payloads at #{raw_path}" if raw_path
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def find_raw_ref(value, path = [])
|
|
99
|
+
case value
|
|
100
|
+
when Hash
|
|
101
|
+
value.each do |key, entry|
|
|
102
|
+
normalized_key = key.respond_to?(:to_sym) ? key.to_sym : key
|
|
103
|
+
return (path + [normalized_key]).join(".") if RAW_REF_KEYS.include?(normalized_key)
|
|
104
|
+
|
|
105
|
+
nested = find_raw_ref(entry, path + [normalized_key])
|
|
106
|
+
return nested if nested
|
|
107
|
+
end
|
|
108
|
+
when Array
|
|
109
|
+
value.each_with_index do |entry, index|
|
|
110
|
+
nested = find_raw_ref(entry, path + [index])
|
|
111
|
+
return nested if nested
|
|
112
|
+
end
|
|
113
|
+
when String
|
|
114
|
+
return path.join(".") if value.start_with?(RAW_REF_PREFIX)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
nil
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def normalize_hash(value, name)
|
|
121
|
+
raise ArgumentError, "#{name} must be a hash" unless value.respond_to?(:to_h)
|
|
122
|
+
|
|
123
|
+
value.to_h.each_with_object({}) do |(key, entry), hash|
|
|
124
|
+
normalized_key = key.respond_to?(:to_sym) ? key.to_sym : key
|
|
125
|
+
hash[normalized_key] = normalize_value(entry)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def normalize_value(value)
|
|
130
|
+
case value
|
|
131
|
+
when Hash
|
|
132
|
+
normalize_hash(value, :value)
|
|
133
|
+
when Array
|
|
134
|
+
value.map { |entry| normalize_value(entry) }
|
|
135
|
+
else
|
|
136
|
+
value
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def deep_freeze(value)
|
|
141
|
+
case value
|
|
142
|
+
when Array
|
|
143
|
+
value.map { |entry| deep_freeze(entry) }.freeze
|
|
144
|
+
when Hash
|
|
145
|
+
value.transform_values { |entry| deep_freeze(entry) }.freeze
|
|
146
|
+
else
|
|
147
|
+
value.freeze
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Igniter
|
|
4
|
+
module Lang
|
|
5
|
+
class SchemaCompatibilityDiagnostic
|
|
6
|
+
SEMANTICS = {
|
|
7
|
+
report_only: true,
|
|
8
|
+
runtime_enforced: false,
|
|
9
|
+
migration_execution_authorized: false,
|
|
10
|
+
ledger_core: false
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
REQUIRED_EVIDENCE_LINKS = %i[
|
|
14
|
+
compatibility_report_ref
|
|
15
|
+
semantic_image_ref
|
|
16
|
+
loaded_schema_descriptor_ref
|
|
17
|
+
].freeze
|
|
18
|
+
|
|
19
|
+
REQUIRED_MIGRATION_PROFILE_KEYS = %i[
|
|
20
|
+
migration_receipt_ref
|
|
21
|
+
replaces_image_id
|
|
22
|
+
replacement_semantic_image_ref
|
|
23
|
+
replacement_schema_fingerprint
|
|
24
|
+
loaded_schema_fingerprint
|
|
25
|
+
migration_chain
|
|
26
|
+
replacement_image_lifecycle
|
|
27
|
+
migration_receipt_lifecycle
|
|
28
|
+
packet_links
|
|
29
|
+
post_migration_report_ref
|
|
30
|
+
post_migration_schema_decision
|
|
31
|
+
post_migration_compatibility_decision
|
|
32
|
+
].freeze
|
|
33
|
+
|
|
34
|
+
REQUIRED_PACKET_LINKS = %i[
|
|
35
|
+
replaces
|
|
36
|
+
caused_by
|
|
37
|
+
produced_by
|
|
38
|
+
produced_in
|
|
39
|
+
has_supersedes
|
|
40
|
+
].freeze
|
|
41
|
+
|
|
42
|
+
DECISIONS = %i[trusted provisional migrating blocked].freeze
|
|
43
|
+
|
|
44
|
+
attr_reader :diagnostic_id,
|
|
45
|
+
:contract_ref,
|
|
46
|
+
:old_schema_version,
|
|
47
|
+
:new_schema_version,
|
|
48
|
+
:old_schema_fingerprint,
|
|
49
|
+
:new_schema_fingerprint,
|
|
50
|
+
:schema_check_outcome,
|
|
51
|
+
:migration_available,
|
|
52
|
+
:compatibility_decision,
|
|
53
|
+
:evidence_links,
|
|
54
|
+
:migration_ref,
|
|
55
|
+
:migration_profile,
|
|
56
|
+
:profile_cases,
|
|
57
|
+
:metadata
|
|
58
|
+
|
|
59
|
+
def initialize(
|
|
60
|
+
diagnostic_id:,
|
|
61
|
+
contract_ref:,
|
|
62
|
+
old_schema_version:,
|
|
63
|
+
new_schema_version:,
|
|
64
|
+
old_schema_fingerprint:,
|
|
65
|
+
new_schema_fingerprint:,
|
|
66
|
+
schema_check_outcome:,
|
|
67
|
+
migration_available:,
|
|
68
|
+
compatibility_decision:,
|
|
69
|
+
evidence_links:,
|
|
70
|
+
migration_ref: nil,
|
|
71
|
+
migration_profile: nil,
|
|
72
|
+
metadata: {}
|
|
73
|
+
)
|
|
74
|
+
@diagnostic_id = require_value(:diagnostic_id, diagnostic_id)
|
|
75
|
+
@contract_ref = require_value(:contract_ref, contract_ref)
|
|
76
|
+
@old_schema_version = require_value(:old_schema_version, old_schema_version)
|
|
77
|
+
@new_schema_version = require_value(:new_schema_version, new_schema_version)
|
|
78
|
+
@old_schema_fingerprint = require_value(:old_schema_fingerprint, old_schema_fingerprint)
|
|
79
|
+
@new_schema_fingerprint = require_value(:new_schema_fingerprint, new_schema_fingerprint)
|
|
80
|
+
@schema_check_outcome = normalize_decision(:schema_check_outcome, schema_check_outcome)
|
|
81
|
+
@migration_available = normalize_boolean(:migration_available, migration_available)
|
|
82
|
+
@compatibility_decision = normalize_decision(:compatibility_decision, compatibility_decision)
|
|
83
|
+
@evidence_links = normalize_evidence_links(evidence_links)
|
|
84
|
+
@migration_ref = migration_ref
|
|
85
|
+
@migration_profile = normalize_migration_profile(migration_profile)
|
|
86
|
+
validate_migration_evidence!
|
|
87
|
+
@profile_cases = build_profile_cases.freeze
|
|
88
|
+
@metadata = deep_freeze(normalize_hash(metadata, :metadata))
|
|
89
|
+
freeze
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def report_only?
|
|
93
|
+
true
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def runtime_enforced?
|
|
97
|
+
false
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def status
|
|
101
|
+
return :blocked if blocked?
|
|
102
|
+
return :migrating if schema_check_outcome == :migrating || compatibility_decision == :migrating
|
|
103
|
+
return :provisional if schema_check_outcome == :provisional || compatibility_decision == :provisional
|
|
104
|
+
|
|
105
|
+
:trusted
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def blocked?
|
|
109
|
+
schema_check_outcome == :blocked ||
|
|
110
|
+
compatibility_decision == :blocked ||
|
|
111
|
+
profile_cases.any? { |entry| entry.fetch(:status) == :blocked }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def to_h
|
|
115
|
+
payload = {
|
|
116
|
+
diagnostic_id: diagnostic_id,
|
|
117
|
+
contract_ref: contract_ref,
|
|
118
|
+
old_schema_version: old_schema_version,
|
|
119
|
+
new_schema_version: new_schema_version,
|
|
120
|
+
old_schema_fingerprint: old_schema_fingerprint,
|
|
121
|
+
new_schema_fingerprint: new_schema_fingerprint,
|
|
122
|
+
schema_check_outcome: schema_check_outcome,
|
|
123
|
+
migration_available: migration_available,
|
|
124
|
+
compatibility_decision: compatibility_decision,
|
|
125
|
+
status: status,
|
|
126
|
+
evidence_links: evidence_links,
|
|
127
|
+
profile_cases: profile_cases,
|
|
128
|
+
semantics: SEMANTICS,
|
|
129
|
+
metadata: metadata
|
|
130
|
+
}
|
|
131
|
+
payload[:migration_ref] = migration_ref if migration_ref
|
|
132
|
+
payload[:migration_profile] = migration_profile if migration_profile
|
|
133
|
+
payload
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
private
|
|
137
|
+
|
|
138
|
+
def require_value(name, value)
|
|
139
|
+
raise ArgumentError, "#{name} is required" if value.nil?
|
|
140
|
+
|
|
141
|
+
value
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def normalize_decision(name, value)
|
|
145
|
+
decision = require_value(name, value).to_sym
|
|
146
|
+
return decision if DECISIONS.include?(decision)
|
|
147
|
+
|
|
148
|
+
raise ArgumentError, "#{name} must be one of #{DECISIONS.join(", ")}"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def normalize_boolean(name, value)
|
|
152
|
+
return value if [true, false].include?(value)
|
|
153
|
+
|
|
154
|
+
raise ArgumentError, "#{name} must be true or false"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def normalize_evidence_links(value)
|
|
158
|
+
links = normalize_hash(value, :evidence_links)
|
|
159
|
+
REQUIRED_EVIDENCE_LINKS.each do |key|
|
|
160
|
+
raise ArgumentError, "evidence_links.#{key} is required" if links[key].nil?
|
|
161
|
+
end
|
|
162
|
+
deep_freeze(links)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def validate_migration_evidence!
|
|
166
|
+
return unless migration_available
|
|
167
|
+
return if migration_ref || evidence_links[:migration_descriptor_ref]
|
|
168
|
+
|
|
169
|
+
raise ArgumentError, "migration_available requires migration_ref or evidence_links.migration_descriptor_ref"
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def normalize_migration_profile(value)
|
|
173
|
+
return nil if value.nil?
|
|
174
|
+
|
|
175
|
+
profile = normalize_hash(value, :migration_profile)
|
|
176
|
+
REQUIRED_MIGRATION_PROFILE_KEYS.each do |key|
|
|
177
|
+
raise ArgumentError, "migration_profile.#{key} is required" if profile[key].nil?
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
profile[:post_migration_schema_decision] =
|
|
181
|
+
normalize_decision(:post_migration_schema_decision, profile[:post_migration_schema_decision])
|
|
182
|
+
profile[:post_migration_compatibility_decision] =
|
|
183
|
+
normalize_decision(:post_migration_compatibility_decision, profile[:post_migration_compatibility_decision])
|
|
184
|
+
profile[:packet_links] = normalize_packet_links(profile[:packet_links])
|
|
185
|
+
deep_freeze(profile)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def normalize_packet_links(value)
|
|
189
|
+
packet_links = normalize_hash(value, :packet_links)
|
|
190
|
+
REQUIRED_PACKET_LINKS.each do |key|
|
|
191
|
+
raise ArgumentError, "migration_profile.packet_links.#{key} is required" if packet_links[key].nil?
|
|
192
|
+
end
|
|
193
|
+
packet_links
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def build_profile_cases
|
|
197
|
+
return [] unless migration_profile
|
|
198
|
+
|
|
199
|
+
[
|
|
200
|
+
profile_case("P-1", "migration_receipt_ref", receipt_ref_present?),
|
|
201
|
+
profile_case("P-2", "replaces_image_id", value_present?(migration_profile[:replaces_image_id])),
|
|
202
|
+
profile_case("P-3", "packet_links.replaces", packet_ref_matches?(:replaces, :replaces_image_id)),
|
|
203
|
+
profile_case("P-4", "packet_links.caused_by", packet_ref_matches?(:caused_by, :migration_receipt_ref)),
|
|
204
|
+
profile_case("P-5", "packet_links.has_supersedes", !migration_profile.dig(:packet_links, :has_supersedes)),
|
|
205
|
+
profile_case("P-6", "replacement_schema_fingerprint", replacement_fingerprint_matches?),
|
|
206
|
+
profile_case("P-7", "post_migration_schema_decision", post_migration_schema_trusted?),
|
|
207
|
+
profile_case("P-8", "post_migration_compatibility_decision", post_migration_compatibility_trusted?),
|
|
208
|
+
profile_case("P-9", "migration_chain", migration_profile[:migration_chain] == []),
|
|
209
|
+
p10_case
|
|
210
|
+
].map { |entry| deep_freeze(entry) }
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def profile_case(code, field, passed)
|
|
214
|
+
{
|
|
215
|
+
code: code,
|
|
216
|
+
field: field.to_sym,
|
|
217
|
+
status: passed ? :trusted : :blocked
|
|
218
|
+
}
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def p10_case
|
|
222
|
+
passed = !wrong_replacement_fingerprint?
|
|
223
|
+
case_entry = profile_case("P-10", "oof_code", passed || oof_mr3_blocked?)
|
|
224
|
+
case_entry[:status] = :blocked if wrong_replacement_fingerprint?
|
|
225
|
+
case_entry[:oof_code] = "OOF-MR3" if wrong_replacement_fingerprint?
|
|
226
|
+
case_entry
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def receipt_ref_present?
|
|
230
|
+
receipt_ref = migration_profile[:migration_receipt_ref]
|
|
231
|
+
return false unless value_present?(receipt_ref)
|
|
232
|
+
|
|
233
|
+
linked_receipt = evidence_links[:migration_receipt_ref]
|
|
234
|
+
linked_receipt.nil? || linked_receipt == receipt_ref
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def packet_ref_matches?(link_key, profile_key)
|
|
238
|
+
migration_profile.dig(:packet_links, link_key) == migration_profile[profile_key]
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def replacement_fingerprint_matches?
|
|
242
|
+
migration_profile[:replacement_schema_fingerprint] == migration_profile[:loaded_schema_fingerprint]
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def wrong_replacement_fingerprint?
|
|
246
|
+
!replacement_fingerprint_matches?
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def post_migration_schema_trusted?
|
|
250
|
+
migration_profile[:post_migration_schema_decision] == :trusted
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def post_migration_compatibility_trusted?
|
|
254
|
+
migration_profile[:post_migration_compatibility_decision] == :trusted
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def oof_mr3_blocked?
|
|
258
|
+
migration_profile[:oof_code] == "OOF-MR3" &&
|
|
259
|
+
migration_profile[:post_migration_schema_decision] == :blocked &&
|
|
260
|
+
compatibility_decision == :blocked &&
|
|
261
|
+
schema_check_outcome == :blocked
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def value_present?(value)
|
|
265
|
+
!value.nil? && value != ""
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def normalize_hash(value, name)
|
|
269
|
+
raise ArgumentError, "#{name} must be a hash" unless value.respond_to?(:to_h)
|
|
270
|
+
|
|
271
|
+
value.to_h.each_with_object({}) do |(key, entry), hash|
|
|
272
|
+
normalized_key = key.respond_to?(:to_sym) ? key.to_sym : key
|
|
273
|
+
hash[normalized_key] = normalize_value(entry)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def normalize_value(value)
|
|
278
|
+
case value
|
|
279
|
+
when Hash
|
|
280
|
+
normalize_hash(value, :value)
|
|
281
|
+
when Array
|
|
282
|
+
value.map { |entry| normalize_value(entry) }
|
|
283
|
+
else
|
|
284
|
+
value
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def deep_freeze(value)
|
|
289
|
+
case value
|
|
290
|
+
when Array
|
|
291
|
+
value.map { |entry| deep_freeze(entry) }.freeze
|
|
292
|
+
when Hash
|
|
293
|
+
value.transform_values { |entry| deep_freeze(entry) }.freeze
|
|
294
|
+
else
|
|
295
|
+
value.freeze
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Igniter
|
|
4
|
+
module Lang
|
|
5
|
+
module Types
|
|
6
|
+
class Descriptor
|
|
7
|
+
attr_reader :kind, :of, :dimensions, :metadata
|
|
8
|
+
|
|
9
|
+
def initialize(kind:, of:, dimensions: {}, metadata: {})
|
|
10
|
+
@kind = kind.to_sym
|
|
11
|
+
@of = of
|
|
12
|
+
@dimensions = dimensions.transform_keys(&:to_sym).freeze
|
|
13
|
+
@metadata = metadata.transform_keys(&:to_sym).freeze
|
|
14
|
+
freeze
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_h
|
|
18
|
+
{
|
|
19
|
+
kind: kind,
|
|
20
|
+
of: serialize_type(of),
|
|
21
|
+
dimensions: serialize_dimensions,
|
|
22
|
+
metadata: metadata
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def inspect
|
|
27
|
+
"#<#{self.class.name} #{to_h.inspect}>"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def ==(other)
|
|
31
|
+
other.is_a?(self.class) && to_h == other.to_h
|
|
32
|
+
end
|
|
33
|
+
alias eql? ==
|
|
34
|
+
|
|
35
|
+
def hash
|
|
36
|
+
to_h.hash
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def serialize_dimensions
|
|
42
|
+
dimensions.to_h do |name, value|
|
|
43
|
+
[name, serialize_type(value)]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def serialize_type(value)
|
|
48
|
+
case value
|
|
49
|
+
when Descriptor
|
|
50
|
+
value.to_h
|
|
51
|
+
when Module
|
|
52
|
+
value.name
|
|
53
|
+
else
|
|
54
|
+
value.respond_to?(:to_h) ? value.to_h : value
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class History
|
|
60
|
+
def self.[](of)
|
|
61
|
+
Descriptor.new(kind: :history, of: of)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
class BiHistory
|
|
66
|
+
def self.[](of)
|
|
67
|
+
Descriptor.new(kind: :bi_history, of: of)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class OLAPPoint
|
|
72
|
+
def self.[](of, dimensions = {})
|
|
73
|
+
Descriptor.new(kind: :olap_point, of: of, dimensions: dimensions)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class Forecast
|
|
78
|
+
def self.[](of)
|
|
79
|
+
Descriptor.new(kind: :forecast, of: of)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|