Skip to content

Commit

Permalink
feat(misconf): log causes of HCL file parsing errors
Browse files Browse the repository at this point in the history
Signed-off-by: nikpivkin <[email protected]>
  • Loading branch information
nikpivkin committed Oct 2, 2024
1 parent 9baf658 commit e35e099
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 0 deletions.
50 changes: 50 additions & 0 deletions pkg/iac/scanners/terraform/parser/parser.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package parser

import (
"bufio"
"context"
"errors"
"fmt"
"io"
"io/fs"
"os"
Expand Down Expand Up @@ -163,6 +165,14 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) error {
if p.stopOnHCLError {
return err
}
var diags hcl.Diagnostics
if errors.As(err, &diags) {
errc := p.showParseErrors(p.moduleFS, path, diags)
if errc == nil {

Check failure on line 171 in pkg/iac/scanners/terraform/parser/parser.go

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

nestingReduce: invert if cond, replace body with `continue`, move old body after the statement (gocritic)
continue
}
p.logger.Error("Failed to get the causes of the parsing error", log.Err(errc))
}
p.logger.Error("Error parsing file", log.FilePath(path), log.Err(err))
continue
}
Expand All @@ -171,6 +181,46 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) error {
return nil
}

func (p *Parser) showParseErrors(fsys fs.FS, path string, diags hcl.Diagnostics) error {
file, err := fsys.Open(path)
if err != nil {
return fmt.Errorf("failed to read file: %w", err)
}
defer file.Close()

for _, diag := range diags {

Check failure on line 191 in pkg/iac/scanners/terraform/parser/parser.go

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest)

importShadow: shadow of imported package 'path' (gocritic)
if subj := diag.Subject; subj != nil {
lines, err := readLinesFromFile(file, subj.Start.Line, subj.End.Line)
if err != nil {
return err
}

cause := strings.Join(lines, "\n")
p.logger.Error("Error parsing file", log.FilePath(path),
log.String("cause", cause), log.Err(diag))
}
}

return nil
}

func readLinesFromFile(f io.Reader, from, to int) ([]string, error) {
scanner := bufio.NewScanner(f)
rawLines := make([]string, 0, to-from+1)

for lineNum := 0; scanner.Scan() && lineNum < to; lineNum++ {
if lineNum >= from-1 {
rawLines = append(rawLines, scanner.Text())
}
}

if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("failed to scan file: %w", err)
}

return rawLines, nil
}

var ErrNoFiles = errors.New("no files found")

func (p *Parser) Load(ctx context.Context) (*evaluator, error) {
Expand Down
21 changes: 21 additions & 0 deletions pkg/iac/scanners/terraform/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1884,3 +1884,24 @@ variable "baz" {}
assert.Contains(t, buf.String(), "Variable values was not found in the environment or variable files.")
assert.Contains(t, buf.String(), "variables=\"foo\"")
}

func TestLogParseErrors(t *testing.T) {
var buf bytes.Buffer
slog.SetDefault(slog.New(log.NewHandler(&buf, nil)))

src := `resource "aws-s3-bucket" "name" {
bucket = <
}`

fsys := fstest.MapFS{
"main.tf": &fstest.MapFile{
Data: []byte(src),
},
}

parser := New(fsys, "")
err := parser.ParseFS(context.TODO(), ".")
require.NoError(t, err)

assert.Contains(t, buf.String(), `cause=" bucket = <"`)
}

0 comments on commit e35e099

Please sign in to comment.