Read past a provision field a later layout adds
Decode refused any field it did not know, so every reader on an older mesh-sdk refused a key the moment a writer added one (plan, this release). It now reads past it and drops it; Encode still writes the layout alone, so no value rides in a provision (issue 1126 review 1). Claude-Session: https://claude.ai/code/session_01NcbgfJ9Gum47zkFKWRaovL
This commit is contained in:
@@ -264,12 +264,12 @@ func Encode(p Provision) ([]byte, error) {
|
||||
return json.Marshal(p)
|
||||
}
|
||||
|
||||
// Decode reads a key's value strictly: a field the layout does not name is refused, so no value, sealed or not, rides in
|
||||
// a provision (clause 1, ADR 0201 §13).
|
||||
// Decode reads a key's value. **A field the layout does not name is read past and dropped** (issue 1126 review 1): a
|
||||
// reader on an older mesh-sdk must not refuse a key a newer writer adds a field to. No value rides in a provision all
|
||||
// the same (clause 1, ADR 0201 §13): Encode writes the layout alone, so what a reader does not know is never kept.
|
||||
func Decode(data []byte) (Provision, error) {
|
||||
var p Provision
|
||||
dec := json.NewDecoder(bytes.NewReader(data))
|
||||
dec.DisallowUnknownFields()
|
||||
if err := dec.Decode(&p); err != nil {
|
||||
return Provision{}, fmt.Errorf("provisions: a provision is not readable: %w", err)
|
||||
}
|
||||
|
||||
@@ -56,10 +56,16 @@ func TestAProvisionIsAReferenceUnderItsConsumersKey(t *testing.T) {
|
||||
t.Errorf("%s: %s parses as %s %s %s %s, %v", c.name, key, node, consumer, provision, local, err)
|
||||
}
|
||||
}
|
||||
// A value never rides in a provision: a field the layout does not name is refused.
|
||||
if _, err := Decode([]byte(`{"v":1,"provision":"p","consumer":{"module":"c","node":"n"},"provider":{"module":"p","node":"n"},` +
|
||||
`"state":"provided","at":"2026-10-29T22:00:00Z","password":"hunter2"}`)); err == nil {
|
||||
t.Error("a provision carrying a password was read")
|
||||
// A field a later layout adds is read past, never kept (issue 1126 review 1: a reader on an older mesh-sdk must not
|
||||
// refuse a key a newer writer adds a field to). A value still never rides in a provision: Encode writes the layout
|
||||
// alone, so what a reader does not know is dropped, and encoding it again carries none of it.
|
||||
later, err := Decode([]byte(`{"v":1,"provision":"p","consumer":{"module":"c","node":"n"},"provider":{"module":"p","node":"n"},` +
|
||||
`"state":"provided","at":"2026-10-29T22:00:00Z","a-later-field":{"x":1},"password":"hunter2"}`))
|
||||
if err != nil || later.Provision != "p" || later.State != Provided {
|
||||
t.Errorf("a provision with a field of a later layout: %+v, %v", later, err)
|
||||
}
|
||||
if again, _ := Encode(later); strings.Contains(string(again), "hunter2") || strings.Contains(string(again), "a-later-field") {
|
||||
t.Errorf("a field the layout does not name was kept: %s", again)
|
||||
}
|
||||
plan := Plan{Node: "novox", Module: "restic", Plan: catalogue.Plan{}}
|
||||
raw, err := EncodePlan(plan)
|
||||
|
||||
Reference in New Issue
Block a user