Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

Add the filename to Rego fragment locations. #13

Merged
merged 1 commit into from
Aug 4, 2020
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
25 changes: 9 additions & 16 deletions pkg/doc/fragment.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"bytes"
"errors"
"fmt"
"io"

"github.com/projectcontour/integration-tester/pkg/utils"

Expand Down Expand Up @@ -79,6 +78,10 @@ func (t FragmentType) String() string {

// Location tracks the lines that bound a Fragment within some larger Document.
type Location struct {
// Filename is the name of the file this Fragment was read from
// (if that is known by the fragment reader).
Filename string

// Start is the line number this location starts on.
Start int

Expand All @@ -87,6 +90,10 @@ type Location struct {
}

func (l Location) String() string {
if l.Filename != "" {
return fmt.Sprintf("%s:%d-%d", l.Filename, l.Start, l.End)
}

return fmt.Sprintf("%d-%d", l.Start, l.End)
}

Expand Down Expand Up @@ -153,20 +160,6 @@ func decodeYAMLOrJSON(data []byte) (*unstructured.Unstructured, error) {
return &unstructured.Unstructured{Object: into}, nil
}

func decodeModule(data []byte) (*ast.Module, error) {
m, err := utils.ParseCheckFragment(string(data))
if err != nil {
return nil, err
}

// ParseModule can return nil with no error (empty module).
if m == nil {
return nil, io.EOF
}

return m, nil
}

// IsDecoded returns whether this fragment has been decoded to a known fragment type.
func (f *Fragment) IsDecoded() bool {
switch f.Type {
Expand Down Expand Up @@ -208,7 +201,7 @@ func (f *Fragment) Decode() (FragmentType, error) {
// Since we do want to propagate errors so that users can debug
// scripts, we have to assume this is meant to be Rego.

m, err := decodeModule(f.Bytes)
m, err := utils.ParseCheckFragment(f.Location.String(), string(f.Bytes))
if err != nil {
return FragmentTypeInvalid,
utils.ChainErrors(
Expand Down
15 changes: 11 additions & 4 deletions pkg/doc/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Document struct {
// YAML document separator (see https://yaml.org/spec/1.0/#id2561718).
// The contents of each Fragment is opaque and need not be YAML.
func ReadDocument(in io.Reader) (*Document, error) {
filename := ""
startLine := 0
currentLine := 0

Expand All @@ -45,6 +46,10 @@ func ReadDocument(in io.Reader) (*Document, error) {

scanner := bufio.NewScanner(in)

if f, ok := in.(*os.File); ok {
filename = f.Name()
}

// Scan the input a line at a time.
for scanner.Scan() {
currentLine++
Expand All @@ -66,8 +71,9 @@ func ReadDocument(in io.Reader) (*Document, error) {
doc.Parts = append(doc.Parts, Fragment{
Bytes: utils.CopyBytes(buf.Bytes()),
Location: Location{
Start: startLine,
End: currentLine - 1,
Filename: filename,
Start: startLine,
End: currentLine - 1,
},
})
}
Expand All @@ -85,8 +91,9 @@ func ReadDocument(in io.Reader) (*Document, error) {
doc.Parts = append(doc.Parts, Fragment{
Bytes: utils.CopyBytes(buf.Bytes()),
Location: Location{
Start: startLine,
End: currentLine,
Filename: filename,
Start: startLine,
End: currentLine,
},
})
}
Expand Down
9 changes: 7 additions & 2 deletions pkg/utils/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,20 @@ func ParseModuleFile(filePath string) (*ast.Module, error) {
// Rego input is assumed to not have a package declaration so a random
// package name is prepended to make the parsed module globally unique.
// ParseCheckFragment can return nil with no error if the input is empty.
func ParseCheckFragment(input string) (*ast.Module, error) {
// If the filename parameter is empty, an internal name will be generated.
func ParseCheckFragment(filename string, input string) (*ast.Module, error) {
// Rego requires a package name to generate any Rules. Force
// a package name that is unique to the fragment. Note that
// we also use this to generate a unique filename placeholder
// since Rego internals will sometime use this as a map key.
moduleName := RandomStringN(12)

if filename == "" {
filename = fmt.Sprintf("internal/check/%s", moduleName)
}

m, err := ast.ParseModule(
fmt.Sprintf("internal/check/%s", moduleName),
filename,
fmt.Sprintf("package check.%s\n%s", moduleName, input))
if err != nil {
return nil, err
Expand Down