diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-10-20 09:40:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-10-20 09:40:42 +0000 |
commit | ee664acb356f8123f4f6b00b73c1e1cf0866c7fb (patch) | |
tree | f8479f94a28f66654c6a4f6fb99bad6b4e86a40e /doc/development/sec/analyzer_development_guide.md | |
parent | 62f7d5c5b69180e82ae8196b7b429eeffc8e7b4f (diff) | |
download | gitlab-ce-15.5.0-rc42.tar.gz |
Add latest changes from gitlab-org/gitlab@15-5-stable-eev15.5.0-rc42
Diffstat (limited to 'doc/development/sec/analyzer_development_guide.md')
-rw-r--r-- | doc/development/sec/analyzer_development_guide.md | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/doc/development/sec/analyzer_development_guide.md b/doc/development/sec/analyzer_development_guide.md new file mode 100644 index 00000000000..a35bc2b7237 --- /dev/null +++ b/doc/development/sec/analyzer_development_guide.md @@ -0,0 +1,185 @@ +--- +stage: Secure +group: Static Analysis +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +--- + +# Sec section analyzer development + +Analyzers are shipped as Docker images to execute within a CI pipeline context. This guide describes development and testing +practices across analyzers. + +## Shared modules + +There are a number of shared Go modules shared across analyzers for common behavior and interfaces: + +- The [`command`](https://gitlab.com/gitlab-org/security-products/analyzers/command#how-to-use-the-library) Go package implements a CLI interface. +- The [`common`](https://gitlab.com/gitlab-org/security-products/analyzers/common) project provides miscellaneous shared modules for logging, certificate handling, and directory search capabilities. +- The [`report`](https://gitlab.com/gitlab-org/security-products/analyzers/report) Go package's `Report` and `Finding` structs marshal JSON reports. +- The [`template`](https://gitlab.com/gitlab-org/security-products/analyzers/template) project scaffolds new analyzers. + +## How to use the analyzers + +Analyzers are shipped as Docker images. For example, to run the +[semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) Docker image to scan the working directory: + +1. `cd` into the directory of the source code you want to scan. +1. Run `docker login registry.gitlab.com` and provide username plus + [personal](../../user/profile/personal_access_tokens.md#create-a-personal-access-token) + or [project](../../user/project/settings/project_access_tokens.md#create-a-project-access-token) + access token with at least the `read_registry` scope. +1. Run the Docker image: + + ```shell + docker run \ + --interactive --tty --rm \ + --volume "$PWD":/tmp/app \ + --env CI_PROJECT_DIR=/tmp/app \ + -w /tmp/app \ + registry.gitlab.com/gitlab-org/security-products/analyzers/semgrep:latest /analyzer run + ``` + +1. The Docker container generates a report in the mounted project directory with a report filename corresponding to the analyzer category. For example, [SAST](../../user/application_security/sast) generates a file named `gl-sast-report.json`. + +## Analyzers development + +To update the analyzer: + +1. Modify the Go source code. +1. Build a new Docker image. +1. Run the analyzer against its test project. +1. Compare the generated report with what's expected. + +Here's how to create a Docker image named `analyzer`: + +```shell +docker build -t analyzer . +``` + +For example, to test Secret Detection run the following: + +```shell +wget https://gitlab.com/gitlab-org/security-products/ci-templates/-/raw/master/scripts/compare_reports.sh +sh ./compare_reports.sh sd test/fixtures/gl-secret-detection-report.json test/expect/gl-secret-detection-report.json \ +| patch -Np1 test/expect/gl-secret-detection-report.json && Git commit -m 'Update expectation' test/expect/gl-secret-detection-report.json +rm compare_reports.sh +``` + +You can also compile the binary for your own environment and run it locally +but `analyze` and `run` probably won't work +since the runtime dependencies of the analyzer are missing. + +Here's an example based on +[SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs): + +```shell +go build -o analyzer +./analyzer search test/fixtures +./analyzer convert test/fixtures/app/spotbugsXml.Xml > ./gl-sast-report.json +``` + +## How to test the analyzers + +Video walkthrough of how Dependency Scanning analyzers are using [downstream pipeline](../../ci/pipelines/downstream_pipelines.md) feature to test analyzers using test projects: + +[![How Sec leverages the downstream pipeline feature of GitLab to test analyzers end to end](http://img.youtube.com/vi/KauRBlfUbDE/0.jpg)](http://www.youtube.com/watch?v=KauRBlfUbDE) + +### Testing local changes + +To test local changes in the shared modules (such as `command` or `report`) for an analyzer +you can use the +[`go mod replace`](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) +directive to load `command` with your local changes instead of using the version of command that has been +tagged remotely. For example: + +```shell +go mod edit -replace gitlab.com/gitlab-org/security-products/analyzers/command/v3=/local/path/to/command +``` + +Alternatively you can achieve the same result by manually updating the `go.mod` file: + +```plaintext +module gitlab.com/gitlab-org/security-products/analyzers/awesome-analyzer/v2 + +replace gitlab.com/gitlab-org/security-products/analyzers/command/v3 => /path/to/command + +require ( + ... + gitlab.com/gitlab-org/security-products/analyzers/command/v3 v2.19.0 +) +``` + +#### Testing local changes in Docker + +To use Docker with `replace` in the `go.mod` file: + +1. Copy the contents of `command` into the directory of the analyzer. `cp -r /path/to/command path/to/analyzer/command`. +1. Add a copy statement in the analyzer's `Dockerfile`: `COPY command /command`. +1. Update the `replace` statement to make sure it matches the destination of the `COPY` statement in the step above: +`replace gitlab.com/gitlab-org/security-products/analyzers/command/v3 => /command` + +## Versioning and release process + +Analyzers are independent projects that follow their own versioning. `Patch` version bumps tend to correspond to a `Minor` version bump of the underlying tools (i.e. [`bandit`](https://wiki.openstack.org/wiki/Security/Projects/Bandit)), allowing us greater flexibility in reserving `Minor` bumps for more significant changes to our scanners. In case of breaking changes imposed by the wrapped scanner, creating a new analyzer on a separate repository must be considered. + +The analyzers are released as Docker images following this scheme: + +- each push to the `master` branch will override the `edge` image tag +- each push to any `awesome-feature` branch will generate a matching `awesome-feature` image tag +- each Git tag will generate the corresponding `Major.Minor.Patch` image tag. A manual job allows to override the corresponding `Major` and the `latest` image tags to point to this `Major.Minor.Patch`. + +To release a new analyzer Docker image, there are two different options: + +- Manual release process +- Automatic release process + +### Manual release process + +1. Ensure that the `CHANGELOG.md` entry for the new analyzer is correct. +1. Ensure that the release source (typically the `master` or `main` branch) has a passing pipeline. +1. Create a new release for the analyzer project by selecting the **Deployments** menu on the left-hand side of the project window, then selecting the **Releases** sub-menu. +1. Select **New release** to open the **New Release** page. + 1. In the **Tag name** drop down, enter the same version used in the `CHANGELOG.md`, for example `v2.4.2`, and select the option to create the tag (`Create tag v2.4.2` here). + 1. In the **Release title** text box enter the same version used above, for example `v2.4.2`. + 1. In the `Release notes` text box, copy and paste the notes from the corresponding version in the `CHANGELOG.md`. + 1. Leave all other settings as the default values. + 1. Select **Create release**. + +After following the above process and creating a new release, a new Git tag is created with the `Tag name` provided above. This triggers a new pipeline with the given tag version and a new analyzer Docker image is built. + +If the analyzer uses the [`analyzer.yml` template](https://gitlab.com/gitlab-org/security-products/ci-templates/blob/b446fd3/includes-dev/analyzer.yml#L209-217), then the pipeline triggered as part of the **New release** process above automatically tags and deploys a new version of the analyzer Docker image. + +If the analyzer does not use the `analyzer.yml` template, you'll need to manually tag and deploy a new version of the analyzer Docker image: + +1. Select the **CI/CD** menu on the left-hand side of the project window, then select the **Pipelines** sub-menu. +1. A new pipeline should currently be running with the same tag used previously, for example `v2.4.2`. +1. After the pipeline has completed, it will be in a `blocked` state. +1. Select the `Manual job` play button on the right hand side of the window and select `tag version` to tag and deploy a new version of the analyzer Docker image. + +Use your best judgment to decide when to create a Git tag, which will then trigger the release job. If you +can't decide, then ask for other's input. + +### Automatic release process + +The following must be performed before the automatic release process can be used: + +1. Configure `CREATE_GIT_TAG: true` as a [`CI/CD` environment variable](../../ci/variables/index.md). +1. Check the `Variables` in the CI/CD project settings. Unless the project already inherits the `GITLAB_TOKEN` environment variable from the project group, create a [project access token](../../user/project/settings/project_access_tokens.md) with `complete read/write access to the API` and configure `GITLAB_TOKEN` as a [`CI/CD` environment variable](../../ci/variables/index.md) which refers to this token. + +After the above steps have been completed, the automatic release process executes as follows: + +1. A project maintainer merges an MR into the default branch. +1. The default pipeline is triggered, and the `upsert git tag` job is executed. + - If the most recent version in the `CHANGELOG.md` matches one of the Git tags, the job is a no-op. + - Else, this job automatically creates a new release and Git tag using the [releases API](../../api/releases/index.md#create-a-release). The version and message is obtained from the most recent entry in the `CHANGELOG.md` file for the project. +1. A pipeline is automatically triggered for the new Git tag. This pipeline releases the `latest`, `major`, `minor` and `patch` Docker images of the analyzer. + +### Steps to perform after releasing an analyzer + +1. After a new version of the analyzer Docker image has been tagged and deployed, please test it with the corresponding test project. +1. Announce the release on the relevant group Slack channel. Example message: + + > FYI I've just released `ANALYZER_NAME` `ANALYZER_VERSION`. `LINK_TO_RELEASE` + +**Never delete a Git tag that has been pushed** as there is a good +chance that the tag will be used and/or cached by the Go package registry. |