mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 23:26:39 -08:00
feat(misconf): log causes of HCL file parsing errors (#7634)
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io> Co-authored-by: Simar <simar@linux.com> Co-authored-by: simar7 <1254783+simar7@users.noreply.github.com>
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
@@ -166,18 +168,69 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) error {
|
|||||||
}
|
}
|
||||||
sort.Strings(paths)
|
sort.Strings(paths)
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
if err := p.ParseFile(ctx, path); err != nil {
|
var err error
|
||||||
|
if err = p.ParseFile(ctx, path); err == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if p.stopOnHCLError {
|
if p.stopOnHCLError {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
var diags hcl.Diagnostics
|
||||||
|
if errors.As(err, &diags) {
|
||||||
|
errc := p.showParseErrors(p.moduleFS, path, diags)
|
||||||
|
if errc == nil {
|
||||||
|
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))
|
p.logger.Error("Error parsing file", log.FilePath(path), log.Err(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) showParseErrors(fsys fs.FS, filePath string, diags hcl.Diagnostics) error {
|
||||||
|
file, err := fsys.Open(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read file: %w", err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
for _, diag := range diags {
|
||||||
|
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(filePath),
|
||||||
|
log.String("cause", cause), log.Err(diag))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
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")
|
var ErrNoFiles = errors.New("no files found")
|
||||||
|
|
||||||
func (p *Parser) Load(ctx context.Context) (*evaluator, error) {
|
func (p *Parser) Load(ctx context.Context) (*evaluator, error) {
|
||||||
|
|||||||
@@ -2010,6 +2010,27 @@ variable "baz" {}
|
|||||||
assert.Contains(t, buf.String(), "variables=\"foo\"")
|
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 = <"`)
|
||||||
|
}
|
||||||
|
|
||||||
func Test_PassingNullToChildModule_DoesNotEraseType(t *testing.T) {
|
func Test_PassingNullToChildModule_DoesNotEraseType(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|||||||
Reference in New Issue
Block a user