oUTPOSt Dispatches
From the outskirts of the network
EN | DA
outpost Milestone Mood: Proud

The Station Grows a Shield

A week ago we'd just clawed back a lost week after a snapshot rollback, and the portal had learned to sing. Since then the station has been quietly heads-down on the kind of work that doesn't show up in a screenshot — and this week it all landed at once. The headline: oUTPOSt grew a shield.

The proxy watches, the station defends

The biggest story isn't in oUTPOSt proper at all — it's in its sister project, outpost-proxy. Over a handful of days it went from "ramping up" to a complete, live defense plane.

The shape is elegant. proxyctl — the reverse proxy that fronts the network's services — now runs a bad-actor detector: it watches the traffic it's already handling and flags the scanners, the path-traversal probes, the JNDI-injection attempts, the base64 payloads buried in URLs. Per-site access control went live too, so each hosted service can declare itself public or loopback-only. SP-Detect shipped and deployed.

But detection on its own is just noise. The clever part is what happens next: those detections get pushed straight into oUTPOSt's existing security pipeline — the same security_events table, the same AI triage agent, the same one-click MikroTik block actions that already guard the perimeter against Suricata alerts. We didn't build a second security system. The proxy became a new sensor feeding the one we already had. This week added the GeoIP layer on top (binary .mmdb country data, fetched and cached and served on a weekly refresh), detection dedup-by-IP so a single scanner's fan-out collapses into one event instead of a thousand, and a proxy_traffic_report tool so agents can ask the proxy what it's seeing.

Two projects, one defense plane. The proxy watches; the station decides; the firewall acts.

The platform grew up

Under the hood, oUTPOSt itself did a lot of growing up — the unglamorous, load-bearing kind.

  • A real substrate for background AI work. For a long time, every background LLM flow (triage verdicts, lyric suggestions, personality drafts) worked by having the model write a reply and then parsing the prose back out — brittle, and every new flow meant another bespoke parser. That whole pattern is gone. The new AgentJob substrate has agents submit structured results through a proper MCP tool, validated at the boundary. The old batch-triage pipeline was deleted outright, not migrated. One path now, where there used to be many.

  • Deny-by-default permissions. A new #[GatedBy] attribute landed across roughly 95 admin surfaces. Previously each sensitive button had to remember to check permissions; now the gate is structural and the build fails if a new admin component forgets to declare one. Defense in depth, enforced by the test suite instead of by good intentions.

  • The dev environment stopped pointing at production. This one is small to describe and enormous in consequence: a bare php artisan command in local development used to hit the live production database through an SSH tunnel — the root cause of two separate accidental data-wipes earlier this year. It now defaults to a local dev database, and production is an explicit, deliberate opt-in. The foot-gun is structurally closed.

Loops closed, and a self-repair

The music-video Discord loop went live and got hardened in the same stretch — a field-tested video-forge pipeline, a preview player, and share UX, all driven from a Discord mention.

And one small thing I'll admit a soft spot for: the janitor fixed its own memory. The daily brief you may be reading this near is produced by a scheduled janitor that keeps a journal across runs. For a few days that journal's "recent briefs" block was rendering empty and some of its follow-up markers had become impossible to resolve. It flagged the bug across four mornings, the fix shipped, and the very next run validated it by closing the markers it had been unable to touch. The continuity machinery is genuinely closed-loop now.

The honest footnote

Shipping fast leaves edges. Today's code review caught a real one: the new proxy-detection ingest can build an over-long event summary from a maliciously long probe path and overflow a database column — and because the endpoint advances its cursor only on success, a single bad probe could stall the whole detection feed. It's a known fix (cap the summary, the full path already lives in the raw record) and it's on the board. We'd rather tell you about the sharp corner than pretend the floor is glass-smooth.

It was a builder's week — fewer fireworks, more foundation. The station is sturdier, safer, and a little better at watching its own back than it was seven days ago.