From d68f88c05343612e87930f8b742292421632cf10 Mon Sep 17 00:00:00 2001
From: Marc Barussaud <marc.barussaud@orange.com>
Date: Mon, 28 Oct 2024 08:35:44 +0000
Subject: [PATCH] Resolve "add a sast tool"

---
 README.md                      | 30 ++++++++++++-
 kicker.json                    | 29 ++++++++++++
 templates/gitlab-ci-golang.yml | 82 ++++++++++++++++++++++++++++++++++
 3 files changed, 140 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 691d514..c4aceec 100644
--- a/README.md
+++ b/README.md
@@ -174,6 +174,34 @@ In addition to a textual report in the console, this job produces the following
 | `$GO_PROJECT_DIR/reports/go-ci-lint.codeclimate.json` | [Code Climate](https://docs.codeclimate.com/docs/pylint) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscodequality) |
 | `$GO_PROJECT_DIR/reports/go-ci-lint.checkstyle.xml`   | Checkstyle                                               | [SonarQube integration](https://docs.sonarqube.org/latest/analysis/external-issues/)                        |
 
+### `go-semgrep` job
+
+This job performs a [Semgrep](https://semgrep.dev/docs/) analysis.
+
+It is bound to the `test` stage, and uses the following variables:
+
+| Input / Variable | Description | Default Value |
+| ---------------- | ----------- | ------------- |
+| `semgrep-disabled` / `GO_SEMGREP_DISABLED` | Set to `true` to disable this job | _none_ |
+| `semgrep-image` / `GO_SEMGREP_IMAGE` | The Docker image used to run [Semgrep](https://semgrep.dev/docs/) | `registry.hub.docker.com/semgrep/semgrep:latest` |
+| `semgrep-args` / `GO_SEMGREP_ARGS` | Semgrep [scan options](https://semgrep.dev/docs/cli-reference#semgrep-scan-command-options) | `--metrics off --disable-version-check` |
+| `semgrep-rules` / `GO_SEMGREP_RULES` | Space-separated list of [Semgrep rules](https://semgrep.dev/docs/running-rules).<br/>Can be both local YAML files or remote rules from the [Segmrep Registry](https://semgrep.dev/explore) (denoted by the `p/` prefix). | `p/golang p/gosec` |
+| `semgrep-download-rules-enabled` / `GO_SEMGREP_DOWNLOAD_RULES_ENABLED` | Download Semgrep remote rules | `true` |
+
+> :information_source: Semgrep may [collect some metrics](https://semgrep.dev/docs/metrics), especially when using rules from the Semgrep Registry.
+> To protect your privacy and let you run Semgrep in air-gap environments, this template disables all Semgrep metrics by default:
+>
+> * rules from the Semgrep registry are pre-downloaded and passed to Semgrep as local rule files (can be disabled by setting `semgrep-download-rules-enabled` / `GO_SEMGREP_DOWNLOAD_RULES_ENABLED` to `false`),
+> * the `--metrics` option is set to `off`,
+> * the `--disable-version-check` option is set.
+
+In addition to a textual report in the console, this job produces the following reports, kept for one week:
+
+| Report | Format | Usage |
+| ------ | ------ | ----- |
+| `$GO_PROJECT_DIR/reports/golang-semgrep.gitlab.json` | [GitLab's SAST format](https://semgrep.dev/docs/cli-reference#semgrep-scan-command-options) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportssast) |
+| `$GO_PROJECT_DIR/reports/golang-semgrep.native.json` | [Semgrep's JSON format](https://semgrep.dev/docs/cli-reference#semgrep-scan-command-options) | [DefectDojo integration](https://documentation.defectdojo.com/integrations/parsers/file/semgrep)<br/>_This report is generated only if DefectDojo template is detected_ |
+
 ### `go-mod-outdated` job
 
 This job enables a manual [Go-mod-outdated](https://github.com/psampaz/go-mod-outdated) analysis.
@@ -249,4 +277,4 @@ It is bound to the `test` stage, and uses the following variables:
 | Input / Variable | Description                            | Default value     |
 | --------------------- | -------------------------------------- | ----------------- |
 | `vulncheck-disabled` / `GO_VULNCHECK_DISABLED` | Set to `true` to disable this job | _none_ 
-| `vulncheck-args` / `GO_VULNCHECK_ARGS` | `govulncheck` [command line arguments](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck#hdr-Flags) | `./...` |
\ No newline at end of file
+| `vulncheck-args` / `GO_VULNCHECK_ARGS` | `govulncheck` [command line arguments](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck#hdr-Flags) | `./...` |
diff --git a/kicker.json b/kicker.json
index 3d1e9cc..df960da 100644
--- a/kicker.json
+++ b/kicker.json
@@ -152,6 +152,35 @@
         }
       ]
     },
+    {
+      "id": "go-semgrep",
+      "name": "Semgrep",
+      "description": "[Semgrep](https://semgrep.dev/docs/) analysis",
+      "disable_with": "GO_SEMGREP_DISABLED",
+      "variables": [
+        {
+          "name": "GO_SEMGREP_IMAGE",
+          "description": "The Docker image used to run [Semgrep](https://semgrep.dev/docs/)",
+          "default": "registry.hub.docker.com/semgrep/semgrep:latest"
+        },
+        {
+          "name": "GO_SEMGREP_ARGS",
+          "description": "Semgrep [scan options](https://semgrep.dev/docs/cli-reference#semgrep-scan-command-options)",
+          "default": "--metrics off --disable-version-check"
+        },
+        {
+          "name": "GO_SEMGREP_RULES",
+          "description": "Space-separated list of [Semgrep rules](https://semgrep.dev/docs/running-rules).\n\nCan be both local YAML files or remote rules from the [Semgrep Registry](https://semgrep.dev/explore) (denoted by the `p/` prefix)",
+          "default": "p/golang p/gosec"
+        },
+        {
+          "name": "GO_SEMGREP_DOWNLOAD_RULES_ENABLED",
+          "description": "Download Semgrep remote rules",
+          "type": "boolean",
+          "default": "true"
+        }
+      ]
+    },
     {
       "id": "govulncheck",
       "name": "Govulncheck",
diff --git a/templates/gitlab-ci-golang.yml b/templates/gitlab-ci-golang.yml
index b3c300c..14b9045 100644
--- a/templates/gitlab-ci-golang.yml
+++ b/templates/gitlab-ci-golang.yml
@@ -81,6 +81,26 @@ spec:
     ci-lint-args:
       description: '`golangci-lint` [command line arguments](https://github.com/golangci/golangci-lint#command-line-options)'
       default: -E gosec,goimports ./...
+    semgrep-image:
+      description: The Docker image used to run [Semgrep](https://semgrep.dev/docs/)
+      default: registry.hub.docker.com/semgrep/semgrep:latest
+    semgrep-disabled:
+      description: Disable Semgrep
+      type: boolean
+      default: false
+    semgrep-args:
+      description: Semgrep [scan options](https://semgrep.dev/docs/cli-reference#semgrep-scan-command-options)
+      default: --metrics off --disable-version-check
+    semgrep-rules:
+      description: |-
+        Space-separeted list of [Semgrep rules](https://semgrep.dev/docs/running-rules).
+
+        Can be both local YAML files or remote rules from the [Semgrep Registry](https://semgrep.dev/explore) (denoted by the `p/` prefix)
+      default: p/golang p/gosec
+    semgrep-download-rules-enabled:
+      description: Download Semgrep remote rules
+      type: boolean
+      default: true
     mod-outdated-args:
       description: '`god-mod-outdated` [command line arguments](https://github.com/psampaz/go-mod-outdated#usage'
       default: -update -direct
@@ -196,6 +216,11 @@ variables:
   GO_CI_LINT_DISABLED: $[[ inputs.ci-lint-disabled ]]
   GO_SBOM_DISABLED: $[[ inputs.sbom-disabled ]]
   GO_VULNCHECK_DISABLED: $[[ inputs.vulncheck-disabled ]]
+  GO_SEMGREP_IMAGE: $[[ inputs.semgrep-image ]]
+  GO_SEMGREP_DISABLED: $[[ inputs.semgrep-disabled ]]
+  GO_SEMGREP_ARGS: $[[ inputs.semgrep-args ]]
+  GO_SEMGREP_RULES: $[[ inputs.semgrep-rules ]]
+  GO_SEMGREP_DOWNLOAD_RULES_ENABLED: $[[ inputs.semgrep-download-rules-enabled ]]
 
   # Image of cyclonedx-gomod used for SBOM analysis
   GO_SBOM_IMAGE: $[[ inputs.sbom-image ]]
@@ -534,6 +559,31 @@ stages:
     fi
   }
 
+  function setup_semgrep_rules() {
+    if [[ "${GO_SEMGREP_DOWNLOAD_RULES_ENABLED}" == "true" ]]
+    then
+      log_info "Download Semgrep rule files..."
+      for rule in $GO_SEMGREP_RULES
+      do
+        if [[ -r $rule ]]
+        then
+          log_info "... rule file $rule found: skip"
+          SEMGREP_RULES="${SEMGREP_RULES} $rule"
+        else
+          log_info "... rule file $rule not found : download (https://semgrep.dev/c/$rule)"
+          dest_file="semgrep-${rule/p\//}.yml"
+          wget "https://semgrep.dev/c/$rule" -O "$dest_file"
+          SEMGREP_RULES="${SEMGREP_RULES} $dest_file"
+        fi
+      done
+      SEMGREP_RULES="${SEMGREP_RULES:1}"
+      export SEMGREP_RULES
+    else
+      # download not enabled: simply use $GO_SEMGREP_RULES
+      export SEMGREP_RULES="${GO_SEMGREP_RULES}"
+    fi
+  }
+
   unscope_variables
   eval_all_secrets
 
@@ -675,6 +725,38 @@ go-ci-lint:
       when: never
     - !reference [.test-policy, rules]
 
+# SAST: semgrep
+go-semgrep:
+  extends: .go-base
+  image: $GO_SEMGREP_IMAGE
+  # unset cache from parent job
+  cache : {}
+  dependencies: []
+  stage: test
+  before_script:
+    - *go-scripts
+    - cd $GO_PROJECT_DIR
+    - mkdir -p -m 777 reports
+    - setup_semgrep_rules
+  script:
+    - >-
+      semgrep ci ${TRACE+--verbose} ${GO_SEMGREP_ARGS}
+      --gitlab-sast-output=reports/golang-semgrep.gitlab.json
+      ${DEFECTDOJO_SEMGREP_REPORTS:+--json-output=reports/golang-semgrep.native.json}
+  artifacts:
+    name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $ĈI_COMMIT_REF_SLUG"
+    when: "always"
+    expire_in: 1 week
+    reports:
+      sast: $GO_PROJECT_DIR/reports/golang-semgrep.gitlab.json
+    paths:
+      - $GO_PROJECT_DIR/reports/golang-semgrep.*
+  rules:
+    # exclude if disable
+    - if: '$GO_SEMGREP_DISABLED == "true"'
+      when: never
+    - !reference [.test-policy, rules]
+
 go-mod-outdated:
   extends: .go-base
   stage: test
-- 
GitLab