Skip to content

CLI Integration

How clef report communicates with Clef Pro.

Authentication

All CLI endpoints use API key authentication:

x-api-key: clef_<token>

The API key resolves to a specific team and integration. No JWT or OAuth required.

Flow

1. Fetch config and last known state

GET /api/v1/integrations/:integrationId

The CLI reads two fields from the response:

  • lastCommitSha — the commit hash of the most recent report (null if first run)
  • config — collection settings (e.g. whether to include CI context)

2. Determine what to report

bash
if lastCommitSha is null:
  # First report — evaluate HEAD only
  commits = [HEAD]

elif lastCommitSha == HEAD:
  # Up to date — nothing to do
  exit 0

else:
  # Backfill — all commits since last report
  commits = $(git log <lastCommitSha>..HEAD --reverse)

3. Evaluate locally

For each commit, the CLI:

  • Checks out the commit
  • Evaluates each namespace/environment for health status
  • Computes drift across environments per namespace
  • Evaluates policy rules (configured on the integration)
  • Composes human-readable descriptions — no raw metadata leaves the CI

4. Submit

Single commit:

POST /api/v1/reports

Multiple commits (backfill):

POST /api/v1/reports/batch

Report schema

Single report body

json
{
  "commitSha": "a1b2c3d4e5f6...",
  "commitTimestamp": 1700000000000,
  "branch": "main",
  "cliVersion": "1.0.0",

  "summary": {
    "filesScanned": 12,
    "namespaces": ["database", "oauth"],
    "environments": ["production", "staging"],
    "cells": [
      {
        "namespace": "database",
        "environment": "production",
        "healthStatus": "healthy",
        "description": "4 keys, 3 recipients, rotated 12d ago"
      }
    ],
    "violations": 1,
    "passed": false
  },

  "drift": [
    {
      "namespace": "database",
      "isDrifted": true,
      "severity": "warning",
      "summary": "Development has an additional recipient"
    }
  ],

  "policyResults": [
    {
      "ruleId": "missing_keys",
      "ruleName": "Missing encryption keys",
      "passed": false,
      "severity": "critical",
      "message": "Missing key detected in oauth/production",
      "scope": "oauth/production"
    }
  ],

  "ci": {
    "provider": "github_actions",
    "pipelineUrl": "https://github.com/acme/platform/actions/runs/123",
    "triggeredBy": "push"
  }
}

Batch report body

json
{
  "cliVersion": "1.0.0",
  "reports": [
    { "commitSha": "oldest...", "commitTimestamp": 1700000000000, "branch": "main", "summary": {}, "drift": [], "policyResults": [] },
    { "commitSha": "middle...", "commitTimestamp": 1700001000000, "branch": "main", "summary": {}, "drift": [], "policyResults": [] },
    { "commitSha": "head...", "commitTimestamp": 1700002000000, "branch": "main", "summary": {}, "drift": [], "policyResults": [], "ci": {} }
  ]
}
  • Max 500 reports per batch
  • Ordered oldest → newest (last = HEAD)
  • Alerts generated only from the last report

Idempotency

Reports are keyed by commit hash. Submitting the same commit twice overwrites the previous record. This is an upsert, not an insert.

  • Single report retries: safe, always overwrites
  • Batch retries: safe, every report in the batch overwrites its previous version
  • Partial batch retries: safe, already-written reports get overwritten with identical data

The retry logic is: if you didn't get a 201, send the same request again. No dedup tokens, no delta computation.

The report tracks createdAt (first write, preserved on retry) and updatedAt (every write). If they differ, the report was retried.

Responses

Single report (201)

json
{
  "data": {
    "reportId": "a1b2c3d...",
    "passed": false,
    "violations": 1,
    "alertsGenerated": 1
  },
  "success": true
}

Batch report (201)

json
{
  "data": {
    "reportsWritten": 15,
    "alertsGenerated": 1
  },
  "success": true
}

Errors

StatusMeaningAction
201SuccessDone
400Validation error (bad schema)Fix payload
401Invalid or revoked API keyFix key
500Server errorRetry (idempotent)
TimeoutUnknown stateRetry (idempotent)