Skip to content

atom-fetcher: drift detection + atty doctor surface #209

@fentas

Description

@fentas

Follow-up to PR #208 (closes #202). The atom-fetcher's opt-in pinning landed in #208 with the trust-model improvements (caps, perm gate, deny_unknown_fields, hard-fail on typo, per-tick reload). Drift detection — telling operators when their pin is N commits behind upstream — is the UX layer that makes pinning practical to maintain without external tooling.

Agreed design (from PR #208 review discussion)

Detection

Lightweight head-SHA probe per source, once per cron tick:

```
GET https://api.github.com/repos///commits/master?per_page=1
→ .sha (~1 KB JSON response, unauthenticated, 60 req/h limit, plenty for 6h cadence)
```

Compare to `cfg.pins..commit` (pinned mode) or to the previous tick's seen SHA (live-tracking mode, optional drift telemetry).

State

`/var/lib/atty-guard/atoms.drift.json` — daemon-written, atty:atty 0640:

```json
{
"updated_at": "2026-05-22T10:00:00Z",
"sources": [
{
"name": "gtfobins",
"pinned": "7382261ef936e35896ba70e7a6b833352ffb9a22",
"upstream": "5dc1f4a8a1b2c3d4e5f6789012345678901234ab",
"behind_since": "2026-05-20T14:33:00Z"
}
]
}
```

Surfaces

  1. `atty-guard atoms status` (CLI) — reads atoms.drift.json (or via UDS for non-root callers), prints per-source: pinned/last-seen, upstream HEAD, days behind. Exit 0 in-sync, 1 if drift.
  2. `atoms_drift` UDS RPC — read-only request/response shape `{"method":"atoms_drift"}` → `{"type":"atoms_drift","sources":[...]}`. No SO_PEERCRED auth gate (read-only).
  3. journald WARNING on first drift transition (in-sync → behind). Throttled to once per drift window so the log doesn't fill up.
  4. `atty doctor` integration — extend the doctor command (Zig side) to query `atoms_drift` and print a yellow line when a source is behind its pin. Falls back silently if daemon unreachable.

Deferred (`atoms_drift` is read-only so simple; `atty-guard atoms status` builds on existing UDS client; the journald + atty doctor pieces follow standard patterns).

Why not in #208

Splitting kept #208 focused on the security improvements (caps, perm gate, opt-in pinning with digest verify, doc honesty). Drift detection is UX over a security feature that already works manually (`gh api .../commits/master` + diff the SHA against the pin file). Different review surface; one PR per concept.

Acceptance

  • `atoms.drift.json` written after each successful cron tick.
  • `atoms_drift` UDS RPC returns the same shape as the JSON file.
  • `atty-guard atoms status` reads via direct file OR UDS, prints human-readable report, exits 0/1 by drift state.
  • `atty doctor` prints yellow drift line when applicable.
  • journald breadcrumb on first drift transition, throttled.
  • Tests cover: drift JSON round-trip; UDS RPC parse; `atty-guard atoms status` exit codes; transition-throttle behavior.

Tracker: this issue. Parent: #205.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions