Spec 027 — Agent telemetry ingestion + reference agent#81
Merged
Conversation
Wires `POST /agent/telemetry` so a Nexus agent on a Docker host can push host + container stats. Builds on spec 026's hashed agent tokens. - AuthenticateAgent middleware (alias `agent.auth`): hashes the Authorization bearer with sha256, looks up an active token, rejects 401 on miss/malformed/revoked/archived-host. Stamps last_used_at after a successful auth + rate-limit pass and attaches the resolved Host + AgentToken to the request attributes. - Per-token rate limit (60 req/min) lives inside the same middleware rather than a separate `throttle:` named limiter, because Laravel's default middleware priority runs ThrottleRequests before unlisted custom middleware — a named limiter keyed off the request attribute would always see null. Returns 429 with Retry-After. - IngestTelemetryRequest validates the full payload + ±1h past / +5min future skew window on `recorded_at`. - IngestHostTelemetryAction wraps in a single transaction: updates host facts (only when present), flips status `pending` → `online`, inserts one host_metric_snapshots row, dispatches container array. - SyncContainerSnapshotsAction upserts containers on (host_id, container_id) and appends one container_metric_snapshots row per entry. Container removal is deferred — missing rows are left intact. - Reference Node agent at agent/reference-agent.mjs (single file, no deps, Node 20+) plus agent/README.md documenting env vars, exit codes, payload contract, and a sample systemd unit. - Tests: 22 new (5 middleware auth cases + last_used_at gating, 7 controller cases incl. 3 rate-limit cases, 4 ingest-action unit tests, 4 container-sync unit tests). Full suite 456 passing. CSRF exclusion for `agent/telemetry` registered alongside the GitHub webhook entry.
- Strip session/cookie/Inertia stack from /agent/telemetry route. Agents are non-browser JSON clients on a 30s heartbeat — leaving the web group middleware on the route would spawn ~144k orphan session rows per day at 50 hosts and emit Set-Cookie on every 204. Verified by a feature test that asserts no cookies on the response. - Skip Online → Online status writes in IngestHostTelemetryAction so every healthy heartbeat doesn't issue a redundant UPDATE. - Add tests: non-string recorded_at (0 / false / []), host-isolation for same container_id on two hosts, status-no-op when already Online, no session middleware on agent endpoint. - Flip spec status to done, tick acceptance criteria, record both implementation deviations (rate-limit-in-middleware, web-stack-strip) in the work log so future readers have the rationale. - Bump phase-6 + master tracker (1/4 → 2/4 specs done). Tests grew 22 → 26 new (full suite 460 passing). Pint clean, build green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #80
Spec: `specs/phase-6-docker-hosts/027-agent-telemetry-ingestion.md`
Summary
POST /agent/telemetrywired with a single `AuthenticateAgent` middleware that does both bearer-token auth and per-token rate limiting (60 req/min/token). Hashing matches spec 026's `AgentToken::hash()`. 401 on missing / malformed / revoked / archived-host. 429 with `Retry-After` on overflow.Test plan
Self-review notes
Self-review pass via `superpowers:code-reviewer` flagged 5 should-fix items + several nice-to-haves. Addressed in commit 4536780:
Implementation deviations from the spec (worth knowing)
Deferred