12 KiB
12 KiB
FCM-M2-001 — Generated Environment Boundary
- Issue/card: #758 / FCM-M2-001
- Branch/base:
feat/758-generated-env-boundaryfromorigin/maine9c4aa3e8b3780719cd5a43c0ef3f37fc70de666 - Budget assumption: 30K-card budget; implement only the deterministic generated/local environment boundary and its launch-chain/docs/tests.
Objective
Replace the generic fleet agent .env authority/merge path with a deterministic roster-derived <agent>.env.generated projection and strict, data-only <agent>.env.local. The roster remains the desired-state authority. Reject bad input before the launcher creates a tmux session; never print sensitive or privileged-command values.
Scope and non-goals
- In scope: deterministic render/write, strict generated/local parse rules, legacy
.envdisposition/quarantine, systemd/launcher boundary, permission/path checks, focused fail-closed tests, operator/reference documentation, USC interface evidence. - Excluded: roster CRUD/mutation, v2 roster schema changes, lifecycle/reconcile/apply behavior, migration/canary rollout, connectors, remote surfaces, live-fleet actions, and M2-002.
Plan
- Add red tests for generated-key shadowing, malformed/duplicate/unknown/command/sensitive input, no-value diagnostics, deterministic/idempotent projection, secure file modes, and legacy disposition.
- Implement a pure strict environment contract plus atomic projection/quarantine helper.
- Replace the generic
.envwriter/merge path and systemd reference with.env.generated+.env.localownership. - Make the shell launcher parse the files without
source/eval, reject unsafe input before tmux creation, and construct only the roster-derived runtime command. - Add operator/reference documentation with the requested USC M1 interface evidence and M2–M4 gate statement.
- Run focused/package/root gates and audit the USC interface packet. Per continuation scope, stop before review, commit, push, PR, or live mutation.
Initial evidence
- No existing owner: target worktree path absent; no target local/remote branch;
pr-list.sh -s openreturned no open PRs. - M1 compiler/API/docs and executable disposition evidence are present at the assigned base.
- Existing launch chain writes
fleet/agents/<agent>.env, preserves arbitrary legacy lines viamergeAgentEnv, sourcesMOSAIC_AGENT_COMMAND, and executes it throughbash -c; all are M2 remediation targets. ~/.config/mosaic/guides/SECURITY.mdis absent. Read the available security-review role contract and the vault/secrets guide instead.
Verification log
Continuation (2026-07-14)
- Preserved the inherited 14-file delta; no reset, stash, rebase, roster mutation, lifecycle action, live-fleet action, commit, push, or PR action was performed.
- Focused gates passed:
pnpm --dir packages/mosaic test -- src/fleet/generated-env-boundary.spec.ts— 1 file, 10 tests passed.bash packages/mosaic/framework/tools/fleet/test-start-agent-session.sh— passed.bash packages/mosaic/framework/systemd/user/test-fleet-units.sh— passed.pnpm --dir packages/mosaic test -- src/commands/fleet.spec.ts— 1 file, 192 tests passed.
- Package gates passed before final documentation/format follow-up:
pnpm --dir packages/mosaic typecheck— passed.pnpm --dir packages/mosaic lint— passed.pnpm --dir packages/mosaic test— 52 files, 752 tests passed.
pnpm format:checkinitially failed only for the new boundary reference and generated-boundary TypeScript files; targeted Prettier normalization was applied. A finalpnpm format:checkpassed.- USC packet audit: the M1 structural compiler is
parseRosterV2with rosterversion: 2; the semantic resolver isvalidateRosterV2Semantics; disposition artifacts retainversion: 1fixture evidence.docs/TASKS.mdrecords M1-001 done, M1-002 in-progress, and M1-003 not-started; no product release version is claimed. The packet now distinguishes these statuses from checkout artifact presence and states the M2 → M3 → M4 downstream gates.
Review remediation (2026-07-14)
- Blocker 1 red-first: Added a launcher reproducer with a
0777fleet/agentsparent and a private generated file. Before implementation,bash packages/mosaic/framework/tools/fleet/test-start-agent-session.shfailed:FAIL: generated file under a world-writable parent was accepted. The failure occurred after the launch path reached fake tmux, proving the parent was not validated. - Blocker 2 red-first: Added a
symlink()projection-directory reproducer that preloads generated/local/quarantine/legacy target files and asserts no target mutation. Before implementation,pnpm --dir packages/mosaic test -- src/fleet/generated-env-boundary.spec.tsfailed the new test because the existing writer followed theagentEnvDirsymlink and parsed its target legacy input (expected /unsafe-directory/i, receivedcode=malformed-line). The initial test-only missingmkdirimport was corrected before recording this behavior failure. - Blocker 3 red-first: Added fresh/stale/absent native-heartbeat regression coverage. Before implementation, an isolated fake-tmux launcher reproducer with a fresh
<agent>.hb.nativemarker failedFAIL: fresh native heartbeat was overwritten; the existing sidecar immediately replaced nativestatus=busy/modelcontent. - Remediation result: The launcher now rejects a group/world-accessible or symlinked
fleet/agentsparent before an environment read or tmux call. The projection writer useslstatbefore chmod/write processing and rejects a symlinked directory without creating generated/local/quarantine files or deleting legacy input. The heartbeat sidecar defers to a fresh non-symlink native marker and falls back when stale/absent. Focused green evidence before independent review:bash packages/mosaic/framework/tools/fleet/test-start-agent-session.shandpnpm --dir packages/mosaic test -- src/fleet/generated-env-boundary.spec.ts(11 tests) passed. - Independent-review follow-up red-first: Codex code review returned one blocker and security review one medium CWE-732 finding: the writer repaired an already
0777directory withchmodbefore trusting its contents. Added a reproducer with a safe local file beneath an existing0777directory. Before the follow-up fix,pnpm --dir packages/mosaic test -- src/fleet/generated-env-boundary.spec.tsfailed because the promise resolved and wrotecoder0.env.generatedinstead of rejecting. - Independent-review remediation: Existing directories now pass non-following private-directory validation before any read or chmod; only a directory created in this call is normalized to
0700. The fleet-add test fixture now creates its simulated trustedfleet/agentsboundary at0700; this corrects fixture setup to match the new required contract rather than weakening the rejection assertion. Focused reruns passed: generated-boundary 12 tests, launcher boundary suite, and fleet suite 192 tests. - Final verification before re-review: Launcher + systemd suites passed; package suite passed (52 files, 754 tests); package lint/typecheck, root typecheck (42 tasks), format check, and diff check passed. The rerun code review still reports a tmux command-arity blocker, and the security rerun reports systemd
EnvironmentFilepre-validation injection findings for both agent units. These were discovered after the specified three-remediation scope; no additional source changes were made. Independent review therefore remainsREQUEST CHANGESdespite the requested three fixes passing their behavioral suites.
Systemd pre-validation remediation (2026-07-14)
- Red-first: Updated the fleet unit contract to reject any
EnvironmentFile=projection preload, require a cleared bootstrap environment, and require a validated exact-stop path. Before implementation,bash packages/mosaic/framework/systemd/user/test-fleet-units.shfailed:FAIL: agent units must not preload projections before strict parsing. - Red-first parser/stop coverage: Added interaction-wrapper and exact-stop cases to the launcher boundary suite. Before implementation,
bash packages/mosaic/framework/tools/fleet/test-start-agent-session.shfailed:FAIL: interaction did not use shared strict parser first, because the interaction wrapper consumed inherited environment before projection validation. - Focused green: Both unit templates now use
env -iwith fixedHOME, agent instance, and PATH; neither hasEnvironment=/EnvironmentFile=. The interaction wrapper delegates tostart-agent-session.sh --interaction, so strict generated/local parsing precedes pinned Pi profile checks.--stopreuses the strict generated parser before exact=<agent>socket/session termination. Passed: systemd unit suite, launcher boundary suite (including malformed interaction, pinned profile, and ambient-socket stop cases), and 210 focused TypeScript tests. - Final verification:
pnpm --dir packages/mosaic testpassed (52 files, 754 tests); package lint/typecheck, root typecheck (42 tasks), format/diff, and shell syntax checks passed. Security review passed with no findings. Code review repeated the previously refuted tmux argv concern and a pre-existing Claude trust-lock suggestion; per the assigned narrow follow-up, no tmux or unrelated trust-path change was made.
Risks and next review
- This card is uncommitted and unreleased. The canonical tracker still records its dependencies as M1-002 in progress and M1-003 not started; this continuation does not reinterpret those task states.
- Final post-documentation checks passed:
pnpm --dir packages/mosaic typecheck,pnpm --dir packages/mosaic lint,pnpm --dir packages/mosaic test(52 files, 752 tests),pnpm typecheck(42 Turbo tasks), andpnpm format:check. - Obtain independent code and security review of the complete delta next. Do not run commit, push, PR, or live-fleet commands in this continuation.
Fresh-install directory remediation (2026-07-14)
- Objective: Remediate only the fresh-install path where
installFleetcreatedfleet/agentswith host-umask permissions before the boundary writer correctly rejected it. - Plan: Add a real
fleet install --no-enableintegration reproducer; prove red; let the existing boundary writer own directory creation; run focused and full gates. No commit, push, PR, review disposition, or live-fleet action. - Red evidence: Before the one-line remediation,
pnpm --dir packages/mosaic test -- src/commands/fleet.spec.tsfailed the new test withAgentEnvBoundaryError: code=unsafe-permissionsatensurePrivateProjectionDirectory, afterinstallFleetpre-created the directory. - Change: Removed only the recursive
mkdir(activePaths.agentEnvDir)ininstallFleet.writeAgentEnvironmentProjectionremains the sole creator and retains its existinglstat, private-directory, symlink, and existing-unsafe-directory fail-closed checks. - Focused green:
pnpm --dir packages/mosaic test -- src/commands/fleet.spec.ts— 193 tests passed. The new integration executes a freshfleet install --no-enable, asserts a real non-symlink0700directory and a0600generated projection. Existing unsafe-directory coverage remains ingenerated-env-boundary.spec.tsand asserts no chmod repair/no generated file write. - Full gates green: generated-boundary 12 tests; launcher and systemd suites; package typecheck/lint and 52 files / 755 tests; root typecheck (42 tasks), lint, format, diff check, and root test (42 tasks) all passed.
- Independent review: The complete inherited uncommitted delta still has Codex
REQUEST CHANGESfindings outside this narrow fix (tmux command arity and Claude trust-lock regression), plus a security-review medium finding on unvalidated writable ancestor directories. No out-of-scope source changes were made. - Risk: The writer's existing create-then-validate sequence is relied on for the creation boundary; a concurrent substitution causes fail-closed validation rather than repair. The review findings above remain residual risks for the complete card delta.