carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

| Previous finding | Round 8 assessment | |---|---| | R1-1: flat tenant borrows a nested socket | Fixed by the peer-cgroup check (§5.4). | | R1-2: aliases and path routes remain public | Fixed by checking the final upstream (§5.1). | | R1-3: new box starts public | Fixed for the reported missing-mirror case (§5.1). A separate upgrade-classification gap follows below. | | R1-4: revoked grants return after restart | Fixed for retained local state; fresh-box replay remains explicitly accepted (§5.3). | | R1-5: door exceptions fail across routing | Resolved by removing the owner exception and defining the identity transition (§5.4). | | R1-6: socket lifecycle conflicts | Fixed by instance-level listener ownership (§5.4). | | R1-7: transport and body limits | Resolved at spec level (§5.5). | | R2-1: stamp follows serving | Fixed by the admission barrier (§5.1). | | R2-2: upgrade serves unclassified engines | Fixed for the reported declaring-live-manifest case (§5.1). Divergence between installed and running builds remains uncovered below. | | R2-3: flat callers borrow door credentials | Fixed by the door’s UID restriction (§§5.4, 6.2). | | R2-4: deployment verification fails | Fixed by watch tickets (§5.8). | | R2-5: port-80 refusal cannot work remotely | Resolved by the narrowed contract (§5.1). | | R3-1: previously admitted requests cross the mark | Fixed: acknowledgement waits for cancellation and completion (§5.1). | | R3-2: flat tenant injects into a nested caller | Fixed by excluding unisolated execution while armed; historical compromise remains explicitly excluded (§6.2). | | R3-3: grant-only routes lack watch tickets | Fixed: every deploy target receives a ticket (§5.8). | | R4-1: foreign instances and workers remain unisolated | Fixed by the arming prerequisite and launch refusals (§6.2). | | R4-2: path routing widens an engine grant | Fixed by exact-host engine dispatch (§5.4). | | R4-3: watch tickets expire mid-watch | Fixed by renewal every four minutes (§5.8). | | R5-1: platform-minted hostnames cannot classify | Fixed by execution-owner inheritance and the expanded ownership mechanism (§5.1). | | R5-2: arming rejects isolated unit-backed routes | Fixed by distinguishing backing from exec layout (§6.2). | | R5-3: home edge lacks the probe path | Fixed by signing the watcher’s probe path (§5.8). | | R6-1: minted row’s own grant is ignored | Fixed by aggregating grants across the execution-owner group (§5.1). | | R6-2: static platform domains are refused | Fixed by restricting inheritance to minted instance rows (§5.1). | | R7-1: clearing exposes a still-serving generation | Fixed for the reported rollout: clearing waits for activation and declaring generations’ exit (§5.1). | | R7-2: TCP-backed minted rows have no owner | Fixed by recorded ownership and unique, non-empty backend matching, including TCP (§5.1). |

Reviewed spec 9306d7a5 against locally available amadan origin/main at aaa6a949. The implementation files cited below match that revision. No files changed.

  1. P1 — First-upgrade classification bypasses the new activation proof (§§5.1, 6.3).

Run an awake, unit-backed route with hibernation enabled. Its running build A declares doc_engine, but the route holds no doc-engine grant. On the old platform build, the root adoption pass installs non-declaring build B and repoints the live symlink. Before the agent cycles A, the agent crashes. Start the upgraded agent.

The new column is NULL. The startup rule classifies it from B’s live manifest and writes 0, although A still runs. Public requests can consequently reach the declaring build. The new proof requirement applies to clearing an existing 1; the initial NULL→0 classification does not require it.

This installed/running divergence exists on main: root adoption passes a nil restart callback for hibernating routes, including awake ones (internal/release/adopt.go:1174). The manifest loader follows the live symlink (internal/host/caps_pass.go:111). A fresh agent can encounter an already-running unit, and UnitBackend.Start issues systemctl start, which leaves that process running; it also reads the version from the symlink (internal/activator/backend_unit.go:134).

Suggested fix: Require activation evidence before classifying an existing NULL route as public, just as for clearing 1. A non-declaring installed manifest alone is insufficient. Keep the route refused until the execution layer proves that no declaring build remains, or proves it stopped with a non-declaring next-start version.

  1. P2 — A sleeping unit-backed route cannot complete the transition back to public (§5.1).

On an upgraded box, let an internal, unit-backed engine hibernate. It has no remaining group grant. Promote a non-declaring release without running a deployment watch.

Adoption repoints the sleeping route without waking it. The new clearing rule nevertheless requires the unit’s current main process to have started from the new version. There is no main process. The mark therefore stays 1, and public requests are refused before they can wake the non-declaring release. Unlike the nested/exec rule immediately above it, the unit-backed rule has no stopped-instance alternative.

Adoption deliberately preserves sleep (internal/release/adopt.go:1176). Unit-backed tenants have no scheduled wake and sleep until a request (internal/activator/backend_unit.go:174); request-driven wake happens in the dispatch branch that §5.1 places after the refusal (internal/edge/edge.go:1767). The route needs an additional authenticated wake or operator intervention to escape this state.

Suggested fix: Add a unit-backed stopped-state proof: the unit has no remaining processes, its next-start version is non-declaring, and no group grant remains. Permit clearing on that proof without waking it.

Overall verdict: reject. Initial classification can still expose a declaring process during upgrade. The new clearing rule also strands sleeping unit-backed routes.