diff --git a/pkg/config/config_parser.go b/pkg/config/config_parser.go index 03d26422c70a08..ce03998b7a12d2 100644 --- a/pkg/config/config_parser.go +++ b/pkg/config/config_parser.go @@ -5,12 +5,13 @@ import ( "os" "strings" - "github.com/cloudquery/cloudquery/pkg/policy" - "github.com/creasty/defaults" - "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/gohcl" "github.com/spf13/viper" + + "github.com/cloudquery/cloudquery/pkg/policy" + + "github.com/hashicorp/hcl/v2" ) func (p *Parser) LoadConfigFromSource(name string, data []byte) (*Config, hcl.Diagnostics) { @@ -47,42 +48,9 @@ func (p *Parser) decodeConfig(body hcl.Body, diags hcl.Diagnostics) (*Config, hc for _, block := range content.Blocks { switch block.Type { case "cloudquery": - contentDiags = gohcl.DecodeBody(block.Body, &p.HCLContext, &config.CloudQuery) - diags = append(diags, contentDiags...) - // TODO: decode in a more generic way - - if config.CloudQuery.Connection == nil { - config.CloudQuery.Connection = &Connection{ - DSN: "", - } - } - if config.CloudQuery.History != nil { - if err := defaults.Set(config.CloudQuery.History); err != nil { - diags = append(diags, &hcl.Diagnostic{Severity: hcl.DiagError, Summary: "failed to set defaults in history"}) - } - } - - if dsn := viper.GetString("dsn"); dsn != "" { - config.CloudQuery.Connection.DSN = dsn - } - if dir := viper.GetString("plugin-dir"); dir != "." { - if dir == "." { - if dir, err := os.Getwd(); err == nil { - config.CloudQuery.PluginDirectory = dir - } - } else { - config.CloudQuery.PluginDirectory = dir - } - } - if dir := viper.GetString("policy-dir"); dir != "" { - if dir == "." { - if dir, err := os.Getwd(); err != nil { - config.CloudQuery.PolicyDirectory = dir - } - } else { - config.CloudQuery.PolicyDirectory = dir - } - } + cqBlock, cqDiags := decodeCloudQueryBlock(block, &p.HCLContext) + diags = diags.Extend(cqDiags) + config.CloudQuery = cqBlock case "provider": cfg, cfgDiags := decodeProviderBlock(block, &p.HCLContext, existingProviders) diags = append(diags, cfgDiags...) @@ -142,3 +110,54 @@ func ReadModuleConfigProfiles(module string, block hcl.Body) (map[string]hcl.Bod } return ret, nil } + +func decodeCloudQueryBlock(block *hcl.Block, ctx *hcl.EvalContext) (CloudQuery, hcl.Diagnostics) { + var cq CloudQuery + var diags hcl.Diagnostics + diags = diags.Extend(gohcl.DecodeBody(block.Body, ctx, &cq)) + + // TODO: decode in a more generic way + if cq.Connection == nil { + cq.Connection = &Connection{ + DSN: "", + } + } + if cq.History != nil { + if err := defaults.Set(cq.History); err != nil { + diags = append(diags, &hcl.Diagnostic{Severity: hcl.DiagError, Summary: "failed to set defaults in history"}) + } + } + if dsn := viper.GetString("dsn"); dsn != "" { + cq.Connection.DSN = dsn + } + if dir := viper.GetString("plugin-dir"); dir != "." { + if dir == "." { + if dir, err := os.Getwd(); err == nil { + cq.PluginDirectory = dir + } + } else { + cq.PluginDirectory = dir + } + } + if dir := viper.GetString("policy-dir"); dir != "" { + if dir == "." { + if dir, err := os.Getwd(); err == nil { + cq.PolicyDirectory = dir + } + } else { + cq.PolicyDirectory = dir + } + } + // validate provider versions + for _, cp := range cq.Providers { + if cp.Version != "latest" && !strings.HasPrefix(cp.Version, "v") { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Provider %s version %s is invalid", cp.Name, cp.Version), + Detail: "Please set to 'latest' version or valid semantic versioning starting with vX.Y.Z", + Subject: &block.DefRange, + }) + } + } + return cq, diags +} diff --git a/pkg/config/parser_test.go b/pkg/config/parser_test.go index 3102a0e5e37bde..4ca743296897cb 100644 --- a/pkg/config/parser_test.go +++ b/pkg/config/parser_test.go @@ -144,6 +144,16 @@ provider "aws" { ` const expectedDuplicateAliasProviderError = "test.hcl:23,3-21: Duplicate Alias; Provider with alias same-aws for provider aws already exists, give it a different alias." +const testBadVersion = `cloudquery { + connection { + dsn = "postgres://postgres:pass@localhost:5432/postgres" + } + provider "test" { + source = "cloudquery" + version = "0.0.0" + } +}` + type Account struct { ID string `hcl:",label"` RoleARN string `hcl:"role_arn,optional"` @@ -185,6 +195,13 @@ func TestParser_LoadConfigFromSource(t *testing.T) { }, cfg) } +func TestParser_BadVersion(t *testing.T) { + p := NewParser() + _, diags := p.LoadConfigFromSource("test.hcl", []byte(testBadVersion)) + assert.NotNil(t, diags) + assert.Equal(t, "test.hcl:1,1-11: Provider test version 0.0.0 is invalid; Please set to 'latest' version or valid semantic versioning starting with vX.Y.Z", diags[0].Error()) +} + func TestParser_DuplicateProviderNaming(t *testing.T) { p := NewParser() _, diags := p.LoadConfigFromSource("test.hcl", []byte(testMultipleProviderConfig))