From 92af4fa44ef157d26c72711617141e7f223705ab Mon Sep 17 00:00:00 2001 From: yummybomb <19238148+yummybomb@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:44:25 +0000 Subject: [PATCH 1/7] Document audit logs API --- docs.json | 1 + info/audit-logs.mdx | 130 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 info/audit-logs.mdx diff --git a/docs.json b/docs.json index 9b0eef6..f3d9ee9 100644 --- a/docs.json +++ b/docs.json @@ -116,6 +116,7 @@ ] }, "info/api-keys", + "info/audit-logs", "browsers/file-io", "browsers/curl", "browsers/ssh", diff --git a/info/audit-logs.mdx b/info/audit-logs.mdx new file mode 100644 index 0000000..b4a6e41 --- /dev/null +++ b/info/audit-logs.mdx @@ -0,0 +1,130 @@ +--- +title: "Audit Logs" +description: "List organization API request audit events" +--- + +Audit logs record authenticated API requests for your organization. Use them to review who called Kernel, which endpoint they called, when the request happened, and how the request completed. + +Audit logs are ordered newest first. The `start` timestamp is inclusive, the `end` timestamp is exclusive, and each request can cover up to 30 days. Each page returns up to 100 events. + +## List audit logs + +Use the SDKs to page through logs for a time window. + + +```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', + limit: 100, + 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", + limit=100, + method="POST", +): + print(event.timestamp, event.method, event.path, event.status) +``` + + +## Filter audit logs + +Use filters to narrow the time window to the events you need: + +- `auth_strategy` filters by authentication method, such as `api_key`, `dashboard`, or `oauth`. +- `service` filters by the service that emitted the audit event. +- `method` filters by HTTP method. +- `exclude_method` excludes a single HTTP method. +- `search` matches path, user ID, email, client IP, and status. +- `search_user_id` adds one or more user IDs to the search. + + +```typescript TypeScript +const logs = kernel.auditLogs.list({ + start: '2026-06-01T00:00:00Z', + end: '2026-06-08T00:00:00Z', + limit: 50, + auth_strategy: 'api_key', + exclude_method: 'GET', + search: '/browsers', +}); + +for await (const event of logs) { + console.log(event.email, event.client_ip, event.user_agent); +} +``` + +```python Python +logs = client.audit_logs.list( + start="2026-06-01T00:00:00Z", + end="2026-06-08T00:00:00Z", + limit=50, + auth_strategy="api_key", + exclude_method="GET", + search="/browsers", +) + +for event in logs: + print(event.email, event.client_ip, event.user_agent) +``` + + +## Page with HTTP + +The API returns the next cursor in the `X-Next-Page-Token` response header. Pass it back as `page_token` to read the next page. + +```bash +curl --get https://api.onkernel.com/audit-logs \ + --header "Authorization: Bearer $KERNEL_API_KEY" \ + --data-urlencode "start=2026-06-01T00:00:00Z" \ + --data-urlencode "end=2026-06-02T00:00:00Z" \ + --data-urlencode "limit=100" +``` + +```bash +curl --get https://api.onkernel.com/audit-logs \ + --header "Authorization: Bearer $KERNEL_API_KEY" \ + --data-urlencode "start=2026-06-01T00:00:00Z" \ + --data-urlencode "end=2026-06-02T00:00:00Z" \ + --data-urlencode "limit=100" \ + --data-urlencode "page_token=eyJ0IjoiMjAyNi0wNi0wMVQyMzo1OTo1OS43NDUxMjNaIn0" +``` + +Use `X-Has-More: true` to decide whether to continue paging. Page tokens are opaque; store and pass them exactly as returned. + +## Response fields + +Each audit log entry includes: + +- `timestamp` +- `auth_strategy` +- `user_id` +- `email` +- `status` +- `method` +- `path` +- `route` +- `domain` +- `duration_ms` +- `client_ip` +- `user_agent` + +See the [API reference](https://kernel.sh/docs/api-reference/audit-logs/list-audit-logs) for the full request and response schema. From 6392fd86ff26ec59dc53d297c53d4b557b08de73 Mon Sep 17 00:00:00 2001 From: yummybomb <19238148+yummybomb@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:47:35 +0000 Subject: [PATCH 2/7] Add Go audit log examples --- info/audit-logs.mdx | 64 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/info/audit-logs.mdx b/info/audit-logs.mdx index b4a6e41..788b53e 100644 --- a/info/audit-logs.mdx +++ b/info/audit-logs.mdx @@ -43,6 +43,37 @@ for event in client.audit_logs.list( ): 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), + Limit: kernel.Int(100), + 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) + } +} +``` ## Filter audit logs @@ -85,6 +116,39 @@ logs = client.audit_logs.list( for event in logs: print(event.email, event.client_ip, event.user_agent) ``` + +```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, 8, 0, 0, 0, 0, time.UTC), + Limit: kernel.Int(50), + AuthStrategy: kernel.String("api_key"), + ExcludeMethod: kernel.String("GET"), + Search: kernel.String("/browsers"), + }) + for pager.Next() { + event := pager.Current() + fmt.Println(event.Email, event.ClientIP, event.UserAgent) + } + if err := pager.Err(); err != nil { + panic(err) + } +} +``` ## Page with HTTP From 3b91857722993fe6f10ad32ac13303def764eba4 Mon Sep 17 00:00:00 2001 From: yummybomb <19238148+yummybomb@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:14:07 +0000 Subject: [PATCH 3/7] Clarify audit log filter wording and show paging headers Filters narrow results, not the time window; add --include to the HTTP paging examples so the X-Next-Page-Token response header is visible. --- info/audit-logs.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/info/audit-logs.mdx b/info/audit-logs.mdx index 788b53e..b8cde9d 100644 --- a/info/audit-logs.mdx +++ b/info/audit-logs.mdx @@ -78,7 +78,7 @@ func main() { ## Filter audit logs -Use filters to narrow the time window to the events you need: +Use filters to narrow results to the events you need: - `auth_strategy` filters by authentication method, such as `api_key`, `dashboard`, or `oauth`. - `service` filters by the service that emitted the audit event. @@ -156,7 +156,7 @@ func main() { The API returns the next cursor in the `X-Next-Page-Token` response header. Pass it back as `page_token` to read the next page. ```bash -curl --get https://api.onkernel.com/audit-logs \ +curl --include --get https://api.onkernel.com/audit-logs \ --header "Authorization: Bearer $KERNEL_API_KEY" \ --data-urlencode "start=2026-06-01T00:00:00Z" \ --data-urlencode "end=2026-06-02T00:00:00Z" \ @@ -164,7 +164,7 @@ curl --get https://api.onkernel.com/audit-logs \ ``` ```bash -curl --get https://api.onkernel.com/audit-logs \ +curl --include --get https://api.onkernel.com/audit-logs \ --header "Authorization: Bearer $KERNEL_API_KEY" \ --data-urlencode "start=2026-06-01T00:00:00Z" \ --data-urlencode "end=2026-06-02T00:00:00Z" \ From e4dbf8bb1bd394c0f4f02c2fd1560ebb7a7d6a9b Mon Sep 17 00:00:00 2001 From: yummybomb <19238148+yummybomb@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:11:16 +0000 Subject: [PATCH 4/7] Clarify audit log date range limit --- info/audit-logs.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/info/audit-logs.mdx b/info/audit-logs.mdx index b8cde9d..f93dbe4 100644 --- a/info/audit-logs.mdx +++ b/info/audit-logs.mdx @@ -7,6 +7,8 @@ Audit logs record authenticated API requests for your organization. Use them to Audit logs are ordered newest first. The `start` timestamp is inclusive, the `end` timestamp is exclusive, and each request can cover up to 30 days. Each page returns up to 100 events. +Keep each audit log request to a 30-day range or less. For longer investigations, split the query into multiple time windows. + ## List audit logs Use the SDKs to page through logs for a time window. From 1ac1f19aaa62e5e71969573625b39bf7aa345ac3 Mon Sep 17 00:00:00 2001 From: yummybomb <19238148+yummybomb@users.noreply.github.com> Date: Thu, 16 Jul 2026 19:13:22 +0000 Subject: [PATCH 5/7] Document audit log search and export workflows --- docs.json | 1 + info/audit-logs.mdx | 241 ++++++++++++++++++++++++++++++----- reference/cli.mdx | 3 + reference/cli/audit-logs.mdx | 93 ++++++++++++++ 4 files changed, 303 insertions(+), 35 deletions(-) create mode 100644 reference/cli/audit-logs.mdx diff --git a/docs.json b/docs.json index f3d9ee9..4e93dd5 100644 --- a/docs.json +++ b/docs.json @@ -290,6 +290,7 @@ "reference/cli/managed-auth", "reference/cli/projects", "reference/cli/api-keys", + "reference/cli/audit-logs", "reference/cli/mcp" ] } diff --git a/info/audit-logs.mdx b/info/audit-logs.mdx index f93dbe4..01aaaf1 100644 --- a/info/audit-logs.mdx +++ b/info/audit-logs.mdx @@ -1,17 +1,49 @@ --- title: "Audit Logs" -description: "List organization API request audit events" +description: "Search and export organization API request audit events" --- Audit logs record authenticated API requests for your organization. Use them to review who called Kernel, which endpoint they called, when the request happened, and how the request completed. -Audit logs are ordered newest first. The `start` timestamp is inclusive, the `end` timestamp is exclusive, and each request can cover up to 30 days. Each page returns up to 100 events. +Choose the workflow that matches the amount of data you need: -Keep each audit log request to a 30-day range or less. For longer investigations, split the query into multiple time windows. +| Workflow | Best for | Output | +|---|---|---| +| Search | Interactive investigation and recent activity | A table, JSON array, or paginated SDK results | +| Export | Archival, compliance, and offline analysis | JSON Lines (`.jsonl`) or gzip-compressed JSON Lines (`.jsonl.gz`) | -## List audit logs +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. -Use the SDKs to page through logs for a time window. +## Search with the CLI + +Search the previous 24 hours: + +```bash +kernel audit-logs search +``` + +Add a time window and filters: + +```bash +kernel audit-logs search \ + --start 2026-06-01 \ + --end 2026-06-08 \ + --search /browsers \ + --limit 500 \ + --output json +``` + +The CLI accepts RFC 3339 timestamps or `YYYY-MM-DD` dates. Date-only values represent midnight UTC. + + + The CLI excludes `GET` requests by default to reduce noise. Pass `--include-get` to include them, or `--method GET` to return only `GET` requests. The API and SDKs don't exclude `GET` unless you set `exclude_method`. + + +See the [audit log CLI reference](/reference/cli/audit-logs) for all flags and defaults. + +## Search with an SDK + +Each API page contains up to 100 events. The SDK pagination helpers request older pages as you iterate. ```typescript TypeScript @@ -80,14 +112,14 @@ func main() { ## Filter audit logs -Use filters to narrow results to the events you need: +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` filters by HTTP method. -- `exclude_method` excludes a single HTTP method. +- `method` includes one HTTP method. +- `exclude_method` excludes one or more HTTP methods, with up to 10 values. - `search` matches path, user ID, email, client IP, and status. -- `search_user_id` adds one or more user IDs to the search. +- `search_user_id` adds up to 100 user IDs to the free-text search. ```typescript TypeScript @@ -96,7 +128,7 @@ const logs = kernel.auditLogs.list({ end: '2026-06-08T00:00:00Z', limit: 50, auth_strategy: 'api_key', - exclude_method: 'GET', + exclude_method: ['GET'], search: '/browsers', }); @@ -111,7 +143,7 @@ logs = client.audit_logs.list( end="2026-06-08T00:00:00Z", limit=50, auth_strategy="api_key", - exclude_method="GET", + exclude_method=["GET"], search="/browsers", ) @@ -135,12 +167,12 @@ func main() { 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, 8, 0, 0, 0, 0, time.UTC), - Limit: kernel.Int(50), - AuthStrategy: kernel.String("api_key"), - ExcludeMethod: kernel.String("GET"), - Search: kernel.String("/browsers"), + Start: time.Date(2026, time.June, 1, 0, 0, 0, 0, time.UTC), + End: time.Date(2026, time.June, 8, 0, 0, 0, 0, time.UTC), + Limit: kernel.Int(50), + AuthStrategy: kernel.String("api_key"), + ExcludeMethod: []string{"GET"}, + Search: kernel.String("/browsers"), }) for pager.Next() { event := pager.Current() @@ -155,7 +187,13 @@ func main() { ## Page with HTTP -The API returns the next cursor in the `X-Next-Page-Token` response header. Pass it back as `page_token` to read the next page. +The REST API returns pagination state in these response headers: + +- `X-Limit` is the page size applied to the request. +- `X-Has-More` indicates whether older records remain. +- `X-Next-Page-Token` contains the opaque token for the next page. + +Request the first page: ```bash curl --include --get https://api.onkernel.com/audit-logs \ @@ -165,32 +203,165 @@ curl --include --get https://api.onkernel.com/audit-logs \ --data-urlencode "limit=100" ``` +If `X-Has-More` is `true`, copy the `X-Next-Page-Token` value and pass it unchanged: + ```bash curl --include --get https://api.onkernel.com/audit-logs \ --header "Authorization: Bearer $KERNEL_API_KEY" \ --data-urlencode "start=2026-06-01T00:00:00Z" \ --data-urlencode "end=2026-06-02T00:00:00Z" \ --data-urlencode "limit=100" \ - --data-urlencode "page_token=eyJ0IjoiMjAyNi0wNi0wMVQyMzo1OTo1OS43NDUxMjNaIn0" + --data-urlencode "page_token=$NEXT_PAGE_TOKEN" +``` + +Page tokens are opaque. Don't decode, construct, or modify them. + +## Download an export with the CLI + +Use the CLI to download every chunk in a time window into one verified gzip-compressed JSONL file: + +```bash +kernel audit-logs download \ + --start 2026-06-01 \ + --end 2026-07-01 \ + --to audit-june.jsonl.gz +``` + +The CLI: + +1. downloads up to 50,000 records per chunk, +2. verifies each chunk against its `X-Content-Sha256` checksum, +3. retries transient and integrity failures, +4. writes to a temporary `.partial` file, and +5. publishes the final file only after every chunk succeeds. + +Incomplete downloads are removed and don't resume across CLI runs. Rerunning the command starts the export again. Use `--force` to replace an existing output file. + +Like CLI search, CLI download excludes `GET` by default. Search and download accept the same filters. + +## Download an export chunk with HTTP + +The export API returns one chunk per request. Save the response headers separately from the binary body: + +```bash +curl --fail-with-body --silent --show-error --get \ + https://api.onkernel.com/audit-logs/export/chunk \ + --header "Authorization: Bearer $KERNEL_API_KEY" \ + --data-urlencode "start=2026-06-01T00:00:00Z" \ + --data-urlencode "end=2026-06-02T00:00:00Z" \ + --data-urlencode "format=jsonl.gz" \ + --dump-header audit-logs-chunk.headers \ + --output audit-logs-chunk.jsonl.gz +``` + +When `X-Has-More` is `true`, copy `X-Next-Cursor` and pass it unchanged to download the next chunk: + +```bash +curl --fail-with-body --silent --show-error --get \ + https://api.onkernel.com/audit-logs/export/chunk \ + --header "Authorization: Bearer $KERNEL_API_KEY" \ + --data-urlencode "start=2026-06-01T00:00:00Z" \ + --data-urlencode "end=2026-06-02T00:00:00Z" \ + --data-urlencode "format=jsonl.gz" \ + --data-urlencode "cursor=$NEXT_CURSOR" \ + --dump-header audit-logs-next-chunk.headers \ + --output audit-logs-next-chunk.jsonl.gz +``` + +## Download an export chunk with an SDK + +Save the response body exactly as returned, then inspect `X-Has-More`. When it is `true`, pass `X-Next-Cursor` as `cursor` on the next request. + + +```typescript TypeScript +import { writeFile } from 'node:fs/promises'; +import Kernel from '@onkernel/sdk'; + +const kernel = new Kernel({ + apiKey: process.env.KERNEL_API_KEY, +}); + +const response = await kernel.auditLogs.exportChunk({ + start: '2026-06-01T00:00:00Z', + end: '2026-06-02T00:00:00Z', + format: 'jsonl.gz', + exclude_method: ['GET'], +}); + +await writeFile( + 'audit-logs-chunk.jsonl.gz', + Buffer.from(await response.arrayBuffer()), +); + +console.log(response.headers.get('x-has-more')); +console.log(response.headers.get('x-next-cursor')); +``` + +```python Python +import os +from kernel import Kernel + +client = Kernel(api_key=os.environ["KERNEL_API_KEY"]) + +response = client.audit_logs.export_chunk( + start="2026-06-01T00:00:00Z", + end="2026-06-02T00:00:00Z", + format="jsonl.gz", + exclude_method=["GET"], +) +response.write_to_file("audit-logs-chunk.jsonl.gz") + +print(response.http_response.headers.get("x-has-more")) +print(response.http_response.headers.get("x-next-cursor")) ``` -Use `X-Has-More: true` to decide whether to continue paging. Page tokens are opaque; store and pass them exactly as returned. +```go Go +package main + +import ( + "context" + "io" + "os" + "time" + + "github.com/kernel/kernel-go-sdk" +) + +func main() { + ctx := context.Background() + client := kernel.NewClient() + + response, err := client.AuditLogs.ExportChunk(ctx, 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"}, + }) + if err != nil { + panic(err) + } + defer response.Body.Close() + + file, err := os.Create("audit-logs-chunk.jsonl.gz") + if err != nil { + panic(err) + } + defer file.Close() -## Response fields + if _, err := io.Copy(file, response.Body); err != nil { + panic(err) + } + + println(response.Header.Get("X-Has-More")) + println(response.Header.Get("X-Next-Cursor")) +} +``` + -Each audit log entry includes: + + SDK examples above download one chunk. A complete custom exporter must repeat requests until `X-Has-More` is `false`, persist the cursor only after safely writing a chunk, and verify `X-Content-Sha256` against the exact response bytes. Use the CLI when you don't need custom storage or processing. + -- `timestamp` -- `auth_strategy` -- `user_id` -- `email` -- `status` -- `method` -- `path` -- `route` -- `domain` -- `duration_ms` -- `client_ip` -- `user_agent` +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/list-audit-logs) for the full request and response schema. +See the [API reference](https://kernel.sh/docs/api-reference/audit-logs/list-audit-logs) for the complete search contract and response schema. diff --git a/reference/cli.mdx b/reference/cli.mdx index 7a47a9d..b0cc1a3 100644 --- a/reference/cli.mdx +++ b/reference/cli.mdx @@ -61,6 +61,9 @@ kernel --version Create, list, rename, and delete API keys. + + Search and download organization audit logs. + ## Quick Start diff --git a/reference/cli/audit-logs.mdx b/reference/cli/audit-logs.mdx new file mode 100644 index 0000000..eda9825 --- /dev/null +++ b/reference/cli/audit-logs.mdx @@ -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 -## 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` includes one HTTP method. -- `exclude_method` excludes one or more HTTP methods, with up to 10 values. -- `search` matches path, user ID, email, client IP, and status. -- `search_user_id` adds up to 100 user IDs to the free-text search. - - -```typescript TypeScript -const logs = kernel.auditLogs.list({ - start: '2026-06-01T00:00:00Z', - end: '2026-06-08T00:00:00Z', - limit: 50, - auth_strategy: 'api_key', - exclude_method: ['GET'], - search: '/browsers', -}); - -for await (const event of logs) { - console.log(event.email, event.client_ip, event.user_agent); -} -``` - -```python Python -logs = client.audit_logs.list( - start="2026-06-01T00:00:00Z", - end="2026-06-08T00:00:00Z", - limit=50, - auth_strategy="api_key", - exclude_method=["GET"], - search="/browsers", -) - -for event in logs: - print(event.email, event.client_ip, event.user_agent) -``` - -```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, 8, 0, 0, 0, 0, time.UTC), - Limit: kernel.Int(50), - AuthStrategy: kernel.String("api_key"), - ExcludeMethod: []string{"GET"}, - Search: kernel.String("/browsers"), - }) - for pager.Next() { - event := pager.Current() - fmt.Println(event.Email, event.ClientIP, event.UserAgent) - } - if err := pager.Err(); err != nil { - panic(err) - } -} -``` - - -## Page with HTTP +## Search with HTTP -The REST API returns pagination state in these response headers: +Search over raw HTTP with a `GET` request. The response carries pagination state in these headers: - `X-Limit` is the page size applied to the request. - `X-Has-More` indicates whether older records remain. @@ -211,14 +154,16 @@ curl --include --get https://api.onkernel.com/audit-logs \ --data-urlencode "start=2026-06-01T00:00:00Z" \ --data-urlencode "end=2026-06-02T00:00:00Z" \ --data-urlencode "limit=100" \ - --data-urlencode "page_token=$NEXT_PAGE_TOKEN" + --data-urlencode "page_token=" ``` Page tokens are opaque. Don't decode, construct, or modify them. +See the [API reference](https://kernel.sh/docs/api-reference/audit-logs/list-audit-logs) for the complete search contract and response schema. + ## Download an export with the CLI -Use the CLI to download every chunk in a time window into one verified gzip-compressed JSONL file: +The export workflow is exposed through the `kernel audit-logs download` command and the export-chunk API endpoint. Use the CLI to download every chunk in a time window into one verified gzip-compressed JSONL file: ```bash kernel audit-logs download \ @@ -227,49 +172,14 @@ kernel audit-logs download \ --to audit-june.jsonl.gz ``` -The CLI: - -1. downloads up to 50,000 records per chunk, -2. verifies each chunk against its `X-Content-Sha256` checksum, -3. retries transient and integrity failures, -4. writes to a temporary `.partial` file, and -5. publishes the final file only after every chunk succeeds. - -Incomplete downloads are removed and don't resume across CLI runs. Rerunning the command starts the export again. Use `--force` to replace an existing output file. +The download is all-or-nothing: the CLI verifies every chunk it receives and writes the output file only after the whole export succeeds. Incomplete downloads are removed and don't resume across CLI runs; rerunning the command starts the export again. Use `--force` to replace an existing output file. See the [audit log CLI reference](/reference/cli/audit-logs#download-behavior) for chunk sizes, checksums, and retry behavior. Like CLI search, CLI download excludes `GET` by default. Search and download accept the same filters. -## Download an export chunk with HTTP - -The export API returns one chunk per request. Save the response headers separately from the binary body: - -```bash -curl --fail-with-body --silent --show-error --get \ - https://api.onkernel.com/audit-logs/export/chunk \ - --header "Authorization: Bearer $KERNEL_API_KEY" \ - --data-urlencode "start=2026-06-01T00:00:00Z" \ - --data-urlencode "end=2026-06-02T00:00:00Z" \ - --data-urlencode "format=jsonl.gz" \ - --dump-header audit-logs-chunk.headers \ - --output audit-logs-chunk.jsonl.gz -``` - -When `X-Has-More` is `true`, copy `X-Next-Cursor` and pass it unchanged to download the next chunk: - -```bash -curl --fail-with-body --silent --show-error --get \ - https://api.onkernel.com/audit-logs/export/chunk \ - --header "Authorization: Bearer $KERNEL_API_KEY" \ - --data-urlencode "start=2026-06-01T00:00:00Z" \ - --data-urlencode "end=2026-06-02T00:00:00Z" \ - --data-urlencode "format=jsonl.gz" \ - --data-urlencode "cursor=$NEXT_CURSOR" \ - --dump-header audit-logs-next-chunk.headers \ - --output audit-logs-next-chunk.jsonl.gz -``` - ## Download an export chunk with an SDK +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. + Save the response body exactly as returned, then inspect `X-Has-More`. When it is `true`, pass `X-Next-Cursor` as `cursor` on the next request. @@ -358,10 +268,39 @@ func main() { ``` +## Download an export chunk with HTTP + +Save the response headers separately from the binary body: + +```bash +curl --fail-with-body --silent --show-error --get \ + https://api.onkernel.com/audit-logs/export/chunk \ + --header "Authorization: Bearer $KERNEL_API_KEY" \ + --data-urlencode "start=2026-06-01T00:00:00Z" \ + --data-urlencode "end=2026-06-02T00:00:00Z" \ + --data-urlencode "format=jsonl.gz" \ + --dump-header audit-logs-chunk.headers \ + --output audit-logs-chunk.jsonl.gz +``` + +When `X-Has-More` is `true`, copy `X-Next-Cursor` and pass it unchanged to download the next chunk: + +```bash +curl --fail-with-body --silent --show-error --get \ + https://api.onkernel.com/audit-logs/export/chunk \ + --header "Authorization: Bearer $KERNEL_API_KEY" \ + --data-urlencode "start=2026-06-01T00:00:00Z" \ + --data-urlencode "end=2026-06-02T00:00:00Z" \ + --data-urlencode "format=jsonl.gz" \ + --data-urlencode "cursor=" \ + --dump-header audit-logs-next-chunk.headers \ + --output audit-logs-next-chunk.jsonl.gz +``` + - SDK examples above download one chunk. A complete custom exporter must repeat requests until `X-Has-More` is `false`, persist the cursor only after safely writing a chunk, and verify `X-Content-Sha256` against the exact response bytes. Use the CLI when you don't need custom storage or processing. + The SDK and HTTP examples above download one chunk. A complete custom exporter must repeat requests until `X-Has-More` is `false`, persist the cursor only after safely writing a chunk, and verify `X-Content-Sha256` against the exact response bytes. Use the CLI when you don't need custom storage or processing. 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/list-audit-logs) for the complete search contract and response schema. +See the [API reference](https://kernel.sh/docs/api-reference/audit-logs/download-an-audit-log-export-chunk) for the complete export contract and response schema. diff --git a/reference/cli/audit-logs.mdx b/reference/cli/audit-logs.mdx index eda9825..e8c037d 100644 --- a/reference/cli/audit-logs.mdx +++ b/reference/cli/audit-logs.mdx @@ -20,11 +20,11 @@ kernel audit-logs search \ 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