-
Notifications
You must be signed in to change notification settings - Fork 0
116 lint intrf+first #675
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
116 lint intrf+first #675
Changes from 59 commits
Commits
Show all changes
69 commits
Select commit
Hold shift + click to select a range
bf4aad8
basic lint infrastructure
ShiriMoran 25cf656
lint for filters rules splitting subnets - defining structs
ShiriMoran ed695b3
added comments
ShiriMoran 0d5a121
fix typo
ShiriMoran 3adf6ac
added relevant func def to interface of FilterTrafficResource
ShiriMoran e791e9b
implemented interface to get rules details
ShiriMoran d0bcda8
first lint implemented
ShiriMoran 9f32da6
tests for lint - not checked yet
ShiriMoran 4340cfb
typos fixed (still not working)
ShiriMoran 4818c11
finalizes 1st lint testing
ShiriMoran 9f95194
finalizes 1st lint testing
ShiriMoran 19f0a88
lint batch 1
ShiriMoran 67641b9
typo fix in tests
ShiriMoran 75b37a3
lint
ShiriMoran ab86a64
lint
ShiriMoran 84eaa7b
lint
ShiriMoran 281e72e
typo fix
ShiriMoran b9d0b12
lint
ShiriMoran 94e504f
lint
ShiriMoran 7c13d5d
getFindings()
ShiriMoran dc4a984
cosmetic
ShiriMoran 6063eaf
printing improvements
ShiriMoran 7e33a2b
towards full support in multiVPC
ShiriMoran 3226f8d
support in multiVPC
ShiriMoran acc15cd
support in multiVPC
ShiriMoran 74f3936
have deterministic output result
ShiriMoran a8275ed
have deterministic output result
ShiriMoran 17bc9cb
multiVPC - added vpcUID to finding
ShiriMoran 68fff4f
multiVPC - added vpcUID to finding
ShiriMoran 1389d71
lint
ShiriMoran 9b35898
printing improve
ShiriMoran a4c71ce
lint
ShiriMoran 7f4b9b2
Merge branch 'main' into 116_lint_intrf+first
ShiriMoran 614beaa
Merge branch 'main' into 116_lint_intrf+first
ShiriMoran f821d56
CR
ShiriMoran f00f046
Update cmd/analyzer/subcmds/lint.go
ShiriMoran ee98502
CR: finding interface, add getDescription() to linter interface
ShiriMoran f43c560
lint
ShiriMoran bf411a7
lint
ShiriMoran 311a807
lint
ShiriMoran ef44270
Merge remote-tracking branch 'origin/116_lint_intrf+first' into 116_l…
ShiriMoran 0f9ecb0
redefine interface
ShiriMoran e5b065a
fixed tests
ShiriMoran 67aed51
lint
ShiriMoran e3dc90c
Merge branch 'main' into 116_lint_intrf+first
ShiriMoran 4b53121
comment
ShiriMoran 9ee9329
CR
ShiriMoran 56a9c47
exporting functionality
ShiriMoran 02b1008
CR: specific linters are internal
ShiriMoran 167a8a1
CR: specific linters are internal
ShiriMoran 7ebbe1a
CR: add standard addFinding(f finding) and getFindings()
ShiriMoran afbb01e
CR:impl only once getFindings()
ShiriMoran c200190
CR:impl only once string() of linter
ShiriMoran ba96424
lint
ShiriMoran cf6ae7e
toJSON implemented, still not checked
ShiriMoran d633a91
lint
ShiriMoran bec59f1
lint
ShiriMoran 708b354
Merge branch 'main' into 116_lint_intrf+first
ShiriMoran 340c5b9
fix manually merge with main
ShiriMoran 475aa2d
Merge branch 'main' into 116_lint_intrf+first
ShiriMoran cc0106d
CR fix typo
ShiriMoran cae9a91
Merge remote-tracking branch 'origin/116_lint_intrf+first' into 116_l…
ShiriMoran e5640d2
CR add documentation
ShiriMoran 8d0aa6b
CR RuleIndx -> RuleIndex.
ShiriMoran 90a6081
Merge branch 'main' into 116_lint_intrf+first
ShiriMoran c1911d9
CR
ShiriMoran 1189ec4
Merge remote-tracking branch 'origin/116_lint_intrf+first' into 116_l…
ShiriMoran a3e1ab9
lint
ShiriMoran 2994329
Merge branch 'main' into 116_lint_intrf+first
ShiriMoran File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
/* | ||
Copyright 2023- IBM Inc. All Rights Reserved. | ||
|
||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package subcmds | ||
|
||
import ( | ||
"github.com/spf13/cobra" | ||
|
||
"github.com/np-guard/vpc-network-config-analyzer/pkg/linter" | ||
) | ||
|
||
func NewLintCommand(args *inArgs) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "lint", | ||
Short: "Run various checks for ensuring best-practices", | ||
Long: `Execute various (configurable) linting and provides findings`, | ||
Args: cobra.NoArgs, | ||
RunE: func(cmd *cobra.Command, _ []string) error { | ||
return lintVPCConfigs(cmd, args) | ||
}, | ||
} | ||
return cmd | ||
} | ||
|
||
func lintVPCConfigs(cmd *cobra.Command, inArgs *inArgs) error { | ||
cmd.SilenceUsage = true // if we got this far, flags are syntactically correct, so no need to print usage | ||
cmd.SilenceErrors = true // also, error will be printed to logger in main(), so no need for cobra to also print it | ||
|
||
multiConfigs, err1 := buildConfigs(inArgs) | ||
if err1 != nil { | ||
return err1 | ||
} | ||
_, _, err2 := linter.LinterExecute(multiConfigs.Configs()) | ||
return err2 | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
"Firewall rules implying different connectivity for different endpoints within a subnet" issues: | ||
------------------------------------------------------------------------------------------------ | ||
In VPC test-vpc1-ky, Network acl acl3-ky rule's indexed 1 splits subnet subnet3-ky (10.240.30.0/24). Splitting rule details: index: 1, direction: outbound , src: 10.240.30.0/31 , dst: 10.240.20.0/24, conn: all, action: allow | ||
In VPC test-vpc1-ky, Network acl acl3-ky rule's indexed 3 splits subnet subnet3-ky (10.240.30.0/24). Splitting rule details: index: 3, direction: inbound , src: 10.240.20.0/24 , dst: 10.240.30.0/31, conn: all, action: allow |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
"Firewall rules implying different connectivity for different endpoints within a subnet" issues: | ||
------------------------------------------------------------------------------------------------ | ||
In VPC test-vpc1-ky, Network acl sg1-ky rule's indexed 1 splits subnet subnet1-ky (10.240.10.0/24). Splitting rule details: index: 1, direction: inbound, conns: protocol: all, remote: sg1-ky (10.240.10.4/32), local: 0.0.0.0/0 | ||
In VPC test-vpc1-ky, Network acl sg1-ky rule's indexed 3 splits subnets subnet2-ky (10.240.20.0/24), subnet3-ky (10.240.30.0/24). Splitting rule details: index: 3, direction: inbound, conns: protocol: all, remote: sg2-ky (10.240.20.4/32,10.240.30.4/32), local: 0.0.0.0/0 | ||
In VPC test-vpc1-ky, Network acl sg1-ky rule's indexed 4 splits subnet subnet3-ky (10.240.30.0/24). Splitting rule details: index: 4, direction: inbound, conns: protocol: all, remote: sg3-ky (10.240.30.5/32,10.240.30.6/32), local: 0.0.0.0/0 | ||
In VPC test-vpc1-ky, Network acl sg2-ky rule's indexed 4 splits subnet subnet1-ky (10.240.10.0/24). Splitting rule details: index: 4, direction: inbound, conns: protocol: all, remote: sg1-ky (10.240.10.4/32), local: 0.0.0.0/0 | ||
In VPC test-vpc1-ky, Network acl sg2-ky rule's indexed 6 splits subnets subnet2-ky (10.240.20.0/24), subnet3-ky (10.240.30.0/24). Splitting rule details: index: 6, direction: outbound, conns: protocol: tcp, dstPorts: 1-65535, remote: sg2-ky (10.240.20.4/32,10.240.30.4/32), local: 0.0.0.0/0 | ||
In VPC test-vpc1-ky, Network acl sg2-ky rule's indexed 7 splits subnets subnet2-ky (10.240.20.0/24), subnet3-ky (10.240.30.0/24). Splitting rule details: index: 7, direction: inbound, conns: protocol: tcp, dstPorts: 1-65535, remote: sg2-ky (10.240.20.4/32,10.240.30.4/32), local: 0.0.0.0/0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
no lint "Firewall rules implying different connectivity for different endpoints within a subnet" issues |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
/* | ||
Copyright 2023- IBM Inc. All Rights Reserved. | ||
|
||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package ibmvpc | ||
|
||
import ( | ||
"fmt" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/np-guard/vpc-network-config-analyzer/pkg/linter" | ||
"github.com/np-guard/vpc-network-config-analyzer/pkg/vpcmodel" | ||
) | ||
|
||
const lintOut = "lint_out" | ||
|
||
var lintTests = []*vpcGeneralTest{ | ||
{ | ||
name: "basic_acl3", | ||
inputConfig: "acl_testing3", | ||
}, | ||
{ | ||
name: "basic_sg1", | ||
inputConfig: "sg_testing1_new", | ||
}, | ||
{ | ||
name: "multivpc", | ||
inputConfig: "tgw_larger_example", | ||
}, | ||
} | ||
|
||
func TestAllLint(t *testing.T) { | ||
// lintTests is the list of tests to run | ||
for testIdx := range lintTests { | ||
tt := lintTests[testIdx] | ||
tt.mode = outputComparison | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
tt.runLintTest(t) | ||
}) | ||
} | ||
fmt.Println("done") | ||
} | ||
|
||
// uncomment the function below for generating the expected output files instead of comparing | ||
/* | ||
func TestAllLintWithGeneration(t *testing.T) { | ||
// tests is the list of tests to run | ||
for testIdx := range lintTests { | ||
tt := lintTests[testIdx] | ||
tt.mode = outputGeneration | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Parallel() | ||
tt.runLintTest(t) | ||
}) | ||
} | ||
fmt.Println("done") | ||
} | ||
*/ | ||
func (tt *vpcGeneralTest) runLintTest(t *testing.T) { | ||
// all tests in lint mode | ||
// output use case is not significant here, but being used so that lint test can rely on existing mechanism | ||
tt.useCases = []vpcmodel.OutputUseCase{vpcmodel.AllEndpoints} | ||
// init test - set the input/output file names according to test name | ||
tt.initTest() | ||
|
||
// get vpcConfigs obj from parsing + analyzing input config file | ||
vpcConfigs := getVPCConfigs(t, tt, true) | ||
|
||
// generate actual output for all use cases specified for this test | ||
err := runLintTestPerUseCase(t, tt, vpcConfigs.Configs(), lintOut) | ||
require.Equal(t, tt.errPerUseCase[vpcmodel.AllEndpoints], err, "comparing actual err to expected err") | ||
for uc, outFile := range tt.actualOutput { | ||
fmt.Printf("test %s use-case %d - generated output file: %s\n", tt.name, uc, outFile) | ||
} | ||
} | ||
|
||
// runExplainTestPerUseCase executes lint for the required use case and compares/generates the output | ||
func runLintTestPerUseCase(t *testing.T, | ||
tt *vpcGeneralTest, | ||
cConfigs map[string]*vpcmodel.VPCConfig, | ||
outDir string) error { | ||
// output use case is not significant here, but being used so that lint test can rely on existing mechanism | ||
initLintTestFileNames(tt, outDir) | ||
_, actualOutput, _ := linter.LinterExecute(cConfigs) | ||
if err := compareOrRegenerateOutputPerTest(t, tt.mode, actualOutput, tt, vpcmodel.AllEndpoints); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func initLintTestFileNames(tt *vpcGeneralTest, testDir string) { | ||
expectedFileName, actualFileName := getLintTestFileName(tt.name) | ||
// output use case is not significant here, but being used so that lint test can rely on existing mechanism | ||
tt.actualOutput[vpcmodel.AllEndpoints] = filepath.Join(getTestsDirOut(testDir), actualFileName) | ||
tt.expectedOutput[vpcmodel.AllEndpoints] = filepath.Join(getTestsDirOut(testDir), expectedFileName) | ||
} | ||
|
||
// getLintTestFileName returns expected file name and actual file name, for the relevant use case | ||
func getLintTestFileName(testName string) (expectedFileName, actualFileName string) { | ||
res := testName + "_Lint" | ||
expectedFileName = res | ||
actualFileName = actualOutFilePrefix + res | ||
return expectedFileName, actualFileName | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
Copyright 2023- IBM Inc. All Rights Reserved. | ||
|
||
SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package linter | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/np-guard/models/pkg/ipblock" | ||
"github.com/np-guard/vpc-network-config-analyzer/pkg/vpcmodel" | ||
) | ||
|
||
const splitRuleSubnetName = "rules-splitting-subnets" | ||
|
||
// filterRuleSplitSubnet: rules of filters that are inconsistent w.r.t. subnets. | ||
type filterRuleSplitSubnet struct { | ||
basicLinter | ||
} | ||
|
||
// a rule with the list of subnets it splits | ||
type splitRuleSubnet struct { | ||
vpcName string | ||
rule vpcmodel.RuleOfFilter | ||
splitSubnets []vpcmodel.Subnet | ||
} | ||
|
||
// ///////////////////////////////////////////////////////// | ||
// lint interface implementation for filterRuleSplitSubnet | ||
// //////////////////////////////////////////////////////// | ||
func (lint *filterRuleSplitSubnet) lintName() string { | ||
return splitRuleSubnetName | ||
} | ||
|
||
func (lint *filterRuleSplitSubnet) lintDescription() string { | ||
return "Firewall rules implying different connectivity for different endpoints within a subnet" | ||
} | ||
|
||
func (lint *filterRuleSplitSubnet) check() error { | ||
for _, config := range lint.configs { | ||
if config.IsMultipleVPCsConfig { | ||
continue // no use in executing lint on dummy vpcs | ||
} | ||
for _, layer := range vpcmodel.FilterLayers { | ||
filterLayer := config.GetFilterTrafficResourceOfKind(layer) | ||
rules, err := filterLayer.GetRules() | ||
if err != nil { | ||
return err | ||
} | ||
for _, rule := range rules { | ||
adisos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
subnetsSplitByRule := []vpcmodel.Subnet{} | ||
for _, subnet := range config.Subnets { | ||
splitSubnet, err := ruleSplitSubnet(subnet, rule.IPBlocks) | ||
if err != nil { | ||
return err | ||
} | ||
if splitSubnet { | ||
subnetsSplitByRule = append(subnetsSplitByRule, subnet) | ||
} | ||
} | ||
if len(subnetsSplitByRule) > 0 { | ||
lint.addFinding(&splitRuleSubnet{vpcName: config.VPC.Name(), rule: rule, | ||
splitSubnets: subnetsSplitByRule}) | ||
} | ||
} | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// given a subnet and IPBlocks mentioned in a rule, returns the list | ||
func ruleSplitSubnet(subnet vpcmodel.Subnet, ruleIPBlocks []*ipblock.IPBlock) (bool, error) { | ||
cidr := subnet.CIDR() | ||
subnetCidrIPBlock, err := ipblock.FromCidr(cidr) | ||
if err != nil { | ||
return false, err | ||
} | ||
adisos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for _, ruleIPBlock := range ruleIPBlocks { | ||
if ruleIPBlock.Overlap(subnetCidrIPBlock) && !subnetCidrIPBlock.ContainedIn(ruleIPBlock) { | ||
return true, nil | ||
} | ||
} | ||
return false, nil | ||
} | ||
|
||
/////////////////////////////////////////////////////////// | ||
// finding interface implementation for splitRuleSubnet | ||
////////////////////////////////////////////////////////// | ||
|
||
func (finding *splitRuleSubnet) vpc() string { | ||
return finding.vpcName | ||
} | ||
|
||
func (finding *splitRuleSubnet) string() string { | ||
rule := finding.rule | ||
thisLayerName := "Network acl" | ||
if finding.rule.LayerName == vpcmodel.SecurityGroupLayer { | ||
thisLayerName = "Security group" | ||
} | ||
subnetsStrSlice := make([]string, len(finding.splitSubnets)) | ||
for i, subnet := range finding.splitSubnets { | ||
subnetsStrSlice[i] = fmt.Sprintf("%s (%s)", subnet.Name(), subnet.CIDR()) | ||
} | ||
subnetStr := strings.Join(subnetsStrSlice, ", ") | ||
if len(subnetsStrSlice) > 1 { | ||
subnetStr = "subnets " + subnetStr | ||
} else { | ||
subnetStr = "subnet " + subnetStr | ||
} | ||
return fmt.Sprintf("In VPC %s, %s %s rule's indexed %d splits %s. Splitting rule details: %s", | ||
finding.vpc(), thisLayerName, rule.FilterName, rule.RuleIndx, subnetStr, rule.RuleDesc) | ||
} | ||
|
||
// for json: a rule with the list of subnets it splits | ||
type splitRuleSubnetJSON struct { | ||
VpcName string `json:"vpc_name"` | ||
Rule vpcmodel.RuleOfFilter `json:"rule_details"` | ||
SplitSubnets []subnetJSON `json:"splitted_subnets"` | ||
} | ||
|
||
type subnetJSON struct { | ||
Name string `json:"name"` | ||
CIDR string `json:"cidr"` | ||
} | ||
|
||
func (finding *splitRuleSubnet) toJSON() any { | ||
rule := finding.rule | ||
splitSubnetsJSON := make([]subnetJSON, len(finding.splitSubnets)) | ||
for i, splitSubnet := range finding.splitSubnets { | ||
splitSubnetsJSON[i] = subnetJSON{Name: splitSubnet.Name(), CIDR: splitSubnet.CIDR()} | ||
} | ||
res := splitRuleSubnetJSON{VpcName: finding.vpcName, Rule: vpcmodel.RuleOfFilter{LayerName: rule.LayerName, | ||
FilterName: rule.FilterName, RuleIndx: rule.RuleIndx, RuleDesc: rule.RuleDesc}, | ||
SplitSubnets: splitSubnetsJSON} | ||
return res | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.