본문으로 건너뛰기

TRUSCA API (2.2.0-dev)

Download OpenAPI specification:Download

Open-source self-hosted SCA portal — CVE, license compliance, and SBOM management with EPSS prioritization, VEX consumption, CI build gating, and Trivy-backed CVE matching with weekly DB refresh + automatic re-matching on new vulnerability data.

auth

Request a password reset link (public, rate limited)

Public — no authentication required, but limited per PASSWORD_RESET_RATE_LIMIT (5/min/IP by default).

Body shape: {"email": "<address>"}. Always returns 204 + empty body (CWE-204). When the address matches a registered user we additionally enqueue an email via Celery. When the per-email cooldown is active we set Retry-After to the configured cooldown and STILL return 204.

Request Body schema: application/json
required
email
required
string <email> (Email)

Responses

Request samples

Content type
application/json
{
  • "email": "user@example.com"
}

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Login (public, rate limited)

Public — no authentication required, but limited to 5 attempts/minute/IP.

On success: 200 + access_token in the body, refresh as HttpOnly cookie. On bad credentials: 401 problem+json.

Request Body schema: application/json
required
email
required
string <email> (Email)
password
required
string (Password) [ 1 .. 256 ] characters

Responses

Request samples

Content type
application/json
{
  • "email": "user@example.com",
  • "password": "string"
}

Response samples

Content type
application/json
{
  • "access_token": "string",
  • "expires_in": 0,
  • "token_type": "bearer"
}

Logout (revoke refresh cookie)

Revoke the refresh cookie. Idempotent — always returns 204 even if the cookie is absent or already revoked.

cookie Parameters
Refresh Token (string) or Refresh Token (null) (Refresh Token)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Return the currently authenticated user and their memberships

Authenticated. UserPublic + the caller's team memberships.

The frontend reads memberships to resolve a team_id for project creation / write scoping. Ordered oldest-first so memberships[0] is a stable default team.

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true,
  • "memberships": [
    ]
}

List OAuth provider availability (public)

Public — no authentication required (explicit exception to CLAUDE.md core rule #12: the consumer is the anonymous /login page, which must decide which OAuth sign-in buttons to render BEFORE any credential exists).

Always lists every supported provider with a bare configured boolean. configured is True only when both the client id AND client secret are set — the same condition under which /{provider}/authorize actually works (M-15: a half-configured or unconfigured provider previously surfaced as a rendered button that 503'd on click).

Security: the response carries booleans only — never client ids, secrets, or any other configuration detail.

Responses

Response samples

Content type
application/json
{
  • "providers": [
    ]
}

Begin OAuth sign-in (public)

Public — no authentication required.

302 → provider's authorize URL with a signed state. Returns:

  • 503 + oauth_provider_disabled Problem Details when the provider's client id/secret is not configured.
  • 404 Problem Details when the provider name is unknown (FastAPI's Literal[] gate normally catches this; the explicit branch survives future enum widening).
  • 403 demo_read_only Problem Details when the deployment runs in read-only live-demo mode (OAuth sign-in is a write; see :func:_demo_read_only_blocked).
path Parameters
provider
required
string (Provider)
Enum: "github" "google"
query Parameters
Redirect After (string) or Redirect After (null) (Redirect After)

Responses

Response samples

Content type
application/json
null

OAuth callback (public)

Public — the provider's redirect lands here after consent.

Success path: 302 → redirect_after (or configured default) with the refresh-token HttpOnly cookie attached.

Failure path: 302 → configured failure URL with ?error=<reason>. The provider's own ?error=access_denied (user clicked "Cancel") falls through here too — we forward a normalised error=oauth_denied.

Read-only demo: if DEMO_READ_ONLY is enabled we 403 BEFORE any token exchange or DB write (see :func:_demo_read_only_blocked), so the callback can never create/link a User or Team in the demo.

path Parameters
provider
required
string (Provider)
Enum: "github" "google"
query Parameters
Code (string) or Code (null) (Code)
State (string) or State (null) (State)
Error (string) or Error (null) (Error)

Responses

Response samples

Content type
application/json
null

Rotate refresh token (public; refresh cookie is the credential)

Public — the refresh cookie is the credential.

Successful rotation: 200 + new access_token + new refresh cookie. Reuse detected (cookie already rotated): 401, entire chain revoked.

cookie Parameters
Refresh Token (string) or Refresh Token (null) (Refresh Token)

Responses

Response samples

Content type
application/json
{
  • "access_token": "string",
  • "expires_in": 0,
  • "token_type": "bearer"
}

Register a new user (public)

Public — no authentication required.

Returns the new user (without password). 422 for validation errors, 409 if the email is already registered.

Request Body schema: application/json
required
email
required
string <email> (Email)
Full Name (string) or Full Name (null) (Full Name)
password
required
string (Password) [ 8 .. 256 ] characters

At least 8 characters (NIST 800-63B minimum), not a common password.

Responses

Request samples

Content type
application/json
{
  • "email": "user@example.com",
  • "full_name": "string",
  • "password": "stringst"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true
}

Confirm a password reset using a one-shot token (public)

Public — the reset token is the credential.

On success: 204 + every refresh token for the user is revoked. On bad / expired / used token: 422 problem+json.

Request Body schema: application/json
required
new_password
required
string (New Password) [ 8 .. 256 ] characters

At least 8 characters (NIST 800-63B minimum), not a common password.

token
required
string (Token) [ 8 .. 256 ] characters

Responses

Request samples

Content type
application/json
{
  • "new_password": "stringst",
  • "token": "stringst"
}

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

public

Liveness probe — PUBLIC, unauthenticated

Cheap PURE-LIVENESS probe used by docker-compose / k8s liveness checks.

PUBLIC / unauthenticated (CLAUDE.md rule #12 explicit exception). This proves only that the uvicorn process is accepting requests — it does NOT touch the database and says nothing about schema state. For "is the schema migrated and safe to serve traffic / start workers", use GET /health/ready (api/v1/health.py).

v2.1 Track B (B5): also surfaces demo_read_only so the SPA can render the read-only banner and disable write actions without needing a separate build. The flag is resolved at request time (CLAUDE.md rule #11), so the same image behaves correctly whether DEMO_READ_ONLY is set or not.

Responses

Response samples

Content type
application/json
{ }

Readiness probe (schema at Alembic HEAD) — PUBLIC, unauthenticated

Return 200 when the DB schema matches the Alembic HEAD, else 503.

PUBLIC: no auth dependency by design (probe endpoint — see module docstring and CLAUDE.md core rule #12). The check is read-only (a single SELECT on alembic_version plus an in-image read of the script tree).

Responses

Response samples

Content type
application/json
{
  • "status": "ready"
}

admin

Search audit log (admin) — paginated, filterable

query Parameters
Actor User Id (string) or Actor User Id (null) (Actor User Id)
Target Table (string) or Target Table (null) (Target Table)
Action (string) or Action (null) (Action)
From (string) or From (null) (From)
To (string) or To (null) (To)
Q (string) or Q (null) (Q)
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "has_more": true,
  • "items": [
    ],
  • "page": 1,
  • "page_size": 1,
  • "total": 0
}

Search audit log (admin) — paginated, filterable

query Parameters
Actor User Id (string) or Actor User Id (null) (Actor User Id)
Target Table (string) or Target Table (null) (Target Table)
Action (string) or Action (null) (Action)
From (string) or From (null) (From)
To (string) or To (null) (To)
Q (string) or Q (null) (Q)
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "has_more": true,
  • "items": [
    ],
  • "page": 1,
  • "page_size": 1,
  • "total": 0
}

Export audit log to CSV (admin) — streaming, capped at 100k rows

query Parameters
Actor User Id (string) or Actor User Id (null) (Actor User Id)
Target Table (string) or Target Table (null) (Target Table)
Action (string) or Action (null) (Action)
From (string) or From (null) (From)
To (string) or To (null) (To)
Q (string) or Q (null) (Q)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Export audit log to CSV (admin) — streaming, capped at 100k rows

query Parameters
Actor User Id (string) or Actor User Id (null) (Actor User Id)
Target Table (string) or Target Table (null) (Target Table)
Action (string) or Action (null) (Action)
From (string) or From (null) (From)
To (string) or To (null) (To)
Q (string) or Q (null) (Q)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

List all backups (admin) — auto + manual, newest first

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "total": 0
}

List all backups (admin) — auto + manual, newest first

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "total": 0
}

Trigger a manual backup (admin) — enqueues the Celery task

Responses

Response samples

Content type
application/json
{
  • "name": "string",
  • "task_id": "string"
}

Trigger a manual backup (admin) — enqueues the Celery task

Responses

Response samples

Content type
application/json
{
  • "name": "string",
  • "task_id": "string"
}

Restore from an uploaded backup archive (admin) — destructive

header Parameters
X-Confirm-Restore (string) or X-Confirm-Restore (null) (X-Confirm-Restore)
Content-Length (integer) or Content-Length (null) (Content-Length)
Request Body schema: multipart/form-data
required
archive
required
string <application/octet-stream> (Archive)

tar.gz produced by GET /download.

Responses

Response samples

Content type
application/json
{
  • "message": "string",
  • "task_id": "string"
}

Restore from an uploaded backup archive (admin) — destructive

header Parameters
X-Confirm-Restore (string) or X-Confirm-Restore (null) (X-Confirm-Restore)
Content-Length (integer) or Content-Length (null) (Content-Length)
Request Body schema: multipart/form-data
required
archive
required
string <application/octet-stream> (Archive)

tar.gz produced by GET /download.

Responses

Response samples

Content type
application/json
{
  • "message": "string",
  • "task_id": "string"
}

Delete a manual backup (admin) — auto backups are protected

path Parameters
name
required
string (Name)

Backup directory name.

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Delete a manual backup (admin) — auto backups are protected

path Parameters
name
required
string (Name)

Backup directory name.

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Download a backup archive (admin) — streams a tar.gz of the directory

path Parameters
name
required
string (Name)

Backup directory name.

Responses

Response samples

Content type
application/json
null

Download a backup archive (admin) — streams a tar.gz of the directory

path Parameters
name
required
string (Name)

Backup directory name.

Responses

Response samples

Content type
application/json
null

Disk usage telemetry (admin) — workspace / DT volume / Postgres / Redis

Responses

Response samples

Content type
application/json
{
  • "collected_at": "2019-08-24T14:15:22Z",
  • "items": [
    ]
}

Disk usage telemetry (admin) — workspace / DT volume / Postgres / Redis

Responses

Response samples

Content type
application/json
{
  • "collected_at": "2019-08-24T14:15:22Z",
  • "items": [
    ]
}

System health summary (admin) — postgres / redis / celery / DT / disk

Responses

Response samples

Content type
application/json
{
  • "components": [
    ],
  • "updated_at": "2019-08-24T14:15:22Z"
}

System health summary (admin) — postgres / redis / celery / DT / disk

Responses

Response samples

Content type
application/json
{
  • "components": [
    ],
  • "updated_at": "2019-08-24T14:15:22Z"
}

List scans (admin) — cross-team queue with optional status/kind/project filters

query Parameters
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50
Status (string) or Status (null) (Status)
Kind (string) or Kind (null) (Kind)
Project (string) or Project (null) (Project)

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 1,
  • "page_size": 1,
  • "total": 0
}

List scans (admin) — cross-team queue with optional status/kind/project filters

query Parameters
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50
Status (string) or Status (null) (Status)
Kind (string) or Kind (null) (Kind)
Project (string) or Project (null) (Project)

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 1,
  • "page_size": 1,
  • "total": 0
}

Force-cancel a scan (admin) — Celery revoke + status='cancelled'

path Parameters
scan_id
required
string <uuid> (Scan Id)

Responses

Response samples

Content type
application/json
null

Force-cancel a scan (admin) — Celery revoke + status='cancelled'

path Parameters
scan_id
required
string <uuid> (Scan Id)

Responses

Response samples

Content type
application/json
null

List teams (admin) — paginated, name search

query Parameters
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50
Search (string) or Search (null) (Search)

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0
}

List teams (admin) — paginated, name search

query Parameters
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50
Search (string) or Search (null) (Search)

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0
}

Create a team (admin)

Request Body schema: application/json
required
Description (string) or Description (null) (Description)
name
required
string (Name) [ 1 .. 255 ] characters
slug
required
string (Slug) [ 1 .. 64 ] characters

Responses

Request samples

Content type
application/json
{
  • "description": "string",
  • "name": "string",
  • "slug": "string"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Create a team (admin)

Request Body schema: application/json
required
Description (string) or Description (null) (Description)
name
required
string (Name) [ 1 .. 255 ] characters
slug
required
string (Slug) [ 1 .. 64 ] characters

Responses

Request samples

Content type
application/json
{
  • "description": "string",
  • "name": "string",
  • "slug": "string"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Delete a team (admin) — archives projects, refuses on active scans

path Parameters
team_id
required
string <uuid> (Team Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Delete a team (admin) — archives projects, refuses on active scans

path Parameters
team_id
required
string <uuid> (Team Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Get one team (admin) — detail with members and project count

path Parameters
team_id
required
string <uuid> (Team Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Get one team (admin) — detail with members and project count

path Parameters
team_id
required
string <uuid> (Team Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Update a team (admin)

path Parameters
team_id
required
string <uuid> (Team Id)
Request Body schema: application/json
required
Description (string) or Description (null) (Description)
Name (string) or Name (null) (Name)
Slug (string) or Slug (null) (Slug)

Responses

Request samples

Content type
application/json
{
  • "description": "string",
  • "name": "string",
  • "slug": "string"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Update a team (admin)

path Parameters
team_id
required
string <uuid> (Team Id)
Request Body schema: application/json
required
Description (string) or Description (null) (Description)
Name (string) or Name (null) (Name)
Slug (string) or Slug (null) (Slug)

Responses

Request samples

Content type
application/json
{
  • "description": "string",
  • "name": "string",
  • "slug": "string"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Add (or update) a team member (admin)

path Parameters
team_id
required
string <uuid> (Team Id)
Request Body schema: application/json
required
role
required
string (Role)

Either team_admin or developer.

user_id
required
string <uuid> (User Id)

Responses

Request samples

Content type
application/json
{
  • "role": "string",
  • "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Add (or update) a team member (admin)

path Parameters
team_id
required
string <uuid> (Team Id)
Request Body schema: application/json
required
role
required
string (Role)

Either team_admin or developer.

user_id
required
string <uuid> (User Id)

Responses

Request samples

Content type
application/json
{
  • "role": "string",
  • "user_id": "a169451c-8525-4352-b8ca-070dd449a1a5"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Remove a team member (admin)

path Parameters
team_id
required
string <uuid> (Team Id)
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Remove a team member (admin)

path Parameters
team_id
required
string <uuid> (Team Id)
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "description": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "members": [
    ],
  • "name": "string",
  • "project_count": 0,
  • "slug": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Trivy vulnerability DB status (admin) — last_update / freshness / vuln_count

Responses

Response samples

Content type
application/json
{
  • "cache_dir": "string",
  • "db_size_bytes": 0,
  • "db_version": "string",
  • "freshness": "fresh",
  • "last_update": "2019-08-24T14:15:22Z",
  • "next_refresh_at": "2019-08-24T14:15:22Z",
  • "refresh_interval_hours": 1,
  • "repository": "string",
  • "vuln_count": 0
}

Trivy vulnerability DB status (admin) — last_update / freshness / vuln_count

Responses

Response samples

Content type
application/json
{
  • "cache_dir": "string",
  • "db_size_bytes": 0,
  • "db_version": "string",
  • "freshness": "fresh",
  • "last_update": "2019-08-24T14:15:22Z",
  • "next_refresh_at": "2019-08-24T14:15:22Z",
  • "refresh_interval_hours": 1,
  • "repository": "string",
  • "vuln_count": 0
}

List users (admin) — paginated, filterable

query Parameters
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50
Role (string) or Role (null) (Role)
Active (boolean) or Active (null) (Active)
Search (string) or Search (null) (Search)

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0
}

List users (admin) — paginated, filterable

query Parameters
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50
Role (string) or Role (null) (Role)
Active (boolean) or Active (null) (Active)
Search (string) or Search (null) (Search)

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0
}

Get one user (admin) — detail with memberships + scan count

path Parameters
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true,
  • "last_login_at": "2019-08-24T14:15:22Z",
  • "memberships": [
    ],
  • "scan_count": 0,
  • "updated_at": "2019-08-24T14:15:22Z"
}

Get one user (admin) — detail with memberships + scan count

path Parameters
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true,
  • "last_login_at": "2019-08-24T14:15:22Z",
  • "memberships": [
    ],
  • "scan_count": 0,
  • "updated_at": "2019-08-24T14:15:22Z"
}

Re-activate a user (admin)

path Parameters
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true,
  • "last_login_at": "2019-08-24T14:15:22Z",
  • "memberships": [
    ],
  • "scan_count": 0,
  • "updated_at": "2019-08-24T14:15:22Z"
}

Re-activate a user (admin)

path Parameters
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true,
  • "last_login_at": "2019-08-24T14:15:22Z",
  • "memberships": [
    ],
  • "scan_count": 0,
  • "updated_at": "2019-08-24T14:15:22Z"
}

Deactivate a user (admin) — revokes refresh tokens

path Parameters
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true,
  • "last_login_at": "2019-08-24T14:15:22Z",
  • "memberships": [
    ],
  • "scan_count": 0,
  • "updated_at": "2019-08-24T14:15:22Z"
}

Deactivate a user (admin) — revokes refresh tokens

path Parameters
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true,
  • "last_login_at": "2019-08-24T14:15:22Z",
  • "memberships": [
    ],
  • "scan_count": 0,
  • "updated_at": "2019-08-24T14:15:22Z"
}

Initiate a password reset (admin) — Phase 6 wires email delivery

Issues a one-shot reset token (bcrypt-hashed in storage) and returns 204.

Phase 6 PR #18 will wire the SMTP / Slack delivery channel. Until then the plaintext token is generated, persisted as a hash, audit-logged via the listener (which masks the hash to ***), and discarded.

-- Account-enumeration semantics (security-reviewer F5) -------------------

This endpoint returns 404 when user_id does not exist. That IS an enumeration oracle in isolation, but it is acceptable HERE because the route is super-admin-gated by require_super_admin_or_404 — any caller who can reach this code path is already authorised to read the full user list (GET /v1/admin/users), so the 404 leaks no information they did not already have. The trust boundary is ABOVE this endpoint, not at it.

The Phase 6 PR #18 PUBLIC password-reset flow ("forgot password") MUST NOT copy this 404-on-miss pattern. That endpoint is unauthenticated, so a 404 vs. 204 split there would let an attacker enumerate registered emails (CWE-204 Observable Response Discrepancy). The public flow returns a uniform 204 regardless of whether the email exists, with the actual reset email sent only when a match is found. See docs/v2-execution-plan.md §3.7 for the Phase 6 contract.

path Parameters
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Initiate a password reset (admin) — Phase 6 wires email delivery

Issues a one-shot reset token (bcrypt-hashed in storage) and returns 204.

Phase 6 PR #18 will wire the SMTP / Slack delivery channel. Until then the plaintext token is generated, persisted as a hash, audit-logged via the listener (which masks the hash to ***), and discarded.

-- Account-enumeration semantics (security-reviewer F5) -------------------

This endpoint returns 404 when user_id does not exist. That IS an enumeration oracle in isolation, but it is acceptable HERE because the route is super-admin-gated by require_super_admin_or_404 — any caller who can reach this code path is already authorised to read the full user list (GET /v1/admin/users), so the 404 leaks no information they did not already have. The trust boundary is ABOVE this endpoint, not at it.

The Phase 6 PR #18 PUBLIC password-reset flow ("forgot password") MUST NOT copy this 404-on-miss pattern. That endpoint is unauthenticated, so a 404 vs. 204 split there would let an attacker enumerate registered emails (CWE-204 Observable Response Discrepancy). The public flow returns a uniform 204 regardless of whether the email exists, with the actual reset email sent only when a match is found. See docs/v2-execution-plan.md §3.7 for the Phase 6 contract.

path Parameters
user_id
required
string <uuid> (User Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Change a user's role (admin)

path Parameters
user_id
required
string <uuid> (User Id)
Request Body schema: application/json
required
role
required
string (Role)

One of super_admin / team_admin / developer.

Team Id (string) or Team Id (null) (Team Id)

Required when role is team_admin or developer; ignored for super_admin.

Responses

Request samples

Content type
application/json
{
  • "role": "string",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true,
  • "last_login_at": "2019-08-24T14:15:22Z",
  • "memberships": [
    ],
  • "scan_count": 0,
  • "updated_at": "2019-08-24T14:15:22Z"
}

Change a user's role (admin)

path Parameters
user_id
required
string <uuid> (User Id)
Request Body schema: application/json
required
role
required
string (Role)

One of super_admin / team_admin / developer.

Team Id (string) or Team Id (null) (Team Id)

Required when role is team_admin or developer; ignored for super_admin.

Responses

Request samples

Content type
application/json
{
  • "role": "string",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "email": "string",
  • "full_name": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_active": true,
  • "is_superuser": true,
  • "last_login_at": "2019-08-24T14:15:22Z",
  • "memberships": [
    ],
  • "scan_count": 0,
  • "updated_at": "2019-08-24T14:15:22Z"
}

api-keys

Paginated list of API keys visible to the caller

query Parameters
Scope (string) or Scope (null) (Scope)
Team Id (string) or Team Id (null) (Team Id)
Project Id (string) or Project Id (null) (Project Id)
include_revoked
boolean (Include Revoked)
Default: false
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0
}

Issue a new API key (plaintext returned ONCE in raw_key)

Request Body schema: application/json
required
Expires In Days (integer) or Expires In Days (null) (Expires In Days)

Optional TTL in days. The key stops authenticating after this many days. Omit for a non-expiring key (CI keys should set one and rotate). Max 1825 (5 years).

name
required
string (Name) [ 1 .. 100 ] characters
Project Id (string) or Project Id (null) (Project Id)
scope
required
string (Scope)
Enum: "org" "team" "project"
Team Id (string) or Team Id (null) (Team Id)

Responses

Request samples

Content type
application/json
{
  • "expires_in_days": 1,
  • "name": "string",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "scope": "org",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba"
}

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "key_prefix": "string",
  • "name": "string",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "raw_key": "string",
  • "scope": "org",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba"
}

Revoke (soft-delete) an API key

path Parameters
api_key_id
required
string <uuid> (Api Key Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

approvals

Paginated list of approval requests (team-scoped; super_admin sees all)

query Parameters
Status (string) or Status (null) (Status)

Single status or a comma-separated list of statuses (e.g. pending,under_review).

Team Id (string) or Team Id (null) (Team Id)
Requested By User Id (string) or Requested By User Id (null) (Requested By User Id)
From Dt (string) or From Dt (null) (From Dt)
To Dt (string) or To Dt (null) (To Dt)
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0
}

Open a new approval request for a component in a project

Request Body schema: application/json
required
component_id
required
string <uuid> (Component Id)
project_id
required
string <uuid> (Project Id)

Responses

Request samples

Content type
application/json
{
  • "component_id": "41afafe5-2a48-424a-baef-34c2ad44ef7b",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9"
}

Response samples

Content type
application/json
{
  • "component_id": "41afafe5-2a48-424a-baef-34c2ad44ef7b",
  • "component_name": "string",
  • "component_purl": "string",
  • "decided_at": "2019-08-24T14:15:22Z",
  • "decided_by_user_id": "c750fc7f-0b29-4c93-a0d7-9578b1a62969",
  • "decision_note": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "project_name": "string",
  • "project_slug": "string",
  • "requested_at": "2019-08-24T14:15:22Z",
  • "requested_by_user_id": "ed1d5170-d6e9-4e60-8754-78ea9640e9db",
  • "status": "pending",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "version": 0
}

Delete a non-terminal approval (original requester, team_admin, or super_admin)

path Parameters
approval_id
required
string <uuid> (Approval Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Single approval detail — includes ETag header for optimistic concurrency

path Parameters
approval_id
required
string <uuid> (Approval Id)

Responses

Response samples

Content type
application/json
{
  • "component_id": "41afafe5-2a48-424a-baef-34c2ad44ef7b",
  • "component_name": "string",
  • "component_purl": "string",
  • "decided_at": "2019-08-24T14:15:22Z",
  • "decided_by_user_id": "c750fc7f-0b29-4c93-a0d7-9578b1a62969",
  • "decision_note": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "project_name": "string",
  • "project_slug": "string",
  • "requested_at": "2019-08-24T14:15:22Z",
  • "requested_by_user_id": "ed1d5170-d6e9-4e60-8754-78ea9640e9db",
  • "status": "pending",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "version": 0
}

Transition an approval's status (requires If-Match header)

path Parameters
approval_id
required
string <uuid> (Approval Id)
header Parameters
If-Match (string) or If-Match (null) (If-Match)
Request Body schema: application/json
required
action
required
string (Action)
Enum: "under_review" "approved" "rejected"
Decision Note (string) or Decision Note (null) (Decision Note)

Responses

Request samples

Content type
application/json
{
  • "action": "under_review",
  • "decision_note": "string"
}

Response samples

Content type
application/json
{
  • "component_id": "41afafe5-2a48-424a-baef-34c2ad44ef7b",
  • "component_name": "string",
  • "component_purl": "string",
  • "decided_at": "2019-08-24T14:15:22Z",
  • "decided_by_user_id": "c750fc7f-0b29-4c93-a0d7-9578b1a62969",
  • "decision_note": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "project_name": "string",
  • "project_slug": "string",
  • "requested_at": "2019-08-24T14:15:22Z",
  • "requested_by_user_id": "ed1d5170-d6e9-4e60-8754-78ea9640e9db",
  • "status": "pending",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "version": 0
}

audit

Search audit log scoped to the caller's teams (team_admin+)

query Parameters
Actor User Id (string) or Actor User Id (null) (Actor User Id)
Target Table (string) or Target Table (null) (Target Table)
Action (string) or Action (null) (Action)
From (string) or From (null) (From)
To (string) or To (null) (To)
Q (string) or Q (null) (Q)
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "has_more": true,
  • "items": [
    ],
  • "page": 1,
  • "page_size": 1,
  • "total": 0
}

components

Component detail (drawer payload). 404 if component is invisible to caller.

path Parameters
component_id
required
string <uuid> (Component Id)

Responses

Response samples

Content type
application/json
{
  • "created_at": "2019-08-24T14:15:22Z",
  • "dependency_scope": "required",
  • "depth": 0,
  • "direct": false,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "license": "string",
  • "license_category": "forbidden",
  • "name": "string",
  • "obligations": [
    ],
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "purl": "string",
  • "raw_data": { },
  • "severity_max": "critical",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "version": "string",
  • "vulnerabilities": [
    ]
}

dashboard

Portfolio overview for the caller's accessible projects (auth required)

Aggregate counts (projects, scans, severities, licenses, approvals) plus the 10 most recent scans, scoped to the caller's accessible projects.

Responses

Response samples

Content type
application/json
{
  • "license_category_counts": {
    },
  • "pending_approvals_count": 2,
  • "project_count": 7,
  • "recent_scans": [
    ],
  • "scan_status_counts": {
    },
  • "vulnerability_severity_counts": {
    }
}

github-app

Paginated list of GitHub App credentials visible to the caller

query Parameters
Team Id (string) or Team Id (null) (Team Id)
include_revoked
boolean (Include Revoked)
Default: false
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0
}

Register a GitHub App credential (private key encrypted at rest)

query Parameters
team_id
required
string <uuid> (Team Id)

The team that owns this credential.

Request Body schema: application/json
required
app_id
required
string (App Id) [ 1 .. 64 ] characters
App Slug (string) or App Slug (null) (App Slug)
private_key
required
string (Private Key) non-empty

The GitHub App PEM private key (plaintext). Accepted ONCE at registration, encrypted at rest, and never returned.

Webhook Secret (string) or Webhook Secret (null) (Webhook Secret)

Responses

Request samples

Content type
application/json
{
  • "app_id": "string",
  • "app_slug": "string",
  • "private_key": "string",
  • "webhook_secret": "string"
}

Response samples

Content type
application/json
{
  • "app_id": "string",
  • "app_slug": "string",
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "has_private_key": true,
  • "has_webhook_secret": true,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "revoked_at": "2019-08-24T14:15:22Z",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Revoke (soft-delete) a GitHub App credential

path Parameters
credential_id
required
string <uuid> (Credential Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Fetch one GitHub App credential's metadata

path Parameters
credential_id
required
string <uuid> (Credential Id)

Responses

Response samples

Content type
application/json
{
  • "app_id": "string",
  • "app_slug": "string",
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "has_private_key": true,
  • "has_webhook_secret": true,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "revoked_at": "2019-08-24T14:15:22Z",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "updated_at": "2019-08-24T14:15:22Z"
}

List installations under a credential

path Parameters
credential_id
required
string <uuid> (Credential Id)
query Parameters
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0
}

Link (opt-in) an installation under a credential

path Parameters
credential_id
required
string <uuid> (Credential Id)
Request Body schema: application/json
required
Account Login (string) or Account Login (null) (Account Login)
installation_id
required
string (Installation Id) [ 1 .. 64 ] characters
Project Id (string) or Project Id (null) (Project Id)

The TrustedOSS project this installation is opted-in to.

Repository Full Name (string) or Repository Full Name (null) (Repository Full Name)

Responses

Request samples

Content type
application/json
{
  • "account_login": "string",
  • "installation_id": "string",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "repository_full_name": "string"
}

Response samples

Content type
application/json
{
  • "account_login": "string",
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "credential_id": "13c40afa-2996-4a0c-b2e9-68fba9462242",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "installation_id": "string",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "repository_full_name": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

license-policies

Paginated list of license policies visible to the caller

query Parameters
Organization Id (string) or Organization Id (null) (Organization Id)
Team Id (string) or Team Id (null) (Team Id)
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0
}

Read the org-default license policy (super_admin)

path Parameters
organization_id
required
string <uuid> (Organization Id)

Responses

Response samples

Content type
application/json
{
  • "category_overrides": {
    },
  • "compound_operator_strategy": {
    },
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "enabled": true,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "license_exceptions": [
    ],
  • "name": "string",
  • "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "unknown_license_category": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Create or update the org-default license policy (super_admin)

path Parameters
organization_id
required
string <uuid> (Organization Id)
Request Body schema: application/json
required
object (Category Overrides)
object (Compound Operator Strategy)
enabled
boolean (Enabled)
Default: true
Array of objects (License Exceptions)
Name (string) or Name (null) (Name)
unknown_license_category
string (Unknown License Category)
Default: "conditional"
Enum: "allowed" "conditional" "forbidden"

Responses

Request samples

Content type
application/json
{
  • "category_overrides": {
    },
  • "compound_operator_strategy": {
    },
  • "enabled": true,
  • "license_exceptions": [
    ],
  • "name": "string",
  • "unknown_license_category": "allowed"
}

Response samples

Content type
application/json
{
  • "category_overrides": {
    },
  • "compound_operator_strategy": {
    },
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "enabled": true,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "license_exceptions": [
    ],
  • "name": "string",
  • "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "unknown_license_category": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Reset (delete) a team's license policy

path Parameters
team_id
required
string <uuid> (Team Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Read the effective license policy for a team

path Parameters
team_id
required
string <uuid> (Team Id)

Responses

Response samples

Content type
application/json
{
  • "category_overrides": {
    },
  • "compound_operator_strategy": {
    },
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "enabled": true,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "license_exceptions": [
    ],
  • "name": "string",
  • "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "unknown_license_category": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Create or update a team's license policy

path Parameters
team_id
required
string <uuid> (Team Id)
Request Body schema: application/json
required
object (Category Overrides)
object (Compound Operator Strategy)
enabled
boolean (Enabled)
Default: true
Array of objects (License Exceptions)
Name (string) or Name (null) (Name)
unknown_license_category
string (Unknown License Category)
Default: "conditional"
Enum: "allowed" "conditional" "forbidden"

Responses

Request samples

Content type
application/json
{
  • "category_overrides": {
    },
  • "compound_operator_strategy": {
    },
  • "enabled": true,
  • "license_exceptions": [
    ],
  • "name": "string",
  • "unknown_license_category": "allowed"
}

Response samples

Content type
application/json
{
  • "category_overrides": {
    },
  • "compound_operator_strategy": {
    },
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "enabled": true,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "license_exceptions": [
    ],
  • "name": "string",
  • "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "unknown_license_category": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Un-waive (remove a license_exceptions entry from the team policy)

path Parameters
team_id
required
string <uuid> (Team Id)
query Parameters
spdx_id
required
string (Spdx Id) [ 1 .. 128 ] characters
Component Purl (string) or Component Purl (null) (Component Purl)

Responses

Response samples

Content type
application/json
{
  • "category_overrides": {
    },
  • "compound_operator_strategy": {
    },
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "enabled": true,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "license_exceptions": [
    ],
  • "name": "string",
  • "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "unknown_license_category": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Waive a license (add a license_exceptions entry to the team policy)

path Parameters
team_id
required
string <uuid> (Team Id)
Request Body schema: application/json
required
Component Purl (string) or Component Purl (null) (Component Purl)
Expires At (string) or Expires At (null) (Expires At)
reason
required
string (Reason) [ 1 .. 1000 ] characters
spdx_id
required
string (Spdx Id) [ 1 .. 128 ] characters

Responses

Request samples

Content type
application/json
{
  • "component_purl": "string",
  • "expires_at": "2019-08-24T14:15:22Z",
  • "reason": "string",
  • "spdx_id": "string"
}

Response samples

Content type
application/json
{
  • "category_overrides": {
    },
  • "compound_operator_strategy": {
    },
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "enabled": true,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "license_exceptions": [
    ],
  • "name": "string",
  • "organization_id": "7c60d51f-b44e-4682-87d6-449835ea4de6",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "unknown_license_category": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

licenses

License finding drawer payload (404 if invisible to caller)

path Parameters
finding_id
required
string <uuid> (Finding Id)

Responses

Response samples

Content type
application/json
{
  • "affected_components": [
    ],
  • "affected_components_total": 0,
  • "affected_components_truncated": false,
  • "category": "allowed",
  • "created_at": "2019-08-24T14:15:22Z",
  • "finding_kind": "declared",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "is_deprecated_license_id": false,
  • "is_fsf_libre": false,
  • "is_osi_approved": false,
  • "license_id": "38cf2dcf-77be-45c4-b03d-412af2743263",
  • "name": "string",
  • "ort_match": { },
  • "reference_url": "string",
  • "spdx_id": "string",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Per-license rows + category distribution for the project's latest scan

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
limit
integer (Limit) [ 1 .. 500 ]
Default: 50
offset
integer (Offset) >= 0
Default: 0
Array of Category (strings) or Category (null) (Category)
Array of Kind (strings) or Kind (null) (Kind)
Search (string) or Search (null) (Search)
sort
string (Sort) ^(category|name|spdx_id|affected_count)$
Default: "category"
order
string (Order) ^(asc|desc)$
Default: "desc"
Scan Id (string) or Scan Id (null) (Scan Id)

Optional release-snapshot anchor (feature #28). When given, list license rows of this SPECIFIC succeeded scan instead of the project's latest succeeded scan. Must belong to this project and be succeeded, else 404. Omit for the default latest-succeeded behaviour.

Responses

Response samples

Content type
application/json
{
  • "distribution": {
    },
  • "items": [
    ],
  • "total": 0
}

notifications

Paginated list of notifications for the authenticated user

query Parameters
unread_only
boolean (Unread Only)
Default: false
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 20

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "page_size": 0,
  • "total": 0,
  • "unread_count": 0
}

Mark all of the caller's unread notifications as read

Responses

Unread notification count for the authenticated user (bell badge)

Responses

Response samples

Content type
application/json
{
  • "count": 0
}

Mark a single notification as read (idempotent)

path Parameters
notification_id
required
string <uuid> (Notification Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

projects

List projects visible to the caller

query Parameters
Team Id (string) or Team Id (null) (Team Id)
include_archived
boolean (Include Archived)
Default: false
Q (string) or Q (null) (Q)
page
integer (Page) >= 1
Default: 1
size
integer (Size) [ 1 .. 100 ]
Default: 20

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "size": 0,
  • "total": 0
}

Create a project (auth required, role >= developer)

Request Body schema: application/json
required
Default Branch (string) or Default Branch (null) (Default Branch)
Description (string) or Description (null) (Description)
Git Url (string) or Git Url (null) (Git Url)
name
required
string (Name) [ 1 .. 255 ] characters
slug
required
string (Slug) [ 1 .. 64 ] characters
team_id
required
string <uuid> (Team Id)
visibility
string (Visibility)
Default: "team"
Enum: "team" "organization"

Responses

Request samples

Content type
application/json
{
  • "default_branch": "string",
  • "description": "string",
  • "git_url": "string",
  • "name": "string",
  • "slug": "string",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "visibility": "team"
}

Response samples

Content type
application/json
{
  • "archived_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "created_by_user_name": "string",
  • "default_branch": "string",
  • "description": "string",
  • "git_url": "string",
  • "has_git_credential": false,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "last_scan_at": "2019-08-24T14:15:22Z",
  • "latest_scan_id": "df070bcd-0cf7-4ee8-8a3b-eea17ac86447",
  • "latest_scan_status": "queued",
  • "license_category_summary": {
    },
  • "name": "string",
  • "release_count": 0,
  • "scan_count": 0,
  • "severity_summary": {
    },
  • "slug": "string",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "visibility": "team"
}

Archive (soft-delete) the project (developer and above)

path Parameters
project_id
required
string <uuid> (Project Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Read one project (IDOR-safe; 403 if not a team member)

path Parameters
project_id
required
string <uuid> (Project Id)

Responses

Response samples

Content type
application/json
{
  • "archived_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "created_by_user_name": "string",
  • "default_branch": "string",
  • "description": "string",
  • "git_url": "string",
  • "has_git_credential": false,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "last_scan_at": "2019-08-24T14:15:22Z",
  • "latest_scan_id": "df070bcd-0cf7-4ee8-8a3b-eea17ac86447",
  • "latest_scan_status": "queued",
  • "license_category_summary": {
    },
  • "name": "string",
  • "release_count": 0,
  • "scan_count": 0,
  • "severity_summary": {
    },
  • "slug": "string",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "visibility": "team"
}

Update mutable project fields (role >= team_admin)

path Parameters
project_id
required
string <uuid> (Project Id)
Request Body schema: application/json
required
clear_git_credential
boolean (Clear Git Credential)
Default: false

Set true to remove a stored git credential (column → NULL). Cannot be combined with a non-empty git_credential.

Default Branch (string) or Default Branch (null) (Default Branch)
Description (string) or Description (null) (Description)
Git Credential (string) or Git Credential (null) (Git Credential)

Write-only plaintext git credential (PAT / deploy token) for cloning a private repo. Encrypted at rest; NEVER returned in any response. Provide a non-empty value to set/rotate it. Omit to leave it unchanged. Use clear_git_credential: true to remove it.

Git Url (string) or Git Url (null) (Git Url)
Name (string) or Name (null) (Name)
Visibility (string) or Visibility (null) (Visibility)

Responses

Request samples

Content type
application/json
{
  • "clear_git_credential": false,
  • "default_branch": "string",
  • "description": "string",
  • "git_credential": "string",
  • "git_url": "string",
  • "name": "string",
  • "visibility": "team"
}

Response samples

Content type
application/json
{
  • "archived_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z",
  • "created_by_user_id": "209f54c4-4c33-43bc-9c6a-ef4c65ad7473",
  • "created_by_user_name": "string",
  • "default_branch": "string",
  • "description": "string",
  • "git_url": "string",
  • "has_git_credential": false,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "last_scan_at": "2019-08-24T14:15:22Z",
  • "latest_scan_id": "df070bcd-0cf7-4ee8-8a3b-eea17ac86447",
  • "latest_scan_status": "queued",
  • "license_category_summary": {
    },
  • "name": "string",
  • "release_count": 0,
  • "scan_count": 0,
  • "severity_summary": {
    },
  • "slug": "string",
  • "team_id": "810007d0-bec5-486c-b5d1-28fcd8a079ba",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "visibility": "team"
}

Paginated component list for the project's latest scan

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
limit
integer (Limit) [ 1 .. 500 ]
Default: 50
offset
integer (Offset) >= 0
Default: 0
Search (string) or Search (null) (Search)
Array of Severity (strings) or Severity (null) (Severity)
Array of License Category (strings) or License Category (null) (License Category)
Direct (boolean) or Direct (null) (Direct)

W2 #31 — Direct/Transitive toggle. true keeps only direct deps (graph depth 1), false only transitive (or graph-less) deps. Omit to include both. BD-equivalent of the 'Dependency type' facet.

Array of Dependency Scope (strings) or Dependency Scope (null) (Dependency Scope)

W2 #31 — BD-style 'Usage' facet. Repeatable; accepted values: required, optional, unspecified (the NULL-scope bucket — common for SBOMs that don't encode scope). Unknown values are dropped, so a query that filters only by unknown values returns an empty page (not a 422). Omit to include all.

sort
string (Sort) ^(name|severity|license)$
Default: "name"
order
string (Order) ^(asc|desc)$
Default: "asc"
Scan Id (string) or Scan Id (null) (Scan Id)

Optional release-snapshot anchor (feature #28). When given, list components of this SPECIFIC succeeded scan instead of the project's latest succeeded scan. Must belong to this project and be succeeded, else 404. Omit for the default latest-succeeded behaviour.

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "limit": 0,
  • "offset": 0,
  • "total": 0
}

Diff two release snapshots (succeeded scans) of the project

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
base
required
string <uuid> (Base)

Base snapshot scan id (typically the OLDER release, e.g. v0.1). Must belong to this project and be succeeded, else 404 (existence-hide).

target
required
string <uuid> (Target)

Target snapshot scan id (typically the NEWER release, e.g. v0.2). Must belong to this project and be succeeded, else 404. base == target is allowed and yields an all-empty diff.

Responses

Response samples

Content type
application/json
{
  • "base": {
    },
  • "components": {
    },
  • "licenses": {
    },
  • "summary": {
    },
  • "target": {
    },
  • "truncated": false,
  • "vulnerabilities": {
    }
}

Aggregated risk / scan picture for the project (Phase 3 Overview tab)

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
Scan Id (string) or Scan Id (null) (Scan Id)

Optional release-snapshot anchor (feature #28). When given, aggregate this SPECIFIC succeeded scan instead of the project's latest succeeded scan. Must belong to this project and be succeeded, else 404. Omit for the default latest-succeeded behaviour.

Responses

Response samples

Content type
application/json
{
  • "current_user_role": "super_admin",
  • "has_git_credential": false,
  • "last_scan_at": "2019-08-24T14:15:22Z",
  • "last_succeeded_scan_at": "2019-08-24T14:15:22Z",
  • "license_distribution": {
    },
  • "license_score": 100,
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "project_name": "string",
  • "recent_scans": [
    ],
  • "risk_score": 100,
  • "security_score": 100,
  • "severity_distribution": {
    },
  • "total_components": 0,
  • "vuln_data_available": true
}

List the project's release snapshots (succeeded scans, newest-first)

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
page
integer (Page) >= 1
Default: 1
size
integer (Size) [ 1 .. 100 ]
Default: 20

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 1,
  • "size": 20,
  • "total": 1
}

Trigger a scan for the project (queues a Celery task; returns 202 Accepted)

path Parameters
project_id
required
string <uuid> (Project Id)
Request Body schema: application/json
required
kind
string (Kind)
Default: "source"
Enum: "source" "container" "sbom"
object (Metadata)

Responses

Request samples

Content type
application/json
{
  • "kind": "source",
  • "metadata": { }
}

Response samples

Content type
application/json
{
  • "celery_task_id": "string",
  • "completed_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z",
  • "current_step": "string",
  • "error_message": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "kind": "source",
  • "metadata": { },
  • "progress_percent": 0,
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "project_name": "string",
  • "project_slug": "string",
  • "ref": "string",
  • "release": "string",
  • "requested_by_user_id": "ed1d5170-d6e9-4e60-8754-78ea9640e9db",
  • "started_at": "2019-08-24T14:15:22Z",
  • "status": "queued",
  • "superseded_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Upload a .zip of local source for scanning (auth required, role >= developer)

path Parameters
project_id
required
string <uuid> (Project Id)
Request Body schema: multipart/form-data
required
upload
required
string <application/octet-stream> (Upload)

A .zip archive of the project source tree.

Responses

Response samples

Content type
application/json
{
  • "archive_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}

compliance

Unified Compliance grid (licenses × obligations) for the project's latest succeeded scan

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
limit
integer (Limit) [ 1 .. 500 ]
Default: 50
offset
integer (Offset) >= 0
Default: 0
Array of Category (strings) or Category (null) (Category)

Filter rows by license category. Repeat the parameter to OR-join multiple values (e.g. ?category=forbidden&category=conditional).

Array of Kind (strings) or Kind (null) (Kind)

Filter rows to licenses that carry at least one obligation of the given kind. Repeat to OR-join.

Search (string) or Search (null) (Search)

Substring match against SPDX id and license name. LIKE metacharacters are escaped server-side.

Has Obligations (boolean) or Has Obligations (null) (Has Obligations)

When true, return only licenses that carry at least one obligation row. When false, return only licenses with NONE. Ignored when kind is also given.

sort
string (Sort) ^(category|license_name|spdx_id|affected_coun...
Default: "category"
order
string (Order) ^(asc|desc)$
Default: "desc"
Scan Id (string) or Scan Id (null) (Scan Id)

Optional release-snapshot anchor (feature #28). When given, the grid reflects this specific succeeded scan instead of the project's latest succeeded scan. Must belong to this project and be succeeded, else 404.

Responses

Response samples

Content type
application/json
{
  • "distribution": {
    },
  • "generated_at": "2019-08-24T14:15:22Z",
  • "items": [
    ],
  • "limit": 1,
  • "offset": 0,
  • "total": 0
}

policy-gate

Evaluate the build-gate verdict for the project's latest succeeded scan

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
Scan Id (string) or Scan Id (null) (Scan Id)

Optional release-snapshot anchor (feature #28). When given, evaluate the build gate against this SPECIFIC succeeded scan instead of the project's latest succeeded scan (so the Overview gate card can reflect a pinned release). Must belong to this project and be succeeded, else 404. Omit for the default latest-succeeded behaviour (the CI contract).

Responses

Response samples

Content type
application/json
{
  • "critical_cve_count": 0,
  • "epss_gate_count": 0,
  • "epss_threshold": 1,
  • "evaluated_at": "2019-08-24T14:15:22Z",
  • "forbidden_license_count": 0,
  • "gate": "pass",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "reachable_critical_cve_count": 0,
  • "reachable_gate_enforced": false,
  • "reason": "string",
  • "scan_id": "9a59f0f5-5572-476d-a7fc-c960ef43a5af"
}

Render an SCA Markdown report and (optionally) post it to a GitHub PR

path Parameters
scan_id
required
string <uuid> (Scan Id)
Request Body schema: application/json
required
dry_run
boolean (Dry Run)
Default: false

When true the endpoint builds the Markdown comment but does not call GitHub. Useful for local CI rehearsals and used by the default integration tests so they do not require network access.

pr_number
required
integer (Pr Number) [ 1 .. 10000000 ]

GitHub PR number.

repo_full_name
required
string (Repo Full Name) [ 3 .. 140 ] characters

GitHub owner/repo slug. Validated against the GitHub naming rules so we never call api.github.com with attacker-controlled path segments.

Responses

Request samples

Content type
application/json
{
  • "dry_run": false,
  • "pr_number": 1,
  • "repo_full_name": "string"
}

Response samples

Content type
application/json
{
  • "body_preview": "string",
  • "comment_id": 0,
  • "comment_url": "string",
  • "gate": "pass",
  • "status": "posted"
}

obligations

Compose a NOTICE attribution body for the project's latest scan

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
format
string (Format) ^(text|markdown|html)$
Default: "text"

Output format. text returns text/plain, markdown returns text/markdown, html returns a self-contained text/html document.

download
boolean (Download)
Default: false

When true, set Content-Disposition: attachment so browsers save the body as a file. Default is inline.

Responses

Response samples

Content type
null

Per-(license, kind) obligation rows + distribution for the project's latest scan

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
limit
integer (Limit) [ 1 .. 500 ]
Default: 50
offset
integer (Offset) >= 0
Default: 0
Array of Kind (strings) or Kind (null) (Kind)
Array of Category (strings) or Category (null) (Category)
Search (string) or Search (null) (Search)
sort
string (Sort) ^(category|license_name|kind|affected_count)$...
Default: "category"
order
string (Order) ^(asc|desc)$
Default: "desc"
Scan Id (string) or Scan Id (null) (Scan Id)

Optional release-snapshot anchor (feature #28). When given, list obligation rows of this SPECIFIC succeeded scan instead of the project's latest succeeded scan. Must belong to this project and be succeeded, else 404. Omit for the default latest-succeeded behaviour.

Responses

Response samples

Content type
application/json
{
  • "distribution": {
    },
  • "items": [
    ],
  • "total": 0
}

Obligation drawer payload (404 if invisible to caller within this project)

path Parameters
project_id
required
string <uuid> (Project Id)
obligation_id
required
string <uuid> (Obligation Id)

Responses

Response samples

Content type
application/json
{
  • "affected_components": [
    ],
  • "affected_components_total": 0,
  • "affected_components_truncated": false,
  • "created_at": "2019-08-24T14:15:22Z",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "kind": "string",
  • "license_category": "allowed",
  • "license_id": "38cf2dcf-77be-45c4-b03d-412af2743263",
  • "license_name": "string",
  • "license_reference_url": "string",
  • "license_spdx_id": "string",
  • "link": "string",
  • "text": "string",
  • "text_truncated": false,
  • "updated_at": "2019-08-24T14:15:22Z"
}

remediation

Preview the npm dependency-bump edit for a project (dry-run, no PR)

path Parameters
project_id
required
string <uuid> (Project Id)
Request Body schema: application/json
Any of
Manifest (string) or Manifest (null) (Manifest)

Raw package.json text to edit. When omitted, the endpoint reads the manifest from the latest preserved scan source (best-effort).

Any of
string (Manifest)

Raw package.json text to edit. When omitted, the endpoint reads the manifest from the latest preserved scan source (best-effort).

Responses

Request samples

Content type
application/json
Example
{
  • "manifest": "{\n \"name\": \"demo\",\n \"dependencies\": {\n \"lodash\": \"^4.17.20\"\n }\n}\n"
}

Response samples

Content type
application/json
{
  • "changed": true,
  • "changes": [
    ],
  • "ecosystem": "npm",
  • "edited_manifest": "{\n \"name\": \"demo\",\n \"dependencies\": {\n \"lodash\": \"^4.17.21\"\n }\n}\n",
  • "manifest_found": true,
  • "manifest_source": "preserved_source",
  • "notes": [ ],
  • "project_id": "5b8f1c2e-0c2a-4a1e-9c3d-9c2b1a0f7e11",
  • "recommendations": [
    ],
  • "scan_id": "7a1d2c3b-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
  • "warnings": [
    ]
}

Open an automated npm remediation PR on the project's opted-in repo

Open (or return the existing) automated npm remediation PR.

team_admin RBAC + opt-in enforcement live in the service. Returns 201 for a freshly opened PR, 200 for an idempotent hit on an existing open PR, and 204 when there is nothing to remediate.

path Parameters
project_id
required
string <uuid> (Project Id)
Request Body schema: application/json
Any of
Manifest (string) or Manifest (null) (Manifest)

Raw package.json text to edit. When omitted, the service reads the manifest from the latest preserved scan source (best-effort).

Any of
string (Manifest)

Raw package.json text to edit. When omitted, the service reads the manifest from the latest preserved scan source (best-effort).

Responses

Request samples

Content type
application/json
Example
{
  • "manifest": "{\n \"name\": \"demo\",\n \"dependencies\": {\n \"lodash\": \"^4.17.20\"\n }\n}\n"
}

Response samples

Content type
application/json
{
  • "base_branch": "main",
  • "created_at": "2026-05-25T12:00:00Z",
  • "ecosystem": "npm",
  • "head_branch": "trustedoss/remediation-1a2b3c4d",
  • "id": "9c2b1a0f-7e11-4a1e-9c3d-5b8f1c2e0c2a",
  • "package_changes": [
    ],
  • "pr_number": 42,
  • "project_id": "5b8f1c2e-0c2a-4a1e-9c3d-9c2b1a0f7e11",
  • "repository_full_name": "acme/widget",
  • "status": "open",
  • "updated_at": "2026-05-25T12:00:01Z"
}

List the project's automated remediation PR records

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
page
integer (Page) >= 1
Default: 1
page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "total": 1
}

reports

List download / export history for the project's Reports center

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
Array of Type (strings) or Type (null) (Type)

Optional filter — one or more report_type values to include. Repeat the parameter (?type=notice&type=sbom) for multi-select. Omit for all four types.

Scan Id (string) or Scan Id (null) (Scan Id)

Optional filter — return only rows where scan_id matches. Pair with type=sbom etc. to find all artefacts produced for one scan.

page
integer (Page) >= 1
Default: 1

1-based page number.

page_size
integer (Page Size) [ 1 .. 200 ]
Default: 50

Rows per page (1..200, default 50).

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 1,
  • "page_size": 1,
  • "total": 0
}

Download a vulnerability PDF report for the project's latest scan

path Parameters
project_id
required
string <uuid> (Project Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

sbom

Export SBOM for the project's latest succeeded scan

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
format
string (Format)
Default: "cyclonedx-json"
Enum: "cyclonedx-json" "cyclonedx-xml" "spdx-json" "spdx-tv"

SBOM output format.

Scan Id (string) or Scan Id (null) (Scan Id)

Optional release-snapshot anchor (feature #28). When given, export this SPECIFIC succeeded scan instead of the project's latest succeeded scan. Must belong to this project and be succeeded, else 404. Omit for the default latest-succeeded behaviour.

Responses

Download the in-toto / SLSA provenance attestation for the latest SBOM

path Parameters
project_id
required
string <uuid> (Project Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Download the Fulcio certificate for the attestation (keyless signing only)

path Parameters
project_id
required
string <uuid> (Project Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Download the Fulcio signing certificate (keyless signing only)

path Parameters
project_id
required
string <uuid> (Project Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Download the cosign public key for verifying SBOM signatures

path Parameters
project_id
required
string <uuid> (Project Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Download the detached cosign signature for the latest SBOM

path Parameters
project_id
required
string <uuid> (Project Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Download a zip bundle (SBOM + signature + cert/public-key + attestation + README)

path Parameters
project_id
required
string <uuid> (Project Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

scans

List scans for a project (most recent first)

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
page
integer (Page) >= 1
Default: 1
size
integer (Size) [ 1 .. 100 ]
Default: 20

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "size": 0,
  • "total": 0
}

List scans across every project accessible to the caller

query Parameters
Status (string) or Status (null) (Status)

Filter by scan status.

page
integer (Page) >= 1
Default: 1
size
integer (Size) [ 1 .. 100 ]
Default: 20

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "page": 0,
  • "size": 0,
  • "total": 0
}

Delete a terminal scan and its findings (own-team scans only)

Hard-delete a terminal scan and (via cascade) its findings / components.

DT-style retention reclaims most stale scans automatically; this is the manual escape hatch. Auth: any team member (developer+). The owning-team check lives in the service (delete_scan), which existence-hides other teams' scans as 404. Active scans (queued/running) return 409 — cancel first. A release-labelled scan returns 409 unless force=true.

path Parameters
scan_id
required
string <uuid> (Scan Id)
query Parameters
force
boolean (Force)
Default: false

Delete even when the scan carries an explicit metadata.release label. Release-labelled snapshots are immutable by default.

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

Read one scan (IDOR-safe via project team membership)

path Parameters
scan_id
required
string <uuid> (Scan Id)

Responses

Response samples

Content type
application/json
{
  • "celery_task_id": "string",
  • "completed_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z",
  • "current_step": "string",
  • "error_message": "string",
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "kind": "source",
  • "metadata": { },
  • "progress_percent": 0,
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "project_name": "string",
  • "project_slug": "string",
  • "ref": "string",
  • "release": "string",
  • "requested_by_user_id": "ed1d5170-d6e9-4e60-8754-78ea9640e9db",
  • "started_at": "2019-08-24T14:15:22Z",
  • "status": "queued",
  • "superseded_at": "2019-08-24T14:15:22Z",
  • "updated_at": "2019-08-24T14:15:22Z"
}

Cancel a queued / running scan owned by the caller's team

Cancel one of the caller's own team's scans.

PR-A1 (scan stability). Auth: any authenticated team member (developer or higher). The owning-team check lives in the service (cancel_scan_for_actor) which existence-hides other teams' scans as 404 — so a developer cannot probe scan ids belonging to other teams.

Admin force-cancel (POST /v1/admin/scans/{id}/cancel) remains separate and cross-team; the two share the same revoke + status-mutation core.

path Parameters
scan_id
required
string <uuid> (Scan Id)

Responses

Response samples

Content type
application/json
null

Download the persisted tool log for one scan

Stream the per-scan scan.log written by tasks._progress.publish_log.

Authorization: same gate as GET /v1/scans/{scan_id} — reuses services.scan_service.get_scan so team-membership / super-admin rules stay in lock-step with the metadata endpoint. A non-member sees the same 404 as a non-existent scan id (existence-hide) so a developer cannot probe scan ids belonging to other teams via this endpoint.

Lifecycle: the file is written incrementally by the worker as the scan runs. While the scan is still running the response returns whatever has been flushed so far (the publisher uses a line-buffered handle, so each completed line is on disk by the time it is on the WebSocket). After the scan terminates the file stays on disk until workspace_cleaner reaps the parent workspace directory (current default: per WORKSPACE_ORPHAN_MAX_AGE_SECONDS).

path Parameters
scan_id
required
string <uuid> (Scan Id)

Responses

Response samples

Content type
null

source-tree

Read one file from a scan's preserved source + per-line license matches

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
path
required
string (Path)

File to read, relative to the source root.

Scan Id (string) or Scan Id (null) (Scan Id)

Scan to read; defaults to the project's latest scan.

raw
boolean (Raw)
Default: false

When true, stream the FULL member as application/octet-stream (no per-file viewer cap) for download instead of the capped JSON preview. Same path-traversal / symlink defences apply.

Responses

Response samples

Content type
{
  • "byte_size": 1071,
  • "content": "MIT License\n\nCopyright (c) ...",
  • "encoding": "utf-8",
  • "license_matches": [
    ],
  • "path": "LICENSE",
  • "scan_id": "5b6c0f2e-3a1d-4e8a-9b2c-7d4e1f0a9c33",
  • "truncated": false
}

List immediate children of a directory in a scan's preserved source

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
path
string (Path)
Default: ""

Directory whose immediate children to list. Empty = root.

page
integer (Page) >= 1
Default: 1

1-based page index.

size
integer (Size) [ 1 .. 500 ]
Default: 100

Page size (max 500).

Scan Id (string) or Scan Id (null) (Scan Id)

Scan to read; defaults to the project's latest scan.

Responses

Response samples

Content type
application/json
{
  • "entries": [
    ],
  • "page": 1,
  • "path": "src",
  • "scan_id": "5b6c0f2e-3a1d-4e8a-9b2c-7d4e1f0a9c33",
  • "size": 50,
  • "total": 1
}

vex

Export a VEX document from the project's current finding triage

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
format
string (Format)
Default: "openvex"
Enum: "openvex" "cyclonedx"

VEX output format.

Responses

Import a VEX document, auto-transitioning matching findings (team_admin)

path Parameters
project_id
required
string <uuid> (Project Id)
Request Body schema: multipart/form-data
required
upload
required
string <application/octet-stream> (Upload)

An OpenVEX or CycloneDX VEX JSON document (format auto-detected).

Responses

Response samples

Content type
application/json
{
  • "applied": 0,
  • "errors": [
    ],
  • "format": "openvex",
  • "matched": 0,
  • "skipped": 0
}

vulnerabilities

Paginated CVE findings for the project's latest scan

path Parameters
project_id
required
string <uuid> (Project Id)
query Parameters
limit
integer (Limit) [ 1 .. 500 ]
Default: 50
offset
integer (Offset) >= 0
Default: 0
Search (string) or Search (null) (Search)
Array of Severity (strings) or Severity (null) (Severity)
Array of Status (strings) or Status (null) (Status)
Array of License Category (strings) or License Category (null) (License Category)

W2 #33 — License risk-axis filter. Repeatable; accepted values: forbidden, conditional, allowed, unknown (the cv had no license finding in this scan). Unknown values are dropped, so a query that filters ONLY by unknown values returns an empty page (not a 422). Omit to include all categories.

Min Epss (number) or Min Epss (null) (Min Epss)

Keep only findings whose CVE has an EPSS exploit-probability >= this threshold, in [0, 1]. CVEs with no published EPSS score are excluded. Omit to disable EPSS filtering.

Reachable (string) or Reachable (null) (Reachable)

Tri-state reachability filter (v2.3). true → only findings whose vulnerable symbol is reachable on the call graph; false → only findings an analyser proved NOT reachable; unknown → only not-analysed findings (reachable IS NULL). Omit to disable the reachability filter.

sort
string (Sort) ^(severity|cvss|status|discovered_at|epss|rea...
Default: "severity"

Sort key. reachable ranks reachable findings first (then not-analysed, then proven-unreachable), tie-broken by severity desc. component sorts by affected package name.

order
string (Order) ^(asc|desc)$
Default: "desc"
Scan Id (string) or Scan Id (null) (Scan Id)

Optional release-snapshot anchor (feature #28). When given, list CVE findings of this SPECIFIC succeeded scan instead of the project's latest succeeded scan. Must belong to this project and be succeeded, else 404. Omit for the default latest-succeeded behaviour.

Responses

Response samples

Content type
application/json
{
  • "items": [
    ],
  • "limit": 0,
  • "offset": 0,
  • "severity_distribution": {
    },
  • "total": 0
}

Transition many findings in one project to the same VEX status

W2 #33b — apply one VEX transition across many findings in one round-trip.

Per-row failures (404 / 403 / 422) are surfaced in the response envelope so the UI can render "succeeded N · failed M" with per-row details. Only envelope-level shape violations (empty list, > cap, unknown enum) return RFC 7807 — those would still abort a per-row partial commit, so they belong on the envelope rather than masquerading as per-row outcomes.

path Parameters
project_id
required
string <uuid> (Project Id)
Request Body schema: application/json
required
finding_ids
required
Array of strings <uuid> (Finding Ids) [ 1 .. 200 ] items [ items <uuid > ]

Finding ids to transition. 1..200 entries; duplicates are deduplicated server-side. Ids that do not exist in THIS project (cross-project / cross-team / never-existed) are reported as a per-row 404 — they do not abort the bulk.

Justification (string) or Justification (null) (Justification)

Free-form note recorded as analysis_justification on every successfully-transitioned row. Omit to leave each row's existing justification untouched.

target_status
required
string (Target Status)
Enum: "new" "analyzing" "exploitable" "not_affected" "false_positive" "suppressed" "fixed"

Target status applied to every supplied id. Per-row transition-matrix and role checks still run (developer → suppressed is blocked per row even in a bulk that contains it).

Responses

Request samples

Content type
application/json
{
  • "finding_ids": [
    ],
  • "justification": "string",
  • "target_status": "new"
}

Response samples

Content type
application/json
{
  • "failed": 0,
  • "results": [
    ],
  • "succeeded": 0,
  • "target_status": "new",
  • "total": 1
}

Vulnerability finding drawer payload (404 if invisible to caller)

path Parameters
finding_id
required
string <uuid> (Finding Id)

Responses

Response samples

Content type
application/json
{
  • "affected_components": [
    ],
  • "analysis_justification": "string",
  • "analysis_source": "manual",
  • "analysis_state": "string",
  • "analyst_user_id": "0983c53a-1216-4076-815a-f64301f7aa2c",
  • "analyzed_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z",
  • "cve_id": "string",
  • "cvss_score": 0,
  • "cvss_vector": "string",
  • "details": "string",
  • "epss_percentile": 0.99412,
  • "epss_score": 0.97123,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "published_at": "2019-08-24T14:15:22Z",
  • "reachability_analyzed_at": "2019-08-24T14:15:22Z",
  • "reachability_source": "govulncheck",
  • "reachable": true,
  • "references": [
    ],
  • "scan_id": "9a59f0f5-5572-476d-a7fc-c960ef43a5af",
  • "severity": "critical",
  • "status": "new",
  • "status_history": [
    ],
  • "summary": "string",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "upgrade_recommendation": {
    },
  • "vex_origin": {
    }
}

Transition a vulnerability finding's VEX status (audit-logged)

path Parameters
finding_id
required
string <uuid> (Finding Id)
Request Body schema: application/json
required
If Match (string) or If Match (null) (If Match)

Optional optimistic-concurrency token. When supplied, the server compares this against the current row's updated_at. Mismatch → 409 Conflict (RFC 7807). When omitted, the update proceeds without lock (best-effort).

Justification (string) or Justification (null) (Justification)

Free-form note recorded as analysis_justification. Required by the UI for VEX-significant transitions but enforced softly: the API accepts an empty justification (regulators often re-trigger the transition once with the note attached).

status
required
string (Status)
Enum: "new" "analyzing" "exploitable" "not_affected" "false_positive" "suppressed" "fixed"

Target status.

Responses

Request samples

Content type
application/json
{
  • "if_match": "2019-08-24T14:15:22Z",
  • "justification": "string",
  • "status": "new"
}

Response samples

Content type
application/json
{
  • "affected_components": [
    ],
  • "analysis_justification": "string",
  • "analysis_source": "manual",
  • "analysis_state": "string",
  • "analyst_user_id": "0983c53a-1216-4076-815a-f64301f7aa2c",
  • "analyzed_at": "2019-08-24T14:15:22Z",
  • "created_at": "2019-08-24T14:15:22Z",
  • "cve_id": "string",
  • "cvss_score": 0,
  • "cvss_vector": "string",
  • "details": "string",
  • "epss_percentile": 0.99412,
  • "epss_score": 0.97123,
  • "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  • "project_id": "405d8375-3514-403b-8c43-83ae74cfe0e9",
  • "published_at": "2019-08-24T14:15:22Z",
  • "reachability_analyzed_at": "2019-08-24T14:15:22Z",
  • "reachability_source": "govulncheck",
  • "reachable": true,
  • "references": [
    ],
  • "scan_id": "9a59f0f5-5572-476d-a7fc-c960ef43a5af",
  • "severity": "critical",
  • "status": "new",
  • "status_history": [
    ],
  • "summary": "string",
  • "updated_at": "2019-08-24T14:15:22Z",
  • "upgrade_recommendation": {
    },
  • "vex_origin": {
    }
}

users-me

Return the caller's notification preferences (creates defaults)

Responses

Response samples

Content type
application/json
{
  • "email_enabled": true,
  • "in_app_enabled": true,
  • "slack_enabled": true,
  • "teams_enabled": true
}

Replace the caller's notification preferences (full-row PUT)

Full-row update — every channel field must be supplied.

The body's only meaningful inputs are the four channel toggles. Any additional fields a caller may send (user_id, id, ...) are ignored: Pydantic strips unknown fields by default and the service is keyed off actor.id, never the body.

Chore O / M3 — In-app notifications cannot be disabled. The frontend documents the in-app switch as "rendered but disabled"; this server- side guard closes the API drift where a direct PUT could opt out.

Request Body schema: application/json
required
email_enabled
required
boolean (Email Enabled)
in_app_enabled
required
boolean (In App Enabled)
slack_enabled
required
boolean (Slack Enabled)
teams_enabled
required
boolean (Teams Enabled)

Responses

Request samples

Content type
application/json
{
  • "email_enabled": true,
  • "in_app_enabled": true,
  • "slack_enabled": true,
  • "teams_enabled": true
}

Response samples

Content type
application/json
{
  • "email_enabled": true,
  • "in_app_enabled": true,
  • "slack_enabled": true,
  • "teams_enabled": true
}

List the caller's connected OAuth identities (sorted oldest-first)

Responses

Response samples

Content type
application/json
{
  • "has_password": true,
  • "items": [
    ]
}

Unlink one of the caller's OAuth identities

Remove an OAuth identity link from the authenticated user.

Returns 204 on success. Domain failures map to RFC 7807:

  • 404 urn:trustedoss:problem:oauth_identity_not_found — identity does not exist OR belongs to another user (existence-hide; the two cases share a shape).
  • 409 urn:trustedoss:problem:oauth_unlink_blocks_login — unlinking would leave the user with no way to authenticate.
path Parameters
identity_id
required
string <uuid> (Identity Id)

Responses

Response samples

Content type
application/json
{
  • "detail": [
    ]
}

webhooks

Receive a GitHub webhook delivery

header Parameters
X-Hub-Signature-256 (string) or X-Hub-Signature-256 (null) (X-Hub-Signature-256)
X-Github-Event (string) or X-Github-Event (null) (X-Github-Event)
X-Github-Delivery (string) or X-Github-Delivery (null) (X-Github-Delivery)

Responses

Response samples

Content type
application/json
null

Receive a GitLab webhook delivery

header Parameters
X-Gitlab-Token (string) or X-Gitlab-Token (null) (X-Gitlab-Token)
X-Gitlab-Event (string) or X-Gitlab-Event (null) (X-Gitlab-Event)
X-Gitlab-Webhook-Uuid (string) or X-Gitlab-Webhook-Uuid (null) (X-Gitlab-Webhook-Uuid)

Responses

Response samples

Content type
application/json
null