Conversation
call_provider signed the Bedrock request over json.dumps(request_body) (default ", " / ": " separators) but then posted the dict through httpx's json= parameter. httpx >= 0.28 serialises json= with compact separators, so the bytes on the wire differ from the bytes that were hashed into x-amz-content-sha256 and the canonical request, and AWS rejects every Bedrock call with a signature mismatch. Post the exact signed string via content= for the bedrock provider so the hash and the body always agree; every other provider still uses json=.
|
Someone is attempting to deploy a commit to the Superagent Team on Vercel. A member of the Team first needs to authorize it. |
Contributor License AgreementAll contributors are covered by a CLA. |
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.
Calling the Python SDK with a
bedrock/...model fails on every request: AWS returns a SigV4 signature mismatch, because the payload hash the SDK signs is computed over different bytes than the ones httpx actually sends.Root cause
call_providerinsdk/python/src/safety_agent/providers/__init__.pysigns the Bedrock request overjson.dumps(request_body)(default", "/": "separators) and puts that hash inx-amz-content-sha256and the canonical request. It then posts the request withjson=request_body. httpx >= 0.28 serialisesjson=with compact(",", ":")separators, so the body on the wire no longer matches the signed payload.pyproject.tomlonly requireshttpx>=0.27.0and no lockfile is committed, so a freshuv syncinstalls 0.28.x and every Bedrock call is rejected.Fix
sdk/python/src/safety_agent/providers/__init__.py: build arequest_kwargsdict that is{"json": request_body}for every provider and{"content": payload.encode("utf-8")}for bedrock, wherepayloadis the exact string that was signed. The threeclient.post(...)sites use**request_kwargsinstead ofjson=request_body. Behaviour for all non-bedrock providers is unchanged.Tests
sdk/python/tests/test_bedrock_provider.py(new): mockshttpx.AsyncClient, callscall_provider("bedrock/..."), rebuilds the request withhttpx.Request(...)from the kwargs that were passed topost, and assertssha256(request.content)equals thex-amz-content-sha256header. Fails onmain(hash mismatch), passes with the fix.uv run pytestinsdk/python: 153 passed.Not changed
BedrockProvider.get_signed_headers) is untouched; it was correct for the string it was given.AWS_BEDROCK_API_KEYeither, which is why this never surfaced in CI).▚▚ Shipped by breken — self-healing software. This one's on us. breken.ai
Note
Low Risk
Targeted HTTP transport change for Bedrock only; non-Bedrock providers still use
json=and signing logic is unchanged.Overview
Fixes Bedrock SigV4 failures caused by a mismatch between the payload bytes signed for AWS and the body httpx actually sends when using
json=request_body(compact JSON in httpx 0.28+ vs the string fromjson.dumpsused for signing).call_providernow builds sharedrequest_kwargs: default{"json": request_body}for other providers, and for bedrock{"content": payload.encode("utf-8")}wherepayloadis the exact string passed into signing. All threeclient.postpaths use**request_kwargsinstead of hard-codedjson=.Adds
test_bedrock_provider.pywith a mocked httpx call that assertsx-amz-content-sha256matchessha256of the wire body rebuilt from the post kwargs.Reviewed by Cursor Bugbot for commit 27776c4. Configure here.