Skip to content

Commit f1a8ede

Browse files
authored
Merge pull request #25 from RoseSecurity/add-dry-run-flag
feat: add dry run command for homebrew distribution
2 parents 35c523c + ff5f2a0 commit f1a8ede

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

cmd/recommend.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package cmd
22

33
import (
4+
"fmt"
5+
"os"
6+
47
"github.com/RoseSecurity/kuzco/internal"
58
u "github.com/RoseSecurity/kuzco/pkg/utils"
69
"github.com/spf13/cobra"
@@ -19,9 +22,24 @@ func init() {
1922
recommendCmd.Flags().StringVarP(&model, "model", "m", "llama3.2", "LLM model to use for generating recommendations")
2023
recommendCmd.Flags().StringVarP(&prompt, "prompt", "p", "", "User prompt for guiding the response format of the LLM model")
2124
recommendCmd.Flags().StringVarP(&addr, "address", "a", "http://localhost:11434", "IP Address and port to use for the LLM model (ex: http://localhost:11434)")
25+
recommendCmd.Flags().BoolVar(&dryrun, "dry-run", false, "Test unused parameter functionality")
26+
// Hide dry run flag
27+
recommendCmd.Flags().Lookup("dry-run").Hidden = true
2228
}
2329

2430
func Analyze(cmd *cobra.Command, args []string) {
31+
// Run the logic test if the flag is set
32+
if dryrun {
33+
var unusedAttrs []string
34+
unusedAttrs, err := internal.DryRun(filePath, tool)
35+
if err != nil {
36+
u.LogErrorAndExit(err)
37+
} else {
38+
fmt.Println("Unused attributes:", unusedAttrs)
39+
}
40+
os.Exit(0)
41+
}
42+
2543
// Validate that the specified model exists in Ollama
2644
if err := internal.ValidateModel(model, addr); err != nil {
2745
u.LogErrorAndExit(err)

cmd/root.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var (
1515
model string
1616
prompt string
1717
addr string
18+
dryrun bool
1819
)
1920

2021
var rootCmd = &cobra.Command{

internal/dry_run.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package internal
2+
3+
import (
4+
"fmt"
5+
"path/filepath"
6+
"strings"
7+
)
8+
9+
// DryRun checks the provided file for unused attributes based on a provider schema.
10+
func DryRun(filePath, tool string) ([]string, error) {
11+
if !(strings.HasSuffix(filePath, ".tf") || strings.HasSuffix(filePath, ".tofu")) {
12+
return nil, fmt.Errorf("the provided file must have a .tf or .tofu extension")
13+
}
14+
15+
resources, err := ParseConfigurationFile(filePath)
16+
if err != nil {
17+
return nil, fmt.Errorf("error parsing configuration file: %v", err)
18+
}
19+
20+
// Placeholder schema, which would typically be loaded based on the provider type
21+
var providerSchema ProviderSchema
22+
dir := filepath.Dir(filePath) // Ensure `dir` is correctly derived
23+
24+
switch tool {
25+
case "terraform":
26+
providerSchema, err = ExtractTerraformProviderSchema(dir)
27+
if err != nil {
28+
return nil, fmt.Errorf("error extracting Terraform provider schema: %v", err)
29+
}
30+
case "opentofu":
31+
providerSchema, err = ExtractOpenTofuProviderSchema(dir)
32+
if err != nil {
33+
return nil, fmt.Errorf("error extracting OpenTofu provider schema: %v", err)
34+
}
35+
default:
36+
return nil, fmt.Errorf("unsupported tool: %s. Supported tools are 'terraform' and 'opentofu'", tool)
37+
}
38+
39+
// Identify and return unused attributes
40+
unusedAttrs, err := testPossibleAttributes(resources, providerSchema, tool)
41+
if err != nil {
42+
return nil, fmt.Errorf("error identifying unused attributes: %v", err)
43+
}
44+
45+
return unusedAttrs, nil
46+
}
47+
48+
// testPossibleAttributes checks each resource for unused attributes and returns them.
49+
func testPossibleAttributes(resources []Resource, schema ProviderSchema, tool string) ([]string, error) {
50+
var unusedAttrs []string
51+
for _, resource := range resources {
52+
if possibleAttrs, ok := schema.ResourceTypes[resource.Type]; ok {
53+
usedAttrs := resource.Attributes
54+
unusedAttrsForResource := testFindUnusedAttributes(usedAttrs, possibleAttrs)
55+
56+
// Collect unused attributes
57+
unusedAttrs = append(unusedAttrs, unusedAttrsForResource...)
58+
} else {
59+
fmt.Printf("No schema found for resource type %s. Skipping unused attribute check.\n", resource.Type)
60+
}
61+
}
62+
return unusedAttrs, nil
63+
}
64+
65+
// testFindUnusedAttributes identifies unused attributes by comparing used and possible attributes.
66+
func testFindUnusedAttributes(usedAttrs map[string]string, possibleAttrs map[string]interface{}) []string {
67+
var unusedAttrs []string
68+
for attr := range possibleAttrs {
69+
if _, used := usedAttrs[attr]; !used {
70+
unusedAttrs = append(unusedAttrs, attr)
71+
}
72+
}
73+
return unusedAttrs
74+
}

0 commit comments

Comments
 (0)