carlos / platform Public

caps: channel-neutrality assertion — canary/* in, canary/* out

Plan Task 9's laddercheck-style pin: nothing in this design may consult,
constrain, or be constrained by a channel name, the same promise
internal/release/laddercheck_test.go holds for the ladder itself. A capability
change that refused (or even noticed) one of production's live channels would
stop deploys.

Two halves, because neither alone is the whole claim. Structural: no
identifier or literal in internal/caps's own PRODUCTION source (never its
tests) says "channel" or "canary" outside a comment, checked with go/parser
rather than grep so a doc comment stating the rule can never trip the test
that states it — currently zero hits, comments included. Behavioural: this
package's inputs (Plan, Set, Grants, Ops) carry no channel field at all, and
RenderService/RenderSocket take (app, *Set, Grants) only, never a Host — so
converging the same declared+granted set under a Host named for each of
production's four live channels produces byte-identical unit text. The
channel name is sanitized into a legal hostname only so the loop has
something to converge under; it is never a render input.

liveChannels is copied from laddercheck_test.go's list rather than imported —
internal/caps must not depend on internal/release, and importing this test
package the other way would prove nothing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell ee0012bd9693afbaabbcb7bf7fbc74c1b2ba4770 parent 6719db8
1 file changed, +141 −0
  • internal/caps/neutrality_test.go +141 −0
diff --git a/internal/caps/neutrality_test.go b/internal/caps/neutrality_test.go
new file mode 100644
index 000000000..c879e6aa3
--- /dev/null
+++ b/internal/caps/neutrality_test.go
@@ -0,0 +1,141 @@
+package caps
+
+import (
+ "bytes"
+ "go/parser"
+ "go/token"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+// liveChannels mirrors internal/release/laddercheck_test.go's list — the
+// channels production is running on RIGHT NOW. Copied rather than imported:
+// internal/caps must not import internal/release (and importing this test
+// package from there would prove the wrong direction), so four literal
+// strings are cheaper than restructuring either package to share them. If
+// laddercheck_test.go's list ever changes, this one should be re-copied by
+// hand — a shared constant would be one more thing this package would need
+// to import from outside itself.
+var liveChannels = []string{"canary/platform-adoption", "canary/keymail", "canary/console", "canary/rehearsal"}
+
+// TestCapabilitiesNeverConsultAChannelName is this package's half of the
+// design's channel-neutrality claim (spec: "Nothing in this change may
+// consult, constrain, or be constrained by a channel name" — the same
+// promise internal/release/laddercheck_test.go pins for the ladder itself).
+// canary/* in, canary/* out — the fleet runs on those channels and a
+// capability change that refused, favoured, or even NOTICED one would stop
+// deploys production depends on.
+//
+// Two halves, because neither alone is the whole claim:
+//
+// - structural: no identifier or literal in this package's own PRODUCTION
+// source (not its tests) says "channel" or "canary" outside a comment.
+// Parsed with go/parser rather than grepped so that a doc comment
+// EXPLAINING channel-neutrality (as this very comment does) can never
+// trip the test that states it.
+// - behavioural: this package's inputs — Plan, Set, Grants, Ops — carry no
+// channel field to begin with, and RenderService/RenderSocket take
+// (app, *Set, Grants) only, never a Host and never a channel. So a route
+// "on" any of production's four live channels converges byte-identical
+// unit text for the same declared and granted capabilities. Converging
+// the same Plan under a Host named for each channel and diffing the
+// rendered bytes (never the path, which DOES vary by host) is what makes
+// that a test rather than an assertion about code nobody re-reads.
+func TestCapabilitiesNeverConsultAChannelName(t *testing.T) {
+ t.Run("structural", func(t *testing.T) {
+ assertNoChannelWord(t, ".")
+ })
+ t.Run("behavioural", func(t *testing.T) {
+ s := &Set{
+ V: Version, Command: "relay", Daemon: true, Children: true, RuntimeDir: "keymail",
+ Ports: []Port{{Port: 25, Name: "mx"}},
+ Data: &Data{Replicate: DataReplicateApp},
+ HostRole: true,
+ }
+ g := Grants{Ports: map[int]bool{25: true}, HostRole: true}
+
+ var first []byte
+ var firstChannel string
+ for _, ch := range liveChannels {
+ // The channel name is sanitized into a legal hostname ONLY so this
+ // loop has something host-shaped to converge under. Host is not a
+ // render input — RenderService and RenderSocket never take one —
+ // so this is not smuggling the channel in through the back door;
+ // it is the strongest form of "cannot reach it" available: even a
+ // value DERIVED from the channel name, sitting in the one plan
+ // field a channel might plausibly have leaked into, changes
+ // nothing about what gets written.
+ host := "relay-" + strings.NewReplacer("canary/", "", "/", "-").Replace(ch) + ".example.com"
+ etc := t.TempDir()
+ o := Ops{
+ EtcDir: etc,
+ StateRoot: t.TempDir(),
+ Systemctl: func(...string) error { return nil },
+ Query: func(...string) bool { return false },
+ EnsureUser: func(string) error { return nil },
+ }
+ p := Plan{Host: host, App: "keymail", Set: s, Grants: g}
+ if _, err := Converge(o, p); err != nil {
+ t.Fatalf("converge for channel %q: %v", ch, err)
+ }
+ svcPath, _ := DropInPaths(etc, host)
+ body, err := os.ReadFile(svcPath)
+ if err != nil {
+ t.Fatalf("read rendered drop-in for channel %q: %v", ch, err)
+ }
+ if first == nil {
+ first, firstChannel = body, ch
+ continue
+ }
+ if !bytes.Equal(first, body) {
+ t.Errorf("materialized capabilities differ between channel %q and %q for an identical declared+granted set:\n%s\n---\n%s",
+ firstChannel, ch, first, body)
+ }
+ }
+ })
+}
+
+// assertNoChannelWord fails if any non-test .go file directly in dir mentions
+// "channel" or "canary" outside a comment. Comments are found with
+// go/parser's ParseComments and blanked out of the source before the search,
+// so a doc comment stating the neutrality rule (this file's own included)
+// can never be mistaken for a violation of it.
+func assertNoChannelWord(t *testing.T, dir string) {
+ t.Helper()
+ entries, err := os.ReadDir(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ fset := token.NewFileSet()
+ for _, e := range entries {
+ name := e.Name()
+ if e.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
+ continue
+ }
+ path := filepath.Join(dir, name)
+ src, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ file, err := parser.ParseFile(fset, path, src, parser.ParseComments)
+ if err != nil {
+ t.Fatalf("parse %s: %v", path, err)
+ }
+ sanitized := append([]byte(nil), src...)
+ for _, cg := range file.Comments {
+ start := fset.Position(cg.Pos()).Offset
+ end := fset.Position(cg.End()).Offset
+ for i := start; i < end && i < len(sanitized); i++ {
+ sanitized[i] = ' '
+ }
+ }
+ lower := strings.ToLower(string(sanitized))
+ for _, word := range []string{"channel", "canary"} {
+ if strings.Contains(lower, word) {
+ t.Errorf("%s mentions %q outside a comment — internal/caps must never consult or constrain a channel name", name, word)
+ }
+ }
+ }
+}