Scanning with GitHub Actions

Learn how to implement Endor Labs in GitHub action workflows.

GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline. You can use GitHub Actions to include Endor Labs into your CI pipeline seamlessly.

Using this pipeline, developers can view and detect:

  • Policy violations in the source code
  • Secrets inadvertently included in the source code

The Endor Labs verifications are conducted as automated checks and help you discover violations before pushing code to the repository. Information about the violations can be included as comments on the corresponding pull request (PR). This enables developers to easily identify issues and take remedial measures early in the development life cycle.

  • For policy violations, the workflow is designed to either emit a warning or return an error based on your action policy configurations.
  • For secrets discovered in the commits, developers can view the PR comments and take necessary remedial measures.

To start using Endor Labs with GitHub:

Install Software Prerequisites

To ensure the successful execution of the Endor Labs GitHub action, the following prerequisites must be met:

  • The GitHub action must be able to authenticate with the Endor Labs API.
  • You must have the value of the Endor Labs namespace handy for authentication.
  • You must have access to the Endor Labs API.
  • If you use keyless authentication, you must set an authorization policy in Endor Labs. See Authorization policies for details.

Example GitHub Action Workflow

Endor Labs scanning workflow using GitHub actions that accomplishes the following tasks in your CI environment:

  • Tests PRs to the default branch and monitors the most recent push to the default branch.
  • Builds a Java project and sets up the Java build tools. If your project is not on Java, then configure this workflow with your project-specific steps and build tools.
  • Authenticates to Endor Labs with GitHub Actions keyless authentication.
  • Scan with Endor Labs.
  • Comments on PRs if any policy violations occur.
  • Generates findings and uploads results to GitHub in SARIF format.

The following example workflow shows how to scan with Endor Labs for a Java application using the recommended keyless authentication for GitHub actions:

name: Endor Labs Dependency and Secrets Scan
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
jobs:
  scan:
    permissions:
      security-events: write # Used to upload Sarif artifact to GitHub
      contents: read # Used to check out a private repository
      actions: read # Required for private repositories to upload Sarif files. GitHub Advanced Security licenses are required.
      id-token: write # Used for keyless authentication with Endor Labs
      pull-requests: write # Required to automatically comment on PRs for new policy violations
    runs-on: ubuntu-latest
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v3
    - name: Setup Java
      uses: actions/setup-java@v3
      with:
        distribution: 'microsoft'
        java-version: '17'
    - name: Build Package
      run: mvn clean install
    - name: Endor Labs Scan Pull Request
      if: github.event_name == 'pull_request'
      uses: endorlabs/github-action@v1.1.4
      with:
        namespace: 'example' # Replace with your Endor Labs tenant namespace
        scan_dependencies: true
        scan_secrets: true
        pr: true
        enable_pr_comments: true # Required to automatically comment on PRs for new policy violations
        github_token: ${{ secrets.GITHUB_TOKEN }} # Required for PR comments on new policy violations

  scan-main:
    permissions:
      id-token: write
      repository-projects: read
      pull-requests: read
      contents: read
    name: endorctl-scan
    runs-on: ubuntu-latest
    steps:
    - name: Checkout Repository
      uses: actions/checkout@v3
    - name: Setup Java
      uses: actions/setup-java@v3
      with:
        distribution: 'microsoft'
        java-version: '17'
    - name: Build Package
      run: mvn clean install
    - name: 'Endor Labs Scan Push to main'
      if: ${{ github.event_name == 'push' }}
      uses: endorlabs/github-action@v1.1.4
      with:
        namespace: 'example' # Replace with your Endor Labs tenant namespace
        scan_dependencies: true
        scan_secrets: true
        pr: false
        scan_summary_output_type: 'table'
        sarif_file: 'findings.sarif'
    - name: Upload findings to github
      uses: github/codeql-action/upload-sarif@v3
      with:
        sarif_file: 'findings.sarif'

Authenticate with Endor Labs

Endor Labs recommends using keyless authentication in CI environments. Keyless authentication is more secure and reduces the cost of secret rotation. To set up keyless authentication see Keyless Authentication.

If you choose not to use keyless authentication, you can configure an API key and secret in GitHub for authentication as outlined in Managing API keys.

Authentication Without Keyless Authentication for GitHub

If you are not using keyless authentication for GitHub Actions, you must not provide id-token: write permissions to your GitHub token unless specifically required by a step in this job. You must also set enable_github_action_token: false in your Endor Labs GitHub action configuration.

The following example configuration uses the Endor Labs API key for authentication:

      - name: Scan with Endor Labs
        uses: endorlabs/github-action@v1.1.4
        with:
          namespace: 'example'
          api_key: ${{ secrets.ENDOR_API_CREDENTIALS_KEY }}
          api_secret: ${{ secrets.ENDOR_API_CREDENTIALS_SECRET }}
          enable_github_action_token: false

The following example configuration uses a GCP service account for keyless authentication to Endor Labs:

      - name: Scan with Endor Labs
        uses: endorlabs/github-action@v1.1.4
        with:
          namespace: 'example'
          gcp_service_account: '<Insert_Your_Service_Account>@<Insert_Your_Project>.iam.gserviceaccount.com'
          enable_github_action_token: false

Endor Labs GitHub Action Configuration Parameters

The following input configuration parameters are supported for the Endor Labs GitHub Action:

Common parameters

The following input global parameters are supported for the Endor Labs GitHub action:

Flags Description
api_key Set the API key used to authenticate with Endor Labs.
api_secret Set the secret corresponding to the API key used to authenticate with Endor Labs.
enable_github_action_token Set to false if you prefer to use another form of authentication over GitHub action OIDC tokens. (Default: true)
endorctl_checksum Set to the checksum associated with a pinned version of endorctl.
endorctl_version Set to a version of endorctl to pin this specific version for use. Defaults to the latest version.
log_level Set the log level. (Default: info)
log_verbose Set to true to enable verbose logging. (Default: false)
namespace Set to the namespace of the project that you are working with. (Required)
gcp_service_account Set the target service account for GCP based authentication. GCP authentication is only enabled if this flag is set. Cannot be used with api_key.

Scanning parameters

The following input parameters are also supported for the Endor Labs GitHub action when used for scanning:

Flags Description
additional_args Use additional_args with endorctl scan for advanced scenarios. However, no example use case currently exists as standard options suffice for typical needs.
enable_pr_comments Set to true to publish new findings as review comments. Requires pr and github_token. Additionally, the pull-requests: write permissions must be set in the workflow. (Default: false)
export_scan_result_artifact Set to false to disable the json scan result artifact export. (Default: true)
github_token Set the token used to authenticate with GitHub. Mandatory if enable_pr_comments is set to true
phantom_dependencies Set to true to enable phantom dependency analysis. (Default: false)
output_file Set a file to save the scan results. Use this instead of export_scan_result_artifact to save any scan results data to a file in the workspace for processing by others steps in the same job, instead of the workflow run log.
pr Set to false to track this scan as a monitored version within Endor Labs, as opposed to a point-in-time policy and finding test for a PR. (Default: true)
pr_baseline Set to the Git reference that you are merging to, such as the default branch. Enables endorctl to compare findings, so developers are only alerted to issues in the current changeset. Example: pr_baseline: "main". Note: Not needed if enable_pr_comments is set to true.
run_stats Set to false to disable reporting of CPU/RAM/time scan statistics via time -v (sometimes required on Windows runners). (Default: true)
sarif_file Set to a path on your GitHub runner to store the analysis results in SARIF format.
scan_dependencies Scan Git commits and generate findings for all dependencies. (Default: true)
scan_git_logs Perform a more complete and detailed scan of secrets in the repository history. Must be used together with scan_secrets. (Default: false)
scan_github_actions Scan source code repository for GitHub actions used in workflow files to analyze vulnerabilities and malware. (Default: false)
scan_tools Scan source code repository for CI/CD tools. (Default: false)
scan_package Scan a specified artifact or a package. Set the path to an artifact with scan_path. (Default: false)
scan_container Scan a specified container image. The image must be set with image and a project can be defined with project_name. (Default: false)
project_name Specify a project name for a container image scan or a package scan.
image Specify a container image to scan.
scan_path Set the path of the directory to scan. (Default: .)
scan_secrets Scan the source code repository and generate findings for secrets. See also scan_git_logs. (Default: false)
scan_summary_output_type Set the desired output format to table, json, yaml, or summary. (Default: json)
tags Specify a list of user-defined tags to add to this scan. You can use tags to search and filter scans later.
use-bazel Enable the usage of Bazel for the scan. (Default: false)
bazel_exclude_targets Specify a list of Bazel targets to exclude from the scan.
bazel_include_targets Specify a list of Bazel targets to scan. If bazel_targets_include is not set, the bazel_targets_query value is used to determine which Bazel targets to scan.
bazel_targets_query Specify a Bazel query to determine which Bazel targets to scan. Ignored if bazel_targets_include is set.

Configure Endor Labs Action Policies

Configure an action policy in the Endor Labs user interface to perform an action when a rule is triggered. See Action Policies for details on action policies.

  • Set the Policy Template to Detected Secrets and select the Template Parameters as desired.
  • Choose Enforce Policy and
    • Select Warn as the recommended action.
    • Select Break the Build to fail the build CI pipeline.

PR Comments

You can configure GitHub Actions to comment on PRs if there are any policy violations. When you raise a PR, Endor Labs scans and detects policy violations. A comment is added in the PR with the details of violation. The CI pipeline warns you or fails the build based on your action policy configuration. The PR comments also include recommendations to help you take necessary remedial actions.

You can customize the template of the comment according to your requirement.

Enable PR Comments

Make sure that your GitHub action workflow includes the following configuration.

  • The workflow must have a with clause including: enable_pr_comments to true to publish new findings as review comments and github_token: ${{ secrets.GITHUB_TOKEN }}. This token is automatically provisioned by GitHub when using GitHub actions. See GitHub configuration parameters for more information.
  • To grant Endor Labs the ability to comment on PRs you must include the permission pull-requests: write.

The following example configuration comments on PRs if a policy violation is detected.

      - name: Endor Labs Scan PR to Default Branch
        if: github.event_name == 'pull_request'
        uses: endorlabs/github-action@v1.1.4
        with:
          namespace: 'example' # Update with your Endor Labs namespace
          scan_summary_output_type: 'table'
          scan_dependencies: true
          scan_secrets: true
          pr: true
          enable_pr_comments: true
          github_token: ${{ secrets.GITHUB_TOKEN }}

PR Comments Example

You can view a live example of a GitHub repository with a workflow that enables PR comments.

The main.yaml file contains the following configuration to enable PR comments.

name: Build Release
on:
  pull_request:
    branches: [main]
  workflow_dispatch:
  push:
    branches: [main]
  schedule:
    - cron: "23 23 * * 0"
jobs:
  build:
    permissions:
      pull-requests: write
      security-events: write
      contents: read
      id-token: write
      actions: read
    runs-on: ubuntu-latest
    env:
      ENDOR_NAMESPACE: "endorlabs-hearts-github"
    steps:
      - name: Endor Labs Scan PR to Default Branch
        if: github.event_name == 'pull_request'
        uses: endorlabs/github-action@v1
        with:
          namespace: ${{ env.ENDOR_NAMESPACE }}
          pr: true
          enable_pr_comments: true
          github_token: ${{ secrets.GITHUB_TOKEN }}

The PR #10 introduced a reachable vulnerability. Since the workflow has enable_pr_comments set as true, a comment is added to the PR on the policy violation.

PR Comment

You can expand the comment to view more details about the violation and take steps to resolve the issue.

PR Comment Details

Customize GitHub PR comments notification templates

Endor Labs provides a default template with standard information that will be included in your pull requests as comments. You can use the default template, or you can choose to edit and customize this template to fit your organization’s specific requirements. You can also create custom templates using Go Templates.

  1. Sign in to Endor Labs and navigate to Manage>Integrations
  2. Look for GitHub PR comments under Notifications.
  3. Click Edit Template.
  4. Make the required changes and click Save Template.
  5. Click Restore to Default to revert the changes.
  6. Use the download icon in the top right corner to download this template.
  7. Use the copy icon to copy the information in the template.

Data model

To create custom templates for PR comments, you must understand the data supplied to the template.

See the following protobuf specification for the GithubCommentData message that this template uses.

syntax = "proto3";

package internal.endor.ai.endor.v1;

import "google/protobuf/wrappers.proto";
import "spec/internal/endor/v1/finding.proto";
import "spec/internal/endor/v1/package_version.proto";

option go_package = "github.com/endorlabs/monorepo/src/golang/spec/internal.endor.ai/endor/v1";
option java_package = "ai.endor.internal.spec";

// The list of finding UUIDs.
message FindingUuids {
  repeated string uuids = 1;
}

// The map of dependency name to findings.
message DependencyToFindings {
  map<string, FindingUuids> dependency_to_findings = 1;
}

// The map of PackageVersion UUID to DependencyToFindings.
message PackageToDependencies {
  map<string, DependencyToFindings> package_to_dependencies = 1;
}

message GithubCommentData {
  // The header of the PR comment. Identifies the PR comment published by Endor Labs.
  // It should always be at top of the template.
  google.protobuf.StringValue comment_header = 1;

  // The footer of the PR comment.
  google.protobuf.StringValue comment_footer = 2;

  // The map of finding UUID to finding object.
  map<string, internal.endor.ai.endor.v1.Finding> findings_map = 3;

  // The map of policy UUID to policy name.
  // This will contain only the policies that are triggered or violated.
  map<string, string> policies_map = 4;

  // The map of policy UUID to the list of finding UUIDs.
  map<string, FindingUuids> policy_findings_map = 5;

  // The map of PackageVersion UUID to PackageVersion object.
  map<string, internal.endor.ai.endor.v1.PackageVersion> package_versions_map = 6;

  // The data needs to be grouped as follows:
  //
  // - Policy 1
  // 		- Package 1
  //			- Dependency Package 1
  //				- Finding 1
  //				- Finding 2
  //			- Dependency Package 2
  //				- Finding 3
  //				- Finding 4
  // 		- Package 2
  //			- Dependency Package 1
  //				- Finding 1
  //				- Finding 5
  // - Policy 2
  //		....
  //
  //		Map 0[PolicyUUID]/Map 1[PkgVerUUID]/Map 2 [Dep Names]/Finding UUID
  map<string, PackageToDependencies> data_map = 7;

  google.protobuf.StringValue api_endpoint = 8;
}

To understand Finding and PackageVersion definitions that are used in this protobuf specification, see:

See the following specification to understand the additional functions that are also available. You can access these functions by using their corresponding keys.


// FuncMap contains the additional functions that are available to GithubCommentTemplate.
var FuncMap = template.FuncMap{
	"now": toTime, // 'now' gives the current time

	// 'enumToString' coverts the enums for finding level, finding category and finding tags to string
	"enumToString": enumToString,

	// 'getPackageVersionURL' returns the URL for a given PackageVersion
	"getPackageVersionURL": func(apiURL string, packageVersion *endorpb.PackageVersion) string {
		result, err := common.GetPackageVersionURL(apiURL, packageVersion)
		if err != nil {
			return ""
		}
		return result
	},

	// 'getFindingURL' returns the URL for a given Finding
	"getFindingURL": func(apiURL string, finding *endorpb.Finding) string {
		result, err := common.GetFindingURL(apiURL, finding)
		if err != nil {
			return ""
		}
		return result
	},

	// 'add' returns the sum of two integers
	"add": func(n int, incr int) int {
		return n + incr
	},

	// 'getOtherFindingsPackageMarker' returns the key for _findingsWithNoPackages for lookup in DataMap
	// Not all findings are associated with a PackageVersion, such findings are grouped under this key
	// in the DataMap
	"getOtherFindingsPackageMarker": func() string { return _findingsWithNoPackages },

	// 'getOtherFindingsDependencyMarker' returns the key for _findingsWithNoDeps for lookup in DataMap
	// Not all findings are associated with a dependency, such findings are grouped under this key
	// in the DataMap
	"getOtherFindingsDependencyMarker": func() string { return _findingsWithNoDeps },

	// 'getFindingsCountString' returns a string with number of findings, example - "5 findings"
	"getFindingsCountString": func(dataMap *endorpb.PackageToDependencies) string {
		count := 0

		for _, depMap := range dataMap.PackageToDependencies {
			for _, findingMap := range depMap.DependencyToFindings {
				count += len(findingMap.Uuids)
			}
		}

		findingsStr := "findings"
		if count == 1 {
			findingsStr = "finding"
		}

		return fmt.Sprintf("%d %s", count, findingsStr)
	},
}