Files
Gitea-Tools/tests/test_issue_978_instance_fleet_snapshot.py
T
jcwalker3andClaude Opus 4.8 7e19079b5c feat(launcher): trusted client-instance identity for project-scoped launches
Issue #985. The production launcher could mint one trusted
GITEA_MCP_CLIENT_INSTANCE per launch, but two gaps kept real launches on
untrusted legacy-pid-* identities:

1. build_application_mcp_servers required a profile for all five sanctioned
   namespaces, so a project-scoped configuration exposing only author,
   reviewer, and merger could not use it without inventing controller and
   reconciler profiles that must not exist.
2. The module produced configuration data but had no runnable entry point, so
   every real launch bypassed it entirely.

Changes:

- resolve_launch_namespaces() validates an explicit namespace subset as an
  allow-list; unknown, duplicate, and empty selections are refused rather than
  silently narrowing a launch. Omitting it preserves five-namespace behaviour.
- build_application_mcp_servers() accepts that subset, requires profiles only
  for the launched namespaces, starts only those workers, and reports
  excluded_namespaces / project_scoped.
- collect_instance_ids_from_mcp_servers() inspects the launch's own namespaces
  instead of an assumed five, and reports missing_servers, so a three-namespace
  launch can prove shared attribution without reading as two absent workers.
- Runnable entry point: python3 -m mcp_application_launcher mints one trusted
  identity, writes a per-launch 0600 mcpServers config, and execs the client.
  CLIENT_LAUNCH_SPECS is a data-driven registry so other supported clients use
  the same mint-once/propagate-to-all mechanism. --dry-run prints the plan.
- Provenance sealing now fails closed. The inst- format is public and
  reproducible, so format alone could previously let anyone who set one
  environment variable manufacture a trusted identity. Trust now additionally
  requires GITEA_MCP_INSTANCE_PROVENANCE=trusted_launcher, which only the
  launcher writes; a well-formed but unsealed value is classified
  unsealed_launcher and refused, while still being reported for diagnosis.

Deliberate behaviour change: tests/test_issue_978_instance_fleet_snapshot.py
test_client_hints_trusted_when_set previously asserted that a well-formed ID
alone was trusted. It now supplies the launcher seal, and a new companion test
asserts the unsealed case fails closed. This tightens the contract; no
assertion was weakened.

No static or persistent per-project instance IDs are introduced, duplicate
worker and cohort detection are untouched, and no fleet or mutation gate is
relaxed.

Tests: tests/test_issue_985_project_scoped_launcher.py, 47 passed, 3 subtests.
Full suite from a branches/ worktree: 28 failed, 6252 passed, 6 skipped against
a master baseline at 32ab8392 of 28 failed, 6204 passed, 6 skipped; the failing
sets are byte-identical, so zero regressions and zero masked failures.

Closes #985

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-07-31 03:15:53 -05:00

1475 lines
53 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Instance-level fleet identity and health snapshots (#978).
Covers the acceptance criteria for multi-instance fleets: two Codex launches
remain distinct, ten workers attribute correctly, same client_type is not a
duplicate, collisions fail closed, historical rows stay non-blocking, and the
controller/reconciler read surface grants no mutation authority.
All identifiers are synthetic.
"""
from __future__ import annotations
import inspect
import json
import os
import tempfile
import unittest
from datetime import datetime, timedelta, timezone
from typing import Any
from unittest import mock
import mcp_fleet_snapshot as fleet
import mcp_worker_identity as mwi
NOW = datetime(2026, 7, 30, 7, 0, 0, tzinfo=timezone.utc)
TTL = 900.0
NAMESPACES = ("author", "reviewer", "merger", "controller", "reconciler")
def _registry() -> mwi.WorkerRegistry:
handle, path = tempfile.mkstemp(suffix=".sqlite3")
os.close(handle)
os.unlink(path)
return mwi.WorkerRegistry(path)
def _alive(_pid: int | None) -> bool:
return True
def _dead(_pid: int | None) -> bool:
return False
def _register(
registry: mwi.WorkerRegistry,
*,
client: str,
instance: str,
session: str,
generation: str,
namespace: str,
pid: int,
now: datetime = NOW,
ttl: float = TTL,
fleet_run_id: str | None = "run-canary",
status_after: str | None = None,
worker_identity: str | None = None,
process_identity: str | None = None,
repository_binding: str = "/repo/Gitea-Tools",
startup_revision: str = "rev-live",
instance_id_provenance: str = fleet.INSTANCE_ID_PROVENANCE_TRUSTED,
role: str | None = None,
) -> dict[str, Any]:
identity = worker_identity or mwi.generate_worker_identity(
client, f"{session}-{namespace}", now=now, nonce=f"{pid}-{namespace}"
)
outcome = registry.register(
worker_identity=identity,
client_name=client,
client_instance_id=instance,
session_id=session,
generation_id=generation,
role=role or namespace,
profile=f"prgs-{namespace}",
namespace=namespace,
remote="prgs",
repository_binding=repository_binding,
pid=pid,
heartbeat_ttl_seconds=ttl,
now=now,
fleet_run_id=fleet_run_id,
process_identity=process_identity or f"pid-{pid}",
startup_revision=startup_revision,
loaded_revision=startup_revision,
parity_revision=startup_revision,
live_revision=startup_revision,
instance_id_provenance=instance_id_provenance,
pid_alive_probe=_alive,
)
outcome["identity"] = identity
if status_after and outcome.get("registered"):
if status_after == mwi.STATUS_RELEASED:
registry.release(worker_identity=identity, now=now)
elif status_after == mwi.STATUS_SUPERSEDED:
# Direct status write for historical rows.
with registry._tx() as conn: # noqa: SLF001 — test-only fixture
conn.execute(
"UPDATE worker_registrations SET status = ? WHERE worker_identity = ?",
(mwi.STATUS_SUPERSEDED, identity),
)
return outcome
def _five_workers(
registry: mwi.WorkerRegistry,
*,
client: str,
instance: str,
session_prefix: str,
gen_prefix: str,
pid_base: int,
now: datetime = NOW,
) -> list[dict[str, Any]]:
out = []
for i, ns in enumerate(NAMESPACES):
out.append(
_register(
registry,
client=client,
instance=instance,
session=f"{session_prefix}-{ns}",
generation=f"{gen_prefix}-{ns}",
namespace=ns,
pid=pid_base + i,
now=now,
)
)
return out
class InstanceIdentityTests(unittest.TestCase):
def test_generate_distinct_instance_ids(self):
a = fleet.generate_client_instance_id("codex", launch_nonce="a", now=NOW)
b = fleet.generate_client_instance_id("codex", launch_nonce="b", now=NOW)
self.assertNotEqual(a, b)
self.assertTrue(a.startswith("inst-codex-"))
self.assertTrue(fleet.assess_instance_identity(a)["trusted"])
def test_legacy_pid_fallback_not_trusted(self):
a = fleet.assess_instance_identity("pid-1234")
self.assertFalse(a["trusted"])
self.assertEqual(a["provenance"], fleet.INSTANCE_ID_PROVENANCE_LEGACY)
def test_missing_instance_id(self):
a = fleet.assess_instance_identity(None)
self.assertFalse(a["complete"])
self.assertEqual(a["provenance"], fleet.INSTANCE_ID_PROVENANCE_MISSING)
class TwoCodexInstancesTests(unittest.TestCase):
"""AC1AC3: two Codex instances, ten workers, same type not duplicate."""
def test_two_codex_instances_ten_workers(self):
registry = _registry()
inst_a = fleet.generate_client_instance_id("codex", launch_nonce="A", now=NOW)
inst_b = fleet.generate_client_instance_id("codex", launch_nonce="B", now=NOW)
_five_workers(
registry,
client="codex",
instance=inst_a,
session_prefix="sessA",
gen_prefix="genA",
pid_base=1000,
)
_five_workers(
registry,
client="codex",
instance=inst_b,
session_prefix="sessB",
gen_prefix="genB",
pid_base=2000,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(status=None),
now=NOW + timedelta(seconds=10),
pid_alive_probe=_alive,
canonical_repository="/repo/Gitea-Tools",
expected_live_revision="rev-live",
)
self.assertEqual(snap["live_worker_count"], 10)
self.assertEqual(snap["instance_count"], 2)
self.assertIn("codex", snap["multi_instance_same_client_type"])
self.assertEqual(len(snap["multi_instance_same_client_type"]["codex"]), 2)
self.assertTrue(snap["same_client_type_not_duplicate"])
# No finding that treats same client_type alone as a duplicate.
for f in snap["active_blockers"]:
self.assertNotIn("client_type alone", f["detail"].lower())
by_inst = {i["client_instance_id"]: i for i in snap["instances"]}
self.assertEqual(by_inst[inst_a]["worker_count"], 5)
self.assertEqual(by_inst[inst_b]["worker_count"], 5)
self.assertEqual(set(by_inst[inst_a]["namespaces"]), set(NAMESPACES))
self.assertEqual(set(by_inst[inst_b]["namespaces"]), set(NAMESPACES))
self.assertTrue(snap["live_fleet_safe"])
def test_mixed_client_types(self):
registry = _registry()
_five_workers(
registry,
client="codex",
instance="inst-codex-1",
session_prefix="c",
gen_prefix="gc",
pid_base=10,
)
_five_workers(
registry,
client="claude_code",
instance="inst-claude-1",
session_prefix="l",
gen_prefix="gl",
pid_base=20,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=5),
pid_alive_probe=_alive,
)
self.assertEqual(snap["instance_count"], 2)
self.assertTrue(snap["live_fleet_safe"])
class CollisionTests(unittest.TestCase):
def test_live_reuse_of_instance_id_different_client_types(self):
registry = _registry()
shared = "inst-shared-collision"
_register(
registry,
client="codex",
instance=shared,
session="s1",
generation="g1",
namespace="author",
pid=1,
)
# Second client type forced onto same instance id via direct SQL to
# bypass register's same-namespace guard and exercise classification.
with registry._tx() as conn: # noqa: SLF001
conn.execute(
"""
INSERT INTO worker_registrations (
worker_identity, client_name, client_instance_id, session_id,
generation_id, role, profile, namespace, remote,
repository_binding, pid, transport, token_fingerprint,
started_at, last_heartbeat_at, heartbeat_ttl_seconds,
fencing_epoch, status, process_identity, instance_id_provenance
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
""",
(
"claude_code-20260730T070000Z-aaaaaaaaaaaa",
"claude_code",
shared,
"s2",
"g2",
"author",
"prgs-author",
"reviewer",
"prgs",
"/repo/Gitea-Tools",
2,
None,
None,
mwi._ts(NOW), # noqa: SLF001
mwi._ts(NOW), # noqa: SLF001
TTL,
1,
mwi.STATUS_ACTIVE,
"pid-2",
fleet.INSTANCE_ID_PROVENANCE_TRUSTED,
),
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_INSTANCE_ID_COLLISION, classes)
self.assertFalse(snap["live_fleet_safe"])
def test_duplicate_namespace_within_instance(self):
registry = _registry()
inst = "inst-dup-ns"
first = _register(
registry,
client="codex",
instance=inst,
session="s-a",
generation="g-a",
namespace="author",
pid=11,
)
self.assertTrue(first["registered"], first)
# Direct second author under same instance (bypass register guard).
with registry._tx() as conn: # noqa: SLF001
conn.execute(
"""
INSERT INTO worker_registrations (
worker_identity, client_name, client_instance_id, session_id,
generation_id, role, profile, namespace, remote,
repository_binding, pid, transport, token_fingerprint,
started_at, last_heartbeat_at, heartbeat_ttl_seconds,
fencing_epoch, status, process_identity, instance_id_provenance
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
""",
(
"codex-20260730T070000Z-bbbbbbbbbbbb",
"codex",
inst,
"s-b",
"g-b",
"author",
"prgs-author",
"author",
"prgs",
"/repo/Gitea-Tools",
12,
None,
None,
mwi._ts(NOW), # noqa: SLF001
mwi._ts(NOW), # noqa: SLF001
TTL,
2,
mwi.STATUS_ACTIVE,
"pid-12",
fleet.INSTANCE_ID_PROVENANCE_TRUSTED,
),
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_DUPLICATE_NAMESPACE, classes)
def test_register_refuses_duplicate_namespace(self):
registry = _registry()
inst = "inst-reg-dup"
a = _register(
registry,
client="codex",
instance=inst,
session="s1",
generation="g1",
namespace="author",
pid=21,
)
self.assertTrue(a["registered"])
b = _register(
registry,
client="codex",
instance=inst,
session="s2",
generation="g2",
namespace="author",
pid=22,
)
self.assertFalse(b["registered"])
self.assertEqual(b.get("collision_kind"), "duplicate_namespace_worker")
def test_reused_worker_identity(self):
registry = _registry()
identity = mwi.generate_worker_identity("codex", "sess", now=NOW, nonce="fixed")
first = _register(
registry,
client="codex",
instance="inst-1",
session="s1",
generation="g1",
namespace="author",
pid=31,
worker_identity=identity,
)
self.assertTrue(first["registered"])
second = registry.register(
worker_identity=identity,
client_name="codex",
client_instance_id="inst-2",
session_id="s2",
generation_id="g2",
namespace="author",
pid=32,
now=NOW,
pid_alive_probe=_alive,
)
self.assertFalse(second["registered"])
self.assertTrue(second["collision"])
def test_reused_session_identity(self):
registry = _registry()
_register(
registry,
client="codex",
instance="inst-1",
session="shared-session",
generation="g1",
namespace="author",
pid=41,
)
_register(
registry,
client="codex",
instance="inst-2",
session="shared-session",
generation="g2",
namespace="reviewer",
pid=42,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_SESSION_COLLISION, classes)
def test_reused_generation_across_instances(self):
registry = _registry()
_register(
registry,
client="codex",
instance="inst-1",
session="s1",
generation="gen-shared",
namespace="author",
pid=51,
)
_register(
registry,
client="codex",
instance="inst-2",
session="s2",
generation="gen-shared",
namespace="author",
pid=52,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_GENERATION_COLLISION, classes)
def test_reused_pid_and_process_identity(self):
registry = _registry()
_register(
registry,
client="codex",
instance="inst-1",
session="s1",
generation="g1",
namespace="author",
pid=61,
process_identity="proc-same",
)
_register(
registry,
client="codex",
instance="inst-2",
session="s2",
generation="g2",
namespace="reviewer",
pid=61,
process_identity="proc-same",
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_PID_COLLISION, classes)
self.assertIn(fleet.CLASS_PROCESS_COLLISION, classes)
def test_ownership_fencing_collision(self):
registry = _registry()
_register(
registry,
client="codex",
instance="inst-1",
session="s1",
generation="gen-fence",
namespace="author",
pid=71,
)
# Second instance forced onto same generation+epoch via SQL.
with registry._tx() as conn: # noqa: SLF001
conn.execute(
"""
INSERT INTO worker_registrations (
worker_identity, client_name, client_instance_id, session_id,
generation_id, role, profile, namespace, remote,
repository_binding, pid, transport, token_fingerprint,
started_at, last_heartbeat_at, heartbeat_ttl_seconds,
fencing_epoch, status, process_identity, instance_id_provenance
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
""",
(
"codex-20260730T070000Z-cccccccccccc",
"codex",
"inst-2",
"s2",
"gen-fence",
"reviewer",
"prgs-reviewer",
"reviewer",
"prgs",
"/repo/Gitea-Tools",
72,
None,
None,
mwi._ts(NOW), # noqa: SLF001
mwi._ts(NOW), # noqa: SLF001
TTL,
1, # same epoch as first (first got epoch 1)
mwi.STATUS_ACTIVE,
"pid-72",
fleet.INSTANCE_ID_PROVENANCE_TRUSTED,
),
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertTrue(
{fleet.CLASS_OWNERSHIP_COLLISION, fleet.CLASS_GENERATION_COLLISION}
& classes
)
class ManifestAndEdgeTests(unittest.TestCase):
def test_missing_and_unmanifested(self):
registry = _registry()
live = "inst-live"
expected = "inst-expected-missing"
_register(
registry,
client="codex",
instance=live,
session="s",
generation="g",
namespace="author",
pid=81,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
expected_manifest=[
{"client_instance_id": expected, "client_type": "codex"},
],
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
self.assertEqual(snap["missing_expected_instance_ids"], [expected])
self.assertEqual(snap["unmanifested_instance_ids"], [live])
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_MISSING, classes)
self.assertIn(fleet.CLASS_UNMANIFESTED, classes)
def test_unknown_client(self):
registry = _registry()
with registry._tx() as conn: # noqa: SLF001
conn.execute(
"""
INSERT INTO worker_registrations (
worker_identity, client_name, client_instance_id, session_id,
generation_id, role, profile, namespace, remote,
repository_binding, pid, transport, token_fingerprint,
started_at, last_heartbeat_at, heartbeat_ttl_seconds,
fencing_epoch, status, process_identity, instance_id_provenance
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
""",
(
"unknown_client-20260730T070000Z-dddddddddddd",
"unknown_client",
"inst-unk",
"s",
"g",
"author",
"prgs-author",
"author",
"prgs",
"/repo/Gitea-Tools",
91,
None,
None,
mwi._ts(NOW), # noqa: SLF001
mwi._ts(NOW), # noqa: SLF001
TTL,
1,
mwi.STATUS_ACTIVE,
"pid-91",
fleet.INSTANCE_ID_PROVENANCE_TRUSTED,
),
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_UNKNOWN_CLIENT, classes)
def test_foreign_repository(self):
registry = _registry()
_register(
registry,
client="codex",
instance="inst-fr",
session="s",
generation="g",
namespace="author",
pid=101,
repository_binding="/other/repo",
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
canonical_repository="/repo/Gitea-Tools",
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_FOREIGN_REPOSITORY, classes)
def test_old_revision(self):
registry = _registry()
_register(
registry,
client="codex",
instance="inst-old",
session="s",
generation="g",
namespace="author",
pid=111,
startup_revision="rev-old",
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
expected_live_revision="rev-live",
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_OLD_REVISION, classes)
def test_stale_worker(self):
registry = _registry()
_register(
registry,
client="codex",
instance="inst-stale",
session="s",
generation="g",
namespace="author",
pid=121,
now=NOW,
ttl=60.0,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=120),
pid_alive_probe=_dead,
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_STALE_WORKER, classes)
def test_historical_not_active_blocker(self):
registry = _registry()
_register(
registry,
client="codex",
instance="inst-hist",
session="s",
generation="g",
namespace="author",
pid=131,
status_after=mwi.STATUS_RELEASED,
)
_register(
registry,
client="codex",
instance="inst-live",
session="s2",
generation="g2",
namespace="author",
pid=132,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(status=None),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
self.assertEqual(snap["historical_worker_count"], 1)
self.assertTrue(
all(f["classification"] == fleet.CLASS_HISTORICAL for f in snap["historical_findings"])
)
# Only historical finding for the dead row — live fleet otherwise safe.
hist_blockers = [
f
for f in snap["active_blockers"]
if f["classification"] == fleet.CLASS_HISTORICAL
]
self.assertEqual(hist_blockers, [])
self.assertTrue(snap["live_fleet_safe"])
def test_legacy_incomplete_identity(self):
registry = _registry()
_register(
registry,
client="codex",
instance="pid-999",
session="s",
generation="g",
namespace="author",
pid=141,
instance_id_provenance=fleet.INSTANCE_ID_PROVENANCE_LEGACY,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
classes = {f["classification"] for f in snap["active_blockers"]}
self.assertIn(fleet.CLASS_LEGACY_INCOMPLETE, classes)
self.assertFalse(snap["mutation_safe"])
class LifecycleTests(unittest.TestCase):
def test_heartbeat_continuity_across_snapshots(self):
registry = _registry()
outcome = _register(
registry,
client="codex",
instance="inst-hb",
session="s",
generation="g",
namespace="author",
pid=151,
)
identity = outcome["identity"]
earlier = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
later_time = NOW + timedelta(seconds=30)
registry.heartbeat(
worker_identity=identity,
fencing_epoch=outcome["fencing_epoch"],
now=later_time,
expected_session_id="s",
expected_generation_id="g",
expected_client_name="codex",
expected_pid=151,
)
later = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=later_time + timedelta(seconds=1),
pid_alive_probe=_alive,
)
cmp = fleet.compare_snapshot_heartbeats(earlier, later)
self.assertTrue(cmp["stable_ownership"])
self.assertEqual(cmp["shared_live_workers"], [identity])
self.assertTrue(cmp["continuity"][0]["heartbeat_non_decreasing"])
def test_worker_reconnect_preserves_instance(self):
"""Reconnect = heartbeat renew; same instance/worker/session."""
registry = _registry()
o = _register(
registry,
client="codex",
instance="inst-rc",
session="s-rc",
generation="g-rc",
namespace="author",
pid=161,
)
before = registry.get(o["identity"])
registry.heartbeat(
worker_identity=o["identity"],
fencing_epoch=o["fencing_epoch"],
now=NOW + timedelta(seconds=20),
expected_session_id="s-rc",
expected_generation_id="g-rc",
expected_client_name="codex",
expected_pid=161,
)
after = registry.get(o["identity"])
self.assertEqual(before["client_instance_id"], after["client_instance_id"])
self.assertEqual(before["session_id"], after["session_id"])
self.assertEqual(before["worker_identity"], after["worker_identity"])
def test_worker_restart_new_worker_same_instance(self):
registry = _registry()
inst = "inst-restart"
old = _register(
registry,
client="codex",
instance=inst,
session="s-old",
generation="g-old",
namespace="author",
pid=171,
)
registry.release(worker_identity=old["identity"], now=NOW + timedelta(seconds=5))
new = _register(
registry,
client="codex",
instance=inst,
session="s-new",
generation="g-new",
namespace="author",
pid=172,
now=NOW + timedelta(seconds=10),
)
self.assertTrue(new["registered"])
self.assertNotEqual(old["identity"], new["identity"])
snap = fleet.snapshot_instance_fleet(
registry.list_workers(status=None),
now=NOW + timedelta(seconds=15),
pid_alive_probe=_alive,
)
live = [w for w in snap["live_workers"] if w["client_instance_id"] == inst]
self.assertEqual(len(live), 1)
self.assertEqual(live[0]["worker_identity"], new["identity"])
self.assertEqual(snap["historical_worker_count"], 1)
def test_full_application_restart_new_instance(self):
registry = _registry()
old_inst = fleet.generate_client_instance_id("codex", launch_nonce="old", now=NOW)
new_inst = fleet.generate_client_instance_id(
"codex", launch_nonce="new", now=NOW + timedelta(hours=1)
)
for ns, pid in zip(NAMESPACES, range(181, 186)):
o = _register(
registry,
client="codex",
instance=old_inst,
session=f"old-{ns}",
generation=f"oldg-{ns}",
namespace=ns,
pid=pid,
)
registry.release(worker_identity=o["identity"], now=NOW + timedelta(minutes=1))
for ns, pid in zip(NAMESPACES, range(191, 196)):
_register(
registry,
client="codex",
instance=new_inst,
session=f"new-{ns}",
generation=f"newg-{ns}",
namespace=ns,
pid=pid,
now=NOW + timedelta(minutes=2),
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(status=None),
now=NOW + timedelta(minutes=3),
pid_alive_probe=_alive,
)
live_ids = {i["client_instance_id"] for i in snap["instances"]}
self.assertEqual(live_ids, {new_inst})
self.assertEqual(snap["historical_worker_count"], 5)
class PermissionAndSingleClientTests(unittest.TestCase):
def test_single_client_still_supported(self):
registry = _registry()
_five_workers(
registry,
client="codex",
instance="inst-single",
session_prefix="solo",
gen_prefix="solo-g",
pid_base=300,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
self.assertEqual(snap["instance_count"], 1)
self.assertEqual(snap["live_worker_count"], 5)
self.assertTrue(snap["live_fleet_safe"])
self.assertTrue(snap["mutation_safe"])
def test_snapshot_has_consistency_token(self):
registry = _registry()
_register(
registry,
client="codex",
instance="inst-tok",
session="s",
generation="g",
namespace="author",
pid=400,
)
snap = fleet.snapshot_instance_fleet(
registry.list_workers(),
now=NOW + timedelta(seconds=1),
pid_alive_probe=_alive,
)
self.assertTrue(snap["consistency_token"].startswith("fleetrev-"))
self.assertEqual(snap["consistency_token"], snap["registry_revision"])
self.assertIn("snapshot_at", snap)
def test_tool_role_gate_denies_author(self):
import gitea_mcp_server as server
with mock.patch.object(server, "_profile_operation_gate", return_value=[]):
with mock.patch.object(
server,
"get_profile",
return_value={
"profile_name": "prgs-author",
"role": "author",
"allowed_operations": ["gitea.read"],
"forbidden_operations": [],
},
):
result = server.gitea_snapshot_instance_fleet(remote="prgs")
self.assertFalse(result.get("success"))
self.assertEqual(result.get("denied_role"), "author")
self.assertTrue(result.get("read_only"))
self.assertFalse(result.get("mutation_performed", True))
def test_tool_allows_controller(self):
import gitea_mcp_server as server
registry = _registry()
_register(
registry,
client="codex",
instance="inst-ctrl",
session="s",
generation="g",
namespace="controller",
pid=410,
)
with mock.patch.object(server, "_profile_operation_gate", return_value=[]):
with mock.patch.object(
server,
"get_profile",
return_value={
"profile_name": "prgs-controller",
"role": "controller",
"allowed_operations": ["gitea.read"],
"forbidden_operations": [],
},
):
with mock.patch.object(server, "_worker_registry", return_value=registry):
with mock.patch.object(
server, "_current_master_parity", return_value={}
):
result = server.gitea_snapshot_instance_fleet(remote="prgs")
self.assertTrue(result.get("success"), result)
self.assertTrue(result.get("read_only"))
self.assertTrue(result["permission_scope"]["denied_unrelated_mutations"])
self.assertEqual(result["permission_scope"]["granted_operations"], ["gitea.read"])
def test_tool_allows_reconciler(self):
import gitea_mcp_server as server
registry = _registry()
with mock.patch.object(server, "_profile_operation_gate", return_value=[]):
with mock.patch.object(
server,
"get_profile",
return_value={
"profile_name": "prgs-reconciler",
"role": "reconciler",
"allowed_operations": ["gitea.read"],
"forbidden_operations": [],
},
):
with mock.patch.object(server, "_worker_registry", return_value=registry):
with mock.patch.object(
server, "_current_master_parity", return_value={}
):
result = server.gitea_snapshot_instance_fleet(remote="prgs")
self.assertTrue(result.get("success"), result)
def test_capability_map_entry(self):
import task_capability_map as tcm
entry = tcm.TASK_CAPABILITY_MAP["snapshot_instance_fleet"]
self.assertEqual(entry["permission"], "gitea.read")
self.assertEqual(entry["role"], "controller")
self.assertIn("gitea_snapshot_instance_fleet", tcm.TASK_CAPABILITY_MAP)
def test_fleet_run_env_allowlisted(self):
import gitea_config
self.assertIn("GITEA_MCP_FLEET_RUN_ID", gitea_config.RECOGNIZED_GITEA_ENV_KEYS)
def test_docs_exist(self):
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
path = os.path.join(root, "docs", "instance-fleet-identity.md")
self.assertTrue(os.path.isfile(path))
with open(path, encoding="utf-8") as fh:
text = fh.read()
self.assertIn("client_instance_id", text)
self.assertIn("exactly_one_per_profile", text)
self.assertIn("gitea_snapshot_instance_fleet", text)
def test_tool_is_registered(self):
import gitea_mcp_server as server
self.assertTrue(callable(server.gitea_snapshot_instance_fleet))
src = inspect.getsource(server.gitea_snapshot_instance_fleet)
self.assertIn("controller", src)
self.assertIn("reconciler", src)
class ClientHintsTests(unittest.TestCase):
def test_client_hints_legacy_when_unset(self):
import gitea_mcp_server as server
env = {"GITEA_MCP_CLIENT": "codex"}
with mock.patch.dict(os.environ, env, clear=False):
# Ensure instance key is absent.
os.environ.pop("GITEA_MCP_CLIENT_INSTANCE", None)
hints = server._client_identity_hints()
self.assertFalse(hints["instance_identity_trusted"])
self.assertTrue(
str(hints["client_instance_id"]).startswith("legacy-pid-")
or hints["instance_id_provenance"] == fleet.INSTANCE_ID_PROVENANCE_LEGACY
)
def test_client_hints_trusted_when_set(self):
"""Trusted requires the launcher seal as well as the format (#985).
Before #985 a well-formed ``inst-…`` value alone was accepted as
trusted. The format is public and reproducible, so anyone able to set
one environment variable could hand-write a valid-looking ID; #985
therefore additionally requires the provenance marker that only the
production launcher writes. This case now supplies the full sealed env
the launcher actually emits.
"""
import gitea_mcp_server as server
inst = fleet.generate_client_instance_id("codex", launch_nonce="t", now=NOW)
with mock.patch.dict(
os.environ,
{
"GITEA_MCP_CLIENT": "codex",
"GITEA_MCP_CLIENT_INSTANCE": inst,
"GITEA_MCP_INSTANCE_PROVENANCE": (
fleet.INSTANCE_ID_PROVENANCE_TRUSTED
),
"GITEA_MCP_FLEET_RUN_ID": "run-1",
},
clear=False,
):
hints = server._client_identity_hints()
self.assertTrue(hints["instance_identity_trusted"])
self.assertTrue(hints["instance_launcher_sealed"])
self.assertEqual(hints["client_instance_id"], inst)
self.assertEqual(hints["fleet_run_id"], "run-1")
def test_client_hints_wellformed_but_unsealed_not_trusted(self):
"""#985: a valid-looking ID without the launcher seal fails closed."""
import gitea_mcp_server as server
inst = fleet.generate_client_instance_id(
"codex", launch_nonce="unsealed", now=NOW
)
with mock.patch.dict(
os.environ,
{
"GITEA_MCP_CLIENT": "codex",
"GITEA_MCP_CLIENT_INSTANCE": inst,
"GITEA_MCP_FLEET_RUN_ID": "run-1",
},
clear=False,
):
os.environ.pop("GITEA_MCP_INSTANCE_PROVENANCE", None)
hints = server._client_identity_hints()
self.assertFalse(hints["instance_identity_trusted"])
self.assertFalse(hints["instance_launcher_sealed"])
# Still reported for diagnosis rather than silently discarded.
self.assertEqual(hints["client_instance_id"], inst)
self.assertEqual(
hints["instance_id_provenance"],
fleet.INSTANCE_ID_PROVENANCE_UNSEALED,
)
def test_malformed_user_supplied_instance_not_trusted(self):
import gitea_mcp_server as server
with mock.patch.dict(
os.environ,
{
"GITEA_MCP_CLIENT": "codex",
"GITEA_MCP_CLIENT_INSTANCE": "user-spoofed-not-launcher",
},
clear=False,
):
hints = server._client_identity_hints()
self.assertFalse(hints["instance_identity_trusted"])
self.assertEqual(hints["client_instance_id"], "user-spoofed-not-launcher")
class ProductionLauncherB1Tests(unittest.TestCase):
"""#978 review 655 B1: production launcher mints + propagates instance ID."""
def test_one_launch_shares_id_across_five_namespaces(self):
import mcp_application_launcher as launcher
profiles = {ns: f"prgs-{ns}" for ns in NAMESPACES}
built = launcher.build_application_mcp_servers(
profiles,
client_type="codex",
config_path="/cfg/profiles.json",
launch_nonce="launch-one",
now=NOW,
command="/venv/bin/python3",
args=["mcp_server.py"],
)
servers = built["mcpServers"]
self.assertEqual(len(servers), 5)
ids = {
servers[f"gitea-{ns}"]["env"]["GITEA_MCP_CLIENT_INSTANCE"]
for ns in NAMESPACES
}
self.assertEqual(len(ids), 1, ids)
shared = next(iter(ids))
self.assertTrue(fleet.assess_instance_identity(shared)["trusted"])
self.assertEqual(built["client_instance_id"], shared)
# No legacy placeholder on any production worker env.
for ns in NAMESPACES:
env = servers[f"gitea-{ns}"]["env"]
self.assertEqual(env["GITEA_MCP_CLIENT_INSTANCE"], shared)
self.assertEqual(
env["GITEA_MCP_INSTANCE_PROVENANCE"],
fleet.INSTANCE_ID_PROVENANCE_TRUSTED,
)
self.assertEqual(env["GITEA_MCP_CLIENT"], "codex")
self.assertEqual(env["GITEA_CLIENT_MANAGED"], "1")
self.assertFalse(env["GITEA_MCP_CLIENT_INSTANCE"].startswith("legacy-"))
proof = launcher.collect_instance_ids_from_mcp_servers(servers)
self.assertTrue(proof["shared_single_trusted_id"], proof)
def test_two_launches_receive_different_ids(self):
import mcp_application_launcher as launcher
profiles = {ns: f"prgs-{ns}" for ns in NAMESPACES}
a = launcher.build_application_mcp_servers(
profiles,
client_type="codex",
launch_nonce="L1",
now=NOW,
command="python3",
args=["mcp_server.py"],
)
b = launcher.build_application_mcp_servers(
profiles,
client_type="codex",
launch_nonce="L2",
now=NOW,
command="python3",
args=["mcp_server.py"],
)
self.assertNotEqual(a["client_instance_id"], b["client_instance_id"])
def test_resume_reuses_supplied_trusted_id(self):
import mcp_application_launcher as launcher
profiles = {ns: f"prgs-{ns}" for ns in NAMESPACES}
first = launcher.build_application_mcp_servers(
profiles,
client_type="claude_code",
launch_nonce="resume-src",
now=NOW,
command="python3",
args=["mcp_server.py"],
)
resumed = launcher.build_application_mcp_servers(
profiles,
client_type="claude_code",
client_instance_id=first["client_instance_id"],
command="python3",
args=["mcp_server.py"],
)
self.assertEqual(first["client_instance_id"], resumed["client_instance_id"])
def test_refuses_untrusted_instance_id_on_production_path(self):
import mcp_application_launcher as launcher
profiles = {ns: f"prgs-{ns}" for ns in NAMESPACES}
with self.assertRaises(ValueError):
launcher.build_application_mcp_servers(
profiles,
client_type="codex",
client_instance_id="pid-999",
command="python3",
args=["mcp_server.py"],
)
with self.assertRaises(ValueError):
launcher.namespace_worker_env(
profile_name="prgs-author",
client_type="codex",
client_instance_id="user-supplied-garbage",
)
def test_extra_env_cannot_override_trusted_instance_keys(self):
import mcp_application_launcher as launcher
trusted = fleet.generate_client_instance_id(
"codex", launch_nonce="seal", now=NOW
)
env = launcher.namespace_worker_env(
profile_name="prgs-author",
client_type="codex",
client_instance_id=trusted,
extra_env={
"GITEA_MCP_CLIENT_INSTANCE": "inst-spoofed-20260730T000000Z-deadbeefdead",
"GITEA_MCP_INSTANCE_PROVENANCE": "trusted_launcher",
"GITEA_CLIENT_MANAGED": "0",
"GITEA_MCP_CLIENT": "gemini",
"GITEA_AUTHOR_WORKTREE": "/ok/extra",
},
)
self.assertEqual(env["GITEA_MCP_CLIENT_INSTANCE"], trusted)
self.assertEqual(env["GITEA_CLIENT_MANAGED"], "1")
self.assertEqual(env["GITEA_MCP_CLIENT"], "codex")
self.assertEqual(env["GITEA_AUTHOR_WORKTREE"], "/ok/extra")
def test_gitea_config_launcher_entry_uses_production_path(self):
"""Production launcher_entry — not a test helper — mints trusted IDs."""
import gitea_config
entry_a = gitea_config.launcher_entry(
"prgs-author",
"/cfg/profiles.json",
client_type="codex",
launch_nonce="cfg-a",
)["gitea-tools"]
entry_b = gitea_config.launcher_entry(
"prgs-author",
"/cfg/profiles.json",
client_type="codex",
launch_nonce="cfg-b",
)["gitea-tools"]
id_a = entry_a["env"]["GITEA_MCP_CLIENT_INSTANCE"]
id_b = entry_b["env"]["GITEA_MCP_CLIENT_INSTANCE"]
self.assertNotEqual(id_a, id_b)
self.assertTrue(fleet.assess_instance_identity(id_a)["trusted"])
self.assertTrue(fleet.assess_instance_identity(id_b)["trusted"])
def test_multi_namespace_launcher_entries_api(self):
import gitea_config
profiles = {ns: f"prgs-{ns}" for ns in NAMESPACES}
built = gitea_config.multi_namespace_launcher_entries(
profiles,
client_type="grok",
config_path="/cfg/profiles.json",
launch_nonce="multi-api",
)
self.assertTrue(built["shared_instance_id_across_namespaces"])
self.assertEqual(built["namespace_count"], 5)
proof = __import__(
"mcp_application_launcher", fromlist=["*"]
).collect_instance_ids_from_mcp_servers(built["mcpServers"])
self.assertTrue(proof["shared_single_trusted_id"], proof)
def test_malformed_and_missing_fail_safely(self):
self.assertFalse(fleet.assess_instance_identity("")["trusted"])
self.assertFalse(fleet.assess_instance_identity(None)["trusted"])
self.assertFalse(fleet.assess_instance_identity("legacy-pid-1")["trusted"])
self.assertFalse(fleet.assess_instance_identity("not-an-inst-id")["trusted"])
self.assertFalse(fleet.assess_instance_identity("inst-")["trusted"])
self.assertFalse(fleet.assess_instance_identity("user-spoofed")["trusted"])
# Reserved inst- prefix from the launcher is trusted.
self.assertTrue(fleet.assess_instance_identity("inst-codex-1")["trusted"])
class InstanceAwareMutationGateB2Tests(unittest.TestCase):
"""#978 review 655 B2: mutation gate is instance-aware, not profile-only."""
def _ps_lines(self, rows):
# rows: list of (pid, lstart, command) — command ignored beyond mcp_server.py
header = " PID LSTART COMMAND\n"
body = "".join(
f"{pid} {lstart} /path/to/python mcp_server.py\n"
for pid, lstart, _env in rows
)
return header + body
def _side_effect(self, rows, *, self_pid=1000):
ps_out = self._ps_lines(rows)
env_by_pid = {str(pid): env for pid, _ls, env in rows}
def side_effect(args, **kwargs):
mock_run = mock.MagicMock()
if args[0] == "ps" and "eww" in args:
mock_run.stdout = env_by_pid.get(str(args[2]), "")
return mock_run
if args[0] == "ps":
mock_run.stdout = ps_out
return mock_run
if args[0] == "git":
mock_run.stdout = "deadbeef"
return mock_run
raise ValueError(args)
return side_effect
def test_two_valid_instances_same_profile_allowed(self):
import gitea_mcp_server as server
inst_a = fleet.generate_client_instance_id(
"codex", launch_nonce="gate-a", now=NOW
)
inst_b = fleet.generate_client_instance_id(
"codex", launch_nonce="gate-b", now=NOW
)
lstart = "Wed Jul 8 15:00:00 2026"
rows = [
(
2001,
lstart,
(
f"GITEA_MCP_PROFILE=prgs-author GITEA_CLIENT_MANAGED=1 "
f"GITEA_MCP_CLIENT_INSTANCE={inst_a} "
f"GITEA_MCP_WORKER_IDENTITY=worker-a "
f"GITEA_MCP_GENERATION_ID=gen-a"
),
),
(
2002,
lstart,
(
f"GITEA_MCP_PROFILE=prgs-author GITEA_CLIENT_MANAGED=1 "
f"GITEA_MCP_CLIENT_INSTANCE={inst_b} "
f"GITEA_MCP_WORKER_IDENTITY=worker-b "
f"GITEA_MCP_GENERATION_ID=gen-b"
),
),
]
with mock.patch("subprocess.run") as mock_run, mock.patch(
"os.path.getmtime", return_value=datetime(2026, 7, 8, 11, 0, 0).timestamp()
), mock.patch("os.path.exists", return_value=True), mock.patch(
"os.getpid", return_value=9999
):
mock_run.side_effect = self._side_effect(rows)
reasons = server._check_mcp_runtimes_diagnostics(
"create_issue", ["prgs-author"]
)
self.assertFalse(
any("Duplicate MCP server process(es) detected" in r for r in reasons),
reasons,
)
def test_duplicate_same_instance_and_namespace_blocked(self):
import gitea_mcp_server as server
inst = fleet.generate_client_instance_id(
"codex", launch_nonce="dup", now=NOW
)
lstart = "Wed Jul 8 15:00:00 2026"
rows = [
(
3001,
lstart,
(
f"GITEA_MCP_PROFILE=prgs-author GITEA_CLIENT_MANAGED=1 "
f"GITEA_MCP_CLIENT_INSTANCE={inst} "
f"GITEA_MCP_WORKER_IDENTITY=worker-1 "
f"GITEA_MCP_GENERATION_ID=gen-1"
),
),
(
3002,
lstart,
(
f"GITEA_MCP_PROFILE=prgs-author GITEA_CLIENT_MANAGED=1 "
f"GITEA_MCP_CLIENT_INSTANCE={inst} "
f"GITEA_MCP_WORKER_IDENTITY=worker-2 "
f"GITEA_MCP_GENERATION_ID=gen-2"
),
),
]
with mock.patch("subprocess.run") as mock_run, mock.patch(
"os.path.getmtime", return_value=datetime(2026, 7, 8, 11, 0, 0).timestamp()
), mock.patch("os.path.exists", return_value=True), mock.patch(
"os.getpid", return_value=9999
):
mock_run.side_effect = self._side_effect(rows)
reasons = server._check_mcp_runtimes_diagnostics(
"create_issue", ["prgs-author"]
)
self.assertTrue(
any("Duplicate MCP server process(es) detected" in r for r in reasons),
reasons,
)
self.assertTrue(
any("duplicate namespace" in r.lower() or "client_instance_id" in r for r in reasons),
reasons,
)
def test_missing_instance_evidence_still_fail_closed(self):
"""Two profile-sharing processes without trusted IDs remain blocked."""
import gitea_mcp_server as server
lstart = "Wed Jul 8 15:00:00 2026"
rows = [
(
4001,
lstart,
"GITEA_MCP_PROFILE=prgs-author GITEA_CLIENT_MANAGED=1",
),
(
4002,
lstart,
"GITEA_MCP_PROFILE=prgs-author GITEA_CLIENT_MANAGED=1",
),
]
with mock.patch("subprocess.run") as mock_run, mock.patch(
"os.path.getmtime", return_value=datetime(2026, 7, 8, 11, 0, 0).timestamp()
), mock.patch("os.path.exists", return_value=True), mock.patch(
"os.getpid", return_value=9999
):
mock_run.side_effect = self._side_effect(rows)
reasons = server._check_mcp_runtimes_diagnostics(
"create_issue", ["prgs-author"]
)
self.assertTrue(
any("Duplicate MCP server process(es) detected" in r for r in reasons),
reasons,
)
def test_single_instance_still_ok(self):
import gitea_mcp_server as server
inst = fleet.generate_client_instance_id(
"codex", launch_nonce="single", now=NOW
)
lstart = "Wed Jul 8 15:00:00 2026"
rows = [
(
5001,
lstart,
(
f"GITEA_MCP_PROFILE=prgs-author GITEA_CLIENT_MANAGED=1 "
f"GITEA_MCP_CLIENT_INSTANCE={inst} "
f"GITEA_MCP_WORKER_IDENTITY=worker-only "
f"GITEA_MCP_GENERATION_ID=gen-only"
),
),
]
with mock.patch("subprocess.run") as mock_run, mock.patch(
"os.path.getmtime", return_value=datetime(2026, 7, 8, 11, 0, 0).timestamp()
), mock.patch("os.path.exists", return_value=True), mock.patch(
"os.getpid", return_value=9999
):
mock_run.side_effect = self._side_effect(rows)
reasons = server._check_mcp_runtimes_diagnostics(
"create_issue", ["prgs-author"]
)
self.assertFalse(
any("Duplicate MCP server process(es) detected" in r for r in reasons),
reasons,
)
if __name__ == "__main__":
unittest.main()