diff --git a/pkg/cmd/scan.go b/pkg/cmd/scan.go index 9816fcc8..7f53bf00 100644 --- a/pkg/cmd/scan.go +++ b/pkg/cmd/scan.go @@ -157,6 +157,11 @@ func NewScanCmd() *cobra.Command { false, "Includes cloud provider service-linked roles (disabled by default)", ) + fl.StringVar(&opts.DriftignorePath, + "driftignore", + ".driftignore", + "Path to the driftignore file", + ) configDir, err := homedir.Dir() if err != nil { diff --git a/pkg/cmd/scan_test.go b/pkg/cmd/scan_test.go index 7181d5ae..a961b4e5 100644 --- a/pkg/cmd/scan_test.go +++ b/pkg/cmd/scan_test.go @@ -45,6 +45,8 @@ func TestScanCmd_Valid(t *testing.T) { {args: []string{"scan", "--strict"}}, {args: []string{"scan", "--tf-provider-version", "1.2.3"}}, {args: []string{"scan", "--tf-provider-version", "3.30.2"}}, + {args: []string{"scan", "--driftignore", "./path/to/driftignore.s3"}}, + {args: []string{"scan", "--driftignore", ".driftignore"}}, } for _, tt := range cases { @@ -85,6 +87,7 @@ func TestScanCmd_Invalid(t *testing.T) { {args: []string{"scan", "--filter", "Type='test'", "--filter", "Type='test2'"}, expected: "Filter flag should be specified only once"}, {args: []string{"scan", "--tf-provider-version", ".30.2"}, expected: "Invalid version argument .30.2, expected a valid semver string (e.g. 2.13.4)"}, {args: []string{"scan", "--tf-provider-version", "foo"}, expected: "Invalid version argument foo, expected a valid semver string (e.g. 2.13.4)"}, + {args: []string{"scan", "--driftignore"}, expected: "flag needs an argument: --driftignore"}, } for _, tt := range cases { diff --git a/pkg/driftctl.go b/pkg/driftctl.go index bc9cd64a..c9de92c2 100644 --- a/pkg/driftctl.go +++ b/pkg/driftctl.go @@ -31,6 +31,7 @@ type ScanOptions struct { DisableTelemetry bool ProviderVersion string ConfigDir string + DriftignorePath string } type DriftCTL struct { @@ -38,12 +39,11 @@ type DriftCTL struct { iacSupplier resource.Supplier alerter alerter.AlerterInterface analyzer analyser.Analyzer - filter *jmespath.JMESPath resourceFactory resource.ResourceFactory - strictMode bool scanProgress globaloutput.Progress iacProgress globaloutput.Progress resourceSchemaRepository resource.SchemaRepositoryInterface + opts *ScanOptions } func NewDriftCTL(remoteSupplier resource.Supplier, @@ -59,12 +59,11 @@ func NewDriftCTL(remoteSupplier resource.Supplier, iacSupplier, alerter, analyser.NewAnalyzer(alerter), - opts.Filter, resFactory, - opts.StrictMode, scanProgress, iacProgress, resourceSchemaRepository, + opts, } } @@ -100,7 +99,7 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) { middlewares.NewAwsRoleManagedPolicyExpander(d.resourceFactory), ) - if !d.strictMode { + if !d.opts.StrictMode { middleware = append(middleware, middlewares.NewAwsDefaults(), ) @@ -112,8 +111,8 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) { return nil, err } - if d.filter != nil { - engine := filter.NewFilterEngine(d.filter) + if d.opts.Filter != nil { + engine := filter.NewFilterEngine(d.opts.Filter) remoteResources, err = engine.Run(remoteResources) if err != nil { return nil, err @@ -125,7 +124,7 @@ func (d DriftCTL) Run() (*analyser.Analysis, error) { } logrus.Debug("Checking for driftignore") - driftIgnore := filter.NewDriftIgnore() + driftIgnore := filter.NewDriftIgnore(d.opts.DriftignorePath) analysis, err := d.analyzer.Analyze(remoteResources, resourcesFromState, driftIgnore) analysis.Duration = time.Since(start) diff --git a/pkg/filter/driftignore.go b/pkg/filter/driftignore.go index a0f3e28f..4a969f92 100644 --- a/pkg/filter/driftignore.go +++ b/pkg/filter/driftignore.go @@ -15,13 +15,15 @@ type DriftIgnore struct { resExclusionList map[string]struct{} // map[type.id] exists to ignore resExclusionWildcardList map[string]struct{} // map[type.id] exists with wildcard to ignore driftExclusionList map[string][]string // map[type.id] contains path for drift to ignore + driftignorePath string } -func NewDriftIgnore() *DriftIgnore { +func NewDriftIgnore(path string) *DriftIgnore { d := DriftIgnore{ resExclusionList: map[string]struct{}{}, resExclusionWildcardList: map[string]struct{}{}, driftExclusionList: map[string][]string{}, + driftignorePath: path, } err := d.readIgnoreFile() if err != nil { @@ -31,7 +33,7 @@ func NewDriftIgnore() *DriftIgnore { } func (r *DriftIgnore) readIgnoreFile() error { - file, err := os.Open(".driftignore") + file, err := os.Open(r.driftignorePath) if err != nil { return err } diff --git a/pkg/filter/driftignore_test.go b/pkg/filter/driftignore_test.go index 9af64710..28b0e4fd 100644 --- a/pkg/filter/driftignore_test.go +++ b/pkg/filter/driftignore_test.go @@ -2,7 +2,6 @@ package filter import ( "os" - "path" "reflect" "strings" "testing" @@ -19,6 +18,7 @@ func TestDriftIgnore_IsResourceIgnored(t *testing.T) { name string resources []resource.Resource want []bool + path string }{ { name: "drift_ignore_no_file", @@ -28,10 +28,10 @@ func TestDriftIgnore_IsResourceIgnored(t *testing.T) { Id: "id1", }, }, - want: []bool{ false, }, + path: "testdata/drift_ignore_no_file/.driftignore", }, { name: "drift_ignore_empty", @@ -44,6 +44,7 @@ func TestDriftIgnore_IsResourceIgnored(t *testing.T) { want: []bool{ false, }, + path: "testdata/drift_ignore_empty/.driftignore", }, { name: "drift_ignore_invalid_lines", @@ -61,6 +62,7 @@ func TestDriftIgnore_IsResourceIgnored(t *testing.T) { false, true, }, + path: "testdata/drift_ignore_invalid_lines/.driftignore", }, { name: "drift_ignore_valid", @@ -108,6 +110,7 @@ func TestDriftIgnore_IsResourceIgnored(t *testing.T) { true, true, }, + path: "testdata/drift_ignore_valid/.driftignore", }, { name: "drift_ignore_wildcard", @@ -150,16 +153,15 @@ func TestDriftIgnore_IsResourceIgnored(t *testing.T) { false, true, }, + path: "testdata/drift_ignore_wildcard/.driftignore", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cwd, _ := os.Getwd() defer func() { _ = os.Chdir(cwd) }() - if err := os.Chdir(path.Join("testdata", tt.name)); err != nil { - t.Fatal(err) - } - r := NewDriftIgnore() + + r := NewDriftIgnore(tt.path) got := make([]bool, 0, len(tt.want)) for _, res := range tt.resources { got = append(got, r.IsResourceIgnored(res)) @@ -180,6 +182,7 @@ func TestDriftIgnore_IsFieldIgnored(t *testing.T) { tests := []struct { name string args []Args + path string }{ { name: "drift_ignore_no_file", @@ -196,6 +199,7 @@ func TestDriftIgnore_IsFieldIgnored(t *testing.T) { Want: false, }, }, + path: "testdata/drift_ignore_no_file/.driftignore", }, { name: "drift_ignore_empty", @@ -211,6 +215,7 @@ func TestDriftIgnore_IsFieldIgnored(t *testing.T) { Want: false, }, }, + path: "testdata/drift_ignore_empty/.driftignore", }, { name: "drift_ignore_fields", @@ -281,16 +286,15 @@ func TestDriftIgnore_IsFieldIgnored(t *testing.T) { Want: true, }, }, + path: "testdata/drift_ignore_fields/.driftignore", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cwd, _ := os.Getwd() defer func() { _ = os.Chdir(cwd) }() - if err := os.Chdir(path.Join("testdata", tt.name)); err != nil { - t.Fatal(err) - } - r := NewDriftIgnore() + + r := NewDriftIgnore(tt.path) for _, arg := range tt.args { got := r.IsFieldIgnored(arg.Res, arg.Path) if arg.Want != got {