Skip to content

Commit

Permalink
feat: support for dynamic metadata fields (#902)
Browse files Browse the repository at this point in the history
* feat: support for dynamic metadata fields

Signed-off-by: chenk <[email protected]>

* test: update dynamic test

Signed-off-by: chenk <[email protected]>

* fix: cyclomatic complexity

Signed-off-by: chenk <[email protected]>

Signed-off-by: chenk <[email protected]>
Co-authored-by: Liam Galvin <[email protected]>
  • Loading branch information
chen-keinan and liamg authored Aug 30, 2022
1 parent 06354bb commit 4a64f1e
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 5 deletions.
21 changes: 17 additions & 4 deletions pkg/rego/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func NewMetadataRetriever(compiler *ast.Compiler) *MetadataRetriever {
}
}

func (m *MetadataRetriever) RetrieveMetadata(ctx context.Context, module *ast.Module) (*StaticMetadata, error) {
func (m *MetadataRetriever) RetrieveMetadata(ctx context.Context, module *ast.Module, inputs ...Input) (*StaticMetadata, error) {

namespace := getModuleNamespace(module)
metadataQuery := fmt.Sprintf("data.%s.__rego_metadata__", namespace)
Expand All @@ -96,6 +96,11 @@ func (m *MetadataRetriever) RetrieveMetadata(ctx context.Context, module *ast.Mo
rego.Query(metadataQuery),
rego.Compiler(m.compiler),
}
// support dynamic metadata fields
for _, in := range inputs {
options = append(options, rego.Input(in.Contents))
}

instance := rego.New(options...)
set, err := instance.Eval(ctx)
if err != nil {
Expand All @@ -119,6 +124,15 @@ func (m *MetadataRetriever) RetrieveMetadata(ctx context.Context, module *ast.Mo
return nil, fmt.Errorf("failed to parse metadata: not an object")
}

err = m.updateMetadata(meta, &metadata)
if err != nil {
return nil, err
}

return &metadata, nil
}

func (m *MetadataRetriever) updateMetadata(meta map[string]interface{}, metadata *StaticMetadata) error {
if raw, ok := meta["id"]; ok {
metadata.ID = fmt.Sprintf("%s", raw)
}
Expand Down Expand Up @@ -149,14 +163,13 @@ func (m *MetadataRetriever) RetrieveMetadata(ctx context.Context, module *ast.Mo
if raw, ok := meta["frameworks"]; ok {
frameworks, ok := raw.(map[string][]string)
if !ok {
return nil, fmt.Errorf("failed to parse framework metadata: not an object")
return fmt.Errorf("failed to parse framework metadata: not an object")
}
for fw, sections := range frameworks {
metadata.Frameworks[framework.Framework(fw)] = sections
}
}

return &metadata, nil
return nil
}

func (m *MetadataRetriever) queryInputOptions(ctx context.Context, module *ast.Module) InputOptions {
Expand Down
2 changes: 1 addition & 1 deletion pkg/rego/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func (s *Scanner) ScanInput(ctx context.Context, inputs ...Input) (scan.Results,
continue
}

staticMeta, err := s.retriever.RetrieveMetadata(ctx, module)
staticMeta, err := s.retriever.RetrieveMetadata(ctx, module, inputs...)
if err != nil {
return nil, err
}
Expand Down
66 changes: 66 additions & 0 deletions pkg/rego/scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -678,3 +678,69 @@ deny {

assert.Greater(t, len(results.GetFailed()[0].Traces()), 0)
}
func Test_dynamicMetadata(t *testing.T) {

srcFS := testutil.CreateFS(t, map[string]string{
"policies/test.rego": `
package defsec.test
__rego_metadata__ := {
"title" : sprintf("i am %s",[input.text])
}
deny {
input.text
}
`,
})

scanner := NewScanner()
require.NoError(
t,
scanner.LoadPolicies(false, srcFS, []string{"policies"}, nil),
)

results, err := scanner.ScanInput(context.TODO(), Input{
Path: "/evil.lol",
Contents: map[string]interface{}{
"text": "dynamic",
},
Type: "???",
})
require.NoError(t, err)
assert.Equal(t, results[0].Rule().Summary, "i am dynamic")
}
func Test_staticMetadata(t *testing.T) {

srcFS := testutil.CreateFS(t, map[string]string{
"policies/test.rego": `
package defsec.test
__rego_metadata__ := {
"title" : "i am static"
}
deny {
input.text
}
`,
})

scanner := NewScanner()
require.NoError(
t,
scanner.LoadPolicies(false, srcFS, []string{"policies"}, nil),
)

results, err := scanner.ScanInput(context.TODO(), Input{
Path: "/evil.lol",
Contents: map[string]interface{}{
"text": "test",
},
Type: "???",
})
require.NoError(t, err)
assert.Equal(t, results[0].Rule().Summary, "i am static")
}

0 comments on commit 4a64f1e

Please sign in to comment.