Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions sds-go/go/regex_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package dd_sds
import "C"

import (
"bytes"
"encoding/json"
"fmt"
"unsafe"
Expand Down Expand Up @@ -288,3 +289,40 @@ func (m MatchAction) MarshalJSON() ([]byte, error) {

return json.Marshal(o)
}

// UnmarshalJSON decodes MatchAction JSON produced by MarshalJSON. The inner
// match_action key mirrors type for round-trip with Go-marshaled rules; Rust
// only uses the type tag on MatchAction.
func (m *MatchAction) UnmarshalJSON(data []byte) error {
var raw struct {
Type MatchActionType `json:"type"`
MatchAction MatchActionType `json:"match_action"`
RedactionValue string `json:"replacement"`
CharacterCount uint32 `json:"character_count"`
Direction PartialRedactionDirection `json:"direction"`
}

decoder := json.NewDecoder(bytes.NewReader(data))
decoder.DisallowUnknownFields()
if err := decoder.Decode(&raw); err != nil {
return err
}

actionType := raw.Type
if actionType == "" {
actionType = raw.MatchAction
}
if actionType == "" {
actionType = MatchActionNone
}

m.Type = actionType
switch actionType {
case MatchActionRedact:
m.RedactionValue = raw.RedactionValue
case MatchActionPartialRedact:
m.CharacterCount = raw.CharacterCount
m.Direction = raw.Direction
}
return nil
}
99 changes: 99 additions & 0 deletions sds-go/go/regex_rule_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package dd_sds

import (
"bytes"
"encoding/json"
"errors"
"reflect"
"testing"
)

func TestMatchActionUnmarshalJSON_exportPlaceholder(t *testing.T) {
var got MatchAction
if err := json.Unmarshal([]byte(`{"type":"","match_action":""}`), &got); err != nil {
t.Fatalf("unmarshal: %v", err)
}
want := MatchAction{Type: MatchActionNone}
if !reflect.DeepEqual(got, want) {
t.Fatalf("got %#v, want %#v", got, want)
}
}

func TestMatchActionUnmarshalJSON_redact(t *testing.T) {
var got MatchAction
raw := `{"type":"Redact","match_action":"Redact","replacement":"[REDACTED]"}`
if err := json.Unmarshal([]byte(raw), &got); err != nil {
t.Fatalf("unmarshal: %v", err)
}
want := MatchAction{
Type: MatchActionRedact,
RedactionValue: "[REDACTED]",
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("got %#v, want %#v", got, want)
}
}

func TestMatchActionUnmarshalJSON_partialRedact(t *testing.T) {
var got MatchAction
raw := `{"type":"PartialRedact","match_action":"PartialRedact","character_count":4,"direction":"FirstCharacters"}`
if err := json.Unmarshal([]byte(raw), &got); err != nil {
t.Fatalf("unmarshal: %v", err)
}
want := MatchAction{
Type: MatchActionPartialRedact,
CharacterCount: 4,
Direction: FirstCharacters,
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("got %#v, want %#v", got, want)
}
}

func TestMatchActionUnmarshalJSON_unknownField(t *testing.T) {
err := json.Unmarshal([]byte(`{"type":"None","unexpected":true}`), &MatchAction{})
if err == nil {
t.Fatal("expected error for unknown field")
}
if !errors.Is(err, errors.New("json: unknown field \"unexpected\"")) && err.Error() != `json: unknown field "unexpected"` {
t.Fatalf("error = %q", err)
}
}

func TestMatchActionMarshalJSON_roundTrip(t *testing.T) {
in := MatchAction{
Type: MatchActionRedact,
RedactionValue: "[REDACTED]",
}
data, err := json.Marshal(in)
if err != nil {
t.Fatalf("marshal: %v", err)
}

var got MatchAction
dec := json.NewDecoder(bytes.NewReader(data))
dec.DisallowUnknownFields()
if err := dec.Decode(&got); err != nil {
t.Fatalf("unmarshal: %v", err)
}
if !reflect.DeepEqual(got, in) {
t.Fatalf("round trip mismatch: got %#v, want %#v", got, in)
}
}

func TestRegexRuleConfigUnmarshalJSON_withMatchAction(t *testing.T) {
raw := `{
"id": "r",
"pattern": "secret",
"match_action": {"type":"","match_action":""}
}`
var cfg RegexRuleConfig
dec := json.NewDecoder(bytes.NewReader([]byte(raw)))
dec.DisallowUnknownFields()
if err := dec.Decode(&cfg); err != nil {
t.Fatalf("decode: %v", err)
}
if cfg.MatchAction.Type != MatchActionNone {
t.Fatalf("MatchAction.Type = %q, want %q", cfg.MatchAction.Type, MatchActionNone)
}
}
Loading