hecks 3.12.0 → 3.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hecks/adapters/driven/script_runner.adapter +3 -0
  3. data/lib/hecks/adapters/driven/script_runner.rb +93 -0
  4. data/lib/hecks/adapters/driven.rb +1 -0
  5. data/lib/hecks/bluebook/meta_validator/syntax_boot.rb +16 -12
  6. data/lib/hecks/bluebook/meta_validator.rb +28 -21
  7. data/lib/hecks/deploy/bluebook/deploy.bluebook +1 -1
  8. data/lib/hecks/framework/bluebook/change.behaviors +30 -0
  9. data/lib/hecks/framework/bluebook/change.bluebook +162 -0
  10. data/lib/hecks/framework/bluebook/change.hecksagon +21 -0
  11. data/lib/hecks/framework/change.oidc.json +34 -0
  12. data/lib/hecks/framework/console_settings.oidc.json +103 -0
  13. data/lib/hecks/framework/governance.oidc.json +28 -0
  14. data/lib/hecks/framework/identity.oidc.json +18 -0
  15. data/lib/hecks/framework/privacy.oidc.json +30 -0
  16. data/lib/hecks/gate/stages.yml +3 -0
  17. data/lib/hecks/grammar/translation.oidc.json +48 -0
  18. data/lib/hecks/hecks/adapters/codebase/test_runner.rb +12 -1
  19. data/lib/hecks/hecks/adapters/deploy_toolchain.rb +2 -1
  20. data/lib/hecks/projections/deploy/fargate/cdn/lines.rb +12 -1
  21. data/lib/hecks/projections/site/admin_cms/templates/membership.rb +10 -7
  22. data/lib/hecks/projections/site/edge/behaviours.rb +10 -6
  23. data/lib/hecks/projections/site/edge/checks.rb +2 -0
  24. data/lib/hecks/projections/site/edge/function_checks.rb +104 -0
  25. data/lib/hecks/projections/site/edge/function_code.rb +86 -0
  26. data/lib/hecks/projections/site/edge/redirect_host.js.tmpl +65 -0
  27. data/lib/hecks/projections/site/edge.rb +35 -9
  28. data/lib/hecks/projections/site/site_cdn.rb +21 -7
  29. data/lib/hecks/projections/site/table/row_builder.rb +12 -2
  30. data/lib/hecks/projections/site/table.rb +4 -2
  31. data/lib/hecks/site/bluebook/site.bluebook +16 -1
  32. data/lib/hecks/tools/oidc_manifests.rb +44 -6
  33. data/lib/hecks/tools/site_routes/templates.rb +13 -9
  34. data/lib/hecks/version.rb +1 -1
  35. data/prebuilt/{verdicts-df19f35868d3284a70f55e42dcef87ef4e65e6a678e5135f72e1f6cff4c1357b.json → verdicts-48318ca172edd21443b1ad02801c697fff100b746e828f09db987647641a5df2.json} +1 -1
  36. data/rust/host/HECKS_RELEASE +1 -1
  37. data/rust/host/src/auth.rs +58 -0
  38. data/rust/host/src/platform_signin/session.rs +1 -1
  39. metadata +21 -7
  40. /data/lib/hecks/framework/{oidc.json → compliance.oidc.json} +0 -0
  41. /data/lib/hecks/grammar/{oidc.json → expression.oidc.json} +0 -0
  42. /data/prebuilt/{d74a00e996222c1d8b676d5959092effc46b4dc59e0555f3bf9554ac58e3094a.marshal → 2b59737fbdbd5f44edda0fddce2611f45d76087b3a7c782d1f1a17ea58c77948.marshal} +0 -0
  43. /data/prebuilt/{9ee54e2f0d4d6d3fe046827779b221e02de665fba911a048ae5dd8b8fbfb7d90.marshal → 58208399bada10b0db99928c48e38789288fc58f7b71a72b21bfa386680e32ed.marshal} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: beba8cd60d4c859286fa1121e3b382cc63e826e010dfd336714befa036dfad94
4
- data.tar.gz: 16deb6ba2dd98c8d09385e77a9773f92ef12726d097e71601d2e3cfdbb83ae00
3
+ metadata.gz: e1a1eacc3bae3f940928e23269c95e0306f291ec5a2b6d62268e254f12f1902e
4
+ data.tar.gz: e4168d9e617dbad8912a65dbe10be8a3a32a6a08b18fd84542a05fa9803aeaef
5
5
  SHA512:
6
- metadata.gz: fe730368d2f8942c67a5510c5b8344bdad86f9aa0990515903e147da4fe71fbc6f17880ea2a1b26de4ffa0d24ad20c416455df58ee8a66617e1f832b2637e2b0
7
- data.tar.gz: a41080c78fc7b1e9d43347fd4b965d6811c246baee7072214c5f7895564eccc94ce699b86bc739de0f3d7d7830fb8057e6bf2e0699496e201ffd057c7e6a39d5
6
+ metadata.gz: a49c8992b247138d92232d00123dd73986be81040bb1356fc912f97905644bbb35a38af431a1d81475b9ce07c644ab8c2aab3370c3fabaf685c0f8a93a16bd70
7
+ data.tar.gz: 48ccea615a818989da2a01babb5c9d344a5a7c94fbe2eea47301a1437f29aa671134011a626f317c128bcaf1aaa912a21f056e30c8b133643123df129aa7a470
@@ -0,0 +1,3 @@
1
+ Hecks.adapter "ScriptRunner" do
2
+ port "Script"
3
+ end
@@ -0,0 +1,93 @@
1
+ require "digest"
2
+ require "json"
3
+
4
+ module Hecks
5
+ module Adapters
6
+ # The `Script` port's adapter for a `Change`: it runs the scripts registered with it, in this
7
+ # process. A script is a name, a `plan` that says what it would do without doing it, and an
8
+ # `apply` that does it.
9
+ #
10
+ # `examine` plans a change and answers the plan with a digest of it. `perform` plans again and
11
+ # carries the change out only when the plan still has the digest that was confirmed, so what
12
+ # runs is what the person saw. A script that cannot be found, or whose plan or apply raises,
13
+ # refuses the change with its message.
14
+ class ScriptRunner
15
+ # A script: what it would do, and doing it. Both take the arguments as a Hash of String keys.
16
+ Script = Struct.new(:plan, :apply, keyword_init: true)
17
+
18
+ # Why a change was refused: an unknown script, a plan that moved, or the script's own failure.
19
+ class Refused < StandardError; end
20
+
21
+ class << self
22
+ # @return [Hash{String => Script}] the scripts this process can run, by name
23
+ def scripts = @scripts ||= {}
24
+
25
+ # @param name [String] the name a change asks for
26
+ # @param plan [#call] takes the arguments, returns the text of what the script would do
27
+ # @param apply [#call] takes the arguments, does it, returns the text of what happened
28
+ # @return [Script] the registered script
29
+ def register(name, plan:, apply:) = scripts[name.to_s] = Script.new(plan: plan, apply: apply)
30
+
31
+ # Forgets every registered script.
32
+ #
33
+ # @return [Hash] the empty registry
34
+ def reset! = @scripts = {}
35
+ end
36
+
37
+ # Accepts the arguments every driven adapter is built with and keeps none of them.
38
+ #
39
+ # @param aggregate [Object, nil] unused
40
+ # @param settings [Hash] unused
41
+ # @param root [String, nil] unused
42
+ def initialize(aggregate: nil, settings: {}, root: nil); end
43
+
44
+ # Plans the change.
45
+ #
46
+ # @param held [Hash] the record: `script` and `arguments`
47
+ # @return [Hash{Symbol => Hash}] `plan:` what the script would do, and `digest:` its
48
+ # fingerprint
49
+ # @raise [Refused] when the script is unknown or its plan raises
50
+ def examine(**held)
51
+ name, args = request(held)
52
+ text = planned(name, args)
53
+ { plan: { value: text }, digest: { value: digest(name, args, text) } }
54
+ end
55
+
56
+ # Carries out a confirmed change if its plan has not moved.
57
+ #
58
+ # @param held [Hash] the record: `script`, `arguments` and `planned_digest`
59
+ # @return [Hash{Symbol => Hash}] `report:` what the script reported
60
+ # @raise [Refused] when the script is unknown, the plan has moved, or the script raises
61
+ def perform(**held)
62
+ name, args = request(held)
63
+ current = digest(name, args, planned(name, args))
64
+ raise Refused, "the plan moved since it was confirmed; plan it again" unless current == plain(held[:planned_digest])
65
+
66
+ { report: { value: run(name, :apply, args).to_s } }
67
+ end
68
+
69
+ private
70
+
71
+ def request(held) = [plain(held[:script]), arguments(held[:arguments])]
72
+
73
+ def planned(name, args) = run(name, :plan, args).to_s
74
+
75
+ def run(name, step, args)
76
+ script = self.class.scripts.fetch(name) { raise Refused, "no script is registered as #{name.inspect}" }
77
+ script.public_send(step).call(args)
78
+ rescue Refused
79
+ raise
80
+ rescue StandardError => e
81
+ raise Refused, "#{name} #{step} failed: #{e.message}"
82
+ end
83
+
84
+ # The digest stands for the script, its arguments and its plan, so none of them can change
85
+ # between confirming and applying.
86
+ def digest(name, args, text) = Digest::SHA256.hexdigest(JSON.generate([name, args.sort.to_h, text]))
87
+
88
+ def arguments(list) = Array(list).to_h { |pair| [plain(pair[:key]), plain(pair[:value])] }
89
+
90
+ def plain(cell) = cell.is_a?(Hash) && cell.key?(:value) ? cell[:value] : cell
91
+ end
92
+ end
93
+ end
@@ -27,3 +27,4 @@ require_relative "driven/governance_authorization"
27
27
  require_relative "driven/identity_registry"
28
28
  require_relative "driven/google_authentication"
29
29
  require_relative "driven/claude_code"
30
+ require_relative "driven/script_runner"
@@ -37,19 +37,23 @@ module Hecks
37
37
  end
38
38
 
39
39
  # Dispatches every seed row into a fresh "Bluebook" instance and
40
- # reads the result back.
40
+ # reads the result back. The table is memoized for the process, so it is built with no
41
+ # ambient caller: an enclosing `Hecks.as_caller` would have the language's own
42
+ # `Language`-role commands refused.
41
43
  def boot
42
- bluebook = MetaValidator.grammar_registry.bluebook("Bluebook")
43
- # `fresh_runtime`, not a new `Runtime::Registry` — the grammar
44
- # registry already has "Bluebook" registered and its adapter
45
- # ports already loaded.
46
- runtime = MetaValidator.fresh_runtime
47
-
48
- declare_syntax(runtime, bluebook)
49
- admit_keywords(runtime, bluebook)
50
- admit_arguments(runtime, bluebook)
51
-
52
- read_back(runtime, bluebook)
44
+ Runtime::Caller.without do
45
+ bluebook = MetaValidator.grammar_registry.bluebook("Bluebook")
46
+ # `fresh_runtime`, not a new `Runtime::Registry` — the grammar
47
+ # registry already has "Bluebook" registered and its adapter
48
+ # ports already loaded.
49
+ runtime = MetaValidator.fresh_runtime
50
+
51
+ declare_syntax(runtime, bluebook)
52
+ admit_keywords(runtime, bluebook)
53
+ admit_arguments(runtime, bluebook)
54
+
55
+ read_back(runtime, bluebook)
56
+ end
53
57
  end
54
58
 
55
59
  # An Integer stays an Integer — `position` is `Position`-typed, so
@@ -168,32 +168,39 @@ module Hecks
168
168
  end
169
169
 
170
170
  # The booted, self-judged language registry every ordinary bluebook is
171
- # judged against — built once per process and memoized, with shadow parsing off: a caller
172
- # inside `while_shadow_parsing` that is first to ask would otherwise memoize a grammar
173
- # parsed in that mode, or fail to load it.
171
+ # judged against — built once per process and memoized, with shadow parsing off and no
172
+ # ambient caller bound. A caller inside `while_shadow_parsing` that is first to ask would
173
+ # otherwise memoize a grammar parsed in that mode, or fail to load it; one inside
174
+ # `Hecks.as_caller` would have the language's own `Language`-role commands refused, and the
175
+ # grammar would be memoized without the chapters those refusals dropped.
174
176
  #
175
177
  # @return [Runtime::Registry] the booted, fixpoint-judged language
176
178
  # registry
177
179
  def self.grammar_registry
178
- @grammar_registry ||= while_not_shadow_parsing do
179
- registry = load_grammar_into(Runtime::Registry.new)
180
- # Assigned before the fixpoint judge below, since judging re-enters
181
- # grammar_registry (via fresh_runtime/Plan.for) and a bare `||=`
182
- # would still be nil mid-evaluation, recursing forever.
183
- @grammar_registry = registry
184
- # The language now judges itself; every bluebook from here on is
185
- # judged by that assembled graph, not the raw bootstrap one. Must
186
- # run after load_grammar_into's ensure clears @bootstrapping.
187
- while_forcing_fixpoint do
188
- LANGUAGE_CHAPTERS.each { |name| registry.add_bluebook(call(registry.bluebook(name))) }
189
- load_attached_grammar_into(registry)
190
- end
191
- # Keyed on this registry's object identity, not a bare boolean, so
192
- # a manual reset can never leave a stale "ready" from the previous
193
- # cycle.
194
- @grammar_ready_for = registry.object_id
195
- registry
180
+ @grammar_registry ||= while_not_shadow_parsing { Runtime::Caller.without { build_grammar_registry } }
181
+ end
182
+
183
+ # The one-time build behind `grammar_registry`.
184
+ #
185
+ # @return [Runtime::Registry] the booted, fixpoint-judged language registry
186
+ def self.build_grammar_registry
187
+ registry = load_grammar_into(Runtime::Registry.new)
188
+ # Assigned before the fixpoint judge below, since judging re-enters
189
+ # grammar_registry (via fresh_runtime/Plan.for) and a bare `||=`
190
+ # would still be nil mid-evaluation, recursing forever.
191
+ @grammar_registry = registry
192
+ # The language now judges itself; every bluebook from here on is
193
+ # judged by that assembled graph, not the raw bootstrap one. Must
194
+ # run after load_grammar_into's ensure clears @bootstrapping.
195
+ while_forcing_fixpoint do
196
+ LANGUAGE_CHAPTERS.each { |name| registry.add_bluebook(call(registry.bluebook(name))) }
197
+ load_attached_grammar_into(registry)
196
198
  end
199
+ # Keyed on this registry's object identity, not a bare boolean, so
200
+ # a manual reset can never leave a stale "ready" from the previous
201
+ # cycle.
202
+ @grammar_ready_for = registry.object_id
203
+ registry
197
204
  end
198
205
 
199
206
  # Whether `grammar_registry`'s memoized singleton has finished its
@@ -2806,7 +2806,7 @@ Hecks.bluebook "Deploy" do
2806
2806
  end
2807
2807
 
2808
2808
  command "ProjectOidc" do
2809
- goal "Write each domain's OIDC client and scope manifest beside it as oidc.json"
2809
+ goal "Write each domain's OIDC client and scope manifest beside it: oidc.json, or one <chapter>.oidc.json for each chapter of a directory that holds several"
2810
2810
 
2811
2811
  attribute :domains, DomainList, optional: true
2812
2812
  attribute :run, RunKey
@@ -0,0 +1,30 @@
1
+ Hecks.behaviors "Change" do
2
+ vision "A change names its script, faults when that script cannot plan it, and is confirmed only from a plan."
3
+
4
+ loads "change.bluebook", "governance.bluebook", "change.hecksagon", "../../../../spec/fixtures/change/governance.hecksagon"
5
+
6
+ test "Request refuses a change that names no script" do
7
+ tests "Request", on: "Change"
8
+ input run: { value: "c1" }, script: { value: "" }
9
+ expect refused: "must match"
10
+ end
11
+
12
+ test "Request refuses a change that is not named" do
13
+ tests "Request", on: "Change"
14
+ input run: { value: "" }, script: { value: "rename" }
15
+ expect refused: "must match"
16
+ end
17
+
18
+ test "Request faults a change whose script nobody registered" do
19
+ tests "Request", on: "Change"
20
+ input run: { value: "c2" }, script: { value: "no_such_script" }
21
+ expect status: "faulted"
22
+ end
23
+
24
+ test "Confirm refuses a change that was never planned" do
25
+ tests "Confirm", on: "Change"
26
+ setup "Change::Change.Request", run: { value: "c3" }, script: { value: "no_such_script" }
27
+ input run: { value: "c3" }, digest: { value: "ab12" }
28
+ expect refused: "the digest confirmed is the digest planned"
29
+ end
30
+ end
@@ -0,0 +1,162 @@
1
+ Hecks.bluebook "Change" do
2
+ vision "A change you can preview: it is planned, shown, confirmed against exactly that plan, and only then carried out, whatever script it runs."
3
+ supporting
4
+
5
+ # A framework member like Governance and Identity: attach it with `attaches "Change"` in the
6
+ # consuming domain's own `.hecksagon`. The script is the port's adapter, so what a change
7
+ # does lives behind the `Script` port, and this chapter holds only how any change moves.
8
+ aggregate "Change" do
9
+ description "One change a script makes, previewed before it is carried out and applied only if its plan is unchanged."
10
+
11
+ attribute :run, RunKey
12
+ attribute :script, ScriptName
13
+ attribute :arguments, list_of(Argument), optional: true
14
+ attribute :plan, Report, optional: true
15
+ attribute :planned_digest, Digest, optional: true
16
+ attribute :report, Report, optional: true
17
+ attribute :refusal, Report, optional: true
18
+ identified_by :run
19
+
20
+ value_object "RunKey" do
21
+ attribute :value, String, pattern: '[^ \t\n\r]'
22
+
23
+ invariant("a change is named") { !value.to_s.empty? }
24
+ end
25
+
26
+ # The name the script is registered under with the adapter.
27
+ value_object "ScriptName" do
28
+ attribute :value, String, pattern: '[^ \t\n\r]'
29
+
30
+ invariant("a change names its script") { !value.to_s.empty? }
31
+ end
32
+
33
+ # One argument of the script, spelled as text; the script says what each key means.
34
+ value_object "Argument" do
35
+ attribute :key, String
36
+ attribute :value, String
37
+ end
38
+
39
+ value_object "Report" do
40
+ attribute :value, String
41
+ end
42
+
43
+ # A fingerprint of the plan, the script and its arguments: confirming one digest applies
44
+ # that plan and no other.
45
+ value_object "Digest" do
46
+ attribute :value, String, pattern: '[0-9a-f]+'
47
+
48
+ invariant("a plan has a digest") { !value.to_s.empty? }
49
+ end
50
+
51
+ lifecycle :status, default: "requested" do
52
+ mark :failure, "faulted"
53
+ transition "Plan" => "planned", from: "requested"
54
+ transition "Confirm" => "confirmed", from: "planned"
55
+ transition "Complete" => "applied", from: "confirmed"
56
+ transition "Fault" => "faulted", from: ["requested", "planned", "confirmed"]
57
+ end
58
+
59
+ command "Request" do
60
+ role "Maintainer"
61
+ goal "Ask for a change by naming its script and giving the script's arguments"
62
+
63
+ attribute :run, RunKey
64
+ attribute :script, ScriptName
65
+ attribute :arguments, list_of(Argument), optional: true
66
+
67
+ sets :run
68
+ sets :script
69
+ sets :arguments
70
+
71
+ emits ChangeRequested
72
+ end
73
+
74
+ command "Plan" do
75
+ role "System"
76
+ goal "Record what the script would do, and the digest that stands for it"
77
+
78
+ reference_to Change
79
+ attribute :plan, Report
80
+ attribute :digest, Digest
81
+
82
+ sets :plan
83
+ sets :planned_digest, to: :digest
84
+
85
+ emits ChangePlanned
86
+ end
87
+
88
+ command "Confirm" do
89
+ role "Maintainer"
90
+ goal "Agree to the plan shown, by naming its digest"
91
+
92
+ reference_to Change
93
+ attribute :digest, Digest
94
+
95
+ given("the digest confirmed is the digest planned") { digest.value == planned_digest.value }
96
+
97
+ emits ChangeConfirmed
98
+ end
99
+
100
+ command "Complete" do
101
+ role "System"
102
+ goal "Record that the confirmed plan was carried out, and what the script reported"
103
+
104
+ reference_to Change
105
+ attribute :report, Report
106
+
107
+ sets :report
108
+
109
+ emits ChangeApplied
110
+ end
111
+
112
+ command "Fault" do
113
+ role "System"
114
+ goal "Record that the change was refused or could not be carried out, and why"
115
+
116
+ reference_to Change
117
+ attribute :refusal, Report
118
+
119
+ sets :refusal
120
+
121
+ emits ChangeFaulted
122
+ end
123
+
124
+ query "Outcome" do
125
+ description "How one change stands: its status, its plan, and what it reported or why it failed."
126
+ attribute :run, RunKey
127
+ where(run: :run)
128
+ order_by :run
129
+ end
130
+
131
+ query "Faulted" do
132
+ description "Every change that was refused or could not be carried out."
133
+ where(status: "faulted")
134
+ order_by :run
135
+ end
136
+ end
137
+
138
+ policy "ExamineWhenRequested" do
139
+ on "Change.ChangeRequested"
140
+ trigger Change::Script::Examine, with: { run: :run }
141
+ end
142
+
143
+ policy "RecordThePlanWhenExamined" do
144
+ on "Change.ChangeExamined"
145
+ trigger Change::Plan, with: { plan: :plan, digest: :digest }
146
+ end
147
+
148
+ policy "PerformWhenConfirmed" do
149
+ on "Change.ChangeConfirmed"
150
+ trigger Change::Script::Perform, with: { run: :run }
151
+ end
152
+
153
+ policy "RecordTheOutcomeWhenPerformed" do
154
+ on "Change.ChangeAnswered"
155
+ trigger Change::Complete, with: { report: :report }
156
+ end
157
+
158
+ policy "RecordTheRefusal" do
159
+ on "Change.ChangeRefused"
160
+ trigger Change::Fault, with: { refusal: :refusal }
161
+ end
162
+ end
@@ -0,0 +1,21 @@
1
+ Hecks.hecksagon "Change" do
2
+ # `Change.Request` and `Change.Confirm` declare roles; same reason as Compliance.
3
+ attaches "Governance"
4
+ persisted_by "Memory"
5
+
6
+ # The change moves through two asks: `Examine` plans it, `Perform` carries it out. What a
7
+ # script does is the adapter's, so the chapter never names one.
8
+ Change::Change.port "Script" do
9
+ asks "Examine", to: Change do
10
+ attribute :run, RunKey
11
+ answers "ChangeExamined"
12
+ refuses "ChangeRefused"
13
+ end
14
+
15
+ asks "Perform", to: Change do
16
+ attribute :run, RunKey
17
+ answers "ChangeAnswered"
18
+ refuses "ChangeRefused"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,34 @@
1
+ {
2
+ "audience": "Change",
3
+ "scopes": [
4
+ {
5
+ "scope": "change:change.complete",
6
+ "verb": "Change::Change.Complete",
7
+ "role": "System"
8
+ },
9
+ {
10
+ "scope": "change:change.confirm",
11
+ "verb": "Change::Change.Confirm",
12
+ "role": "Maintainer"
13
+ },
14
+ {
15
+ "scope": "change:change.fault",
16
+ "verb": "Change::Change.Fault",
17
+ "role": "System"
18
+ },
19
+ {
20
+ "scope": "change:change.plan",
21
+ "verb": "Change::Change.Plan",
22
+ "role": "System"
23
+ },
24
+ {
25
+ "scope": "change:change.request",
26
+ "verb": "Change::Change.Request",
27
+ "role": "Maintainer"
28
+ }
29
+ ],
30
+ "roles": [
31
+ "Maintainer",
32
+ "System"
33
+ ]
34
+ }
@@ -0,0 +1,103 @@
1
+ {
2
+ "audience": "ConsoleSettings",
3
+ "scopes": [
4
+ {
5
+ "scope": "console_settings:collection.declare",
6
+ "verb": "ConsoleSettings::Collection.Declare",
7
+ "role": "Console"
8
+ },
9
+ {
10
+ "scope": "console_settings:collection.replace_columns",
11
+ "verb": "ConsoleSettings::Collection.ReplaceColumns",
12
+ "role": "Console"
13
+ },
14
+ {
15
+ "scope": "console_settings:collection.replace_detail_field_columns",
16
+ "verb": "ConsoleSettings::Collection.ReplaceDetailFieldColumns",
17
+ "role": "Console"
18
+ },
19
+ {
20
+ "scope": "console_settings:collection.replace_detail_fields",
21
+ "verb": "ConsoleSettings::Collection.ReplaceDetailFields",
22
+ "role": "Console"
23
+ },
24
+ {
25
+ "scope": "console_settings:collection.replace_field_formats",
26
+ "verb": "ConsoleSettings::Collection.ReplaceFieldFormats",
27
+ "role": "Console"
28
+ },
29
+ {
30
+ "scope": "console_settings:collection.replace_preconditions",
31
+ "verb": "ConsoleSettings::Collection.ReplacePreconditions",
32
+ "role": "Console"
33
+ },
34
+ {
35
+ "scope": "console_settings:collection.set_extra",
36
+ "verb": "ConsoleSettings::Collection.SetExtra",
37
+ "role": "Console"
38
+ },
39
+ {
40
+ "scope": "console_settings:collection.set_identity",
41
+ "verb": "ConsoleSettings::Collection.SetIdentity",
42
+ "role": "Console"
43
+ },
44
+ {
45
+ "scope": "console_settings:collection.set_key",
46
+ "verb": "ConsoleSettings::Collection.SetKey",
47
+ "role": "Console"
48
+ },
49
+ {
50
+ "scope": "console_settings:collection.set_label",
51
+ "verb": "ConsoleSettings::Collection.SetLabel",
52
+ "role": "Console"
53
+ },
54
+ {
55
+ "scope": "console_settings:collection.set_list_query",
56
+ "verb": "ConsoleSettings::Collection.SetListQuery",
57
+ "role": "Console"
58
+ },
59
+ {
60
+ "scope": "console_settings:collection.set_nav_order",
61
+ "verb": "ConsoleSettings::Collection.SetNavOrder",
62
+ "role": "Console"
63
+ },
64
+ {
65
+ "scope": "console_settings:collection.set_primary_field",
66
+ "verb": "ConsoleSettings::Collection.SetPrimaryField",
67
+ "role": "Console"
68
+ },
69
+ {
70
+ "scope": "console_settings:overview.declare",
71
+ "verb": "ConsoleSettings::Overview.Declare",
72
+ "role": "Console"
73
+ },
74
+ {
75
+ "scope": "console_settings:overview.replace_stats",
76
+ "verb": "ConsoleSettings::Overview.ReplaceStats",
77
+ "role": "Console"
78
+ },
79
+ {
80
+ "scope": "console_settings:state_style.declare",
81
+ "verb": "ConsoleSettings::StateStyle.Declare",
82
+ "role": "Console"
83
+ },
84
+ {
85
+ "scope": "console_settings:state_style.set_attention",
86
+ "verb": "ConsoleSettings::StateStyle.SetAttention",
87
+ "role": "Console"
88
+ },
89
+ {
90
+ "scope": "console_settings:state_style.set_extra",
91
+ "verb": "ConsoleSettings::StateStyle.SetExtra",
92
+ "role": "Console"
93
+ },
94
+ {
95
+ "scope": "console_settings:state_style.set_tone",
96
+ "verb": "ConsoleSettings::StateStyle.SetTone",
97
+ "role": "Console"
98
+ }
99
+ ],
100
+ "roles": [
101
+ "Console"
102
+ ]
103
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ "audience": "Governance",
3
+ "scopes": [
4
+ {
5
+ "scope": "governance:role_assignment.assign",
6
+ "verb": "Governance::RoleAssignment.Assign",
7
+ "role": "Governance administrator"
8
+ },
9
+ {
10
+ "scope": "governance:role_assignment.revoke",
11
+ "verb": "Governance::RoleAssignment.Revoke",
12
+ "role": "Governance administrator"
13
+ },
14
+ {
15
+ "scope": "governance:role_transition.grant",
16
+ "verb": "Governance::RoleTransition.Grant",
17
+ "role": "Governance administrator"
18
+ },
19
+ {
20
+ "scope": "governance:role_transition.revoke",
21
+ "verb": "Governance::RoleTransition.Revoke",
22
+ "role": "Governance administrator"
23
+ }
24
+ ],
25
+ "roles": [
26
+ "Governance administrator"
27
+ ]
28
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "audience": "Identity",
3
+ "scopes": [
4
+ {
5
+ "scope": "identity:external_identifier.link",
6
+ "verb": "Identity::ExternalIdentifier.Link",
7
+ "role": "Identity registrar"
8
+ },
9
+ {
10
+ "scope": "identity:identity.register",
11
+ "verb": "Identity::Identity.Register",
12
+ "role": "Identity registrar"
13
+ }
14
+ ],
15
+ "roles": [
16
+ "Identity registrar"
17
+ ]
18
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "audience": "Privacy",
3
+ "scopes": [
4
+ {
5
+ "scope": "privacy:marking.mark",
6
+ "verb": "Privacy::Marking.Mark",
7
+ "role": "Deployment"
8
+ },
9
+ {
10
+ "scope": "privacy:marking.unmark",
11
+ "verb": "Privacy::Marking.Unmark",
12
+ "role": "Deployment"
13
+ },
14
+ {
15
+ "scope": "privacy:subject_key.issue",
16
+ "verb": "Privacy::SubjectKey.Issue",
17
+ "role": "System"
18
+ },
19
+ {
20
+ "scope": "privacy:subject_key.shred",
21
+ "verb": "Privacy::SubjectKey.Shred",
22
+ "role": "Privacy officer"
23
+ }
24
+ ],
25
+ "roles": [
26
+ "Deployment",
27
+ "Privacy officer",
28
+ "System"
29
+ ]
30
+ }
@@ -20,8 +20,11 @@
20
20
  # with `only=`: several of them write generated files and compare, so the stage is not meant to
21
21
  # run whole in one checkout.
22
22
  pre_push:
23
+ # HECKS_PROCESS_SPECS keeps the examples tagged `process` (they start child processes, so a plain
24
+ # `rspec` leaves them out) in the suite this stage runs.
23
25
  env:
24
26
  HECKS_ENVIRONMENT: memory
27
+ HECKS_PROCESS_SPECS: "1"
25
28
  checks:
26
29
  - id: rspec
27
30
  title: rspec (parallel)