security

package
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: MIT Imports: 8 Imported by: 0

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

View Source
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.

View Source
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

View Source
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

func LoadGraph() (*Graph, error)

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

func (g *Graph) FindFunc(pkgPath, name string) (string, bool)

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

func (g *Graph) FindSpawnReachable() []Violation

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

func (g *Graph) HandlerCount() int

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

func (g *Graph) Reaches(from, to string) ([]string, bool)

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.

func (Violation) String

func (v Violation) String() string

String renders the violation as the path a reviewer needs to see. Printing the chain rather than just the endpoints is the difference between a test that reports a problem and a test that helps fix one — the fix is almost always at an intermediate hop, not at either end.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL