ace-lab 0.9.0 → 0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +363 -104
- data/README.md +66 -100
- data/docs/usage.md +529 -592
- data/lib/ace/lab/atoms/install_schema.rb +373 -0
- data/lib/ace/lab/cli/commands/install.rb +161 -0
- data/lib/ace/lab/cli/commands/prepare.rb +118 -0
- data/lib/ace/lab/cli/commands/project_add.rb +101 -0
- data/lib/ace/lab/cli/commands/status.rb +109 -0
- data/lib/ace/lab/cli/commands/verify.rb +115 -0
- data/lib/ace/lab/cli.rb +21 -23
- data/lib/ace/lab/install_manifest_path.rb +23 -0
- data/lib/ace/lab/models/status_report.rb +38 -0
- data/lib/ace/lab/molecules/account_provisioner.rb +196 -0
- data/lib/ace/lab/molecules/config_state_classifier.rb +145 -0
- data/lib/ace/lab/molecules/directory_provisioner.rb +208 -0
- data/lib/ace/lab/molecules/grant_provisioner.rb +250 -0
- data/lib/ace/lab/molecules/grant_resolver.rb +34 -23
- data/lib/ace/lab/molecules/hitl_routes.rb +263 -0
- data/lib/ace/lab/molecules/install_manifest_loader.rb +64 -0
- data/lib/ace/lab/molecules/key_provisioner.rb +736 -0
- data/lib/ace/lab/molecules/lab_state_scanner.rb +55 -0
- data/lib/ace/lab/molecules/overseer_provisioner.rb +188 -0
- data/lib/ace/lab/molecules/project_registry.rb +251 -0
- data/lib/ace/lab/molecules/repository_provisioner.rb +141 -0
- data/lib/ace/lab/molecules/role_verifier.rb +223 -0
- data/lib/ace/lab/organisms/install.rb +213 -0
- data/lib/ace/lab/organisms/prepare.rb +156 -0
- data/lib/ace/lab/organisms/project_add.rb +170 -0
- data/lib/ace/lab/organisms/status_service.rb +70 -0
- data/lib/ace/lab/organisms/verify.rb +768 -0
- data/lib/ace/lab/version.rb +1 -1
- data/lib/ace/lab.rb +34 -6
- metadata +34 -108
- data/lib/ace/lab/atoms/protected_publication_input.rb +0 -50
- data/lib/ace/lab/atoms/protected_workspace_prune_input.rb +0 -114
- data/lib/ace/lab/atoms/protected_workspace_prune_preview.rb +0 -86
- data/lib/ace/lab/atoms/service_input.rb +0 -92
- data/lib/ace/lab/cli/commands/assignment.rb +0 -92
- data/lib/ace/lab/cli/commands/command_execute.rb +0 -28
- data/lib/ace/lab/cli/commands/run.rb +0 -65
- data/lib/ace/lab/cli/commands/service.rb +0 -240
- data/lib/ace/lab/models/service_receipt.rb +0 -18
- data/lib/ace/lab/molecules/command_owner_admission.rb +0 -183
- data/lib/ace/lab/molecules/command_policy.rb +0 -158
- data/lib/ace/lab/molecules/hitl_authorizer.rb +0 -63
- data/lib/ace/lab/molecules/ordinary_admission_resolver.rb +0 -131
- data/lib/ace/lab/molecules/ordinary_listener.rb +0 -262
- data/lib/ace/lab/molecules/ordinary_merge_read.rb +0 -45
- data/lib/ace/lab/molecules/ordinary_native_read.rb +0 -106
- data/lib/ace/lab/molecules/ordinary_owner_admission.rb +0 -152
- data/lib/ace/lab/molecules/ordinary_owner_config.rb +0 -232
- data/lib/ace/lab/molecules/ordinary_receiver_config.rb +0 -94
- data/lib/ace/lab/molecules/ordinary_socket.rb +0 -126
- data/lib/ace/lab/molecules/ordinary_worktree_read.rb +0 -216
- data/lib/ace/lab/molecules/protected_cleanup_owner_admission.rb +0 -163
- data/lib/ace/lab/molecules/protected_cleanup_owner_client.rb +0 -165
- data/lib/ace/lab/molecules/protected_cleanup_owner_identity.rb +0 -239
- data/lib/ace/lab/molecules/protected_publication_publisher.rb +0 -110
- data/lib/ace/lab/molecules/protected_service_handler.rb +0 -43
- data/lib/ace/lab/molecules/protected_service_policy.rb +0 -156
- data/lib/ace/lab/molecules/service_executor.rb +0 -99
- data/lib/ace/lab/molecules/service_policy.rb +0 -289
- data/lib/ace/lab/organisms/authority_composition.rb +0 -87
- data/lib/ace/lab/organisms/command_executor.rb +0 -220
- data/lib/ace/lab/organisms/command_run_client.rb +0 -131
- data/lib/ace/lab/organisms/ordinary_assignment_client.rb +0 -120
- data/lib/ace/lab/organisms/ordinary_authority_composition.rb +0 -153
- data/lib/ace/lab/organisms/ordinary_merge_receiver.rb +0 -679
- data/lib/ace/lab/organisms/ordinary_merge_request.rb +0 -456
- data/lib/ace/lab/organisms/protected_cleanup_owner.rb +0 -361
- data/lib/ace/lab/organisms/protected_service_client.rb +0 -129
- data/lib/ace/lab/organisms/protected_service_listener.rb +0 -181
- data/lib/ace/lab/organisms/protected_service_publication.rb +0 -268
- data/lib/ace/lab/organisms/protected_service_receiver.rb +0 -267
- data/lib/ace/lab/organisms/protected_service_recovery.rb +0 -185
- data/lib/ace/lab/organisms/protected_service_request.rb +0 -128
- data/lib/ace/lab/organisms/protected_service_worker.rb +0 -89
- data/lib/ace/lab/organisms/service_request_service.rb +0 -249
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ff20c0d594202a649d5597257411b611d6faf6b66128fd8ff4ad0702989b6e16
|
|
4
|
+
data.tar.gz: 1d6575916e526eec678ee39c9be5025f53653fcdfac27c8075692c936d3351bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 32b6ee73258e1534a9ff91f2bc83d30ff4265b124aefcee056652dd0544ef770aba4036e055e282fc35ea1c2a993cfefa67f46480e82ecf4f294fbda5561deeb
|
|
7
|
+
data.tar.gz: 786a3ca1af5fad657f722d3ea2c0ba525988c5461ed18a94023650e17f5b7870c15a754d71560ee442e78bd6527a42823d25dc297911666156bf57287072e9c7
|
data/CHANGELOG.md
CHANGED
|
@@ -7,118 +7,377 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
-
## [0.9.0] - 2026-10-16
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- Wire ordinary artifact retention to fresh installed project visibility and the existing exact service or canonical proposal decision; retention does not select an executor or consume publication authorization.
|
|
15
|
-
- Expose ordinary candidate upload, assigned review export/acceptance and canonical merge evidence through retained assignment requests. Compose their proof owner with the existing merge receiver and command executor journal.
|
|
16
|
-
- Expose ordinary driver status, bootstrap, progress, result and exact recovery commands using the selected Assign owner; authenticate coordinator replacement with bounded process-generation observation.
|
|
17
|
-
|
|
18
|
-
### Changed
|
|
19
|
-
|
|
20
|
-
- Require an explicit `purpose: command` or `purpose: test` on every installed command-policy entry. Only test commands with exact candidate head/tree and canonical successful execution can authorize merge evidence; previous entries without purpose are refused.
|
|
21
|
-
|
|
22
|
-
## [0.8.0] - 2026-10-16
|
|
23
|
-
|
|
24
|
-
### Added
|
|
25
|
-
|
|
26
|
-
- Compose ordinary Assign, HITL and Forgejo merge under one installed owner and journal, with readiness barriers and fresh native/project admission.
|
|
27
|
-
- Optionally serve existing mTLS HITL beside the ordinary Unix listener under the same canonical owner, journal, proposal policy and one-use OTP vault. Validate the configured project and service identity before either listener starts.
|
|
28
|
-
- Add retained assignment prepare/request clients and bounded canonical worktree observations. Separate stable configuration identity from changing decisions, preserve no-effect settlement after slow provider calls, and clean delivery handler process groups.
|
|
29
|
-
- This source cut enables initial installation; it does not claim autonomous release or installed two-project acceptance.
|
|
30
|
-
|
|
31
|
-
## [0.7.0] - 2026-10-16
|
|
11
|
+
## [0.13.0] - 2026-10-20
|
|
32
12
|
|
|
33
13
|
### Added
|
|
34
14
|
|
|
35
|
-
-
|
|
36
|
-
|
|
15
|
+
- `ace-lab verify` (L8.5, task 8xg.t.sbz.7.4): read-only end-of-install
|
|
16
|
+
readiness verification UNDER THE TARGET ACCOUNTS. For every account,
|
|
17
|
+
directory, key pair, role, project and grant declared in the trusted
|
|
18
|
+
install manifest it recomputes the facts from the same artifacts
|
|
19
|
+
install/resume derive truth from — no journal, no second state
|
|
20
|
+
owner, nothing written. Checks: account existence/login class
|
|
21
|
+
(non-login shells block readiness), declared directory mode/owner,
|
|
22
|
+
key pair usability (0600/0644/`.ssh` 0700 modes, account ownership,
|
|
23
|
+
and the public fingerprint matching the key derived from the private
|
|
24
|
+
half — the exact probe `prepare` applies, now exposed as a public
|
|
25
|
+
read-only `KeyProvisioner#pair_fingerprint`), role instruction
|
|
26
|
+
readability by the role's account (the `prepare` role verifier),
|
|
27
|
+
repository structure with origin matching the manifest remote
|
|
28
|
+
(local origins probed with `git ls-remote`; network origins reported
|
|
29
|
+
`unknown`, not dialed by the read-only verifier), principal grants
|
|
30
|
+
resolved through the real read-side mechanics (`CallerAuthorizer`)
|
|
31
|
+
against the trusted document, per-project registry visibility, and
|
|
32
|
+
the private `.ace-tasks/_overseer/` folder being present and
|
|
33
|
+
Git-ignored (`git check-ignore`). Every check reports pass/fail/
|
|
34
|
+
unknown with a concrete reason; a failure never hides healthy data
|
|
35
|
+
(the full report renders first) and blocks the `ready` verdict; the
|
|
36
|
+
command exits non-zero naming every failed check. Output: table or
|
|
37
|
+
stable JSON (`ready`/`checks`/`counts`) for the overseer or the next
|
|
38
|
+
tool. A fresh install and a resumed one verify identically.
|
|
39
|
+
|
|
40
|
+
- Resuming the installer's own interrupted installation (L8.4, task
|
|
41
|
+
8xg.t.sbz.7.3): re-running `ace-lab install` after a mid-run crash
|
|
42
|
+
recognizes the partial state — derived from the real artifacts the
|
|
43
|
+
steps read and write, with no journal or marker file — and finishes
|
|
44
|
+
it. Steps that already completed report `exists`/`verified` without
|
|
45
|
+
destructive rework (converged directories and key pairs keep their
|
|
46
|
+
inode; a converged trusted document stays byte-identical), missing
|
|
47
|
+
steps complete (a half-written key pair regenerates only the public
|
|
48
|
+
half; partially granted own principals converge while foreign
|
|
49
|
+
sections of the document are kept), and grants are still configured
|
|
50
|
+
only over a converged install. Foreign content is refused at every
|
|
51
|
+
step: a project directory with foreign content, a repository with a
|
|
52
|
+
foreign origin, a foreign declared directory (e.g. a symlink) and a
|
|
53
|
+
trusted document granting undeclared projects each fail their step
|
|
54
|
+
with a classified, concrete message before any takeover or cleanup,
|
|
55
|
+
wet and in `--dry-run` alike (prediction parity on partial states).
|
|
56
|
+
|
|
57
|
+
- `ace-lab install` (L8.3, task 8xg.t.sbz.7.2): the full new-lab
|
|
58
|
+
installation from the trusted install manifest, composing the
|
|
59
|
+
existing molecules in a fixed order — `Prepare` (L8.1: accounts,
|
|
60
|
+
directories, keys, roles), `ProjectAdd` (L8.2) per manifest-declared
|
|
61
|
+
project, and the new `GrantProvisioner` that writes the trusted-tier
|
|
62
|
+
principal grants into `/etc/lab/ace-lab/authorization.yml` so the
|
|
63
|
+
installed projects are visible to `ace-lab projects` and
|
|
64
|
+
`ace-overseer projects` with no read-side change. The manifest schema
|
|
65
|
+
(still v1) gains optional `projects` (id/path/remote/label; unique
|
|
66
|
+
ids and paths) and `grants` (principal → declared project ids)
|
|
67
|
+
sections. A foreign lab is refused before any mutation: an existing
|
|
68
|
+
trusted document granting projects the manifest does not declare
|
|
69
|
+
aborts with a classified error and zero writes, and a manifest that
|
|
70
|
+
would remove an existing grant is refused (grants only grow);
|
|
71
|
+
undeclared principals and every other document section are preserved.
|
|
72
|
+
A converged wet re-run writes nothing at all — the trusted document
|
|
73
|
+
(admin-authored comments included) stays byte-identical; a manifest
|
|
74
|
+
with no `grants` over an absent document is a no-op (`skipped`,
|
|
75
|
+
nothing created). The existing document's principals are validated
|
|
76
|
+
exactly like the read side before any write (shared validation with
|
|
77
|
+
`GrantResolver`; malformed policies are refused with a classified
|
|
78
|
+
error instead of silently rewritten, whitespace-padded principal
|
|
79
|
+
names are normalized, and duplicate-after-strip principals are
|
|
80
|
+
rejected by the manifest schema).
|
|
81
|
+
Idempotent re-runs converge (`exists` statuses); `--dry-run`
|
|
82
|
+
faithfully predicts every phase (`would_*`) with exit 0, wet failures
|
|
83
|
+
render the report then exit non-zero naming each failed step.
|
|
84
|
+
|
|
85
|
+
- `ace-lab project add` (L8.2, task 8xg.t.sbz.7.1): registers a project
|
|
86
|
+
and makes it ready for team work. A `ProjectAdd` organism runs three
|
|
87
|
+
idempotent steps in a fixed order — `RepositoryProvisioner` (clone the
|
|
88
|
+
declared origin into the target path, or verify/converge an existing
|
|
89
|
+
repository's origin; refuse a different origin or a foreign
|
|
90
|
+
non-repository location), `OverseerProvisioner` (prepare the private
|
|
91
|
+
gitignored `.ace-tasks/_overseer/` folder plus its `.gitignore` entry,
|
|
92
|
+
never touching existing content), and `ProjectRegistry` (register the
|
|
93
|
+
project's id/label/path/remote in the project-tier
|
|
94
|
+
`.ace/lab/config.yml` cascade document, refusing contradictory
|
|
95
|
+
registrations, path conflicts, unparseable or foreign documents before
|
|
96
|
+
any write). Consumers need no change: `ace-lab status` classifies the
|
|
97
|
+
project as configured through the ordinary cascade and
|
|
98
|
+
`ace-lab projects` / `ace-overseer projects` list it through the
|
|
99
|
+
existing topology surface. `--dry-run` predicts with zero mutations;
|
|
100
|
+
wet failures print the report and exit non-zero naming each step.
|
|
101
|
+
|
|
102
|
+
- Adapter and tool declarations in the install manifest (tasks
|
|
103
|
+
8xg.t.sbz.7.2/.7.4, LAB-3): the schema (v1) now accepts an
|
|
104
|
+
`adapters` list (`id`, `kind` `communication`/`hitl`, optional local
|
|
105
|
+
`command`, optional `config` mapping) and a `tools` list of required
|
|
106
|
+
executable names. `ace-lab install` validates and normalizes the
|
|
107
|
+
declarations (the trusted manifest stays their single state owner —
|
|
108
|
+
no second configuration file), echoes them in its report under
|
|
109
|
+
`adapters`/`tools`, and finishes with a NEW final `verify` stage over
|
|
110
|
+
the converged lab whose readiness gates the install's `ok` (dry runs
|
|
111
|
+
skip the stage — nothing has converged to verify). `ace-lab verify`
|
|
112
|
+
gained matching checks: every required tool must resolve to an
|
|
113
|
+
executable on PATH (presence only — no execution, no network), and
|
|
114
|
+
every declared adapter must have a valid configuration with its
|
|
115
|
+
command, when declared, resolvable; a missing tool or broken adapter
|
|
116
|
+
is a classified check failure that blocks readiness, never a crash.
|
|
117
|
+
Network reachability of communication adapters stays out of scope
|
|
118
|
+
(L9). The install CLI renders the verify verdict and names every
|
|
119
|
+
failed check in its non-zero-exit summary.
|
|
120
|
+
|
|
121
|
+
- Target-executor ownership propagation for installed projects (task
|
|
122
|
+
8xg.t.sbz.7.4, LAB-2): `ProjectAdd` accepts an `owner` account and,
|
|
123
|
+
when the installer runs as root, chowns a converged project tree to
|
|
124
|
+
the declared executor (derived by install from the owning declared
|
|
125
|
+
directory above the project) so root installs yield
|
|
126
|
+
executor-writable repositories; non-root installers report the step
|
|
127
|
+
skipped and `verify` judges the executor's actual access on the real
|
|
128
|
+
permission bits. The report carries the new `owner` step.
|
|
37
129
|
|
|
38
130
|
### Changed
|
|
39
131
|
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
- Add the ordinary fixed merge producer mode (`ace-lab service request/status --mode ordinary-merge`) per xz9.4: durable-once admission that issues the opaque reference only through the committed journal record, canonical SHA-256 request digests over the full eight-field binding, identical-replay acknowledgment, authorization/binding conflict refusals, read-only status, and terminal receipts bound to the admitted record and its execution identity.
|
|
49
|
-
|
|
50
|
-
## [0.5.2] - 2026-10-11
|
|
51
|
-
|
|
52
|
-
### Changed
|
|
53
|
-
|
|
54
|
-
- Follow the `ace-hitl` 0.14 lifecycle boundary line with dedicated per-authority socket-group configuration.
|
|
55
|
-
|
|
56
|
-
## [0.5.1] - 2026-10-10
|
|
132
|
+
- `ace-lab status` refined to the reviewed `l7-statuses` implementation
|
|
133
|
+
(task 8xg.t.sbz.6.0; extracted from the superseded PR #382): tri-state
|
|
134
|
+
classification moved into a `ConfigStateClassifier` molecule with the
|
|
135
|
+
corrected config cascade precedence and missing-state classification,
|
|
136
|
+
ADR-034 state-owner scanning isolated into a `LabStateScanner`
|
|
137
|
+
(per-location error isolation), and a `StatusReport` model behind a
|
|
138
|
+
`StatusService` organism — table/json/`-q` output preserved.
|
|
57
139
|
|
|
58
140
|
### Fixed
|
|
59
141
|
|
|
60
|
-
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
142
|
+
- Review 8xirj8: a failed payload write inside `HitlRoutes`' exclusive
|
|
143
|
+
temp-file helper no longer leaks the temp file (close + delete +
|
|
144
|
+
re-raise); the shallow per-key merge semantics are documented.
|
|
145
|
+
|
|
146
|
+
- Review 8xir47 (findings 1, 3, 4): a decidable HITL route failure is
|
|
147
|
+
no longer masked as UNKNOWN when PATH is unset (route failures take
|
|
148
|
+
precedence over the PATH-unset probe message and always FAIL
|
|
149
|
+
readiness); the ownership-skip message names the actually failing
|
|
150
|
+
step instead of always blaming the repository step; the
|
|
151
|
+
prepare-dependency project report carries the `hitl` key like every
|
|
152
|
+
other ProjectAdd report variant.
|
|
153
|
+
|
|
154
|
+
- Review 8xir47 (findings 5-6) in `HitlRoutes`: the runtime route
|
|
155
|
+
configuration (`.ace/hitl/config.yml`) is now written ATOMICALLY
|
|
156
|
+
(exclusive temp file + rename, the ProjectRegistry discipline) — a
|
|
157
|
+
crash mid-write can no longer truncate the operator-facing config.
|
|
158
|
+
Convergence is now by route NAME everywhere: on re-install the
|
|
159
|
+
manifest-declared keys are merged into the existing same-name route
|
|
160
|
+
(manifest keys win, operator extra keys such as `pane: p5` survive
|
|
161
|
+
instead of being silently replaced), operator-added routes are kept,
|
|
162
|
+
and `verify` accepts a same-name route carrying every
|
|
163
|
+
manifest-declared key/value even when the operator extended it with
|
|
164
|
+
extra keys — an extended route no longer fails verification until
|
|
165
|
+
re-install. An unchanged route list is never rewritten (comments
|
|
166
|
+
survive idempotent no-op installs); a converging write is a YAML
|
|
167
|
+
round-trip and drops comments, as documented in the class docstring.
|
|
168
|
+
|
|
169
|
+
- PR #393 final audit (FINAL-LAB1): `ProjectAdd` now resolves declared
|
|
170
|
+
project owners through the REAL system passwd lookup by default (the
|
|
171
|
+
same `Etc.getpwnam` seam `RoleVerifier`/`Verify` use). The previous
|
|
172
|
+
`account_lookup: nil` default made every declared owner
|
|
173
|
+
"nonexistent" in production installs — only tests injected a lookup,
|
|
174
|
+
masking the bug. A root installer also no longer skips ownership
|
|
175
|
+
propagation when the project root already carries the target uid: a
|
|
176
|
+
root uid match proves nothing about generated children (`.ace/lab/
|
|
177
|
+
config.yml`, `.ace/hitl/config.yml` may still be root-owned), so the
|
|
178
|
+
whole tree is always converged. A declared directory matching a
|
|
179
|
+
project path exactly (not only as a prefix) now selects that
|
|
180
|
+
project's owner too.
|
|
181
|
+
|
|
182
|
+
- PR #393 final audit (FINAL-LAB2): `kind: hitl` adapter declarations
|
|
183
|
+
are now projected into the runtime HITL configuration contract —
|
|
184
|
+
`hitl.adapters.routes` in every declared project's
|
|
185
|
+
`.ace/hitl/config.yml`, the exact cascade location the ace-hitl
|
|
186
|
+
route loader reads (an empty adapter configuration used to yield
|
|
187
|
+
`ok:true`/`ready:true` while the runtime failed with NoRoutesError).
|
|
188
|
+
The new `HitlRoutes` molecule installs the routes idempotently
|
|
189
|
+
(operator-owned routes and settings are preserved; unparseable
|
|
190
|
+
documents are refused, not overwritten), and `ace-lab verify`
|
|
191
|
+
re-derives the expected route per adapter and validates the
|
|
192
|
+
resulting configuration against the runtime loader's rules
|
|
193
|
+
(non-empty mapping list, required `adapter`, single-segment route
|
|
194
|
+
names, no duplicates) in every declared project — a missing or
|
|
195
|
+
invalid route configuration blocks readiness. The committed suite
|
|
196
|
+
cross-checks the written document against the real
|
|
197
|
+
`Ace::Hitl::Molecules::HitlRouteLoader` so the mirrored validation
|
|
198
|
+
cannot drift.
|
|
199
|
+
|
|
200
|
+
- PR #393 final audit (FINAL-LAB3): required tools and adapter
|
|
201
|
+
commands are now probed FOR THE TARGET EXECUTORS, not the installing
|
|
202
|
+
account — an installer-owned mode-0700 executable fails readiness
|
|
203
|
+
when the declared executor (different uid) cannot run it. The new
|
|
204
|
+
`RoleVerifier#executable_access_reason` applies the same
|
|
205
|
+
governing-class permission logic (owner/group/other short-circuit,
|
|
206
|
+
supplementary groups, ancestor search) as the repository access
|
|
207
|
+
checks, and the project-directory access mask now requires
|
|
208
|
+
read+write+search (a directory without x on itself is unusable to
|
|
209
|
+
the executor however rw it is). Tool/adapter availability that is
|
|
210
|
+
undecidable (unset PATH) still reports `unknown`; as with every
|
|
211
|
+
other unknown it does not block readiness by itself and never counts
|
|
212
|
+
as a verified pass.
|
|
213
|
+
|
|
214
|
+
- Review fix: `check_adapters` status precedence — a malformed adapter
|
|
215
|
+
configuration (not a mapping) stays a decidable FAIL even when PATH
|
|
216
|
+
is unset (only the command probe may degrade to unknown); the dead
|
|
217
|
+
`tool_reason` helper introduced with the tri-state probe is removed;
|
|
218
|
+
and two review-round acceptance scenarios (gitignore-symlink
|
|
219
|
+
read-through refusal, verify-stage crash classification) were
|
|
220
|
+
accidentally defined outside their minitest classes and never
|
|
221
|
+
executed — they now run (and pass) in the package suite.
|
|
222
|
+
|
|
223
|
+
- Critical review fix: `ProjectAdd`'s privileged ownership propagation
|
|
224
|
+
called `FileUtils.chown_R` with the wrong argument order (path
|
|
225
|
+
passed as the user, the gid Integer as the file list), so every
|
|
226
|
+
root install with a declared owner failed the `owner` step with a
|
|
227
|
+
misleading error. The chown is now invoked as
|
|
228
|
+
`chown_R(uid, gid, path)`, rescued for TypeError as well, and is an
|
|
229
|
+
injectable seam so the root branch is testable without uid 0.
|
|
230
|
+
- Review fix: an unset or empty `PATH` no longer produces false FAILs
|
|
231
|
+
for the tools/adapters checks — the probe is tri-state and yields
|
|
232
|
+
`unknown` ("PATH is unset; cannot probe …") instead of blocking
|
|
233
|
+
readiness in minimal-PATH environments.
|
|
234
|
+
- Review fix (trust posture): a privileged (root) installer never
|
|
235
|
+
executes the repository-controlled `bin/ace-nav` binstub during
|
|
236
|
+
final verification — under root only the PATH-installed resolver is
|
|
237
|
+
used, consistent with the LAB-1 symlink refusals.
|
|
238
|
+
- Review fix: an unexpected exception from the final verify stage is
|
|
239
|
+
a classified `verify: failed` install stage, never a raw crash.
|
|
240
|
+
- Review fix: a symlinked `.gitignore` is refused up front even when
|
|
241
|
+
the ignore rule would already match — no privileged read-through
|
|
242
|
+
(`git check-ignore` follows the link) either.
|
|
243
|
+
|
|
244
|
+
- Privileged provisioning writes no longer follow repository-controlled
|
|
245
|
+
symlinks (LAB-1, audit PR #393): `OverseerProvisioner` refuses a
|
|
246
|
+
symlinked `.gitignore` (checked via lstat before any read/append) or
|
|
247
|
+
`.ace-tasks` component before creating anything, and
|
|
248
|
+
`ProjectRegistry` refuses a symlinked `.ace`/`.ace/lab` ancestor and
|
|
249
|
+
creates its atomic-write temp file EXCLUSIVELY (`O_CREAT|O_EXCL`)
|
|
250
|
+
under an unguessable random name instead of the predictable
|
|
251
|
+
`.config.yml.tmp.<PID>` that a pre-planted symlink could capture
|
|
252
|
+
(F3) — a committed symlink can no longer redirect installer writes
|
|
253
|
+
outside the project.
|
|
254
|
+
|
|
255
|
+
- `ace-lab verify` now judges project readiness for the declared
|
|
256
|
+
TARGET EXECUTOR, not the invoking installer (LAB-2): every account a
|
|
257
|
+
role binds must be able to reach the project through its ancestors
|
|
258
|
+
(search permission) and read/write the project directory — a
|
|
259
|
+
repository behind an installer-owned 0700 ancestor with a different
|
|
260
|
+
target UID is NOT ready even though the installer's git access
|
|
261
|
+
succeeded. The check shares the role verifier's governing-class
|
|
262
|
+
permission logic so the two can never drift apart.
|
|
263
|
+
|
|
264
|
+
- Final verification resolves protocol role instructions
|
|
265
|
+
(`wfi://`, `prompt://`, `tmpl://`) through the actual resolver for
|
|
266
|
+
the execution context (LAB-4): prepare's syntax-only protocol check
|
|
267
|
+
is no longer reused as proof of readiness, so a syntactically valid
|
|
268
|
+
but nonexistent role (`wfi://does-not-exist/not-a-role`) fails the
|
|
269
|
+
check and blocks readiness. Resolution runs `bin/ace-nav resolve`
|
|
270
|
+
(project binstub, else PATH) from every declared project root; an
|
|
271
|
+
environment without the resolver reports `unknown` and does not
|
|
272
|
+
block, mirroring the offline posture for network remotes.
|
|
273
|
+
|
|
274
|
+
- `_overseer` ignore provisioning decides through REAL Git evaluation
|
|
275
|
+
(LAB-5): `OverseerProvisioner` uses `git check-ignore` (the same
|
|
276
|
+
probe verify applies) instead of matching `.gitignore` lines, so a
|
|
277
|
+
later negation (`!.ace-tasks/_overseer/`) no longer masquerades as
|
|
278
|
+
an effective ignore rule — the effective rule is appended and the
|
|
279
|
+
decision re-evaluated to confirm.
|
|
280
|
+
|
|
281
|
+
- A malformed per-project registry (e.g. `topology: invalid`) is now a
|
|
282
|
+
classified per-project check failure instead of a `TypeError` from
|
|
283
|
+
`dig` that killed the entire readiness report (LAB-6): the document
|
|
284
|
+
is validated through `TopologySchema.normalize!`, and healthy checks
|
|
285
|
+
beside the failure keep running and stay visible.
|
|
286
|
+
|
|
287
|
+
- `RepositoryProvisioner` compares project identity against the RAW
|
|
288
|
+
stored remote URL (`git config --get remote.origin.url`) instead of
|
|
289
|
+
the `insteadOf`-expanded `git remote get-url` value (LAB-7):
|
|
290
|
+
idempotent re-add/resume under a common SSH rewrite configuration
|
|
291
|
+
(`url.<base>.insteadOf`) no longer false-fails an identical project —
|
|
292
|
+
connection rewriting is Git transport policy, not a changed identity.
|
|
293
|
+
|
|
294
|
+
- `KeyProvisioner`'s internal pair-usability probe could return
|
|
295
|
+
`false` instead of `nil` for an unusable pair (the new public
|
|
296
|
+
`pair_fingerprint` probe normalizes to `nil`); existing internal
|
|
297
|
+
callers treated both as falsy and were unaffected.
|
|
298
|
+
|
|
299
|
+
- `GrantProvisioner` failure reports now carry `kept: []` like every
|
|
300
|
+
other grants status, so machine consumers of the install report see
|
|
301
|
+
one stable schema for the grants section regardless of outcome.
|
|
302
|
+
|
|
303
|
+
- `project add` review fixes (round 1, task 8xg.t.sbz.7.1):
|
|
304
|
+
`RepositoryProvisioner#repository?` now requires the target path to
|
|
305
|
+
be the Git repository toplevel (`rev-parse --show-toplevel` compared
|
|
306
|
+
against the expanded path), so a non-empty directory nested inside a
|
|
307
|
+
parent repository's work tree is refused as a foreign location
|
|
308
|
+
instead of converging and mutating the parent's origin (8xikzhvh);
|
|
309
|
+
`ProjectRegistry` pre-validates the loaded document with
|
|
310
|
+
`TopologySchema.normalize!` (a malformed `topology.projects` entry is
|
|
311
|
+
a classified "not this lab's registry" failure, not a `TypeError`
|
|
312
|
+
crash — 8xikzhvi), validates the updated document before the dry-run
|
|
313
|
+
branch so `--dry-run` predicts invalid id/label failures exactly like
|
|
314
|
+
the wet run (8xikzhvj), writes the registry atomically via a temp
|
|
315
|
+
file plus `File.rename` (8xikzhvk), updates the label on re-add with
|
|
316
|
+
a changed `--label` and reports the new `updated`/`would_update`
|
|
317
|
+
statuses (8xikzhvl), refuses an empty-but-existing registry file with
|
|
318
|
+
a clear message (8xikzhvq), and `OverseerProvisioner` no longer
|
|
319
|
+
counts a `!` negation line as an existing ignore entry (8xikzhvp).
|
|
320
|
+
`docs/usage.md` documents the trusted-tier grant and project-root
|
|
321
|
+
prerequisites for listing the new project (8xikzhvm) and that
|
|
322
|
+
`path`/`remote` registry fields are installer-owned data outside the
|
|
323
|
+
public projection (8xikzhvs).
|
|
324
|
+
- Security (8xi1p4z5): when an ancestor of the key path denies search
|
|
325
|
+
permission (`EACCES` on realpath, e.g. an account locking out the
|
|
326
|
+
unprivileged installer), `KeyProvisioner`'s git-worktree guard now
|
|
327
|
+
fails closed — the path is judged as inside a worktree and refused —
|
|
328
|
+
instead of falling back to the lexical spelling, which a symlink
|
|
329
|
+
behind the denied ancestor could fool (the pre-F2 behavior). The
|
|
330
|
+
`:repair_public` classification branch is documented as a deliberate
|
|
331
|
+
TOCTOU safety net (8xi1p4z7), and the dry-run contract comment now
|
|
332
|
+
states that prediction uses read-only filesystem probes plus
|
|
333
|
+
read-only `ssh-keygen` invocations (8xi1p4z4).
|
|
334
|
+
- `RoleVerifier` (8xi16mz1): the reachability walk now resolves the
|
|
335
|
+
instruction file's OWN symlink too (`File.realpath(path)`), not just
|
|
336
|
+
the ancestors of the link's path. Previously a symlinked instruction
|
|
337
|
+
pointing at a file behind an unsearchable directory (e.g. 0700
|
|
338
|
+
other-owned) verified as reachable because only the symlink's own
|
|
339
|
+
ancestors were checked; the target's directory chain is what open(2)
|
|
340
|
+
traverses, so it is what the walk judges now.
|
|
341
|
+
- `KeyProvisioner` (8xi16mz2/8xi16mz5/8xi16mz6): the dry-run
|
|
342
|
+
prediction and the wet existing path now share one
|
|
343
|
+
`classify_existing_pair` step (read-only `pair_fingerprint`,
|
|
344
|
+
including a 0600 tmpdir copy when the private key's mode has drifted
|
|
345
|
+
and ssh-keygen would refuse to load it), run BEFORE the mode-drift
|
|
346
|
+
branch. A garbage pair with mode drift now predicts `failed` (not
|
|
347
|
+
usable) instead of `would_fix_mode` — the wet run converges the
|
|
348
|
+
modes and then fails verification, and the prediction says exactly
|
|
349
|
+
that; `would_fix_mode` is only ever predicted for a verified pair.
|
|
350
|
+
The duplicated not-usable message became the shared
|
|
351
|
+
`NOT_USABLE_TEMPLATE` constant.
|
|
352
|
+
- Security (PR #392 F2): `KeyProvisioner`'s git-worktree guard now
|
|
353
|
+
resolves the PHYSICAL ancestors of the key path (realpath of the
|
|
354
|
+
deepest existing ancestor plus the lexical tail) before any
|
|
355
|
+
generate/mutation step. Previously the guard walked lexical
|
|
356
|
+
directories only, so `/outside/alias/.ssh/id_ed25519` with `alias`
|
|
357
|
+
a symlink into a repository passed and the real key landed inside
|
|
358
|
+
the worktree — including when `.ssh` did not exist yet behind the
|
|
359
|
+
alias. Symlinked ancestors resolving outside any worktree remain
|
|
360
|
+
legitimate.
|
|
361
|
+
- `KeyProvisioner` (PR #392 F4): a pair that cannot be verified as
|
|
362
|
+
usable is now a `failed` item, never `exists`/`created` with
|
|
363
|
+
`fingerprint: nil`. Verification requires the `.pub` fingerprint to
|
|
364
|
+
match the public key derived from the private key via
|
|
365
|
+
`ssh-keygen -y` (comparing `-lf` on the private file is not sound —
|
|
366
|
+
ssh-keygen resolves the adjacent `.pub`), so garbage files and a
|
|
367
|
+
`.pub` belonging to a different private key both fail the prepare
|
|
368
|
+
aggregate (`ok: false`, non-zero exit). An unknown pair is still
|
|
369
|
+
never overwritten (takeover-refusal policy).
|
|
370
|
+
- `RoleVerifier` (PR #392 F5): instruction files are verified for
|
|
371
|
+
reachability, not just read bits — every ancestor directory of the
|
|
372
|
+
resolved path (realpath follows ancestor symlinks) must grant the
|
|
373
|
+
account search permission through its governing POSIX class (owner,
|
|
374
|
+
primary/supplementary group via the `group_source` seam, or other;
|
|
375
|
+
shared with the file-read check so the two cannot drift). A 0644
|
|
376
|
+
file behind a 0700 directory owned by another account is now
|
|
377
|
+
`failed`, not `verified`. ACLs remain out of scope.
|
|
378
|
+
- `AccountProvisioner` (PR #392, macOS UID allocation):
|
|
379
|
+
`next_darwin_uid` parses only the trailing `UniqueID` column of
|
|
380
|
+
each `dscl -list` line instead of scanning the whole output, so
|
|
381
|
+
digits inside account names such as `deploy-2026` can no longer be
|
|
382
|
+
mistaken for UIDs.
|
|
113
383
|
|
|
114
|
-
- Topology/routing CLI (`ace-lab`) addressing projects, agents, and services by
|
|
115
|
-
stable IDs: `projects`, `agents`, `services`, `resolve`, `route` commands with
|
|
116
|
-
deterministic JSON output (`--format json`).
|
|
117
|
-
- ADR-022 configuration contract for Lab topology (`schema_version: 1`) with
|
|
118
|
-
validated stable IDs, project references, capability normalization, binding
|
|
119
|
-
attestation fields, and verified-local-principal authorization mapping.
|
|
120
|
-
- Classified query outcomes: `missing`, `ambiguous`, `stale`, `unauthorized`,
|
|
121
|
-
`invalid_configuration`.
|
|
122
|
-
- Allowlist-based public projection; tokens, auth-file paths, endpoint
|
|
123
|
-
credentials, URL userinfo, query parameters, fragments, and raw pane/session
|
|
124
|
-
identifiers never appear in public output.
|