-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat(partition): add venom test * feat(partition): create empty partition mask * feat(partition): test partition conditions * feat(partition): exec active partition * fix(partition): partitions must be ordered * feat(partition): update docs
- Loading branch information
1 parent
a3e799c
commit f2acba3
Showing
7 changed files
with
269 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
package partition | ||
|
||
import ( | ||
"bytes" | ||
"hash/fnv" | ||
tmpl "text/template" | ||
|
||
"github.com/cgi-fr/pimo/pkg/template" | ||
|
||
"github.com/cgi-fr/pimo/pkg/model" | ||
"github.com/rs/zerolog/log" | ||
) | ||
|
||
type MaskEngine struct { | ||
partitions []Partition | ||
seed int64 | ||
seeder model.Seeder | ||
} | ||
|
||
type Partition struct { | ||
name string | ||
when *template.Engine | ||
exec model.Pipeline | ||
} | ||
|
||
func buildDefinition(masks []model.MaskType, globalSeed int64) model.Definition { | ||
definition := model.Definition{ | ||
Version: "1", | ||
Seed: globalSeed, | ||
Functions: nil, | ||
Masking: []model.Masking{}, | ||
Caches: nil, | ||
} | ||
|
||
for _, mask := range masks { | ||
definition.Masking = append(definition.Masking, model.Masking{ | ||
Selector: model.SelectorType{Jsonpath: "."}, | ||
Mask: mask, | ||
}) | ||
} | ||
|
||
return definition | ||
} | ||
|
||
// NewMask return a MaskEngine from a value | ||
func NewMask(partitions []model.PartitionType, caches map[string]model.Cache, fns tmpl.FuncMap, seed int64, seeder model.Seeder, seedField string) (MaskEngine, error) { | ||
parts := []Partition{} | ||
|
||
// Build partitions pipelines | ||
for _, partition := range partitions { | ||
template, err := template.NewEngine(partition.When, fns, seed, seedField) | ||
if err != nil { | ||
return MaskEngine{}, err | ||
} | ||
|
||
if partition.When == "" { | ||
template = nil | ||
} | ||
|
||
definition := buildDefinition(partition.Then, seed) | ||
pipeline := model.NewPipeline(nil) | ||
pipeline, _, err = model.BuildPipeline(pipeline, definition, caches, fns, "", "") | ||
if err != nil { | ||
return MaskEngine{}, err | ||
} | ||
|
||
parts = append(parts, Partition{ | ||
name: partition.Name, | ||
when: template, | ||
exec: pipeline, | ||
}) | ||
} | ||
|
||
return MaskEngine{parts, seed, seeder}, nil | ||
} | ||
|
||
func execPipeline(pipeline model.Pipeline, e model.Entry) (model.Entry, error) { | ||
var result []model.Entry | ||
|
||
err := pipeline. | ||
WithSource(model.NewSourceFromSlice([]model.Dictionary{model.NewDictionary().With(".", e)})). | ||
// Process(model.NewCounterProcessWithCallback("internal", 1, updateContext)). | ||
AddSink(model.NewSinkToSlice(&result)). | ||
Run() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if len(result) == 0 { | ||
return nil, nil | ||
} | ||
|
||
return result[0], nil | ||
} | ||
|
||
func (me MaskEngine) Mask(e model.Entry, context ...model.Dictionary) (model.Entry, error) { | ||
log.Info().Msg("Mask partition") | ||
|
||
// exec all partitions | ||
for _, partition := range me.partitions { | ||
var output bytes.Buffer | ||
|
||
if partition.when != nil { | ||
if err := partition.when.Execute(&output, context[0].UnpackUnordered()); err != nil { | ||
return nil, err | ||
} | ||
} else { | ||
output.WriteString("true") | ||
} | ||
|
||
if output.String() == "true" { | ||
log.Info().Msgf("Mask partition - executing partition %s", partition.name) | ||
|
||
result, err := execPipeline(partition.exec, e) | ||
if err != nil { | ||
return e, err | ||
} | ||
|
||
return result, nil | ||
} | ||
} | ||
|
||
return e, nil | ||
} | ||
|
||
// Factory create a mask from a configuration | ||
func Factory(conf model.MaskFactoryConfiguration) (model.MaskEngine, bool, error) { | ||
if len(conf.Masking.Mask.Partition) > 0 { | ||
seeder := model.NewSeeder(conf.Masking.Seed.Field, conf.Seed) | ||
|
||
// set differents seeds for differents jsonpath | ||
h := fnv.New64a() | ||
h.Write([]byte(conf.Masking.Selector.Jsonpath)) | ||
conf.Seed += int64(h.Sum64()) //nolint:gosec | ||
mask, err := NewMask(conf.Masking.Mask.Partition, conf.Cache, conf.Functions, conf.Seed, seeder, conf.Masking.Seed.Field) | ||
if err != nil { | ||
return mask, true, err | ||
} | ||
return mask, true, nil | ||
} | ||
return nil, false, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
name: partition mask | ||
testcases: | ||
- name: simple partition with default case | ||
steps: | ||
- script: |- | ||
cat > masking.yml <<EOF | ||
version: "1" | ||
seed: 42 | ||
masking: | ||
- selector: | ||
jsonpath: "id" | ||
mask: | ||
partitions: | ||
- name: idrh | ||
when: '[[ .id | default "" | mustRegexMatch "^P[A-Z]{3}[0-9]{3}$" ]]' | ||
then: | ||
- constant: "IDRH" | ||
- name: digits | ||
when: '[[ .id | default "" | mustRegexMatch "^[0-9]+$" ]]' | ||
then: | ||
- constant: "DIGITS" | ||
- name: others | ||
then: | ||
- constant: "OTHER" | ||
EOF | ||
- script: sed -i "s/\[\[/\{\{/g" masking.yml | ||
- script: sed -i "s/\]\]/\}\}/g" masking.yml | ||
- script: |- | ||
pimo <<EOF | ||
{"case": 1, "id": "PZZZ123"} | ||
{"case": 2, "id": "12345"} | ||
{"case": 3, "id": "PABC000"} | ||
{"case": 4, "id": "PABCD000"} | ||
{"case": 5, "id": ""} | ||
{"case": 6, "id": null} | ||
EOF | ||
assertions: | ||
- result.code ShouldEqual 0 | ||
- 'result.systemout ShouldContainSubstring {"case":1,"id":"IDRH"}' | ||
- 'result.systemout ShouldContainSubstring {"case":2,"id":"DIGITS"}' | ||
- 'result.systemout ShouldContainSubstring {"case":3,"id":"IDRH"}' | ||
- 'result.systemout ShouldContainSubstring {"case":4,"id":"OTHER"}' | ||
- 'result.systemout ShouldContainSubstring {"case":5,"id":"OTHER"}' | ||
- 'result.systemout ShouldContainSubstring {"case":6,"id":"OTHER"}' | ||
- result.systemerr ShouldBeEmpty |