Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions lint/rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,30 @@ func TestAll(rulesPath string) error {
return err
}

// Check for duplicate rule numbers
ruleNumberMap := make(map[string][]string)
for _, rule := range allRules {
if rule.RuleNumber != "" {
ruleNumberMap[rule.RuleNumber] = append(ruleNumberMap[rule.RuleNumber], rule.Path)
}
}

// Report duplicates
hasDuplicates := false
for ruleNumber, paths := range ruleNumberMap {
if len(paths) > 1 {
hasDuplicates = true
log.Errorf("Duplicate rule number '%s' found in the following rules:", ruleNumber)
for _, path := range paths {
log.Errorf(" - %s", path)
}
}
}

if hasDuplicates {
return fmt.Errorf("found duplicate rule numbers")
}

for _, rule := range allRules {
runTestCases(rule)
}
Expand Down
159 changes: 159 additions & 0 deletions lint/rules_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package lint

import (
"os"
"path/filepath"
"testing"
)

Expand All @@ -13,3 +15,160 @@ func TestAllRules(t *testing.T) {
}
})
}

func TestDuplicateRuleNumbers(t *testing.T) {
// Create a temporary directory for test rules
tempDir := t.TempDir()

// Create two rules with the same rule number
rule1Content := `# METADATA
# scope: package
# title: Test Rule 1
# description: First test rule
# custom:
# category: Test
# rulename: TestRule1
# severity: LOW
# rulenumber: 001_0001
# remediation: Fix it
# input: .*test\.yaml
package app.test.rule1
import rego.v1

default allow := false
allow if count(errors) == 0
errors contains "test error" if false
`

rule2Content := `# METADATA
# scope: package
# title: Test Rule 2
# description: Second test rule with same number
# custom:
# category: Test
# rulename: TestRule2
# severity: LOW
# rulenumber: 001_0001
# remediation: Fix it
# input: .*test\.yaml
package app.test.rule2
import rego.v1

default allow := false
allow if count(errors) == 0
errors contains "test error" if false
`

// Write the rule files
rule1Path := filepath.Join(tempDir, "rule1.rego")
rule2Path := filepath.Join(tempDir, "rule2.rego")

err := os.WriteFile(rule1Path, []byte(rule1Content), 0644)
if err != nil {
t.Fatalf("Failed to write rule1: %v", err)
}

err = os.WriteFile(rule2Path, []byte(rule2Content), 0644)
if err != nil {
t.Fatalf("Failed to write rule2: %v", err)
}

// Test that duplicate rule numbers are detected
err = TestAll(tempDir)
if err == nil {
t.Error("Expected error for duplicate rule numbers, but got nil")
}

if err != nil && err.Error() != "found duplicate rule numbers" {
t.Errorf("Expected 'found duplicate rule numbers' error, got: %v", err)
}
}

func TestUniqueRuleNumbers(t *testing.T) {
// Create a temporary directory for test rules
tempDir := t.TempDir()

// Create two rules with different rule numbers
rule1Content := `# METADATA
# scope: package
# title: Test Rule 1
# description: First test rule
# custom:
# category: Test
# rulename: TestRule1
# severity: LOW
# rulenumber: 001_0001
# remediation: Fix it
# input: .*test\.yaml
package app.test.rule1
import rego.v1

default allow := false
allow if count(errors) == 0
errors contains "test error" if false
`

rule2Content := `# METADATA
# scope: package
# title: Test Rule 2
# description: Second test rule with different number
# custom:
# category: Test
# rulename: TestRule2
# severity: LOW
# rulenumber: 001_0002
# remediation: Fix it
# input: .*test\.yaml
package app.test.rule2
import rego.v1

default allow := false
allow if count(errors) == 0
errors contains "test error" if false
`

// Write the rule files
rule1Path := filepath.Join(tempDir, "rule1.rego")
rule2Path := filepath.Join(tempDir, "rule2.rego")

// Create test files for the rules
testFile1 := filepath.Join(tempDir, "rule1_test.yaml")
testFile2 := filepath.Join(tempDir, "rule2_test.yaml")

testContent := `TestCases:
- name: "test case"
input:
test: true
allow: true
`

err := os.WriteFile(rule1Path, []byte(rule1Content), 0644)
if err != nil {
t.Fatalf("Failed to write rule1: %v", err)
}

err = os.WriteFile(rule2Path, []byte(rule2Content), 0644)
if err != nil {
t.Fatalf("Failed to write rule2: %v", err)
}

err = os.WriteFile(testFile1, []byte(testContent), 0644)
if err != nil {
t.Fatalf("Failed to write test file 1: %v", err)
}

err = os.WriteFile(testFile2, []byte(testContent), 0644)
if err != nil {
t.Fatalf("Failed to write test file 2: %v", err)
}

// Test that unique rule numbers pass validation
err = TestAll(tempDir)
if err != nil {
// We expect errors from running the actual tests, but not from duplicate rule numbers
if err.Error() == "found duplicate rule numbers" {
t.Errorf("Should not get duplicate rule numbers error with unique numbers: %v", err)
}
// Other errors from test execution are fine for this test
}
}
Loading