| index 9ec390d6a..de3f5b07b 100644 |
| --- a/internal/release/resign_test.go |
| +++ b/internal/release/resign_test.go |
| @@ -2,6 +2,9 @@ package release |
| |
| import ( |
| "context" |
| + "crypto/ed25519" |
| + "encoding/base64" |
| + "encoding/json" |
| "errors" |
| "fmt" |
| "strings" |
| @@ -151,6 +154,82 @@ func TestResignRequiresTheVerifiedMarker(t *testing.T) { |
| } |
| } |
| |
| +// unbindPointer rewrites a channel's pointer as one signed before the account |
| +// binding existed: same fields, no account, root-signed. |
| +func unbindPointer(t *testing.T, s Store, priv ed25519.PrivateKey, acct, app, channel string) { |
| + t.Helper() |
| + ctx := context.Background() |
| + key := ChannelKey(acct, app, channel) |
| + body, etag, err := GetQualified(ctx, s, key) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + var w signedWrapper |
| + if err := json.Unmarshal(body, &w); err != nil { |
| + t.Fatal(err) |
| + } |
| + payload, err := base64.StdEncoding.DecodeString(w.Payload) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + var p ChannelPointer |
| + if err := json.Unmarshal(payload, &p); err != nil { |
| + t.Fatal(err) |
| + } |
| + p.Account = "" |
| + payload, err = json.MarshalIndent(&p, "", " ") |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + b64 := base64.StdEncoding.EncodeToString(payload) |
| + wire, err := json.MarshalIndent(signedWrapper{Payload: b64, Sig: base64.StdEncoding.EncodeToString(ed25519.Sign(priv, []byte(b64)))}, "", " ") |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if _, err := s.Put(ctx, key, wire, etag); err != nil { |
| + t.Fatal(err) |
| + } |
| +} |
| + |
| +// A channel not promoted since the account binding has no account in its |
| +// pointer. Resign targets exactly those, and must bind the account. |
| +func TestResignBindsTheAccountOnAPreBindingPointer(t *testing.T) { |
| + s := NewDirStore(t.TempDir()) |
| + ctx := context.Background() |
| + priv, pub := testKeys(t) |
| + shipRelease(t, s, "bab", "km", "v1", adoptPlatform, []byte("one")) |
| + shipRelease(t, s, "bab", "km", "v2", adoptPlatform, []byte("two")) |
| + for _, v := range []string{"v1", "v2"} { |
| + if err := Promote(ctx, s, priv, "bab", "km", "stable", v); err != nil { |
| + t.Fatal(err) |
| + } |
| + } |
| + unbindPointer(t, s, priv, "bab", "km", "stable") |
| + if p := readPtr(t, s, pub, "stable"); p.Account != "" { |
| + t.Fatalf("test setup: pointer still bound to %q", p.Account) |
| + } |
| + markerOn(t, s, priv, "bab") |
| + sg := RootSigner(priv) |
| + plan, err := sg.PlanResign(ctx, s, "bab", "km", "stable") |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if err := sg.Resign(ctx, s, plan, "ops"); err != nil { |
| + t.Fatalf("resign of a pre-binding pointer: %v", err) |
| + } |
| + p := readPtr(t, s, pub, "stable") |
| + if p.Account != "bab" || p.Digest != plan.Digest || p.HistoryDigests[0] != plan.HistoryDigests[0] { |
| + t.Fatalf("resigned pointer = %+v", p) |
| + } |
| +} |
| + |
| +func TestResignRefusesAnInvalidPlan(t *testing.T) { |
| + priv, _ := testKeys(t) |
| + if err := RootSigner(priv).claimRawResign(context.Background(), NewDirStore(t.TempDir()), &ResignPlan{Account: "bab", App: "km", Channel: "../x"}, "ops"); err == nil { |
| + t.Fatal("a plan with an invalid channel was signed") |
| + } |
| +} |
| + |
| func TestResignRefusesANilPlan(t *testing.T) { |
| priv, _ := testKeys(t) |
| if err := RootSigner(priv).Resign(context.Background(), NewDirStore(t.TempDir()), nil, "ops"); err == nil { |