carlos / platform Public

release: the grant gains its floor — no pointer predates the key that signed it

The review's one substantive finding: a scoped key could sign a pointer
dated years before its own mint and it verified, because expiry only had
a ceiling. The floor is clock-free and adoption-safe for the same reason
the ceiling is — a genuine promotion always stamps promoted_at at or
after minted_at — and it closes forged pre-grant history. Mutation-
verified: removing the floor fails exactly its test.

Also: rungs deduped at mint (noise in every listing forever), and the
spec now states what previously lived only in a code comment — expiry is
evadable by the key's own holder and defeats expiry only, never scope —
plus the 90-day default the implementation had and the spec lacked.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Paul Campbell 8091c6f63876d459a86b5d105a9de8f54103a02f parent 81c4f1f
3 files changed, +71 −0
  • docs/superpowers/specs/2026-08-03-scoped-signing-keys-design.md +8 −0
  • internal/release/grant.go +20 −0
  • internal/release/grant_test.go +43 −0
diff --git a/docs/superpowers/specs/2026-08-03-scoped-signing-keys-design.md b/docs/superpowers/specs/2026-08-03-scoped-signing-keys-design.md
index ace630d33..4b50a3dc9 100644
--- a/docs/superpowers/specs/2026-08-03-scoped-signing-keys-design.md
+++ b/docs/superpowers/specs/2026-08-03-scoped-signing-keys-design.md
@@ -124,6 +124,14 @@ an expired grant fails at promote time and at verify time. (Revocation of
an actively-misused key is by rotating the ROOT key, which invalidates every
grant at once — documented as the incident response, not built.)
+Stated plainly, because it lives nowhere else: **expiry is evadable by the
+key's own holder** — promoted_at is signer-controlled, so a scoped key can
+backdate a pointer inside its own validity window. Backdating defeats expiry
+only, never scope: stable stays refused whatever the date says. Expiry is
+hygiene against forgotten keys, not revocation against hostile ones. There is
+also a floor: a pointer dated before the grant's minted_at is refused as
+forged history — no real promotion by a key can predate the key.
+
## 6. Non-goals
- Per-app or per-account scoping (rung-only for v1; the grant schema's
diff --git a/internal/release/grant.go b/internal/release/grant.go
index 0a3c0aa10..59df20a95 100644
--- a/internal/release/grant.go
+++ b/internal/release/grant.go
@@ -97,6 +97,8 @@ func MintKeyGrant(root ed25519.PrivateKey, name string, rungs []string, ttl time
}
// Checked here as well as in validateGrant so the refusal names the flag
// the operator typed rather than the document they never saw.
+ seen := map[string]bool{}
+ deduped := rungs[:0:0]
for _, r := range rungs {
if r == RungStable {
return "", "", fmt.Errorf("mint key grant: %s is never delegable — moving stable requires the root key itself", RungStable)
@@ -104,7 +106,14 @@ func MintKeyGrant(root ed25519.PrivateKey, name string, rungs []string, ttl time
if RungIndex(r) < 0 {
return "", "", fmt.Errorf("mint key grant: %q is not a rung (%s)", r, strings.Join(delegableRungs(), ", "))
}
+ // Deduped at mint (2026-08-03 review, MINOR 6): a repeated rung is
+ // harmless to verify but noise in every grant listing forever.
+ if !seen[r] {
+ seen[r] = true
+ deduped = append(deduped, r)
+ }
}
+ rungs = deduped
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return "", "", err
@@ -263,6 +272,17 @@ func (g *Grant) allows(channel string, at time.Time) error {
return fmt.Errorf("key grant %q expired at %s, before %s",
g.Name, g.ExpiresAt.Format(time.RFC3339), at.UTC().Format(time.RFC3339))
}
+ // The lower bound (2026-08-03 review, IMPORTANT 1): a pointer dated
+ // before the grant even existed is forged history — no real promotion by
+ // this key can predate the key. Clock-free and adoption-safe for the same
+ // reason the upper bound is: a genuine promotion always stamps
+ // promoted_at at or after minted_at, so nothing legitimately adopted can
+ // trip this, while a backdated pointer aimed under the grant's floor
+ // fails closed.
+ if at.Before(g.MintedAt) {
+ return fmt.Errorf("key grant %q was minted %s; a pointer dated %s predates the key that signed it",
+ g.Name, g.MintedAt.Format(time.RFC3339), at.UTC().Format(time.RFC3339))
+ }
return nil
}
diff --git a/internal/release/grant_test.go b/internal/release/grant_test.go
index ec1c64f9f..ff762cbbe 100644
--- a/internal/release/grant_test.go
+++ b/internal/release/grant_test.go
@@ -374,3 +374,46 @@ func TestGrantBlobParseErrorsNameTheSource(t *testing.T) {
}
}
}
+
+// A pointer dated before the grant existed is forged history: no real
+// promotion by a key can predate the key, so the floor refuses it outright
+// (2026-08-03 review, IMPORTANT 1 — before the floor, a scoped key could
+// sign a pointer dated years before its own mint and it verified).
+//
+// Mutation-mindedness: delete the at.Before(g.MintedAt) refusal in allows()
+// and the first half of this test goes green when it must not; the second
+// half pins that the exact mint instant — the earliest honest promotion —
+// stays allowed, so the floor cannot drift into refusing real history.
+func TestGrantRefusesAPointerPredatingTheGrant(t *testing.T) {
+ _, scopedPub := testKeys(t)
+ g := goodGrant(scopedPub)
+ err := g.allows("edge", g.MintedAt.Add(-time.Second))
+ if err == nil {
+ t.Fatal("grant honoured a pointer dated before the grant was minted")
+ }
+ if !strings.Contains(err.Error(), "predates") {
+ t.Errorf("refusal %q does not say the pointer predates the key", err)
+ }
+ if err := g.allows("edge", g.MintedAt); err != nil {
+ t.Errorf("grant refused its own mint instant: %v", err)
+ }
+}
+
+// Duplicate rungs are collapsed at mint (2026-08-03 review, MINOR 6):
+// harmless to verify, noise in every listing of the grant forever.
+func TestMintDeduplicatesRungs(t *testing.T) {
+ root, _ := testKeys(t)
+ rootPub := root.Public().(ed25519.PublicKey)
+ _, blob := mintGrant(t, root, "dupes", []string{"edge", "edge", "canary", "edge"}, time.Hour)
+ sg, err := parseGrantBlob(blob, "test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ g, err := verifyGrant(rootPub, sg)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(g.Rungs) != 2 {
+ t.Fatalf("rungs = %v, want the two distinct ones", g.Rungs)
+ }
+}