This is the multi-page printable view of this section. Click here to print.
Advanced use cases
1 - Using the query service
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.
- Request a list of Projects, but only return the
uuid
,meta.name
andprocessing_status
fields for each Project. - Connect the Project
uuid
to the corresponding child PackageVersionspec.project_uuid
field. - 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.
- Request a list of Projects, but only return the
uuid
andmeta.name
fields for each Project. - Connect the Project
uuid
to the corresponding child RepositoryVersionmeta.parent_uuid
field. - 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
}
Find a Project and related Finding counts
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
}
2 - Using saved queries
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[]'