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 5 assessment | |---|---| | R1-1: flat tenant borrows a nested socket | Fixed by the cgroup check (§5.4). | | R1-2: aliases and path routes remain public | Fixed for attached aliases and path maps (§5.1). Platform-minted route rows present a separate classification gap below. | | R1-3: new box starts public | Fixed by classification before serving and refusal of NULL (§5.1). | | 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 by refusal of unclassified routes before listeners open (§5.1). | | R2-3: flat callers borrow door credentials | Fixed by the door’s UID restriction (§§5.4, 6.2). | | R2-4: deployment verification fails | Ticket mechanism provided (§5.8); its probe-path source has a separate integration gap below. | | 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 at spec level by excluding unisolated execution while armed (§6.2), with historical compromise explicitly outside that guarantee. | | 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 for the reported attack (§6.2). The arming predicate also rejects supported isolated routes; see below. | | R4-2: path routing widens an engine grant | Fixed by exact-host engine dispatch without path routing (§5.4). | | R4-3: watch tickets expire mid-watch | Fixed by renewal every four minutes (§5.8). |

Reviewed spec 50a1f3fc against locally available amadan origin/main at 512baa59. All implementation files cited below match that revision. No files changed.

  1. P2 — Platform-minted hostnames cannot complete classification (§5.1).

Start with an ordinary public instance and its automatically minted <app>.<account>.<apps-domain> hostname. Upgrade the edge. Both rows receive NULL, but the minted row has no live release of its own. Following the specified classifier leaves that hostname refused indefinitely, even with a healthy bucket and a readable source manifest.

Platform domains are separate registry rows: mintedRoute copies the backend into a new Platform: true row without a version (reconcile.go:881). Adoption excludes those rows expressly because they have no independently executed live symlink (adopt.go:1210). The manifest loader returns nothing when that hostname has no live version (caps_pass.go:111). These rows therefore do not inherit the primary upstream through the separate route_aliases fold described in §5.1.

Suggested fix: Define how platform-minted rows resolve to their source route and share its classification and admission barrier. They must remain usable for public sources and become internal before an engine source activates.

  1. P2 — The arming predicate rejects isolated unit-backed routes (§6.2).

Put a granted nested caller and a DynamicUser-backed engine on the same box. Run carlos engines arm. Section 6.2 explicitly permits DynamicUser services, but its requirement that every instance route classify nested rejects the engine. The caller consequently receives no engine socket.

Unit-backed capability routes are still Kind == "instance" (adopt.go:1225, adopt.go:1265). Their standard socket is /run/carlos/apps/<host>.sock (carlos-app@.socket:35). Classify recognises only the flat and nested exec paths, so this route classifies foreign (layout.go:103). Platform-minted instance rows can fail the same test because they copy another hostname’s socket.

Suggested fix: Apply the nested-layout requirement to tenant execution owners using the exec backend. Admit the explicitly permitted isolated unit-backed class separately, and assess generated aliases through their execution owner. Retain the refusal of actual foreign exec launches and workers.

  1. P2 — The home edge has no source for the specified deployment probe path (§5.8).

Configure an internal app’s build probe as /healthz, then deploy it. The CLI polls /healthz, but §5.8 permits only / or “the release’s declared probe path.” No such declaration exists in the release manifest, and the proposed ticket carries only hostname, version and expiry. The home edge cannot establish that /healthz is allowed.

The console reads the probe from its app database and returns it with the ship response (apicli.go:2114, apicli.go:2285). The CLI uses that value (deploy.go:404); release.Manifest contains no probe field (release.go:47).

Suggested fix: Include the authorized probe path in the signed watch ticket, sourced from the same configuration the watcher uses. Define the corresponding signed path for bucket-mode watches.

Overall verdict: accept with fixes. The round-4 security findings are addressed at spec level; these three integration gaps remain.