Documentation
¶
Overview ¶
Package security is an executable specification of cloop's threat model.
The security guarantees this suite protects are stated in prose in the README and enforced in code across four packages that do not import each other: pkg/executor (the host-execution policy), pkg/secretbroker (scoped credential grants), pkg/executorstore (enrollment token persistence), and pkg/ui (the control plane that must never execute anything itself). Nothing in that arrangement fails loudly when a refactor quietly reconnects the UI to os/exec, widens a container's privileges, or lets an expired lease redeem. A guarantee that only exists in prose is a guarantee that regresses silently.
So these tests assert the properties directly, at the boundary a reviewer would check by hand: not "does this function work" but "is it still impossible to reach exec.Command from an HTTP handler". They live outside the packages they audit on purpose — an external test can only use the exported surface, which is the same surface an attacker and an embedder see, and it cannot be weakened by a change to package internals without that change being visible here.
This file implements the static reachability analysis behind guarantee (1). The rest of the suite is behavioral.
Index ¶
Constants ¶
const ExecutorBoundary = ModulePath + "/pkg/executor"
ExecutorBoundary is the one package tree permitted to spawn processes.
The whole architecture rests on this being the only door: a driver under pkg/executor knows *where* a workload runs (this host, a container, a remote agent) and is the only code entitled to decide. Everything upstream of it speaks in Specs and Handles. Traversal stops here rather than treating it as a violation, which is what makes this a boundary check and not a ban.
const ModulePath = "github.com/blechschmidt/cloop"
ModulePath is the import path prefix of this module. Everything outside it is a dependency we do not audit.
Variables ¶
var AuditedRoots = []string{ ModulePath + "/pkg/ui", ModulePath + "/pkg/apiserver", }
AuditedRoots are the packages whose HTTP handlers must not reach process execution. Both terminate network requests from potentially untrusted callers, so both inherit the same obligation.
Functions ¶
This section is empty.
Types ¶
type Graph ¶
type Graph struct {
// contains filtered or unexported fields
}
Graph is a whole-module function reference graph.
func LoadGraph ¶
LoadGraph type-checks every package in the module and builds the reference graph.
It deliberately loads the whole module rather than just the audited packages: the interesting violations are transitive, hiding two or three hops away in a helper package that shells out to git, and a check that only reads pkg/ui would never see them.
func (*Graph) FindFunc ¶
FindFunc returns the graph key for a function declared in pkgPath.
name may be a plain function ("forget") or a method ("(*Agent).forget" is matched by "forget" too, since a package rarely declares both). The lookup is by suffix rather than by an assembled FullName because the receiver's rendering — pointer, alias, type parameters — is a detail a test should not have to reproduce exactly.
func (*Graph) FindSpawnReachable ¶
FindSpawnReachable returns every audited handler that transitively reaches process execution outside the executor boundary.
Search is breadth-first so the reported path is the shortest one, which is almost always the one that explains the violation best. Packages under pkg/executor terminate the search: reaching a driver is the intended architecture, and the drivers spawn processes because that is their job.
func (*Graph) HandlerCount ¶
HandlerCount reports how many HTTP handlers were discovered, so a test can refuse to pass vacuously when a refactor renames or moves them all.
func (*Graph) Reaches ¶
Reaches reports whether `to` is reachable from `from`, returning the path.
Same reference-graph semantics as FindSpawnReachable: taking a function's address counts as an edge. For a "the wipe is reachable" assertion that over-approximates in the *unsafe* direction, so the path is returned for the test to print and a human to sanity-check rather than trusted blindly.
type Violation ¶
type Violation struct {
Handler string
// Path is the chain of functions from handler to spawn, inclusive.
Path []string
// Spawn is the display name of the offending stdlib call.
Spawn string
}
Violation is one HTTP handler that can reach a process-spawning call without passing through the executor boundary.