2e138a199b61b4e8d133cdfe413b961cada19edf
8 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
2e138a199b |
CB-634: one shared "fleet" workspace + rename bridged -> fleetd cutover
Two changes ship together here.
1. One shared herdr workspace. The lead and every worker now live in one
workspace called "fleet", so the operator sees one "session" with many
windows, not two. Before, the lead sat in a "leads" workspace and workers
in "bridged-workers", which read as two sessions. The lead is still told
apart from workers by its exact tab label ("lead: <name>"), so putting them
in one space is safe. LeadTabScanner keeps the exclude-by-label mechanism
for split layouts; Fleetd now passes an empty exclude set.
2. Rename the daemon from "bridged" to "fleetd" (the binary, config, scripts,
launchd/systemd units, module dir, and MCP mount).
- Module dir bridged/ -> fleetd/; jar finalName -> fleetd.jar.
- Log line, comments, docs, and CLAUDE.md updated to say fleetd.
- Scripts renamed: redeploy-bridged.sh -> redeploy-fleetd.sh,
bridged-launchd-wrapper.sh -> fleetd-launchd-wrapper.sh.
- Deploy units renamed: dev.ltms.bridged.plist -> dev.ltms.fleetd.plist,
bridged.service -> fleetd.service; launchd Label -> dev.ltms.fleetd.
- Config default bridged.yaml -> fleetd.yaml; the legacy bridged.yaml is
still read as a fallback, and still gitignored.
- MCP: drop the deprecated bridge_* tool twins; only fleet_* remain. The
server name is "fleet". The mount name in the local .mcp.json becomes
"fleet" (gitignored, not in this commit).
- Env var defaults BRIDGED_API_TOKEN -> FLEETD_API_TOKEN, fixture
BRIDGED_WORKER_TOKEN -> FLEETD_WORKER_TOKEN.
Kept on purpose: the BRIDGED_MEMBER marker. Renaming it is a coupled change to
the credential-scrub security control (an operator secrets.sh may guard on it),
so it stays until that migration is done on its own.
Metrics were already fleet_* (CB-632); MetricNamesTest still guards that no
name says bridged_.
The canonical CLAUDE.md block and the wiki template stay byte-identical
(wiki working tree edited, committed to the wiki repo separately).
949 tests pass (mvn clean install). 4 fewer than before = the 4 removed
bridge_* alias tests.
|
||
|
|
e38eac1a33 |
CB-632: ignore fleetd.yaml too, and fix the docs that named the old example
Unit 3 renamed bridged.example.yaml to fleetd.example.yaml and taught Fleetd to read fleetd.yaml first. Two things it left behind. bridged/.gitignore still ignored only bridged.yaml. An operator who follows the new comment and copies the example to fleetd.yaml gets an untracked live config holding tokens, and git offers to commit it. Both names are ignored now, because both names work until the cutover. Three design docs still pointed readers at bridged.example.yaml, a file that no longer exists under that name. |
||
|
|
8101290933 |
CB-632: rename the exported metrics bridged_* -> fleet_*
Part of #145 (CB-632). Doing this NOW, ahead of the rest of the path renames, for one reason: the vms lead is about to wire a monitoring dashboard to these series. Renaming a metric after a dashboard points at it breaks continuity and silently leaves a dead panel. Renaming it before costs nothing, so it goes first rather than at the cutover. Nine series renamed, all declared in FleetMetrics. Two real defects found while doing it: - FleetApp had "bridged_auth_failures_total" written as a LITERAL instead of using FleetMetrics.AUTH_FAILURES -- a second hand-written copy of a name, which is how these drift. It now uses the constant, so there is one source for that name again. - Nothing guarded the prefix. One test does assert a wire name (FleetAppAuthTest checks the real /metrics body for fleet_sessions), which is good, but it covers one series out of nine. The literal above was covered by nothing at all. So this adds MetricNamesTest, which reads the constants reflectively rather than listing them -- a test that lists the nine names is itself a second hand-written copy, and would pass while a tenth went unchecked. It asserts its own denominator too: "no name starts with bridged_" is true of an empty set, so a sweep that found nothing would pass loudly. Asserting the count of 9 makes a broken sweep fail instead. Also renamed three herdr contract-test workspace labels, __bridged_* -> __fleet_*. Those are throwaway workspaces created by ensureWorkspace, not metrics, but they are the same word. Verified: mvn clean install green, 52 classes, 881 tests, 0 failures. Test count is up by 3 -- the new prefix, denominator and uniqueness checks. No bridged_ string remains anywhere outside wiki/. |
||
|
|
ecc590f344 |
CB-632 unit 5: rename the daemon and classes in the docs prose
Part of #145 (CB-632). Documentation only, plus one internal literal. Unit 1 renamed the package and classes, which left every doc describing classes that no longer exist. This fixes the prose across README.md, docs/ and bridged/docs/ -- 18 files. Renamed: dev.ltms.bridged -> dev.ltms.fleet, the five class names, and "bridged" where it names the daemon as a product rather than a path. Also renamed two literals, because a doc that disagrees with the code is worse than one that is out of date: - bridged-local-noauth -> fleetd-local-noauth. A placeholder apiKey OpenCodeLauncher sends when a profile resolves no token, to a local endpoint that does not check it. No test asserts the old string. - the vnd.ltms.bridged.* media type in the M4 design doc. It appears in no Java file, so nothing implements it yet. Deliberately NOT renamed, because each is still literally true today and changes only at the cutover: - paths: bridged/, bridged.yaml, bridged.example.yaml, bridged.jar, .bridged-worktrees, deploy/dev.ltms.bridged.plist, scripts/redeploy-bridged.sh, bridged-launchd-wrapper.sh - bridged_* metric names -- renaming these after the monitoring is wired would break dashboard continuity, so they move before it is - bridge_* MCP tool names, which answer alongside fleet_* on purpose - BRIDGED_* environment variables, read by a file outside this repo Method note: perl, not sed. BSD sed has no \b and no lookaround, and a word-boundary expression there fails silently. The prose replace uses (?<![\w./-])bridged(?![\w./-]) so it cannot touch a path or an identifier, then every remaining hit was read by hand. Verified: mvn clean install green, 51 classes, 878 tests, 0 failures. |
||
|
|
76e4b577a0 |
CB-622: rename bridge_* tool names to fleet_* in Markdown docs
Rename the eleven MCP tool names (bridge_ack/ask/list/poll/profiles/reply/ send/spawn/status/stop/whoami) to their fleet_* names across the Markdown documentation. fleet_* is written as the normal name; one deprecation note in README.md says bridge_* still works for one release. docs/MCP-Contract.md is renamed only inside section 6 (lines 210-293): sections 1-5 and 7-11 are stale pre-build design text (CB-609) and are deliberately left with old names so dead text does not look maintained. Also renames e2e/bridge_ask_transcript.md to e2e/fleet_ask_transcript.md to match its content. CLAUDE.md, wiki/, plugin/skills/setup/SKILL.md and .claude/skills/port-to-opencode/SKILL.md are owned by other units and are untouched. |
||
|
|
2773ab600d |
CB-402: live dogfood complete — Stage B verified against opencode 1.18.5
Closes the one known-unverified item before cross-host. CB-402 merged in
|
||
|
|
9daf1ec5ba |
CB-5xx: Stage 5 hardening — auth, authz+audit, metrics, CI, supervision
Closes out single-host before the cross-host work. Sequenced BEFORE CB-308 deliberately: federation's own gating concern is the trust model, and it inherits whatever identity shape lands here. The finding this stage is built around: bridged had exactly ONE security control, the loopback bind. ConnectionIdentity resolves a worker from its connection (unforgeable), but every caller that was not a recognised worker pane fell through to being treated as the PRIMARY -- the most privileged role on the bus. Latent today; load-bearing the moment a bind widens. CB-501 auth: - Role/Principal/CallerResolver: connection identity first, bearer token second, ANONYMOUS third. Inverts the old default so absence of identity means nothing, not everything. - Worker identity is never token-gated, so enabling auth cannot lock the fleet out of bridge_reply. - Constant-time token compare (MessageDigest.isEqual). - validateAuthExposure(): a non-loopback bind under loopback-trust now REFUSES TO START. Makes the dangerous config unrepresentable rather than merely documented. - TLS terminates at a reverse proxy by design (D3), not in the JVM. CB-505 authz + audit, enforced on BOTH entry paths: - The docs describe MCP as "a thin adapter over the REST core"; at code level it is not. BridgeMcp calls MessageService directly, and /mcp is a raw servlet on Jetty's context handler that never traverses Javalin's before filter. Enforcing only at REST would have left /mcp open. - Load-bearing rule is own-session-only: a worker may reply/ask only as itself. Structurally true over MCP already; over REST the session id in the URL path had simply been trusted. - Audit: JSON lines to a dedicated appender, additivity=false. Never records message content -- this bus carries source and prompts. CB-502 metrics: zero new dependencies. A ~150-line Prometheus text renderer instead of the specced Micrometer, because this pom already hand-pins jackson-annotations to reconcile Jackson 2/3, imports a Jetty BOM against skew, and carries four accepted-CVE advisories -- and CLAUDE.md's mandated dependency CVE gate could not be run (no JetBrains MCP server connected). Instrumented at MessageService, the single funnel both surfaces share. CB-503 CI: .gitea/workflows/ci.yml against the already-running Gitea runner. Needs no contract-exclusion flag -- the pom's default-excludes profile already sets excludedGroups=contract, so plain `mvn clean install` IS the mock-socket surface. Provisions JDK 25 explicitly (runner default-jdk is older). CB-504 supervision: launchd agent (the real target -- this host is macOS, there is no systemd) plus a systemd unit for the Linux gateways CB-308 adds. Ordering directives are advisory, so the actual fix is that startup now waits up to 30s for the herdr socket and then serves degraded, instead of crashing into a restart loop on a boot-order race. Also fixes drift found while surveying: - bridged.example.yaml documented spawn_ready_timeout_ms in snake_case; config binds via plain Jackson with ignoreUnknown, so uncommenting it would have been silently dropped and the default kept. Now camelCase, with a test that loads the shipped example and one that pins every documented knob's spelling -- no test had ever loaded that file. - Added the 6 shipped-but-undocumented knobs (worktreeRoot, parityOverlay, gitTokenEnv, gitHostEnv, configDir, primary:). - README "Next" listed bridge_ask and session lifecycle as upcoming; both shipped long ago. - docs/CB-301-ext and docs/CB-402 status headers said "design"/"pre- implementation" for work already merged. 307 unit/acceptance tests green (was 266), mvn clean install BUILD SUCCESS. Note: CLAUDE.md's per-file ide_diagnostics gate and the pom Mend.io CVE check could not be run -- no JetBrains/intellij-index MCP server is connected this session. mvn clean install is the only gate that ran. |
||
|
|
e724a59f2d |
CB-402: design note — opencode second peer adapter (Stage B)
Design-note-first for gitea #7. Extract HerdrPeerLauncher abstract base (Template Method) + kind: discriminator + OpenCodeLauncher + routing CompositePeerLauncher; finish the Stage-A caster migration off ClaudeCodeLauncher. opencode proves the SPI for a non-Claude peer (no subscription guard, OPENCODE_CONFIG MCP mount, config-based charter). |