diff --git a/compose/service/record.go b/compose/service/record.go index 0ce388557..111727cef 100644 --- a/compose/service/record.go +++ b/compose/service/record.go @@ -861,6 +861,13 @@ func (svc record) procUpdate(ctx context.Context, s store.Storer, invokerID uint // Mark all values as updated (new) upd.Values.SetUpdatedFlag(true) + // First sanitization + // + // Before values are merged with existing data and + // sent to automation scripts (if any) + // we need to make sure it does not get sanitized data + upd.Values = svc.sanitizer.Run(m, upd.Values) + // Copy values to updated record // to make sure nobody slips in something we do not want upd.CreatedAt = old.CreatedAt diff --git a/tests/compose/record_test.go b/tests/compose/record_test.go index 5c7d7ec26..79ee17477 100644 --- a/tests/compose/record_test.go +++ b/tests/compose/record_test.go @@ -8,6 +8,7 @@ import ( "mime/multipart" "net/http" "net/url" + "strconv" "testing" "time" @@ -287,6 +288,111 @@ func TestRecordUpdate(t *testing.T) { h.a.NotNil(r) } +func TestRecordUpdate_refUnchanged(t *testing.T) { + h := newHelper(t) + h.clearRecords() + + namespace := h.makeNamespace("record testing namespace") + + // mods + mRef := h.makeRecordModuleWithFieldsOnNs("record testing module", namespace) + module := h.makeRecordModuleWithFieldsOnNs("record testing module", namespace, + &types.ModuleField{ + Name: "name", + Kind: "String", + }, + &types.ModuleField{ + Name: "ref", + Kind: "Record", + Options: types.ModuleFieldOptions{ + "moduleID": mRef.ID, + }, + }, + ) + + // Records + rRef := h.makeRecord(mRef) + record := h.makeRecord(module, + &types.RecordValue{ + Name: "name", + Value: "value; name", + }, + &types.RecordValue{ + Name: "ref", + Value: strconv.FormatUint(rRef.ID, 10), + Ref: rRef.ID, + }, + ) + + h.allow(types.ModuleRBACResource.AppendWildcard(), "record.update") + + h.apiInit(). + Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). + JSON(fmt.Sprintf(`{"values": [{"name": "name", "value": "changed-val"}, {"name": "ref", "value": "%d"}]}`, rRef.ID)). + Expect(t). + Status(http.StatusOK). + Assert(helpers.AssertNoErrors). + End() + + r := h.lookupRecordByID(module, record.ID) + h.a.Equal(rRef.ID, r.Values.Get("ref", 0).Ref) + h.a.Equal(strconv.FormatUint(rRef.ID, 10), r.Values.Get("ref", 0).Value) + h.a.NotNil(r) +} + +func TestRecordUpdate_refChanged(t *testing.T) { + h := newHelper(t) + h.clearRecords() + + namespace := h.makeNamespace("record testing namespace") + + // mods + mRef := h.makeRecordModuleWithFieldsOnNs("record testing module", namespace) + module := h.makeRecordModuleWithFieldsOnNs("record testing module", namespace, + &types.ModuleField{ + Name: "name", + Kind: "String", + }, + &types.ModuleField{ + Name: "ref", + Kind: "Record", + Options: types.ModuleFieldOptions{ + "moduleID": mRef.ID, + }, + }, + ) + + // Records + rRef := h.makeRecord(mRef) + rRef2 := h.makeRecord(mRef) + record := h.makeRecord(module, + &types.RecordValue{ + Name: "name", + Value: "value; name", + }, + &types.RecordValue{ + Name: "ref", + Value: strconv.FormatUint(rRef.ID, 10), + Ref: rRef.ID, + }, + ) + + h.allow(types.ModuleRBACResource.AppendWildcard(), "record.update") + + h.apiInit(). + Post(fmt.Sprintf("/namespace/%d/module/%d/record/%d", module.NamespaceID, module.ID, record.ID)). + JSON(fmt.Sprintf(`{"values": [{"name": "name", "value": "changed-val"}, {"name": "ref", "value": "%d"}]}`, rRef2.ID)). + Expect(t). + Status(http.StatusOK). + Assert(helpers.AssertNoErrors). + End() + + r := h.lookupRecordByID(module, record.ID) + h.a.Equal(rRef2.ID, r.Values.Get("ref", 0).Ref) + h.a.Equal(strconv.FormatUint(rRef2.ID, 10), r.Values.Get("ref", 0).Value) + h.a.NotNil(r) +} + func TestRecordUpdate_deleteOld(t *testing.T) { h := newHelper(t) h.clearRecords()