gosec/CONTRIBUTING.md
dannyc-grafana 09b914371e
Documentation on adding new rules and analyzers (#1262)
* Create CONTRIBUTING.md

Add some docs for developers who want to extend gosec

* Address comments from ccojocar

* Update CONTRIBUTING.md

Co-authored-by: Oleksandr Redko <oleksandr.red+github@gmail.com>

* Update CONTRIBUTING.md

Co-authored-by: Oleksandr Redko <oleksandr.red+github@gmail.com>

* Update README.md

Co-authored-by: Oleksandr Redko <oleksandr.red+github@gmail.com>

* Update CONTRIBUTING.md

Co-authored-by: Oleksandr Redko <oleksandr.red+github@gmail.com>

* Update CONTRIBUTING.md

Co-authored-by: Oleksandr Redko <oleksandr.red+github@gmail.com>

* Linting/formatting pass

* Update CONTRIBUTING.md

* Update README.md

Fix phrasing to be clearer

---------

Co-authored-by: Oleksandr Redko <oleksandr.red+github@gmail.com>
2024-12-16 10:38:51 +01:00

3.9 KiB

Contributing

Adding a new rule

New rules can be implemented in two ways:

  • as a gosec.Rule -- these define an arbitrary function which will be called on every AST node in the analyzed file, and are appropriate for rules that mostly need to reason about a single statement.
  • as an Analyzer -- these can operate on the entire program, and receive an SSA representation of the package. This type of rule is useful when you need to perform a more complex analysis that requires a great deal of context.

Adding a gosec.Rule

  1. Copy an existing rule file as a starting point-- ./rules/unsafe.go is a good option, as it implements a very simple rule with no additional supporting logic. Put the copied file in the ./rules/ directory.
  2. Change the name of the rule constructor function and of the types in the rule file you've copied so they will be unique.
  3. Edit the Generate function in ./rules/rulelist.go to include your rule.
  4. Add a RuleID to CWE ID mapping for your rule to the ruleToCWE map in ./issue/issue.go. If you need a CWE that isn't already defined in ./cwe/data.go, add it to the idWeaknessess map in that file.
  5. Use make to compile gosec. The binary will now contain your rule.

To make your rule actually useful, you will likely want to use the support functions defined in ./resolve.go, ./helpers.go and ./call_list.go. There are inline comments explaining the purpose of most of these functions, and you can find usage examples in the existing rule files.

Adding an Analyzer

  1. Create a new go file under ./analyzers/ with the following scaffolding in it:
package analyzers

import (
        "fmt"

        "golang.org/x/tools/go/analysis"
        "golang.org/x/tools/go/analysis/passes/buildssa"
        "github.com/securego/gosec/v2/issue"
)

const defaultIssueDescriptionMyAnalyzer = "My new analyzer!"

func newMyAnalyzer(id string, description string) *analysis.Analyzer {
        return &analysis.Analyzer{
                Name:     id,
                Doc:      description,
                Run:      runMyAnalyzer,
                Requires: []*analysis.Analyzer{buildssa.Analyzer},
        }
}

func runMyAnalyzer(pass *analysis.Pass) (interface{}, error) {
        ssaResult, err := getSSAResult(pass)
        if err != nil {
                return nil, fmt.Errorf("building ssa representation: %w", err)
        }
        var issues []*issue.Issue
        fmt.Printf("My Analyzer ran! %+v\n", ssaResult)

        return issues, nil
}
  1. Add the analyzer to ./analyzers/analyzerslist.go in the defaultAnalyzers variable under an entry like {"G999", "My test analyzer", newMyAnalyzer}
  2. Add a RuleID to CWE ID mapping for your rule to the ruleToCWE map in ./issue/issue.go. If you need a CWE that isn't already defined in ./cwe/data.go, add it to the idWeaknessess map in that file.
  3. make; then run the gosec binary produced. You should see the output from our print statement.
  4. You now have a working example analyzer to play with-- look at the other implemented analyzers for ideas on how to make useful rules.

Developing your rule

There are some utility tools which are useful for analyzing the SSA and AST representation gosec works with before writing rules or analyzers.

For instance to dump the SSA, the ssadump tool can be used as following:

ssadump -build F main.go

Consult the documentation for ssadump for an overview of available output flags and options.

For outputting the AST and supporting information, there is a utility tool in https://github.com/securego/gosec/blob/master/cmd/gosecutil/tools.go which can be compiled and used as standalone.

gosecutil -tool ast main.go

Valid tool arguments for this command are ast, callobj, uses, types, defs, comments, and imports.