diff --git a/pinecone/_internal/http_client.py b/pinecone/_internal/http_client.py index a756b3fc..3fa65f84 100644 --- a/pinecone/_internal/http_client.py +++ b/pinecone/_internal/http_client.py @@ -104,7 +104,14 @@ def _log_curl( headers: dict[str, str], body: bytes | None = None, ) -> None: - """Log a curl-equivalent command for debugging when PINECONE_DEBUG_CURL is set.""" + """Log a curl-equivalent command for debugging when PINECONE_DEBUG_CURL is set. + + Sensitive header values (see ``_SENSITIVE_HEADERS``) are redacted. The + request body is intentionally *not* logged verbatim: Pinecone request bodies + carry user vector and metadata payloads that may contain sensitive data + (e.g. PII embedded in metadata). Only the body size is emitted, and a + ``--data-binary @body.json`` placeholder shows where to supply it manually. + """ if not os.environ.get("PINECONE_DEBUG_CURL"): return safe_headers = _redact_headers(headers) @@ -112,7 +119,7 @@ def _log_curl( for key, value in safe_headers.items(): parts.append(f"-H '{key}: {value}'") if body is not None: - parts.append(f"-d '{body.decode('utf-8', errors='replace')}'") + parts.append(f"--data-binary @body.json # {len(body)} byte body omitted") curl_cmd = " ".join(parts) logger.debug("curl equivalent:\n%s", curl_cmd) diff --git a/tests/unit/test_debug_logging.py b/tests/unit/test_debug_logging.py index 923506fe..f0d9927e 100644 --- a/tests/unit/test_debug_logging.py +++ b/tests/unit/test_debug_logging.py @@ -82,9 +82,11 @@ def test_curl_logging_redacts_api_key( assert "my-secret-key-12345" not in caplog.text assert "Api-Key: ***" in caplog.text - def test_curl_logging_includes_body( + def test_curl_logging_omits_body_contents( self, monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture ) -> None: + # The raw request body must never be logged: it can carry user vector + # and metadata payloads (potentially PII). Only the byte count is shown. monkeypatch.setenv("PINECONE_DEBUG_CURL", "1") body = b'{"vectors": [{"id": "v1"}]}' with caplog.at_level(logging.DEBUG, logger="pinecone._internal.http_client"): @@ -94,8 +96,8 @@ def test_curl_logging_includes_body( {"Api-Key": "test-key", "Content-Type": "application/json"}, body=body, ) - assert "-d " in caplog.text - assert '{"vectors": [{"id": "v1"}]}' in caplog.text + assert '{"vectors": [{"id": "v1"}]}' not in caplog.text + assert f"{len(body)} byte body omitted" in caplog.text def test_curl_logging_includes_all_headers( self, monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture @@ -144,7 +146,9 @@ def test_post_logs_curl_with_body( finally: client.close() assert "curl -X POST" in caplog.text - assert "-d " in caplog.text + assert "byte body omitted" in caplog.text + # Raw request payload must not appear in logs. + assert '"id": "v1"' not in caplog.text @respx.mock def test_no_curl_output_when_disabled(