diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 479503e..f9c85ae 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,19 +1,19 @@ include: - - component: gitlab.com/$CI_PROJECT_PATH/sast@$CI_COMMIT_SHA + - component: $CI_SERVER_FQDN/$CI_PROJECT_PATH/sast@$CI_COMMIT_SHA stages: [test, release] -ensure-brakeman-job-added: +ensure-semgrep-job-added: image: badouralix/curl-jq script: - | - route="https://gitlab.com/api/v4/projects/$CI_PROJECT_ID/pipelines/$CI_PIPELINE_ID/jobs" - count=`curl --silent $route | jq 'map(select(.name | contains("brakeman-sast"))) | length'` + route="$CI_API_V4_URL/projects/$CI_PROJECT_ID/pipelines/$CI_PIPELINE_ID/jobs" + count=`curl --silent $route | jq 'map(select(.name | contains("semgrep-sast"))) | length'` if [ "$count" != "1" ]; then exit 1 fi rules: - - if: $CI_COMMIT_BRANCH + - if: $CI_COMMIT_BRANCH && $CI_SERVER_HOST =~ /gitlab.com/ # Ensure that a project description exists, because it will be important to display # the resource in the catalog. @@ -21,14 +21,16 @@ check-description: image: badouralix/curl-jq script: - | - route="https://gitlab.com/api/v4/projects/$CI_PROJECT_ID" + route="$CI_API_V4_URL/projects/$CI_PROJECT_ID" desc=`curl --silent $route | jq '.description'` if [ "$desc" = "null" ]; then - echo "Description not set. Please set a projet description" + echo "Description not set. Please set a project description" exit 1 else echo "Description set" fi + rules: + - if: $CI_SERVER_HOST =~ /gitlab.com/ # Ensure that a `README.md` exists in the root directory as it represents the # documentation for the whole components repository. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0fb88d0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 GitLab Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 7c18e30..ed7a4de 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,24 @@ -# SAST (Static Application Security Testing) -Read more about this feature here: https://docs.gitlab.com/ee/user/application_security/sast/ +This project provides components for the use of Static Application Security Testing as well as Infrastructure as Code scanning. -Configure SAST with CI/CD variables (https://docs.gitlab.com/ee/ci/variables/index.html). -List of available variables: https://docs.gitlab.com/ee/user/application_security/sast/index.html#available-cicd-variables +[[_TOC_]] -## Usage +## Static Application Security Testing (SAST) + +### Documentation References + +Configuration for SAST can be performed through [CI/CD Variables](https://docs.gitlab.com/ee/ci/variables/index.html) or via the definition of [Inputs](https://docs.gitlab.com/ci/inputs/). + +More information about GitLab SAST is available within [GitLab documentation](https://docs.gitlab.com/ee/user/application_security/sast/), along with the [available variables](https://docs.gitlab.com/ee/user/application_security/sast/index.html#available-cicd-variables). + +### Usage You should add this component to an existing `.gitlab-ci.yml` file by using the `include:` keyword. ```yaml include: - - component: gitlab.com/gitlab-components/sast/sast@ + - component: gitlab.com/components/sast/sast@ ``` where `` is the latest released tag or `main`. @@ -21,7 +27,7 @@ If you are converting the configuration to use components and want to leverage t ```yaml include: - - component: gitlab.com/gitlab-components/sast/sast@main + - component: gitlab.com/components/sast/sast@main rules: - if: $SAST_DISABLED == "true" || $SAST_DISABLED == "1" when: never @@ -35,17 +41,49 @@ This assumes `SAST_DISABLED` variable is already defined in `.gitlab-ci.yml` wit ### Inputs | Input | Default value | Description | -| ----- | ------------- | ----------- | -| `stage` | `test` | The stage where you want the job to be added | -| `image_prefix` | `$CI_TEMPLATE_REGISTRY_HOST/security-products` | Define where all Docker image are pulled from | -| `image_tag` | `4` | Tag of the Docker image to use | +| ----- | ------------- | ----------- | +| `stage` | `test` | The stage where you want the job to be added | +| `image_prefix` | `$CI_TEMPLATE_REGISTRY_HOST/security-products` | Define where all Docker image are pulled from | +| `image_tag` | `4` | Tag of the Docker image to use | | `image_suffix` | `""` | Suffix added to image. If set to `-fips`, [`FIPS-enabled` images](https://docs.gitlab.com/ee/user/application_security/sast/#fips-enabled-images) are used for scan. Only used by `semgrep` analyzer | -| `excluded_analyzers` | `""` | Comma separated list of analyzers that should not run | -| `excluded_paths` | `"spec, test, tests, tmp"` | Comma separated list of paths to exclude | +| `excluded_analyzers` | `""` | Comma separated list of analyzers that should not run | +| `excluded_paths` | `"spec, test, tests, tmp"` | Comma separated list of paths to exclude | | `search_max_depth` | `4` | Defines how many directory levels the search for programming languages should span | | `run_kubesec_sast` | `"false"` | Set it to `"true"` to run `kubesec-sast` job | -| `include_experimental` | `"false"` | Set it to `"true"` to enable [experimental analyzers](https://docs.gitlab.com/ee/user/application_security/sast/#experimental-features) | +| `run_advanced_sast` | `false` | Set it to `true` to enable [GitLab Advanced SAST](https://docs.gitlab.com/ee/user/application_security/sast/gitlab_advanced_sast.html) | +| `ff_glas_enable_php_support` | `"true"` | Set it to `"false"` to disable [PHP support for GLAS](https://gitlab.com/groups/gitlab-org/-/epics/14273) | + +## Infrastructure as Code (IaC) Scanning + +### Documentation References + +Configuration for IaC scanning can be performed through [CI/CD Variables](https://docs.gitlab.com/ee/ci/variables/index.html) or via the definition of [Inputs](https://docs.gitlab.com/ci/inputs/). + +More information about GitLab Infrastructure as Code scanning is available within [GitLab documentation](https://docs.gitlab.com/user/application_security/iac_scanning/). + +### Usage + +You should add this component to an existing `.gitlab-ci.yml` file by using the `include:` +keyword. + +```yaml +include: + - component: gitlab.com/components/sast/iac-sast@ +``` + +where `` is the latest released tag or `main`. + +### Inputs + +| Input | Default value | Description | +| ----- | ------------- | ----------- | +| `stage` | `test` | The stage where you want the job to be added | +| `image_prefix` | `$CI_TEMPLATE_REGISTRY_HOST/security-products` | Define where all Docker image are pulled from | +| `image_tag` | `6` | Tag of the Docker image to use | +| `image_suffix` | `""` | Suffix added to image. | +| `excluded_paths` | `"spec, test, tests, tmp"` | Comma separated list of paths to exclude | +| `search_max_depth` | `4` | Defines how many directory levels the search for programming languages should span | ## Contribute -Please read about CI/CD components and best practices at: https://docs.gitlab.com/ee/ci/components \ No newline at end of file +Please read about CI/CD components and best practices at: https://docs.gitlab.com/ee/ci/components diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..e5c20d1 Binary files /dev/null and b/logo.png differ diff --git a/templates/iac-sast.yml b/templates/iac-sast.yml new file mode 100644 index 0000000..81ff32c --- /dev/null +++ b/templates/iac-sast.yml @@ -0,0 +1,38 @@ +# Component created based on GitLab's IAC SAST Scanning template +# Read more about this feature here: https://docs.gitlab.com/ee/user/application_security/iac_scanning/ + +spec: + inputs: + stage: + default: test + excluded_paths: + default: "spec, test, tests, tmp" + excluded_analyzers: + default: "" + image_prefix: + default: "$CI_TEMPLATE_REGISTRY_HOST/security-products" + image_suffix: + default: "" + search_max_depth: + default: 4 + image_tag: + default: 6 + +--- +kics-iac-sast: + stage: $[[ inputs.stage ]] + image: + name: "$[[ inputs.image_prefix ]]/kics:$[[ inputs.image_tag ]]$[[ inputs.image_suffix ]]" + variables: + SEARCH_MAX_DEPTH: $[[ inputs.search_max_depth ]] + script: + - /analyzer run + artifacts: + access: 'developer' + reports: + sast: gl-sast-report.json + allow_failure: true + rules: + - if: '"$[[ inputs.excluded_analyzers ]]" =~ /kics/' + when: never + - if: $CI_COMMIT_BRANCH diff --git a/templates/sast.yml b/templates/sast.yml index e924a1c..64e7743 100644 --- a/templates/sast.yml +++ b/templates/sast.yml @@ -5,7 +5,7 @@ spec: image_prefix: default: "$CI_TEMPLATE_REGISTRY_HOST/security-products" image_tag: - default: '4' + default: '6' image_suffix: default: "" excluded_analyzers: @@ -16,8 +16,14 @@ spec: default: '4' run_kubesec_sast: default: 'false' + run_advanced_sast: + default: false + type: boolean include_experimental: default: 'false' + ff_glas_enable_php_support: + default: true + type: boolean --- .sast-analyzer: stage: $[[ inputs.stage ]] @@ -27,40 +33,123 @@ spec: # E.g. SEARCH_MAX_DEPTH is overridden in some analyzers. We should pass the input instead. variables: SEARCH_MAX_DEPTH: $[[ inputs.search_max_depth ]] - SAST_EXCLUDED_PATHS: $[[ inputs.excluded_paths ]] + DEFAULT_SAST_EXCLUDED_PATHS: $[[ inputs.excluded_paths ]] + SAST_EXCLUDED_PATHS: "$DEFAULT_SAST_EXCLUDED_PATHS" script: - /analyzer run artifacts: + access: 'developer' reports: sast: gl-sast-report.json -brakeman-sast: +.deprecated-16.8: + extends: .sast-analyzer + script: + - echo "This job was deprecated in GitLab 16.8 and removed in GitLab 17.0" + - echo "For more information see https://gitlab.com/gitlab-org/gitlab/-/issues/425085" + - exit 1 + rules: + - when: never + +.gitlab-advanced-sast-exist-rules: + exists: + - '**/*.py' + - '**/*.go' + - '**/*.java' + - '**/*.jsp' + - '**/*.js' + - '**/*.jsx' + - '**/*.ts' + - '**/*.tsx' + - '**/*.cjs' + - '**/*.mjs' + - '**/*.cs' + - '**/*.rb' + - '**/*.php' + +.semgrep-with-advanced-sast-exist-rules: + exists: + - '**/*.c' + - '**/*.cc' + - '**/*.cpp' + - '**/*.c++' + - '**/*.cp' + - '**/*.cxx' + - '**/*.h' + - '**/*.hpp' + - '**/*.scala' + - '**/*.sc' + - '**/*.php' + - '**/*.swift' + - '**/*.m' + - '**/*.kt' + - '**/*.properties' + - '**/application*.yml' + - '**/bootstrap*.yml' + - '**/application*.yaml' + - '**/bootstrap*.yaml' + +.semgrep-exist-rules: + exists: + - '**/*.py' + - '**/*.js' + - '**/*.jsx' + - '**/*.ts' + - '**/*.tsx' + - '**/*.c' + - '**/*.cc' + - '**/*.cpp' + - '**/*.c++' + - '**/*.cp' + - '**/*.cxx' + - '**/*.h' + - '**/*.hpp' + - '**/*.go' + - '**/*.java' + - '**/*.cs' + - '**/*.scala' + - '**/*.sc' + - '**/*.php' + - '**/*.swift' + - '**/*.m' + - '**/*.rb' + - '**/*.kt' + - '**/*.cjs' + - '**/*.mjs' + - '**/*.properties' + - '**/application*.yml' + - '**/bootstrap*.yml' + - '**/application*.yaml' + - '**/bootstrap*.yaml' + +gitlab-advanced-sast: extends: .sast-analyzer image: - name: "$[[ inputs.image_prefix ]]/brakeman:$[[ inputs.image_tag ]]" + name: "$[[ inputs.image_prefix ]]/gitlab-advanced-sast:${SAST_ANALYZER_IMAGE_TAG}$[[ inputs.image_suffix ]]" + variables: + FF_GLAS_ENABLE_PHP_SUPPORT: "$[[ inputs.ff_glas_enable_php_support ]]" + SAST_ANALYZER_IMAGE_TAG: 2 + SEARCH_MAX_DEPTH: 20 + cache: + key: "scan-metrics-$CI_COMMIT_REF_SLUG" + fallback_keys: + - "scan-metrics-$CI_DEFAULT_BRANCH" + paths: + - "scan_metrics.csv" rules: - - if: '"$[[ inputs.excluded_analyzers ]]" =~ /brakeman/' + - if: '"$[[ inputs.excluded_analyzers ]]" =~ /gitlab-advanced-sast/' when: never - - if: $CI_COMMIT_BRANCH - exists: - - '**/*.rb' - - '**/Gemfile' + - if: '"$[[ inputs.run_advanced_sast ]]" != "true"' + when: never + - if: $CI_COMMIT_BRANCH && + $GITLAB_FEATURES =~ /\bsast_advanced\b/ + exists: !reference [.gitlab-advanced-sast-exist-rules, exists] + +brakeman-sast: + extends: .deprecated-16.8 flawfinder-sast: - extends: .sast-analyzer - image: - name: "$[[ inputs.image_prefix ]]/flawfinder:$[[ inputs.image_tag ]]" - rules: - - if: '"$[[ inputs.excluded_analyzers ]]" =~ /flawfinder/' - when: never - - if: $CI_COMMIT_BRANCH - exists: - - '**/*.c' - - '**/*.cc' - - '**/*.cpp' - - '**/*.c++' - - '**/*.cp' - - '**/*.cxx' + extends: .deprecated-16.8 kubesec-sast: extends: .sast-analyzer @@ -71,52 +160,17 @@ kubesec-sast: when: never - if: '$CI_COMMIT_BRANCH && "$[[ inputs.run_kubesec_sast ]]" == "true"' -.mobsf-sast: - extends: .sast-analyzer - image: - name: "$[[ inputs.image_prefix ]]/mobsf:$[[ inputs.image_tag ]]" - mobsf-android-sast: - extends: .mobsf-sast - rules: - - if: '"$[[ inputs.excluded_analyzers ]]" =~ /mobsf/' - when: never - - if: '$CI_COMMIT_BRANCH && "$[[ inputs.include_experimental ]]" == "true"' - exists: - - '**/*.apk' - - '**/AndroidManifest.xml' + extends: .deprecated-16.8 mobsf-ios-sast: - extends: .mobsf-sast - rules: - - if: '"$[[ inputs.excluded_analyzers ]]" =~ /mobsf/' - when: never - - if: '$CI_COMMIT_BRANCH && "$[[ inputs.include_experimental ]]" == "true"' - exists: - - '**/*.ipa' - - '**/*.xcodeproj/*' + extends: .deprecated-16.8 nodejs-scan-sast: - extends: .sast-analyzer - image: - name: "$[[ inputs.image_prefix ]]/nodejs-scan:$[[ inputs.image_tag ]]" - rules: - - if: '"$[[ inputs.excluded_analyzers ]]" =~ /nodejs-scan/' - when: never - - if: $CI_COMMIT_BRANCH - exists: - - '**/package.json' + extends: .deprecated-16.8 phpcs-security-audit-sast: - extends: .sast-analyzer - image: - name: "$[[ inputs.image_prefix ]]/phpcs-security-audit:$[[ inputs.image_tag ]]" - rules: - - if: '"$[[ inputs.excluded_analyzers ]]" =~ /phpcs-security-audit/' - when: never - - if: $CI_COMMIT_BRANCH - exists: - - '**/*.php' + extends: .deprecated-16.8 pmd-apex-sast: extends: .sast-analyzer @@ -131,15 +185,12 @@ pmd-apex-sast: security-code-scan-sast: extends: .sast-analyzer - image: - name: "$[[ inputs.image_prefix ]]/security-code-scan:$[[ inputs.image_tag ]]" + script: + - echo "This job was deprecated in GitLab 15.9 and removed in GitLab 16.0" + - echo "For more information see https://gitlab.com/gitlab-org/gitlab/-/issues/390416" + - exit 1 rules: - - if: '"$[[ inputs.excluded_analyzers ]]" =~ /security-code-scan/' - when: never - - if: $CI_COMMIT_BRANCH - exists: - - '**/*.csproj' - - '**/*.vbproj' + - when: never semgrep-sast: extends: .sast-analyzer @@ -150,20 +201,33 @@ semgrep-sast: rules: - if: '"$[[ inputs.excluded_analyzers ]]" =~ /semgrep/' when: never + # When gitlab-advanced-sast runs with PHP support enabled, exclude the `*.php` extension, as well as other files already scanned by gitlab-advanced-sast + - if: '$CI_COMMIT_BRANCH && + $GITLAB_FEATURES =~ /\bsast_advanced\b/ && + "$[[ inputs.excluded_analyzers ]]" !~ /gitlab-advanced-sast/ && + "$[[ inputs.run_advanced_sast ]]" == "true" && + "$[[ inputs.ff_glas_enable_php_support ]]" == "true"' + variables: + SAST_EXCLUDED_PATHS: "$DEFAULT_SAST_EXCLUDED_PATHS, **/*.py, **/*.go, **/*.java, **/*.js, **/*.jsx, **/*.ts, **/*.tsx, **/*.cjs, **/*.mjs, **/*.cs, **/*.rb, **/*.php" + exists: !reference [.semgrep-with-advanced-sast-exist-rules, exists] + # When gitlab-advanced-sast runs but PHP support is disabled, exclude files already scanned by gitlab-advanced-sast + - if: '$CI_COMMIT_BRANCH && + $GITLAB_FEATURES =~ /\bsast_advanced\b/ && + "$[[ inputs.excluded_analyzers ]]" !~ /gitlab-advanced-sast/ && + "$[[ inputs.run_advanced_sast ]]" == "true" && + "$[[ inputs.ff_glas_enable_php_support ]]" != "true"' + variables: + SAST_EXCLUDED_PATHS: "$DEFAULT_SAST_EXCLUDED_PATHS, **/*.py, **/*.go, **/*.java, **/*.js, **/*.jsx, **/*.ts, **/*.tsx, **/*.cjs, **/*.mjs, **/*.cs, **/*.rb" + exists: !reference [.semgrep-with-advanced-sast-exist-rules, exists] + # Fallback when advanced SAST covers everything + - if: '$CI_COMMIT_BRANCH && + $GITLAB_FEATURES =~ /\bsast_advanced\b/ && + "$[[ inputs.excluded_analyzers ]]" !~ /gitlab-advanced-sast/ && + "$[[ inputs.run_advanced_sast ]]" == "true"' + when: never + # Default case - run for all supported files - if: $CI_COMMIT_BRANCH - exists: - - '**/*.py' - - '**/*.js' - - '**/*.jsx' - - '**/*.ts' - - '**/*.tsx' - - '**/*.c' - - '**/*.go' - - '**/*.java' - - '**/*.cs' - - '**/*.html' - - '**/*.scala' - - '**/*.sc' + exists: !reference [.semgrep-exist-rules, exists] sobelow-sast: extends: .sast-analyzer @@ -190,5 +254,3 @@ spotbugs-sast: - if: $CI_COMMIT_BRANCH exists: - '**/*.groovy' - - '**/*.scala' - - '**/*.kt'