Skip to content
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

Adding Analyze command to guacone #1809

Open
wants to merge 64 commits into
base: main
Choose a base branch
from

Conversation

arorasoham9
Copy link
Contributor

@arorasoham9 arorasoham9 commented Apr 4, 2024

Description of the PR

Analyze command for guacone
Comparing SBOMs with only patch version differences
guacone analyze diff --uri --sboms=https://anchore.com/syft/image/k8s.gcr.io/kube-apiserver-v1.24.1-583a02ce-8f7e-4794-91af-35f27ffeb73d,https://anchore.com/syft/image/k8s.gcr.io/kube-apiserver-v1.24.2-ee7e0a81-87de-4761-9689-4f7162d81e44
Screenshot 2024-11-19 at 10 01 36 AM

The diff is a 4 step process:

  • Create graph for SBOMs
  • Find all paths in both graphs
  • Find the paths that are present in one graph and not in the other, do this for both graphs.
  • Pair paths from one graph to the other that are closest, then find the difference between these pairs.

Each step has tests to ensure that it is stable. Meaning, if the steps are repeated for the same Input SBOM, the results are the same. The JSON you see are the test SBOMS I use to carry out the tests for each step of the diff. These JSON files are marshalled HasSBOM nodes for SBOMs I ingested into GUAC, pulled using the Node function.

PR Checklist

  • All commits have a Developer Certificate of Origin (DCO) -- they are generated using -s flag to git commit.
  • All new changes are covered by tests
  • If GraphQL schema is changed, make generate has been run
  • If OpenAPI spec is changed, make generate has been run
  • If collectsub protobuf has been changed, make proto has been run
  • All CI checks are passing (tests and formatting)
  • All dependent PRs have already been merged

@arorasoham9
Copy link
Contributor Author

@pxp928 ready for review.

@pxp928
Copy link
Collaborator

pxp928 commented Apr 4, 2024

Cool, @arorasoham9 can you add some screenshots to what the output will look like for the CLI?

// See the License for the specific language governing permissions and
// limitations under the License.

package guacanalyze
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one major task would be to add unit tests to this package. Some things like the graph, getting data from graphQL can be abstracted away but do you have some tests you can add here to test the functionality?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have any at the moment. I can write a few. Could they come in a future PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added unit tests as requested.

@arorasoham9
Copy link
Contributor Author

arorasoham9 commented Apr 4, 2024

Cool, @arorasoham9 can you add some screenshots to what the output will look like for the CLI?

Added some screenshots. The Prettify function errored out at many instances so I improvised to print the same details that function does but taken from the graph DS itself, not graphQL.

node *Node
)
if node, err = g.Vertex(ID); err != nil {
fmt.Println("Error setting node attribute", err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to return this as an error.

)
if node, err = g.Vertex(ID); err != nil {
fmt.Println("Error setting node attribute", err)
os.Exit(1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use os.Exit(1) should return error


func GetNodeAttribute(g graph.Graph[string, *Node],ID, key string) interface{} {
var (
err error
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to instantiate this here, can just it on line 72?

node.Attributes[key] = value
}

func GetNodeAttribute(g graph.Graph[string, *Node],ID, key string) interface{} {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this returning an interface{}

foundHasSBOMPkg, err = model.HasSBOMs(ctx, gqlclient, model.HasSBOMSpec{Subject: &model.PackageOrArtifactSpec{Package: &model.PkgSpec{Id: &pkgResponse.Packages[0].Namespaces[0].Names[0].Versions[0].Id}},
})
if err != nil {
fmt.Printf("(purl)failed getting hasSBOM with error :%v", err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dont use fmt.Printf, you should return an error via fmt.Errorf

func verifyAnalyzeFlags(slsas, sboms []string, errSlsa, errSbom error, uri, purl, id bool) {

if (errSlsa != nil && errSbom != nil) || (len(slsas) ==0 && len(sboms) == 0 ){
fmt.Println("Must specify slsa or sboms ")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return a proper error and dont use os.Exit

namespaceTwo, okTwo := GetNodeAttribute(analysisGraph,diffList.MissingAddedRemovedLinks[i][1], "Namespace[0]").(string)

if !okOne || !okTwo {
fmt.Println("Error getting node namespace attribute")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clean up and pass out proper error

table.SetAlignment(tablewriter.ALIGN_LEFT)
table.Render()
if (!all && max > maxprint){
fmt.Println("Run with --all to see full list")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should user logger here: https://github.com/guacsec/guac/blob/main/pkg/handler/processor/process/process.go#L117

It should be able to be pulled from the context:

logger := logging.FromContext(ctx)

}

func HasSBOMToGraph(cmd *cobra.Command, ctx context.Context, gqlclient graphql.Client) ( []graph.Graph[string, *Node]){
slsas, errSlsa := cmd.Flags().GetStringSlice("slsa")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pass in options or something similar and not the actual cmd. See: https://github.com/guacsec/guac/blob/main/cmd/guacone/cmd/s3.go#L80-L93

if uri {
hasSBOMResponseOne, err = FindHasSBOMBy(model.HasSBOMSpec{} ,sboms[0],"", "", ctx, gqlclient)
if err != nil {
fmt.Println("(uri)failed to lookup sbom:", sboms[0], err)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix error

@@ -0,0 +1,66 @@
package guacanalyze_test
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing header

Copy link
Collaborator

@jeffmendoza jeffmendoza left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly code organization and naming comments.

"github.com/guacsec/guac/pkg/logging"
"github.com/spf13/cobra"
"github.com/spf13/viper"
analysis "github.com/guacsec/guac/pkg/analyzer"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for the import rename here?

if diff && intersect && union || diff && intersect || diff && union || intersect && union {
fmt.Println("Must specify only one of --diff, --intersect, --union")
return
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a positional argument if required, not a flag/option.

}

//create graphs
graphs := analysis.HasSBOMToGraph(cmd, ctx, gqlclient)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't pass cmd to a package under pkg/. Those shouldn't have a dependency on cli commands or cobra. Explicitly pass the parameters this needs.


func init() {

rootCmd.PersistentFlags().Bool("intersect", false, "compute intesection of given sboms")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't add flags to rootCmd, this will show up on all guacone cmds if so. Use this analyzeCmd you are creating.
Also, cli options are normally under pkg/cli/store.go but this command has so many it might make sense to just leave them here.

rootCmd.PersistentFlags().Bool("purl", false, "input is a pURL")
rootCmd.PersistentFlags().Bool("id", false, "input is an Id")
rootCmd.PersistentFlags().Bool("metadata", false, "Compare SBOM metadata")
rootCmd.PersistentFlags().Bool("inclSoft", false, "Compare Included Softwares")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to incl-soft and similar for others. All cli options use hyphen-case.

rootCmd.PersistentFlags().Int("maxprint", PRINT_MAX, "max number of similar sboms to print")
rootCmd.AddCommand(analyzeCmd)

}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a newline to the end of the file

)
if node, err = g.Vertex(ID); err != nil {
fmt.Println("Error setting node attribute", err)
os.Exit(1)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't have any os.Exit in a package under pkg/, assume this is a library that can be called from anywhere. Propagate errors back to the caller.

return foundHasSBOMPkg, nil
}

func verifyAnalyzeFlags(slsas, sboms []string, errSlsa, errSbom error, uri, purl, id bool) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this should be under the file in cmd/, shouldn't have any flag validation here in pkg/.

//print to stdout
printHighlightedAnalysis(dot, diffList, all, maxprint, action, analysisGraph )
}
func max(nums []int) int {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add an empty line between functions.

//Create dot file
createGraphDotFile(dot, analysisGraph)
//print to stdout
printHighlightedAnalysis(dot, diffList, all, maxprint, action, analysisGraph )
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything under pkg/ should not print anything to stdout. Any logic should result in a datastructure that returns back to cmd/ and is then printed. This helps for testability. Looks like much of this may need to be moved back to cmd/

@pxp928
Copy link
Collaborator

pxp928 commented Apr 18, 2024

@arorasoham9 did the node functionality get fixed?

Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
arorasoham9 and others added 15 commits July 5, 2024 14:47
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
…th the comparing path, not sure which to use

Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
arorasoham9 and others added 4 commits August 16, 2024 05:02
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
Signed-off-by: Soham Arora <arorasoham9@gmail.com>
@lumjjb
Copy link
Contributor

lumjjb commented Oct 28, 2024

Hey @arorasoham9 , would you be able to chat at bit more amount helping to turn the corner to complete the PR.

Signed-off-by: arorasoham9 <68672198+arorasoham9@users.noreply.github.com>
Signed-off-by: arorasoham9 <68672198+arorasoham9@users.noreply.github.com>
Signed-off-by: arorasoham9 <68672198+arorasoham9@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants