carlos / platform Public

release: the per-app production flag — root-signed, missing means not production

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VioXzogWf1Xi4Rswz2B6EK
Paul Campbell 507d2e47886538cca44eca325b41f2d4d62661f2 parent 9991d6c
2 files changed, +312 −0
  • internal/release/production.go +159 −0
  • internal/release/production_test.go +153 −0
diff --git a/internal/release/production.go b/internal/release/production.go
new file mode 100644
index 000000000..d22c4f010
--- /dev/null
+++ b/internal/release/production.go
@@ -0,0 +1,159 @@
+// The per-app production flag — the console bake controls spec
+// (docs/superpowers/specs/2026-08-04-console-bake-controls-design.md, §2–§3).
+//
+// production: true means the supply-chain bake window (bake.go) applies to
+// this app's held channels; false — and MISSING, the default — means its
+// boxes adopt immediately. The object is root-signed in the pointer's own
+// signedWrapper envelope, and root-ONLY: a wrapper carrying a key grant is
+// refused before its signature is even checked, because a scoped key that
+// could flip the flag could skip the very window it bakes under.
+//
+// What verification here does NOT decide: whether a missing or unreadable
+// flag downgrades a box that once saw production: true. It never does —
+// that memory, the ratchet and the replay floor are the box's own
+// (bake.go's production memory), because anyone with bucket write but no
+// key can delete an object, and deletion must not be a downgrade (spec §4).
+package release
+
+import (
+ "context"
+ "crypto/ed25519"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "os"
+ "time"
+)
+
+// ProductionFlag is the signed payload: one app's declaration that it is (or
+// is not) in production, and therefore whether its releases bake.
+type ProductionFlag struct {
+ Schema int `json:"schema"` // 1
+ Account string `json:"account"`
+ App string `json:"app"`
+ Production bool `json:"production"`
+ // Actor is who flipped it — a console member's address. Recorded for the
+ // same reason the pointer's audit trail exists: an invisible bypass is a
+ // broken gate.
+ Actor string `json:"actor,omitempty"`
+ SetAt time.Time `json:"set_at"`
+}
+
+// ProductionKey is where an app's flag lives: beside channels/ and
+// releases/, deliberately NEVER under ChannelsPrefix — those listings are
+// parsed as channel pointers by the console and the CLI.
+func ProductionKey(acct, app string) string {
+ return appPrefix(acct, app) + "production.json"
+}
+
+// SetProduction writes the flag, root key only, CAS over whatever is there
+// (a concurrent flip surfaces as ErrCASConflict — re-ask, never overwrite
+// blind). SetAt is stamped here; boxes use their OWN sighting for the
+// ratchet and this stamp only as a replay floor.
+func SetProduction(ctx context.Context, s Store, priv ed25519.PrivateKey, acct, app string, production bool, actor string) error {
+ if len(priv) != ed25519.PrivateKeySize {
+ return fmt.Errorf("set production: no usable release signing key")
+ }
+ if !ValidAccount(acct) {
+ return fmt.Errorf("set production: invalid account %q", acct)
+ }
+ if !ValidApp(app) {
+ return fmt.Errorf("set production: invalid app %q", app)
+ }
+ key := ProductionKey(acct, app)
+ _, etag, err := s.Get(ctx, key)
+ if errors.Is(err, os.ErrNotExist) {
+ etag = "" // first write: create-only
+ } else if err != nil {
+ return fmt.Errorf("set production: read %s: %w", key, err)
+ }
+ f := &ProductionFlag{
+ Schema: 1, Account: acct, App: app, Production: production,
+ Actor: actor, SetAt: time.Now().UTC().Truncate(time.Second),
+ }
+ if err := validateProductionFlag(f, acct, app); err != nil {
+ return fmt.Errorf("set production: %w", err)
+ }
+ payload, err := json.MarshalIndent(f, "", " ")
+ if err != nil {
+ return err
+ }
+ b64 := base64.StdEncoding.EncodeToString(payload)
+ wrapper, err := json.MarshalIndent(signedWrapper{
+ Payload: b64,
+ Sig: base64.StdEncoding.EncodeToString(ed25519.Sign(priv, []byte(b64))),
+ }, "", " ")
+ if err != nil {
+ return err
+ }
+ _, err = s.Put(ctx, key, wrapper, etag)
+ return err
+}
+
+// GetProduction resolves an app's flag. A MISSING object is (nil, nil): the
+// default, not production — but never let a nil collapse the distinction the
+// spec draws: any OTHER failure (unreadable, unverifiable, misnamed) is the
+// error, and callers on the adopt path treat it as production=true, failing
+// toward baking.
+func GetProduction(ctx context.Context, s Store, pub ed25519.PublicKey, acct, app string) (*ProductionFlag, error) {
+ raw, _, err := s.Get(ctx, ProductionKey(acct, app))
+ if errors.Is(err, os.ErrNotExist) {
+ return nil, nil
+ }
+ if err != nil {
+ return nil, err
+ }
+ return verifyProductionFlag(pub, raw, acct, app)
+}
+
+// verifyProductionFlag is verifyPointer's discipline for the flag: refuse a
+// grant outright, check the signature against the ROOT key alone, decode
+// after, validate the payload names the account/app whose key it sits at.
+func verifyProductionFlag(pub ed25519.PublicKey, wrapper []byte, wantAcct, wantApp string) (*ProductionFlag, error) {
+ var sw signedWrapper
+ if err := json.Unmarshal(wrapper, &sw); err != nil {
+ return nil, fmt.Errorf("production flag wrapper: %v", err)
+ }
+ if sw.Grant != nil {
+ return nil, fmt.Errorf("production flag %s/%s: signed by a scoped key — the flag takes the root key, because a delegate that could flip it could skip the window it bakes under", wantAcct, wantApp)
+ }
+ if len(pub) != ed25519.PublicKeySize {
+ return nil, fmt.Errorf("production flag: no usable release public key")
+ }
+ sig, err := base64.StdEncoding.DecodeString(sw.Sig)
+ if err != nil {
+ return nil, fmt.Errorf("production flag sig: %v", err)
+ }
+ if !ed25519.Verify(pub, []byte(sw.Payload), sig) {
+ return nil, fmt.Errorf("production flag signature verification failed")
+ }
+ payload, err := base64.StdEncoding.DecodeString(sw.Payload)
+ if err != nil {
+ return nil, fmt.Errorf("production flag payload: %v", err)
+ }
+ var f ProductionFlag
+ if err := json.Unmarshal(payload, &f); err != nil {
+ return nil, fmt.Errorf("production flag payload: %v", err)
+ }
+ if err := validateProductionFlag(&f, wantAcct, wantApp); err != nil {
+ return nil, err
+ }
+ return &f, nil
+}
+
+func validateProductionFlag(f *ProductionFlag, wantAcct, wantApp string) error {
+ if f.Schema != 1 {
+ return fmt.Errorf("unsupported production flag schema %d", f.Schema)
+ }
+ if f.Account != wantAcct || f.App != wantApp {
+ return fmt.Errorf("production flag names %s/%s, expected %s/%s", f.Account, f.App, wantAcct, wantApp)
+ }
+ if !ValidAccount(f.Account) || !ValidApp(f.App) {
+ return fmt.Errorf("production flag has invalid account/app %s/%s", f.Account, f.App)
+ }
+ if f.SetAt.IsZero() {
+ return fmt.Errorf("production flag has no set_at")
+ }
+ return nil
+}
diff --git a/internal/release/production_test.go b/internal/release/production_test.go
new file mode 100644
index 000000000..da712bf89
--- /dev/null
+++ b/internal/release/production_test.go
@@ -0,0 +1,153 @@
+package release
+
+// The production flag (2026-08-04 console bake controls spec §2–§3): a
+// root-signed per-app object deciding whether the supply-chain bake applies.
+// The properties tested here, in the order they'd hurt if lost: missing is
+// the default (nil, nil); a set flag round-trips; a scoped key's wrapper is
+// refused even with a valid root grant; a tampered payload is refused; the
+// key sits OUTSIDE channels/ so pointer listings never try to parse it.
+
+import (
+ "context"
+ "crypto/ed25519"
+ "crypto/rand"
+ "encoding/base64"
+ "encoding/json"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestProductionFlagDefaultIsMissing(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ _, pub := testKeys(t)
+ f, err := GetProduction(context.Background(), s, pub, "bab", "kass")
+ if err != nil || f != nil {
+ t.Fatalf("GetProduction on empty store = %v, %v; want nil, nil (the default: not production)", f, err)
+ }
+}
+
+func TestProductionFlagRoundTrips(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ priv, pub := testKeys(t)
+ if err := SetProduction(ctx, s, priv, "bab", "kass", true, "paul@keymail.dev"); err != nil {
+ t.Fatalf("SetProduction: %v", err)
+ }
+ f, err := GetProduction(ctx, s, pub, "bab", "kass")
+ if err != nil {
+ t.Fatalf("GetProduction: %v", err)
+ }
+ if f == nil || !f.Production || f.Actor != "paul@keymail.dev" || f.SetAt.IsZero() {
+ t.Fatalf("flag = %+v, want production on, actor recorded, set_at stamped", f)
+ }
+ // Flip it off over the existing object — the CAS path.
+ if err := SetProduction(ctx, s, priv, "bab", "kass", false, "paul@keymail.dev"); err != nil {
+ t.Fatalf("SetProduction off: %v", err)
+ }
+ if f, _ = GetProduction(ctx, s, pub, "bab", "kass"); f == nil || f.Production {
+ t.Fatalf("flag = %+v after flipping off, want production false", f)
+ }
+}
+
+// The flag key lives beside channels/, never inside it: ChannelsPrefix
+// listings are parsed as pointers by the console and CLI.
+func TestProductionKeyIsOutsideChannels(t *testing.T) {
+ if k := ProductionKey("bab", "kass"); k != "apps/bab/kass/production.json" {
+ t.Fatalf("ProductionKey = %q", k)
+ }
+ if strings.HasPrefix(ProductionKey("bab", "kass"), ChannelsPrefix("bab", "kass")) {
+ t.Fatal("production flag key sits under channels/ — pointer listings would try to parse it")
+ }
+}
+
+// A scoped key must not be able to mint the flag: a wrapper carrying ANY
+// grant is refused before signature checking, and a wrapper signed by a key
+// other than the root fails signature checking. Together: root only.
+func TestProductionFlagRefusesScopedAndForeignKeys(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ priv, pub := testKeys(t)
+
+ // Build a validly-shaped flag payload signed by a DIFFERENT key.
+ otherPub, otherPriv, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _ = otherPub
+ payload, _ := json.Marshal(ProductionFlag{Schema: 1, Account: "bab", App: "kass",
+ Production: false, SetAt: timeNowTestHelper()})
+ b64 := base64.StdEncoding.EncodeToString(payload)
+ wrapper, _ := json.Marshal(signedWrapper{
+ Payload: b64,
+ Sig: base64.StdEncoding.EncodeToString(ed25519.Sign(otherPriv, []byte(b64))),
+ })
+ if _, err := s.Put(ctx, ProductionKey("bab", "kass"), wrapper, ""); err != nil {
+ t.Fatal(err)
+ }
+ if _, err := GetProduction(ctx, s, pub, "bab", "kass"); err == nil {
+ t.Fatal("a flag signed by a non-root key verified")
+ }
+
+ // A wrapper WITH a grant is refused outright — even a grant the root
+ // really signed. Mint a real scoped key and have it sign the flag.
+ seed, grantB64, err := MintKeyGrant(priv, "builder", []string{RungEdge}, maxGrantTTL)
+ if err != nil {
+ t.Fatal(err)
+ }
+ scopedKey, err := ParseSigningKey(seed, "test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ sg, err := parseGrantBlob(grantB64, "test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ wrapper, _ = json.Marshal(signedWrapper{
+ Payload: b64,
+ Sig: base64.StdEncoding.EncodeToString(ed25519.Sign(scopedKey, []byte(b64))),
+ Grant: sg,
+ })
+ if _, err := s.Put(ctx, ProductionKey("bab", "kass"), wrapper, etagOfKey(t, s, "bab", "kass")); err != nil {
+ t.Fatal(err)
+ }
+ _, err = GetProduction(ctx, s, pub, "bab", "kass")
+ if err == nil || !strings.Contains(err.Error(), "root") {
+ t.Fatalf("a grant-bearing flag wrapper verified (err=%v), want a root-only refusal", err)
+ }
+}
+
+// etagOfKey reads the current etag of an app's flag so a test can CAS over it.
+func etagOfKey(t *testing.T, s Store, acct, app string) string {
+ t.Helper()
+ _, etag, err := s.Get(context.Background(), ProductionKey(acct, app))
+ if err != nil {
+ t.Fatal(err)
+ }
+ return etag
+}
+
+func TestProductionFlagRefusesWrongApp(t *testing.T) {
+ s := NewDirStore(t.TempDir())
+ ctx := context.Background()
+ priv, pub := testKeys(t)
+ if err := SetProduction(ctx, s, priv, "bab", "kass", true, ""); err != nil {
+ t.Fatal(err)
+ }
+ // Copy kass's flag to keymail's key — a cross-app replay must be refused
+ // because the SIGNED payload names the app.
+ raw, _, err := s.Get(ctx, ProductionKey("bab", "kass"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if _, err := s.Put(ctx, ProductionKey("bab", "keymail"), raw, ""); err != nil {
+ t.Fatal(err)
+ }
+ if _, err := GetProduction(ctx, s, pub, "bab", "keymail"); err == nil {
+ t.Fatal("another app's flag verified under keymail's key")
+ }
+}
+
+// timeNowTestHelper is a stamped, truncated now — what signProductionFlag
+// itself writes — for tests that hand-build payloads.
+func timeNowTestHelper() time.Time { return time.Now().UTC().Truncate(time.Second) }