carlos / platform Public

host: CARLOS_REGION_HA is on only for a ParseBool true; a box record already under this label for another instance is logged loudly

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev 07c3030e80a587376a75d9847ba302c2c6fcc2d5 parent 86f307e
2 files changed, +102 −22
  • internal/host/boxrecord.go +52 −14
  • internal/host/boxrecord_test.go +50 −8
diff --git a/internal/host/boxrecord.go b/internal/host/boxrecord.go
index 9069d3524..c338b6a25 100644
--- a/internal/host/boxrecord.go
+++ b/internal/host/boxrecord.go
@@ -3,12 +3,14 @@ package host
import (
"context"
"encoding/base64"
+ "encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"os"
+ "strconv"
"strings"
"time"
@@ -16,14 +18,13 @@ import (
"github.com/carlosframework/platform/internal/release"
)
-// regionHAEnabled is CARLOS_REGION_HA: on for any value but "" and "0".
-// Every region HA behaviour on a box is behind it (spec 1 §8 step 2).
+// regionHAEnabled is CARLOS_REGION_HA: on only for a value
+// strconv.ParseBool reads as true ("1", "t", "true" in any case); "",
+// "0", "false", "off", "no" and anything unparseable are off. Every region
+// HA behaviour on a box is behind it (spec 1 §8 step 2).
func regionHAEnabled(getenv func(string) string) bool {
- switch strings.TrimSpace(getenv("CARLOS_REGION_HA")) {
- case "", "0":
- return false
- }
- return true
+ on, err := strconv.ParseBool(strings.TrimSpace(getenv("CARLOS_REGION_HA")))
+ return err == nil && on
}
const (
@@ -93,22 +94,59 @@ func readIdentityRecord(client *http.Client, base, box string, now time.Time) (b
IdentitySignature: cleaned, WrittenAt: now.UTC().Format(time.RFC3339)}, nil
}
+// recordInstanceID is the instanceId in a record's identity document. It
+// does not check the signature: it only tells whether a record names this
+// box's instance.
+func recordInstanceID(rec boxid.Record) (string, error) {
+ doc, err := base64.StdEncoding.DecodeString(rec.IdentityDocument)
+ if err != nil {
+ return "", errors.New("identity document is not base64")
+ }
+ var d struct {
+ InstanceID string `json:"instanceId"`
+ }
+ if err := json.Unmarshal(doc, &d); err != nil || d.InstanceID == "" {
+ return "", errors.New("identity document names no instance")
+ }
+ return d.InstanceID, nil
+}
+
// publishBoxRecord makes one attempt to publish this box's enrollment
// evidence. done is true once there is nothing left to retry: the record
// is in place, or a different one already holds this reference, which
-// only an operator can sort out and which is logged loudly.
+// only an operator can sort out and which is logged loudly. A record
+// already under this reference is never rewritten, but it is checked
+// against this box's own identity: one signed for another instance, or
+// one that cannot be read, is reported the same loud way.
func publishBoxRecord(ctx context.Context, s release.Store, box string, read func() (boxid.Record, error)) (done bool, err error) {
if !boxid.ValidBox(box) {
return true, fmt.Errorf("box reference %q is not a label; no enrollment evidence is published", box)
}
- if _, err := boxid.Load(ctx, s, box); err == nil {
- return true, nil // create-only: an existing record is never rewritten
- } else if !errors.Is(err, os.ErrNotExist) {
+ existing, err := boxid.Load(ctx, s, box)
+ if err != nil && !errors.Is(err, os.ErrNotExist) {
return false, err
}
- rec, err := read()
- if err != nil {
- return false, err
+ rec, rerr := read()
+ if rerr != nil {
+ return false, rerr
+ }
+ if err == nil {
+ var held boxid.Record
+ if jerr := json.Unmarshal(existing, &held); jerr != nil {
+ return true, fmt.Errorf("the record already under %s cannot be read: %v", box, jerr)
+ }
+ theirs, ierr := recordInstanceID(held)
+ if ierr != nil {
+ return true, fmt.Errorf("the record already under %s: %v", box, ierr)
+ }
+ mine, ierr := recordInstanceID(rec)
+ if ierr != nil {
+ return false, fmt.Errorf("this box's own identity: %v", ierr)
+ }
+ if theirs != mine {
+ return true, fmt.Errorf("the record already under %s is signed for instance %s, this box is %s", box, theirs, mine)
+ }
+ return true, nil // create-only: an existing record is never rewritten
}
err = boxid.Publish(ctx, s, rec)
if errors.Is(err, release.ErrCASConflict) {
diff --git a/internal/host/boxrecord_test.go b/internal/host/boxrecord_test.go
index 8d55ce309..d3eb1de40 100644
--- a/internal/host/boxrecord_test.go
+++ b/internal/host/boxrecord_test.go
@@ -83,21 +83,59 @@ func TestReadIdentityRecordRefusesWhatIsNotAnAnswer(t *testing.T) {
}
}
+// identityRecord is a record whose document names instance; the
+// signature is not checked on this path.
+func identityRecord(instance, writtenAt string) boxid.Record {
+ doc := base64.StdEncoding.EncodeToString([]byte(`{"accountId":"111122223333","region":"eu-west-1","instanceId":"` + instance + `"}`))
+ return boxid.Record{V: 1, Box: "annie-welding", IdentityDocument: doc, IdentitySignature: "c2ln", WrittenAt: writtenAt}
+}
+
func TestPublishBoxRecordWritesOnceAndNeverRewrites(t *testing.T) {
ctx, st := context.Background(), release.NewDirStore(t.TempDir())
- reads := 0
- read := func() (boxid.Record, error) {
- reads++
- return boxid.Record{V: 1, Box: "annie-welding", IdentityDocument: "ZG9j", IdentitySignature: "c2ln", WrittenAt: "2026-10-06T09:00:00Z"}, nil
- }
+ writtenAt := "2026-10-06T09:00:00Z"
+ read := func() (boxid.Record, error) { return identityRecord("i-0abc", writtenAt), nil }
if done, err := publishBoxRecord(ctx, st, "annie-welding", read); !done || err != nil {
t.Fatalf("first publish: done=%v err=%v", done, err)
}
+ first, err := boxid.Load(ctx, st, "annie-welding")
+ if err != nil {
+ t.Fatal(err)
+ }
+ writtenAt = "2026-10-06T10:00:00Z" // a later run reads a fresh record
if done, err := publishBoxRecord(ctx, st, "annie-welding", read); !done || err != nil {
t.Fatalf("second publish: done=%v err=%v", done, err)
}
- if reads != 1 {
- t.Fatalf("IMDS read %d times; an existing record must not be re-read or rewritten", reads)
+ if again, _ := boxid.Load(ctx, st, "annie-welding"); string(again) != string(first) {
+ t.Fatalf("an existing record was rewritten:\n%s\n%s", first, again)
+ }
+}
+
+// Final review 3: a record already under this box's label that is signed
+// for another instance is someone else's claim on the reference. It is
+// never rewritten, and it is reported once, as done with an error, so the
+// loop logs it loudly.
+func TestPublishBoxRecordReportsARecordForAnotherInstance(t *testing.T) {
+ ctx, st := context.Background(), release.NewDirStore(t.TempDir())
+ if err := boxid.Publish(ctx, st, identityRecord("i-0zzz", "2026-10-06T08:00:00Z")); err != nil {
+ t.Fatal(err)
+ }
+ read := func() (boxid.Record, error) { return identityRecord("i-0abc", "2026-10-06T09:00:00Z"), nil }
+ done, err := publishBoxRecord(ctx, st, "annie-welding", read)
+ if !done || err == nil || !strings.Contains(err.Error(), "i-0zzz") || !strings.Contains(err.Error(), "i-0abc") {
+ t.Fatalf("done=%v err=%v; want done with an error naming both instances", done, err)
+ }
+ // An existing record this box cannot decode is reported the same way.
+ st2 := release.NewDirStore(t.TempDir())
+ if _, err := st2.Put(ctx, boxid.Key("annie-welding"), []byte(`{"v":1}`), ""); err != nil {
+ t.Fatal(err)
+ }
+ if done, err := publishBoxRecord(ctx, st2, "annie-welding", read); !done || err == nil {
+ t.Fatalf("an unreadable existing record: done=%v err=%v", done, err)
+ }
+ // Until this box can read its own identity, it retries.
+ failing := func() (boxid.Record, error) { return boxid.Record{}, errors.New("IMDS down") }
+ if done, err := publishBoxRecord(ctx, st, "annie-welding", failing); done || err == nil {
+ t.Fatalf("own identity unreadable: done=%v err=%v; want a retry", done, err)
}
}
@@ -133,7 +171,11 @@ func TestPublishBoxRecordDoesNotPublishWhenItCannotRead(t *testing.T) {
}
func TestRegionHAEnabled(t *testing.T) {
- for v, want := range map[string]bool{"": false, "0": false, " 0 ": false, "1": true, "yes": true} {
+ // Final review 5: only what strconv.ParseBool reads as true turns it on.
+ for v, want := range map[string]bool{
+ "": false, "0": false, " 0 ": false, "false": false, "FALSE": false, "off": false, "no": false, "yes": false, "garbage": false,
+ "1": true, " 1 ": true, "true": true, "TRUE": true, "t": true,
+ } {
if got := regionHAEnabled(func(string) string { return v }); got != want {
t.Errorf("CARLOS_REGION_HA=%q: %v, want %v", v, got, want)
}