Skip to content

Latest commit

 

History

History
241 lines (180 loc) · 10.2 KB

README-code-scan.md

File metadata and controls

241 lines (180 loc) · 10.2 KB

gha-security/code-scan

Usage

Add the following step to your workflow configuration:

jobs:
  code-scan:
    name: Code Scan
    uses: entur/gha-security/.github/workflows/code-scan.yml@v2
    secrets: inherit

or add the Entur Shared Workflow CodeQL Scan. Go to the Actions tab in your repository, click on New workflow and select the button Configure on the CodeQL Scan workflow.

Inputs

INPUT TYPE REQUIRED DEFAULT DESCRIPTION
use_setup_gradle boolean false false Use "gradle/action/setup-gradle" before running autobuild
(Java/Kotlin only). Potentially speeds up build
times if cache from main
branch is utilized

Golden Path

  • Workflow must be named codeql.yml.

Example

# codeql.yml
name: "CodeQL"

on:
    pull_request:
        branches:
            - main
    push:
        branches:
            - main
        paths-ignore:
            - '**/README.md'
    schedule:
        - cron: "0 3 * * MON"
  
jobs:
    code-scan:
        name: Code Scan
        uses: entur/gha-security/.github/workflows/code-scan.yml@v2
        secrets: inherit

Optional Dependency caching for Java/Kotlin

Code vulnerability scans of Java and Kotlin are done by running autobuild, which runs any identified build systems, like Gradle.

If the project uses the gradle/actions/setup-gradle action, you can set code scanning to utilize any available cache from the 'main' branch. This potentially speeds up code analysis jobs.

Caching is deactivated by default.

To activate caching, set input use_setup_gradle to true.

Example:

# codeql.yml
name: "CodeQL"

...

jobs:
    code-scan:
        name: Code Scan
        uses: entur/gha-security/.github/workflows/code-scan.yml@v2
        secrets: inherit
        with:
          use_setup_gradle: true

Allow lists

The reusable workflow uses CodeQL to scan the codebase for vulnerabilities. Any discovered vulnerabilities will be published in the Security tab for the repository, under the Code Scanning section. If you believe a finding is a false positive or otherwise not relevant, you can either manually dimiss the alert, or create a allowlist file (YAML-file) that dismisses all alerts that matches a vulnerability ID. This list is then used in the current repo, but can also be shared and used with other repos.

Requirements:

  • The allowlist file MUST adhere to the format specified later in this document.
  • The allowlist file MUST be named either codescan.yml or codescan.yaml.
  • The file MUST be placed in .entur/security, relative to the root of the repository.

Note: If the scan is performed on a pull request, remember to filter the Code Scanning results by pull request number and not the branch name.

Shared allowlists works by referencing it in when you define an allowlist for your project. The contents of that list is then combined with the one in your repo. The contents of the "local" allowlist takes presedence of the "external" list.

To use an external allowlist create a YAML file in a different repository, reference the name of the repository in the .spec.inherit field of your allowlist.

Read Permissions of the repo containing any external allowslists are REQUIRED. It is important to note that a fine-grained access token must be created, with READ CONTENT permissions to the repository. The token then MUST be added as a secret to the repository where the workflow is executed, and MUST be named EXTERNAL_REPOSITORY_TOKEN.

You can find documentation on how to create a fine-grained access token here, and how to add it as a secret to your repository here.

Requirements for referencing external allowlists

  • A fine-grained access token must be created to access the external allowlist file, with READ CONTENT permissions to the external repository.
  • The token must be added as a secret to the repository where the workflow is run, and be named EXTERNAL_REPOSITORY_TOKEN.
  • Any repository using an external allowlist file for inheritance, must still define an allowlist referencing the name of the repo containing the external list. See schema for more info.

Schema for allowlist file

apiVersion: entur.io/securitytools/v1
kind: CodeScanConfig
metadata:
  id: {unique identifier}
  name: {human readable name}
  owner: {responsible team or developer}
spec:
  inherit: {repository where the external allowlist file is placed}
  allowlist:
  - cwe: {cwe-id}
    comment: {comment explaining why the vulnerability is dismissed}
    reason: {reason for dismissing the vulnerability}

Metadata:

All fields in metadata are REQUIRED.

The id field MUST be a unique alphanumeric (no special characters) string identifing the allowlist. This can be anything, but when in doubt use your app ID.

The name field under the metadata section SHOULD be the name of the project.

The owner field MUST be whomever's responsible for the list, like team or a single developer.

Spec:

The OPTIONAL inherit field MUST be the name of containing repository where containing a valid allow list you wish to inherit from. Only used when using an external allowlist.

The OPTIONAL allowlist field MUST be a list of vulnerabilities that you want to dismiss/allow. For each vulnerability you want to dismiss, you MUST add a new item to the list. Each item is an object and MUST contain the following fields: cwe, comment, and reason.

  • The cwe field corresponds to the CWE-ID of the vulnerability you want to dismiss,
  • The comment field is a comment explaining why the vulnerability is dismissed.
  • The reason field MUST be one of the following types:
    • false_positive This alert is not valid
    • wont_fix This alert is not relevant
    • test This alert is not in production code

Note: inherit and allowlist are NOT mutually exclusive. Any items in allowlist takes presedence over an inherited allowlist.

Example

apiVersion: entur.io/securitytools/v1
kind: CodeScanConfig
metadata:
  id: myprojectconfig
  name: my-project-config
  owner: team-supreme
spec:
  inherit: other-repo-name
  allowlist:
  - cwe: "cwe-080"
    comment: "This alert is a false positive"
    reason: "false_positive"
  - cwe: "cwe-916"
    comment: "Wont be able to fix this in the near future"
    reason: "wont_fix"
  - cwe: "cwe-400"
    comment: "Used for testing purposes"
    reason: "test"  

Troubleshooting

Some potential pitfalls and solutions with CodeQL

Code scanning results: Configuration(s) not found

This can happen if you previously had earlier commit(s) in main branch that had an analysis that included the configuration(s).
CodeQL tries looking for the analysis with the configuration it warns about in the PR, but does not find it.

To fix this error it requires deleting all previous analysis for the configuration.
They should be in their own set by the unique category set and ref set.

Example of analysis with a kotlin configuration:

{
    "ref": "refs/heads/main",
    "commit_sha": "...",
    "analysis_key": ".github/workflows/codeql.yml:codeql-analysis",
    "environment": "{\"language\":\"kotlin\"}",
    "category": "/language:kotlin",
    "error": "",
    "created_at": "2025-01-03T12:42:17Z",
    "results_count": 0,
    "rules_count": 74,
    "id": 0,
    "url": "https://api.github.com/repos/entur/repository_name/code-scanning/analyses/....",
    "sarif_id": "...",
    "tool": {
      "name": "CodeQL",
      "guid": null,
      "version": "2.20.0"
    },
    "deletable": true,
    "warning": ""
  }

See Github documentation for how to delete code scanning analysis for the configuration.

Autobuild fails for Gradle projects because of JVM version mismatch

This can happen if Autobuild detects the wrong version of the JVM to run Gradle with. This can be solved by statically setting the JVM version in the Gradle toolchain:

...
java {
  toolchain {
    languageVersion.set(JavaLanguageVersion.of(<JVM_VERSION>)) // Replace with correct JVM Version
  }
}
...

Autobuild fails for Gradle projects with multiple gradle project files.

Autobuild checks the root project file for which JVM version to set based on the version set on the JVM toolchain. Github also has a page that explains it in more detail: Autodetection for java

Autodetect will not find the correct version from child project files, if you have a root project file that does not compile JVM code. To fix this, you can trick autobuild with a comment.

The comment needs to be set on first line of the root project file (build.gradle)

// Hint for the CodeQL autobuilder: sourceCompatibility = <JVM_VERSION>
...

More detail about this fix in the Github Issues thread

Github Rulesets

See Security rulesets for how to setup code scanning merge protection ruleset.