diff --git a/acceptance-register.md b/acceptance-register.md index 256a237..ba1442e 100644 --- a/acceptance-register.md +++ b/acceptance-register.md @@ -36,6 +36,7 @@ Real-world validation that cannot run at development stage, and the human prereq | AR-18 | A Windows node identifies a running WSL VM's worker process (`vmmem` or `vmmemWSL`) as one `GUEST_VM` consumer in unmanaged load, never controlled, and never presents the VM's Linux processes as its own (ArcForges-Design 03 §1, §2, §9; A-L01, AD-0018 §2). Procedure: on Windows 11 with WSL2 and one distribution installed, (1) start the distribution outside ArcForges (`wsl -d -e sleep 600`); (2) run a native node; (3) `arcforges ps --label guest --json` lists the VM worker with label `PROCESS_LABEL_GUEST_VM`, no task, and a memory figure close to Task Manager's for that process, and no Linux process of the distribution appears; (4) allocate about 2 GiB inside the distribution (for example `python3 -c "b=bytearray(2<<30); import time; time.sleep(60)"`): `arcforges resources --json` shows unmanaged memory rising and the memory budget falling by about that amount within about 10 s; (5) a task running `wsl.exe -d -e sleep 30` has every process flagged `crossesVmBoundary`, and `ps --label managed` lists only Windows processes of its job; (6) run `ArcForges.ClosedLoop.Tests -method *ATaskThatRunsWsl*` there and keep the VM workers it prints | WSL is not installed on the workstation, so no VM worker runs there; the `crosses_vm_boundary` flag itself is proven with the inbox `wsl.exe` (AF-RES-01) | A Windows 11 machine with WSL2 and one distribution (user-provided; installing WSL is the user's step) | AF-RES-01 | Open | | AR-19 | Successful Windows process adoption (ArcForges-Design 04 §10; `ResourceService.AdoptProcess`): a same-user process outside every job is adopted into the root job and a nested adoption job (the root job's limits apply, V-W01), appears as an `ADOPTED` task with label `ADOPTED`, its existing children follow, it can be terminated through `process.terminate`, and it ends `LOST` ("no exit status: the node is not the adopted process's parent") when it exits; after a node restart an adoption job the node cannot reopen (L-14) ends the task `LOST` through `container_missing`. Procedure: on a Windows 11 machine where a process created through WMI `Win32_Process.Create` is outside every job (check with `IsProcessInJob`), run `Node.Platform.Windows.Tests -method *AdoptionTests.AProcessOutsideAnyJobIsAdoptedWithItsChildrenAndTerminated` and `Node.Core.Tests -method *AdoptionLifecycleTests.AnAdoptedProcessThatEndsByItselfEndsItsTaskLostWithoutAnExitStatus` and `-method *AdoptionLifecycleTests.AnAdoptionContainerTheNodeCannotReopenAfterARestartIsLost`; none may skip with the "already in a job" reason | On the workstation every user process, a WMI-created one included, is already in a job (ArcForges-Design register L-30), so 04 §10 refuses every candidate and the capability `adopt` reports `LIMITED`; the refusal path is proven there (AF-SEC-01) | A Windows 11 machine or VM where a WMI-created process is outside every job (user-provided) | AF-SEC-01 | Open | | AR-20 | MR-07: establish the cause of the Windows supervisor test's unexplained node stop exit 75 and verify a discriminating repair if required | The historical failure has not recurred with the retained diagnostics; non-recurrence cannot establish its cause or prove a fix | A captured native Windows recurrence with verbose transport/descriptor/node/supervisor evidence, or a proven causal reproduction; the Windows MCP venue is already available, no new human provisioning | AF-NODE-01 | Open; unresolved observation, not a passed check or task block | +| AR-21 | MR-11: a non-elevated Windows node and an elevated client of the same user: user-SID pipe ownership succeeds, but an unidentifiable elevated peer is refused before API execution | Existing automated ownership tests do not create two processes at different integrity levels; owner deferred full end-to-end testing on 2026-10-15 (ledger 30) | User-performed Windows 11 cross-integrity run at final end-to-end acceptance; no automatic elevation or re-request now | AF-NODE-01 | Open; deferred validation, no task block | ## 2. Human prerequisites @@ -90,3 +91,42 @@ When a recurrence is observed during authorized maintenance: Do not assign the old RECOVERING/INTERNAL race as the cause of the different pipe-missing exit 75 without evidence. 5. Close only with a proven cause and a discriminating regression/repair where required, reviewed and verified at its final pushed commit on the required native hosts. More silent runs alone never close this entry. No retry-count increase or weakened assertion. + +### AR-21: MR-11 same-user cross-integrity client + +Current development evidence: the user-SID ownership fix and three `PipeOwnershipTests` already exist in ArcForges main +`5eaee92a4a964469bad41dad28dad9787b7552cf`; the fix was introduced by `3c323b2` during AF-NODE-01. `OwnerIsUser` rejects another +user, BUILTIN\Administrators, SYSTEM and absent SIDs. A real user-owned pipe carries a byte after the owner check; a pipe owned by +the token's default owner is accepted only when that owner is the user. The retained Windows CI leg at reviewed head +`8fe744ffee80f24b59f835af60ba43e4a5163391` ran Client.Tests 102/102, no skips. This is existing evidence, not a new cross-integrity +run. No missing ownership test or source repair was found. DesktopPlatform's separate transport is MR-12, not resolved here. + +The two checks differ: the client checks the server pipe's user SID; the node must also identify its peer. Current NodeClient turns +three dropped hellos into AccessDenied and explains that an elevated client of a non-elevated node is refused. A successful pipe +ownership test does not prove successful node Hello across integrity levels. This acceptance expects that refusal, not privilege +support or node elevation. The real pair remains unverified; the owner's ledger-30 deferral is retained without re-asking. + +User-performed procedure at final end-to-end acceptance (not run in this maintenance pass): +1. Record the source revision, matching Release binary paths, Windows version and whether each shell is elevated. In an ordinary + shell and then in the user's elevated shell run the already built ownership tests: + `dotnet test --project tests/ArcForges.Client.Tests -c Release --no-build --filter-class ArcForges.Client.Tests.PipeOwnershipTests --minimum-expected-tests 3 --output Detailed`. + Preserve the test output identifying the token-owner relation; both runs must pass all three tests without skips. The SID rule + tests alone are not a substitute for the next two-process case. +2. In the ordinary shell prepare a unique temporary test root, its `config/node.json` containing a `dataRoot` inside that root, and a + unique pipe name. Set `ARCFORGES_CONFIG_DIR` to that config directory, `ARCFORGES_ENDPOINT` to that pipe name and + `ARCFORGES_TEST_MACHINE=isolated`; unset `ARCFORGES_OS_SECRET_STORE_TESTS`. Use `--test-mode` on every invocation, as the existing + ClosedLoop TestNode fixture does, so the node data key uses the isolated file-backed store. Never select a real credential store. + Run ` node run --test-mode` there. In another ordinary shell with the same three test-environment values, + run ` node wait-ready --test-mode`, then ` status --json --test-mode` as baseline. +3. In the user's elevated shell set the same isolated test-environment values and no OS-store opt-in. Run + ` status --json --verbose --test-mode` with a 30 s external bound. Preserve exit/stdout/stderr and the + node log. Require the client ownership check to accept the user-owned pipe, then AccessDenied/refusal when the ordinary node + cannot identify the elevated peer; no successful Hello, privileged API action, replacement node or elevation by ArcForges. + If the OS permits peer resolution instead, preserve that evidence and review the stated expectation before closing this entry. +4. Re-run ordinary-shell status to prove the original node remains usable; stop it from that ordinary shell with + ` node stop --test-mode`. Preserve process identities, endpoint descriptor and logs before disposing only + this temporary environment. No managed privileged task, second account, device-policy change or real credential cleanup is needed. + +Residual risk: no retained run proves the actual ordinary-node/elevated-client peer-resolution/refusal combination. Close only with +that two-process evidence and review of the observed result. AR-02 second-account isolation and the deferred positive auto-start leg +remain separate and open; this entry neither proves nor changes them. diff --git a/delivery-graph.json b/delivery-graph.json index 1c98d7d..2740a87 100644 --- a/delivery-graph.json +++ b/delivery-graph.json @@ -894,7 +894,8 @@ "F-N02" ], "acceptance_register": [ - "AR-02" + "AR-02", + "AR-21" ], "human_prerequisites": [], "risks": [ diff --git a/ledger/ledger.jsonl b/ledger/ledger.jsonl index 30bf492..b931185 100644 --- a/ledger/ledger.jsonl +++ b/ledger/ledger.jsonl @@ -131,3 +131,4 @@ {"at": "2026-10-25T16:20:01Z", "task": "AF-SEC-01", "kind": "note", "text": "MR-08 resolved in the delivered gate: TaskGate maps nonterminal ADOPTED CancelTask to process.terminate (introduced cd0bb00a, delivered ArcForges#31 merge 2180053; both ancestors of freshly fetched main 5eaee92). REMOTE is DENY and approval cannot bypass it; settled/replay paths cannot issue a new stop. Existing adopted gate/audit and per-origin matrix tests retained, included in verified head 8fe744f; no new runtime verification claimed. See maintenance/2026-10-25-mr08-permission.md."} {"at": "2026-10-25T16:20:01Z", "task": "AF-CLD-05", "kind": "note", "text": "MR-08 future obligation assigned in acceptance while task stays planned: on the real signed remote-to-node path, REMOTE cancel_task of a nonterminal ADOPTED task must be denied as process.terminate before any stop, leave the process running and audit denial; medium risk, step-up and approval cannot bypass REMOTE DENY. The delivered local gate is already correct; real remote integration is not implemented or claimed verified in this maintenance pass."} {"at": "2026-10-25T16:22:16Z", "task": "AF-AI-01", "kind": "note", "text": "MR-09 assigned, not implemented: re-read ledger 88, current ClientSessions/empty AgentRoots and Design 11 section 1 at main c36bf89. AF-AI-01 acceptance now requires registered-root verified CLI descendants to stay AGENT despite pty/console, with effective permission/approval coverage on native Windows and Linux (F-A02). Added the security Design reference and notes describing the pre-registration HUMAN consequence and residual missing-root/escaped-ancestry same-user bypasses; no hostile-agent isolation claim, no real-client validation claimed, task stays planned. No feature implementation or task activation."} +{"at": "2026-10-25T16:26:12Z", "task": "AF-NODE-01", "kind": "note", "text": "MR-11 deferred validation AR-21, not a new runtime repair: current ArcForges main 5eaee92 retains user-SID pipe owner check introduced 3c323b2 and three PipeOwnershipTests, rejecting other user/group/SYSTEM/null owners. Retained native Windows CI at reviewed head 8fe744f passed Client.Tests 102/102 without skips; no fresh cross-integrity evidence claimed. Client pipe ownership and node peer resolution are separate: current NodeClient refuses after three dropped hellos with AccessDenied and elevated-client guidance. Actual non-elevated-node/elevated-client combination remains unproven and follows owner ledger-30 final end-to-end deferral, without re-asking or elevating here. AR-21 now records evidence, isolated test-mode procedure, expected fail-closed peer refusal and closure limits, linked from AF-NODE-01; task remains delivered, no task block. MR-12 DesktopPlatform, AR-02 second-account and positive auto-start remain separate. No real credential-store operation or privileged managed task."} diff --git a/maintenance/2026-10-24-repair-list.md b/maintenance/2026-10-24-repair-list.md index c8b9099..1633a3d 100644 --- a/maintenance/2026-10-24-repair-list.md +++ b/maintenance/2026-10-24-repair-list.md @@ -37,7 +37,7 @@ managed tasks, no option that disables protection to enable elevation. The stop | MR-08 | Remote `CancelTask` (REMOTE, medium) would reach ADOPTED tasks, terminating an adopted process although the matrix marks terminating a process D for REMOTE. | 59 (4), 65 | ArcForges, Plan | No REMOTE caller exists before AF-CLD-04/05 *(confirm the gate's ADOPTED handling)* | fix in the gate if the delivered matrix already decides it; otherwise assign to AF-CLD-05 with the obligation in its record | resolved in delivered gate: AF-SEC-01/ArcForges#31 (merge 2180053; TaskGate branch introduced cd0bb00a) maps ADOPTED cancellation to process.terminate, REMOTE DENY; unchanged current main 5eaee92 and existing gate/matrix coverage checked; real remote-path refusal now explicit in planned AF-CLD-05 acceptance, not claimed verified; [evidence](2026-10-25-mr08-permission.md); ledger AF-SEC-01 and AF-CLD-05 notes | | MR-09 | An agent CLI with a pseudo-terminal is classified HUMAN until agent roots are registered (documented bypass, Design 11 §1). | 88 | Plan | AF-AI-01 acceptance names agent-root identification (F-A02) but not this consequence | assign: AF-AI-01 record names the obligation | assigned: AF-AI-01 acceptance now requires registered-root CLI descendants with a pty/console to remain AGENT, including effective permission/approval coverage on Windows and Linux (F-A02); notes name the current missing-root consequence and residual same-user bypasses, Design 11 reference added; task stays planned, no implementation or real-client validation claimed; ledger AF-AI-01 note | | MR-10 | The interim origin trusted a self-declared client kind. | 59 (1), 64 | ArcForges | AF-SEC-01 verifies client kinds against the peer's executable (ArcForges#31; ledger 87) | resolved | resolved: ArcForges#31 (merge 2180053); `ClientSessions` assigns the origin from the client kind verified against the peer's executable (`ClientImages.Verifies`); ledger AF-SEC-01 delivered | -| MR-11 | Cross-integrity case: a non-elevated node with an elevated same-user client (resolution and acceptance entry). | 20, 30 | ArcForges, Plan | ArcForges.Client owner-SID check fixed in AF-NODE-01; no acceptance-register entry *(confirm)* | fix: test if missing; acceptance-register entry for the real elevated case (deferred validation) | open | +| MR-11 | Cross-integrity case: a non-elevated node with an elevated same-user client (resolution and acceptance entry). | 20, 30 | ArcForges, Plan | ArcForges.Client owner-SID check fixed in AF-NODE-01; no acceptance-register entry *(confirm)* | fix: test if missing; acceptance-register entry for the real elevated case (deferred validation) | deferred validation (AR-21): ArcForges.Client user-SID repair and three existing ownership tests confirmed (retained Client.Tests 102/102 at 8fe744f); real non-elevated-node/elevated-client peer identification/refusal remains unproven, owner final end-to-end deferral retained; procedure and AF-NODE-01 register link added, no elevation performed; DesktopPlatform MR-12 separate; ledger AF-NODE-01 note | | MR-12 | DesktopPlatform `LocalRpcClientChannel` CurrentUserOnly check refuses an elevated same-user client (the defect ArcForges.Client fixed locally). | 30 | DesktopPlatform | *(confirm in DesktopPlatform main)* | fix in DesktopPlatform; adoption by ArcForges recorded separately (MR-43) | open | | MR-92 | Lost `JobRemoved` signal: `SystemdManager`'s handler looked for the job's waiter and recorded the result only when it found none, while `WaitJob` registers its waiter and then reads the record; a wait registering in between missed the end and ran to its timeout although the job had finished (seen as a 10 s adoption refusal in `AdoptionTests`; an attempt's 90 s start wait could record 'did not start' for a running attempt). | found in MR-76 (Linux leg at bbd4ddb) | ArcForges | live-manager probe: 68 of 20,800 waits missed on main, 0 of 28,800 with the fix | fix | fixed: ArcForges#40 (merge 64e9f7c); ledger AF-EXEC-02 note | | MR-95 | Timeouts and CPU-time limits never fire for an attempt recovered STARTING: the supervisor's timeout and CPU-time checks require `attempt.StartedTimestamp`, which only the change to RUNNING sets, and recovery reads `row.StartedAt`, so a command that a recovered launch starts (during the node gap or after) runs without `timeout_ms` or a CPU-time limit, contrary to 04 section 6 and section 9. | found in MR-89 review (ArcForges#42) | ArcForges | `ExecutionSupervisor.cs` timeout/CPU check and recovery (lines cited in #42's review record) | fix: give a recovered STARTING attempt a start time once its command is known to run; fault test with a restart in a launch step | open |