Validate input before credentials; fix help rendering and closed pipes#55
Merged
Conversation
…elp legibility
Six issues surfaced by CLI usability testing:
- Treat a missing/broken OS keyring backend as "no stored key": every
credentialed command (and aai doctor/init) crashed with a NoKeyringError
traceback on headless machines. Reads degrade to None, deletes are
suppressed, and run_command gains a last-resort handler so a bug prints
one clean line (JSON shape under --json), never a traceback.
- Document authentication in the root help (login / ASSEMBLYAI_API_KEY /
--env / AAI_ENV) and name the env var in the not-signed-in suggestion.
- Validate inputs before credentials: local audio paths are existence-
checked before key resolution (transcribe/stream/agent), and transcript
ids must be url-safe tokens before they reach the API path — a crafted
id could previously steer an authenticated GET to an arbitrary route.
whoami now honors ASSEMBLYAI_API_KEY as a preflight check for CI.
- Honor the closed-pipe-is-success contract end to end: Rich's console
and vendored Click both converted EPIPE to exit 1 before main.run()'s
BrokenPipeError handler could see it.
- Render flag names un-clipped at 80 columns (no more "--end-of-turn-c…"):
help-table name columns no longer shrink below their content, and the
one unfittable flag is renamed to --end-of-turn-confidence.
- Fold vendored Click's flag suggestion into the message instead of the
stringified tuple it printed ("('(Possible options: --json)',)").
https://claude.ai/code/session_012SruYtH5KNGh7pcwMqYrxc
…il gates Three paper cuts hit while working in this repo: - AGENTS.md's setup command (uv sync --extra dev) errors: dev tooling is a PEP 735 dependency group installed by default, not an extra. Say so. - A bare pytest ran the e2e/install/install_script suites, which need network/credentials and fail confusingly in sandboxes; addopts now carries the same -m exclusion check.sh uses (an explicit -m still overrides it). - The diff-cover and mutation gates are the slowest failures to discover via the full script; document how to re-run just those two stages. https://claude.ai/code/session_012SruYtH5KNGh7pcwMqYrxc
Rich force-enables color under GITHUB_ACTIONS, so in CI the option
highlighter interleaves style codes inside the error message ("No such
option: --zzqq") and the plain substring asserts fail. Compare on the
color-free render, same as the snapshot tests' _normalize.
https://claude.ai/code/session_012SruYtH5KNGh7pcwMqYrxc
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.
Summary
This PR hardens input validation to run before credential resolution, fixes help text rendering on narrow terminals, and ensures the CLI properly handles closed downstream pipes (e.g.,
aai … | head).Key Changes
Input validation before credentials:
resolve_audio_source()now checks that local file paths exist before any credential resolution, so typos read as "file not found" (exit 2) rather than auth failures or API errorsvalidate_transcript_id()to reject path traversal attempts (e.g.,../../etc/passwd) before they're interpolated into API request pathsget_transcript()validates the transcript ID before making the requesttranscribe,stream, andagentcommands now fail cleanly on missing local files before prompting for login--show-codepaths bypass the existence check (generating code for a file you don't have yet is legitimate)Help rendering fixes:
_NoClipTableto pin theno_wrapflag on all columns except the last two, preventing flag names like--end-of-turn-confidencefrom being clipped to--end-of-turn-c…on 80-column terminals"('(Possible options: --json)',)", now displays clean(Possible options: --json)Closed-pipe handling:
PipeSafeConsoleintheme.pyre-raisesBrokenPipeErrorinstead of converting it toSystemExit(1), soaai … | headexits 0 (success) rather than 1main.run()catches theSystemExit(1)that Typer's vendored Click raises when it detects a closed pipe (viaPacifyFlushWrapper) and rewrites it to exit 0Keyring robustness:
config.pynow treatskeyring.errors.NoKeyringError(headless machines with no keyring backend) as "no key stored" rather than crashing_keyring_get()helper wraps all keyring reads to suppressKeyringErrorexceptionsclear_api_key()andclear_session()now suppress the broaderKeyringError(not justPasswordDeleteError) to handle headless environmentsError handling improvements:
run_command()incontext.pynow catches unexpected exceptions and emits them as clean one-line errors (with JSON shape under--json) rather than tracebackscheck_source_exists()intranscribe_exec.pyto validate audio sources early in the transcribe flowDocumentation:
ASSEMBLYAI_API_KEYenv var,--env/AAI_ENVfor backend selectionAGENTS.mdto clarify that dev dependencies are a PEP 735[dependency-groups]group, not a[project]extraTesting
test_source_validation.pycovers file existence checks, transcript ID validation, and the validation-before-credentials contracttest_help_rendering.pypins flag rendering and unknown-flag suggestions across all commandstest_context.py,test_config.py,test_main_module.py, andtest_theme.pywith tests for the new error handling and closed-pipe behaviorhttps://claude.ai/code/session_012SruYtH5KNGh7pcwMqYrxc