Refuse an action where it was written, not on the machine

A module may not declare an action: the link may not carry a command to
run, and that bound is what limits a compromised control plane to shapes
it cannot turn into arbitrary code (novox/hq ADR 0005). The host
enforces it, correctly and in the right place.

But a module's resources reach a machine over the link, so a manifest
carrying an action was accepted here, stored, resolved, planned and
pushed — and refused on the machine, in the host's log, with nothing
connecting it back to the manifest that caused it.

The rule held. It was just unusable, which is the same shape as the
network shape earlier today: the refusal was right, arrived far from its
cause, and nobody was reading the log.

The refusal names the rule and what to do instead, because "you may not"
with no alternative is where a module author stops.

Found while checking a claim I had written in the coverage document —
that a module cannot declare one. It could; it just could not deliver
it. The document is corrected.
This commit is contained in:
2026-09-01 02:55:56 +02:00
parent be2dca27ab
commit 96f90ab986
2 changed files with 58 additions and 0 deletions
+22
View File
@@ -573,6 +573,28 @@ func ParseManifest(raw []byte) (Manifest, error) {
m.Module, c.Authority))
}
}
// **A module may not declare an action, and this is where it is said** (novox/hq ADR 0005).
//
// The host already refuses one, correctly and for the right reason: the link may not carry a
// command to run, and that bound is what limits a compromised control plane to shapes it
// cannot turn into arbitrary code. But a module's resources reach a machine over the link, so
// a manifest carrying an action was accepted here, stored, resolved, planned and pushed — and
// refused on the machine, in the host's log, with nothing connecting it back to the manifest
// that caused it.
//
// That is the same failure as the network shape earlier today: the refusal was right, arrived
// far from its cause, and nobody was reading the log. A rule enforced only at the far end is
// enforced; it is just not usable.
for _, r := range m.Resources {
if fmt.Sprint(r["type"]) != "action" {
continue
}
problems = append(problems, fmt.Sprintf(
"%s declares %v, which is an action, and a module may not: the link may not carry a "+
"command to run (novox/hq ADR 0005). A module that needs something done ships a "+
"program that reads what the mesh delivered and reconciles",
m.Module, r["id"]))
}
for name, where := range m.OwnSecrets {
if !strings.HasPrefix(where, "/") {
problems = append(problems, fmt.Sprintf(
+36
View File
@@ -37,3 +37,39 @@ func TestARoleNameIsFineWhereTheConsumerCannotTellTheDifference(t *testing.T) {
}
}
}
// A module may not declare an action, and it is refused where it was written.
//
// The host refuses one arriving over the link, which is the bound the whole security argument
// rests on (novox/hq ADR 0005) and is enforced in the right place. But a module's resources reach
// a machine *over* the link, so a manifest carrying an action used to be accepted here, stored,
// resolved and pushed — and then refused on the machine, in a log, with nothing tying it back to
// the manifest. Enforced at the far end only is enforced and not usable.
func TestAModuleMayNotDeclareAnAction(t *testing.T) {
_, err := ParseManifest([]byte(`{"module":"probe","version":"1","resources":[
{"id":"migrate","type":"action","command":["/bin/true"],"verify":["/bin/true"]}]}`))
if err == nil {
t.Fatal("a manifest declaring an action was accepted, and the machine would refuse it")
}
if !strings.Contains(err.Error(), "may not") || !strings.Contains(err.Error(), "0005") {
t.Errorf("the refusal does not say what rule it is: %v", err)
}
// And it says what to do instead, because "you may not" without an alternative is where a
// module author stops.
if !strings.Contains(err.Error(), "ships a program") {
t.Errorf("the refusal names no alternative: %v", err)
}
}
// Every other shape a module may declare still passes, so the check above bounds one thing.
func TestTheOtherShapesAreStillAccepted(t *testing.T) {
_, err := ParseManifest([]byte(`{"module":"probe","version":"1","resources":[
{"id":"d","type":"directory","path":"/var/lib/probe","mode":"0700"},
{"id":"f","type":"file","path":"/var/lib/probe/x","content":"x\n"},
{"id":"n","type":"network","name":"probe"},
{"id":"c","type":"container","name":"probe","image":"probe@sha256:` +
`0000000000000000000000000000000000000000000000000000000000000000"}]}`))
if err != nil {
t.Fatalf("an ordinary manifest was refused: %v", err)
}
}