feat(audit): log audio endpoint bodies with dashboard playback#364
Conversation
The /v1/audio/speech and /v1/audio/transcriptions endpoints were absent from the endpoint classifier, so they defaulted to ModelInteraction:false and were skipped by the audit middleware's OnlyModelInteractions gate. Classify them (and /v1/audio/translations) as model interactions with the appropriate body modes so they appear in audit and request logs. They are intentionally not IngressManaged: the audio handlers parse their own bodies and do not run through the translated-inference pipeline. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…h dashboard playback
Audio responses are binary, so the audit body-capture path corrupted them
via UTF-8 coercion (invalid bytes -> U+FFFD), making them unrecoverable.
Audio request bodies were never captured at all (audio is not
ingress-managed, so there is no request snapshot to read from).
Add a dedicated LOGGING_LOG_AUDIO_BODIES env var (default false), independent
of LOGGING_LOG_BODIES, that controls audio input/output logging:
- Response: the audio handler captures the output. When the flag is on it is
stored losslessly as base64 (capped at 10MB, else a too-large placeholder)
for playback; otherwise a lightweight {content_type, bytes} placeholder is
stored. The audit middleware now skips audio Content-Types so it neither
corrupts the bytes nor clobbers the handler-set body.
- Request: speech logs its JSON input (text, voice, format); transcription
logs upload metadata (filename, model, params) but never the raw audio.
Dashboard: render an <audio> player for stored audio (base64 data URL,
content-type and payload sanitized) and a labeled placeholder otherwise.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughAdds audit logging for OpenAI-compatible audio endpoints (/v1/audio/speech, /v1/audio/transcriptions): audio audit data contract, ChangesAudio endpoint audit logging
Sequence Diagram(s)sequenceDiagram
participant Client
participant AudioService
participant AuditMiddleware
Client->>AudioService: POST /v1/audio/speech
AudioService->>AudioService: serialize speech params
AudioService->>AuditMiddleware: EnrichEntryWithRequestBody
AudioService->>Client: return audio response
AudioService->>AudioService: detect audio content type
AudioService->>AuditMiddleware: EnrichEntryWithResponseBody
AuditMiddleware->>AuditMiddleware: publish live audit update
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR makes audio endpoints visible and playable in audit logs. It changes:
Confidence Score: 4/5This is close, but the storage cap should be fixed before merging.
internal/auditlog/audio_body.go Important Files Changed
Reviews (2): Last reviewed commit: "fix(audit): address PR review on audio b..." | Re-trigger Greptile |
| case path == "/v1/audio/transcriptions" || path == "/v1/audio/translations": | ||
| return EndpointDescriptor{ | ||
| ModelInteraction: true, | ||
| Dialect: "openai_compat", | ||
| Operation: OperationAudioTranscriptions, | ||
| } |
There was a problem hiding this comment.
This classifies /v1/audio/translations as a model interaction, but the server only registers /v1/audio/speech and /v1/audio/transcriptions. A client posting to /v1/audio/translations still gets a 404 instead of reaching an audio handler, so this endpoint remains unavailable even though the audit classifier and tests now say it is supported.
|
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
internal/auditlog/auditlog.go (1)
259-269: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick winAdd explicit
LogAudioBodiesinitialization for consistency.
DefaultConfig()explicitly sets all other boolean fields (Enabled: false,LogBodies: false,LogHeaders: false) but omits the newLogAudioBodiesfield. While the zero value is correct, explicitly setting it maintains consistency with the existing pattern in this function.♻️ Proposed addition
func DefaultConfig() Config { return Config{ Enabled: false, LogBodies: false, + LogAudioBodies: false, LogHeaders: false, BufferSize: 1000, FlushInterval: 5 * time.Second, RetentionDays: 30, OnlyModelInteractions: true, } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/auditlog/auditlog.go` around lines 259 - 269, The DefaultConfig function currently initializes most boolean fields explicitly but omits the new LogAudioBodies field; update DefaultConfig (the function named DefaultConfig returning Config) to include an explicit LogAudioBodies: false entry alongside Enabled, LogBodies, and LogHeaders so the new boolean is initialized consistently with the others in the Config literal.internal/auditlog/middleware.go (1)
137-166:⚠️ Potential issue | 🟡 Minor | ⚡ Quick win
ResponseBodyTooBigToHandleis set for audio responses despite lossless handler capture.The truncation flag (Lines 139-141) is evaluated before the
IsAudioContentTypeguard. For audio responses,responseCapturestill buffers bytes up toMaxBodyCaptureand setstruncatedwhen exceeded — even though the audio handler captures the body losslessly via its own path (with the separate 10 MBtoo_largecap). IfMaxBodyCaptureis smaller than the audio payload, the entry is incorrectly markedResponseBodyTooBigToHandle = truealongside a fully-stored audio body, producing conflicting audit metadata. Move the flag inside the non-audio branch.🐛 Proposed fix: gate the truncation flag on non-audio responses
- // Set truncation flag if response body exceeded limit - if responseCapture.truncated { - entry.Data.ResponseBodyTooBigToHandle = true - } - bodyBytes := responseCapture.body.Bytes() // Audio responses are binary; the audio handler captures them // losslessly as base64 (gated by LogAudioBodies) before this // runs. Skip here so we neither corrupt the bytes via UTF-8 // coercion nor clobber the handler-set body. if !IsAudioContentType(c.Response().Header().Get("Content-Type")) { + // Set truncation flag if response body exceeded limit + if responseCapture.truncated { + entry.Data.ResponseBodyTooBigToHandle = true + } + // Decompress if Content-Encoding header is present if contentEncoding := c.Response().Header().Get("Content-Encoding"); contentEncoding != "" { if decompressed, ok := decompressBody(bodyBytes, contentEncoding); ok { bodyBytes = decompressed } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@internal/auditlog/middleware.go` around lines 137 - 166, The truncation flag entry.Data.ResponseBodyTooBigToHandle is being set for all responses before checking IsAudioContentType, causing audio responses (which are captured losslessly by the audio handler) to be incorrectly marked too-big; update the block in the middleware so that after verifying cfg.LogBodies, responseCapture != nil, shouldCaptureResponseBody(c) and responseCapture.body.Len() > 0 you do NOT set ResponseBodyTooBigToHandle until after the IsAudioContentType check — move the existing truncated check (responseCapture.truncated -> entry.Data.ResponseBodyTooBigToHandle) inside the non-audio branch where IsAudioContentType(...) is false, keeping the rest of the JSON unmarshalling/decompression logic (decompressBody, json.Unmarshal, toValidUTF8String) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/admin/dashboard/static/css/dashboard.css`:
- Around line 2896-2914: The CSS uses an undefined custom property --muted in
the .audit-audio-meta and .audit-audio-note rules; update those rules to use
var(--text-muted, `#888`) instead of var(--muted, `#888`) so they match the rest of
the stylesheet's theme variable (--text-muted) and inherit correct colors in
light/dark modes.
---
Outside diff comments:
In `@internal/auditlog/auditlog.go`:
- Around line 259-269: The DefaultConfig function currently initializes most
boolean fields explicitly but omits the new LogAudioBodies field; update
DefaultConfig (the function named DefaultConfig returning Config) to include an
explicit LogAudioBodies: false entry alongside Enabled, LogBodies, and
LogHeaders so the new boolean is initialized consistently with the others in the
Config literal.
In `@internal/auditlog/middleware.go`:
- Around line 137-166: The truncation flag entry.Data.ResponseBodyTooBigToHandle
is being set for all responses before checking IsAudioContentType, causing audio
responses (which are captured losslessly by the audio handler) to be incorrectly
marked too-big; update the block in the middleware so that after verifying
cfg.LogBodies, responseCapture != nil, shouldCaptureResponseBody(c) and
responseCapture.body.Len() > 0 you do NOT set ResponseBodyTooBigToHandle until
after the IsAudioContentType check — move the existing truncated check
(responseCapture.truncated -> entry.Data.ResponseBodyTooBigToHandle) inside the
non-audio branch where IsAudioContentType(...) is false, keeping the rest of the
JSON unmarshalling/decompression logic (decompressBody, json.Unmarshal,
toValidUTF8String) unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2c8b7190-476f-444b-945e-29068e968693
📒 Files selected for processing (17)
.env.templateconfig/logging.gointernal/admin/dashboard/static/css/dashboard.cssinternal/admin/dashboard/static/js/modules/audit-list.jsinternal/admin/dashboard/static/js/modules/audit-list.test.cjsinternal/admin/dashboard/static/js/modules/conversation-helpers.jsinternal/app/app.gointernal/auditlog/audio_body.gointernal/auditlog/audio_body_test.gointernal/auditlog/auditlog.gointernal/auditlog/auditlog_test.gointernal/auditlog/factory.gointernal/auditlog/middleware.gointernal/core/endpoints.gointernal/core/endpoints_test.gointernal/server/audio_service.gointernal/server/handlers.go
Add the new env var to the audit logging configuration table and CLAUDE.md reference, and describe audio body capture (base64 storage + dashboard playback when enabled, placeholder when disabled) in the Audio API guide. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@CLAUDE.md`:
- Line 119: Update the logging documentation for LOGGING_LOG_AUDIO_BODIES to
state that base64-encoded audio is capped at 10 MB and that any audio payloads
exceeding this limit are marked "too_large" rather than being logged; mention
this applies to the /v1/audio/speech endpoint (base64 audio for playback) and
transcription uploads, and clarify that this cap is independent of
LOGGING_LOG_BODIES so users understand the behavior when audio exceeds the
threshold.
- Line 119: Update the CLAUDE.md audit logging line to include the same storage
warning present in config/logging.go for LOGGING_LOG_AUDIO_BODIES: add a clear
note that enabling LOGGING_LOG_AUDIO_BODIES stores full audio in the audit log
and can grow storage quickly, and include guidance on when to change the default
(e.g., only enable for short-term debugging or with retention/purging policies).
Reference the setting name LOGGING_LOG_AUDIO_BODIES and mirror the warning
phrasing from config/logging.go so users see the storage implications before
enabling it.
- Line 119: Update the audit logging docs entry that currently lists
`/v1/audio/speech` to also include `/v1/audio/translations`; specifically, when
describing `LOGGING_LOG_AUDIO_BODIES` and the logged audio endpoints, add
`/v1/audio/translations` alongside `/v1/audio/speech` and mention that it will
log base64 audio inputs/outputs (and dashboard playback) and upload metadata for
translations, and clarify that this behavior is independent of
`LOGGING_LOG_BODIES`.
In `@docs/advanced/audio-api.mdx`:
- Around line 95-98: Update the audit-logging documentation to include the
missing /v1/audio/translations endpoint: modify the paragraph that lists enabled
endpoints (currently mentions /v1/audio/speech and /v1/audio/transcriptions) to
also describe /v1/audio/translations' audit behavior (what is stored/omitted and
any size or format constraints), matching the style used for /v1/audio/speech
and /v1/audio/transcriptions so readers know all three endpoints are covered.
- Line 94: The doc's placeholder `{content_type, bytes}` is outdated; update the
documented placeholder to match the implementation by replacing it with
`{__audio__, content_type, bytes, stored:false}`, ensuring the sentinel
`__audio__` is first, `content_type` and `bytes` follow in that order, and the
`stored:false` flag is present to indicate audio bytes are not stored.
In `@docs/advanced/configuration.mdx`:
- Line 115: Update the documented placeholder format string that currently reads
"{content_type, bytes}" to reflect the actual implementation by replacing it
with the full placeholder "{__audio__, content_type, bytes, stored: false}";
look for the exact literal "{content_type, bytes}" in the configuration docs and
change it to the new format so the docs match the PR's response placeholder
structure.
- Line 112: Update the sentence that currently mentions
"/v1/audio/transcriptions" so it also includes "/v1/audio/translations" (e.g.,
"and `/v1/audio/transcriptions` and `/v1/audio/translations` stores upload
metadata"), ensuring both STT endpoints are documented as behaving identically
(storing metadata only); edit the line containing "dashboard can play it back,
and `/v1/audio/transcriptions` stores upload" to list both endpoints in the same
style.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 360a450a-f8f7-48bc-8733-1a20146d6b1f
📒 Files selected for processing (3)
CLAUDE.mddocs/advanced/audio-api.mdxdocs/advanced/configuration.mdx
| - **Storage:** `STORAGE_TYPE` (sqlite), `SQLITE_PATH` (data/gomodel.db), `POSTGRES_URL`, `MONGODB_URL` | ||
| - **Models:** `MODELS_ENABLED_BY_DEFAULT` (true), `MODEL_OVERRIDES_ENABLED` (true), `KEEP_ONLY_ALIASES_AT_MODELS_ENDPOINT` (false), `CONFIGURED_PROVIDER_MODELS_MODE` (`fallback` or `allowlist`, default `fallback`; `allowlist` skips upstream `/models` for providers with configured lists); persisted overrides restrict/allow selectors with `user_paths`. When alias-only models listing is enabled, `GET /v1/models` returns only model aliases, not full concrete model specs, to operators. | ||
| - **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30) | ||
| - **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30) |
There was a problem hiding this comment.
Document the 10 MB size cap and too-large handling.
The PR objectives specify that base64 encoding is "capped at 10 MB; larger marked too_large." Users should be informed of this size limit to understand the behavior when audio exceeds this threshold.
📝 Suggested documentation update
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
+- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback (capped at 10 MB), upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CLAUDE.md` at line 119, Update the logging documentation for
LOGGING_LOG_AUDIO_BODIES to state that base64-encoded audio is capped at 10 MB
and that any audio payloads exceeding this limit are marked "too_large" rather
than being logged; mention this applies to the /v1/audio/speech endpoint (base64
audio for playback) and transcription uploads, and clarify that this cap is
independent of LOGGING_LOG_BODIES so users understand the behavior when audio
exceeds the threshold.
Add storage warning for audio logging.
The code comment in config/logging.go includes a critical warning: "WARNING: stores full audio in the audit log; grows storage quickly." This warning should be included in the user-facing documentation to help users understand the storage implications before enabling this feature.
Based on learnings, documentation should "explain when to change" defaults—the storage warning is essential context for that decision.
📝 Suggested documentation addition
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
+- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`; ⚠️ stores full audio, grows storage quickly), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30) | |
| - **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`; ⚠️ stores full audio, grows storage quickly), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CLAUDE.md` at line 119, Update the CLAUDE.md audit logging line to include
the same storage warning present in config/logging.go for
LOGGING_LOG_AUDIO_BODIES: add a clear note that enabling
LOGGING_LOG_AUDIO_BODIES stores full audio in the audit log and can grow storage
quickly, and include guidance on when to change the default (e.g., only enable
for short-term debugging or with retention/purging policies). Reference the
setting name LOGGING_LOG_AUDIO_BODIES and mirror the warning phrasing from
config/logging.go so users see the storage implications before enabling it.
Document the /v1/audio/translations endpoint.
The PR objectives and endpoint registration include /v1/audio/translations as a supported audio endpoint, but the documentation only mentions /v1/audio/speech and transcriptions. Please add translations to the list of supported endpoints for completeness.
📝 Suggested documentation update
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)
+- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions/translations; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| - **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30) | |
| - **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: log audio endpoint inputs/outputs — base64 audio for `/v1/audio/speech` + dashboard playback, upload metadata for transcriptions/translations; independent of `LOGGING_LOG_BODIES`), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CLAUDE.md` at line 119, Update the audit logging docs entry that currently
lists `/v1/audio/speech` to also include `/v1/audio/translations`; specifically,
when describing `LOGGING_LOG_AUDIO_BODIES` and the logged audio endpoints, add
`/v1/audio/translations` alongside `/v1/audio/speech` and mention that it will
log base64 audio inputs/outputs (and dashboard playback) and upload metadata for
translations, and clarify that this behavior is independent of
`LOGGING_LOG_BODIES`.
Make LOGGING_LOG_AUDIO_BODIES a refinement of the master LOGGING_LOG_BODIES switch rather than an independent flag. Audio bodies are only captured when body logging is enabled; LOGGING_LOG_AUDIO_BODIES then decides whether the audio bytes are embedded as base64 (playable) or recorded as a placeholder. This avoids a privacy footgun: disabling LOGGING_LOG_BODIES for compliance now guarantees no content bodies are stored, including audio. The useful "log text but skip heavy audio" case is preserved (bodies on, audio off). Update docs/env/config comments accordingly and add gating tests covering the full matrix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (3)
CLAUDE.md (1)
119-119:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winInclude the 10 MB cap, storage warning, and
/v1/audio/translationsendpoint.Three documentation gaps:
- The 10 MB cap for base64 audio (documented in configuration.mdx) should be mentioned here
- The storage growth warning (present in config/logging.go and .env.template) is missing
/v1/audio/translationsis a supported endpoint but only speech and transcriptions are listed🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@CLAUDE.md` at line 119, Update the CLAUDE.md logging description to include the 10 MB base64 audio cap, the storage growth warning, and the missing audio translations endpoint: mention the 10 MB cap for base64 audio uploads (as in configuration.mdx), add the storage growth warning text present in config/logging.go and .env.template (explain logs can grow quickly and suggest retention or disabling), and list /v1/audio/translations alongside /v1/audio/speech and transcriptions in the supported endpoints sentence; reference the existing LOGGING_* flags (LOGGING_LOG_BODIES, LOGGING_LOG_AUDIO_BODIES, LOGGING_RETENTION_DAYS) when noting the audio size limit and retention behavior.docs/advanced/audio-api.mdx (1)
91-101:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winCorrect the placeholder format and add
/v1/audio/translations.Same two documentation issues as in configuration.mdx:
Placeholder format incomplete. Line 97 documents
{content_type, bytes}but should be{__audio__: true, content_type, bytes, stored: false}to match the actualAudioBodyLogstructure.Missing
/v1/audio/translations. Line 100 mentions/v1/audio/transcriptionsbut not/v1/audio/translations. Both STT endpoints behave identically (storing upload metadata, never raw audio bytes) and should be documented together.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/advanced/audio-api.mdx` around lines 91 - 101, Update the docs: replace the incomplete placeholder `{content_type, bytes}` with the actual AudioBodyLog shape `{__audio__: true, content_type, bytes, stored: false}` for the "Body logging on, audio off" case, and add `/v1/audio/translations` alongside `/v1/audio/transcriptions` noting that both STT endpoints store only upload metadata (filename, model, params) and never raw uploaded audio bytes; ensure the sentence mentions both endpoints behave identically and that `/v1/audio/speech` still stores full generated audio when audio logging is on.docs/advanced/configuration.mdx (1)
109-117:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winCorrect the placeholder format and add
/v1/audio/translations.Two documentation issues:
Placeholder format is incomplete. Line 115 documents
{content_type, bytes}but the actualAudioBodyLogstructure includes the__audio__marker field (seeinternal/auditlog/audio_body.go). The complete placeholder is{__audio__: true, content_type, bytes, stored: false}. The__audio__marker is essential for the dashboard to detect and render audio bodies.Missing
/v1/audio/translations. The PR adds audit logging for three endpoints (/v1/audio/speech,/v1/audio/transcriptions, and/v1/audio/translations), but line 112 only mentions transcriptions. Translations should be listed alongside transcriptions since both STT endpoints store upload metadata identically.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/advanced/configuration.mdx` around lines 109 - 117, Update the docs to match the actual AudioBodyLog structure and list all three audio endpoints: replace the incomplete placeholder `{content_type, bytes}` with the full marker form used by AudioBodyLog (`{__audio__: true, content_type, bytes, stored: false}` so the dashboard can detect audio), and add `/v1/audio/translations` alongside `/v1/audio/transcriptions` when describing STT endpoints that store upload metadata (also ensure `/v1/audio/speech` remains listed for the speech endpoint).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@CLAUDE.md`:
- Line 119: Update the CLAUDE.md logging description to include the 10 MB base64
audio cap, the storage growth warning, and the missing audio translations
endpoint: mention the 10 MB cap for base64 audio uploads (as in
configuration.mdx), add the storage growth warning text present in
config/logging.go and .env.template (explain logs can grow quickly and suggest
retention or disabling), and list /v1/audio/translations alongside
/v1/audio/speech and transcriptions in the supported endpoints sentence;
reference the existing LOGGING_* flags (LOGGING_LOG_BODIES,
LOGGING_LOG_AUDIO_BODIES, LOGGING_RETENTION_DAYS) when noting the audio size
limit and retention behavior.
In `@docs/advanced/audio-api.mdx`:
- Around line 91-101: Update the docs: replace the incomplete placeholder
`{content_type, bytes}` with the actual AudioBodyLog shape `{__audio__: true,
content_type, bytes, stored: false}` for the "Body logging on, audio off" case,
and add `/v1/audio/translations` alongside `/v1/audio/transcriptions` noting
that both STT endpoints store only upload metadata (filename, model, params) and
never raw uploaded audio bytes; ensure the sentence mentions both endpoints
behave identically and that `/v1/audio/speech` still stores full generated audio
when audio logging is on.
In `@docs/advanced/configuration.mdx`:
- Around line 109-117: Update the docs to match the actual AudioBodyLog
structure and list all three audio endpoints: replace the incomplete placeholder
`{content_type, bytes}` with the full marker form used by AudioBodyLog
(`{__audio__: true, content_type, bytes, stored: false}` so the dashboard can
detect audio), and add `/v1/audio/translations` alongside
`/v1/audio/transcriptions` when describing STT endpoints that store upload
metadata (also ensure `/v1/audio/speech` remains listed for the speech
endpoint).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: cdef5216-54df-4c19-8a7a-0b7053eef2b7
📒 Files selected for processing (8)
.env.templateCLAUDE.mdconfig/logging.godocs/advanced/audio-api.mdxdocs/advanced/configuration.mdxinternal/auditlog/auditlog.gointernal/server/audio_service.gointernal/server/audio_service_test.go
Validated automated review findings (greptile, CodeRabbit) and applied the
valid ones:
- Drop /v1/audio/translations from the endpoint classifier, tests, and docs:
the route is not registered or implemented, so classifying it was misleading
(greptile P1). Rejected the conflicting suggestion to document it.
- Move the response-writer truncation flag inside the non-audio branch so an
oversized audio response is not marked ResponseBodyTooBigToHandle while its
body is fully captured by the audio handler (CodeRabbit). Add a regression test.
- Dashboard CSS: use the defined --text-muted variable instead of the undefined
--muted (CodeRabbit).
- Clarify the audioBodyMaxBytes comment: the cap is on raw bytes; base64 is ~4/3
larger, which matters on document stores with a hard per-record limit such as
MongoDB's 16 MB (greptile P2).
- Set LogAudioBodies explicitly in DefaultConfig; correct the documented
placeholder shape to {__audio__, content_type, bytes, stored: false}; note the
10 MB cap in the CLAUDE.md reference (CodeRabbit).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
docs/advanced/configuration.mdx (1)
91-100:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFix the audit-logging defaults in this table.
LOGGING_LOG_BODIESandLOGGING_LOG_HEADERSare documented astruehere, but the audit config default ininternal/auditlog.DefaultConfig()isfalsefor both. Leaving the table as-is gives operators the wrong baseline for what gets persisted by default.As per coding guidelines, documentation should be concise, practical, and user-focused, showing defaults.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/advanced/configuration.mdx` around lines 91 - 100, Update the defaults in the configuration table to match the actual code defaults: change the LOGGING_LOG_BODIES and LOGGING_LOG_HEADERS entries from `true` to `false` so they align with internal/auditlog.DefaultConfig() (which sets both to false); ensure the table reflects the real defaults shown by that function and keep the rest of the variable descriptions unchanged.docs/advanced/audio-api.mdx (1)
94-101:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winComplete the body-logging behavior matrix.
This section currently describes the placeholder audio response, but it omits two load-bearing details from the feature contract: with audio logging off, the
/v1/audio/speechrequest JSON is also not stored; with audio logging on, transcription responses still follow normal body logging while only the uploaded audio bytes stay excluded. Without those, the retention behavior is easy to misread.As per coding guidelines, documentation should be concise, practical, and user-focused, showing defaults, explaining when to change them, and including minimal examples when useful.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/advanced/audio-api.mdx` around lines 94 - 101, The docs fragment about body-logging for audio is missing two contract details: update the paragraph that mentions LOGGING_LOG_BODIES and the `{__audio__, content_type, bytes, stored: false}` placeholder to state that when LOGGING_LOG_BODIES=false the `/v1/audio/speech` request JSON is not stored at all; and when body logging is on, clarify that `/v1/audio/transcriptions` responses follow normal body-logging semantics (metadata and text saved) but the raw uploaded audio bytes are never persisted. Keep the three-mode matrix (logging off / logging on audio off / logging on audio on), explicitly state the default, reference `/v1/audio/speech` and `/v1/audio/transcriptions`, and ensure the placeholder description and storage rules for request JSON vs. audio bytes are unambiguous.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/admin/dashboard/static/css/dashboard.css`:
- Line 2898: Replace the unnecessary fallback usage "var(--text-muted, `#888`)"
with the consistent "var(--text-muted)" wherever it appears (e.g., the color
declarations currently using var(--text-muted, `#888`)); remove the hardcoded
"`#888`" fallback so the stylesheet consistently relies on the :root variable and
matches other usages of --text-muted.
---
Outside diff comments:
In `@docs/advanced/audio-api.mdx`:
- Around line 94-101: The docs fragment about body-logging for audio is missing
two contract details: update the paragraph that mentions LOGGING_LOG_BODIES and
the `{__audio__, content_type, bytes, stored: false}` placeholder to state that
when LOGGING_LOG_BODIES=false the `/v1/audio/speech` request JSON is not stored
at all; and when body logging is on, clarify that `/v1/audio/transcriptions`
responses follow normal body-logging semantics (metadata and text saved) but the
raw uploaded audio bytes are never persisted. Keep the three-mode matrix
(logging off / logging on audio off / logging on audio on), explicitly state the
default, reference `/v1/audio/speech` and `/v1/audio/transcriptions`, and ensure
the placeholder description and storage rules for request JSON vs. audio bytes
are unambiguous.
In `@docs/advanced/configuration.mdx`:
- Around line 91-100: Update the defaults in the configuration table to match
the actual code defaults: change the LOGGING_LOG_BODIES and LOGGING_LOG_HEADERS
entries from `true` to `false` so they align with
internal/auditlog.DefaultConfig() (which sets both to false); ensure the table
reflects the real defaults shown by that function and keep the rest of the
variable descriptions unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2eeb2574-f490-429e-96ea-d879698ce690
📒 Files selected for processing (10)
CLAUDE.mddocs/advanced/audio-api.mdxdocs/advanced/configuration.mdxinternal/admin/dashboard/static/css/dashboard.cssinternal/auditlog/audio_body.gointernal/auditlog/auditlog.gointernal/auditlog/auditlog_test.gointernal/auditlog/middleware.gointernal/core/endpoints.gointernal/core/endpoints_test.go
💤 Files with no reviewable changes (1)
- internal/core/endpoints_test.go
| // ~4/3 of this (≈13.3 MB at the cap). On document stores with a hard per-record | ||
| // ceiling (e.g. MongoDB's 16 MB BSON limit) a near-cap clip plus other entry | ||
| // fields can approach that ceiling; lower this if you log audio to such a store. | ||
| const audioBodyMaxBytes = 10 * 1024 * 1024 |
There was a problem hiding this comment.
Encoded audio still exceeds storage
The cap is still applied to the raw audio size, so BuildAudioResponseBody accepts a 10 MiB speech response and then stores about 13.3 MiB of base64 in the audit entry. With MongoDB, that leaves very little room for request body, headers, workflow data, and BSON overhead before the 16 MiB document limit is exceeded. An otherwise allowed audio capture can fail the audit insert and lose the playback entry. The limit needs to be based on the stored representation or lowered enough to leave document headroom.
Context Used: CLAUDE.md (source)
Address the second round of PR review: - greptile (P1): the 10 MB cap was on raw bytes, so the stored base64 (~13.3 MB) left too little room under MongoDB's 16 MB BSON document limit once request, header, and workflow fields were added — a near-cap clip could fail the audit insert and drop the whole entry. Lower the raw cap to 8 MB (~10.7 MB base64), leaving comfortable headroom, and update the docs (8 MB). - CodeRabbit: drop the unnecessary `#888` fallback on `var(--text-muted)` to match the rest of the stylesheet (the variable is always defined in :root). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
♻️ Duplicate comments (4)
docs/advanced/configuration.mdx (1)
112-112:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winInclude
/v1/audio/translationsin the documentation.The PR adds audit logging for three endpoints (
/v1/audio/speech,/v1/audio/transcriptions, and/v1/audio/translations), but/v1/audio/translationsis not mentioned here. Both STT endpoints behave identically (storing metadata only).📝 Proposed fix
- dashboard can play it back, and `/v1/audio/transcriptions` stores upload metadata - (never the raw audio bytes). It defaults to `false` because audio payloads are + dashboard can play it back, and `/v1/audio/transcriptions` and + `/v1/audio/translations` store upload metadata (never the raw audio bytes). + It defaults to `false` because audio payloads are🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/advanced/configuration.mdx` at line 112, Update the sentence that currently reads "dashboard can play it back, and `/v1/audio/transcriptions` stores upload metadata" to also mention `/v1/audio/translations`, e.g., state that both `/v1/audio/transcriptions` and `/v1/audio/translations` store upload metadata and behave identically to `/v1/audio/speech`; ensure the new text references `/v1/audio/translations` explicitly so the docs reflect the added audit logging for that endpoint.docs/advanced/audio-api.mdx (1)
100-101:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winInclude
/v1/audio/translationsin the documentation.The PR adds audit logging for three endpoints, but
/v1/audio/translationsis not mentioned. It should be documented alongside/v1/audio/transcriptionssince both STT endpoints behave identically (storing metadata only).📝 Proposed fix
- player**, and `/v1/audio/transcriptions` stores upload metadata (filename, model, - params) but never the raw uploaded audio bytes. + player**, and `/v1/audio/transcriptions` and `/v1/audio/translations` store + upload metadata (filename, model, params) but never the raw uploaded audio bytes.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/advanced/audio-api.mdx` around lines 100 - 101, Update the sentence that currently references `/v1/audio/transcriptions` to also include `/v1/audio/translations`, clarifying that both STT endpoints store only upload metadata (filename, model, params) and not raw audio bytes; locate the sentence mentioning `/v1/audio/transcriptions` in docs/advanced/audio-api.mdx and change it to list both endpoints together (e.g., "/v1/audio/transcriptions and /v1/audio/translations store upload metadata...") so the documentation matches the added audit logging.CLAUDE.md (2)
119-119:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winDocument
/v1/audio/translationsendpoint.The PR objectives include
/v1/audio/translationsas a supported audio endpoint, but the documentation only mentions/v1/audio/speechand transcriptions. Based on learnings, documentation should be complete and practical.📝 Proposed fix
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: refines `LOGGING_LOG_BODIES` for audio endpoints — base64 audio for `/v1/audio/speech` (≤8 MB, else `too_large`) + dashboard playback, upload metadata for transcriptions; no effect unless `LOGGING_LOG_BODIES` is on, in which case audio-off records a placeholder), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30) +- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: refines `LOGGING_LOG_BODIES` for audio endpoints — base64 audio for `/v1/audio/speech` (≤8 MB, else `too_large`) + dashboard playback, upload metadata for transcriptions/translations; no effect unless `LOGGING_LOG_BODIES` is on, in which case audio-off records a placeholder), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@CLAUDE.md` at line 119, Update the audit-logging documentation sentence that currently only mentions `/v1/audio/speech` to also include `/v1/audio/translations` as a supported audio endpoint and describe how it interacts with the logging flags: state that when LOGGING_LOG_BODIES and LOGGING_LOG_AUDIO_BODIES are enabled, audio payloads for both `/v1/audio/speech` and `/v1/audio/translations` are recorded as base64 (capped at ≤8 MB, otherwise recorded as `too_large`) and available for dashboard playback, and when LOGGING_LOG_BODIES is off a placeholder is recorded; keep the references to LOGGING_ENABLED, LOGGING_LOG_HEADERS, and LOGGING_RETENTION_DAYS unchanged.
119-119:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd storage warning for audio logging.
Based on learnings, documentation should explain when to change defaults. The code comment in
config/logging.goincludes a storage warning that should appear in user-facing docs to help users understand the implications before enabling this feature.📝 Proposed fix
-- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: refines `LOGGING_LOG_BODIES` for audio endpoints — base64 audio for `/v1/audio/speech` (≤8 MB, else `too_large`) + dashboard playback, upload metadata for transcriptions; no effect unless `LOGGING_LOG_BODIES` is on, in which case audio-off records a placeholder), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30) +- **Audit logging:** `LOGGING_ENABLED` (false), `LOGGING_LOG_BODIES` (false), `LOGGING_LOG_AUDIO_BODIES` (false: refines `LOGGING_LOG_BODIES` for audio endpoints — base64 audio for `/v1/audio/speech` (≤8 MB, else `too_large`) + dashboard playback, upload metadata for transcriptions; ⚠️ stores full audio, grows storage quickly; no effect unless `LOGGING_LOG_BODIES` is on, in which case audio-off records a placeholder), `LOGGING_LOG_HEADERS` (false), `LOGGING_RETENTION_DAYS` (30)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@CLAUDE.md` at line 119, The docs list LOGGING_LOG_AUDIO_BODIES but lack the storage/usage warning present in config/logging.go; update CLAUDE.md to include a clear storage warning next to the LOGGING_LOG_AUDIO_BODIES description explaining that enabling audio body logging stores base64 audio (≤8 MB, else recorded as `too_large`), can significantly increase storage and retention costs, and only takes effect when LOGGING_LOG_BODIES is enabled; reference the same behavior and limits as defined by LOGGING_LOG_BODIES, LOGGING_LOG_AUDIO_BODIES and LOGGING_RETENTION_DAYS so users know when to change defaults.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@CLAUDE.md`:
- Line 119: Update the audit-logging documentation sentence that currently only
mentions `/v1/audio/speech` to also include `/v1/audio/translations` as a
supported audio endpoint and describe how it interacts with the logging flags:
state that when LOGGING_LOG_BODIES and LOGGING_LOG_AUDIO_BODIES are enabled,
audio payloads for both `/v1/audio/speech` and `/v1/audio/translations` are
recorded as base64 (capped at ≤8 MB, otherwise recorded as `too_large`) and
available for dashboard playback, and when LOGGING_LOG_BODIES is off a
placeholder is recorded; keep the references to LOGGING_ENABLED,
LOGGING_LOG_HEADERS, and LOGGING_RETENTION_DAYS unchanged.
- Line 119: The docs list LOGGING_LOG_AUDIO_BODIES but lack the storage/usage
warning present in config/logging.go; update CLAUDE.md to include a clear
storage warning next to the LOGGING_LOG_AUDIO_BODIES description explaining that
enabling audio body logging stores base64 audio (≤8 MB, else recorded as
`too_large`), can significantly increase storage and retention costs, and only
takes effect when LOGGING_LOG_BODIES is enabled; reference the same behavior and
limits as defined by LOGGING_LOG_BODIES, LOGGING_LOG_AUDIO_BODIES and
LOGGING_RETENTION_DAYS so users know when to change defaults.
In `@docs/advanced/audio-api.mdx`:
- Around line 100-101: Update the sentence that currently references
`/v1/audio/transcriptions` to also include `/v1/audio/translations`, clarifying
that both STT endpoints store only upload metadata (filename, model, params) and
not raw audio bytes; locate the sentence mentioning `/v1/audio/transcriptions`
in docs/advanced/audio-api.mdx and change it to list both endpoints together
(e.g., "/v1/audio/transcriptions and /v1/audio/translations store upload
metadata...") so the documentation matches the added audit logging.
In `@docs/advanced/configuration.mdx`:
- Line 112: Update the sentence that currently reads "dashboard can play it
back, and `/v1/audio/transcriptions` stores upload metadata" to also mention
`/v1/audio/translations`, e.g., state that both `/v1/audio/transcriptions` and
`/v1/audio/translations` store upload metadata and behave identically to
`/v1/audio/speech`; ensure the new text references `/v1/audio/translations`
explicitly so the docs reflect the added audit logging for that endpoint.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 019aca29-b954-42d4-a09f-07e5560f8625
📒 Files selected for processing (5)
CLAUDE.mddocs/advanced/audio-api.mdxdocs/advanced/configuration.mdxinternal/admin/dashboard/static/css/dashboard.cssinternal/auditlog/audio_body.go
Summary
Audio endpoints (
/v1/audio/speech,/v1/audio/transcriptions) were invisible to the audit log, and when bodies were captured the binary audio was corrupted. This PR makes audio fully auditable and adds opt-in, playable audio capture.Two logical commits:
fix(audit): log audio endpoints as model interactions— the audio paths were missing from the endpoint classifier, so they defaulted toModelInteraction:falseand were dropped by the audit middleware'sOnlyModelInteractionsgate. They are now classified (incl./v1/audio/translations) with correct body modes. NotIngressManaged— the handlers parse their own bodies.feat(audit): capture audio bodies behind LOGGING_LOG_AUDIO_BODIES— a new env var (default false), independent ofLOGGING_LOG_BODIES, controls audio input/output logging.Why
toValidUTF8String, replacing invalid bytes withU+FFFD— irreversibly corrupting the MP3, so a player could never reconstruct it.Behavior
LOGGING_LOG_AUDIO_BODIES{__audio__, content_type, bytes, stored:false}placeholdertoo_large)<audio controls>playerSTT logs upload metadata (filename, model, params) when enabled — never the raw audio bytes; its JSON response is captured by the normal path either way.
Implementation
internal/auditlog/audio_body.go):IsAudioContentType+BuildAudioResponseBody; newEnrichEntryWith{Request,Response}Bodyhelpers. The audit middleware now skips audio Content-Types so it neither corrupts nor clobbers handler-set bodies.internal/server/audio_service.go): captures request input before dispatch and audio output inrespondAudio, from the full untruncated bytes.config/logging.go,auditlog.Config, factory, startup log,.env.template).conversation-helpers.js,audit-list.js,dashboard.css): renders the player or placeholder; content-type and base64 are sanitized before building thedata:URL.Testing
audio_body_test.go(lossless round-trip / no-UTF8-corruption, gating, too-large) + extendedendpoints_test.goandIsModelInteractionPathcases.make test-race+make lintpass via pre-commit.audit-list.test.cjscases (player rendering, placeholder, XSS sanitization of content-type/base64) — 30/30 pass.🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Configuration
Documentation
Tests