> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kguardian.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Seccomp Endpoints

> Per-workload seccomp profiles, distribution readiness, overrides, and node status

These endpoints expose the per-workload seccomp profiles the broker builds from
observed syscalls. See the
[Distributing Seccomp Profiles](/guides/distributing-seccomp-profiles) guide for
the workflow.

Every rendered profile is the **effective** profile:
`(observed ∪ override.add) \ override.remove`, with `defaultAction` from the
override or `SCMP_ACT_LOG`. The `hash` names that effective set — it changes when
the observed union grows *or* when an override changes.

***

## GET /seccomp/profiles

Every workload that has an aggregated syscall set, with its effective hash,
profile path, distribution readiness, and any override. This is the list the
controller's distributor polls and the UI renders.

### Response

```json theme={null}
[
  {
    "namespace": "prod",
    "kind": "Deployment",
    "name": "web",
    "hash": "a1b2c3d4e5f60718",
    "localhostProfile": "kguardian/prod/deployment-web-a1b2c3d4e5f60718.json",
    "defaultAction": "SCMP_ACT_LOG",
    "syscallCount": 73,
    "architectures": ["SCMP_ARCH_X86_64"],
    "distribution": { "ready": 12, "total": 12, "state": "Ready" },
    "recommendedSnippet": {
      "seccompProfile": {
        "type": "Localhost",
        "localhostProfile": "kguardian/prod/deployment-web-a1b2c3d4e5f60718.json"
      }
    },
    "override": null,
    "updatedAt": "2026-09-02T10:15:00"
  }
]
```

`distribution.state` is `Ready` when every live node (`total`) reports the
current file, `Partial` when some do, and `Pending` when none do or no node has
reported yet.

When an override is set, `override` is:

```json theme={null}
{
  "add": ["clock_settime"],
  "remove": [],
  "defaultAction": "SCMP_ACT_ERRNO",
  "note": "weekly cron rotates the cert",
  "updatedBy": "alice",
  "updatedAt": "2026-09-03T09:00:00",
  "revision": 2
}
```

***

## GET /seccomp/profiles/{namespace}/{kind}/{name}

One workload's summary (as above) plus the rendered effective profile document.

### Response

```json theme={null}
{
  "namespace": "prod",
  "kind": "Deployment",
  "name": "web",
  "hash": "a1b2c3d4e5f60718",
  "localhostProfile": "kguardian/prod/deployment-web-a1b2c3d4e5f60718.json",
  "defaultAction": "SCMP_ACT_LOG",
  "distribution": { "ready": 12, "total": 12, "state": "Ready" },
  "override": null,
  "profile": {
    "defaultAction": "SCMP_ACT_LOG",
    "architectures": ["SCMP_ARCH_X86_64"],
    "syscalls": [
      { "names": ["accept4", "read", "write", "..."], "action": "SCMP_ACT_ALLOW" }
    ]
  }
}
```

`404` if the workload has no aggregate yet.

***

## GET /seccomp/profile-file/{namespace}/{kind}/{name}/{hash}

The bare effective `SeccompProfile` document, for a distributor to write to a
node verbatim.

Serves only the **current** hash — a stale hash returns `404` with
`stale hash; re-read /seccomp/profiles`, which is the caller's signal to
re-read the list.

***

## PUT /seccomp/profiles/{namespace}/{kind}/{name}/override

Set or replace the operator override for a workload. **Gated** — returns `404`
unless the broker is started with `SECCOMP_OVERRIDES_ENABLED=true` (Helm:
`seccomp.overrides.enabled`).

The override is stored separately from the observed union, which keeps accruing
underneath. The effective hash is recomputed on the write, so a new
hash-named file lands on every node within one distributor poll; the previous
file is never deleted, so a `DELETE` (below) reverts cleanly.

### Request

```json theme={null}
{
  "add": ["clock_settime", "clock_adjtime"],
  "remove": [],
  "defaultAction": "SCMP_ACT_ERRNO",
  "note": "cert rotation cron, runs weekly",
  "revision": 1,
  "dryRun": false
}
```

* `add` / `remove` — syscall names, `^[a-z][a-z0-9_]{0,63}$`, ≤ 512 each. A name
  in both is a `400`. Names are **not** checked against a real syscall table yet
  (a typo that passes the format check produces a warning-free but useless
  profile).
* `defaultAction` — one of `SCMP_ACT_LOG`, `SCMP_ACT_ERRNO`, `SCMP_ACT_KILL`;
  omit to keep `SCMP_ACT_LOG`.
* `revision` — the revision the client last read. Omit (or `null`) to **create**;
  a mismatch with the stored revision is a `409`.
* `dryRun` — validate and render without persisting.
* `X-Kguardian-Actor` header — recorded as `updatedBy`; defaults to `unknown`.

### Response — `200`

```json theme={null}
{
  "dryRun": false,
  "revision": 2,
  "hash": "7f3c1a0b9d2e4658",
  "warnings": [
    "defaultAction SCMP_ACT_ERRNO blocks — a syscall the workload makes but kube-guardian has not yet observed will fail on the pod's next restart"
  ],
  "profile": { "defaultAction": "SCMP_ACT_ERRNO", "architectures": ["..."], "syscalls": [ ... ] }
}
```

### Errors

| Code  | When                                                                             |
| ----- | -------------------------------------------------------------------------------- |
| `404` | overrides not enabled, or no observed profile for the workload yet               |
| `400` | bad syscall name, `add`/`remove` overlap, invalid `defaultAction`, list over cap |
| `409` | `revision` does not match the stored one — body carries `currentRevision`        |

***

## DELETE /seccomp/profiles/{namespace}/{kind}/{name}/override

Drop the override. The effective profile falls back to the pure observed set and
the hash reverts to the pre-override value — and since that file was never
deleted from any node, no redistribution is needed. Also gated behind
`SECCOMP_OVERRIDES_ENABLED`. `404` if there was no override.

***

## POST /seccomp/node-status

The distributor reports, after every pass, the full set of profile files present
on its node. Replaces the node's row wholesale — it is a snapshot, not a delta.

### Request

```json theme={null}
{
  "node_name": "ip-10-0-1-42.ec2.internal",
  "paths": [
    "kguardian/prod/deployment-web-a1b2c3d4e5f60718.json",
    "kguardian/prod/cronjob-report-9f8e7d6c5b4a3021.json"
  ]
}
```

`node_name` is required; an empty `paths` is valid (the node has no profiles
yet). Returns `200` with an empty body.
