Accept both sp and pp files as mod data extension. Closes #4089

This commit is contained in:
kaidaguerre
2024-02-05 11:11:00 -06:00
committed by GitHub
parent eedf4ba946
commit 33210d4fe7
83 changed files with 977 additions and 99 deletions

View File

@@ -328,6 +328,7 @@ jobs:
- "mod_vars"
- "mod"
- "mod_require"
- "pp_files"
- "check"
- "performance"
- "config_precedence"

View File

@@ -110,6 +110,7 @@ jobs:
- "mod_vars"
- "mod"
- "mod_require"
- "pp_files"
- "check"
- "performance"
- "config_precedence"

View File

@@ -1,4 +1,4 @@
## v0.21.5 [2024-02-02]
## v0.21.5 [tbd]
_Bug fixes_
* Fix dependency variable validation - was failing if dependency variable value was set in the vars file. ([#4110](https://github.com/turbot/steampipe/issues/4110))
* Fix UI freeze when prompting for workspace variables. ([#4105](https://github.com/turbot/steampipe/issues/4105))

View File

@@ -343,7 +343,7 @@ func createWorkspaceMod(ctx context.Context, cmd *cobra.Command, workspacePath s
return nil, fmt.Errorf("mod %s cancelled", cmd.Name())
}
if parse.ModfileExists(workspacePath) {
if _, exists := parse.ModfileExists(workspacePath); exists {
fmt.Println("Working folder already contains a mod definition file")
return nil, nil
}
@@ -354,7 +354,7 @@ func createWorkspaceMod(ctx context.Context, cmd *cobra.Command, workspacePath s
}
// only print message for mod init (not for mod install)
if cmd.Name() == "init" {
fmt.Printf("Created mod definition file '%s'\n", filepaths.ModFilePath(workspacePath))
fmt.Printf("Created mod definition file '%s'\n", filepaths.DefaultModFilePath(workspacePath))
}
// load up the written mod file so that we get the updated

View File

@@ -2,19 +2,19 @@ package constants
import "github.com/turbot/go-kit/helpers"
var ModDataExtensions = []string{".sp", "*.pp"}
var ModDataExtensions = []string{".sp", ".pp"}
var VariablesExtensions = []string{".spvars", ".ppvars"}
var AutoVariablesExtensions = []string{".auto.spvars", ".auto.ppvars"}
const (
PluginExtension = ".plugin"
ConfigExtension = ".spc"
SqlExtension = ".sql"
VariablesExtension = ".spvars"
AutoVariablesExtension = ".auto.spvars"
JsonExtension = ".json"
TextExtension = ".txt"
SnapshotExtension = ".sps"
TokenExtension = ".tptt"
LegacyTokenExtension = ".sptt"
PluginExtension = ".plugin"
ConfigExtension = ".spc"
SqlExtension = ".sql"
JsonExtension = ".json"
TextExtension = ".txt"
SnapshotExtension = ".sps"
TokenExtension = ".tptt"
LegacyTokenExtension = ".sptt"
)
var YamlExtensions = []string{".yml", ".yaml"}

View File

@@ -9,6 +9,8 @@ import (
"github.com/turbot/steampipe/pkg/constants/runtime"
)
var ModFileNames = []string{"mod.sp", "mod.pp"}
// mod related constants
const (
WorkspaceDataDir = ".steampipe"
@@ -16,7 +18,6 @@ const (
WorkspaceModShadowDirPrefix = ".mods."
WorkspaceConfigFileName = "workspace.spc"
WorkspaceIgnoreFile = ".steampipeignore"
ModFileName = "mod.sp"
DefaultVarsFileName = "steampipe.spvars"
WorkspaceLockFileName = ".mod.cache.json"
)
@@ -41,7 +42,16 @@ func DefaultVarsFilePath(workspacePath string) string {
return path.Join(workspacePath, DefaultVarsFileName)
}
func ModFilePath(modFolder string) string {
modFilePath := filepath.Join(modFolder, ModFileName)
return modFilePath
func DefaultModFilePath(modFolder string) string {
return filepath.Join(modFolder, ModFileNames[0])
}
func ModFilePaths(modFolder string) []string {
var modFilePaths []string
for _, modFileName := range ModFileNames {
modFilePaths = append(modFilePaths, filepath.Join(modFolder, modFileName))
}
return modFilePaths
}

View File

@@ -6,7 +6,6 @@ import (
"os"
"github.com/hashicorp/hcl/v2/hclwrite"
"github.com/turbot/steampipe/pkg/filepaths"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/zclconf/go-cty/cty"
)
@@ -52,13 +51,13 @@ func (i *ModInstaller) updateModFile() error {
contents.ApplyChanges(changes)
contents.Apply(hclwrite.Format)
return os.WriteFile(filepaths.ModFilePath(i.workspaceMod.ModPath), contents.Bytes(), 0644)
return os.WriteFile(i.workspaceMod.FilePath(), contents.Bytes(), 0644)
}
// loads the contents of the mod.sp file and wraps it with a thin wrapper
// to assist in byte sequence manipulation
func (i *ModInstaller) loadModFileBytes() (*ByteSequence, error) {
modFileBytes, err := os.ReadFile(filepaths.ModFilePath(i.workspaceMod.ModPath))
modFileBytes, err := os.ReadFile(i.workspaceMod.FilePath())
if err != nil {
return nil, err
}

View File

@@ -326,5 +326,10 @@ func (v unparsedVariableValueString) ParseVariableValue(mode var_config.Variable
// isAutoVarFile determines if the file ends with .auto.spvars or .auto.spvars.json
func isAutoVarFile(path string) bool {
return strings.HasSuffix(path, constants.AutoVariablesExtension)
for _, ext := range constants.AutoVariablesExtensions {
if strings.HasSuffix(path, ext) {
return true
}
}
return false
}

View File

@@ -67,10 +67,11 @@ func loadModDefinition(ctx context.Context, modPath string, parseCtx *parse.ModP
return nil, error_helpers.NewErrorsAndWarning(fmt.Errorf("mod folder %s does not exist", modPath))
}
if parse.ModfileExists(modPath) {
modFilePath, exists := parse.ModfileExists(modPath)
if exists {
// load the mod definition to get the dependencies
var res *parse.DecodeResult
mod, res = parse.ParseModDefinition(modPath, parseCtx.EvalCtx)
mod, res = parse.ParseModDefinition(modFilePath, parseCtx.EvalCtx)
errorsAndWarnings = error_helpers.DiagsToErrorsAndWarnings("mod load failed", res.Diags)
if res.Diags.HasErrors() {
return nil, errorsAndWarnings
@@ -235,7 +236,7 @@ func LoadModResourceNames(ctx context.Context, mod *modconfig.Mod, parseCtx *par
// this will be the mod data extension, plus any registered extensions registered in fileToResourceMap
func GetModFileExtensions() []string {
res := append(modconfig.RegisteredFileExtensions(), constants.ModDataExtensions...)
return append(res, constants.VariablesExtension)
return append(res, constants.VariablesExtensions...)
}
// build list of all filepaths we need to parse/load the mod

View File

@@ -2,19 +2,16 @@ package modconfig
import (
"fmt"
"github.com/turbot/go-kit/hcl_helpers"
"os"
"path/filepath"
"strings"
"github.com/Masterminds/semver/v3"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/hcl/v2/hclwrite"
filehelpers "github.com/turbot/go-kit/files"
"github.com/turbot/go-kit/hcl_helpers"
typehelpers "github.com/turbot/go-kit/types"
"github.com/turbot/steampipe/pkg/filepaths"
"github.com/zclconf/go-cty/cty"
"os"
"path/filepath"
)
// mod name used if a default mod is created for a workspace which does not define one explicitly
@@ -141,6 +138,10 @@ func (m *Mod) IsDefaultMod() bool {
return m.modFilePath == ""
}
func (m *Mod) FilePath() string {
return m.modFilePath
}
// GetPaths implements ModTreeItem (override base functionality)
func (m *Mod) GetPaths() []NodePath {
return []NodePath{{m.Name()}}
@@ -286,13 +287,7 @@ func (m *Mod) Save() error {
}
}
// load existing mod data and remove the mod definitions from it
nonModData, err := m.loadNonModDataInModFile()
if err != nil {
return err
}
modData := append(f.Bytes(), nonModData...)
return os.WriteFile(filepaths.ModFilePath(m.ModPath), modData, 0644)
return os.WriteFile(filepaths.DefaultModFilePath(m.ModPath), f.Bytes(), 0644)
}
func (m *Mod) HasDependentMods() bool {
@@ -306,32 +301,6 @@ func (m *Mod) GetModDependency(modName string) *ModVersionConstraint {
return m.Require.GetModDependency(modName)
}
func (m *Mod) loadNonModDataInModFile() ([]byte, error) {
modFilePath := filepaths.ModFilePath(m.ModPath)
if !filehelpers.FileExists(modFilePath) {
return nil, nil
}
fileData, err := os.ReadFile(modFilePath)
if err != nil {
return nil, err
}
fileLines := strings.Split(string(fileData), "\n")
decl := m.DeclRange
// just use line positions
start := decl.Start.Line - 1
end := decl.End.Line - 1
var resLines []string
for i, line := range fileLines {
if (i < start || i > end) && line != "" {
resLines = append(resLines, line)
}
}
return []byte(strings.Join(resLines, "\n")), nil
}
func (m *Mod) WalkResources(resourceFunc func(item HclResource) (bool, error)) error {
return m.ResourceMaps.WalkResources(resourceFunc)
}

View File

@@ -11,13 +11,13 @@ import (
"github.com/hashicorp/hcl/v2"
"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
"github.com/turbot/steampipe/pkg/error_helpers"
"github.com/turbot/steampipe/pkg/filepaths"
"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
"github.com/zclconf/go-cty/cty"
)
func LoadModfile(modPath string) (*modconfig.Mod, error) {
if !ModfileExists(modPath) {
modFilePath, exists := ModfileExists(modPath)
if !exists {
return nil, nil
}
@@ -27,7 +27,7 @@ func LoadModfile(modPath string) (*modconfig.Mod, error) {
Variables: make(map[string]cty.Value),
}
mod, res := ParseModDefinition(modPath, evalCtx)
mod, res := ParseModDefinition(modFilePath, evalCtx)
if res.Diags.HasErrors() {
return nil, plugin.DiagsToError("Failed to load mod", res.Diags)
}
@@ -38,15 +38,14 @@ func LoadModfile(modPath string) (*modconfig.Mod, error) {
// ParseModDefinition parses the modfile only
// it is expected the calling code will have verified the existence of the modfile by calling ModfileExists
// this is called before parsing the workspace to, for example, identify dependency mods
func ParseModDefinition(modPath string, evalCtx *hcl.EvalContext) (*modconfig.Mod, *DecodeResult) {
func ParseModDefinition(modFilePath string, evalCtx *hcl.EvalContext) (*modconfig.Mod, *DecodeResult) {
res := newDecodeResult()
// if there is no mod at this location, return error
modFilePath := filepaths.ModFilePath(modPath)
if _, err := os.Stat(modFilePath); os.IsNotExist(err) {
res.Diags = append(res.Diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("no mod file found in %s", modPath),
Summary: fmt.Sprintf("modfile %s does not exist", modFilePath),
})
return nil, res
}
@@ -73,7 +72,7 @@ func ParseModDefinition(modPath string, evalCtx *hcl.EvalContext) (*modconfig.Mo
if block == nil {
res.Diags = append(res.Diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("failed to parse mod definition file: no mod definition found in %s", fmt.Sprintf("%s/mod.sp", modPath)),
Summary: fmt.Sprintf("failed to parse mod definition file: no mod definition found in %s", modFilePath),
})
return nil, res
}

View File

@@ -2,6 +2,7 @@ package parse
import (
"fmt"
"github.com/turbot/steampipe/pkg/filepaths"
"io"
"log"
"os"
@@ -81,13 +82,14 @@ func buildOrderedFileNameList(fileData map[string][]byte) []string {
return filePaths
}
// ModfileExists returns whether a mod file exists at the specified path
func ModfileExists(modPath string) bool {
modFilePath := filepath.Join(modPath, "mod.sp")
if _, err := os.Stat(modFilePath); os.IsNotExist(err) {
return false
// ModfileExists returns whether a mod file exists at the specified path and if so returns the filepath
func ModfileExists(modPath string) (string, bool) {
for _, modFilePath := range filepaths.ModFilePaths(modPath) {
if _, err := os.Stat(modFilePath); err == nil {
return modFilePath, true
}
}
return true
return "", false
}
// parse a yaml file into a hcl.File object

View File

@@ -235,29 +235,28 @@ func (w *Workspace) setModfileExists() {
}
}
// TODO comment
// FindModFilePath looks in the current folder for mod.sp or mod.pp
// if not found it looks in the parent folder - right up to the root
func FindModFilePath(folder string) (string, error) {
folder, err := filepath.Abs(folder)
if err != nil {
return "", err
}
modFilePath := filepaths.ModFilePath(folder)
_, err = os.Stat(modFilePath)
if err == nil {
// found the modfile
return modFilePath, nil
for _, modFilePath := range filepaths.ModFilePaths(folder) {
_, err = os.Stat(modFilePath)
if err == nil {
// found the modfile
return modFilePath, nil
}
}
if os.IsNotExist(err) {
// if the file wasn't found, search in the parent directory
parent := filepath.Dir(folder)
if folder == parent {
// this typically means that we are already in the root directory
return "", ErrorNoModDefinition
}
return FindModFilePath(filepath.Dir(folder))
// if the file wasn't found, search in the parent directory
parent := filepath.Dir(folder)
if folder == parent {
// this typically means that we are already in the root directory
return "", ErrorNoModDefinition
}
return modFilePath, nil
return FindModFilePath(filepath.Dir(folder))
}
func HomeDirectoryModfileCheck(ctx context.Context, workspacePath string) error {
@@ -269,8 +268,13 @@ func HomeDirectoryModfileCheck(ctx context.Context, workspacePath string) error
// get the cmd and home dir
cmd := viper.Get(constants.ConfigKeyActiveCommand).(*cobra.Command)
home, _ := os.UserHomeDir()
_, err := os.Stat(filepaths.ModFilePath(workspacePath))
modFileExists := !os.IsNotExist(err)
var modFileExists bool
for _, modFilePath := range filepaths.ModFilePaths(workspacePath) {
if _, err := os.Stat(modFilePath); err != nil {
modFileExists = true
}
}
// check if your workspace path is home dir and if modfile exists
if workspacePath == home && modFileExists {

View File

@@ -0,0 +1,28 @@
benchmark "all_controls_ok" {
title = "All controls in OK, no ALARMS/ERORS"
description = "Benchmark to verify the exit code when no controls are in error/alarm"
children = [
control.ok_1,
control.ok_2
]
}
control "ok_1" {
title = "Control to verify the exit code when no controls are in error/alarm"
description = "Control to verify the exit code when no controls are in error/alarm"
query = query.query_1
severity = "high"
}
control "ok_2" {
title = "Control to verify the exit code when no controls are in error/alarm"
description = "Control to verify the exit code when no controls are in error/alarm"
query = query.query_1
severity = "high"
}
query "query_1"{
title ="query_1"
description = "Simple query 1"
sql = "select 'ok' as status, 'steampipe' as resource, 'acceptance tests' as reason"
}

View File

@@ -0,0 +1,21 @@
benchmark "check_cache_benchmark" {
title = "Benchmark to test the cache functionality in steampipe"
children = [
control.cache_test_1,
control.cache_test_2
]
}
control "cache_test_1" {
title = "Control to test cache functionality 1"
description = "Control to test cache functionality in steampipe."
sql = query.check_cache.sql
severity = "high"
}
control "cache_test_2" {
title = "Control to test cache functionality 2"
description = "Control to test cache functionality in steampipe."
sql = query.check_cache.sql
severity = "high"
}

View File

@@ -0,0 +1,191 @@
benchmark "query_and_control_parameters_benchmark" {
title = "Benchmark to test the query and control parameter functionalities in steampipe"
children = [
control.query_params_with_defaults_and_no_args,
control.query_params_with_defaults_and_partial_named_args,
control.query_params_with_defaults_and_partial_positional_args,
control.query_params_with_defaults_and_all_named_args,
control.query_params_with_defaults_and_all_positional_args,
control.query_params_with_no_defaults_and_no_args,
control.query_params_with_no_defaults_with_named_args,
control.query_params_with_no_defaults_with_positional_args,
control.query_params_array_with_default,
control.query_params_map_with_default,
control.query_params_invalid_arg_syntax,
control.query_inline_sql_from_control_with_partial_named_args,
control.query_inline_sql_from_control_with_partial_positional_args,
control.query_inline_sql_from_control_with_no_args,
control.query_inline_sql_from_control_with_all_positional_args,
control.query_inline_sql_from_control_with_all_named_args
]
}
control "query_params_with_defaults_and_no_args" {
title = "Control to test query param functionality with defaults(and no args passed)"
query = query.query_params_with_all_defaults
}
control "query_params_with_defaults_and_partial_named_args" {
title = "Control to test query param functionality with defaults(and some named args passed in query)"
query = query.query_params_with_all_defaults
args = {
"p2" = "command_parameter_2"
}
}
control "query_params_with_defaults_and_partial_positional_args" {
title = "Control to test query param functionality with defaults(and some positional args passed in query)"
query = query.query_params_with_all_defaults
args = [ "command_parameter_1" ]
}
control "query_params_with_defaults_and_all_named_args" {
title = "Control to test query param functionality with defaults(and all named args passed in query)"
query = query.query_params_with_all_defaults
args = {
"p1" = "command_parameter_1"
"p2" = "command_parameter_2"
"p3" = "command_parameter_3"
}
}
control "query_params_with_defaults_and_all_positional_args" {
title = "Control to test query param functionality with defaults(and all positional args passed in query)"
query = query.query_params_with_all_defaults
args = [ "command_parameter_1", "command_parameter_2", "command_parameter_3" ]
}
control "query_params_with_no_defaults_and_no_args" {
title = "Control to test query param functionality with no defaults(and no args passed)"
query = query.query_params_with_no_defaults
}
control "query_params_with_no_defaults_with_named_args" {
title = "Control to test query param functionality with no defaults(and args passed in query)"
query = query.query_params_with_no_defaults
args = {
"p1" = "command_parameter_1"
"p2" = "command_parameter_2"
"p3" = "command_parameter_3"
}
}
control "query_params_with_no_defaults_with_positional_args" {
title = "Control to test query param functionality with no defaults(and positional args passed in query)"
query = query.query_params_with_no_defaults
args = [ "command_parameter_1", "command_parameter_2","command_parameter_3" ]
}
control "query_params_array_with_default" {
title = "Control to test query param functionality with an array param with default(and no args passed)"
query = query.query_array_params_with_default
}
control "query_params_map_with_default" {
title = "Control to test query param functionality with a map param with default(and no args passed)"
query = query.query_map_params_with_default
}
control "query_params_invalid_arg_syntax" {
title = "Control to test query param functionality with a map param with no default(and invalid args passed in query)"
query = query.query_map_params_with_no_default
args = {
"p1" = "command_parameter_1"
}
}
control "query_inline_sql_from_control_with_partial_named_args" {
title = "Control to test the inline sql functionality within a control with defaults(and some named args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
args = {
"p1" = "command_parameter_1"
"p3" = "command_parameter_3"
}
}
control "query_inline_sql_from_control_with_partial_positional_args" {
title = "Control to test the inline sql functionality within a control with defaults(and some positional args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
args = [ "command_parameter_1", "command_parameter_2" ]
}
control "query_inline_sql_from_control_with_no_args" {
title = "Control to test the inline sql functionality within a control with defaults(and no args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
}
control "query_inline_sql_from_control_with_all_positional_args" {
title = "Control to test the inline sql functionality within a control with defaults(and all positional args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
args = [ "command_parameter_1", "command_parameter_2", "command_parameter_3" ]
}
control "query_inline_sql_from_control_with_all_named_args" {
title = "Control to test the inline sql functionality within a control with defaults(and all named args passed in control)"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "p1"
default = "default_parameter_1"
}
param "p2"{
description = "p2"
default = "default_parameter_2"
}
param "p3"{
description = "p3"
default = "default_parameter_3"
}
args = {
"p1" = "command_parameter_1"
"p2" = "command_parameter_2"
"p3" = "command_parameter_3"
}
}

View File

@@ -0,0 +1,45 @@
benchmark "control_summary_benchmark" {
title = "Benchmark to test the check summary output in steampipe"
children = [
control.sample_control_1,
control.sample_control_2,
control.sample_control_3,
control.sample_control_4,
control.sample_control_5
]
}
control "sample_control_1" {
title = "Sample control 1"
description = "A sample control"
sql = query.static_query.sql
severity = "high"
}
control "sample_control_2" {
title = "Sample control 2"
description = "A sample control"
sql = query.static_query.sql
severity = "critical"
}
control "sample_control_3" {
title = "Sample control 3"
description = "A sample control"
sql = query.static_query.sql
severity = "high"
}
control "sample_control_4" {
title = "Sample control 4"
description = "A sample control that returns ERROR"
sql = query.static_query.sql
severity = "critical"
}
control "sample_control_5" {
title = "Sample control 5"
description = "A sample control"
sql = query.static_query.sql
severity = "high"
}

View File

@@ -0,0 +1,29 @@
benchmark "check_plugin_crash_benchmark" {
title = "Benchmark to test the plugin crash bug while running controls"
children = [
control.plugin_chaos_test_1,
control.plugin_crash_test,
control.plugin_chaos_test_2
]
}
control "plugin_chaos_test_1" {
title = "Control to query a chaos table"
description = "Control to query a chaos table to test all flavours of integer and float data types"
sql = query.check_plugincrash_normalquery1.sql
severity = "high"
}
control "plugin_crash_test" {
title = "Control to simulate a plugin crash"
description = "Control to query a chaos table that prints 50 rows and do an os.Exit(-1) to simulate a plugin crash"
sql = "select * from chaos_plugin_crash"
severity = "high"
}
control "plugin_chaos_test_2" {
title = "Control to query a chaos table"
description = "Control to query a chaos table test the Get call with all the possible scenarios like errors, panics and delays"
sql = query.check_plugincrash_normalquery2.sql
severity = "high"
}

View File

@@ -0,0 +1,4 @@
mod "functionality_test_mod_pp"{
title = "Functionality test mod with pp files"
description = "This is a simple mod used for testing different steampipe features and funtionalities."
}

View File

@@ -0,0 +1,8 @@
select
case
when mod(id,2)=0 then 'alarm'
when mod(id,2)=1 then 'ok'
end status,
unique_col as resource,
id as reason
from chaos.chaos_cache_check where id=2

View File

@@ -0,0 +1,8 @@
select
case
when mod(id,2)=0 then 'alarm'
when mod(id,2)=1 then 'ok'
end status,
int8_data as resource,
int16_data as reason
from chaos_all_numeric_column

View File

@@ -0,0 +1,8 @@
select
case
when mod(id,2)=0 then 'alarm'
when mod(id,2)=1 then 'ok'
end status,
fatal_error as resource,
retryable_error as reason
from chaos_get_errors limit 10

View File

@@ -0,0 +1,56 @@
query "query_params_with_all_defaults"{
description = "query 1 - 3 params all with defaults"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "First parameter"
default = "default_parameter_1"
}
param "p2"{
description = "Second parameter"
default = "default_parameter_2"
}
param "p3"{
description = "Third parameter"
default = "default_parameter_3"
}
}
query "query_params_with_no_defaults"{
description = "query 1 - 3 params with no defaults"
sql = "select 'ok' as status, 'steampipe' as resource, concat($1::text, ' ', $2::text, ' ', $3::text) as reason"
param "p1"{
description = "First parameter"
}
param "p2"{
description = "Second parameter"
}
param "p3"{
description = "Third parameter"
}
}
query "query_array_params_with_default"{
description = "query an array parameter with default"
sql = "select 'ok' as status, 'steampipe' as resource, $1::jsonb->1 as reason"
param "p1"{
description = "Array parameter"
default = ["default_p1_element_01", "default_p1_element_02", "default_p1_element_03"]
}
}
query "query_map_params_with_default"{
description = "query a map parameter with default"
sql = "select 'ok' as status, 'steampipe' as resource, $1::json->'default_property_01' as reason"
param "p1"{
description = "Map parameter"
default = {"default_property_01": "default_property_value_01", "default_property_02": "default_property_value_02"}
}
}
query "query_map_params_with_no_default"{
description = "query a map parameter with no default"
sql = "select 'ok' as status, 'steampipe' as resource, $1::json->'default_property_01' as reason"
param "p1"{
description = "Map parameter"
}
}

View File

@@ -0,0 +1,11 @@
WITH s_path AS (select setting from pg_settings where name='search_path')
SELECT s_path.setting as resource,
CASE
WHEN s_path.setting LIKE 'aws%' THEN 'ok'
ELSE 'alarm'
END as status,
CASE
WHEN s_path.setting LIKE 'aws%' THEN 'Starts with "aws"'
ELSE 'Does not start with "aws"'
END as reason
FROM s_path

View File

@@ -0,0 +1,11 @@
WITH s_path AS (select setting from pg_settings where name='search_path')
SELECT s_path.setting as resource,
CASE
WHEN s_path.setting LIKE 'chaos, b, c%' THEN 'ok'
ELSE 'alarm'
END as status,
CASE
WHEN s_path.setting LIKE 'aws%' THEN 'Starts with "chaos, b, c"'
ELSE 'Does not start with "chaos, b, c"'
END as reason
FROM s_path

View File

@@ -0,0 +1,19 @@
select
case
when num=1 then 'ok'
when mod(num,2)=0 then 'alarm'
when mod(num,3)=0 then 'ok'
when mod(num,5)=0 then 'error'
when mod(num,7)=0 then 'info'
when mod(num,11)=0 then 'skip'
end status,
'steampipe' as resource,
case
when num=1 then 'ok'
when mod(num,2)=0 then 'alarm'
when mod(num,3)=0 then 'ok'
when mod(num,5)=0 then 'error'
when mod(num,7)=0 then 'info'
when mod(num,11)=0 then 'skip'
end reason
from generate_series(1, 12) num

View File

@@ -0,0 +1,19 @@
select
case
when num=1 then 'ok'
when mod(num,2)=0 then 'alarm'
when mod(num,3)=0 then 'ok'
when mod(num,5)=0 then 'error'
when mod(num,7)=0 then 'info'
when mod(num,11)=0 then 'skip'
end status,
num as resource,
case
when num=1 then 'ok'
when mod(num,2)=0 then 'alarm'
when mod(num,3)=0 then 'ok'
when mod(num,5)=0 then 'error'
when mod(num,7)=0 then 'info'
when mod(num,11)=0 then 'skip'
end reason
from generate_series(1, 12) num

View File

@@ -0,0 +1,7 @@
mod "local_mod_with_args_in_require" {
require {
mod "github.com/pskrbasu/steampipe-mod-dependency-vars-1" {
version = "*"
}
}
}

View File

@@ -0,0 +1,12 @@
control "check_1" {
title = "Control to verify mod.sp traversal functionality"
description = "Control to verify verify mod.sp traversal functionality."
query = query.query_1
severity = "high"
}
query "query_1"{
title ="query_1"
description = "Simple query 1"
sql = "select 'ok' as status, 'steampipe' as resource, 'acceptance tests' as reason"
}

View File

@@ -0,0 +1,4 @@
mod "nested_mod"{
title = "Nested mod"
description = "This is a nested mod used for testing the mod.pp resolution traversal up the directory tree feature. This mod is needed in acceptance tests. Do not expand this mod."
}

View File

@@ -0,0 +1 @@
dependency_vars_1.version = "v8.0.0"

View File

@@ -0,0 +1,11 @@
{
"test_vars_dependency_mod": {
"github.com/pskrbasu/steampipe-mod-dependency-vars-1": {
"name": "github.com/pskrbasu/steampipe-mod-dependency-vars-1",
"alias": "dependency_vars_1",
"version": "2.0.0",
"constraint": "*",
"struct_version": 20220411
}
}
}

View File

@@ -0,0 +1,15 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/

View File

@@ -0,0 +1,2 @@
# steampipe-mod-dependency-vars-1
steampipe mod to test mod dependency edge cases

View File

@@ -0,0 +1,11 @@
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
}

View File

@@ -0,0 +1,8 @@
mod "test_vars_dependency_mod" {
title = "test_vars_dependency_mod"
require {
mod "github.com/pskrbasu/steampipe-mod-dependency-vars-1" {
version = "*"
}
}
}

View File

@@ -0,0 +1,11 @@
{
"test_vars_dependency_mod": {
"github.com/pskrbasu/steampipe-mod-dependency-vars-1": {
"name": "github.com/pskrbasu/steampipe-mod-dependency-vars-1",
"alias": "dependency_vars_1",
"version": "2.0.0",
"constraint": "*",
"struct_version": 20220411
}
}
}

View File

@@ -0,0 +1,15 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/

View File

@@ -0,0 +1,2 @@
# steampipe-mod-dependency-vars-1
steampipe mod to test mod dependency edge cases

View File

@@ -0,0 +1,11 @@
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
}

View File

@@ -0,0 +1,8 @@
mod "test_vars_dependency_mod" {
title = "test_vars_dependency_mod"
require {
mod "github.com/pskrbasu/steampipe-mod-dependency-vars-1" {
version = "*"
}
}
}

View File

@@ -0,0 +1 @@
dependency_vars_1.version = "v7.0.0"

View File

@@ -0,0 +1,16 @@
# test_workspace_mod_var_precedence_set_from_command_line_and_both_spvars
### Description
This mod is used to test variable resolution precedence in a mod by passing the --var command line arg, a steampipe.spvars file and an *.auto.spvars file. The mod also has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the --var command line argument over the steampipe.spvars and *.auto.spvars file and over the default value of variable 'version' set in the mod, because command line arguments have higher precendence.
Steampipe loads variables in the following order, with later sources taking precedence over earlier ones:
1. Environment variables
2. The steampipe.spvars file, if present.
3. Any *.auto.spvars files, in alphabetical order by filename.
4. Any --var and --var-file options on the command line, in the order they are provided.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -0,0 +1,10 @@
# test_workspace_mod_var_set_from_auto_spvars
### Description
This mod is used to test variable resolution in a mod by passing the variable value in an auto spvars file. The mod has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the passed
variable value in an suto spvars file over the default value of variable 'version' set in the mod.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -0,0 +1,10 @@
# test_workspace_mod_var_set_from_explicit_spvars
### Description
This mod is used to test variable resolution in a mod by passing the variable value in an explicit spvars file. The mod has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the passed
variable value in an explicit spvars file over the default value of variable 'version' set in the mod.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -0,0 +1,10 @@
# test_workspace_mod_var_set_from_auto_spvars
### Description
This mod is used to test variable resolution in a mod by passing the variable value in an auto spvars file. The mod has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the passed
variable value in an suto spvars file over the default value of variable 'version' set in the mod.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -0,0 +1,10 @@
# test_workspace_mod_var_set_from_auto_spvars
### Description
This mod is used to test variable resolution in a mod by passing the variable value in an auto spvars file. The mod has a default value of variable 'version' set.
### Usage
This mod is used in the tests in `mod_vars.bats` to simulate a scenario where the version defined in the mod is picked from the passed
variable value in an suto spvars file over the default value of variable 'version' set in the mod.

View File

@@ -0,0 +1,16 @@
mod "test_vars_workspace_mod" {
title = "test_vars_workspace_mod"
}
query "version" {
sql = "select $1::text as reason, $1::text as resource, 'ok' as status"
param "p1"{
description = "p1"
default = var.version
}
}
variable "version"{
type = string
default = "v2.0.0"
}

View File

@@ -21,8 +21,23 @@ load "$LIB_BATS_SUPPORT/load.bash"
v5.0.0,v5.0.0,ok'
}
@test "test variable resolution in workspace mod set from auto spvars file" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_auto_spvars
@test "test variable resolution in workspace mod set from steampipe.spvars file" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_steampipe.spvars
run steampipe query query.version --output csv
# check the output - query should use the value of variable set from the steampipe spvars
# file ("v7.0.0") which will give the output:
# +--------+----------+--------+
# | reason | resource | status |
# +--------+----------+--------+
# | v7.0.0 | v7.0.0 | ok |
# +--------+----------+--------+
assert_output 'reason,resource,status
v7.0.0,v7.0.0,ok'
}
@test "test variable resolution in workspace mod set from *.auto.spvars file" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_auto.spvars
run steampipe query query.version --output csv
# check the output - query should use the value of variable set from the auto spvars
@@ -88,7 +103,7 @@ v5.0.0,v5.0.0,ok'
}
@test "test variable resolution in dependency mod set from steampipe.spvars file" {
cd $FILE_PATH/test_data/mods/test_dependency_mod_var_set_from_auto_spvars
cd $FILE_PATH/test_data/mods/test_dependency_mod_var_set_from_steampipe.spvars
run steampipe query dependency_vars_1.query.version --output csv
# check the output - query should use the value of variable set from the steampipe.spvars
@@ -103,7 +118,7 @@ v7.0.0,v7.0.0,ok'
}
@test "test variable resolution in dependency mod set from *.auto.spvars spvars file" {
cd $FILE_PATH/test_data/mods/test_dependency_mod_var_set_from_explicit_spvars
cd $FILE_PATH/test_data/mods/test_dependency_mod_var_set_from_auto.spvars
run steampipe query dependency_vars_1.query.version --output csv
# check the output - query should use the value of variable set from the *.auto.spvars
@@ -135,7 +150,7 @@ v8.0.0,v8.0.0,ok'
}
@test "test variable resolution precedence in workspace mod set from steampipe.spvars and ENV" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_auto_spvars
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_steampipe.spvars
export SP_VAR_version=v9.0.0
run steampipe query query.version --output csv
# check the output - query should use the value of variable set from the steampipe.spvars("v7.0.0") file over

View File

@@ -0,0 +1,141 @@
load "$LIB_BATS_ASSERT/load.bash"
load "$LIB_BATS_SUPPORT/load.bash"
### ppvars file tests ###
@test "test variable resolution in workspace mod set from *.auto.ppvars file" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_auto.ppvars
run steampipe query query.version --output csv
# check the output - query should use the value of variable set from the *.auto.ppvars
# file ("v7.0.0") which will give the output:
# +--------+----------+--------+
# | reason | resource | status |
# +--------+----------+--------+
# | v7.0.0 | v7.0.0 | ok |
# +--------+----------+--------+
assert_output 'reason,resource,status
v7.0.0,v7.0.0,ok'
}
@test "test variable resolution in workspace mod set from explicit ppvars file" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_explicit_ppvars
run steampipe query query.version --output csv --var-file='deps.ppvars'
# check the output - query should use the value of variable set from the explicit ppvars
# file ("v8.0.0") which will give the output:
# +--------+----------+--------+
# | reason | resource | status |
# +--------+----------+--------+
# | v8.0.0 | v8.0.0 | ok |
# +--------+----------+--------+
assert_output 'reason,resource,status
v8.0.0,v8.0.0,ok'
}
@test "test variable resolution in dependency mod set from *.auto.ppvars file" {
cd $FILE_PATH/test_data/mods/test_dependency_mod_var_set_from_auto.ppvars
run steampipe query dependency_vars_1.query.version --output csv
# check the output - query should use the value of variable set from the *.auto.ppvars
# file ("v8.0.0") which will give the output:
# +--------+----------+--------+
# | reason | resource | status |
# +--------+----------+--------+
# | v8.0.0 | v8.0.0 | ok |
# +--------+----------+--------+
assert_output 'reason,resource,status
v8.0.0,v8.0.0,ok'
}
### precedence tests ###
@test "test variable resolution precedence in workspace mod set from auto.ppvars and ENV" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_set_from_auto.ppvars
export SP_VAR_version=v9.0.0
run steampipe query query.version --output csv
# check the output - query should use the value of variable set from the *.auto.ppvars("v7.0.0") file over
# ENV("v9.0.0") which will give the output:
# +--------+----------+--------+
# | reason | resource | status |
# +--------+----------+--------+
# | v7.0.0 | v7.0.0 | ok |
# +--------+----------+--------+
assert_output 'reason,resource,status
v7.0.0,v7.0.0,ok'
}
@test "test variable resolution precedence in workspace mod set from command line(--var) and steampipe.ppvars file and *.auto.ppvars file" {
cd $FILE_PATH/test_data/mods/test_workspace_mod_var_precedence_set_from_both_ppvars
run steampipe query query.version --output csv --var version="v5.0.0"
# check the output - query should use the value of variable set from the command line --var flag("v5.0.0") over
# steampipe.ppvars("v7.0.0") and *.auto.ppvars file("v8.0.0") which will give the output:
# +--------+----------+--------+
# | reason | resource | status |
# +--------+----------+--------+
# | v5.0.0 | v5.0.0 | ok |
# +--------+----------+--------+
assert_output 'reason,resource,status
v5.0.0,v5.0.0,ok'
}
### mod.pp file tests ###
@test "test that mod.pp is not renamed after uninstalling mod" {
cd $FILE_PATH/test_data/mods/local_mod_with_mod.pp_file
run steampipe mod install
assert_success
run steampipe mod uninstall
# check mod.pp file still exists and is not renamed
run ls mod.pp
assert_success
}
### test basic check and query working for mod.pp files ###
@test "query with default params and no params passed through CLI" {
cd $FILE_PATH/test_data/mods/functionality_test_mod_pp
run steampipe query query.query_params_with_all_defaults --output json
# store the reason field in `content`
content=$(echo $output | jq '.[].reason')
assert_equal "$content" '"default_parameter_1 default_parameter_2 default_parameter_3"'
}
@test "control with default params and no args passed in control" {
cd $FILE_PATH/test_data/mods/functionality_test_mod_pp
run steampipe check control.query_params_with_defaults_and_no_args --export test.json
echo $output
ls
# store the reason field in `content`
content=$(cat test.json | jq '.controls[0].results[0].reason')
assert_equal "$content" '"default_parameter_1 default_parameter_2 default_parameter_3"'
rm -f test.json
}
@test "control with no default params and no args passed in control" {
cd $FILE_PATH/test_data/mods/functionality_test_mod_pp
run steampipe check control.query_params_with_no_defaults_and_no_args --output json
# should return an error `failed to resolve value for 3 parameters`
echo $output
[ $(echo $output | grep "failed to resolve value for 3 parameters" | wc -l | tr -d ' ') -eq 0 ]
}
### traversal tests ###
@test "load a mod from an arbitrarily nested sub folder - PASS" {
# go to the nested sub directory within the mod
cd $FILE_PATH/test_data/mods/nested_mod_pp/folder1/folder11/folder111
run steampipe check all
assert_success
cd -
}