no-mistakes(review): Harden GC gate key aliases, fail closed, fix baseline

This commit is contained in:
root
2026-09-12 18:42:36 +00:00
parent 4ea2d0309f
commit de1428b4ae
3 changed files with 31 additions and 8 deletions
+2 -1
View File
@@ -24,11 +24,12 @@ done
| Agent | CT | Node | IP | LiteLLM Alias | Key Source | Platform | | Agent | CT | Node | IP | LiteLLM Alias | Key Source | Platform |
|-------|-----|------|-----|---------------|------------|----------| |-------|-----|------|-----|---------------|------------|----------|
| Koby | 111 | amdpve | .129 | `koby` | Infisical vault | **Hermes** | | Koby | 111 | storepve | .129 | `koby` | Infisical vault | **Hermes** |
| Koonimo | 113 | amdpve | .114 | `koonimo` | Infisical vault | Hermes | | Koonimo | 113 | amdpve | .114 | `koonimo` | Infisical vault | Hermes |
| Shumba | — | 192.168.68.119 | N/A | N/A (DeepSeek) | Hermes (RETIRED — CT119 now Infisical vault) | | Shumba | — | 192.168.68.119 | N/A | N/A (DeepSeek) | Hermes (RETIRED — CT119 now Infisical vault) |
> **Note**: CT hostnames (tdunna→CT111, baggy→CT113) differ from agent identities (koby, koonimo). > **Note**: CT hostnames (tdunna→CT111, baggy→CT113) differ from agent identities (koby, koonimo).
> CT 111 (tdunna, 192.168.68.129, storepve) is report-only — Theo's box; alert only, never garbage-collect.
Access: `pct-run <CT_ID> <command>` — no IPs needed. GPU hosts (.8, .110, .15) use SSH. Access: `pct-run <CT_ID> <command>` — no IPs needed. GPU hosts (.8, .110, .15) use SSH.
Keys are stored in Infisical vault (project=agents, env=production) and injected at Keys are stored in Infisical vault (project=agents, env=production) and injected at
+18 -6
View File
@@ -22,7 +22,8 @@ Usage:
cat scan.json | disk-gc-plan.py # same, via stdin cat scan.json | disk-gc-plan.py # same, via stdin
disk-gc-plan.py --scan scan.json --json # machine-readable plan disk-gc-plan.py --scan scan.json --json # machine-readable plan
Scan entries may carry any of: id / guest / vmid, hostname / name, ip. Scan entries may carry any of: id / guest / vmid / ct / ctid, hostname / name, ip.
A threshold-crossing entry with no recognizable identity is reported, never GC'd.
Exit codes: 0 ok, 1 usage/parse error. Exit codes: 0 ok, 1 usage/parse error.
""" """
from __future__ import annotations from __future__ import annotations
@@ -40,6 +41,9 @@ DEFAULT_CONTRACT = REPO / "disk-gc-threat-response.prose.md"
AMBER, RED, CRITICAL = 75, 85, 95 AMBER, RED, CRITICAL = 75, 85, 95
IDENTITY_FIELDS = ("id", "guest", "vmid", "ct", "ctid", "hostname", "name", "ip")
UNIDENTIFIED_REASON = "unidentified target - refusing to schedule GC"
def load_report_only_guests(contract_path: pathlib.Path) -> list[dict]: def load_report_only_guests(contract_path: pathlib.Path) -> list[dict]:
"""Read the authoritative report_only_guests block out of the contract. """Read the authoritative report_only_guests block out of the contract.
@@ -64,7 +68,7 @@ def _keys(entry: dict) -> set[str]:
"""Guest/host identity keys, shared by exclusions and scan entries so the two """Guest/host identity keys, shared by exclusions and scan entries so the two
sides of the gate can never key on different fields.""" sides of the gate can never key on different fields."""
out: set[str] = set() out: set[str] = set()
for field in ("guest", "id", "vmid", "hostname", "name", "ip"): for field in IDENTITY_FIELDS:
value = entry.get(field) value = entry.get(field)
if value is not None and str(value).strip(): if value is not None and str(value).strip():
out.add(str(value).strip().lower()) out.add(str(value).strip().lower())
@@ -92,12 +96,20 @@ def build_plan(scan: list[dict], report_only: list[dict]) -> list[dict]:
if level is None: if level is None:
continue # GREEN: log only, no action continue # GREEN: log only, no action
scan_keys = _keys(entry) scan_keys = _keys(entry)
match = next((e for e, keys in excluded if keys & scan_keys), None)
target = next( target = next(
(entry.get(k) for k in ("id", "guest", "vmid", "hostname", "name", "ip") (entry.get(k) for k in IDENTITY_FIELDS if entry.get(k) not in (None, "")),
if entry.get(k) not in (None, "")),
"?", "?",
) )
if not scan_keys:
plan.append({
"target": target,
"level": level,
"pct": float(pct),
"action": "report-only",
"reason": UNIDENTIFIED_REASON,
})
continue
match = next((e for e, keys in excluded if keys & scan_keys), None)
if match is not None: if match is not None:
plan.append({ plan.append({
"target": target, "target": target,
@@ -119,7 +131,7 @@ def build_plan(scan: list[dict], report_only: list[dict]) -> list[dict]:
def main() -> int: def main() -> int:
ap = argparse.ArgumentParser(description="Plan disk GC actions with the report-only gate.") ap = argparse.ArgumentParser(description="Plan disk GC actions with the report-only gate.")
ap.add_argument("--scan", help="JSON file: list of {id|hostname|ip, usage_pct}") ap.add_argument("--scan", help="JSON file: list of {id|ct|hostname|ip, usage_pct}")
ap.add_argument("--contract", default=str(DEFAULT_CONTRACT)) ap.add_argument("--contract", default=str(DEFAULT_CONTRACT))
ap.add_argument("--json", action="store_true", help="emit the plan as JSON") ap.add_argument("--json", action="store_true", help="emit the plan as JSON")
args = ap.parse_args() args = ap.parse_args()
+11 -1
View File
@@ -51,8 +51,10 @@ def test_excluded_guest_never_gets_gc_at_any_level(tmp_path):
def test_exclusion_matches_on_any_identity_key(tmp_path): def test_exclusion_matches_on_any_identity_key(tmp_path):
"""The gate is keyed on guest/host, so id, hostname or IP all match.""" """The gate is keyed on guest/host, so id, ct, ctid, hostname or IP all match."""
for entry in ({"id": 111, "usage_pct": 95}, for entry in ({"id": 111, "usage_pct": 95},
{"ct": 111, "usage_pct": 95},
{"ctid": 111, "usage_pct": 95},
{"hostname": "tdunna", "usage_pct": 95}, {"hostname": "tdunna", "usage_pct": 95},
{"ip": "192.168.68.129", "usage_pct": 95}): {"ip": "192.168.68.129", "usage_pct": 95}):
plan = _plan([entry], tmp_path) plan = _plan([entry], tmp_path)
@@ -78,6 +80,14 @@ def test_agent_name_alone_does_not_gate_a_guest(tmp_path):
assert plan and plan[0]["action"] == "gc-executor" assert plan and plan[0]["action"] == "gc-executor"
def test_unidentified_threat_fails_closed(tmp_path):
"""A threshold-crossing entry with no recognized identity must not schedule GC."""
plan = _plan([{"usage_pct": 97}], tmp_path)
assert plan, "an unidentified threat must still be reported"
assert plan[0]["action"] == "report-only", plan
assert plan[0]["reason"], plan
def _plan_with_contract(scan, contract_text, tmp_path, name): def _plan_with_contract(scan, contract_text, tmp_path, name):
contract = tmp_path / name contract = tmp_path / name
contract.write_text(contract_text) contract.write_text(contract_text)