Skip to content

Safety

View as Markdown

The Safety Centre grade (A to E), its checks and fixes, and the public badge.

Operation Method and path
Safety Centre grade and checks GET /v1/projects/{project}/safety
Re-run every safety check now POST /v1/projects/{project}/safety/scan
Apply a finding’s one-click fix (or open an AI fix PR) POST /v1/projects/{project}/safety/checks/{check_id}/fix
Acknowledge a finding (accept the risk) POST /v1/projects/{project}/safety/checks/{check_id}/acknowledge
Public badge summary GET /v1/public/safety/{badge_id}
Public badge image GET /v1/public/safety/{badge_id}/badge.svg
GET /v1/projects/{project}/safety
  • Operation: getSafetyReport
  • Scopes: safety:read

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).
environment query string Defaults to production.

Responses

Status Meaning Body
200 OK OK. SafetyReport

Errors: 400, 401, 403, 404, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl https://api.guv.dev/v1/projects/shopfront/safety \
-H "Authorization: Bearer $GUV_TOKEN"

Example response

{
"project_id": "string",
"environment": "string",
"grade": "A",
"score": 0,
"summary": "Grade B. One thing to fix: members without passkeys.",
"counts": {
"pass": 1,
"warn": 1,
"fail": 1
},
"checks": [
{
"id": "chk_01jbx2m9k7q4r8t5v6w3y0z1ck",
"category": "secrets_in_bundle",
"status": "fail",
"severity": "critical",
"title": "Secret visible in your website's code",
"finding": "Your SUPABASE_SERVICE_ROLE_KEY is visible to anyone visiting your site.",
"environment": "production",
"resource": {
"type": "service",
"id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv",
"name": "web"
},
"blocks_deploy": true,
"fix": [
{
"kind": "manual",
"label": "Rotate the key in Supabase, then update it here",
"command": "guv secrets rotate SUPABASE_SERVICE_ROLE_KEY --env production"
},
{
"kind": "open_pr",
"label": "Ask AI to move the key server-side (opens a PR)"
}
],
"acknowledged": null,
"detected_at": "2026-10-23T14:03:00Z",
"resolved_at": null
}
],
"badge": {
"enabled": false,
"url": "https://guv.dev/",
"svg_url": "https://guv.dev/"
},
"checked_at": "2026-10-22T13:05:00Z"
}
POST /v1/projects/{project}/safety/scan
  • Operation: runSafetyScan
  • Scopes: safety:read
  • Idempotency-Key: required

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).

Responses

Status Meaning Body
202 Accepted Accepted. The work continues in the background; follow the operation. Operation

Errors: 400, 401, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl -X POST https://api.guv.dev/v1/projects/shopfront/safety/scan \
-H "Authorization: Bearer $GUV_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"

Example response

{
"id": "op_01jbx2m9k7q4r8t5v6w3y0z1op",
"kind": "deployment.create",
"status": "running",
"summary": "Deploying web to production",
"workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws",
"project_id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr",
"environment_id": "env_01jbx2m9k7q4r8t5v6w3y0z1en",
"resource": {
"type": "deployment",
"id": "dep_01jbx2m9k7q4r8t5v6w3y0z1dp",
"url": "/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1dp"
},
"progress": {
"current_step": "build",
"completed_steps": 1,
"total_steps": 6,
"percent": 20
},
"steps": [
{
"name": "resolve",
"title": "Reading your settings",
"status": "succeeded",
"attempt": 1,
"started_at": "2026-10-23T14:02:00Z",
"finished_at": "2026-10-23T14:02:01Z"
},
{
"name": "build",
"title": "Building your app",
"status": "running",
"attempt": 1,
"started_at": "2026-10-23T14:02:01Z",
"finished_at": null
}
],
"created_by": {
"type": "user",
"id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us",
"display": "Stewart Webb"
},
"created_at": "2026-10-23T14:02:00Z",
"links": {
"self": "/v1/operations/op_01jbx2m9k7q4r8t5v6w3y0z1op",
"events": "/v1/operations/op_01jbx2m9k7q4r8t5v6w3y0z1op/events",
"resource": "/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1dp"
}
}

Apply a finding’s one-click fix (or open an AI fix PR)

Section titled “Apply a finding’s one-click fix (or open an AI fix PR)”
POST /v1/projects/{project}/safety/checks/{check_id}/fix
  • Operation: applySafetyFix
  • Scopes: safety:write
  • Approval: In environments with protection turned on (usually production), changes by agents and by roles outside approver_roles return approval_required.
  • Idempotency-Key: required; supports ?dry_run=true

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).
check_id * path string Safety check id.
action query integer Index into the check’s fix array.

Responses

Status Meaning Body
200 OK Dry run. Nothing was changed; this is what would happen. Plan
202 Accepted Accepted. The work continues in the background; follow the operation. Operation

Errors: 400, 401, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl -X POST https://api.guv.dev/v1/projects/shopfront/safety/checks/che_01jbx2m9k7q4r8t5v6w3y0z1pr/fix \
-H "Authorization: Bearer $GUV_TOKEN" \
-H "Idempotency-Key: $(uuidgen)"

Example response

{
"id": "op_01jbx2m9k7q4r8t5v6w3y0z1op",
"kind": "deployment.create",
"status": "running",
"summary": "Deploying web to production",
"workspace_id": "ws_01jbx2m9k7q4r8t5v6w3y0z1ws",
"project_id": "prj_01jbx2m9k7q4r8t5v6w3y0z1pr",
"environment_id": "env_01jbx2m9k7q4r8t5v6w3y0z1en",
"resource": {
"type": "deployment",
"id": "dep_01jbx2m9k7q4r8t5v6w3y0z1dp",
"url": "/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1dp"
},
"progress": {
"current_step": "build",
"completed_steps": 1,
"total_steps": 6,
"percent": 20
},
"steps": [
{
"name": "resolve",
"title": "Reading your settings",
"status": "succeeded",
"attempt": 1,
"started_at": "2026-10-23T14:02:00Z",
"finished_at": "2026-10-23T14:02:01Z"
},
{
"name": "build",
"title": "Building your app",
"status": "running",
"attempt": 1,
"started_at": "2026-10-23T14:02:01Z",
"finished_at": null
}
],
"created_by": {
"type": "user",
"id": "usr_01jbx2m9k7q4r8t5v6w3y0z1us",
"display": "Stewart Webb"
},
"created_at": "2026-10-23T14:02:00Z",
"links": {
"self": "/v1/operations/op_01jbx2m9k7q4r8t5v6w3y0z1op",
"events": "/v1/operations/op_01jbx2m9k7q4r8t5v6w3y0z1op/events",
"resource": "/v1/deployments/dep_01jbx2m9k7q4r8t5v6w3y0z1dp"
}
}
POST /v1/projects/{project}/safety/checks/{check_id}/acknowledge

Acknowledged findings still count towards the grade. Findings that block deploys cannot be acknowledged.

  • Operation: acknowledgeSafetyCheck
  • Scopes: safety:write
  • Idempotency-Key: required; supports ?dry_run=true

Parameters

Name In Type Description
project * path string Project id (prj_…) or slug (resolved in the Guv-Workspace workspace, or the caller’s default).
check_id * path string Safety check id.

Request body (application/json, required): SafetyAcknowledge

Field Type Description
reason * string
until string (date-time)

Responses

Status Meaning Body
200 OK OK. With dry_run=true: a Plan (application/vnd.guv.plan+json) and nothing changes. SafetyCheck

Errors: 400, 401, 403, 404, 409, 422, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl -X POST https://api.guv.dev/v1/projects/shopfront/safety/checks/che_01jbx2m9k7q4r8t5v6w3y0z1pr/acknowledge \
-H "Authorization: Bearer $GUV_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"reason": "string",
"until": "2026-10-22T13:05:00Z"
}'

Example response

{
"id": "chk_01jbx2m9k7q4r8t5v6w3y0z1ck",
"category": "secrets_in_bundle",
"status": "fail",
"severity": "critical",
"title": "Secret visible in your website's code",
"finding": "Your SUPABASE_SERVICE_ROLE_KEY is visible to anyone visiting your site.",
"environment": "production",
"resource": {
"type": "service",
"id": "svc_01jbx2m9k7q4r8t5v6w3y0z1sv",
"name": "web"
},
"blocks_deploy": true,
"fix": [
{
"kind": "manual",
"label": "Rotate the key in Supabase, then update it here",
"command": "guv secrets rotate SUPABASE_SERVICE_ROLE_KEY --env production"
},
{
"kind": "open_pr",
"label": "Ask AI to move the key server-side (opens a PR)"
}
],
"acknowledged": null,
"detected_at": "2026-10-23T14:03:00Z",
"resolved_at": null
}
GET /v1/public/safety/{badge_id}
  • Operation: getPublicSafetySummary
  • Scopes: none (public)

Parameters

Name In Type Description
badge_id * path string Public, unguessable badge id of a project.

Responses

Status Meaning Body
200 OK OK. SafetyBadgeSummary

Errors: 400, 404, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl https://api.guv.dev/v1/public/safety/bad_01jbx2m9k7q4r8t5v6w3y0z1pr \
-H "Authorization: Bearer $GUV_TOKEN"

Example response

{
"project_name": "string",
"grade": "A",
"checked_at": "2026-10-22T13:05:00Z",
"data_location": "London, UK",
"categories": [
{
"category": "secrets_in_code",
"label": "string",
"status": "pass"
}
]
}
GET /v1/public/safety/{badge_id}/badge.svg
  • Operation: getPublicSafetyBadge
  • Scopes: none (public)

Parameters

Name In Type Description
badge_id * path string Public, unguessable badge id of a project.

Responses

Status Meaning Body
200 OK OK string

Errors: 400, 404, 429, 500, as problem+json with a stable code.

Example

Terminal window
curl https://api.guv.dev/v1/public/safety/bad_01jbx2m9k7q4r8t5v6w3y0z1pr/badge.svg \
-H "Authorization: Bearer $GUV_TOKEN"

Example response

"string"