From 4e4141dfff1b2d4df80ce01e46f76d557e79e2ce Mon Sep 17 00:00:00 2001 From: dependencytrack-bot <106437498+dependencytrack-bot@users.noreply.github.com> Date: Fri, 18 Sep 2026 11:58:23 +0000 Subject: [PATCH] Update OpenAPI docs Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- docs/reference/api/openapi-v1.yaml | 33 + docs/reference/api/openapi-v2.yaml | 1605 ++++++++++++++++++++++++---- 2 files changed, 1452 insertions(+), 186 deletions(-) diff --git a/docs/reference/api/openapi-v1.yaml b/docs/reference/api/openapi-v1.yaml index 147b8ef4..af80cf68 100644 --- a/docs/reference/api/openapi-v1.yaml +++ b/docs/reference/api/openapi-v1.yaml @@ -9912,6 +9912,10 @@ components: type: integer format: int64 description: UNIX epoch timestamp in milliseconds + expiresAt: + type: integer + format: int64 + description: UNIX epoch timestamp in milliseconds key: type: string lastUsed: @@ -12723,6 +12727,31 @@ components: technicalImpactScore: type: number format: double + ServiceAccount: + type: object + properties: + email: + type: string + maxLength: 255 + minLength: 0 + pattern: "[\\P{Cc}]+" + permissions: + type: array + items: + $ref: "#/components/schemas/Permission" + suspended: + type: boolean + teams: + type: array + items: + $ref: "#/components/schemas/Team" + username: + type: string + maxLength: 255 + minLength: 1 + pattern: "[\\P{Cc}]+" + required: + - username ServiceComponent: type: object properties: @@ -12957,6 +12986,10 @@ components: type: array items: $ref: "#/components/schemas/Permission" + serviceAccounts: + type: array + items: + $ref: "#/components/schemas/ServiceAccount" uuid: type: string format: uuid diff --git a/docs/reference/api/openapi-v2.yaml b/docs/reference/api/openapi-v2.yaml index 8dd3a10a..11ef70ea 100644 --- a/docs/reference/api/openapi-v2.yaml +++ b/docs/reference/api/openapi-v2.yaml @@ -94,9 +94,10 @@ info: - `POST /api/v1/user/login` - `POST /api/v1/user/oidc/login` + - `POST /api/v2/oauth/token` - API v2 does not yet provide its own login endpoints; clients use - the v1 endpoints above to acquire tokens and then call v2 with them. + API v2 does not yet provide its own login endpoints; users log in + through the v1 endpoints above and then call v2 with the token. Tokens are valid for 8 hours by default and **cannot be refreshed**. Clients must re-authenticate once a token expires. @@ -177,10 +178,14 @@ tags: description: Endpoints related to extensions - name: Kev Data Sources description: Endpoints related to KEV data sources +- name: OAuth + description: Endpoints related to OAuth 2.0 token issuance - name: Projects description: Endpoints related to projects - name: Secrets description: Endpoints related to secrets +- name: Service Accounts + description: Endpoints related to service accounts - name: System Capabilities description: Endpoints exposing the capabilities of the running server - name: Task Queues @@ -193,6 +198,8 @@ tags: description: Endpoints related to vulnerabilities - name: Workflows description: Endpoints related to workflows +- name: Workload Identity Providers + description: Endpoints related to workload identity providers paths: /components: get: @@ -748,6 +755,74 @@ paths: $ref: "#/components/responses/generic-not-found-error" default: $ref: "#/components/responses/generic-error" + /oauth/token: + post: + tags: + - OAuth + summary: Create a Dependency-Track access token + description: |- + Creates an access token for the requested grant. + + The access token is an opaque session token. Send it in the `Authorization` header, + as `Bearer `. `scope` is not supported. + + The only grant supported is RFC 8693 token exchange, which requires `subject_token` and `subject_token_type`. + Exchanges for a session of a service account also require `workload_identity_provider` and `service_account`, + and succeed when a binding of the requested service account matches the subject token. + The resulting session has all permissions of the service account. + operationId: createOAuthToken + requestBody: + content: + application/x-www-form-urlencoded: + schema: + $ref: "#/components/schemas/create-oauth-token-request" + required: true + responses: + "200": + description: The access token + headers: + Cache-Control: + description: Always `no-store` + schema: + maxLength: 32 + type: string + Pragma: + description: Always `no-cache` + schema: + maxLength: 32 + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/create-oauth-token-response" + "400": + description: "The request was refused. An unsupported grant yields `unsupported_grant_type`,\ + \ every other refusal yields `invalid_request`." + headers: + Cache-Control: + description: Always `no-store` + schema: + maxLength: 32 + type: string + Pragma: + description: Always `no-cache` + schema: + maxLength: 32 + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/oauth-token-error" + "503": + description: "The grant cannot be processed because a dependency is unavailable,\ + \ such as the keys to verify a subject token. Retrying later may succeed." + content: + application/problem+json: + schema: + $ref: "#/components/schemas/problem-details" + default: + $ref: "#/components/responses/generic-error" + security: [] /projects/{uuid}/clone: post: tags: @@ -787,76 +862,675 @@ paths: $ref: "#/components/responses/generic-forbidden-error" "404": $ref: "#/components/responses/generic-not-found-error" - "409": - $ref: "#/components/responses/generic-conflict-error" + "409": + $ref: "#/components/responses/generic-conflict-error" + default: + $ref: "#/components/responses/generic-error" + /projects/{uuid}/components: + get: + tags: + - Projects + summary: Retrieves a list of all components for a given project. + description: |- + Requires permission `VIEW_PORTFOLIO` + + ### Sortable fields + + Sorting is supported for the following fields: + + * `name` + * `group` + * `last_inherited_risk_score` + * `package_artifact_metadata.published_at` + + Components without resolved artifact metadata, or whose upstream registry did not + report a publication date, are placed at the end of the result for both sort + directions when sorting by `package_artifact_metadata.published_at`. + + ### Expandable fields + + The following fields can be included via `expand`: + + * `metrics` + * `package_metadata` + * `package_artifact_metadata` + * `occurrence_count` + operationId: listProjectComponents + parameters: + - name: uuid + in: path + description: The UUID of the project to retrieve components for + required: true + schema: + type: string + format: uuid + - name: only_outdated + in: query + description: Optionally exclude recent components so only outdated components + are returned + schema: + type: boolean + - name: only_direct + in: query + description: Optionally exclude transitive dependencies so only direct dependencies + are returned + schema: + type: boolean + - name: q + in: query + description: Optional free-text search term. Matches components whose `group` + or `name` contains the given value (case-insensitive). + schema: + type: string + - name: expand + in: query + description: Optional fields to include in each component response item. Unknown + values are silently ignored. + style: form + explode: true + schema: + type: array + items: + type: string + - name: limit + in: query + description: Maximum number of items to retrieve from the collection + schema: + maximum: 1000 + minimum: 1 + type: integer + format: int32 + default: 100 + - name: page_token + in: query + description: Opaque token pointing to a specific position in a collection + schema: + type: string + - name: sort_direction + in: query + schema: + $ref: "#/components/schemas/sort-direction" + - name: sort_by + in: query + description: Field to sort by. Refer to the operation description for information + about which fields are sortable. + schema: + maxLength: 255 + minLength: 1 + type: string + responses: + "200": + description: A list of all components for a given project + content: + application/json: + schema: + $ref: "#/components/schemas/list-project-components-response" + "400": + description: Bad Request + content: + application/problem+json: + schema: + anyOf: + - $ref: "#/components/schemas/invalid-sort-field-problem-details" + - $ref: "#/components/schemas/problem-details" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + /secrets: + get: + tags: + - Secrets + summary: List secret metadata + description: |- + Returns a paginated list of secret metadata. + + Requires the `SYSTEM_CONFIGURATION` or `SYSTEM_CONFIGURATION_READ` permission. + operationId: listSecretMetadata + parameters: + - name: q + in: query + description: Optional search text to filter secrets by. Filtering uses case-insensitive + "starts with" semantics on the secret name. + schema: + type: string + - name: page_token + in: query + description: Opaque token pointing to a specific position in a collection + schema: + type: string + - name: limit + in: query + description: Maximum number of items to retrieve from the collection + schema: + maximum: 1000 + minimum: 1 + type: integer + format: int32 + default: 100 + responses: + "200": + description: Paginated list of secret metadata + content: + application/json: + schema: + $ref: "#/components/schemas/list-secrets-response" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + default: + $ref: "#/components/responses/generic-error" + post: + tags: + - Secrets + summary: Create a secret + description: |- + Creates a new secret. + + Requires the `SECRET_MANAGEMENT` or `SECRET_MANAGEMENT_CREATE` permission. + + Administrators can configure the secret manager to be read-only. + In that case, create requests will be rejected with status code `400`. + operationId: createSecret + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/create-secret-request" + required: true + responses: + "201": + description: Secret created + headers: + Location: + description: URL of the created secret + schema: + type: string + format: uri + "400": + description: Bad Request + content: + application/problem+json: + schema: + anyOf: + - $ref: "#/components/schemas/invalid-request-problem-details" + - $ref: "#/components/schemas/problem-details" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "409": + $ref: "#/components/responses/generic-conflict-error" + default: + $ref: "#/components/responses/generic-error" + /secrets/{name}: + get: + tags: + - Secrets + summary: Get secret metadata + description: |- + Returns metadata about a given secret. + + Requires the `SYSTEM_CONFIGURATION` or `SYSTEM_CONFIGURATION_READ` permission. + operationId: getSecretMetadata + parameters: + - name: name + in: path + description: The name of the secret + required: true + schema: + $ref: "#/components/schemas/secret-name" + responses: + "200": + description: Secret metadata + content: + application/json: + schema: + $ref: "#/components/schemas/secret-metadata" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + delete: + tags: + - Secrets + summary: Delete a secret + description: |- + Deletes an existing secret. + + Requires the `SECRET_MANAGEMENT` or `SECRET_MANAGEMENT_DELETE` permission. + + Administrators can configure the secret manager to be read-only. + In that case, delete requests will be rejected with status code `400`. + operationId: deleteSecret + parameters: + - name: name + in: path + description: The name of the secret + required: true + schema: + $ref: "#/components/schemas/secret-name" + responses: + "204": + description: Secret deleted + "400": + description: Bad Request + content: + application/problem+json: + schema: + anyOf: + - $ref: "#/components/schemas/invalid-request-problem-details" + - $ref: "#/components/schemas/problem-details" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + patch: + tags: + - Secrets + summary: Update a secret + description: |- + Updates an existing secret. + + Requires the `SECRET_MANAGEMENT` or `SECRET_MANAGEMENT_UPDATE` permission. + + Administrators can configure the secret manager to be read-only. + In that case, update requests will be rejected with status code `400`. + operationId: updateSecret + parameters: + - name: name + in: path + description: The name of the secret + required: true + schema: + $ref: "#/components/schemas/secret-name" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/update-secret-request" + required: true + responses: + "204": + description: Secret updated + "304": + description: Not modified + "400": + description: Bad Request + content: + application/problem+json: + schema: + anyOf: + - $ref: "#/components/schemas/invalid-request-problem-details" + - $ref: "#/components/schemas/problem-details" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + /service-accounts: + get: + tags: + - Service Accounts + summary: List service accounts + description: |- + Returns a paginated list of service accounts, ordered by name. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_READ` permission. + operationId: listServiceAccounts + parameters: + - name: q + in: query + description: Optional search text to filter service accounts by. Filtering + uses case-insensitive "contains" semantics on the name. + schema: + maxLength: 59 + type: string + - name: page_token + in: query + description: Opaque token pointing to a specific position in a collection + schema: + type: string + - name: limit + in: query + description: Maximum number of items to retrieve from the collection + schema: + maximum: 1000 + minimum: 1 + type: integer + format: int32 + default: 100 + responses: + "200": + description: Paginated list of service accounts + content: + application/json: + schema: + $ref: "#/components/schemas/list-service-accounts-response" + "400": + $ref: "#/components/responses/invalid-request-error" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + default: + $ref: "#/components/responses/generic-error" + post: + tags: + - Service Accounts + summary: Create a service account + description: |- + Creates a new service account. + + The account's username is the given name, prefixed with `svc:`. + + A new service account has no permissions and no team memberships. + Grant those through the REST API v1 endpoints `POST /api/v1/{permission}/user/{username}` + and `PUT /api/v1/user/membership`. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_CREATE` permission. + operationId: createServiceAccount + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/create-service-account-request" + required: true + responses: + "201": + description: Service account created + headers: + Location: + description: URL of the created service account + schema: + type: string + format: uri + "400": + $ref: "#/components/responses/invalid-request-error" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "409": + $ref: "#/components/responses/generic-conflict-error" + default: + $ref: "#/components/responses/generic-error" + /service-accounts/{name}: + get: + tags: + - Service Accounts + summary: Get a service account + description: |- + Returns details about a service account. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_READ` permission. + operationId: getServiceAccount + parameters: + - name: name + in: path + description: "The name of the service account, without the `svc:` prefix" + required: true + schema: + $ref: "#/components/schemas/service-account-name" + responses: + "200": + description: The service account + content: + application/json: + schema: + $ref: "#/components/schemas/get-service-account-response" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + delete: + tags: + - Service Accounts + summary: Delete a service account + description: |- + Deletes a service account. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_DELETE` permission. + operationId: deleteServiceAccount + parameters: + - name: name + in: path + description: "The name of the service account, without the `svc:` prefix" + required: true + schema: + $ref: "#/components/schemas/service-account-name" + responses: + "204": + description: Service account deleted + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + patch: + tags: + - Service Accounts + summary: Update a service account + description: |- + Updates a service account. + + Suspending an account stops its API keys from authenticating immediately. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_UPDATE` permission. + operationId: updateServiceAccount + parameters: + - name: name + in: path + description: "The name of the service account, without the `svc:` prefix" + required: true + schema: + $ref: "#/components/schemas/service-account-name" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/update-service-account-request" + required: true + responses: + "204": + description: Service account updated + "400": + $ref: "#/components/responses/invalid-request-error" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + /service-accounts/{name}/api-keys: + get: + tags: + - Service Accounts + summary: List the API keys of a service account + description: |- + Returns a paginated list of the API keys a service account owns, newest first. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_READ` permission. + operationId: listServiceAccountApiKeys + parameters: + - name: name + in: path + description: "The name of the service account, without the `svc:` prefix" + required: true + schema: + $ref: "#/components/schemas/service-account-name" + - name: page_token + in: query + description: Opaque token pointing to a specific position in a collection + schema: + type: string + - name: limit + in: query + description: Maximum number of items to retrieve from the collection + schema: + maximum: 1000 + minimum: 1 + type: integer + format: int32 + default: 100 + responses: + "200": + description: Paginated list of API keys + content: + application/json: + schema: + $ref: "#/components/schemas/list-service-account-api-keys-response" + "400": + $ref: "#/components/responses/invalid-request-error" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + post: + tags: + - Service Accounts + summary: Create an API key for a service account + description: |- + Creates a new API key owned by the given service account. + + The plain text key is returned exactly once, in the response body. + It cannot be retrieved afterwards, because only its hash is stored. + + No API keys can be created for a suspended service account. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_CREATE` permission. + operationId: createServiceAccountApiKey + parameters: + - name: name + in: path + description: "The name of the service account, without the `svc:` prefix" + required: true + schema: + $ref: "#/components/schemas/service-account-name" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/create-service-account-api-key-request" + required: true + responses: + "201": + description: API key created + headers: + Location: + description: URL of the created API key + schema: + type: string + format: uri + content: + application/json: + schema: + $ref: "#/components/schemas/create-service-account-api-key-response" + "400": + description: Bad Request + content: + application/problem+json: + schema: + anyOf: + - $ref: "#/components/schemas/invalid-request-problem-details" + - $ref: "#/components/schemas/problem-details" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + "409": + $ref: "#/components/responses/generic-conflict-error" + default: + $ref: "#/components/responses/generic-error" + /service-accounts/{name}/api-keys/{public_id}: + delete: + tags: + - Service Accounts + summary: Delete an API key of a service account + description: |- + Deletes a single API key owned by the given service account. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_DELETE` permission. + operationId: deleteServiceAccountApiKey + parameters: + - name: name + in: path + description: "The name of the service account, without the `svc:` prefix" + required: true + schema: + $ref: "#/components/schemas/service-account-name" + - name: public_id + in: path + description: The public ID of the API key + required: true + schema: + maxLength: 8 + type: string + responses: + "204": + description: API key deleted + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" default: $ref: "#/components/responses/generic-error" - /projects/{uuid}/components: + /service-accounts/{name}/workload-identity-bindings: get: tags: - - Projects - summary: Retrieves a list of all components for a given project. + - Service Accounts + summary: List the workload identity bindings of a service account description: |- - Requires permission `VIEW_PORTFOLIO` - - ### Sortable fields - - Sorting is supported for the following fields: - - * `name` - * `group` - * `last_inherited_risk_score` - * `package_artifact_metadata.published_at` - - Components without resolved artifact metadata, or whose upstream registry did not - report a publication date, are placed at the end of the result for both sort - directions when sorting by `package_artifact_metadata.published_at`. + Returns a paginated list of the workload identity bindings for a service account, + ordered by provider name and subject. - ### Expandable fields - - The following fields can be included via `expand`: - - * `metrics` - * `package_metadata` - * `package_artifact_metadata` - * `occurrence_count` - operationId: listProjectComponents + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_READ` permission. + operationId: listServiceAccountWorkloadIdentityBindings parameters: - - name: uuid + - name: name in: path - description: The UUID of the project to retrieve components for + description: "The name of the service account, without the `svc:` prefix" required: true schema: - type: string - format: uuid - - name: only_outdated - in: query - description: Optionally exclude recent components so only outdated components - are returned - schema: - type: boolean - - name: only_direct - in: query - description: Optionally exclude transitive dependencies so only direct dependencies - are returned - schema: - type: boolean - - name: q + $ref: "#/components/schemas/service-account-name" + - name: page_token in: query - description: Optional free-text search term. Matches components whose `group` - or `name` contains the given value (case-insensitive). + description: Opaque token pointing to a specific position in a collection schema: type: string - - name: expand - in: query - description: Optional fields to include in each component response item. Unknown - values are silently ignored. - style: form - explode: true - schema: - type: array - items: - type: string - name: limit in: query description: Maximum number of items to retrieve from the collection @@ -866,37 +1540,81 @@ paths: type: integer format: int32 default: 100 - - name: page_token - in: query - description: Opaque token pointing to a specific position in a collection - schema: - type: string - - name: sort_direction - in: query - schema: - $ref: "#/components/schemas/sort-direction" - - name: sort_by - in: query - description: Field to sort by. Refer to the operation description for information - about which fields are sortable. - schema: - maxLength: 255 - minLength: 1 - type: string responses: "200": - description: A list of all components for a given project + description: Paginated list of workload identity bindings content: application/json: schema: - $ref: "#/components/schemas/list-project-components-response" + $ref: "#/components/schemas/list-workload-identity-bindings-response" + "400": + $ref: "#/components/responses/invalid-request-error" + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + post: + tags: + - Service Accounts + summary: Create a workload identity binding for a service account + description: |- + Creates a workload identity binding for a service account. + + A trailing `*` in `subject` makes it a prefix match, for example `repo:acme/app:*`. + For `SPIFFE` providers, the prefix must end with `/`. + + For multi-tenant issuers like GitHub and GitLab, ensure that the prefix contains + *at least* your organization to prevent cross-tenant abuse. For example: + + ```json + { + "provider_name": "github-actions", + "subject": "repo:acme-inc/*" + } + ``` + + To match a prefix within a name, add a `condition` such as `claims.sub.startsWith("repo:acme/app-")`. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_CREATE` permission. + operationId: createServiceAccountWorkloadIdentityBinding + parameters: + - name: name + in: path + description: "The name of the service account, without the `svc:` prefix" + required: true + schema: + $ref: "#/components/schemas/service-account-name" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/create-workload-identity-binding-request" + required: true + responses: + "201": + description: Workload identity binding created + headers: + Location: + description: URL of the created workload identity binding + schema: + type: string + format: uri + content: + application/json: + schema: + $ref: "#/components/schemas/create-workload-identity-binding-response" "400": description: Bad Request content: application/problem+json: schema: anyOf: - - $ref: "#/components/schemas/invalid-sort-field-problem-details" + - $ref: "#/components/schemas/invalid-cel-expression-problem-details" + - $ref: "#/components/schemas/invalid-request-problem-details" - $ref: "#/components/schemas/problem-details" "401": $ref: "#/components/responses/generic-unauthorized-error" @@ -906,22 +1624,60 @@ paths: $ref: "#/components/responses/generic-not-found-error" default: $ref: "#/components/responses/generic-error" - /secrets: + /service-accounts/{name}/workload-identity-bindings/{binding_id}: + delete: + tags: + - Service Accounts + summary: Delete a workload identity binding of a service account + description: |- + Deletes a service account's workload identity binding. + + Sessions already created stay valid until they expire. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_DELETE` permission. + operationId: deleteServiceAccountWorkloadIdentityBinding + parameters: + - name: name + in: path + description: "The name of the service account, without the `svc:` prefix" + required: true + schema: + $ref: "#/components/schemas/service-account-name" + - name: binding_id + in: path + description: The identifier of the workload identity binding + required: true + schema: + type: string + format: uuid + responses: + "204": + description: Workload identity binding deleted + "401": + $ref: "#/components/responses/generic-unauthorized-error" + "403": + $ref: "#/components/responses/generic-forbidden-error" + "404": + $ref: "#/components/responses/generic-not-found-error" + default: + $ref: "#/components/responses/generic-error" + /workload-identity-providers: get: tags: - - Secrets - summary: List secret metadata + - Workload Identity Providers + summary: List workload identity providers description: |- - Returns a paginated list of secret metadata. + Returns a paginated list of workload identity providers, ordered by name. - Requires the `SYSTEM_CONFIGURATION` or `SYSTEM_CONFIGURATION_READ` permission. - operationId: listSecretMetadata + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_READ` permission. + operationId: listWorkloadIdentityProviders parameters: - name: q in: query - description: Optional search text to filter secrets by. Filtering uses case-insensitive - "starts with" semantics on the secret name. + description: Optional search text to filter providers by. Filtering uses case-insensitive + "contains" semantics on the name. schema: + maxLength: 63 type: string - name: page_token in: query @@ -939,11 +1695,13 @@ paths: default: 100 responses: "200": - description: Paginated list of secret metadata + description: Paginated list of workload identity providers content: application/json: schema: - $ref: "#/components/schemas/list-secrets-response" + $ref: "#/components/schemas/list-workload-identity-providers-response" + "400": + $ref: "#/components/responses/invalid-request-error" "401": $ref: "#/components/responses/generic-unauthorized-error" "403": @@ -952,28 +1710,39 @@ paths: $ref: "#/components/responses/generic-error" post: tags: - - Secrets - summary: Create a secret + - Workload Identity Providers + summary: Create a workload identity provider description: |- - Creates a new secret. + Creates a new workload identity provider. - Requires the `SECRET_MANAGEMENT` or `SECRET_MANAGEMENT_CREATE` permission. + Use an `audience` unique to this Dependency-Track instance, such as its URL. - Administrators can configure the secret manager to be read-only. - In that case, create requests will be rejected with status code `400`. - operationId: createSecret + The signing keys come either from a URL, or inline. + + For `OIDC` providers, omit both `jwks_url` and `jwks` to have the server read the issuer's + discovery document and store the `jwks_uri` it names. For `SPIFFE` providers, `jwks_url` is + the trust domain's bundle endpoint. + + Provide `jwks` for issuers the server cannot reach, such as a self-managed Kubernetes cluster. + Inline keys are never refreshed. When the issuer rotates its keys, update the provider. + + Unless keys are provided inline, the server fetches them and rejects the request if that fails, + or if the URL resolves to a loopback or link-local address. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_CREATE` permission. + operationId: createWorkloadIdentityProvider requestBody: content: application/json: schema: - $ref: "#/components/schemas/create-secret-request" + $ref: "#/components/schemas/create-workload-identity-provider-request" required: true responses: "201": - description: Secret created + description: Workload identity provider created headers: Location: - description: URL of the created secret + description: URL of the created workload identity provider schema: type: string format: uri @@ -993,30 +1762,30 @@ paths: $ref: "#/components/responses/generic-conflict-error" default: $ref: "#/components/responses/generic-error" - /secrets/{name}: + /workload-identity-providers/{name}: get: tags: - - Secrets - summary: Get secret metadata + - Workload Identity Providers + summary: Get a workload identity provider description: |- - Returns metadata about a given secret. + Returns details about a workload identity provider. - Requires the `SYSTEM_CONFIGURATION` or `SYSTEM_CONFIGURATION_READ` permission. - operationId: getSecretMetadata + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_READ` permission. + operationId: getWorkloadIdentityProvider parameters: - name: name in: path - description: The name of the secret + description: The name of the workload identity provider required: true schema: - $ref: "#/components/schemas/secret-name" + $ref: "#/components/schemas/workload-identity-provider-name" responses: "200": - description: Secret metadata + description: The workload identity provider content: application/json: schema: - $ref: "#/components/schemas/secret-metadata" + $ref: "#/components/schemas/workload-identity-provider" "401": $ref: "#/components/responses/generic-unauthorized-error" "403": @@ -1027,34 +1796,23 @@ paths: $ref: "#/components/responses/generic-error" delete: tags: - - Secrets - summary: Delete a secret + - Workload Identity Providers + summary: Delete a workload identity provider description: |- - Deletes an existing secret. + Deletes a workload identity provider and cascade-deletes its bindings. Sessions already created stay valid until they expire. - Requires the `SECRET_MANAGEMENT` or `SECRET_MANAGEMENT_DELETE` permission. - - Administrators can configure the secret manager to be read-only. - In that case, delete requests will be rejected with status code `400`. - operationId: deleteSecret + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_DELETE` permission. + operationId: deleteWorkloadIdentityProvider parameters: - name: name in: path - description: The name of the secret + description: The name of the workload identity provider required: true schema: - $ref: "#/components/schemas/secret-name" + $ref: "#/components/schemas/workload-identity-provider-name" responses: "204": - description: Secret deleted - "400": - description: Bad Request - content: - application/problem+json: - schema: - anyOf: - - $ref: "#/components/schemas/invalid-request-problem-details" - - $ref: "#/components/schemas/problem-details" + description: Workload identity provider deleted "401": $ref: "#/components/responses/generic-unauthorized-error" "403": @@ -1065,34 +1823,37 @@ paths: $ref: "#/components/responses/generic-error" patch: tags: - - Secrets - summary: Update a secret + - Workload Identity Providers + summary: Update a workload identity provider description: |- - Updates an existing secret. + Updates a workload identity provider. - Requires the `SECRET_MANAGEMENT` or `SECRET_MANAGEMENT_UPDATE` permission. + Only the given fields are changed. The name and type of a provider cannot change. - Administrators can configure the secret manager to be read-only. - In that case, update requests will be rejected with status code `400`. - operationId: updateSecret + Providing `jwks_url` switches the provider to that URL. Providing `jwks` switches it to inline keys. + Changing the `issuer` of an `OIDC` provider that fetches its keys from a URL re-reads the new issuer's + discovery document and replaces the stored `jwks_url`, unless `jwks_url` or `jwks` is given as well. + Bindings of a `SPIFFE` provider stop matching when its trust domain changes. + When the key source changes, the server fetches the new keys and rejects the request if that fails. + + Requires the `ACCESS_MANAGEMENT` or `ACCESS_MANAGEMENT_UPDATE` permission. + operationId: updateWorkloadIdentityProvider parameters: - name: name in: path - description: The name of the secret + description: The name of the workload identity provider required: true schema: - $ref: "#/components/schemas/secret-name" + $ref: "#/components/schemas/workload-identity-provider-name" requestBody: content: application/json: schema: - $ref: "#/components/schemas/update-secret-request" + $ref: "#/components/schemas/update-workload-identity-provider-request" required: true responses: "204": - description: Secret updated - "304": - description: Not modified + description: Workload identity provider updated "400": description: Bad Request content: @@ -1200,7 +1961,7 @@ paths: application/problem+json: schema: anyOf: - - $ref: "#/components/schemas/invalid-vuln-policy-condition-problem-details" + - $ref: "#/components/schemas/invalid-cel-expression-problem-details" - $ref: "#/components/schemas/invalid-request-problem-details" - $ref: "#/components/schemas/problem-details" "401": @@ -1278,7 +2039,7 @@ paths: application/problem+json: schema: anyOf: - - $ref: "#/components/schemas/invalid-vuln-policy-condition-problem-details" + - $ref: "#/components/schemas/invalid-cel-expression-problem-details" - $ref: "#/components/schemas/invalid-request-problem-details" - $ref: "#/components/schemas/problem-details" "401": @@ -2191,19 +2952,97 @@ components: properties: status: type: string - description: Status of the mirror run. - enum: - - PENDING - - RUNNING - - COMPLETED - - FAILED - started_at: - $ref: "#/components/schemas/timestamp" - completed_at: - $ref: "#/components/schemas/timestamp" - failure_reason: + description: Status of the mirror run. + enum: + - PENDING + - RUNNING + - COMPLETED + - FAILED + started_at: + $ref: "#/components/schemas/timestamp" + completed_at: + $ref: "#/components/schemas/timestamp" + failure_reason: + type: string + description: Reason for why the mirror run failed. + create-oauth-token-request: + required: + - grant_type + type: object + properties: + grant_type: + maxLength: 64 + type: string + description: The grant type. Only `urn:ietf:params:oauth:grant-type:token-exchange` + is supported. + example: urn:ietf:params:oauth:grant-type:token-exchange + subject_token: + maxLength: 16384 + type: string + description: The token to exchange. Required for the token exchange grant. + At most 16 KiB. + subject_token_type: + maxLength: 64 + type: string + description: "The type of the subject token. Required for the token exchange\ + \ grant. `urn:ietf:params:oauth:token-type:jwt` for all workload identity\ + \ providers, or `urn:ietf:params:oauth:token-type:id_token` for `OIDC`\ + \ providers." + example: urn:ietf:params:oauth:token-type:jwt + requested_token_type: + maxLength: 64 + type: string + description: The type of token to issue. Optional. Only `urn:ietf:params:oauth:token-type:access_token` + is supported. + example: urn:ietf:params:oauth:token-type:access_token + workload_identity_provider: + $ref: "#/components/schemas/workload-identity-provider-name" + service_account: + $ref: "#/components/schemas/service-account-name" + create-oauth-token-response: + required: + - access_token + - expires_in + - issued_token_type + - token_type + type: object + properties: + access_token: + maxLength: 8192 + type: string + description: An access token. + issued_token_type: + maxLength: 64 + type: string + description: Always `urn:ietf:params:oauth:token-type:access_token`. + example: urn:ietf:params:oauth:token-type:access_token + token_type: + maxLength: 32 + type: string + description: Always `Bearer`. + example: Bearer + expires_in: + maximum: 86400 + minimum: 60 + type: integer + description: "How many seconds the access token is valid for. For token\ + \ exchange, this is the workload identity provider's `session_lifetime_seconds`." + format: int32 + example: 3600 + oauth-token-error: + required: + - error + type: object + properties: + error: + maxLength: 64 + type: string + description: "The RFC 6749 error code, either `invalid_request` or `unsupported_grant_type`." + example: invalid_request + error_description: + maxLength: 256 type: string - description: Reason for why the mirror run failed. + description: "A short, generic description of the error." clone-project-request: required: - version @@ -2317,6 +3156,308 @@ components: minLength: 1 type: string description: The new value. Omit this field to retain the current value. + list-service-accounts-response: + required: + - items + type: object + properties: + items: + type: array + items: + $ref: "#/components/schemas/service-account" + allOf: + - $ref: "#/components/schemas/paginated-response" + create-service-account-request: + required: + - name + type: object + properties: + name: + $ref: "#/components/schemas/service-account-name" + email: + maxLength: 255 + type: string + service-account-name: + maxLength: 59 + pattern: "^(?![sS][vV][cC]:)[a-zA-Z0-9][a-zA-Z0-9+=,.:@_-]*$" + type: string + description: "The name of the service account, without the reserved `svc:` prefix." + example: ci-pipeline + get-service-account-response: + required: + - permissions + - teams + type: object + properties: + teams: + type: array + description: "The teams the service account is a member of, ordered by name." + items: + $ref: "#/components/schemas/service-account-team" + permissions: + type: array + description: "The permissions granted to the service account directly, ordered\ + \ by name. Permissions it inherits from its teams are not included." + items: + maxLength: 255 + type: string + allOf: + - $ref: "#/components/schemas/service-account" + update-service-account-request: + type: object + properties: + email: + maxLength: 255 + type: string + description: "The new email address. Omit this field to retain the current\ + \ address, or set it to an empty string to remove the current address." + suspended: + type: boolean + description: Whether the service account is suspended. Omit this field to + retain the current state. + list-service-account-api-keys-response: + required: + - items + type: object + properties: + items: + type: array + items: + $ref: "#/components/schemas/service-account-api-key" + allOf: + - $ref: "#/components/schemas/paginated-response" + create-service-account-api-key-request: + type: object + properties: + comment: + maxLength: 255 + type: string + expires_in_days: + minimum: 1 + type: integer + description: "Number of days from now after which the key expires. Must\ + \ not exceed the maximum lifetime configured with `dt.api-key.max-lifetime-days`\ + \ (366 days by default). Defaults to 30 days, or the maximum lifetime\ + \ if that is shorter." + format: int32 + create-service-account-api-key-response: + required: + - expires_at + - key + - public_id + type: object + properties: + public_id: + maxLength: 8 + type: string + example: a1b2c3d4 + key: + maxLength: 128 + type: string + description: "The full, plain text key. It is returned exactly once, at\ + \ creation time, and cannot be retrieved again." + expires_at: + description: When the key expires. + allOf: + - $ref: "#/components/schemas/timestamp" + list-workload-identity-bindings-response: + required: + - items + type: object + properties: + items: + type: array + items: + $ref: "#/components/schemas/workload-identity-binding" + allOf: + - $ref: "#/components/schemas/paginated-response" + create-workload-identity-binding-request: + required: + - provider_name + - subject + type: object + properties: + provider_name: + maxLength: 63 + type: string + description: The name of the workload identity provider to trust the subject + of. The provider must exist. + example: github-actions + subject: + maxLength: 512 + pattern: "^[^*]+(?:[:/]\\*)?$" + type: string + description: "The `sub` claim to match. A trailing `*` makes it a prefix\ + \ match, whose prefix must not be empty and must end with `:` or `/`." + example: repo:acme/app:* + condition: + maxLength: 2048 + type: string + description: "An optional CEL expression over the token's claims that must\ + \ evaluate to `true`. The claims are available as the `claims` map, for\ + \ example `claims.ref == \"refs/heads/main\"`. Use it when the subject\ + \ alone cannot express the rule." + example: claims.ref == "refs/heads/main" + create-workload-identity-binding-response: + required: + - uuid + type: object + properties: + uuid: + type: string + description: The identifier of the created binding. + format: uuid + invalid-cel-expression-problem-details: + required: + - errors + type: object + properties: + errors: + type: array + items: + $ref: "#/components/schemas/cel-expression-error" + allOf: + - $ref: "#/components/schemas/problem-details" + list-workload-identity-providers-response: + required: + - items + type: object + properties: + items: + type: array + items: + $ref: "#/components/schemas/workload-identity-provider" + allOf: + - $ref: "#/components/schemas/paginated-response" + create-workload-identity-provider-request: + required: + - audience + - issuer + - name + - type + type: object + properties: + name: + $ref: "#/components/schemas/workload-identity-provider-name" + type: + $ref: "#/components/schemas/workload-identity-provider-type" + issuer: + maxLength: 255 + type: string + description: "The expected `iss` claim for `OIDC` providers, or the SPIFFE\ + \ trust domain for `SPIFFE` providers, such as `example.org`." + example: https://token.actions.githubusercontent.com + audience: + maxLength: 255 + type: string + description: The value that the token's `aud` claim must contain. + example: https://dependency-track.example.com + jwks_url: + maxLength: 2048 + type: string + description: The URL to fetch the signing keys from. Must be `https`. + example: https://example.org/keys + jwks: + type: object + additionalProperties: true + description: An RFC 7517 JSON Web Key Set holding the issuer's public signing + keys. + session_lifetime_seconds: + maximum: 86400 + minimum: 60 + type: integer + description: "The lifetime of sessions created through this provider, unless\ + \ a binding sets its own." + format: int32 + example: 3600 + default: 3600 + workload-identity-provider-name: + maxLength: 63 + pattern: "^[a-zA-Z0-9][a-zA-Z0-9_-]*$" + type: string + description: The name of the workload identity provider. + example: github-actions + workload-identity-provider: + required: + - audience + - created_at + - issuer + - name + - session_lifetime_seconds + - type + type: object + properties: + name: + $ref: "#/components/schemas/workload-identity-provider-name" + type: + $ref: "#/components/schemas/workload-identity-provider-type" + issuer: + maxLength: 255 + type: string + description: "The expected `iss` claim for `OIDC` providers, or the SPIFFE\ + \ trust domain for `SPIFFE` providers." + example: https://token.actions.githubusercontent.com + audience: + maxLength: 255 + type: string + description: The value that the token's `aud` claim must contain. + example: https://dependency-track.example.com + jwks_url: + maxLength: 2048 + type: string + description: "The URL the signing keys are fetched from. For `OIDC` providers,\ + \ this is the `jwks_uri` resolved from the issuer's discovery document.\ + \ Absent when the keys were provided inline." + jwks_key_ids: + maxItems: 64 + type: array + description: The key IDs of the inline key set. Absent when the keys are + fetched from a URL. + items: + maxLength: 255 + type: string + session_lifetime_seconds: + maximum: 86400 + minimum: 60 + type: integer + description: "The lifetime of sessions created through this provider, unless\ + \ a binding sets its own." + format: int32 + example: 3600 + created_at: + $ref: "#/components/schemas/timestamp" + update-workload-identity-provider-request: + type: object + properties: + issuer: + maxLength: 255 + type: string + description: "The expected `iss` claim for `OIDC` providers, or the SPIFFE\ + \ trust domain for `SPIFFE` providers, such as `example.org`." + example: https://token.actions.githubusercontent.com + audience: + maxLength: 255 + type: string + description: The value that the token's `aud` claim must contain. + example: https://dependency-track.example.com + jwks_url: + maxLength: 2048 + type: string + description: The URL to fetch the signing keys from. Must be `https`. + example: https://example.org/keys + jwks: + type: object + additionalProperties: true + description: An RFC 7517 JSON Web Key Set holding the issuer's public signing + keys. + session_lifetime_seconds: + maximum: 86400 + minimum: 60 + type: integer + description: "The lifetime of sessions created through this provider, unless\ + \ a binding sets its own." + format: int32 + example: 3600 list-vuln-policies-response: required: - items @@ -2368,17 +3509,6 @@ components: $ref: "#/components/schemas/timestamp" valid_until: $ref: "#/components/schemas/timestamp" - invalid-vuln-policy-condition-problem-details: - required: - - errors - type: object - properties: - errors: - type: array - items: - $ref: "#/components/schemas/vuln-policy-condition-error" - allOf: - - $ref: "#/components/schemas/problem-details" get-vuln-policy-response: required: - analysis @@ -2970,6 +4100,127 @@ components: $ref: "#/components/schemas/package-metadata" package_artifact_metadata: $ref: "#/components/schemas/package-artifact-metadata" + service-account: + required: + - name + - suspended + - username + type: object + properties: + name: + $ref: "#/components/schemas/service-account-name" + username: + maxLength: 63 + type: string + description: "The full username of the service account, i.e. the name with\ + \ the reserved `svc:` prefix." + example: svc:ci-pipeline + email: + maxLength: 255 + type: string + suspended: + type: boolean + description: Whether the service account is suspended. + service-account-team: + required: + - name + - uuid + type: object + properties: + uuid: + type: string + format: uuid + name: + maxLength: 255 + type: string + service-account-api-key: + required: + - public_id + type: object + properties: + public_id: + maxLength: 8 + type: string + description: "The public, non-secret portion of the key." + example: a1b2c3d4 + comment: + maxLength: 255 + type: string + created_at: + $ref: "#/components/schemas/timestamp" + last_used_at: + $ref: "#/components/schemas/timestamp" + expires_at: + description: When the key expires. + allOf: + - $ref: "#/components/schemas/timestamp" + workload-identity-binding: + required: + - created_at + - provider_name + - subject + - uuid + type: object + properties: + uuid: + type: string + description: The identifier of the binding. + format: uuid + provider_name: + maxLength: 63 + type: string + description: The name of the workload identity provider the binding belongs + to. + example: github-actions + subject: + maxLength: 512 + pattern: "^[^*]+(?:[:/]\\*)?$" + type: string + description: The `sub` claim the binding matches. A trailing `*` makes it + a prefix match. + example: repo:acme/app:* + condition: + maxLength: 2048 + type: string + description: A CEL expression over the token's claims that must evaluate + to `true`. Absent when the binding matches on the subject alone. + example: claims.ref == "refs/heads/main" + created_at: + $ref: "#/components/schemas/timestamp" + last_used_at: + description: When a token was last exchanged through the binding. Absent + when it was never used. + allOf: + - $ref: "#/components/schemas/timestamp" + cel-expression-error: + required: + - column + - line + - message + type: object + properties: + line: + type: integer + description: Line number where the error occurred + format: int32 + column: + type: integer + description: Column number where the error occurred + format: int32 + message: + type: string + description: Description of the error + workload-identity-provider-type: + type: string + description: |- + The type of issuer the provider trusts. + + * `OIDC`: an OpenID Connect issuer. Tokens must carry an `iss` claim equal to the provider's issuer. + * `SPIFFE`: a SPIFFE trust domain. The `iss` claim is ignored, and `sub` must be a SPIFFE ID of that trust domain. + example: OIDC + enum: + - OIDC + - SPIFFE list-vuln-policies-response-item: required: - name @@ -3065,24 +4316,6 @@ components: - DISABLED - APPLY - LOG - vuln-policy-condition-error: - required: - - column - - line - - message - type: object - properties: - line: - type: integer - description: Line number where the error occurred - format: int32 - column: - type: integer - description: Column number where the error occurred - format: int32 - message: - type: string - description: Description of the error vuln-policy-source: type: string enum: @@ -3489,7 +4722,7 @@ components: type: http description: |- Authentication via opaque server-issued session token. - Tokens are obtained from `POST /api/v1/user/login` or - `POST /api/v1/user/oidc/login`. + Tokens are obtained from `POST /api/v1/user/login`, + `POST /api/v1/user/oidc/login`, or `POST /api/v2/oauth/token`. scheme: bearer bearerFormat: Opaque