This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Pull Request scans

Scan pull requests created in your repository.

This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Scan pull requests created in your repository.

Scan pull requests as soon as they are raised in your repository. PR scans detect vulnerabilities in your branch when they are introduced, making it easier to identify and fix them early.

PR scans help you to:

  • Detect new vulnerabilities as developers open or update PRs, instead of after merge.
  • Gate merges based on security and compliance.
  • Enforce policies that can block risky PRs or fail CI builds.
  • Give developers fast feedback on open source, SAST, and secrets findings tied to their changes through PR comments and PR Runs in the Endor Labs UI.

Endor Labs supports scanning pull requests and merge requests to evaluate the impact of proposed changes before they are merged. You can run PR scans in the following ways:

The following workflow describes a robust approach for scanning pull requests and merge requests against a stable baseline branch.

  1. Establish and maintain a baseline branch

    Scan your baseline branch, such as main, regularly with monitoring scans or CI scans. See Set a default branch for how the default branch is chosen and used. See Scanning strategies and Branches and workflows for more information on branch strategy, default branch setup, and recommended scan flags.

  2. Trigger PR scans on feature branches

    Configure PR scans for PRs targeting the baseline branch, for example, main. For large monorepos, enable incremental PR scans to focus only on changed dependencies and code.

  3. Use policies to enforce standards

    Use finding and action policies to decide when to warn, break builds, or block merges for PR scans.

  4. Integrate first-party scans

    Optionally, for app-triggered scans, enable SAST and secrets in the SCM integration when you install or manage the app. For CI-triggered scans, include the appropriate endorctl flags and steps in your pipeline so each run covers dependencies, first-party code, and secrets as needed.

You can scan pull requests or merge requests using endorctl for GitHub, GitLab, and Bitbucket. The --pr flag runs the scan for the current commit and records the results as PR runs that do not affect main branch monitoring scans and reports. Endor Labs stores PR and MR scan findings in PR Runs for three weeks, after which they are removed to accommodate new PR scans.

Run the following command after you commit to a pull request or merge request:

endorctl scan --pr

You can perform an incremental PR scan to scan only changed code and dependencies.

An incremental PR scan scans only the parts of the codebase and dependencies that have changed since the last full baseline scan.

  • Endor Labs identifies packages and dependencies in the PR and scans only those that changed relative to the baseline.
  • If no dependencies changed, the scan is skipped, and Endor Labs reports No changes found.
  • Incremental PR scans only report findings that do not exist in the baseline and are associated with changed dependencies in the PR.
  • You can enable incremental PR scans using the --pr-incremental flag or the equivalent CI settings. This flag is also available for SAST incremental scans and Incremental secret scans.

You need to set a baseline for incremental PR scans so only findings new relative to that branch are reported. For GitHub App or GitLab App scans, or when PR comments are enabled, the baseline is detected automatically. Otherwise, pass --pr-baseline when you run the scan. See Set a default branch for how the default branch is chosen and used.

Baseline mismatch in PR scans
If a finding is fixed in the baseline by upgrading or downgrading a dependency and a PR still modifies that package, the finding can be reported as new. To mitigate this, rebase the PR with the latest baseline content and re-run the PR check.

Run the following command to perform an incremental PR scan. Replace main with your baseline branch.

endorctl scan --pr --pr-baseline=main --pr-incremental

When you set --enable-pr-comments, you must also set --scm-pr-id so the scan can determine where to post comments and infer the baseline automatically.

To run an incremental PR scan and publish findings as review comments on a GitHub PR, use the following command. The --scm-pr-id flag associates the scan with the PR, and comments are posted according to your action policies.

endorctl scan \
  -n <your-namespace> \
  --pr \
  --pr-incremental \
  --scm-pr-id <pull-request-id> \
  --github-token <your-github-token> \
  --enable-pr-comments

In this command:

  • --pr-incremental: Limits the scan to changes relative to the baseline branch.
  • --scm-pr-id: Links the run to the specific PR so comments are attached correctly.
  • --enable-pr-comments: Posts scan results as comments on the PR. When you set --enable-pr-comments, you must also set --scm-pr-id so the scan can determine where to post comments and infer the baseline automatically.
  • --github-token: Authenticates with GitHub to post comments.

The Endor Labs SCM integrations let you scan pull requests or merge requests when they are opened or updated. In the integration settings, enable PR or MR scans to run them automatically and, optionally, enable pull request comments to post findings as review comments. Action policies apply to PR scans the same way as to other scan types.

The following describe platform-specific setup and configuration options:

PR scans can be run from a continuous integration pipeline by invoking endorctl scan with pull request flags in jobs triggered by pull request or merge request events. This approach provides control over when scans run, supports posting findings as PR or MR comments, and allows policies to be enforced, such as failing builds or blocking merges. The scan profile assigned to the project determines the toolchains and environment used for the scan.

A scan profile defines the configuration applied to PR scans for a project, including languages, toolchains, path filters, and parameters such as enable_automated_pr_scans and enable_pr_comments. For CI-initiated PR scans, the scan profile determines the toolchains and environment configuration used to execute the scan.

Note

App-triggered PR scans run only when both of the following are true.

  • Pull Request scans or Merge Request scans are enabled during SCM app installation so the app receives PR or MR events.
  • Pull request scans or enable_automated_pr_scans is enabled in the scan profile assigned to the project.

To scope app-triggered PR scans to selected projects, enable Pull request scans only in the scan profiles assigned to those projects. In GitLab, MR scans can alternatively be scoped by configuring merge request webhooks for selected projects. See Configure scan profile through the UI for more information on scan profile settings.

PR comments are automated comments posted on pull or merge requests when Endor Labs detects policy violations during a PR scan. Enable them in your SCM integration or using --enable-pr-comments in CI, then configure an action policy with Branch Type Pull Request. See Pull Request comments and Action policies for setup and configuration.

PR scan findings are stored as PR Runs and kept for three weeks to accommodate new PR activity.

To view PR scan results in the Endor Labs:

  1. Sign in to Endor Labs and select Projects from the left sidebar.
  2. Search for and select your project from the list.
  3. Select PR RUNS to review the past scans.

From PR Runs you can see scan metadata, a severity summary, and open any scan for findings, issues, and logs. See PR Runs for more information.

How long are PR scan results retained?
Endor Labs retains PR scan findings as PR Runs for three weeks.
Why does a finding appear as new when it was fixed in the baseline?
Endor Labs reports a finding as new if the baseline includes a fix for the issue and the pull request modifies the affected package. To resolve the finding, rebase the pull request on the latest baseline and re-run the PR scan.
Why do two PR scans on the same pull request produce different results?
Results can differ when the PR or baseline branch changes, the scan profile is updated, or the vulnerability database is updated between runs. PR Runs store the findings produced at the time of execution. Subsequent PR scans evaluate the pull request using the current scan profile and the latest analysis data.
Do PR scans block merges automatically?
No, PR scans do not block merges by default. Blocking occurs only when policies are configured to fail CI jobs, apply blocking status checks, or prevent merges through PR comments.
Why does an incremental PR scan fall back to a full scan?
Endor Labs falls back to a full PR scan when no valid baseline exists for the project or when it cannot determine what changed relative to the baseline. Ensure the baseline branch has been scanned at least once before relying on incremental scans.

Pull Request comments

PR comments are automated comments added to pull requests when Endor Labs detects policy violations or security issues during scans. When a PR is raised or updated, Endor Labs runs scans on the proposed changes and adds a comment if any violations are detected based on the configured action policies.

Endor Labs generates the following types of PR comments based on the nature of the findings in a scan:

  • PR comments for Secrets: For findings of type FINDING_CATEGORY_SECRETS, Endor Labs adds a comment directly on the specific line where the secret is detected, using the line number provided in the finding object. These comments remain visible even if the secret is removed in a later scan.
  • PR comments for SCA: For SCA findings, Endor Labs adds a single comment that applies to the entire PR. It summarizes all findings from the policy evaluation results. The comment is updated with each scan run to reflect only the latest findings.
  • PR comments for SAST: For findings of type FINDING_CATEGORY_SAST, Endor Labs adds a single comment that applies to the entire PR. It summarizes all SAST-related policy violations detected during the scan. The comment is updated with each run and reflects only the latest findings.

After enabling PR comments, you must Configure an action policy to allow comments to be posted on pull requests or merge requests.

You can enable PR comments for GitHub through one of the following methods.

You can enable PR comments during the initial setup of the GitHub App or GitHub App (Pro), or by editing an existing integration. Once enabled, Endor Labs automatically adds comments to pull requests when policy violations are detected.

You can configure GitHub Actions to comment on PRs if there are any policy violations. Make sure that your GitHub Actions 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 # Replace v1 with the commit SHA of the latest version of the GitHub Action for enhanced security
        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 }}

The main.yaml file in this sample repository 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 # Replace v1 with the commit SHA of the latest version of the GitHub Action for enhanced security
        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.

You can expand the comment to view the following details:

  • Issue type: Describes the category of the security or policy violation
  • Severity: Indicates how critical the issue is.
  • Impacted files or dependencies: Specifies the files and packages affected by the issue.
  • Remediation steps: Specifies the required fix to resolve the detected issue.

PR Comment Details

You can generate PR comments using the CLI by including the following flags in the endorctl scan command.

endorctl scan \
  --pr \
  --enable-pr-comments \
  --scm-token <your-token> \
  --scm-pr-id <pull-request-id> \
  --namespace <your-namespace>

Ensure that you set the following parameters:

  • Set --enable-pr-comments to activate PR comment generation.
  • Use --scm-pr-id to specify the pull request to comment on.
  • Use --scm-token (or set the ENDOR_SCAN_SCM_TOKEN environment variable) and set the pull-requests permission to write for the token.
Note
You can continue to use --github-pr-id flag, but it will be deprecated and removed in the future.

You can enable MR comments for GitLab through one of the following methods.

You can enable MR comments during the initial setup of the GitLab App or by editing an existing integration. Once enabled, Endor Labs automatically adds comments to merge requests when policy violations are detected. See GitLab MR comments for more information.

You can configure GitLab CI pipelines to comment on merge requests when policy violations are detected. Add --enable-pr-comments, --scm-pr-id=$CI_MERGE_REQUEST_IID, and --scm-token=$ENDOR_SCAN_SCM_TOKEN to your scan command. Configure a GitLab CI/CD variable ENDOR_SCAN_SCM_TOKEN with your GitLab personal access token with the api scope. See Enable MR comments for complete configuration examples.

You can generate MR comments with endorctl by including the following flags in the endorctl scan command.

endorctl scan \
  --pr \
  --enable-pr-comments \
  --scm-token <your-token> \
  --scm-pr-id <merge-request-id> \
  --namespace <your-namespace>

Ensure that you set the following parameters:

  • Set --enable-pr-comments to activate MR comment generation.
  • Use --scm-pr-id to specify the merge request to comment on.
  • Use --scm-token. The token takes priority over installation PATs.
Note
Security review comments for GitLab merge requests are not yet supported.

You must create an Action policy to receive comments on your pull request after enabling PR comments.

  1. Create an Action policy.
  2. Set the Branch Type to Pull Request so the policy applies specifically to pull request scans.
  3. Under Action, select Enforce Policy, then choose:
    • Warn to post a comment without breaking the build.
    • Break the Build to fail the build and block the pull request.
  4. Define the scope of the policy using tags. Only projects that match the specified tags will receive PR comments.

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. Select Integrations from the left sidebar.
  2. Click Edit Template next to GitHub PR comments under Notifications.
  3. Make the required changes and click Save Template.

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 "protoc-gen-openapiv2/options/annotations.proto";
import "spec/internal/endor/v1/common.proto";
import "spec/internal/endor/v1/finding.proto";
import "spec/internal/endor/v1/package_version.proto";
import "spec/internal/endor/v1/security_review_pull_request.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;
}

// Data structure for security review comments on pull requests.
message SecurityReviewCommentData {
  option (internal.endor.ai.endor.v1.parent_kinds) = {};
  option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
    json_schema: {
      extensions: {
        key: "x-internal";
        value {bool_value: true}
      }
    }
  };

  // Represents a specific security risk identified in the code review.
  message SecurityRisk {
    // Icon representing the severity level of the risk.
    google.protobuf.StringValue severity_icon = 1;

    // The category or type of the security risk.
    google.protobuf.StringValue category = 2;

    // The title or name of the security risk.
    google.protobuf.StringValue title = 3;

    // Link to the specific code location where the risk was identified.
    google.protobuf.StringValue code_link = 4;

    // Detailed description of the security risk and potential impact.
    google.protobuf.StringValue description = 5;

    // The level of the security risk.
    google.protobuf.StringValue level = 6;

    // The type of impact (improvement or regression).
    google.protobuf.StringValue impact_type = 7;
  }

  // Represents an issue that occurred during the security analysis.
  message AnalysisIssue {
    // The type of the issue.
    SecurityReviewPullRequest.Spec.IssueType type = 1;

    // A descriptive message about the issue.
    google.protobuf.StringValue message = 2;

    // List of error messages encountered during analysis.
    repeated string errors = 3;

    // List of files that were skipped during analysis.
    repeated string skipped_files = 4;

    // List of files that were summarized instead of fully analyzed.
    repeated string summarized_files = 5;
  }

  // The header of the security review comment.
  // It should always be at the top of the template.
  google.protobuf.StringValue comment_header = 1;

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

  // A description of the changes made in the pull request.
  google.protobuf.StringValue changes_description = 3;

  // A general security assessment description.
  google.protobuf.StringValue security_description = 4;

  // The list of identified security risks in the pull request.
  repeated SecurityRisk security_risks = 5;

  // The list of issues encountered during analysis.
  repeated AnalysisIssue analysis_issues = 6;
}

See the following sections to understand the Finding and PackageVersion definitions that are used in this protobuf specification:

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 CommentTemplate.
var FuncMap = template.FuncMap{
	"now": utils.ToTime, // 'now' gives the current time

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

	// 'getPackageVersionURL' returns the URL for a given PackageVersion
	"getPackageVersionURL": utils.GetPackageVersionURL,

	// 'getFindingURL' returns the URL for a given Finding
	"getFindingURL": utils.GetFindingURL,

	// '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": utils.GetFindingsCountString,

	// 'hasFindingCategory' checks if a finding has a specific category
	"hasFindingCategory": utils.HasFindingCategory,

	// 'isNotEmptyString' checks if a string is not empty
	"isNotEmptyString": utils.IsNotEmptyString,

	// 'getCustomLocation' extracts the location from Custom field
	"getCustomLocation": func(finding *endorpb.Finding) string {
		return utils.GetCustomFieldValue(finding, "location")
	},

	// 'getCustomCodeSnippet' extracts the code snippet from Custom field
	"getCustomCodeSnippet": func(finding *endorpb.Finding) string {
		return utils.GetCustomFieldValue(finding, "code_snippet")
	},

	"fixBackticks": utils.FixUnclosedBackticks,

	// 'getFirstPartyReachableFunctions' extracts first-party functions from reachable paths
	"getFirstPartyReachableFunctions": utils.GetFirstPartyReachableFunctions,

	// 'groupFindingsByRemediation' groups findings by their remediation value
	// Returns a slice of GroupedRemediation where findings with the same remediation are grouped together
	"groupFindingsByRemediation": utils.GroupFindingsByRemediation,

	"consolidateRemediations": utils.ConsolidateRemediations,
}