Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
]
},
"info/api-keys",
"info/audit-logs",
"browsers/file-io",
"browsers/curl",
"browsers/ssh",
Expand Down Expand Up @@ -289,6 +290,7 @@
"reference/cli/managed-auth",
"reference/cli/projects",
"reference/cli/api-keys",
"reference/cli/audit-logs",
"reference/cli/mcp"
]
}
Expand Down
223 changes: 223 additions & 0 deletions info/audit-logs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
---
title: "Audit Logs"
description: "Search and export audit logs for API requests across your organization"
---

Audit logs record authenticated API requests across your entire organization. Use them to review who called Kernel, which endpoint they called, when the request happened, and how the request completed.

Choose the workflow that matches the amount of data you need:

| Workflow | Best for | Output |
|----------|----------|--------|
| Search | Interactive investigation and recent activity | Paginated JSON events |
| Export | Archival, compliance, and offline analysis | JSON Lines (`.jsonl`) or gzip-compressed JSON Lines (`.jsonl.gz`) |

Audit logs are ordered newest first. Time windows use an inclusive `start` and exclusive `end`: `[start, end)`. A search or export can cover up to 30 days. Split longer periods into multiple time windows.

Both workflows are also available from the [CLI](/reference/cli/audit-logs). For the underlying HTTP API, see [search](https://kernel.sh/docs/api-reference/audit-logs/list-audit-logs) and [export](https://kernel.sh/docs/api-reference/audit-logs/download-an-audit-log-export-chunk) in the API reference.

## Filter audit logs

The API and SDKs use the same filters for search and export:

- `auth_strategy` filters by authentication method, such as `api_key`, `dashboard`, or `oauth`.
- `service` filters by the service that emitted the audit event.
- `method` returns only requests that use the specified HTTP method.
- `exclude_method` omits requests that use any of the specified HTTP methods.
- `search` matches path, user ID, email, client IP, and status.
- `search_user_id` matches requests from the specified user IDs in addition to any free-text matches.

<Note>
The API and SDKs include all methods unless you filter. Only the CLI excludes `GET` by default to reduce noise. Pass `--include-get` to remove that default exclusion, or pass `--method GET` to return only GET requests.
</Note>

## Search audit logs

Each API page contains up to 100 events. The SDK pagination helpers request older pages as you iterate.

<CodeGroup>
```typescript TypeScript
import Kernel from '@onkernel/sdk';

const kernel = new Kernel({
apiKey: process.env.KERNEL_API_KEY,
});

for await (const event of kernel.auditLogs.list({
start: '2026-06-01T00:00:00Z',
end: '2026-06-02T00:00:00Z',
method: 'POST',
})) {
console.log(event.timestamp, event.method, event.path, event.status);
}
```

```python Python
import os
from kernel import Kernel

client = Kernel(api_key=os.environ["KERNEL_API_KEY"])

for event in client.audit_logs.list(
start="2026-06-01T00:00:00Z",
end="2026-06-02T00:00:00Z",
method="POST",
):
print(event.timestamp, event.method, event.path, event.status)
```

```go Go
package main

import (
"context"
"fmt"
"time"

"github.com/kernel/kernel-go-sdk"
)

func main() {
ctx := context.Background()
client := kernel.NewClient()

pager := client.AuditLogs.ListAutoPaging(ctx, kernel.AuditLogListParams{
Start: time.Date(2026, time.June, 1, 0, 0, 0, 0, time.UTC),
End: time.Date(2026, time.June, 2, 0, 0, 0, 0, time.UTC),
Method: kernel.String("POST"),
})
for pager.Next() {
event := pager.Current()
fmt.Println(event.Timestamp, event.Method, event.Path, event.Status)
}
if err := pager.Err(); err != nil {
panic(err)
}
}
```
</CodeGroup>

See the [API reference](https://kernel.sh/docs/api-reference/audit-logs/list-audit-logs) for the full request and response schema.

## Export audit logs

The export API returns one chunk per request. Export paging uses a cursor rather than the page token used by search; both are opaque values you pass back unchanged.

Repeat requests until `X-Has-More` is `false`, passing `X-Next-Cursor` back as `cursor`. With the `jsonl.gz` format, each chunk is an independent gzip member, and appending the members produces a valid gzip file. With `jsonl`, each chunk contains raw JSON Lines that you can also append.

The following minimal examples write all chunks to one file. For a hardened export with checksum verification and retries, use the [CLI](/reference/cli/audit-logs#kernel-audit-logs-download).

<CodeGroup>
```typescript TypeScript
import { open } from 'node:fs/promises';
import Kernel from '@onkernel/sdk';

const kernel = new Kernel({
apiKey: process.env.KERNEL_API_KEY,
});

const file = await open('audit-logs.jsonl.gz', 'w');
try {
let cursor: string | undefined;
while (true) {
const response = await kernel.auditLogs.exportChunk({
start: '2026-06-01T00:00:00Z',
end: '2026-06-02T00:00:00Z',
format: 'jsonl.gz',
exclude_method: ['GET'],
cursor,
});

await file.writeFile(Buffer.from(await response.arrayBuffer()));

if (response.headers.get('x-has-more') !== 'true') {
break;
}
cursor = response.headers.get('x-next-cursor') ?? undefined;
}
} finally {
await file.close();
}
```

```python Python
import os
from kernel import Kernel

client = Kernel(api_key=os.environ["KERNEL_API_KEY"])

params = {
"start": "2026-06-01T00:00:00Z",
"end": "2026-06-02T00:00:00Z",
"format": "jsonl.gz",
"exclude_method": ["GET"],
}

with open("audit-logs.jsonl.gz", "wb") as file:
while True:
response = client.audit_logs.export_chunk(**params)
file.write(response.read())
if response.headers.get("x-has-more") != "true":
break
params["cursor"] = response.headers.get("x-next-cursor")
```

```go Go
package main

import (
"context"
"io"
"os"
"time"

"github.com/kernel/kernel-go-sdk"
)

func main() {
ctx := context.Background()
client := kernel.NewClient()

file, err := os.Create("audit-logs.jsonl.gz")
if err != nil {
panic(err)
}
defer file.Close()

params := kernel.AuditLogExportChunkParams{
Start: time.Date(2026, time.June, 1, 0, 0, 0, 0, time.UTC),
End: time.Date(2026, time.June, 2, 0, 0, 0, 0, time.UTC),
Format: kernel.AuditLogExportChunkParamsFormatJSONLGz,
ExcludeMethod: []string{"GET"},
}

for {
response, err := client.AuditLogs.ExportChunk(ctx, params)
if err != nil {
panic(err)
}
_, copyErr := io.Copy(file, response.Body)
closeErr := response.Body.Close()
if copyErr != nil {
panic(copyErr)
}
if closeErr != nil {
panic(closeErr)
}

if response.Header.Get("X-Has-More") != "true" {
break
}
params.Cursor = kernel.String(response.Header.Get("X-Next-Cursor"))
}
}
```
</CodeGroup>

<Warning>
Don't use these minimal loops for a production export without adding integrity checks and durable cursor storage. For each chunk, buffer the exact response bytes, compare their SHA-256 hash with `X-Content-Sha256`, write the verified bytes, and then validate the cursor. When `X-Has-More` is `true`, require a non-empty `X-Next-Cursor` that differs from the current cursor. Persist that cursor only after the verified chunk is safely written. You must also retry transient failures. The [CLI download command](/reference/cli/audit-logs#kernel-audit-logs-download) implements this hardened path.
</Warning>

Export chunks contain one JSON object per line. They use the same fields as search results and add `event_id`, which provides a stable tie-breaker when multiple events share a timestamp.

See the [API reference](https://kernel.sh/docs/api-reference/audit-logs/download-an-audit-log-export-chunk) for the full request and response schema.
3 changes: 3 additions & 0 deletions reference/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ kernel --version
<Card icon="key" title="API Keys" href="/reference/cli/api-keys">
Create, list, rename, and delete API keys.
</Card>
<Card icon="clock-rotate-left" title="Audit Logs" href="/reference/cli/audit-logs">
Search and download organization audit logs.
</Card>
</Columns>

## Quick Start
Expand Down
93 changes: 93 additions & 0 deletions reference/cli/audit-logs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
title: "Audit Logs"
---

Search and download [organization audit logs](/info/audit-logs) from the CLI.

## `kernel audit-logs search`

Search audit logs within a time window. Results are ordered newest first.

```bash
kernel audit-logs search \
--start 2026-06-01 \
--end 2026-06-08 \
--search /browsers \
--limit 500 \
--output json
```

If you omit the time flags, the command searches from 24 hours ago through now. The start is inclusive and the end is exclusive. Each time window can cover up to 30 days.

| Flag | Description |
|------|-------------|
| `--start <time>` | Inclusive start, as RFC 3339 or `YYYY-MM-DD`. Defaults to 24 hours ago. |
| `--end <time>` | Exclusive end, as RFC 3339 or `YYYY-MM-DD`. Defaults to now. |
| `--search <text>` | Search path, user ID, email, client IP, and status. |
| `--method <method>` | Return only requests that use this HTTP method. |
| `--exclude-method <method>` | Exclude requests that use this HTTP method. GET remains excluded unless you pass `--include-get`. |
| `--include-get` | Remove the default GET exclusion when `--method` is not set. |
| `--service <service>` | Filter by service. |
| `--auth-strategy <strategy>` | Filter by authentication strategy. |
| `--user-id <id>` | Add a user ID to the search. Repeat the flag for multiple IDs. |
| `--limit <n>` | Maximum total number of results. Defaults to `100`. |
| `--output json`, `-o json` | Output raw JSON array. |

<Note>
`--limit` controls the total number of CLI results. The CLI automatically requests API pages of up to 100 records until it reaches that limit or runs out of results.
</Note>

### Include GET requests

By default, the CLI returns matching requests for every HTTP method except GET. `--include-get` removes that default exclusion. `--method` selects exactly one method, so `--method GET` returns only GET requests.

```bash
# Return all matching methods, including GET
kernel audit-logs search --include-get

# Return only GET requests
kernel audit-logs search --method GET
```

## `kernel audit-logs download`

Download matching audit logs in a time window as one gzip-compressed JSONL file.

```bash
kernel audit-logs download \
--start 2026-06-01 \
--end 2026-07-01 \
--to audit-june.jsonl.gz
```

`--start` and `--end` are required. The start is inclusive and the end is exclusive, and the time window can cover up to 30 days.

| Flag | Description |
|------|-------------|
| `--start <time>` | Inclusive start, as RFC 3339 or `YYYY-MM-DD`. Required. |
| `--end <time>` | Exclusive end, as RFC 3339 or `YYYY-MM-DD`. Required. |
| `--search <text>` | Search path, user ID, email, client IP, and status. |
| `--method <method>` | Return only requests that use this HTTP method. |
| `--exclude-method <method>` | Exclude requests that use this HTTP method. GET remains excluded unless you pass `--include-get`. |
| `--include-get` | Remove the default GET exclusion when `--method` is not set. |
| `--service <service>` | Filter by service. |
| `--auth-strategy <strategy>` | Filter by authentication strategy. |
| `--user-id <id>` | Add a user ID to the search. Repeat the flag for multiple IDs. |
| `--to <path>` | Output `.jsonl.gz` path. For the example above, the default is `audit-logs-20260601-20260701.jsonl.gz`. |
| `--force` | Replace an existing output file. |

Date-only values represent midnight UTC. For example, `--start 2026-06-01 --end 2026-07-01` covers all of June in UTC.

### Download behavior

The command downloads up to 50,000 records at a time and appends each chunk to `<output>.partial`. Before writing a chunk, it verifies the SHA-256 checksum returned by the API.

A chunk is attempted up to seven times when a network error, HTTP `429`, HTTP `5xx`, truncated response, or checksum mismatch occurs. Retries use exponential backoff capped at eight seconds.

The CLI renames the temporary file to the requested output only after every chunk transfers successfully. If a transfer fails, it removes the incomplete temporary file. If the final rename fails, the completed download remains at `<output>.partial`. Downloads don't resume across CLI runs; rerunning the command starts again from the beginning.

The command refuses to replace an existing output unless you pass `--force`.

## Aliases

You can also use `kernel audit-log`, `kernel auditlogs`, or `kernel auditlog`.
Loading