ace-lab 0.1.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 +7 -0
- data/.ace-defaults/lab/config.yml +41 -0
- data/CHANGELOG.md +22 -0
- data/LICENSE +21 -0
- data/README.md +110 -0
- data/Rakefile +12 -0
- data/docs/usage.md +178 -0
- data/exe/ace-lab +19 -0
- data/lib/ace/lab/atoms/binding_freshness.rb +33 -0
- data/lib/ace/lab/atoms/public_projection.rb +98 -0
- data/lib/ace/lab/atoms/topology_schema.rb +280 -0
- data/lib/ace/lab/cli/commands/agents.rb +43 -0
- data/lib/ace/lab/cli/commands/projects.rb +43 -0
- data/lib/ace/lab/cli/commands/resolve.rb +44 -0
- data/lib/ace/lab/cli/commands/route.rb +48 -0
- data/lib/ace/lab/cli/commands/services.rb +43 -0
- data/lib/ace/lab/cli/commands/support.rb +57 -0
- data/lib/ace/lab/cli.rb +71 -0
- data/lib/ace/lab/models/query_result.rb +55 -0
- data/lib/ace/lab/models/runtime_binding.rb +44 -0
- data/lib/ace/lab/models/topology_entry.rb +74 -0
- data/lib/ace/lab/molecules/caller_authorizer.rb +63 -0
- data/lib/ace/lab/molecules/capability_router.rb +69 -0
- data/lib/ace/lab/molecules/exact_resolver.rb +56 -0
- data/lib/ace/lab/molecules/grant_resolver.rb +180 -0
- data/lib/ace/lab/molecules/inventory_query.rb +78 -0
- data/lib/ace/lab/molecules/topology_loader.rb +49 -0
- data/lib/ace/lab/organisms/topology_service.rb +105 -0
- data/lib/ace/lab/version.rb +7 -0
- data/lib/ace/lab.rb +136 -0
- metadata +203 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ace
|
|
4
|
+
module Lab
|
|
5
|
+
module Organisms
|
|
6
|
+
# Public query facade for all ace-lab CLI commands (spec 8wq.t.1w4):
|
|
7
|
+
# loads and validates topology, derives the verified caller identity,
|
|
8
|
+
# and returns classified QueryResults. Read-only by contract — it never
|
|
9
|
+
# invokes a service, grants credentials, or creates any state.
|
|
10
|
+
class TopologyService
|
|
11
|
+
# Build a service from configuration (ADR-022 cascade when omitted).
|
|
12
|
+
# Normalization happens lazily inside the classified boundary so
|
|
13
|
+
# configuration defects surface as invalid_configuration results.
|
|
14
|
+
def self.from_config(config = nil)
|
|
15
|
+
new(config: config)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# @param config [Hash, nil] pre-supplied configuration to normalize
|
|
19
|
+
# @param loader [Molecules::TopologyLoader, nil] injected loader
|
|
20
|
+
# @param authorizer [Molecules::CallerAuthorizer, nil] injected authorizer
|
|
21
|
+
# @raise [ArgumentError] when only one of loader/authorizer is
|
|
22
|
+
# injected — partial injection would silently mix collaborators
|
|
23
|
+
# (subject review: honor independently injected collaborators)
|
|
24
|
+
def initialize(config: nil, loader: nil, authorizer: nil)
|
|
25
|
+
if loader.nil? != authorizer.nil?
|
|
26
|
+
raise ArgumentError, "loader and authorizer must be injected together or both omitted"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
@config = config
|
|
30
|
+
@loader = loader
|
|
31
|
+
@authorizer = authorizer
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def projects
|
|
35
|
+
query { |index, authorizer| Molecules::InventoryQuery.new(index: index, authorizer: authorizer).projects }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def agents(project:)
|
|
39
|
+
query do |index, authorizer|
|
|
40
|
+
Molecules::InventoryQuery.new(index: index, authorizer: authorizer).agents(project: project)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def services(project:)
|
|
45
|
+
query do |index, authorizer|
|
|
46
|
+
Molecules::InventoryQuery.new(index: index, authorizer: authorizer).services(project: project)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def resolve(id:)
|
|
51
|
+
query { |index, authorizer| Molecules::ExactResolver.new(index: index, authorizer: authorizer).resolve(id) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def route(project:, capability:)
|
|
55
|
+
query do |index, authorizer|
|
|
56
|
+
Molecules::CapabilityRouter.new(index: index, authorizer: authorizer)
|
|
57
|
+
.route(project: project, capability: capability)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
# Run a query against the validated index. Configuration loading,
|
|
64
|
+
# schema validation, and authorization derivation all happen inside
|
|
65
|
+
# this boundary so every defect classifies as invalid_configuration
|
|
66
|
+
# (review R4) and authorization always uses the normalized document
|
|
67
|
+
# the topology was validated against (review R3).
|
|
68
|
+
def query
|
|
69
|
+
index, authorizer = dependencies
|
|
70
|
+
yield index, authorizer
|
|
71
|
+
rescue Ace::Lab::InvalidConfigurationError => e
|
|
72
|
+
Models::QueryResult.failure("invalid_configuration", e.message)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Dependencies are derived fresh for EVERY query: nothing is
|
|
76
|
+
# memoized, so revoking deployment grants revokes access on the next
|
|
77
|
+
# query even for a reused service instance (review round 6, F1).
|
|
78
|
+
def dependencies
|
|
79
|
+
return [@loader.load, @authorizer] if @loader
|
|
80
|
+
|
|
81
|
+
config = @config || Ace::Lab.config
|
|
82
|
+
normalized = Atoms::TopologySchema.normalize!(config)
|
|
83
|
+
grants = if @config
|
|
84
|
+
# Explicitly injected configuration is a trusted in-process
|
|
85
|
+
# input (API use and fixtures)
|
|
86
|
+
normalized["authorization"]["principals"]
|
|
87
|
+
else
|
|
88
|
+
# Cascade path: grants come only from the trusted deployment-
|
|
89
|
+
# controlled document, re-read and re-verified per query; cascade
|
|
90
|
+
# tiers can never define or expand authorization (review round 4, F3)
|
|
91
|
+
Molecules::GrantResolver.resolve(
|
|
92
|
+
documents: Ace::Lab.cascade_documents,
|
|
93
|
+
topology: normalized["topology"],
|
|
94
|
+
trusted_path: Ace::Lab.authorization_path
|
|
95
|
+
)["principals"]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
loader = Molecules::TopologyLoader.new(normalized)
|
|
99
|
+
authorizer = Molecules::CallerAuthorizer.new(principals: grants)
|
|
100
|
+
[loader.load, authorizer]
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
data/lib/ace/lab.rb
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lab/version"
|
|
4
|
+
require "ace/support/config"
|
|
5
|
+
|
|
6
|
+
module Ace
|
|
7
|
+
module Lab
|
|
8
|
+
class Error < StandardError; end
|
|
9
|
+
|
|
10
|
+
# Raised when topology configuration violates the schema contract
|
|
11
|
+
class InvalidConfigurationError < Error; end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Load all ace-lab components
|
|
16
|
+
require_relative "lab/atoms/topology_schema"
|
|
17
|
+
require_relative "lab/atoms/binding_freshness"
|
|
18
|
+
require_relative "lab/atoms/public_projection"
|
|
19
|
+
require_relative "lab/models/runtime_binding"
|
|
20
|
+
require_relative "lab/models/topology_entry"
|
|
21
|
+
require_relative "lab/models/query_result"
|
|
22
|
+
require_relative "lab/molecules/topology_loader"
|
|
23
|
+
require_relative "lab/molecules/caller_authorizer"
|
|
24
|
+
require_relative "lab/molecules/grant_resolver"
|
|
25
|
+
require_relative "lab/molecules/inventory_query"
|
|
26
|
+
require_relative "lab/molecules/exact_resolver"
|
|
27
|
+
require_relative "lab/molecules/capability_router"
|
|
28
|
+
require_relative "lab/organisms/topology_service"
|
|
29
|
+
require_relative "lab/cli"
|
|
30
|
+
|
|
31
|
+
module Ace
|
|
32
|
+
module Lab
|
|
33
|
+
# Returns the gem root directory
|
|
34
|
+
# @return [String] Path to the gem root directory
|
|
35
|
+
def self.gem_root
|
|
36
|
+
@gem_root ||= Gem.loaded_specs["ace-lab"]&.gem_dir ||
|
|
37
|
+
File.expand_path("../..", __dir__)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Check if debug mode is enabled
|
|
41
|
+
# @return [Boolean]
|
|
42
|
+
def self.debug?
|
|
43
|
+
ENV["ACE_DEBUG"] == "1" || ENV["DEBUG"] == "1"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Load ace-lab configuration using the ADR-022 cascade.
|
|
47
|
+
# Deployed topology lives in .ace/lab/config.yml (project) or
|
|
48
|
+
# ~/.ace/lab/config.yml (user); gem defaults are an empty, safe topology.
|
|
49
|
+
# Deliberately NOT memoized: binding facts (attestations) change on disk,
|
|
50
|
+
# and a long-lived consumer must never keep serving replaced bindings
|
|
51
|
+
# from a cached document (review round 7, F1). Cascade reads are small.
|
|
52
|
+
# @return [Hash] Merged configuration hash with defaults
|
|
53
|
+
def self.config
|
|
54
|
+
load_config
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Same discovery the cascade resolver performs for this namespace
|
|
58
|
+
LAB_FILE_PATTERNS = ["lab/config.yml", "lab/config.yaml"].freeze
|
|
59
|
+
|
|
60
|
+
# Authorization grants live in a single deployment-controlled file at a
|
|
61
|
+
# FIXED path — never in the caller-writable configuration cascade and
|
|
62
|
+
# never at a caller-selected location (review rounds 4-5, F3/F1). The
|
|
63
|
+
# file must be root-owned and not group/world-writable, including every
|
|
64
|
+
# directory on its real path; GrantResolver verifies and fails closed.
|
|
65
|
+
AUTHORIZATION_PATH = "/etc/lab/ace-lab/authorization.yml"
|
|
66
|
+
|
|
67
|
+
# Path of the trusted authorization grants document. A method (not a
|
|
68
|
+
# bare constant reference) so tests can stub the seam without any
|
|
69
|
+
# caller-controllable production override.
|
|
70
|
+
# @return [String]
|
|
71
|
+
def self.authorization_path
|
|
72
|
+
AUTHORIZATION_PATH
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Load configuration using Ace::Support::Config cascade.
|
|
76
|
+
# Load failures raise InvalidConfigurationError (classified by the query
|
|
77
|
+
# boundary) — silently falling back to empty defaults would misreport
|
|
78
|
+
# broken deployed configuration as an authorization denial (review R4).
|
|
79
|
+
# @return [Hash] Merged configuration
|
|
80
|
+
# @raise [Ace::Lab::InvalidConfigurationError]
|
|
81
|
+
def self.load_config
|
|
82
|
+
cascade_documents
|
|
83
|
+
|
|
84
|
+
resolver = Ace::Support::Config.create(
|
|
85
|
+
config_dir: ".ace",
|
|
86
|
+
defaults_dir: ".ace-defaults",
|
|
87
|
+
gem_path: gem_root
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
resolver.resolve_namespace("lab").data
|
|
91
|
+
rescue Ace::Lab::InvalidConfigurationError
|
|
92
|
+
raise
|
|
93
|
+
rescue => e
|
|
94
|
+
# Fixed diagnostic only: the underlying exception message may quote
|
|
95
|
+
# configuration content, which must never surface pre-authorization
|
|
96
|
+
# (review round 3, F2)
|
|
97
|
+
raise InvalidConfigurationError, "invalid lab configuration: could not load deployed configuration (#{e.class})"
|
|
98
|
+
end
|
|
99
|
+
private_class_method :load_config
|
|
100
|
+
|
|
101
|
+
# The individual cascade documents for this namespace, same discovery the
|
|
102
|
+
# resolver performs, each validated before use. Cascade merging treats a
|
|
103
|
+
# non-mapping document as an empty overlay, so a malformed root (e.g. a
|
|
104
|
+
# YAML array) would be silently ignored (review round 3, F1). Messages
|
|
105
|
+
# carry the file path — never parsed content.
|
|
106
|
+
#
|
|
107
|
+
# Exposed because authorization grants need per-tier documents: a
|
|
108
|
+
# caller-writable tier must never be able to EXPAND grants (review
|
|
109
|
+
# round 4, F3), which the merged view cannot express.
|
|
110
|
+
#
|
|
111
|
+
# @return [Array<Hash>] {path:, document:, defaults:}
|
|
112
|
+
def self.cascade_documents
|
|
113
|
+
finder = Ace::Support::Config::Molecules::ConfigFinder.new(
|
|
114
|
+
config_dir: ".ace",
|
|
115
|
+
defaults_dir: ".ace-defaults",
|
|
116
|
+
gem_path: gem_root,
|
|
117
|
+
file_patterns: LAB_FILE_PATTERNS
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
finder.find_all.select(&:exists).map do |cascade_path|
|
|
121
|
+
path = cascade_path.path
|
|
122
|
+
document = begin
|
|
123
|
+
require "yaml"
|
|
124
|
+
YAML.safe_load_file(path, permitted_classes: [Date], aliases: true)
|
|
125
|
+
rescue
|
|
126
|
+
raise InvalidConfigurationError, "invalid lab configuration: #{path} could not be parsed as YAML"
|
|
127
|
+
end
|
|
128
|
+
unless document.nil? || document.is_a?(Hash)
|
|
129
|
+
raise InvalidConfigurationError, "invalid lab configuration: #{path} must contain a YAML mapping"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
{path: path, document: document || {}, defaults: path.start_with?(gem_root)}
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ace-lab
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Michal Czyz
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-09-29 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: ace-support-cli
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.6'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.6'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: ace-support-core
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0.31'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0.31'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: ace-support-config
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0.18'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0.18'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: ace-support-test-helpers
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - "~>"
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0.14'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0.14'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: bundler
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '2.0'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '2.0'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: minitest
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '5.0'
|
|
89
|
+
type: :development
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - "~>"
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '5.0'
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: rake
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '13.0'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '13.0'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: rubocop
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '1.88'
|
|
117
|
+
type: :development
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '1.88'
|
|
124
|
+
- !ruby/object:Gem::Dependency
|
|
125
|
+
name: simplecov
|
|
126
|
+
requirement: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - "~>"
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '0.22'
|
|
131
|
+
type: :development
|
|
132
|
+
prerelease: false
|
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - "~>"
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '0.22'
|
|
138
|
+
description: Read-only topology registry and capability router. Resolves stable project,
|
|
139
|
+
agent, and service IDs from ADR-022 configuration without invoking Lab, reading
|
|
140
|
+
credentials, tracking work, or guessing transient pane/session identifiers.
|
|
141
|
+
email:
|
|
142
|
+
- mc@cs3b.com
|
|
143
|
+
executables:
|
|
144
|
+
- ace-lab
|
|
145
|
+
extensions: []
|
|
146
|
+
extra_rdoc_files: []
|
|
147
|
+
files:
|
|
148
|
+
- ".ace-defaults/lab/config.yml"
|
|
149
|
+
- CHANGELOG.md
|
|
150
|
+
- LICENSE
|
|
151
|
+
- README.md
|
|
152
|
+
- Rakefile
|
|
153
|
+
- docs/usage.md
|
|
154
|
+
- exe/ace-lab
|
|
155
|
+
- lib/ace/lab.rb
|
|
156
|
+
- lib/ace/lab/atoms/binding_freshness.rb
|
|
157
|
+
- lib/ace/lab/atoms/public_projection.rb
|
|
158
|
+
- lib/ace/lab/atoms/topology_schema.rb
|
|
159
|
+
- lib/ace/lab/cli.rb
|
|
160
|
+
- lib/ace/lab/cli/commands/agents.rb
|
|
161
|
+
- lib/ace/lab/cli/commands/projects.rb
|
|
162
|
+
- lib/ace/lab/cli/commands/resolve.rb
|
|
163
|
+
- lib/ace/lab/cli/commands/route.rb
|
|
164
|
+
- lib/ace/lab/cli/commands/services.rb
|
|
165
|
+
- lib/ace/lab/cli/commands/support.rb
|
|
166
|
+
- lib/ace/lab/models/query_result.rb
|
|
167
|
+
- lib/ace/lab/models/runtime_binding.rb
|
|
168
|
+
- lib/ace/lab/models/topology_entry.rb
|
|
169
|
+
- lib/ace/lab/molecules/caller_authorizer.rb
|
|
170
|
+
- lib/ace/lab/molecules/capability_router.rb
|
|
171
|
+
- lib/ace/lab/molecules/exact_resolver.rb
|
|
172
|
+
- lib/ace/lab/molecules/grant_resolver.rb
|
|
173
|
+
- lib/ace/lab/molecules/inventory_query.rb
|
|
174
|
+
- lib/ace/lab/molecules/topology_loader.rb
|
|
175
|
+
- lib/ace/lab/organisms/topology_service.rb
|
|
176
|
+
- lib/ace/lab/version.rb
|
|
177
|
+
homepage: https://github.com/cs3b/ace
|
|
178
|
+
licenses:
|
|
179
|
+
- MIT
|
|
180
|
+
metadata:
|
|
181
|
+
allowed_push_host: https://rubygems.org
|
|
182
|
+
homepage_uri: https://github.com/cs3b/ace
|
|
183
|
+
source_code_uri: https://github.com/cs3b/ace/tree/main/ace-lab/
|
|
184
|
+
changelog_uri: https://github.com/cs3b/ace/blob/main/ace-lab/CHANGELOG.md
|
|
185
|
+
rdoc_options: []
|
|
186
|
+
require_paths:
|
|
187
|
+
- lib
|
|
188
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
189
|
+
requirements:
|
|
190
|
+
- - ">="
|
|
191
|
+
- !ruby/object:Gem::Version
|
|
192
|
+
version: 3.2.0
|
|
193
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
194
|
+
requirements:
|
|
195
|
+
- - ">="
|
|
196
|
+
- !ruby/object:Gem::Version
|
|
197
|
+
version: '0'
|
|
198
|
+
requirements: []
|
|
199
|
+
rubygems_version: 3.6.9
|
|
200
|
+
specification_version: 4
|
|
201
|
+
summary: 'Topology and routing CLI for the Lab: address projects, agents, and services
|
|
202
|
+
by stable IDs'
|
|
203
|
+
test_files: []
|