ace-lab 0.6.0 → 0.8.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.
@@ -6,6 +6,7 @@ require "open3"
6
6
  require_relative "protected_service_request"
7
7
  require_relative "../molecules/ordinary_socket"
8
8
  require "ace/assign/atoms/fixed_merge_schemas"
9
+ require "ace/assign/molecules/installed_journal_read"
9
10
 
10
11
  module Ace
11
12
  module Lab
@@ -45,8 +46,7 @@ module Ace
45
46
  def initialize(topology: nil, policy: nil, coordinator: nil, repo_root: nil, ingress: nil)
46
47
  @topology = topology || TopologyService.from_config
47
48
  @repo_root = repo_root || git_toplevel
48
- @coordinator = coordinator ||
49
- Ace::Assign::Organisms::AttemptCoordinator.new(repo_root: @repo_root)
49
+ @coordinator = coordinator
50
50
  @policy = policy || Molecules::ServicePolicy.new(
51
51
  Molecules::GrantResolver.trusted_document(Ace::Lab.authorization_path)
52
52
  )
@@ -71,6 +71,11 @@ module Ace
71
71
  queue_entry: queue_entry, authorization: authorization, request_id: request_id,
72
72
  document: document)
73
73
  principal = authenticate!(project)
74
+ unless @coordinator
75
+ return with_installed_journal(project) { |producer| producer.request(project: project,
76
+ assignment: assignment, attempt: attempt, queue_entry: queue_entry, operation: operation,
77
+ input: input, authorization: authorization, request_id: request_id, **options) }
78
+ end
74
79
  existing = @coordinator.fixed_merge_record(request_id)
75
80
  if existing
76
81
  return ack_envelope(existing) if exact_replay?(existing, project: project,
@@ -137,6 +142,11 @@ module Ace
137
142
  invalid!("invalid input digest", request)
138
143
  end
139
144
  authenticate!(project)
145
+ unless @coordinator
146
+ return with_installed_journal(project) { |producer| producer.status(project: project,
147
+ assignment: assignment, attempt: attempt, queue_entry: queue_entry, reference: reference,
148
+ request: request, input_digest: input_digest, **options) }
149
+ end
140
150
  record = @coordinator.fixed_merge_status(reference: reference, request_id: request,
141
151
  project_id: project, assignment_id: assignment, attempt_id: attempt,
142
152
  queue_entry: queue_entry, input_digest: input_digest)
@@ -198,6 +208,23 @@ module Ace
198
208
 
199
209
  private
200
210
 
211
+ def with_installed_journal(project)
212
+ receiver = @policy.ordinary_receiver!(project)
213
+ unless receiver && %w[journal_repository journal_ref].all? { |key| receiver.key?(key) }
214
+ raise Ace::Lab::InvalidConfigurationError, "installed ordinary journal selection is missing"
215
+ end
216
+ repository, ref = receiver.values_at("journal_repository", "journal_ref")
217
+ boundary = Ace::Assign::Molecules::InstalledJournalRead.new(repo_root: repository,
218
+ ref: ref, owner_uid: receiver.fetch("receiver_uid"))
219
+ boundary.with(deadline: Process.clock_gettime(Process::CLOCK_MONOTONIC) + 30) do |view|
220
+ journal = Ace::Assign::Molecules::EvidenceJournal.new(repo_root: repository,
221
+ ref: ref, checkout_root: File.join(repository, ".unused-reader"), read_boundary: view)
222
+ coordinator = Ace::Assign::Organisms::AttemptCoordinator.new(repo_root: @repo_root, journal: journal)
223
+ yield self.class.new(topology: @topology, policy: @policy, repo_root: @repo_root,
224
+ coordinator: coordinator, ingress: @ingress)
225
+ end
226
+ end
227
+
201
228
  # The immutable binding digest — spec ruling r4: lowercase hex SHA-256
202
229
  # over the canonical JSON (recursively key-sorted, compact, UTF-8) of
203
230
  # the full eight-field binding. Computed once here at admission; the
@@ -242,7 +269,7 @@ module Ace
242
269
  raise Molecules::OrdinarySocket::OrdinaryUnavailable,
243
270
  "ordinary merge admission is not available in the installed configuration"
244
271
  end
245
- receiver.merge("configuration_sha256" => Atoms::ServiceInput.digest(@policy.document))
272
+ receiver.merge("configuration_sha256" => Molecules::ServicePolicy.configuration_digest(@policy.document))
246
273
  end
247
274
 
248
275
  def resolve_selection!(project:, assignment:, attempt:, queue_entry:)
@@ -261,8 +288,15 @@ module Ace
261
288
  "head_ref" => document.fetch("head_ref"), "candidate_head" => document.fetch("candidate_head"),
262
289
  "base_repository" => document.fetch("base_repository"), "base_ref" => document.fetch("base_ref"),
263
290
  "expected_base_head" => document.fetch("expected_base_head")}
264
- @policy.authorize_ordinary!(authorization, binding)
265
- rescue SecurityError => e
291
+ if authorization.start_with?("proposal-")
292
+ @coordinator.proposal_authorization(authorization, binding.slice(
293
+ "operation", "project_id", "assignment_id", "attempt_id", "input_digest", "candidate_head").merge(
294
+ "target" => {"resource" => document.fetch("pr_url"), "artifact_digest" => nil},
295
+ "caller_uid" => Process.uid))
296
+ else
297
+ @policy.authorize_ordinary!(authorization, binding)
298
+ end
299
+ rescue SecurityError, Ace::Assign::AttemptErrors::ReceiptRejected => e
266
300
  # Spec table (ruling r4): the authorization decision or reference is
267
301
  # invalid for this request — missing, expired, revoked, out of scope,
268
302
  # bound to another operation/project/PR/head, or not an ordinary
@@ -306,7 +340,7 @@ module Ace
306
340
  def normalize_ack(response, request_id:, input_digest:)
307
341
  data = response.fetch("data") { {} }
308
342
  expected = %w[schema type request_id input_digest reference]
309
- digest = data["input_digest"]
343
+ digest = data.is_a?(Hash) && data["input_digest"]
310
344
  unless data.is_a?(Hash) && (data.keys - expected).empty? &&
311
345
  expected.all? { |key| data[key].is_a?(String) && !data[key].empty? } &&
312
346
  data.fetch("schema") == Ace::Assign::Atoms::FixedMergeSchemas::ACK_SCHEMA_ID &&
@@ -322,7 +356,7 @@ module Ace
322
356
  def normalize_refusal(response, request_id:, input_digest:)
323
357
  error = response.fetch("error") { {} }
324
358
  expected = %w[schema code message request_id input_digest]
325
- valid = error.is_a?(Hash) && (error.keys - expected).empty? &&
359
+ valid = error.is_a?(Hash) && error.keys.sort == expected.sort &&
326
360
  error.fetch("schema") == Ace::Assign::Atoms::FixedMergeSchemas::REFUSAL_SCHEMA_ID &&
327
361
  CODES.include?(error.fetch("code")) &&
328
362
  error.fetch("message").is_a?(String) && !error.fetch("message").empty? &&
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ace
4
4
  module Lab
5
- VERSION = "0.6.0"
5
+ VERSION = "0.8.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ace-lab
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Czyz
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-10-14 00:00:00.000000000 Z
10
+ date: 2026-10-16 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: ace-runtime
@@ -71,28 +71,56 @@ dependencies:
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0.68'
74
+ version: '0.70'
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '0.68'
81
+ version: '0.70'
82
+ - !ruby/object:Gem::Dependency
83
+ name: ace-herdr
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '0.6'
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '0.6'
82
96
  - !ruby/object:Gem::Dependency
83
97
  name: ace-hitl
84
98
  requirement: !ruby/object:Gem::Requirement
85
99
  requirements:
86
100
  - - "~>"
87
101
  - !ruby/object:Gem::Version
88
- version: '0.15'
102
+ version: '0.16'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '0.16'
110
+ - !ruby/object:Gem::Dependency
111
+ name: ace-git-forgejo
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '0.7'
89
117
  type: :runtime
90
118
  prerelease: false
91
119
  version_requirements: !ruby/object:Gem::Requirement
92
120
  requirements:
93
121
  - - "~>"
94
122
  - !ruby/object:Gem::Version
95
- version: '0.15'
123
+ version: '0.7'
96
124
  - !ruby/object:Gem::Dependency
97
125
  name: ace-support-test-helpers
98
126
  requirement: !ruby/object:Gem::Requirement
@@ -205,6 +233,7 @@ files:
205
233
  - lib/ace/lab/authorization_path.rb
206
234
  - lib/ace/lab/cli.rb
207
235
  - lib/ace/lab/cli/commands/agents.rb
236
+ - lib/ace/lab/cli/commands/assignment.rb
208
237
  - lib/ace/lab/cli/commands/projects.rb
209
238
  - lib/ace/lab/cli/commands/resolve.rb
210
239
  - lib/ace/lab/cli/commands/route.rb
@@ -219,10 +248,20 @@ files:
219
248
  - lib/ace/lab/molecules/caller_authorizer.rb
220
249
  - lib/ace/lab/molecules/capability_router.rb
221
250
  - lib/ace/lab/molecules/exact_resolver.rb
251
+ - lib/ace/lab/molecules/forge_merge_config.rb
252
+ - lib/ace/lab/molecules/forgejo_merge_adapter.rb
222
253
  - lib/ace/lab/molecules/grant_resolver.rb
223
254
  - lib/ace/lab/molecules/hitl_authorizer.rb
224
255
  - lib/ace/lab/molecules/inventory_query.rb
256
+ - lib/ace/lab/molecules/ordinary_admission_resolver.rb
257
+ - lib/ace/lab/molecules/ordinary_listener.rb
258
+ - lib/ace/lab/molecules/ordinary_merge_read.rb
259
+ - lib/ace/lab/molecules/ordinary_native_read.rb
260
+ - lib/ace/lab/molecules/ordinary_owner_admission.rb
261
+ - lib/ace/lab/molecules/ordinary_owner_config.rb
262
+ - lib/ace/lab/molecules/ordinary_receiver_config.rb
225
263
  - lib/ace/lab/molecules/ordinary_socket.rb
264
+ - lib/ace/lab/molecules/ordinary_worktree_read.rb
226
265
  - lib/ace/lab/molecules/protected_cleanup_owner_admission.rb
227
266
  - lib/ace/lab/molecules/protected_cleanup_owner_client.rb
228
267
  - lib/ace/lab/molecules/protected_cleanup_owner_identity.rb
@@ -233,6 +272,9 @@ files:
233
272
  - lib/ace/lab/molecules/service_policy.rb
234
273
  - lib/ace/lab/molecules/topology_loader.rb
235
274
  - lib/ace/lab/organisms/authority_composition.rb
275
+ - lib/ace/lab/organisms/ordinary_assignment_client.rb
276
+ - lib/ace/lab/organisms/ordinary_authority_composition.rb
277
+ - lib/ace/lab/organisms/ordinary_merge_receiver.rb
236
278
  - lib/ace/lab/organisms/ordinary_merge_request.rb
237
279
  - lib/ace/lab/organisms/protected_cleanup_owner.rb
238
280
  - lib/ace/lab/organisms/protected_service_client.rb