fix(v1): redact ffmpeg argv + 400 on missing model for /v1/audio (#14 #18)#69
Merged
Merged
Conversation
…18) Two harness findings on the OpenAI-compatible audio routes: - #14: POST /v1/audio/transcriptions with a non-audio body could leak the moonshine container's ffmpeg argv + tempfile path through the proxy when an out-of-tree / older upstream returned a raw CalledProcessError repr. The dispatcher forwards upstream bodies verbatim by design, so the audio route now scrubs the response for the leak markers ("ffmpeg" / "CalledProcessError") and substitutes a clean 415 envelope with code=audio.unsupported_format. New UnsupportedMediaType subclass added to hal0.errors so other 415 call sites have an ergonomic on-ramp. - #18: POST /v1/audio/speech with a body missing the 'model' field previously fell through the dispatcher's default-model + no-route path and surfaced a misleading 404. The route now raises BadRequest up front with code=request.missing_model so OpenAI clients see the real problem (matching field added on /v1/audio/transcriptions for consistency). Existing tests' code assertion updated from validation.invalid to request.missing_model. Tests ===== - tests/api/test_v1_audio.py (new) covers: * non-audio multipart → 415 audio.unsupported_format, no "ffmpeg" or "CalledProcessError" substring in the response body * clean upstream 5xx body passes through untouched (scrubber narrowness) * /v1/audio/speech missing model → 400 request.missing_model * /v1/audio/speech empty/whitespace model → 400 request.missing_model * happy-path STT + TTS via httpx.MockTransport round-trip * sanity: scrubber leaves non-audio routes alone Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0c4ce34 to
5458a0d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes findings #14 and #18 from tests/harness/FINDINGS.md.
What
test(comfyui): accept digest-pinned image_ref form #14 —
POST /v1/audio/transcriptionswith a non-audio body could surface the moonshine container's ffmpeg argv + tempfile path through the proxy when an out-of-tree / older upstream returned a rawCalledProcessErrorrepr. The dispatcher forwards upstream bodies verbatim by design, so the audio route now scrubs the response for the leak markers (ffmpeg/CalledProcessError) and substitutes a clean 415 envelope withcode=audio.unsupported_format. NewUnsupportedMediaTypesubclass added tohal0.errorsso future 415 call sites have an ergonomic on-ramp.fix(installer): uninstall.sh dev mode + hal0-caddy unit cleanup #18 —
POST /v1/audio/speechwith a body missing themodelfield used to fall through the dispatcher's default-model + no-route path and surface a misleading 404. The route now raisesBadRequestup front withcode=request.missing_modelso OpenAI clients see the real problem. Matching field added on/v1/audio/transcriptionsfor consistency (its existing 400 was onvalidation.invalid— rebadged).Tests
New
tests/api/test_v1_audio.py:audio.unsupported_format, body free offfmpeg/CalledProcessError//tmp//v1/audio/speechmissingmodel→ 400request.missing_model/v1/audio/speechwhitespace-onlymodel→ 400request.missing_modelhttpx.MockTransport(asserts multipart forwarded verbatim with boundary intact)httpx.MockTransport(asserts binary audio bytes flow through)/v1/chat/completionsaloneExisting tests:
tests/api/test_v1_dispatch.pymissing-model assertions to the new code (request.missing_model)UnsupportedMediaTyperow totests/api/test_typed_errors.pyenvelope round-trip parametrize tableTest plan
uv run ruff check src/hal0 tests— cleanuv run ruff format --check src/hal0 tests— cleanuv run pytest tests/api/test_v1_audio.py tests/api/test_v1_dispatch.py tests/api/test_typed_errors.py— 30/30 pass