Skip to content

Commit 3e2fcf9

Browse files
committed
Default audit log downloads to gzip
1 parent 0467576 commit 3e2fcf9

2 files changed

Lines changed: 25 additions & 17 deletions

File tree

src/kernel/resources/audit_logs.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,6 @@ def download(
237237
start: Union[str, datetime],
238238
auth_strategy: str | Omit = omit,
239239
exclude_method: SequenceNotStr[str] | Omit = omit,
240-
format: Literal["jsonl", "jsonl.gz"] | Omit = omit,
241240
limit: int | Omit = omit,
242241
method: str | Omit = omit,
243242
search: str | Omit = omit,
@@ -250,12 +249,13 @@ def download(
250249
extra_body: Body | None = None,
251250
timeout: float | httpx.Timeout | None | NotGiven = not_given,
252251
) -> AuditLogDownloadResult:
253-
"""Download a complete audit log export to a writable binary destination.
252+
"""Download a complete gzip-compressed JSON Lines audit log export.
254253
255-
The SDK verifies every chunk and retries transient transfer failures. It
256-
does not close the destination. If the download fails, the destination
257-
may contain a partial export; use a temporary file and atomic rename
258-
when the completed export must be published atomically.
254+
The SDK writes the export to a writable binary destination, verifies
255+
every chunk, and retries transient transfer failures. It does not close
256+
the destination. If the download fails, the destination may contain a
257+
partial export; use a temporary file and atomic rename when the completed
258+
export must be published atomically.
259259
"""
260260

261261
def fetch_chunk(cursor: str | None) -> ContextManager[StreamedBinaryAPIResponse]:
@@ -265,7 +265,6 @@ def fetch_chunk(cursor: str | None) -> ContextManager[StreamedBinaryAPIResponse]
265265
auth_strategy=auth_strategy,
266266
cursor=cursor if cursor is not None else omit,
267267
exclude_method=exclude_method,
268-
format=format,
269268
limit=limit,
270269
method=method,
271270
search=search,
@@ -481,7 +480,6 @@ async def download(
481480
start: Union[str, datetime],
482481
auth_strategy: str | Omit = omit,
483482
exclude_method: SequenceNotStr[str] | Omit = omit,
484-
format: Literal["jsonl", "jsonl.gz"] | Omit = omit,
485483
limit: int | Omit = omit,
486484
method: str | Omit = omit,
487485
search: str | Omit = omit,
@@ -494,12 +492,13 @@ async def download(
494492
extra_body: Body | None = None,
495493
timeout: float | httpx.Timeout | None | NotGiven = not_given,
496494
) -> AuditLogDownloadResult:
497-
"""Download a complete audit log export to a writable binary destination.
495+
"""Download a complete gzip-compressed JSON Lines audit log export.
498496
499-
The SDK verifies every chunk and retries transient transfer failures. It
500-
does not close the destination. If the download fails, the destination
501-
may contain a partial export; use a temporary file and atomic rename
502-
when the completed export must be published atomically.
497+
The SDK writes the export to a writable binary destination, verifies
498+
every chunk, and retries transient transfer failures. It does not close
499+
the destination. If the download fails, the destination may contain a
500+
partial export; use a temporary file and atomic rename when the completed
501+
export must be published atomically.
503502
"""
504503

505504
def fetch_chunk(cursor: str | None) -> AsyncContextManager[AsyncStreamedBinaryAPIResponse]:
@@ -509,7 +508,6 @@ def fetch_chunk(cursor: str | None) -> AsyncContextManager[AsyncStreamedBinaryAP
509508
auth_strategy=auth_strategy,
510509
cursor=cursor if cursor is not None else omit,
511510
exclude_method=exclude_method,
512-
format=format,
513511
limit=limit,
514512
method=method,
515513
search=search,

tests/test_audit_log_download.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ def test_download_writes_verified_chunks(client: Kernel, respx_mock: MockRouter)
5555
]
5656
)
5757
cursors: list[str | None] = []
58+
formats: list[str | None] = []
5859

5960
def respond(request: httpx.Request) -> httpx.Response:
6061
cursors.append(request.url.params.get("cursor"))
62+
formats.append(request.url.params.get("format"))
6163
return next(responses)
6264

6365
respx_mock.get("/audit-logs/export/chunk").mock(side_effect=respond)
@@ -68,7 +70,6 @@ def respond(request: httpx.Request) -> httpx.Response:
6870
to=destination,
6971
start="2026-06-01T00:00:00Z",
7072
end="2026-06-02T00:00:00Z",
71-
format="jsonl.gz",
7273
on_progress=lambda update: progress.append(
7374
(update.bytes_written, update.chunks, update.rows, update.chunk_rows)
7475
),
@@ -80,17 +81,25 @@ def respond(request: httpx.Request) -> httpx.Response:
8081
assert result.rows == 3
8182
assert progress == [(5, 1, 2, 2), (11, 2, 3, 1)]
8283
assert cursors == [None, "next"]
84+
assert formats == [None, None]
8385

8486

8587
async def test_async_download_writes_verified_chunks(
8688
async_client: AsyncKernel, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
8789
) -> None:
88-
respx_mock.get("/audit-logs/export/chunk").mock(
89-
side_effect=[
90+
responses = iter(
91+
[
9092
chunk_response(b"first", rows=2, has_more=True, next_cursor="next"),
9193
chunk_response(b"second", rows=1, has_more=False),
9294
]
9395
)
96+
formats: list[str | None] = []
97+
98+
def respond(request: httpx.Request) -> httpx.Response:
99+
formats.append(request.url.params.get("format"))
100+
return next(responses)
101+
102+
respx_mock.get("/audit-logs/export/chunk").mock(side_effect=respond)
94103
thread_ids: list[int] = []
95104
write_chunk = audit_log_download._write_chunk
96105

@@ -119,6 +128,7 @@ async def on_progress(_: object) -> None:
119128
assert result.rows == 3
120129
assert progress_called
121130
assert thread_ids and all(thread_id != threading.get_ident() for thread_id in thread_ids)
131+
assert formats == [None, None]
122132

123133

124134
async def test_async_download_retries_body_read_failure(

0 commit comments

Comments
 (0)