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

Return to the regular view of this page.

REST API

Create integrations, retrieve data, and automate your workflows with the Endor Labs REST API.
fe check

Quickstart

Start using the Endor Labs REST API immediately.

Read more

fe terminal

About the REST API

Get oriented with the Endor Labs REST API documentation.

Read more

fe sun

Using the REST API

Learn how to use the API to build your solutions.

Read more

fe key

Authentication

Learn how to authenticate to the Endor Labs REST API.

Read more

fe aperture

Use Cases

Explore use cases with Endor Labs REST API.

Read more

fe settings

Resource Kinds

Learn about the Endor Labs data model.

Read more

fe activity

Best Practices

Best practices when using the Endor Labs REST API.

Read more

fe remediate

Troubleshooting

Diagnose and resolve issues with the Endor Labs REST API.

Read more

fe command

REST API Reference

View the Endor Labs REST API reference.

Read more

1 - Quickstart

Start using the Endor Labs REST API immediately.

This article describes how to quickly get started with the Endor Labs REST API using the Endor Labs command line tool endorctl or curl. For a more detailed guide, see Getting started with the REST API.

The following is an example request to get the number of findings in your namespace:

  1. Authenticate with Endor Labs using endorctl init. For more information, see endorctl init.

    endorctl init --auth-mode google
    
  2. Use the endorctl command-line tool to make your request. Note that you do not have to provide the namespace or access token when using endorctl to access the Endor Labs REST API. For more information, see the Endor Labs CLI documentation.

    endorctl api list -r Finding --count
    
  1. Install curl if it isn’t already installed on your machine. To check if curl is installed, execute curl --version on the command line. If the output provides information about the version of curl, that means curl is installed. If you get a message similar to command not found: curl, you need to download and install curl. For more information, see the curl project download page.

  2. Authenticate with Endor Labs using endorctl init. For more information, see endorctl init.

    endorctl init --auth-mode google
    
  3. Create an access token. The access token produced below has the same scopes/permissions as the API key created through endorctl init. Treat your access token like a password. For more information, see Authentication.

    export ENDOR_TOKEN=$(endorctl auth --print-access-token)
    
  4. Use the Curl command to make your request. Pass your token in an Authorization header. The following is an example request to get the number of findings in a given namespace. If needed, replace $ENDOR_NAMESPACE with the name of your namespace, or export it as a variable using export ENDOR_NAMESPACE=<insert-namespace>.

    curl --get \
      --header "Authorization: Bearer $ENDOR_TOKEN" \
      --header "Accept-Encoding: gzip, deflate, br, zstd" \
      --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings?list_parameters.count=true"
    

For more information on HTTP headers and parameters, see Getting Started.

For more examples of common use cases, see Use cases.

2 - About the REST API

Get oriented with the Endor Labs REST API documentation.

Introduction

You can use the Endor Labs API to build scripts and applications that automate processes, integrate with Endor Labs, and extend Endor Labs. For example, you can use the API to triage findings, build an analytics dashboard, or manage releases.

Each REST API endpoint is documented individually, and the endpoints are categorized by the resource that they primarily affect. For example, you can find endpoints relating to findings in FindingService.

Getting started with the REST API

If you are new to REST APIs, you may find it helpful to refer to the Quickstart or Getting Started guide for an introduction. For more information, see:

If you are familiar with REST APIs but new to the Endor Labs REST API, you may find it helpful to refer to the authentication documentation. For more information, see:

Further reading

2.1 - API Versions

Learn how to specify which REST API version to use whenever you make a request to the Endor Labs REST API.

About API versioning

The Endor Labs REST API is versioned. Any breaking changes will be released in a new API version.

New endpoints, fields, and enum values are backwards compatible within the same version.

For every new version of the API that is released, the major version is specified in the URL. For example, https://api.endorlabs.com/v1/namespaces/my_namespace/projects uses version 1 of the endpoint, per the v1 path segment.

Each resources have their versions specified in the field meta.version. For example the following resource has version 1 per the v1 value for the field meta.version.

{
  "meta": {
    "create_time": "2023-12-05T00:04:21.853Z",
    "kind": "Project",
    "name": "https://github.com/my_organization/my_repository.git",
    "update_time": "2024-05-01T16:50:03.830911988Z",
    "version": "v1"
  },
  "uuid": "656e69058032bf0abaaeb681"
}

When using the endorctl command-line tool to access the API, new endpoints, fields, or enum values are not available if your version of endorctl is older than the API version. Make sure to keep endorctl up-to-date to access the latest features and endpoints. For more information, see Install and configure endorctl.

Check latest API version using curl

To check the latest API version using curl, run the following command:

curl -s https://api.endorlabs.com/meta/version | jq .Service.Version

Example request using curl

curl -s https://api.endorlabs.com/meta/version | jq .Service.Version
"v1.6.322"

Check latest endorctl version

To get both the current and the latest version of endorctl, run the following command:

endorctl --version

In addition to your current version of endorctl you will also see a notification such as the following if a newer version of endorctl is available.

Example request using endorctl

endorctl --version
endorctl version v1.6.293
A newer version of endorctl is available v1.6.317 - currently v1.6.293

2.2 - OpenAPI description

The Endor Labs REST API is fully described in an OpenAPI compliant document.

About OpenAPI

OpenAPI is a specification for describing REST API interfaces. It describes the API as an open standard to act as a dictionary for an API. OpenAPI enables developers to easily find and discover how to use your API. For more information, see the OpenAPI specification documentation.

Using the Endor Labs OpenAPI description

Because the OpenAPI description is machine readable, you can use it to do things like:

  • Generate libraries to facilitate using the REST API
  • Validate and test an integration that uses the REST API
  • Explore and interact with the REST API using third-party tools, such as Postman

For example, Endor Labs uses the OpenAPI description to generate the REST API reference documentation for each endpoint.

For more information, see the Endor Labs OpenAPI documentation.

3 - Using the REST API

Learn how to use the Endor Labs REST API to create integrations, retrieve data, troubleshoot problems, and automate your workflows.

3.1 - Getting started

Learn how to use the Endor Labs REST API.

Introduction

This article describes how to use the Endor Labs REST API. For a quickstart guide, see Quickstart for Endor Labs REST API.

The Endor Labs command line tool endorctl is a convenient wrapper around the Endor Labs REST API and allows you to interact with Endor Labs without having to worry about the REST protocol details. For more information, see Making a request below and the Endor Labs CLI documentation.

For a complete list of Endor Labs REST API endpoints, see the Endor Labs OpenAPI documentation.

About requests to the REST API

This section describes the elements that make up an API request:

Every request to the REST API includes an HTTP method and a path. Depending on the REST API endpoint, you might also need to specify request headers, authentication information, list parameters, or body parameters.

The REST API reference documentation describes the HTTP method, path, and parameters for every endpoint. It also displays example requests and responses for each endpoint. For more information, see the Endor Labs REST API documentation.

HTTP method

The HTTP method of an endpoint defines the type of action it performs on a given resource. Some common HTTP methods are GET, POST, DELETE, and PATCH. The REST API reference documentation provides the HTTP method for every endpoint.

For example, the HTTP method for the List Findings endpoint is GET.

Where possible, the Endor Labs REST API strives to use an appropriate HTTP method for each action.

Action Description
GET Used for retrieving resources.
POST Used for creating resources.
PATCH Used for updating properties of resources.
DELETE Used for deleting resources.

Path

Each endpoint has a path. The Endor Labs REST API reference documentation gives the path for every endpoint. For example, the path for the List Findings endpoint is https://api.endorlabs.com/v1/namespaces/{tenant_meta.namespace}/findings and the path for the Get Finding endpoint is https://api.endorlabs.com/v1/namespaces/{tenant_meta.namespace}/findings/{uuid}.

The curly brackets {} in a path denote path parameters that you need to specify. Path parameters modify the endpoint path and are required in your request. For example, the path parameter for the List Findings endpoint is {tenant_meta.namespace}. To use this path in your API request, replace {tenant_meta.namespace} with the name of the namespace where you want to request a list of findings. To get a specific finding object, add the object UUID to the end of the path.

Headers

Headers provide extra information about the request and the desired response. Following are some examples of headers that you can use in your requests to the Endor Labs REST API. For an example of a request that uses headers, see Making a request.

Authentication

All endpoints require authentication. Use the endorctl init command to authenticate with Endor Labs. For more information, see Authentication. For examples, see Making a request.

Accept-Encoding

Use the Accept-Encoding header to compress the data in the HTTP request to improve performance. If you use a json or REST client, you must always provide the Accept-Encoding header in the following format: Accept-Encoding: gzip, deflate, br, zstd. You must provide the header if you use any default HTTP clients to avoid performance bottlenecks.

Content-Type

To improve API performance, set the Content-Type header to application/jsoncompact. This prevents Endor Labs APIs from returning null or empty values, which is the default behavior.

Request-timeout

Use the Request-timeout header to specify the amount of time, in seconds, that you are willing to wait for a server response. For example: --header "Request-Timeout: 10".

The corresponding option for endorctl requests is -t/--timeout, for example: -t 10s.

Parameters

Many API methods require or allow you to send additional information in parameters in your request. There are a few different types of parameters: Path parameters, list parameters, and body parameters.

Path parameters

Path parameters modify the endpoint path. These parameters are required in your request. For more information, see Path.

List parameters

List parameters allow you to control what data is returned for a request. These parameters are usually optional. The documentation for each Endor Labs REST API endpoint describes any list parameters that it supports.

For example, all Endor Labs endpoints return one hundred objects by default. You can set page_size=2 to return two objects instead of 100. You can set count=true to just return the number of objects. You can use the filter list parameter to only list objects that match a specified list of criteria (see filters). For examples of requests that use list parameters, see Making a request and Use cases.

List Parameter Description
ci_run_uuid Only list objects from a specific PR scan. Example: list_parameters.ci_run_uuid=ee4a914c-8d6d-4b65-8b0e-9755e8a6cb3a
count Get the number of items in the list. Example: list_parameters.count=true
filter Specify the field names and values used to filter results. Example: list_parameters.filter=meta.parent_kind==Project
group.aggregation_paths Specify one or more fields to group objects by. Example: list_parameters.group.aggregation_paths=meta.name
group.show_aggregation_uuids Get the uuids of the objects in each group as specified by group.aggregation_paths. Example: list_parameters.group.aggregation_paths=meta.name&list_parameters.group.show_aggregation_uuids=true
group.unique_count_paths Count the number of unique values, for these fields, in the group. Example: list_parameters.group.aggregation_paths=meta.name&list_parameters.group.unique_count_paths=spec.ecosystem
group.unique_value_paths Get the unique values, for these fields, in the group. Example: list_parameters.group.aggregation_paths=meta.name&list_parameters.group.unique_value_paths=meta.name
group_by_time.aggregation_paths Group the list based on this time field. Example: list_parameters.group_by_time.aggregation_paths=meta.create_time
group_by_time.end_time End of the time period to group objects. Example: list_parameters.group_by_time.end_time=2023-12-31T23:59:59Z
group_by_time.group_size The time interval size to group the objects by. Example: list_parameters.group_by_time.interval=GROUP_BY_TIME_INTERVAL_WEEK&list_parameters.group_by_time.group_size=2
group_by_time.interval The time interval to group the objects by. Example: list_parameters.group_by_time.interval=GROUP_BY_TIME_INTERVAL_DAY
group_by_time.show_aggregation_uuids Get the uuids of the objects in each group as specified by group_by_time.aggregation_paths. Example: list_parameters.group_by_time.show_aggregation_uuids=true
group_by_time.start_time Beginning of the time period to group objects. Example: list_parameters.group_by_time.start_time=2023-01-01T00:00:00Z
mask Set the list of fields to return with a request. If no mask is given, all fields are returned by the API. Example: list_parameters.mask=uuid,mate.name
page_id Set the object UUID to start from. Example: list_parameters.page_id=66073889a6cfeb5e24e72abf
page_size Set the page size to limit the number of results returned (default 100). Example: list_parameters.page_size=10
page_token Set the page token to start from (default 0). Example: list_parameters.page_token=5
sort.order Order of the sort. (default SORT_ENTRY_ORDER_ASC). Example: list_parameters.sort.order=SORT_ENTRY_ORDER_DESC
sort.path Field to sort objects by. Example: list_parameters.sort.path=meta.name
traverse Get data from any child namespaces as well. Example: list_parameters.traverse=true

Body parameters

Body parameters allow you to pass additional data to the API. These parameters can be optional or required, depending on the endpoint. The documentation for each Endor Labs REST API endpoint describes the body parameters that it supports. For more information, see the Endor Labs OpenAPI documentation.

For example, the Create Policy endpoint requires that you specify a name, rule, query statement, and resource kinds for the new policy in your request. It also allows you to optionally specify other information, such as a description, actions, or tags to apply to the new policy. For an example of a request that uses body parameters, see Making a request.

Making a request

The following example retrieves all findings for reachable functions. For more examples, see Use cases.

  1. Setup

    Install the Endor Labs CLI on macOS, Windows, or Linux. For more information, see Install Endor Labs on your local system.

  2. Authenticate

    Authenticate with Endor Labs using endorctl init. For more information, see endorctl init.

    endorctl init --auth-mode google

  3. Make a request

    endorctl api list --resource Finding --filter "spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION"

    Note that you do not have to provide the access token or the namespace when using endorctl to access the Endor Labs REST API.

  1. Setup

    1. You must have curl installed on your machine. To check if curl is already installed, run curl --version- on the command line.

      • If the output provides information about the version of curl, that means curl is installed.
      • If you get a message similar to command not found: curl, that means curl is not installed. Download and install curl. For more information, see the curl download page.
    2. Install the Endor Labs CLI on macOS, Windows, or Linux. For more information, see Install Endor Labs on your local system.

  2. Authenticate

    1. Authenticate with Endor Labs using endorctl init. For more information, see endorctl init.

      endorctl init --auth-mode google

    2. Store the Endor Labs access token

      Run the following command from your terminal to get the Endor Labs access token.

      endorctl auth --print-access-token

  3. Choose an endpoint for your request

    Choose an endpoint to make a request to. You can explore the Endor Labs REST API documentation to discover endpoints that you can use to interact with Endor Labs.

    Identify the HTTP method and path of the endpoint. You will send these with your request. For more information, see HTTP method and Path.

    For example, the List Findings endpoint uses the HTTP method POST and the path /v1/namespaces/{tenant_meta.namespace}/findings.

    Identify any required path parameters. Required path parameters appear in curly brackets {} in the path of the endpoint. Replace each parameter placeholder with the desired value. For more information, see Path.

    For example, the List Findings endpoint uses the path /v1/namespaces/{tenant_meta.namespace}/findings, and the path parameter is {tenant_meta.namespace}. To use this path in your API request, replace {tenant_meta.namespace} with the name of the namespace where you want to list the findings.

  4. Choose options for your request

    Use the curl command to make your request. For more information, see the curl documentation.

    Specify the following options and values in your request:

    • --request or -X followed by the HTTP method as the value. For more information, see HTTP method.

      Note: You can also use the shorthand curl options --get and --post for GET and POST requests respectively.

    • --header or -H:

      • Authorization: Pass your authentication token in an Authorization header. You must use Authorization: Bearer with the Endor Labs REST API. For more information, see Authentication.
      • Accept-Encoding: Provide the Accept-Encoding header in the following format: Accept-Encoding: gzip, deflate, br, zstd to avoid performance bottlenecks. For more information, see Accept-Encoding.
      • Content-Type: Set the header as Content-Type: application/jsoncompact to prevent Endor Labs APIs from returning null or empty value. For more information, see Content-Type.
      • Request-timeout: Specify the amount of time, in seconds, that you are willing to wait for a server response. For more information, see Request-timeout.
    • --url followed by the full path as the value. The full path is a URL that includes the base URL for the Endor Labs REST API (https://api.endorlabs.com) and the path of the endpoint, like this: https://api.endorlabs.com/{PATH}. Replace {PATH} with the path of the endpoint. For more information, see Path.

      To use list parameters, add a ? to the end of the path, then append your list parameter name and value in the form list_parameter.parameter_name=value. Separate multiple list parameters with &. For example, to count the number of “Outdated Release” findings, use ?list_parameters.filter=meta.name==outdated_release&list_parameters.count=true. For more information, see List parameters.

      Note: Filters with spaces must be encoded when using curl. Replace spaces with %20 or use the --data-urlencode option for filters containing spaces.

    • --data or -d followed by any body parameters within a json object. If you do not need to specify any body parameters in your request, omit this option. For more information, see Body parameters.

  5. Make request

    1. Using --url

      curl --request GET \
        --header "Authorization: Bearer $ENDOR_TOKEN" \
        --header "Accept-Encoding: gzip, deflate, br, zstd" \
        --header "Content-Type: application/jsoncompact" \
        --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings?list_parameters.filter=spec.finding_tags%20contains%20FINDING_TAGS_REACHABLE_FUNCTION"
      
    2. Using --data-urlencode

      curl --request GET \
        --header "Authorization: Bearer $ENDOR_TOKEN" \
        --header "Accept-Encoding: gzip, deflate, br, zstd" \
        --header "Content-Type: application/jsoncompact" \
        --data-urlencode "spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION" \
        "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings"
      
  1. Setup

    Install the Endor Labs CLI on macOS, Windows, or Linux. For more information, see Install Endor Labs on your local system.

  2. Authenticate

    1. Authenticate with Endor Labs using endorctl init. For more information, see endorctl init.

      endorctl init --auth-mode google

    2. Store the Endor Labs access token

      Run the following command from your terminal to get the Endor Labs access token.

      endorctl auth --print-access-token

  3. Choose an endpoint for your request

    Choose an endpoint to make a request to. You can explore the Endor Labs REST API documentation to discover endpoints that you can use to interact with Endor Labs.

    Identify the HTTP method and path of the endpoint. You will send these with your request. For more information, see HTTP method and Path.

    For example, the List Findings endpoint uses the HTTP method POST and the path /v1/namespaces/{tenant_meta.namespace}/findings.

    Identify any required path parameters. Required path parameters appear in curly brackets {} in the path of the endpoint. Replace each parameter placeholder with the desired value. For more information, see Path.

    For example, the List Findings endpoint uses the path /v1/namespaces/{tenant_meta.namespace}/findings, and the path parameter is {tenant_meta.namespace}. To use this path in your API request, replace {tenant_meta.namespace} with the name of the namespace where you want to list the findings.

  4. Make a request

    @baseUrl = https://api.endorlabs.com
    @token = <insert-access-token>
    @namespace = <insert-namespace>
    
    ###
    GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION HTTP/1.1
    Authorization: Bearer {{token}}
    

3.2 - Data model

Learn about the Endor Labs data model.

Objects are persistent entities within the Endor Labs system that represent the results of your scans. Specifically, they can describe:

  • The projects and/or package versions that were scanned.
  • The results of the scans, including ScanResults, Findings, and Metrics.
  • The context used for the scan (for example, main branch vs. pull request).
  • The policies used for the scans.

To create, modify, or delete objects, you need to use the Endor Labs REST API - Either indirectly with the endorctl command-line tool or directly with the REST API.

3.2.1 - Common fields

Learn about the common fields for all objects in the Endor Labs data model.

All objects adhere to the same high-level structure as outlined below. Object specific fields are defined in Spec. For more information, see Resource kinds.

UUID

All objects have a unique UUID. You can use UUID to retrieve objects individually through the API.

Meta

All objects include a common nested object called Meta. This mandatory object contains common fields for each object, including:

Field name Description
name The name of the object.
description A description of the object.
kind The resource kind of the object (for example, RepositoryVersion).
version The version of the object, used to differentiate between different versions if needed.
parent_uuid The UUID of the parent object.
parent_kind The resource kind of the parent object (for example, Project).
create_time The time the object was created.
update_time The time the object was last updated (HTTP PATCH).
upsert_time The time the object was last updated or created (HTTP POST).
created_by The name and authentication source of the user who created the object. Example: ewok@endor.ai@google@api-key
updated_by The name and authentication source of the last user who updated the object. Example: vulnerabilityingestor@endor.ai@x509
tags A list of tags attached to the object. Tags can be used to organize objects and find collections of objects that satisfy certain conditions. A tag must be 63 characters or less and may contain alphanumeric characters, @, _, ., and -. An optional prefix must be separated with = (for example, my_tag=my_value).
annotations Map of additional metadata for the object. Annotation keys may contain alphanumeric characters, _, ., and -. Annotation values can be structured or unstructured and may include characters not permitted by tags. Values must be 16384 bytes or smaller.

TenantMeta

Most objects include a common nested object called TenantMeta. TenantMeta contains the following field:

Field name Description
namespace Name of the namespace the object belongs to. Organizes organizational units into virtual groupings of objects. Namespaces must be fully qualified names (for example, the child namespace of endor.prod called app is endor.prod.app).

OSS tenant

There is a common tenant for all OSS projects called oss, to which customers have read access.

Spec

All objects include a common nested object called Spec. This mandatory object contains the specification of the object, representing its current state. For more information, see Resource kinds.

Context

Most objects include a common nested object called Context. Contexts keep objects from different scans separated. The context object has the following fields:

Field name Description
type The type of context, usually defined based on how endorctl is being used.
id The ID of the context, such as a pull request ID or branch reference.
will_be_deleted_at The time when the object will be automatically deleted by the system.
tags A list of tags applied to a context. Used primarily for CI and SBOM contexts.

Context types

Each context has a type and an id. For example, objects created during a scan of the default branch belong to the main context, while objects for non-default branches have the context type ref.

Context type Description
CONTEXT_TYPE_MAIN Objects from a scan of the default branch. All objects in the OSS namespace are in the main context. The context id is always default.
CONTEXT_TYPE_REF Objects from a scan of a specific branch. The context id is the branch reference name.
CONTEXT_TYPE_CI_RUN Objects from a PR scan. The context id is the PR UUID. Objects in this context are deleted after 30 days.
CONTEXT_TYPE_SBOM Objects from an SBOM scan. The context id is the SBOM serial number or some other unique identifier.
CONTEXT_TYPE_EXTERNAL Indicates that this object is a copy/temporary value of an object in another project. Used for same-tenant dependencies. In source code reference this is equivalent to “vendor” folders. Package versions in the external context are only scanned for call graphs. No other operations are performed on them.

Processing status

Project and PackageVersion objects include a common nested object called ProcessingStatus, which contains fields about the processing status of the object (when it was/will be scanned). The processing status object has the following fields:

Field name Description
scan_state The state of the scan.
scan_time The last time the object was scanned. Projects onboarded via the GitHub App are scanned every 24 hours.
analytic_time The last time the object was analyzed. Analytics are run automatically every 24 hours.
disable_automated_scan A boolean used to disable automatic scanning by the system.

Scan state

The following scan states are supported:

Scan state Description
SCAN_STATE_NOT_PROCESSED The object has not yet been processed by the system.
SCAN_STATE_IDLE The object has been scanned at least once.
SCAN_STATE_INGESTING The object is being scanned.
SCAN_STATE_ANALYTIC The object is being analyzed.
SCAN_STATE_UNREACHABLE The object is not reachable from the scheduler.
SCAN_STATE_REQUEST_FULL_RESCAN The object is marked for a complete rescan. This only applies to OSS projects.
SCAN_STATE_REQUEST_INCREMENTAL_RESCAN The object is marked for an incremental rescan, where only new packages discovered in the scan are added.

Example

The following is an example of a Project object:

{
  "meta": {
    "create_time": "2023-12-05T00:04:21.853Z",
    "kind": "Project",
    "name": "https://github.com/my_organization/my_repository.git",
    "update_time": "2024-05-01T16:50:03.830911988Z",
    "version": "v1"
  },
  "processing_status": {
    "analytic_time": "2024-05-01T16:45:06.483972413Z",
    "disable_automated_scan": true,
    "scan_state": "SCAN_STATE_IDLE",
    "scan_time": "2024-03-18T14:38:31.899249002Z"
  },
  "spec": {
    "git": {
      "full_name": "endorlabs/monorepo",
      "git_clone_url": "git@github.com:my_organization/my_repository.git",
      "http_clone_url": "https://github.com/my_organization/my_repository.git",
      "organization": "endorlabs",
      "path": "monorepo",
      "web_url": "https://api.github.com/my_organization/my_repository"
    },
    "internal_reference_key": "https://github.com/my_organization/my_repository.git",
    "platform_source": "PLATFORM_SOURCE_GITHUB"
  },
  "tenant_meta": {
    "namespace": "my_namespace"
  },
  "uuid": "656e69058032bf0abaaeb681"
}

3.2.2 - Resource kinds

Learn about the resource kinds in the Endor Labs data model.

Here is an overview diagram of the Endor Labs data model for the most commonly used resource kinds. Lighter shading identifies the objects that are re-computed on every scan.

data model

This section describes the most commonly used resource kinds. For a complete list of supported resource kinds, see the Endor Labs OpenAPI documentation.

All objects contain a reference to the project UUID, either as the parent object (meta.parent_uuid) or a specific field in the object-specific data if the project is not the direct parent (spec.project_uuid if not specified otherwise).

Use the following command to get a list of all objects of a given resource kind in your tenant.

Here are a few useful options:

  • --count
  • --page-size=1
  • --list-all
  • --filter="meta.parent_uuid==<uuid>"
  • --filter="spec.project_uuid==<uuid>"
endorctl api list -r <resource-kind>

Project

  • This is the logical root of all the other information for a given project.
  • Contains information about the source code location of a project, such as a Git repository, or a package manager package name.
  • Does not have a parent and is not associated with a context.
  • The object name is the HTTP clone URL, for example: "https://github.com/definitelytyped/definitelytyped.git".

For more information, see the ProjectService REST API documentation.

Repository

  • Contains information about the source code for a project.
  • Child of a Project and, just like the Project, does not belong to a context.
  • There is at most one Repository per Project, but a Project may not have a Repository if there is no source code.
  • The object name is the same as the Project.

For more information, see the RepositoryService REST API documentation.

RepositoryVersion

  • Contains information about a specific version of a Repository.
  • Has the Project as the parent.
  • There are often multiple RepositoryVersions per project.
  • Each RepositoryVersion is associated with a Context.
  • The object name is the corresponding branch name, tag, or SHA, for example: "main".

For more information, see the RepositoryVersionService REST API documentation.

PackageVersion

  • Contains information about a specific version of a package and its dependencies.
  • Does not have a parent (for historical reasons), but is associated with a Context and connected to the Project via spec.project_uuid.
  • The object name is the corresponding package version name in the format <ecosystem>://<package-name>@<version>, for example: "mvn://org.webjars.npm:types__json-schema@1.2.3".

For more information, see the PackageVersionService REST API documentation.

Resolution errors

Details about any dependency resolution or call graph generation errors for a package version are stored in spec.resolution_errors. There are three categories of resolution errors, each with a separate field that can contain up to one resolution error:

  1. Unresolved - Details in spec.resolution_errors.unresolved if there was an error computing the unresolved dependencies.
  2. Resolved - Details in spec.resolution_errors.resolved if there was an error resolving the dependency versions.
  3. Call graph - Details in spec.resolution_errors.call_graph if there was an error generating the call graph.

Each resolution error has a status_error field and may also contain details about the target, the operation that failed, and a description of the error. The following status errors are supported:

Status Error Description
STATUS_ERROR_BUILD Indicates that the plugin failed to build the package version. This status error is only used for unresolved dependencies.
STATUS_ERROR_CALL_GRAPH Indicates that the system failed to create the call graph. This status error is only used for call graph computation.
STATUS_ERROR_DEPENDENCY Indicates that the system failed to resolve a dependency. Usually happens when a manifest contains bad associations of dependencies and versions. This status error is only used for resolved dependencies.
STATUS_ERROR_INTERNAL Indicates that there was an internal system failure such as a data stream error.
STATUS_ERROR_MANIFEST_LOAD Indicates that the system is unable to find the manifest of the language (pom.xml, packages.json, etc). This status error is only used for unresolved dependencies.
STATUS_ERROR_MANIFEST_PARSE Indicates that the system failed to parse the manifest. This status error is only used for unresolved dependencies.
STATUS_ERROR_MISSING_ARTIFACT Indicates that the system failed to compute the call graph because the package is not built. This status error is only used for call graph computation.
STATUS_ERROR_NO_CODE_ARTIFACT Indicates that the package version does not have any source code. This status error is only used for call graphs.
STATUS_ERROR_PACKAGE_VERSION_UNAVAILABLE Indicates that the package version is not available from the package manager. This status error is only used for unresolved dependencies.
STATUS_ERROR_UNSUPPORTED Indicates that a package version with an unsupported language was scanned.
STATUS_ERROR_VENV Indicates that the system failed to create the virtual environment required to generate the call graph. This status error is only applicable to Python projects.

Below is an example resolution error in the Resolved category:

{
  "spec": {
    "resolution_errors": {
      "resolved": {
        "description": "failed to discover dependency: unable to resolve dependencies for 'requirements': unable to get direct dependencies: unable to install modules to extract dependencies: unable to resolve package version: ResolveModuleVersion: error in pypi json api for: torch, exact version: 1.9.0+cpu, err: package not found in the repository: unable to resolve dependency version: unable to discover dependencies, unable to discover dependencies",
        "operation": "python:resolvedDependencies:discover",
        "status_error": "STATUS_ERROR_DEPENDENCY",
        "target": "pypi://requirements@main"
      }
    }
  }
}

DependencyMetadata

  • Different from other common resource kinds as it represents the relationship between two PackageVersions: The importer and the dependency.
  • There is one DependencyMetadata object for every dependency for every PackageVersion.
  • Has the importer PackageVersion as the parent and exists in the same Namespace and Context as the parent.
  • The object name is the same as the dependency PackageVersion.
  • Combine the object name (meta.name) and the parent UUID (meta.parent_uuid) to get a unique key.
  • Connected to the Project via spec.importer_data.project_uuid.
  • Details about the relationship are stored in spec.dependency_data, for example:
    • spec.dependency_data.direct
    • spec.dependency_data.reachable
    • spec.dependency_data.scope

For more information, see the DependencyMetadataService REST API documentation.

LinterResult

  • Contains the results of scans using 3rd party programs such as gitleaks or Semgrep.
  • Has a RepositoryVersion or PackageVersion as the parent.
  • Belongs to the same Context as the parent.
  • Connected to the Project through spec.project_uuid.
  • The object name is the name of the rule that created the result, for example: "gen-shady-links".
  • The result origin is stored in spec.origin, for example: "LINTER_RESULT_ORIGIN_SECRETS_SCANNER".

For more information, see the LinterResultService REST API documentation.

Metric

  • Contains the output of the analytics processing.
  • Has a PackageVersion, RepositoryVersion, or Repository as the parent.
  • Belongs to the same Context as the parent.
  • Connected to the Project via spec.project_uuid.
  • The object name is the name of the analytic that created the metric, for example: "package_version_scorecard".

For more information, see the MetricService REST API documentation.

Metric types

There are many different types of Metrics. The specifics are stored under spec.metric_values.<key>.<value>, for example: spec.metric_values.scorefactor.score_factor_list. Some Metrics have more than one key-value field under spec.metric_values. The following table lists all supported Metric types along with the corresponding paths to the Metric specific data under spec.metric_values.

| Metric Name | Metric Values Paths | Description | | github_workflow_posture | GHWorkflowPosture.github_workflows | Posture management of github workflow yaml files for a repository version. | | model_scorecard | scorecard.score_card, scorefactor.score_factor_list | Scorecard for a model repository. | | package_version_scorecard | scorecard.score_card, scorefactor.score_factor_list | Scorecard for a package version. | | pkg_version_info_for_license | licenseInfoType.license_info | License information for a package version. | | pkg_version_stats_for_dependency | dependencyStatsType.dependency_stats | Dependency related statistics for a package version. | | pkg_version_stats_for_linter | linterStats.linter_stats | Linter related statistics for a package version. | | pkg_version_stats_for_secret | secretStats.secret_stats | Secret related statistics for a package version. | | pkg_version_stats_for_vuln | vulnerabilityStatsType.vulnerability_stats, publishedVulnerabilitiesStatsType.time_tracker | Vulnerability related statistics for a package version. | | repo_activity_for_commit | locationActivityTrackerType.time_tracker, locationActivityCountType.tag_counts | Commit activity for a repository. | | repo_activity_for_issue | locationActivityTrackerType.time_tracker, locationActivityCountType.tag_counts | Issue activity for a repository. | | repo_activity_for_pr | allActivityTrackerType.time_tracker, accountActivityTrackerType.time_tracker, locationActivityTrackerType.time_tracker, locationActivityCountType.tag_counts | PR activity for a repository. | | repo_scorecard | scorecard.score_card, scorefactor.score_factor_list | Scorecard for a repository. | | repo_scpm_data | ScpmDataType.scpm_data | RSPM data for a repository. | | repo_stats_for_dependency | dependencyStatsType.dependency_stats | Dependency related statistics for a repository version. | | repo_stats_for_file | fileStats.file_stats | File related statistics for a repository version. | | version_activity_for_commit | locationActivityTrackerType.time_tracker, locationActivityCountType.tag_counts | Commit activity of a repository version. | | version_activity_for_issue | locationActivityTrackerType.time_tracker, locationActivityCountType.tag_counts | Issue activity of a repository version. | | version_activity_for_pr | allActivityTrackerType.time_tracker, accountActivityTrackerType.time_tracker, locationActivityTrackerType.time_tracker, locationActivityCountType.tag_counts | PR activity of a repository version. | | version_cicd_tools | CiCdTools.ci_cd_tools | List of CI/CD Tools for a repository version. | | version_scorecard | scorecard.score_card, scorefactor.score_factor_list | Scorecard for a repository version. | | version_stats_for_dependency | dependencyStatsType.dependency_stats | Dependency related statistics for a repository version. | | version_stats_for_file | fileStats.file_stats | File related statistics for a repository version. | | version_stats_for_vuln | vulnerabilityStatsType.vulnerability_stats, publishedVulnerabilitiesStatsType.time_tracker | Vulnerability related statistics for a package version. |

Finding

  • Contains details of a problem that needs to be fixed.
  • Has a PackageVersion, RepositoryVersion, or Repository as the parent.
  • Belongs to the same Context as the parent.
  • Connected to the Project via spec.project_uuid.
  • There are many different types of Findings and new types can be created by custom Finding Policies.
  • The object name is the Finding type, for example: "outdated_release". For more information, see Finding names and metadata below.
  • The object description contains a more specific description of the Finding, for example: "Outdated Dependency @babel/plugin-syntax-async-generators@7.8.4".
  • Additional finding type specific data is stored in spec.finding_metadata, for example: spec.finding_metadata.vulnerability.
  • PackageVersion Findings often involve both the root PackageVersion and a dependency PackageVersion. The following details about the dependency PackageVersion are available directly in the Finding object:
    • spec.target_dependency_name, for example: "@babel/plugin-syntax-async-generators"
    • spec.target_dependency_package_name, for example: "npm://@babel/plugin-syntax-async-generators@7.8.4"
    • spec.target_dependency_version, for example: "7.8.4"
    • spec.finding_metadata.dependency_package_version_metadata
  • The UUID of the DependencyMetadata for the dependency is stored in spec.target_uuid.
  • There is one Finding object for every PackageVersion that includes a dependency with a given problem. If 10 PackageVersions include a dependency with a vulnerability then there will be 10 findings for the vulnerability.

For more information, see the FindingService REST API documentation.

Finding names and metadata

The following table lists all supported values for the Finding meta.name field along with an example value for the corresponding meta.description and an explanation.

Finding Name Example Description Explanation
archived_source_code_repo Unmaintained Dependency derive-error-chain@0.10.1 The source code repository for this package is archived. There is no additional metadata for this finding type.
bad_license License Risk in Dependency org.codehaus.plexus:plexus-io@2.0.3 The repository for this package is either missing a license or the license found is problematic. There is no additional metadata for this finding type.
dependency_with_critical_vulnerabilities GHSA-65fg-84f6-3jq3: SQL Injection in Log4j 1.2.x A critical severity known vulnerability has been assessed against this version of the software package according to the information in OSV.dev. Additional information about the vulnerability is stored in spec.finding_metadata.vulnerability.
dependency_with_high_severity_vulnerabilities GHSA-w9p3-5cr8-m3jj: Deserialization of Untrusted Data in Log4j 1.x This package version contains a vulnerability that has been marked as high severity according to the information in OSV.dev. Additional information about the vulnerability is stored in spec.finding_metadata.vulnerability.
dependency_with_low_activity_score Dependency tempdir@0.3.7 With Low Activity Score This package may be unmaintained, as determined by several factors contributing to a low activity score. Reliance on packages that are no longer maintained can make it costly or unreasonable to fix significant security risks, or quality issues. This may render the package obsolete over time. By relying on an unmaintained software package, organizations may assume the cost of maintenance and have a longer lead time for fixes on any security issues, if they are fixed at all. Additional information about the score is stored in spec.finding_metadata.dependency_score_card and spec.finding_metadata.dependency_score_factor_list.
dependency_with_low_popularity_score Dependency unicode-canonical-property-names-ecmascript@2.0.0 With Low Popularity Score Popularity is a social proxy for quality. Popular packages are more likely to remain maintained and thoroughly tested. Relying on lesser known packages for critical functions may increase operational risk. Additional information about the score is stored in spec.finding_metadata.dependency_score_card and spec.finding_metadata.dependency_score_factor_list.
dependency_with_low_quality_score Dependency org.slf4j:slf4j-api@1.7.6 With Low Quality Score This package may have an increased risk of bugs and quality issues as determined by several factors contributing to a low-quality score. A low quality score indicates a project may have an immature software development practice. Relying on packages that do not follow code development best practices can result in an increased risk of security and operational problems. Additional information about the score is stored in spec.finding_metadata.dependency_score_card and spec.finding_metadata.dependency_score_factor_list.
dependency_with_low_severity_vulnerabilities GHSA-5mg8-w23w-74h3: Information Disclosure in Guava This package version contains a vulnerability that has been marked as low severity according to the information in OSV.dev. Additional information about the vulnerability is stored in spec.finding_metadata.vulnerability.
dependency_with_malicious_package MAL-2023-462: Malicious code in fsevents (npm) This version of the software package is considered malware according to OSV.dev. Additional information about the malware advisory is stored in spec.finding_metadata.vulnerability.
dependency_with_medium_severity_vulnerabilities GHSA-269g-pwp5-87pp: TemporaryFolder on unix-like systems does not limit access to created files This package version contains a vulnerability that has been marked as medium severity according to the information in OSV.dev. Additional information about the vulnerability is stored in spec.finding_metadata.vulnerability.
dependency_with_multiple_low_scores Dependency esformatter-remove-trailing-commas@1.0.1 With Multiple Low Scores This package version has received low scores across more than one categories. This is stronger indication that the package may be problematic and presents an increased risk for security and operational problems. Additional information about the scores is stored in spec.finding_metadata.dependency_score_card and spec.finding_metadata.dependency_score_factor_list.
dependency_with_very_low_activity_score Dependency is-finite@1.1.0 With Very Low Activity Score This package is very likely to be unmaintained, as determined by several factors contributing to a very low activity score. Reliance on packages that are no longer maintained can make it costly or unreasonable to fix significant security risks, or quality issues. This may render the dependency obsolete over time. By relying on an unmaintained software package, organizations may assume the cost of maintenance and have a longer lead time for fixes on any security issues, if they are fixed at all. Additional information about the score is stored in spec.finding_metadata.dependency_score_card and spec.finding_metadata.dependency_score_factor_list.
dependency_with_very_low_popularity_score Dependency http-range-header@0.3.0 With Very Low Popularity Score Popularity is a social proxy for quality. Popular packages are more likely to remain maintained and thoroughly tested. Relying on lesser known packages for critical functions may increase operational risk. Additional information about the score is stored in spec.finding_metadata.dependency_score_card and spec.finding_metadata.dependency_score_factor_list.
dependency_with_very_low_quality_score Dependency org.apache.sis.core:sis-utility@1.1 With Very Low Quality Score This package is likely to have an increased risk of bugs and quality issues as determined by several factors contributing to a very low-quality score. A low quality score indicates a project may have an immature software development practice. Relying on packages that do not follow code development best practices can result in an increased risk of security and operational problems. Additional information about the score is stored in spec.finding_metadata.dependency_score_card and spec.finding_metadata.dependency_score_factor_list.
missing_source_code Missing Source Code Repository for Dependency commons-dbcp:commons-dbcp@1.4 The package versions source code reference is not currently available. As a result, automated analysis of the package’s activity, popularity, code quality and security have not been performed. Manual assessment is required to assess the operational and security risk of this package. There is no additional metadata for this finding type.
outdated_release Outdated Dependency @babel/plugin-syntax-async-generators@7.8.4 This package has had multiple later releases or a significant period of time has passed since the release of the version currently in use. Relying on outdated dependencies can result in missing important bug fixes or security patches and make upgrades more difficult. There is no additional metadata for this finding type.
policy_finding Code owner approval is not required The finding was created by a Rego policy. The policy UUID is stored in spec.finding_metadata.source_policy_info.uuid.
typosquatted_dependency Dependency serverles@3.27.1 is a Potential Typosquat The name of the dependency is very similar to another package which is more popular and widely used. It is possible that this is a malicious package in the package manager with malware inserted. Additional information about the typosquatted dependency is stored in spec.finding_metadata.typosquatted_dependency_version_metadata.
unpinned_direct_dependency Unpinned Direct Dependency num-integer@0.1.45 This package version has not pinned one of its direct dependencies. Dependencies that are not pinned to a specified version decrease the likelihood of build reproducibility and can be unexpectedly updated, which may introduce operational or security issues into your application. Unpinned dependencies expose organizations to the risk of software supply chain attacks where attackers compromise the upstream software dependency and publish a malicious version of the code. There is no additional metadata for this finding type.
unreachable_direct_dependency Unused Direct Dependency org.typelevel:macro-compat_2.11@1.1.1 Static analysis of this software package indicates that this direct dependency is unused. Unused direct dependencies unnecessarily increase the size of executables, application resource utilization and, increase build time and as a result may decrease developer productivity and application performance. There is no additional metadata for this finding type.

Finding categories

The following finding categories are supported as possible values in the spec.finding_categories list. All findings must have at least one category.

Finding Category UI Category Description
FINDING_CATEGORY_CICD CI/CD CI/CD pipeline findings
FINDING_CATEGORY_GHACTIONS GitHub Actions GitHub action findings
FINDING_CATEGORY_LICENSE_RISK License Risk License issues
FINDING_CATEGORY_MALWARE Malware Malware findings
FINDING_CATEGORY_OPERATIONAL Operational Operational issues
FINDING_CATEGORY_SCPM RSPM Repository security posture management issues
FINDING_CATEGORY_SECRETS Secrets Exposed secrets
FINDING_CATEGORY_SECURITY Security Security issues
FINDING_CATEGORY_SUPPLY_CHAIN Supply Chain Supply chain specific problems (malicious packages, typosquats)
FINDING_CATEGORY_TOOLS Tools Tool-related findings
FINDING_CATEGORY_VULNERABILITY Vulnerability Vulnerability findings

Finding tags

The following finding tags are supported as possible values in the spec.finding_tags list.

Finding Tag UI Attribute Description
FINDING_TAGS_CI_BLOCKER Blocker Finding was marked as blocking by one or more action policies. The policy uuids are stored in spec.actions.policy_uuids.
FINDING_TAGS_CI_WARNING Warning Finding triggered a warning based on one or more action policies. The policy uuids are stored in spec.actions.policy_uuids.
FINDING_TAGS_DIRECT Direct Finding applies to a direct dependency.
FINDING_TAGS_EXCEPTION Exception Finding was marked as exempt from action policies by one or more exception policies. The policy uuids are stored in spec.exceptions.policy_uuids.
FINDING_TAGS_FIX_AVAILABLE Fix Available There is a fix available for the CVE reported in this finding.
FINDING_TAGS_INVALID_SECRET Invalid Secret Finding applies to an invalid secret.
FINDING_TAGS_MALWARE Malware Finding applies to a malicious package.
FINDING_TAGS_NAMESPACE_INTERNAL First Party Finding applies to a dependency that belongs to the same namespace.
FINDING_TAGS_NORMAL Normal Finding applies to a normal, non-test, dependency.
FINDING_TAGS_NOTIFICATION Notification Finding triggered a notification based on one or more action policies. The policy uuids are stored in spec.actions.policy_uuids.
FINDING_TAGS_PATH_EXTERNAL External Path Only Finding applies to a transitive dependency that can only be reached through external, non-OSS, project paths.
FINDING_TAGS_PHANTOM Phantom Finding applies to a phantom dependency.
FINDING_TAGS_POLICY Policy Based Finding was generated by a Rego based finding policy. The policy UUID is stored in spec.finding_metadata.source_policy_info.uuid.
FINDING_TAGS_POTENTIALLY_REACHABLE_DEPENDENCY Potentially Reachable Dependency Finding applies to a potentially reachable dependency.
FINDING_TAGS_POTENTIALLY_REACHABLE_FUNCTION Potentially Reachable Function Finding applies to a potentially reachable function.
FINDING_TAGS_PROJECT_INTERNAL Same Repository Finding applies to a dependency that belongs to the same project.
FINDING_TAGS_REACHABLE_DEPENDENCY Reachable Dependency Finding applies to a reachable dependency.
FINDING_TAGS_REACHABLE_FUNCTION Reachable Function Finding applies to a reachable function.
FINDING_TAGS_SELF Self Finding applies only to the analyzed package version, there is no dependency involved.
FINDING_TAGS_TEST Test Finding applies to a dependency that is not in production code.
FINDING_TAGS_TRANSITIVE Transitive Finding applies to a transitive (indirect) dependency.
FINDING_TAGS_UNDER_REVIEW Under Review Finding applies to suspicious package under review.
FINDING_TAGS_UNFIXABLE Unfixable There is no fix available for the CVE reported in this finding.
FINDING_TAGS_UNREACHABLE_DEPENDENCY Unreachable Dependency Finding applies to an unreachable dependency.
FINDING_TAGS_UNREACHABLE_FUNCTION Unreachable Function Finding applies to an unreachable function.
FINDING_TAGS_VALID_SECRET Valid Secret Finding applies to a valid secret.

Exceptions

There are two ways that a finding can be exempt from triggering action policies (a.k.a. admission and notification policies).

  1. Dismiss finding

    Set the spec.dismiss field to true to exclude the specific finding from action policies. This value persists as long as the finding exists, which is as long as the parent object remains the same. If this is a PackageVersion finding and the root package version number changes, then a new PackageVersion object is created and it gets a new set of findings, so the value of dismiss does not persist.

  2. Add an exception policy

    Exception policies allow you to set any criteria you want to mark findings as exempt and can be applied across all projects, a sub-set of projects, or a specific project, within a tenant. Based on the criteria you set, the exception can persist across multiple package versions.

    Findings matched by one or more exception policies have the FINDING_TAGS_EXCEPTION tag and the corresponding policy object uuids are listed under spec.exceptions.policy_uuids.

Action policies

Findings matched by one or more action policies (a.k.a. admission and notification policies) contain the corresponding policy object uuids in spec.actions.policy_uuids. They also carry a tag corresponding to the specific action, for example, FINDING_TAGS_CI_WARNING, FINDING_TAGS_CI_BLOCKER, or FINDING_TAGS_NOTIFICATION.

ScanResult

  • Contains details of a scan such as:
    • Configuration
    • Host environment details
    • Runtime statistics
    • Findings
    • Policies triggered
    • Error logs
    • Exit code
    • Scan status
  • Has the Project as the parent.
  • Belongs to the same Context as the scan.

For more information, see the ScanResultService REST API documentation.

Scan status

The following scan statuses are supported:

Status Description
STATUS_SUCCESS Scan completed successfully.
STATUS_PARTIAL_SUCCESS Scan completed, but with critical warnings or errors. See spec.logs for more information.
STATUS_FAILURE Scan failed. See spec.exit_code and the exit code documentation for more information.
STATUS_RUNNING Scan is running.

3.3 - Filters

Learn how to use filters with the Endor Labs REST API.

Filters allow you to specify a subset of objects to be returned by a request, for example:

endorctl api list --resource Finding \
  --filter "meta.name==dependency_with_critical_vulnerabilities" \
  --count
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --data-urlencode "list_parameters.filter=meta.name==dependency_with_critical_vulnerabilities" \
  --data-urlencode "list_parameters.count=true" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?list_parameters.filter=meta.name==dependency_with_critical_vulnerabilities&list_parameters.count=true HTTP/1.1
Authorization: Bearer {{token}}

Keys

A filter key is used to specify the field of the object to match against using a dot-delimited path. For example, given an object:

{
  "uuid": "63ef202d090b62ecf3f6655b",
  "meta": {
    "name": "Example Object",
    "tags": ["dev"]
  },
  "spec": {
    "dependencies": [
      {
        "name": "mvn://org.slf4j:slf4j-api@2.0.0",
      },
      {
        "name": "mvn://ch.qos.logback:logback-access@1.3.0",
      }
    ],
    "version": {
      "ref": "v1.6.333",
      "timestamp": "2024-05-31TT21:04:55.799Z"
    }
  }
}
  • uuid specifies the root field with the value "63ef202d090b62ecf3f6655b"
  • meta.name specifies the nested field with the value "Example Object"
  • meta.tags specifies the nested list field containing the values ["dev"]
  • spec.dependencies.name specifies the nested fields within the list with the values: "mvn://org.slf4j:slf4j-api@2.0.0" and "mvn://ch.qos.logback:logback-access@1.3.0"
  • spec.version.ref specifies the nested field with the value "v1.6.333"

For more information, see Data model.

Operators

The following filter operators are supported:

Operator Description
== Matches objects where a specified field is equal to a specified value.
!= Matches objects where a specified field is NOT equal to a specified value.
< Matches objects where a specified field is less than a specified value.
<= Matches objects where a specified field is less than or equal to a specified value.
> Matches objects where a specified field is greater than a specified value.
>= Matches objects where a specified field is greater than or equal to a specified value.
contains Matches objects where a specified list contains one or more specified values.
in Matches objects where a specified field is equal to one ore more specified values.
matches Matches objects where a specified field matches a specified regex pattern.
exists Matches objects where a specified field in a json payload exists.

Contains

Use contains or not contains to filter on the content of a list field. Multiple values are treated as an OR operation, for example:

  • To get all findings for vulnerabilities that have a fix available OR are in a reachable function use:

    spec.finding_tags contains [FINDING_TAGS_FIX_AVAILABLE, FINDING_TAGS_REACHABLE_FUNCTION]

  • To get all findings for vulnerabilities that have a fix available AND are in a reachable function use:

    spec.finding_tags contains [FINDING_TAGS_FIX_AVAILABLE] and spec.finding_tags contains [FINDING_TAGS_REACHABLE_FUNCTION]

  • To get all projects that do not have the meta tags “sanity” or “test” use:

    meta.tags not contains [sanity, test]

In

Use in or not in to filter on the value of a field against one ore more given values. Multiple values are treated as an OR operation, for example:

  • To get all findings with a “Critical” or “High” severity level use:

    spec.finding_level in [FINDING_LEVEL_CRITICAL, FINDING_LEVEL_HIGH]

  • To get all findings that are not from the “Maven” or “npm” ecosystems use:

    spec.ecosystem not in [ECOSYSTEM_MAVEN, ECOSYSTEM_NPM]

Matches

Use matches to filter on a regex pattern. Due to the nature of regex evaluation, this is much slower than using for example == or !=. Also due to the nature of regex evaluation, not matches is not supported.

Exists

If a field does not exist then it can’t be equal to anything, so we use exists and not exists instead of != null or == null. This also covers {}, [], etc.

Values

A filter value is used in combination with the operator to match against the values at the specified field.

Use double quotes to escape string or regex values in a filter, for example:

  • uuid in ["64a3b8326dda5fb62bfcceea", "658323c91aa208f231cc7eff", "658323c963ca516ef02d1b02"]
  • meta.name matches "validation bypass"

NOTE: filters are case-sensitive by default.

To filter with case-insentive values a regex modifier may be used, for example:

  • meta.description matches "(?i)django"

Date/Time Values

Use date to encode date values in a filter, for example:

  • To filter for objects created after a given date, use a date value with the format YYYY-MM-DD:

    meta.update_time >= date(2024-05-01)

  • To filter for objects created between specific times, use a timestamp values with the RFC 3339 format:

    meta.create_time >= date(2024-05-01T13:30:00.000Z) and meta.create_time < date(2024-05-01T23:30:00.000Z)

Use now to encode relative date values in a filter by a given duration offset, for example:

  • To filter for objects created in the last 15 minutes, use:

    meta.create_time >= now(-12h)

  • To filter for objects created in the last 72 hours, use:

    meta.create_time >= now(-72h)

Combinations

Use and or or to combine multiple filters, for example:

  • spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY] and meta.create_time >= date(2024-05-31)
  • meta.name==archived_source_code_repo or meta.name==outdated_release

Nesting filters

Multiple filters may also be nested together into a single filter with the use of parentheses (), for example:

  • (spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY] and spec.level==FINDING_LEVEL_CRITICAL) or (spec.finding_categories contains [FINDING_CATEGORY_SECRETS] and spec.level in [FINDING_LEVEL_CRITICAL, FINDING_LEVEL_HIGH])

3.4 - Masks

Learn how to use field masks with the Endor Labs REST API.

Field masks allow you to specify a subset of fields to be returned for each object by a request. Similar to filter keys, a field-mask key is used to specify the field to return, using a dot-delimited path.

The following example shows how to get just the description and severity for all findings:

endorctl api list --resource Finding \
  --field-mask "meta.description,spec.level"
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings?list_parameters.mask=meta.description,spec.level"
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?list_parameters.mask=meta.description,spec.level HTTP/1.1
Authorization: Bearer {{token}}

jq

The Endor Labs REST API returns results in json format so it is often convenient to use the jq command-line json processor to parse or format the results.

The following example shows how to use jq to extract just the description value from the above request:

endorctl api list --resource Finding \
  --field-mask "meta.description,spec.level" \
  | jq '.list.objects[].meta.description'
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings?list_parameters.mask=meta.description,spec.level"
  | jq '.list.objects[].meta.description'

For more information, see the jq documentation.

3.5 - Pagination

Learn how to navigate through paginated responses from the Endor Labs REST API.

About Pagination

When a response from the REST API includes many results, Endor Labs paginates the results and returns a subset of the results. For example, GET /v1/namespaces/{tenant_meta.namespace}/findings only returns 100 findings from the given namespace even if the namespace has more than 100 findings. This makes the response easier to handle for servers and for people.

You can use the additional data from the list response to request additional pages of data.

This article explains how to request additional pages of results for paginated responses and how to change the number of results returned on each page.

Using page_size

The page_size field allows you to control the number of elements returned. By default, this value is 100, with a maximum of 500. It should be noted that the higher this value is, the longer it will take to get a result from Endor Labs.

endorctl api list --resource Finding \
  --page-size=50
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings?list_parameters.page_size=50"

Using page_token

When a response is paginated, the response includes a value for the field next_page_token. This value can then be used to fetch additional pages of results.

For example, the response to the above request contains the first 50 elements in the objects field along with the following values in the response field:

{
  "list": {
    "objects": [
        ...
    ],
    "response": {
      "next_page_id": "633dd86976186a89d64628c1",
      "next_page_token": 50
    }
  }
}

To access the next page of results, you can use the next_page_token value as the value of page_token in the next request. For example:

endorctl api list --resource Finding \
  --page-size=50 \
  --page-token=50
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings?list_parameters.page_size=50&list_parameters.page_token=50"

This returns 50 elements starting from the 50th element in the list. In this case, it returns elements 50 to 100.

Using page_id

The fields page_id and next_page_id provide the same capabilities as page_token and next_page_token. However, we recommend using page_id and next_page_id as they offer better performance for the request.

endorctl and the flag list-all

The CLI endorctl provides the flag --list-all that allows you to fetch all resources. Internally, the command sends multiple requests to get all resources.

endorctl api list --resource Finding --list-all

3.6 - Sorting

Learn how to sort results from the Endor Labs REST API.

Sort allows you to sort objects in ascending (default) or descending order. Similar to filter keys, a sort-path key is used to specify the field to sort the objects by, using a dot-delimited path.

The following example shows how to sort findings based on create time, in descending order:

endorctl api list --resource Finding \
  --sort-path "meta.create_time" \
  --sort-order descending
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings?list_parameters.sort.path=meta.create_time&list_parameters.sort.order=SORT_ENTRY_ORDER_DESC"
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?list_parameters.sort.path=meta.create_time7list_parameters.sort.order=SORT_ENTRY_ORDER_DESC HTTP/1.1
Authorization: Bearer {{token}}

Sort order

The following sort orders are supported:

Option Description
ascending Ascending order (default)
descending Descending order
Value Description
SORT_ENTRY_ORDER_ASC Ascending order (default)
SORT_ENTRY_ORDER_DESC Descending order

3.7 - Grouping

Learn how to group results from the Endor Labs REST API.

There are many scenarios where it is useful to group the objects returned by the Endor Labs REST API in different ways. Like filter keys, a group-aggregation-paths key is used to specify the field, or fields, by which to group the objects, using a dot-delimited path. For example, the following request returns the count of findings for each severity level:

endorctl api list --resource Finding \
  --filter "spec.finding_categories contains FINDING_CATEGORY_VULNERABILITY" \
  --group-aggregation-paths "spec.level" \
  --timeout 60s
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Request-Timeout: 60" \
  --data-urlencode "list_parameters.filter=spec.finding_categories contains FINDING_CATEGORY_VULNERABILITY" \
  --data-urlencode "list_parameters.group.aggregation_paths=spec.level" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings \
  | jq '.'
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?list_parameters.filter?list_parameters.filter=spec.finding_categories contains FINDING_CATEGORY_VULNERABILITY&list_parameters.group.aggregation_paths=spec.level HTTP/1.1
Content-type: application/json
Authorization: Bearer {{token}}
Request-Timeout: 60
{
  "group_response": {
    "groups": {
      "[{\"key\":\"spec.level\",\"value\":\"FINDING_LEVEL_CRITICAL\"}]": {
        "aggregation_count": {
          "count": 49
        }
      },
      "[{\"key\":\"spec.level\",\"value\":\"FINDING_LEVEL_HIGH\"}]": {
        "aggregation_count": {
          "count": 166
        }
      },
      "[{\"key\":\"spec.level\",\"value\":\"FINDING_LEVEL_LOW\"}]": {
        "aggregation_count": {
          "count": 31
        }
      },
      "[{\"key\":\"spec.level\",\"value\":\"FINDING_LEVEL_MEDIUM\"}]": {
        "aggregation_count": {
          "count": 202
        }
      }
    }
  }
}

Group by path

The following options are available to group objects based on the value of a field in a given path.

Option Description
group-aggregation-paths Specify one or more fields to group objects by.
group-show-aggregation-uuids Get the uuids of the objects in each group as specified by --group-aggregation-paths.
group-unique-count-paths Count the number of unique values, for these fields, in the group.
group-unique-value-paths Get the unique values, for these fields, in the group.

For the complete list of all endorctl api list options, see flags and variables.

List Parameter Description
group.aggregation_paths Specify one or more fields to group objects by.
group.show_aggregation_uuids Get the uuids of the objects in each group as specified by group.aggregation_paths.
group.unique_count_paths Count the number of unique values, for these fields, in the group.
group.unique_value_paths Get the unique values, for these fields, in the group.

For the complete list of all HTTP list parameters, see list parameters.

Group by path example

Here is an example using all options simultaneously to group package versions by call graph resolution error, list the uuids of the package versions in each group, return the number of different ecosystems of the package versions in each group, and list the different ecosystems of the package versions in each group:

endorctl api list --resource PackageVersion \
  --filter "spec.resolution_errors.call_graph exists" \
  --group-aggregation-paths "spec.resolution_errors.call_graph.status_error" \
  --group-show-aggregation-uuids \
  --group-unique-count-paths "spec.ecosystem" \
  --group-unique-value-paths "spec.ecosystem" \
  --timeout 60s
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Request-Timeout: 60" \
  --data-urlencode "list_parameters.filter=spec.resolution_errors.call_graph exists" \
  --data-urlencode "list_parameters.group.aggregation_paths=spec.resolution_errors.call_graph.status_error" \
  --data-urlencode "list_parameters.group.show_aggregation_uuids=true" \
  --data-urlencode "list_parameters.group.unique_value_paths=spec.ecosystem" \
  --data-urlencode "list_parameters.group.unique_count_paths=spec.ecosystem" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/package-versions \
  | jq '.'
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/package-versions?list_parameters.filter?list_parameters.filter=spec.resolution_errors.call_graph exists&list_parameters.group.aggregation_paths=spec.resolution_errors.call_graph.status_error&ist_parameters.group.show_aggregation_uuids=true&list_parameters.group.unique_value_paths=spec.ecosystem&list_parameters.group.unique_count_paths=spec.ecosystem HTTP/1.1
Content-type: application/json
Authorization: Bearer {{token}}
Request-Timeout: 60
{
  "group_response": {
    "groups": {
      "[{\"key\":\"spec.resolution_errors.call_graph.status_error\",\"value\":\"STATUS_ERROR_CALL_GRAPH\"}]": {
        "aggregation_count": {
          "count": 10
        },
        "aggregation_uuids": [
          "6494c13cdcb266d2af02804f",
          "64ace2dd05228d0041488208",
          "64ace2dc05228d00414881eb",
          "64af3a042efc155e48304bf2",
          "65b86b4a0f460309eac456b5",
          "64ace2dc832ee78dd03d85b0",
          "64c190aa17e6bfc2548f7a48",
          "64af39d2bebf530905411327",
          "64c190a817e6bfc2548f7a19",
          "64cc2b68727cd13ec36860c8"
        ],
        "unique_counts": {
          "spec.ecosystem": {
            "count": 2
          }
        },
        "unique_values": {
          "spec.ecosystem": [
            "ECOSYSTEM_MAVEN",
            "ECOSYSTEM_PYPI"
          ]
        }
      },
      "[{\"key\":\"spec.resolution_errors.call_graph.status_error\",\"value\":\"STATUS_ERROR_INTERNAL\"}]": {
        "aggregation_count": {
          "count": 2
        },
        "aggregation_uuids": [
          "6632e2d6b7765d736fac1865",
          "664ba7986fafc782b3cda1f6"
        ],
        "unique_counts": {
          "spec.ecosystem": {
            "count": 1
          }
        },
        "unique_values": {
          "spec.ecosystem": [
            "ECOSYSTEM_NPM"
          ]
        }
      },
      "[{\"key\":\"spec.resolution_errors.call_graph.status_error\",\"value\":\"STATUS_ERROR_MISSING_ARTIFACT\"}]": {
        "aggregation_count": {
          "count": 23
        },
        "aggregation_uuids": [
          "65c3e90ae2dd352a18b6f852",
          "64b99a3b3d5f8dc732555200",
          "64c190a921d68642091aa015",
          "650a2457204ab859367160a2",
          "650a245780113616f95f770e",
          "65d6840edb5cf8c9839c3d47",
          "65e8c21647aae08e2a4e5f5c",
          "64c190a921d68642091aa027",
          "64c190a958d2eff448df09e1",
          "650a2457204ab859367160a6",
          "64c190aa58d2eff448df09f0",
          "64af0879c41c606cbcef6288",
          "64c190ab17e6bfc2548f7a4d",
          "64c190aa17e6bfc2548f7a41",
          "64c190a958d2eff448df09ec",
          "64c190ab21d68642091aa033",
          "64c190ab58d2eff448df09f3",
          "64b99a3b6883c0ec1c456c3a",
          "64c190aa21d68642091aa02f",
          "64b99a3ce3b06b2f8a465bdc",
          "64c190a917e6bfc2548f7a35",
          "64b99a3b6883c0ec1c456c39",
          "650a24573e183ec1be29adc6"
        ],
        "unique_counts": {
          "spec.ecosystem": {
            "count": 1
          }
        },
        "unique_values": {
          "spec.ecosystem": [
            "ECOSYSTEM_MAVEN"
          ]
        }
      },
      "[{\"key\":\"spec.resolution_errors.call_graph.status_error\",\"value\":\"STATUS_ERROR_VENV\"}]": {
        "aggregation_count": {
          "count": 10
        },
        "aggregation_uuids": [
          "64c41863da2fbc7700d12a0e",
          "64c845aca83e181b82ef9041",
          "64dd4f61177264d779e203f3",
          "64c418647146e5738bf0af2d",
          "64c845ac41f581de1a6592d1",
          "64c845ac41f581de1a6592d0",
          "664be4bc6fafc782b363d8e3",
          "652e0bcb1d4d2ceedc87a376",
          "66311e48bf25e232ab24b68c",
          "64d6ce776e5804222a2726de"
        ],
        "unique_counts": {
          "spec.ecosystem": {
            "count": 1
          }
        },
        "unique_values": {
          "spec.ecosystem": [
            "ECOSYSTEM_PYPI"
          ]
        }
      }
    }
  }
}

Group by time

The Endor Labs REST API also provides options to group objects by a given time interval. Common time fields include meta.create_time and meta.update_time, but you can sort objects based on any time field.

For example, to group objects based on create time in 2 week intervals, set the aggregation path to meta.create_time, the time interval to GROUP_BY_TIME_INTERVAL_WEEK and the group size to 2.

The following options are available to group objects based on the value of a time field in a given path:

List Parameter Description
group_by_time.aggregation_paths Group the objects based on this time field.
group_by_time.interval The time interval to group the objects by.
group_by_time.group_size The time interval size to group the objects by.
group_by_time.start_time Beginning of the time period to group objects.
group_by_time.end_time End of the time period to group objects.
group_by_time.show_aggregation_uuids Get the uuids of the objects in each group.

For the complete list of all HTTP list parameters, see list parameters.

Time intervals

The following time intervals are supported:

Value Description
GROUP_BY_TIME_INTERVAL_YEAR Year
GROUP_BY_TIME_INTERVAL_QUARTER Quarter
GROUP_BY_TIME_INTERVAL_MONTH Month
GROUP_BY_TIME_INTERVAL_WEEK Week
GROUP_BY_TIME_INTERVAL_DAY Day
GROUP_BY_TIME_INTERVAL_HOUR Hour
GROUP_BY_TIME_INTERVAL_MINUTE Minute
GROUP_BY_TIME_INTERVAL_SECOND Second

Group by time example

The following example requests the uuids of all critical findings, grouped by create time in two week intervals:

curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Request-Timeout: 60" \
  --data-urlencode "list_parameters.filter=spec.level==FINDING_LEVEL_CRITICAL" \
  --data-urlencode "list_parameters.group_by_time.aggregation_paths=meta.create_time" \
  --data-urlencode "list_parameters.group_by_time.interval=GROUP_BY_TIME_INTERVAL_WEEK" \
  --data-urlencode "list_parameters.group_by_time.group_size=2" \
  --data-urlencode "list_parameters.group_by_time.show_aggregation_uuids=true" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings \
  | jq '.'
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?list_parameters.filter=spec.level==FINDING_LEVEL_CRITICAL&list_parameters.group_by_time.aggregation_paths=meta.create_time&list_parameters.group_by_time.interval=GROUP_BY_TIME_INTERVAL_WEEK&list_parameters.group_by_time.group_size=2&list_parameters.group_by_time.show_aggregation_uuids=true HTTP/1.1
Content-type: application/json
Authorization: Bearer {{token}}
Request-Timeout: 60
{
  "group_response": {
    "groups": {
      "\"2024-01-28T00:00:00Z\"": {
        "aggregation_count": {
          "count": 7
        },
        "aggregation_uuids": [
          "65c02da021a5d767fc147ec0",
          "65c02da021a5d767fc147ec3",
          "65c02da0aa4b66fa5009eaec",
          "65c02da0056f94b6129aa209",
          "65c02da021a5d767fc147eca",
          "65c02da1aa4b66fa5009eaf9",
          "65c02daa056f94b6129aa46f"
        ],
        "unique_counts": {},
        "unique_values": {}
      },
      "\"2024-03-10T00:00:00Z\"": {
        "aggregation_count": {
          "count": 2
        },
        "aggregation_uuids": [
          "65faf8ec357952c8eda2d36b",
          "65fcdcedd40334d9e0065748"
        ],
        "unique_counts": {},
        "unique_values": {}
      },
      "\"2024-03-24T00:00:00Z\"": {
        "aggregation_count": {
          "count": 2
        },
        "aggregation_uuids": [
          "660728d190fdb066027d07bb",
          "660728d8bddd7358d570ce9c"
        ],
        "unique_counts": {},
        "unique_values": {}
      },
      "\"2024-04-07T00:00:00Z\"": {
        "aggregation_count": {
          "count": 15
        },
        "aggregation_uuids": [
          "6615c531bb58b077e43cbb16",
          "6615c531e2a0c32733a7d50b",
          "6615c531e2a0c32733a7d514",
          "66216bb723ebef7ca3f4571a",
          "66216bb7c28c6f37b51cd0e8",
          "66216bb723ebef7ca3f4571d",
          "66216bc62c21fa9407eda175",
          "66216bc6c28c6f37b51cd2d4",
          "66216bc62c21fa9407eda17b",
          "66216bd72c21fa9407eda210",
          "66216bd823ebef7ca3f459a8",
          "66216bd823ebef7ca3f459ab",
          "66216bd8c28c6f37b51cd381",
          "66216be623ebef7ca3f45a8a",
          "66216be6c28c6f37b51cd465"
        ],
        "unique_counts": {},
        "unique_values": {}
      },
      "\"2024-04-21T00:00:00Z\"": {
        "aggregation_count": {
          "count": 1
        },
        "aggregation_uuids": [
          "66341d55f9aa19f4b730a74c"
        ],
        "unique_counts": {},
        "unique_values": {}
      },
      "\"2024-05-19T00:00:00Z\"": {
        "aggregation_count": {
          "count": 19
        },
        "aggregation_uuids": [
          "664be2cc6fafc782b35fdc89",
          "664be2cc6fafc782b35fdceb",
          "664be2d56fafc782b35ff0d8",
          "664be2d56fafc782b35ff0e0",
          "664be2d5f420988edd47792d",
          "664be2dd67636bf844aedcae",
          "664be2dd6fafc782b36000a8",
          "664be2dd6fafc782b36000aa",
          "664be2ddf420988edd4788eb",
          "664be2e867636bf844aef4e9",
          "664be2e8f420988edd47a140",
          "664be2e8f420988edd47a148",
          "6656ababd2d288f1981ea2ba",
          "6656ababce82b72012f10bbc",
          "6656ababce82b72012f10bbd",
          "6656abab252554c986334a6b",
          "6656ababd2d288f1981ea2bd",
          "6656abab252554c986334a6d",
          "6656abacce82b72012f10bbf"
        ],
        "unique_counts": {},
        "unique_values": {}
      },
      "\"2024-06-02T00:00:00Z\"": {
        "aggregation_count": {
          "count": 5
        },
        "aggregation_uuids": [
          "665fa482c980f9f8157e08c3",
          "6660a9f0e238ad93ad92089e",
          "6660a9f05728ef99cf0c8535",
          "6660a9f0b70974e544ccd05a",
          "6660a9f05728ef99cf0c853f"
        ],
        "unique_counts": {},
        "unique_values": {}
      }
    }
  }
}

3.8 - Best practices

Follow these best practices when using the Endor Labs REST API.

Using endorctl

Optimize queries

3.9 - Use cases

Examples of common use cases for interacting with the Endor Labs REST API.

Get list of projects

endorctl api list --resource Project
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/projects"
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/projects HTTP/1.1
Authorization: Bearer {{token}}

Get project UUID

The project UUID connects all the objects for a given project. One way to get the project UUID is to extract it from the uuid field in the Project object. For more information, see Resource kinds.

endorctl api get --resource Project --name <project-name> | jq '.uuid'
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/projects?list_parameters.filter=meta.name==<project-name>" \
  | jq '.list.objects[].uuid'
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/projects?list_parameters.filter=meta.name==<project-name> HTTP/1.1
Authorization: Bearer {{token}}

Get list of findings for a project

Use the following filter to get a list of findings for a given project:

spec.project_uuid==<project-uuid>

endorctl api list --resource Finding --filter "spec.project_uuid==<project-uuid>"
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=spec.project_uuid==<project-uuid>" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?list_parameters.filter=spec.project_uuid==<project-uuid> HTTP/1.1
Authorization: Bearer {{token}}

Get list of findings for reachable functions

Use the following filter to get a list of findings for reachable functions:

spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION

For a list of all finding attributes, see Finding tags.

endorctl api list --resource Finding \
  --filter "spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION"
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?list_parameters.filter=spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION HTTP/1.1
Authorization: Bearer {{token}}

Get list of findings for reachable functions for a project

Combine the previous filters to get a list of findings for reachable functions for a given project:

spec.project_uuid==<project-uuid> and spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION

endorctl api list --resource Finding \
  --filter "spec.project_uuid==<project-uuid> and spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION"
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=spec.project_uuid==<project-uuid> and spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?list_parameters.filter=spec.project_uuid==<project-uuid> and spec.finding_tags contains FINDING_TAGS_REACHABLE_FUNCTION HTTP/1.1
Authorization: Bearer {{token}}

Get list of findings in a category

Use the following filter to get a list of findings in the RSPM category:

spec.finding_categories contains FINDING_CATEGORY_SCPM

For a list of all finding categories, see Finding categories.

endorctl api list --resource Finding \
  --filter "spec.finding_categories contains FINDING_CATEGORY_SCPM"
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=spec.finding_categories contains FINDING_CATEGORY_SCPM" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/findings?list_parameters.filter=spec.finding_categories contains FINDING_CATEGORY_SCPM HTTP/1.1
Authorization: Bearer {{token}}

Get Endor Labs scores for an OSS package

  1. Set the namespace to "oss" as the data for OSS packages are stored in the OSS tenant.

  2. Endor Labs scores for package versions are stored in the "package_version_scorecard" Metric object, in the spec.metric_values.scorecard.score_card.category_scores field, so you need to get this Metric object for the given OSS package. For more information, see the Metric resource kind documentation.

  3. To get Metric objects belonging to a given package version, get the UUID of the corresponding PackageVersion object. The PackageVersion object name must be in the format <ecosystem>://<name>@<version>, for example: "mvn://ch.qos.logback:logback-core@1.3.3". For more information, see the PackageVersion resource kind documentation. Once you have the PackageVersion object, use the following jq command to extract the UUID:

    jq '.list.object[].uuid'

  4. Get the Metric object corresponding to the PackageVersion UUID using the following two filters:

    1. meta.name==package_version_scorecard
    2. meta.parent_uuid==<package-version-uuid>
  5. Use the following jq command to extract just the Endor Labs scores from the Metric object:

    jq '.list.objects[].spec.metric_values.scorecard.score_card.category_scores'

# Get the PackageVersion and extract the uuid
UUID=$(endorctl api list \
  --namespace oss \
  --resource PackageVersion \
  --filter "meta.name==mvn://ch.qos.logback:logback-core@1.3.3" \
  | jq '.list.objects[].uuid')

# Get the Metric and extract the Endor Labs scores
endorctl api list \
  --namespace oss \
  --resource Metric \
  --filter "meta.name==package_version_scorecard and meta.parent_uuid==$UUID" \
  | jq '.list.objects[].spec.metric_values.scorecard.score_card.category_scores'
# Get the PackageVersion and extract the uuid
UUID=$(curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=meta.name==mvn://ch.qos.logback:logback-core@1.3.3" \
  https://api.endorlabs.com/v1/namespaces/oss/package-versions \
  | jq '.list.objects[].uuid')

# Get the Metric and extract the Endor Labs scores
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=meta.name==package_version_scorecard and meta.parent_uuid==$UUID" \
  https://api.endorlabs.com/v1/namespaces/oss/metrics \
  | jq '.list.objects[].spec.metric_values.scorecard.score_card.category_scores'
@baseUrl = https://api.endorlabs.com
@token = <endor-token>

###
GET {{baseUrl}}/v1/namespaces/oss/package-versions?list_parameters.filter=meta.name==mvn://ch.qos.logback:logback-core@1.3.3 HTTP/1.1
Authorization: Bearer {{token}}

###
GET {{baseUrl}}/v1/namespaces/oss/metrics?list_parameters.filter=meta.name==package_version_scorecard and meta.parent_uuid==<package-version-uuid> HTTP/1.1
Authorization: Bearer {{token}}

Below is an example response to the request.

[
  {
    "category": "SCORE_CATEGORY_ACTIVITY",
    "centered_score": 6.956522,
    "description": "Captures the level of activity associated with the repository. Activity information is based on GitHub metadata. Higher levels of activity can mean that the repository is well maintained and will continue to be in the future.",
    "raw_score": 7.0212765,
    "score": 7
  },
  {
    "category": "SCORE_CATEGORY_POPULARITY",
    "centered_score": 8.076923,
    "description": "Captures how popular is the repository. Popularity information is based on GitHub metadata. Popular repositories are more likely to be maintained.",
    "raw_score": 7.368421,
    "score": 9
  },
  {
    "category": "SCORE_CATEGORY_CODE_QUALITY",
    "centered_score": 4.2105265,
    "description": "Provides a view of code quality and adherence to best practices in a repository. This information is based on from both GitHub metadata  and the source code in the repository.",
    "raw_score": 4.848485,
    "score": 4
  },
  {
    "category": "SCORE_CATEGORY_SECURITY",
    "centered_score": 4.7297297,
    "description": "Captures the level of compliance with security best practices as well as vulnerability information for the repository including currently open as well as fixed vulnerabilities.  Analysis only considers vulnerabilities associated with this repository and not its dependencies. Vulnerability information is based on OSV.dev data and Endor's vulnerability database",
    "raw_score": 8.333333,
    "score": 4
  }
]

Get license text from a license finding

  1. Look up a license-related Finding object for a dependency using the following filter:

    spec.finding_categories contains [FINDING_CATEGORY_LICENSE_RISK] and spec.finding_tags not contains [FINDING_TAGS_SELF]

  2. Get the name of the corresponding PackageVersion object from the spec.target_dependency_package_name field. If we have a list of Finding objects, we can use the following jq command to get the PackageVersion name:

    jq '.list.objects[].spec.target_dependency_package_name'

  3. Look up the PackageVersion object and store the UUID.

    Note: If this is an OSS dependency we must use the “oss” namespace.

  4. Look up the corresponding pkg_version_info_for_license Metric object using the following filter:

    meta.name==pkg_version_info_for_license&meta.parent_uuid==$UUID

    Note: The Metric is in the same namespace as the PackageVersion.

  5. Use the following jq command to extract the license text from the Metric object:

    jq '.list.objects[].spec.metric_values.licenseInfoType.license_info.all_licenses[].matched_text'

For more information, see the Metric resource kind documentation.

# Get the target dependency PackageVersion name from a license-related finding
NAME=$(endorctl api list --resource Finding \
  --filter "spec.finding_categories contains [FINDING_CATEGORY_LICENSE_RISK] and spec.finding_tags not contains [FINDING_TAGS_SELF]" \
  --page-size 1 \
  | jq '.list.objects[].spec.target_dependency_package_name')

# Get the target dependency PackageVersion uuid
UUID=$(endorctl api list --resource PackageVersion \
  --namespace oss \
  --filter "meta.name==$NAME" \
  | jq '.list.objects[].uuid')

# Get the corresponding pkg_version_info_for_license Metric and extract the license text
endorctl api list --resource Metric \
  --namespace "oss" \
  --filter "meta.name==pkg_version_info_for_license and meta.parent_uuid==$UUID" \
  | jq '.list.objects[].spec.metric_values.licenseInfoType.license_info.all_licenses[].matched_text'
# Get the target dependency PackageVersion name from a license-related finding
NAME=$(curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=spec.finding_categories contains [FINDING_CATEGORY_LICENSE_RISK] and spec.finding_tags not contains [FINDING_TAGS_SELF]" \
  --data-urlencode "list_parameters.page_size=1" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings \
  | jq '.list.objects[].spec.target_dependency_package_name')

# Get the target dependency PackageVersion uuid
UUID=$(curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=meta.name==$NAME" \
  https://api.endorlabs.com/v1/namespaces/oss/package-versions \
  | jq '.list.objects[].uuid')

# Get the corresponding pkg_version_info_for_license Metric and extract the license text
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=meta.name==pkg_version_info_for_license and meta.parent_uuid==$UUID" \
  https://api.endorlabs.com/v1/namespaces/oss/metrics \
  | jq '.list.objects[].spec.metric_values.licenseInfoType.license_info.all_licenses[].matched_text'

Get list of projects using a given tool

  1. CI/CD tool metrics are stored in the version_cicd_tools Metric object, in the spec.metric_values.CiCdTools.ci_cd_tools.tools list. Use the following filter to get all such Metrics with entries for the given tool name (GitHub Actions in this example). For more information, see the Metric resource kind documentation.

    meta.name==version_cicd_tools and spec.metric_values.CiCdTools.ci_cd_tools.tools.name=='GitHub Actions'

  2. Use the following jq command to get the uuids of the corresponding Project objects:

    .list.objects[].spec.project_uuid

  3. Remove duplicate Project uuids (a Project can have multiple repository versions).

  4. Use the uuids to get the corresponding Project objects.

# Get list of Project uuids
PROJECT_UUIDS=$(endorctl api list --resource Metric \
  --filter "meta.name==version_cicd_tools and spec.metric_values.CiCdTools.ci_cd_tools.tools.name=='GitHub Actions'" \
  | jq -r '.list.objects[].spec.project_uuid')

# Remove duplicate uuids
UNIQUE_UUIDS=$(echo $PROJECT_UUIDS | sort | uniq)

# Get Project for each uuid and extract the name
for uuid in $UNIQUE_UUIDS
do
  endorctl api get --resource Project --uuid $uuid | jq '.meta.name'
done
# Get list of Project uuids
PROJECT_UUIDS=$(curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --data-urlencode "list_parameters.filter=meta.name==version_cicd_tools and spec.metric_values.CiCdTools.ci_cd_tools.tools.name=='GitHub Actions'" \
  https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/metrics \
  | jq -r '.list.objects[].spec.project_uuid')

# Remove duplicate uuids
UNIQUE_UUIDS=$(echo $PROJECT_UUIDS | sort | uniq)

# Get Project for each uuid and extract the name
for uuid in $UNIQUE_UUIDS
do
  curl --get \
    --header "Authorization: Bearer $ENDOR_TOKEN" \
    --header "Accept-Encoding: gzip, deflate, br, zstd" \
    --url https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/projects/$uuid \
    | jq '.meta.name'
done

See also List Projects, with Repository Versions and CI/CD Tool Metrics for an example of how to use the Query Service to get the CI/CD tool Metric objects for a list of projects.

Get the latest scan result

  1. To get the latest object, first sort the objects in descending order, based on the meta.create_time field:

    list_parameters.sort.order=SORT_ENTRY_ORDER_DESC&list_parameters.sort.path=meta.create_time

  2. Then, to get only the latest object, set the page size to 1:

    list_parameters.page_size=1

endorctl api list --resource ScanResult \
  --sort-order descending \
  --sort-path meta.create_time \
  --page-size=1
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/scan-results?list_parameters.sort.order=SORT_ENTRY_ORDER_DESC&list_parameters.sort.path=meta.create_time&list_parameters.page_size=1"
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/scan-results?list_parameters.sort.order=SORT_ENTRY_ORDER_DESC&list_parameters.sort.path=meta.create_time&list_parameters.page_size=1 HTTP/1.1
Authorization: Bearer {{token}}

Create a policy

The following example uses the Create Policy endpoint to create a new policy.

endorctl api create --resource Policy \
  --data '{
    "meta": {
      "description": "Disable action policies for CVE-2020-7677",
      "kind": "Policy",
      "name": "Ignore CVE-2020-7677"
    },
    "propagate": true,
    "spec": {
      "exception": {
        "reason": "EXCEPTION_REASON_RISK_ACCEPTED"
      },
      "policy_type": "POLICY_TYPE_EXCEPTION",
      "query_statements": [
        "data.exceptions.match_finding"
      ],
      "resource_kinds": [
        "Finding"
      ],
      "rule": "package exceptions\n\nmatch_finding[result] {\n\tsome i\n  data.resources.Finding[i].spec.finding_metadata.vulnerability.spec.aliases[_] = \"CVE-2020-7677\"\n  result = { \"Endor\" : { \"Finding\" : data.resources.Finding[i].uuid } }\n}"
    },
    "tenant_meta": {
      "namespace": "$ENDOR_NAMESPACE"
    }
  }'

Note: See also endorctl api create interactive mode.

curl --request POST \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/policies" \
  --data '{
    "meta": {
      "description": "Disable action policies for CVE-2020-7677",
      "kind": "Policy",
      "name": "Ignore CVE-2020-7677"
    },
    "propagate": true,
    "spec": {
      "exception": {
        "reason": "EXCEPTION_REASON_RISK_ACCEPTED"
      },
      "policy_type": "POLICY_TYPE_EXCEPTION",
      "query_statements": [
        "data.exceptions.match_finding"
      ],
      "resource_kinds": [
        "Finding"
      ],
      "rule": "package exceptions\n\nmatch_finding[result] {\n\tsome i\n  data.resources.Finding[i].spec.finding_metadata.vulnerability.spec.aliases[_] = \"CVE-2020-7677\"\n  result = { \"Endor\" : { \"Finding\" : data.resources.Finding[i].uuid } }\n}"
    },
    "tenant_meta": {
      "namespace": "$ENDOR_NAMESPACE"
    }
  }' | jq '.'
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
POST {{baseUrl}}/v1/namespaces/{{namespace}}/policies HTTP/1.1
Authorization: Bearer {{token}}

{
    "meta": {
        "name": "Detect Apache-2.0 License",
        "description": "Raise findings for dependencies using the Apache-2.0 license"
    },
    "spec": {
        "policy_type": "POLICY_TYPE_USER_FINDING",
        "finding_level": "FINDING_LEVEL_CRITICAL",
        "finding": {
            "explanation": "One or more of the licenses associated with this package or package dependency violates organizational license policy.",
            "external_name": "License Compliance Violation",
            "level": "FINDING_LEVEL_CRITICAL",
            "remediation": "Please consult with legal for further instructions or to request an exception.",
            "summary": "Package uses the \"Apache-2.0\" license."
        },
        "query_statements": [
            "data.license.match_license"
        ],
        "resource_kinds": [
            "Metric",
            "PackageVersion"
        ],
        "rule": "package license\n\nmatch_license[result] {\n  some i\n  data.resources.Metric[i]\n  data.resources.Metric[i].meta.name == \"pkg_version_info_for_license\"\n  data.resources.Metric[i].meta.parent_kind == \"PackageVersion\"\n  lower(data.resources.Metric[i].spec.metric_values.licenseInfoType.license_info.all_licenses[_].name) == lower(\"Apache-2.0\")\n  data.resources.PackageVersion[_].uuid == data.resources.Metric[i].meta.parent_uuid\n\n  result = {\n    \"Endor\": {\n      \"PackageVersion\": data.resources.Metric[i].meta.parent_uuid,\n    }\n  }\n}"
    },
    "tenant_meta": {
      "namespace": "{{namespace}}"
    }
}

Update a policy to include a given project

The following example uses the Update Policy endpoint to apply a policy to a given project by updating the spec.project_selector tag list.

endorctl api update --resource Policy --uuid <policy-uuid> \
  --field-mask "spec.project_selector" \
  --data '{ "spec" : { "project_selector" : [ "$uuid=<project-uuid>" ] } }'

Note: See also endorctl api update interactive mode.

curl --request PATCH \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/policies" \
  --data '{
    "request" : {
      "update_mask": "spec.project_selector"
    },
    "object" : {
      "uuid" : "<policy-uuid>",
      "spec" : {
        "project_selector": [
          "$uuid=<project-uuid>"
        ]
      }
    }
  }' | jq '.'
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
PATCH {{baseUrl}}/v1/namespaces/{{namespace}}/policies HTTP/1.1
Authorization: Bearer {{token}}

{
    "request" : {
      "update_mask": "spec.project_selector"
    },
    "object" : {
      "uuid" : "<policy-uuid>",
      "spec" : {
        "project_selector": [
          "$uuid=<project-uuid>"
        ]
      }
    }
}

Update a policy to exclude a given project

The following example uses the Update Policy endpoint to exclude a given project from a policy by updating the spec.project_exceptions tag list.

endorctl api update --resource Policy --uuid <policy-uuid> \
  --field-mask "spec.project_exceptions" \
  --data '{ "spec" : { "project_exceptions" : [ "$uuid=<project-uuid>" ] } }'

Note: See also endorctl api update interactive mode.

curl --request PATCH \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/policies" \
  --data '{
    "request" : {
      "update_mask": "spec.project_exceptions"
    },
    "object" : {
      "uuid" : "<policy-uuid>",
      "spec" : {
        "project_exceptions": [
          "$uuid=<project-uuid>"
        ]
      }
    }
  }' | jq '.'
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
PATCH {{baseUrl}}/v1/namespaces/{{namespace}}/policies HTTP/1.1
Authorization: Bearer {{token}}

{
    "request" : {
      "update_mask": "spec.project_exceptions"
    },
    "object" : {
      "uuid" : "<policy-uuid>",
      "spec" : {
        "project_exceptions": [
          "$uuid=<project-uuid>"
        ]
      }
    }
}

Upgrade a policy to use the latest template version

The following example uses the Update Policy endpoint to upgrade a given policy to use the latest template version.

endorctl api update --resource Policy --uuid <policy-uuid> \
  --field-mask "spec.template_version" \
  --data '{ "spec" : { "template_uuid" : "<template-uuid>", "template_version" : "2.0.0" } }'
curl --request PATCH \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/policies" \
  --data '{
    "request" : {
      "update_mask": "spec.template_version"
    },
    "object" : {
      "uuid" : "<policy-uuid>",
      "spec" : {
        "template_uuid" : "<template-uuid>",
        "template_version" : "2.0.0"
      }
    }
  }' | jq '.'
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
PATCH {{baseUrl}}/v1/namespaces/{{namespace}}/policies HTTP/1.1
Authorization: Bearer {{token}}

{
    "request" : {
      "update_mask": "spec.template_version"
    },
    "object" : {
      "uuid" : "<policy-uuid>",
      "spec" : {
        "template_uuid" : "<template-uuid>",
        "template_version" : "2.0.0"
      }
    }
}

Delete a policy

The following example uses the Delete Policy endpoint to delete a policy.

endorctl api delete --resource Policy --uuid <policy-uuid>
curl --request DELETE \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/policies/<policy-uuid>"
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
DELETE {{baseUrl}}/v1/namespaces/{{namespace}}/policies/<policy-uuid> HTTP/1.1
Authorization: Bearer {{token}}

Add meta tags to an object

The following example uses the Update Finding endpoint to add custom tags to a finding by updating the meta.tags field.

endorctl api update --resource Finding --uuid <finding-uuid> \
  --field-mask "meta.tags" \
  --data '{ "meta" : { "tags" : [ "tag1", "tag2", "tag3" ] } }'

Note: See also endorctl api update interactive mode.

curl --request PATCH \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/findings" \
  --data '{
    "request" : {
      "update_mask": "meta.tags"
    },
    "object" : {
      "uuid" : "<finding-uuid>",
      "meta" : {
        "tags": [
          "tag1",
          "tag2",
          "tag3"
        ]
      }
    }
  }' | jq '.'
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
PATCH {{baseUrl}}/v1/namespaces/{{namespace}}/findings HTTP/1.1
Authorization: Bearer {{token}}

{
    "request" : {
      "update_mask": "meta.tags"
    },
    "object" : {
      "uuid" : "<finding-uuid>",
      "meta" : {
        "tags": [
          "tag1",
          "tag2",
          "tag3"
        ]
      }
    }
}

Get data from child namespaces

Use the traverse option to include data from child namespaces as well as the parent namespace.

endorctl api list --resource Project --traverse
curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --header "Accept-Encoding: gzip, deflate, br, zstd" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/projects?list_parameters.traverse=true"
@baseUrl = https://api.endorlabs.com
@token = <endor-token>
@namespace = <endor-namespace>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/projects?list_parameters.traverse=true HTTP/1.1
Authorization: Bearer {{token}}

3.10 - Advanced use cases

Examples of advanced use cases when interacting with the Endor Labs REST API.

3.10.1 - Using the query service

Learn how to use the Query Service for advanced use cases with the Endor Labs REST API.

In addition to REST API endpoints for individual Resource Kinds, the Endor Labs REST API exposes a generic graph API capability through the Query Service endpoint. This Query Service may be used to retrieve resources and their related resources in a single call.

Requests for resources through the Query Service are sent with a Query that specifies a Resource Kind and optional list parameters to control the data returned from the request for that resource. The Query may also specify nested references, connecting related Resource Kinds, and returning all corresponding data in the response.

List Projects, with Package Version counts

The following Query returns the number of package versions in the default branch of each project.

  1. Request a list of Projects, but only return the uuid, meta.name and processing_status fields for each Project.
  2. Connect the Project uuid to the corresponding child PackageVersion spec.project_uuid field.
  3. Set additional parameters to filter to only resources from the Project’s default branch, and to return the count of resources.©
endorctl api create --resource Query \
  --data '{
    "meta": {
      "name": "Projects with Package Version Counts"
    },
    "spec": {
      "query_spec": {
        "kind": "Project",
        "list_parameters": {
          "mask": "uuid,meta.name,processing_status"
        },
        "references": [
          {
            "connect_from": "uuid",
            "connect_to": "spec.project_uuid",
            "query_spec": {
              "kind": "PackageVersion",
              "list_parameters": {
                "filter": "context.type==CONTEXT_TYPE_MAIN",
                "count": true
              }
            }
          }
        ]
      }
    }
  }'
query_data=$(cat << EOF
{
  "meta": {
    "name": "Projects with Package Version Counts"
  },
  "spec": {
    "query_spec": {
      "kind": "Project",
      "list_parameters": {
        "mask": "uuid,meta.name,processing_status"
      },
      "references": [
        {
          "connect_from": "uuid",
          "connect_to": "spec.project_uuid",
          "query_spec": {
            "kind": "PackageVersion",
            "list_parameters": {
              "filter": "context.type==CONTEXT_TYPE_MAIN",
              "count": true
            }
          }
        }
      ]
    }
  },
  "tenant_meta": {
    "namespace": "$ENDOR_NAMESPACE"
  }
}
EOF
)

curl "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/queries" \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --request POST \
  --data "$query_data"
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
POST {{baseUrl}}/v1/namespaces/{{namespace}}/queries HTTP/1.1
Authorization: Bearer {{token}}

{
  "meta": {
    "name": "Projects with Package Version Counts"
  },
  "spec": {
    "query_spec": {
      "kind": "Project",
      "list_parameters": {
        "mask": "uuid,meta.name,processing_status"
      },
      "references": [
        {
          "connect_from": "uuid",
          "connect_to": "spec.project_uuid",
          "query_spec": {
            "kind": "PackageVersion",
            "list_parameters": {
              "filter": "context.type==CONTEXT_TYPE_MAIN",
              "count": true
            }
          }
        }
      ]
    }
  },
  "tenant_meta": {
    "namespace": "{{namespace}}"
  }
}

The response for the example above includes the query request that was sent, along with the list response data added under the spec.query_response field.

For each Project in the list response, response data for each reference is added under the meta.references field.

{
  "meta": {
    "name": "Projects with Package Version Counts"
  },
  "spec": {
    "query_spec": {
      "kind": "Project",
      "list_parameters": {
        "mask": "uuid,meta.name,processing_status"
      }
    },
    "query_response": {
      "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListProjectsResponse",
      "list": {
        "objects": [
          {
            "meta": {
              "name": "https://github.com/example/app.git",
              "references": {
                "PackageVersion": {
                  "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListPackageVersionsResponse",
                  "count_response": {
                    "count": 12
                  }
                }
              }
            },
            "processing_status": {
              "analytic_time": "2023-10-28T03:41:40.824366382Z",
              "disable_automated_scan": false,
              "scan_state": "SCAN_STATE_IDLE",
              "scan_time": "2024-06-03T17:43:33.994191285Z"
            },
            "uuid": "633cbce48c4eb448a44d717b"
          },
          {
            "meta": {
              "name": "https://github.com/example/go-uuid.git",
              "references": {
                "PackageVersion": {
                  "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListPackageVersionsResponse",
                  "count_response": {
                    "count": 8
                  }
                }
              }
            },
            "processing_status": {
              "analytic_time": "2023-06-21T02:06:43.081498151Z",
              "disable_automated_scan": false,
              "scan_state": "SCAN_STATE_IDLE",
              "scan_time": "2024-06-03T17:43:47.098976874Z"
            },
            "uuid": "633cbce48c4eb448a44d717e"
          },
          {
            "meta": {
              "name": "https://github.com/example/go-lru.git",
              "references": {
                "PackageVersion": {
                  "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListPackageVersionsResponse",
                  "count_response": {
                    "count": 28
                  }
                }
              }
            },
            "processing_status": {
              "analytic_time": "2023-06-21T02:08:44.727640782Z",
              "disable_automated_scan": false,
              "scan_state": "SCAN_STATE_IDLE",
              "scan_time": "2024-06-03T17:43:52.028934453Z"
            },
            "uuid": "633cbce48c4eb448a44d7181"
          }
        ],
        "response": {
          "next_page_token": null
        }
      }
    }
  }
}

List Projects, with Repository Versions and CI/CD Tool Metrics

The following Query requests a list of Projects, with a reference for the related RepositoryVersion resources for the default branch, and the corresponding CI/CD tool Metric resources.

  1. Request a list of Projects, but only return the uuid and meta.name fields for each Project.
  2. Connect the Project uuid to the corresponding child RepositoryVersion meta.parent_uuid field.
  3. Set additional parameters to filter to only resources from the Project’s default branch, and an additional nested reference for Metric objects related to the RepositoryVersions, with a filter to return only Metrics for the CI/CD tools.
endorctl api create --resource Query \
  --data '{
    "meta": {
      "name": "Projects with RepositoryVersions and CI/CD Tool Metrics"
    },
    "spec": {
      "query_spec": {
        "kind": "Project",
        "list_parameters": {
          "mask": "uuid,meta.name"
        },
        "references": [
          {
            "connect_from": "uuid",
            "connect_to": "meta.parent_uuid",
            "query_spec": {
              "kind": "RepositoryVersion",
              "list_parameters": {
                "filter": "context.type==CONTEXT_TYPE_MAIN",
                "mask": "uuid,meta.name,scan_object"
              },
              "references": [
                {
                  "connect_from": "uuid",
                  "connect_to": "meta.parent_uuid",
                  "query_spec": {
                    "kind": "Metric",
                    "list_parameters": {
                      "filter": "spec.analytic==\"version_cicd_tools\""
                    }
                  }
                }
              ]
            }
          }
        ]
      }
    }
  }'
query_data=$(cat << EOF
{
  "meta": {
    "name": "Projects with RepositoryVersions and CI/CD Tool Metrics"
  },
  "spec": {
    "query_spec": {
      "kind": "Project",
      "list_parameters": {
        "mask": "uuid,meta.name"
      },
      "references": [
        {
          "connect_from": "uuid",
          "connect_to": "meta.parent_uuid",
          "query_spec": {
            "kind": "RepositoryVersion",
            "list_parameters": {
              "filter": "context.type==CONTEXT_TYPE_MAIN",
              "mask": "uuid,meta.name,scan_object"
            },
            "references": [
              {
                "connect_from": "uuid",
                "connect_to": "meta.parent_uuid",
                "query_spec": {
                  "kind": "Metric",
                  "list_parameters": {
                    "filter": "spec.analytic==\"version_cicd_tools\""
                  }
                }
              }
            ]
          }
        }
      ]
    }
  },
  "tenant_meta": {
    "namespace": "$ENDOR_NAMESPACE"
  }
}
EOF
)

curl "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/queries" \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --request POST \
  --data "$query_data"
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
POST {{baseUrl}}/v1/namespaces/{{namespace}}/queries HTTP/1.1
Authorization: Bearer {{token}}

{
  "meta": {
    "name": "Projects with RepositoryVersions and CI/CD Tool Metrics"
  },
  "spec": {
    "query_spec": {
      "kind": "Project",
      "list_parameters": {
        "mask": "uuid,meta.name"
      },
      "references": [
        {
          "connect_from": "uuid",
          "connect_to": "meta.parent_uuid",
          "query_spec": {
            "kind": "RepositoryVersion",
            "list_parameters": {
              "filter": "context.type==CONTEXT_TYPE_MAIN",
              "mask": "uuid,meta.name,scan_object"
            },
            "references": [
              {
                "connect_from": "uuid",
                "connect_to": "meta.parent_uuid",
                "query_spec": {
                  "kind": "Metric",
                  "list_parameters": {
                    "filter": "spec.analytic==\"version_cicd_tools\""
                  }
                }
              }
            ]
          }
        }
      ]
    }
  },
  "tenant_meta": {
    "namespace": "{{namespace}}"
  }
}

The response for the example above includes then related RepositoryVersions and Metrics as nested references under their parent resources.

{
  "meta": {
    "name": "Projects with RepositoryVersions and CI/CD Tool Metrics"
  },
  "spec": {
    "query_response": {
      "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListProjectsResponse",
      "list": {
        "objects": [
          {
            "meta": {
              "name": "https://github.com/OWASP-Benchmark/BenchmarkJava.git",
              "references": {
                "RepositoryVersion": {
                  "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListRepositoryVersionsResponse",
                  "list": {
                    "objects": [
                      {
                        "meta": {
                          "name": "master",
                          "references": {
                            "Metric": {
                              "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListMetricsResponse",
                              "list": {
                                "objects": [
                                  {
                                    "spec": {
                                      "analytic": "version_cicd_tools",
                                      "metric_values": {
                                        "CiCdTools": {
                                          "category": "CiCdTools",
                                          "ci_cd_tools": {
                                            "tools": [
                                              // additional content from response not shown here
                                            ]
                                          }
                                        }
                                      }
                                    },
                                    "uuid": "65b0287557d245d7a840220d"
                                  }
                                ],
                                "response": {}
                              }
                            }
                          }
                        },
                        "scan_object": {
                          "scan_time": "2024-04-15T02:17:56.541640347Z",
                          "status": "STATUS_SCANNED"
                        },
                        "uuid": "65b02837f82e0aeecbf468df"
                      }
                    ],
                    "response": {}
                  }
                }
              }
            },
            "uuid": "65b028374ab228de2903786e"
          }
        ],
        "response": {}
      }
    },

    // additional content from response not shown here
}

The following Query example requests the Projects matching the given filter, with multiple references specified for the counts of related Finding resources for the default branch.

Note: when using multiple references of the same Resource Kind, the field return_as is provided as the key to be used in the references of the response.

endorctl api create --resource Query \
  --data '{
    "meta": {
      "name": "Project with Finding counts by category"
    },
    "spec": {
      "query_spec": {
        "kind": "Project",
        "list_parameters": {
          "filter": "meta.name matches \"acme-monorepo\"",
          "mask": "uuid,meta.name"
        },
        "references": [
          {
            "connect_from": "uuid",
            "connect_to": "spec.project_uuid",
            "query_spec": {
              "return_as": "VulnerabilityFindingsCount",
              "kind": "Finding",
              "list_parameters": {
                "count": true,
                "filter": "context.type==CONTEXT_TYPE_MAIN and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY]"
              }
            }
          },
          {
            "connect_from": "uuid",
            "connect_to": "spec.project_uuid",
            "query_spec": {
              "return_as": "SecretsFindingsCount",
              "kind": "Finding",
              "list_parameters": {
                "count": true,
                "filter": "context.type==CONTEXT_TYPE_MAIN and spec.finding_categories contains [FINDING_CATEGORY_SECRETS]"
              }
            }
          },
          {
            "connect_from": "uuid",
            "connect_to": "spec.project_uuid",
            "query_spec": {
              "return_as": "MalwareFindingsCount",
              "kind": "Finding",
              "list_parameters": {
                "count": true,
                "filter": "context.type==CONTEXT_TYPE_MAIN and spec.finding_categories contains [FINDING_CATEGORY_MALWARE]"
              }
            }
          }
        ]
      }
    }
  }'
query_data=$(cat << EOF
{
  "meta": {
    "name": "Project with Finding counts by category"
  },
  "spec": {
    "query_spec": {
      "kind": "Project",
      "list_parameters": {
        "filter": "meta.name matches \"acme-monorepo\"",
        "mask": "uuid,meta.name"
      },
      "references": [
        {
          "connect_from": "uuid",
          "connect_to": "spec.project_uuid",
          "query_spec": {
            "return_as": "VulnerabilityFindingsCount",
            "kind": "Finding",
            "list_parameters": {
              "count": true,
              "filter": "context.type==CONTEXT_TYPE_MAIN and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY]"
            }
          }
        },
        {
          "connect_from": "uuid",
          "connect_to": "spec.project_uuid",
          "query_spec": {
            "return_as": "SecretsFindingsCount",
            "kind": "Finding",
            "list_parameters": {
              "count": true,
              "filter": "context.type==CONTEXT_TYPE_MAIN and spec.finding_categories contains [FINDING_CATEGORY_SECRETS]"
            }
          }
        },
        {
          "connect_from": "uuid",
          "connect_to": "spec.project_uuid",
          "query_spec": {
            "return_as": "MalwareFindingsCount",
            "kind": "Finding",
            "list_parameters": {
              "count": true,
              "filter": "context.type==CONTEXT_TYPE_MAIN and spec.finding_categories contains [FINDING_CATEGORY_MALWARE]"
            }
          }
        }
      ]
    }
  },
  "tenant_meta": {
    "namespace": "$ENDOR_NAMESPACE"
  }
}
EOF
)

curl "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/queries" \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --request POST \
  --data "$query_data"
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
POST {{baseUrl}}/v1/namespaces/{{namespace}}/queries HTTP/1.1
Authorization: Bearer {{token}}

{
  "meta": {
    "name": "Project with Finding counts by category"
  },
  "spec": {
    "query_spec": {
      "kind": "Project",
      "list_parameters": {
        "filter": "meta.name matches \"acme-monorepo\"",
        "mask": "uuid,meta.name"
      },
      "references": [
        {
          "connect_from": "uuid",
          "connect_to": "spec.project_uuid",
          "query_spec": {
            "return_as": "VulnerabilityFindingsCount",
            "kind": "Finding",
            "list_parameters": {
              "count": true,
              "filter": "context.type==CONTEXT_TYPE_MAIN and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY]"
            }
          }
        },
        {
          "connect_from": "uuid",
          "connect_to": "spec.project_uuid",
          "query_spec": {
            "return_as": "SecretsFindingsCount",
            "kind": "Finding",
            "list_parameters": {
              "count": true,
              "filter": "context.type==CONTEXT_TYPE_MAIN and spec.finding_categories contains [FINDING_CATEGORY_SECRETS]"
            }
          }
        },
        {
          "connect_from": "uuid",
          "connect_to": "spec.project_uuid",
          "query_spec": {
            "return_as": "MalwareFindingsCount",
            "kind": "Finding",
            "list_parameters": {
              "count": true,
              "filter": "context.type==CONTEXT_TYPE_MAIN and spec.finding_categories contains [FINDING_CATEGORY_MALWARE]"
            }
          }
        }
      ]
    }
  },
  "tenant_meta": {
    "namespace": "{{namespace}}"
  }
}

The response for the above example includes the Finding counts as references on the Project list response, using the values provided with return_as for the reference keys.

{
  "meta": {
    "name": "Project with Finding counts by category"
  },
  "spec": {
    "query_response": {
      "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListProjectsResponse",
      "list": {
        "objects": [
          {
            "meta": {
              "name": "https://github.com/example/acme-monorepo.git",
              "references": {
                "MalwareFindingsCount": {
                  "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListFindingsResponse",
                  "count_response": {
                    "count": 1
                  }
                },
                "SecretsFindingsCount": {
                  "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListFindingsResponse",
                  "count_response": {
                    "count": 8
                  }
                },
                "VulnerabilityFindingsCount": {
                  "@type": "type.googleapis.com/internal.endor.ai.endor.v1.ListFindingsResponse",
                  "count_response": {
                    "count": 74
                  }
                }
              }
            },
            "uuid": "65bbde52d70a7f64c70de4d6"
          }
        ],
        "response": {}
      }
    },

    // additional content from response not shown here
}

3.10.2 - Using saved queries

Learn how to use saved queries for interacting with the Endor Labs REST API.

The Endor Labs REST API provides the Query Service for flexible requests for resources. The Endor Labs REST API also provides the ability to save and manage queries for your own use cases through the Saved Query Service.

See Using the Query Service for examples on using the Query Service to specify and request resources from the Endor Labs REST API.

Creating a saved query

To create a saved query, a Query object specifying the request is embedded in a SavedQuery object.

saved_query_data=$(cat << EOF
{
  "meta": {
    "name": "Saved Query for Recent Vulnerabilities"
  },
  "spec": {
    "query": {
      "meta": {
        "name": "Query for Recent Vulnerabilities"
      },
      "spec": {
        "query_spec": {
          "kind": "Finding",
          "list_parameters": {
            "filter": "meta.create_time > now(-24h) and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY]",
            "mask": "uuid,meta.create_time,meta.update_time,meta.description,spec.level"
          }
        }
      },
      "tenant_meta": {
        "namespace": "$ENDOR_NAMESPACE"
      }
    }
  }
}
EOF
)

endorctl api create --resource SavedQuery \
  --data "$saved_query_data"
saved_query_data=$(cat << EOF
{
  "meta": {
    "name": "Saved Query for Recent Vulnerabilities"
  },
  "spec": {
    "query": {
      "meta": {
        "name": "Query for Recent Vulnerabilities"
      },
      "spec": {
        "query_spec": {
          "kind": "Finding",
          "list_parameters": {
            "filter": "meta.create_time > now(-24h) and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY]",
            "mask": "uuid,meta.create_time,meta.update_time,meta.description,spec.level"
          }
        }
      },
      "tenant_meta": {
        "namespace": "$ENDOR_NAMESPACE"
      }
    }
  },
  "tenant_meta": {
    "namespace": "$ENDOR_NAMESPACE"
  }
}
EOF
)

curl "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/saved-queries" \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --request POST \
  --data "$saved_query_data"
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>

###
POST {{baseUrl}}/v1/namespaces/{{namespace}}/saved-queries HTTP/1.1
Authorization: Bearer {{token}}

{
  "meta": {
    "name": "Saved Query for Recent Vulnerabilities"
  },
  "spec": {
    "query": {
      "meta": {
        "name": "Query for Recent Vulnerabilities"
      },
      "spec": {
        "query_spec": {
          "kind": "Finding",
          "list_parameters": {
            "filter": "meta.create_time > now(-24h) and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY]",
            "mask": "uuid,meta.create_time,meta.update_time,meta.description,spec.level"
          }
        }
      },
      "tenant_meta": {
        "namespace": "{{namespace}}"
      }
    }
  },
  "tenant_meta": {
    "namespace": "{{namespace}}"
  }
}

Updating a saved query

The following example updates the Query specified in the SavedQuery to add additional list parameters.

saved_query_uuid="<insert-uuid>"
saved_query_data=$(cat << EOF
{
  "spec": {
    "query": {
      "spec": {
        "query_spec": {
          "kind": "Finding",
          "list_parameters": {
            "filter": "meta.create_time > now(-24h) and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY]",
            "mask": "uuid,meta.create_time,meta.update_time,meta.description,spec.level",
            "page_size": 10,
            "sort": {
              "order": "SORT_ENTRY_ORDER_DESC",
              "path": "meta.create_time"
            }
          }
        }
      }
    }
  }
}
EOF
)

endorctl api update --resource SavedQuery \
  --uuid "$saved_query_uuid" \
  --field-mask "spec.query.spec.query_spec" \
  --data "$saved_query_data"
saved_query_uuid="<insert-uuid>"
saved_query_data=$(cat << EOF
{
  "request": {
    "update_mask": "spec.query.spec.query_spec"
  },
  "object": {
    "uuid": "$saved_query_uuid",
    "spec": {
      "query": {
        "spec": {
          "query_spec": {
            "kind": "Finding",
            "list_parameters": {
              "filter": "meta.create_time > now(-24h) and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY]",
              "mask": "uuid,meta.create_time,meta.update_time,meta.description,spec.level",
              "page_size": 10,
              "sort": {
                "order": "SORT_ENTRY_ORDER_DESC",
                "path": "meta.create_time"
              }
            }
          }
        }
      }
    }
  }
}
EOF
)

curl "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/saved-queries" \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --request PATCH \
  --data "$saved_query_data"
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>
@uuid = <insert-uuid>

###
PATCH {{baseUrl}}/v1/namespaces/{{namespace}}/saved-queries HTTP/1.1
Authorization: Bearer {{token}}

{
  "request": {
    "update_mask": "spec.query.spec.query_spec"
  },
  "object": {
    "uuid": "{{uuid}}",
    "spec": {
      "query": {
        "spec": {
          "query_spec": {
            "kind": "Finding",
            "list_parameters": {
              "filter": "meta.create_time > now(-24h) and spec.finding_categories contains [FINDING_CATEGORY_VULNERABILITY]",
              "mask": "uuid,meta.create_time,meta.update_time,meta.description,spec.level",
              "page_size": 10,
              "sort": {
                "order": "SORT_ENTRY_ORDER_DESC",
                "path": "meta.create_time"
              }
            }
          }
        }
      }
    }
  }
}

See also interactive mode for managing updates to a SavedQuery with endorctl api update:

endorctl api update --interactive --resource SavedQuery \
  --name "Saved Query for Recent Vulnerabilities"

Evaluating saved queries

After a Saved Query has been created, the request specified by the Query in the SavedQuery may be evaluated on demand.

endorctl api get --resource SavedQuery --uuid <insert-uuid>
base_url="https://api.endorlabs.com"
uuid="<insert-uuid>"

curl "$base_url/v1/namespaces/$ENDOR_NAMESPACE/saved-queries/$uuid/evaluate" \
  --header "Authorization: Bearer $ENDOR_TOKEN"
@baseUrl = https://api.endorlabs.com
@token = <insert-access-token>
@namespace = <insert-namespace>
@uuid = <insert-uuid>

###
GET {{baseUrl}}/v1/namespaces/{{namespace}}/saved-queries/{{uuid}}/evaluate HTTP/1.1
Authorization: Bearer {{token}}

The resulting data from evaluating the saved query will be returned in the response in a nested field under the Query specification. The jq command may be used to extract the nested data.

For the example queries given above, the following command will evaluate the given saved query, and extract the list of Finding objects from the Query response:

endorctl api get --resource SavedQuery --uuid <insert-uuid> \
  | jq '.spec.query.spec.query_response.list.objects[]'

3.11 - Postman

Learn how to use Endor Labs REST API with Postman

Download Postman

Download Postman from here. You can also use Postman on the web.

Download the Endor Labs OpenAPI json

Go to Endor Labs API Reference and click the download button to download the Endor Labs OpenAPI json file, openapi.json.

Import Endor Labs API json file in Postman

  1. Open the Postman application.
  2. Click Import and select the downloaded openapi.json file.
  3. Select OpenAPI 3.0 with Postman Collection and click Import.

Endor REST API collection is added to your workspace. It may take a couple of minutes to load the entire collection because of the size.

Configure Endor REST API collection

To use the Endor Labs APIs effectively with Postman you need to set the appropriate variables and configure authentication.

Before you proceed further, get your API Key and API Secret from the Endor Labs UI or endorctl. See REST API authentication for more information.

Endor Labs APIs require a bearer token, which is obtained from the CreateAPIReq endpoint. You need to add a pre-request script to obtain this token in the collection. The pre-request script runs when you initiate an API request and fetches the bearer token to be used in your API request.

The pre-request script also adds the following headers to the request:

  • 'Content-Type': 'application/jsoncompact'
  • 'Accept-Encoding': 'gzip, deflate, br, zstd'

We recommend that you create a new environment in Postman to run the APIs. You can save your variables in the environment and not the collection so that secrets are not exposed if you want to export and share the collection. You can also save the variables in the collection and modify the pre-request script to run the APIs without creating an environment.

Create an environment in Postman

  1. Click Environments in left navigation menu.
  2. Click Create New Environment.
  3. Enter a name for your environment.

Configure variables in the environment

  1. Click Environments in left navigation menu.
  2. Select your Endor Labs API environment.
  3. Create a variable with the name, baseUrl and enter https://api.endorlabs.com as the value.
  4. Create the following variables with information that your API Key and API Secret.
    • apiKey : Your API key
    • apiSecret : Your API secret
  5. Create a variable with the name, bearerToken and leave it as empty. Postman Variables
  6. Save the changes.

Configure authentication in the Endor REST API collection

  1. Select Endor REST API collection and select the Authentication tab.
  2. Select Bearer Token as the Auth Type.
  3. Enter {{bearerToken}} in the Bearer Token field. Postman Authentication
  4. Save the changes.

Add the pre-request script to the Endor REST API collection

  1. Select Endor REST API collection and select the Scripts tab.

  2. Select Pre-request.

  3. Enter the following JavaScript code as the pre-request script.

    
     const getTokenEndpoint = pm.environment.get("baseUrl") + '/v1/auth/api-key';
     const apiKey = pm.environment.get("apiKey");
     const apiSecret = pm.environment.get("apiSecret");
     const requestOptions = {
         method: 'POST',
         url: getTokenEndpoint,
         header: {
             'Content-Type': 'application/jsoncompact',
             'Accept-Encoding': 'gzip, deflate, br, zstd'
         },
         body: {
             mode: 'raw',
             raw: JSON.stringify({
                 "key": apiKey,
                 "secret": apiSecret
             })
         }
     };
    
     pm.sendRequest(requestOptions, function(err, response) {
         if (err) {
             console.log(err);
         } else {
             const jsonResponse = response.json();
             pm.environment.set("bearerToken", jsonResponse.token);
    
             // Set headers for the main request
             pm.request.headers.add({
                 key: 'Content-Type',
                 value: 'application/jsoncompact'
             });
             pm.request.headers.add({
                 key: 'Accept-Encoding',
                 value: 'gzip, deflate, br, zstd'
             });
         }
     });
    

    Postman Pre-request Script

  4. Save the changes.

Run Endor Labs API from Postman

  1. Click Collections in the left navigation menu.
  2. Expand Endor REST API collection and select the API that you want to run.
  3. Configure the parameters in the Params tab.
  4. Select the Endor Labs API environment from the Environments drop-down list.
  5. Enter the name of your namespace in the :tenant_meta.namespace or :target_namespace if your API request applies to a namespace.
  6. Click Send to send the API request.

Customize and share Postman collection

You can configure parameters for multiple APIs according to your requirements, save the collection, and share the collection to quickly distribute API requests tailored for your organization.

For example, you might want to create multiple collections that apply to different namespaces and use different parameters for the namespaces. You can customize the parameters for each use case and export the collection for distribution in your development team.

Endor Labs API with Postman: An Example

Consider a scenario where you need to fetch findings that have a CVSS score of more than 9.7.

You need to run the ListFindings API, which is available under Endor REST API > V1 > Namespaces > {tenant_meta.namespace} > findings in the collection.

In the Params tab, select only list_parameters.filter as the key and enter spec.finding_metadata.vulnerability.spec.cvss_v3_severity.score > 9.7 as the value.

Replace :tenant_meta.namespace with the name of your namespace and click Send.

Postman Example Request

The response contains the list of findings that are vulnerabilities with CVSS score greater than 9.7. Postman Example Response

3.12 - Errors

Learn about the Endor Labs REST API error codes.

Endor Labs uses conventional gRPC and HTTP response codes to indicate the success or failure of an API request.

gRPC status codes

Value Code Name Description
0 OK Not an error; returned on success.
1 CANCELLED The operation was cancelled, typically by the caller.
2 UNKNOWN Unknown error; typically indicates an unexpected error.
3 INVALID_ARGUMENT The client specified an invalid argument.
4 DEADLINE_EXCEEDED The deadline expired before the operation could complete.
5 NOT_FOUND The requested entity, such as a file or directory, was not found.
6 ALREADY_EXISTS The entity that a client attempted to create already exists.
7 PERMISSION_DENIED The caller does not have permission to execute the specified operation.
8 RESOURCE_EXHAUSTED Some resource has been exhausted, perhaps a per-user quota, or the entire file system is out of space.
9 FAILED_PRECONDITION The system is not in a state required for the operation’s execution.
10 ABORTED The operation was aborted, typically due to a concurrency issue like a sequencer check failure.
11 OUT_OF_RANGE The operation was attempted beyond the valid range, such as seeking past the end of a file.
12 UNIMPLEMENTED The operation is not implemented or is not supported or enabled in this service.
13 INTERNAL Internal errors; invariants expected by the underlying system are broken.
14 UNAVAILABLE The service is currently unavailable. This is most likely a transient condition and may be corrected by retrying with a backoff.
15 DATA_LOSS Unrecoverable data loss or corruption.
16 UNAUTHENTICATED The request does not have valid authentication credentials for the operation.

For more information, see the gRPC status code documentation.

HTTP status codes

Value Code Name Description
200 OK Everything worked as expected.
400 Bad Request The request was unacceptable, often due to missing a required parameter.
401 Unauthorized No valid API key provided.
402 Request Failed The parameters were valid but the request failed.
403 Forbidden The API key doesn’t have permissions to perform the request.
404 Not Found The requested resource doesn’t exist.
409 Conflict The request conflicts with another request, possibly due to using the same key.
429 Too Many Requests Too many API requests were sent to Endor Labs in a short time. We recommend using an exponential backoff strategy for your requests.
500 , 502, 503, 504 Server Errors Something went wrong on the Endor Labs side (these are rare).

3.13 - Troubleshooting

Learn how to diagnose and resolve common problems for the Endor Labs REST API.

For a full list of error code descriptions, see Errors.

Invalid authorization

If Endor Labs cannot verify your access token, for example, if it is empty or if it has expired, Endor Labs will terminate the request and you will receive an invalid authorization response.

{
    "code": 16,
    "message": "Invalid authorization header: Bearer",
    "details": [
        {
            "@type": "type.googleapis.com/internal.endor.ai.rpc.v1.HTTPErrorInfo",
            "status_code": 401
        }
    ]
}

Remediation

Try creating a new token or, if you have a valid API key and secret in your ~/.endorctl/config.yaml file, unsetting the environment variable (unset ENDOR_TOKEN).

For more information, see Authentication.

Permission Denied

If your access token does not have the required permissions to access a namespace or perform an operation, Endor Labs will terminate the request and you will receive an unauthorized request response.

{
  "code": 7,
  "message": "Unauthorized request for given endpoint",
  "details": [
    {
      "@type": "type.googleapis.com/internal.endor.ai.rpc.v1.HTTPErrorInfo",
      "status_code": 403
    }
  ]
}

Remediation

Check the value of the ENDOR_NAMESPACE environment variable, the variable with the same name in the ~/.endorctl/config.yaml file, or the API endpoint URL.

For more information, see Authentication.

Context deadline exceeded

If it takes too long to process an API request, Endor Labs will terminate the request and you will receive a timeout response and a “context deadline exceeded” message.

{
    "code": 4,
    "message": "context deadline exceeded",
    "details": []
}

Endor Labs reserves the right to change the timeout window to protect the speed and reliability of the API.

Remediation

You can increase the request timeout limit or you can try to simplify your request. For instance, if you are requesting 100 items per page, try requesting fewer items.

For more information, see Best practices.

Invalid argument

If a request is missing a required field, or includes a non-existent field, Endor Labs will return an “invalid argument” response. The response message field contains details about the error, such as the field name and the specific problem with it.

For example, the following response is returned if you request all findings with the field mask uui instead of uuid:

{
  "code": 3,
  "message": "mask: proto: invalid path &#34;uui&#34; for message &#34;internal.endor.ai.endor.v1.Finding&#34;",
  "details": [
    {
      "@type": "type.googleapis.com/internal.endor.ai.rpc.v1.HTTPErrorInfo",
      "status_code": 400
    }
  ]
}

PATCH requests

Here is an example response to an PATCH (update) request that sent a Finding as the payload instead of an UpdateFinding:

{
  "code": 3,
  "message": "invalid Finding.Meta: value is required; invalid Finding.Spec: value is required",
  "details": [
    {
      "@type": "type.googleapis.com/internal.endor.ai.rpc.v1.HTTPErrorInfo",
      "status_code": 400
    }
  ]
}

Remediation

Make sure to use the right data structure as the payload for your PATCH requests. For example:

{
  "request" : {
    "update_mask": "meta.tags"
  },
  "object" : {
    "uuid" : "<uuid>",
    "meta" : {
      "tags": [
        "<tags>"
      ]
    }
  }
}

4 - Authentication

Learn how to authenticate to the Endor Labs REST API.

About Authentication

Endor Labs supports several methods of authentication. In all cases, clients use an Endor Labs specific API token to exchange their identity with Endor Labs. The token uses x509 signatures and is signed by the Endor Labs private key.

The authentication process is initiated by the caller via one of the authentication methods described below. The API authenticates the client and returns an Endor Identity Token (ENDOR_TOKEN) that it can apply to all its requests and is valid for 4 hours.

After creating an API token, you can authenticate your requests by including the token in the Authorization header. For example, you can export it using the ENDOR_TOKEN variable and then use it in curl commands such as the following.

If needed, replace $ENDOR_NAMESPACE with the name of your namespace.

curl --get \
  --header "Authorization: Bearer $ENDOR_TOKEN" \
  --url "https://api.endorlabs.com/v1/namespaces/$ENDOR_NAMESPACE/projects" \

The following sections describe the different ways you can create an ENDOR_TOKEN.

Headless mode

  1. Paste the following URL in your preferred browser:

    https://api.endorlabs.com/v1/auth/google?redirect=headless
    
    https://api.endorlabs.com/v1/auth/github?redirect=headless
    
    https://api.endorlabs.com/v1/auth/gitlab?redirect=headless
    
    https://api.endorlabs.com/v1/auth/login?email=<my_email>&redirect=headless
    
    https://api.endorlabs.com/v1/auth/sso?tenant=<my_namespace>&redirect=headless
    
  2. Use your browser window to authenticate

  3. If authenticating with email, follow the link sent to the provided email

  4. Once authenticated, copy the token displayed by the browser

  5. Go back to your terminal and export it to your ENDOR_TOKEN environment variable

API key and secret

This method provides authentication using Endor Labs API keys. Any user of the system can create an API key under a namespace. The key consists of a key and a secret randomly generated by the system.

Using endorctl

If you authenticate with Endor Labs using endorctl then a ~/.endorctl/config.yaml file is created in your environment containing essential details such as the API key, secret, and tenant namespace.

Use the following command to export the value of your access token:

export ENDOR_TOKEN=$(endorctl auth --print-access-token)

Using the UI

Generating an API key and secret using the Endor Labs user interface enables you to select a custom expiration date and permissions.

To generate an API key and secret via the UI, follow these steps:

  1. On the left sidebar, navigate to the Access Control section, and select API Keys.
  2. Click Generate API Key.
  3. Specify the following key details:
    • Name: Enter a descriptive name for the API key, identifying its purpose or user.
    • Permission Level: Choose the appropriate permission level for the API key. Options include:
      • Admin: Full access to all features and functionalities.
      • Read-only: View-only access, without the ability to modify or create resources.
      • Code Scanner: Access specifically for code scanning functionalities.
      • Policy Editor: Access to policy editing features.
  4. Select the desired expiry date for the API key, ranging from 30 to 90 days.
  5. Click Generate API Key for confirmation.

Under the Advanced section, you have the option to propagate the API key to all child namespaces.

After generating your API key and secret, click Copy API Key & Secret. Make sure to securely store your API secret in a safe location, as it will not be accessible through the Endor Labs UI later.

The copied key and secret will look like this:

# Endor API Key: name
# Expires: 2024-09-05T00:06:16.789Z
ENDOR_API_CREDENTIALS_KEY=endr+foo
ENDOR_API_CREDENTIALS_SECRET=endr+bar

You can then get a token by making a POST request with the API key and secret to the https://api.endorlabs.com/v1/auth/api-key endpoint.

The response contains both the token and the expiration time, so use jq to extract the token and export it directly to the ENDOR_TOKEN environment variable:

export ENDOR_TOKEN=$(curl --request POST \
  --url "https://api.endorlabs.com/v1/auth/api-key" \
  --data '{ "key": "$ENDOR_API_CREDENTIALS_KEY", "secret": "$ENDOR_API_CREDENTIALS_SECRET" }' \
  | jq -r .token)
@baseUrl = https://api.endorlabs.com

###
POST {{baseUrl}}/v1/auth/api-key
content-type: application/json

{
  "key" : "endr+foo", "secret":"endr+bar"
}

Authentication precedence

If you have set up multiple ways to authenticate endorctl, the precedence is as follows:

  1. Arguments in the endorctl command

    You can provide authentication information in the endorctl command, and these credentials take the highest precedence during authentication. Even if authentication information is available in the ~/.endorctl/config.yaml file or the ENDOR_TOKEN environment variable, the value you provide in the command takes precedence.

  2. Authentication information in ~/.endorctl/config.yaml

    If you authenticate with Endor Labs using endorctl, the ~/.endorctl/config.yaml file is created in your environment that contains authentication information (such as API key and tenant namespace). Even if you set a different authentication token as the ENDOR_TOKEN environment variable, the information in the ~/.endorctl/config.yaml file takes precedence.

  3. ENDOR_TOKEN environment variable

    If you do not provide authentication information in the endorctl command or if there is no authentication information in the ~/.endorctl/config.yaml file, the authentication information specified in the ENDOR_TOKEN environment variable is used for authentication. To use the ENDOR_TOKEN variable, ensure that neither the command-line arguments nor the ~/.endorctl/config.yaml file contain authentication information.

Failed authentication

If you try to use a REST API endpoint without an Endor Labs token, you will receive a 401 Unauthorized response. For more information, see troubleshooting.