Repository navigation
Conversation
The CLI already redacts api_key=... in output_error(), but unhandled exceptions bypass it: in --json mode main() prints str(exc), and in text mode Python prints the traceback. For requests errors (connection failures, raise_for_status) both contain the request URL with the key. Move the pattern into roboflow.util.redact.redact_api_key() and apply it in main() for both modes, in RoboflowError and its subclasses (which wrap requests errors, for example in image uploads), and in the error lines the SDK prints for failed model and image uploads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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
Follow-up to 183d0d4, which redacts
api_key=...inoutput_error(). Three paths still print the key, because most requests pass it as a URL query parameter andrequestsputs the full URL into its exception messages:requests.ConnectionErrorfromrfapi.get_project: in--jsonmodemain()printsstr(exc), in text mode Python prints the traceback.RoboflowError,ImageUploadErrorandAnnotationSaveErrormessages that wraprequestserrors (for exampleImageUploadError(str(e))inrfapi.upload_image), whichWorkspace.upload_dataset()prints per image.Version.deploy()andWorkspace.deploy_model()print for failed model uploads.Example on
main:With this PR the message contains
api_key=***. Text mode prints the same traceback as before, with the key replaced, and still exits with code 1.Changes:
roboflow/util/redact.py:redact_api_key(), the pattern fromcli/_output._sanitize_credentials(), which now delegates to it.roboflow/cli/__init__.py:main()redacts unhandled errors in JSON mode and prints a redacted traceback in text mode.roboflow/adapters/rfapi.py:RoboflowErrorand its subclasses redact their message.roboflow/core/version.py,roboflow/core/workspace.py: the printed upload errors are redacted.Proposal: send the key as a header instead
Redaction only treats the symptom. A URL with the key also ends up in server and proxy access logs, and raw
requestsexceptions raised from SDK functions still contain it for SDK users. The API acceptsAuthorization: Bearer <api_key>, and the SDK already uses it invision_events_api.py,workflowevalsapi.pyand the batch-processing helpers. In a read-only check, every read endpoint I tried accepted the header in place of?api_key=(workspace, project, version, batches, workspace search). I could not check write endpoints (image upload, annotation save, model upload, version generation) or the inference hosts without side effects.If you can confirm that all endpoints accept the header, the SDK could send it everywhere and stop putting the key into URLs; with a shared
requests.Session(#491) that would be a change in one place. I'm happy to help with that.Test plan
tests/util/test_redact.py: the helper, the three exception classes, and the printedVersion.deploy()error.tests/cli/test_redact_errors.py:main()in JSON and in text mode with a mockedrequests.ConnectionError. Both tests fail onmainand pass with this change.make check_code_qualitypasses;python -m unittestruns 1216 tests, OK (1 skipped). The slim job (tests.test_slim_compat,tests.test_vision_events) passes on Python 3.10.cc @yeldarby @iurisilvio