| 1 | package console |
| 2 | |
| 3 | import ( |
| 4 | "bytes" |
| 5 | "context" |
| 6 | "crypto/ecdh" |
| 7 | "encoding/base64" |
| 8 | "encoding/json" |
| 9 | "errors" |
| 10 | "os" |
| 11 | "testing" |
| 12 | |
| 13 | "github.com/carlosframework/platform/internal/appconfig" |
| 14 | "github.com/carlosframework/platform/internal/moves" |
| 15 | "github.com/carlosframework/platform/internal/release" |
| 16 | ) |
| 17 | |
| 18 | // D13: the console publishes control/moves-console.json only with the |
| 19 | // moves switch on, and a second start replaces the first start's record. |
| 20 | func TestConsoleRecordNeedsTheSwitch(t *testing.T) { |
| 21 | ctx := context.Background() |
| 22 | priv, err := ecdh.P256().NewPrivateKey(bytes.Repeat([]byte{1}, 32)) |
| 23 | if err != nil { |
| 24 | t.Fatal(err) |
| 25 | } |
| 26 | pubB64 := base64.StdEncoding.EncodeToString(priv.PublicKey().Bytes()) |
| 27 | store := release.NewDirStore(t.TempDir()) |
| 28 | |
| 29 | off := &Server{cfg: Config{Releases: store, SecretsPub: pubB64}} |
| 30 | if err := off.PublishMovesConsole(ctx); err != nil { |
| 31 | t.Fatal(err) |
| 32 | } |
| 33 | if _, _, err := store.Get(ctx, moves.ConsoleKey); !errors.Is(err, os.ErrNotExist) { |
| 34 | t.Fatalf("switch off, yet %s: %v", moves.ConsoleKey, err) |
| 35 | } |
| 36 | |
| 37 | on := &Server{cfg: Config{Releases: store, SecretsPub: pubB64, MovesEnabled: true}} |
| 38 | for start := 0; start < 2; start++ { |
| 39 | if err := on.PublishMovesConsole(ctx); err != nil { |
| 40 | t.Fatalf("start %d: %v", start, err) |
| 41 | } |
| 42 | } |
| 43 | body, _, err := store.Get(ctx, moves.ConsoleKey) |
| 44 | if err != nil { |
| 45 | t.Fatal(err) |
| 46 | } |
| 47 | var rec moves.ConsoleRecord |
| 48 | if err := json.Unmarshal(body, &rec); err != nil { |
| 49 | t.Fatal(err) |
| 50 | } |
| 51 | if rec.V != 1 || rec.Protocol != moves.ProtocolVersion || rec.SecretsKeyFP != appconfig.KeyFingerprint(priv.PublicKey()) || rec.At.IsZero() { |
| 52 | t.Fatalf("record = %+v", rec) |
| 53 | } |
| 54 | |
| 55 | // No secrets key: the record says so by carrying no fingerprint. |
| 56 | bare := &Server{cfg: Config{Releases: store, MovesEnabled: true}} |
| 57 | if err := bare.PublishMovesConsole(ctx); err != nil { |
| 58 | t.Fatal(err) |
| 59 | } |
| 60 | body, _, _ = store.Get(ctx, moves.ConsoleKey) |
| 61 | if bytes.Contains(body, []byte("secrets_key_fp")) { |
| 62 | t.Fatalf("no key, yet %s", body) |
| 63 | } |
| 64 | |
| 65 | // A bucketless console has nowhere to publish and does not fail. |
| 66 | if err := (&Server{cfg: Config{MovesEnabled: true}}).PublishMovesConsole(ctx); err != nil { |
| 67 | t.Fatal(err) |
| 68 | } |
| 69 | } |
| 70 | |