Setting the file. One moment.
Test Source Baseline · LLM To Bedrock · aws/agent-toolkit-for-aws · Skills Docs
ContentsBack to the top of the page 81
Creating Amazon Aurora Db Cluster With Instances
104
Routing Traffic With Route53 And CloudFront
Resilience Program Design
Creating API Gateway Stage
def test_error_detail_handles_non_json_and_is_bounded
— line 101
This file
Number 30.32
Position 32 of 35
Type Python
Size 8 KB
Lines 191 scripts/ test_source_baseline.py
Python · 191 lines · 8 KB
"OPENAI_API_KEY"
,
"ANTHROPIC_API_KEY"
,
"GEMINI_API_KEY"
):
14 os.environ.pop(k, None )
15 os.environ.update(keys)
16
17
18 def test_openai_shape_uses_max_completion_tokens ():
19 _with_keys( OPENAI_API_KEY = "sk-test" )
20 url, headers, body = sb.build_openai_request( "gpt-4o" , "sys" , "hi" )
21 assert url == "https://api.openai.com/v1/chat/completions"
22 assert body[ "max_completion_tokens" ] == sb. MAX_TOKENS
23 assert "max_tokens" not in body, "gpt-5.x rejects max_tokens (HTTP 400)"
24 assert body[ "messages" ][ 0 ] == { "role" : "system" , "content" : "sys" }
25
26
27 def test_openai_no_system_message_when_empty ():
28 _with_keys( OPENAI_API_KEY = "sk-test" )
29 _, _, body = sb.build_openai_request( "gpt-4o" , "" , "hi" )
30 assert [m[ "role" ] for m in body[ "messages" ]] == [ "user" ]
31
32
33 def test_anthropic_shape_uses_top_level_system ():
34 _with_keys( ANTHROPIC_API_KEY = "sk-ant" )
35 url, headers, body = sb.build_anthropic_request( "claude-3-5-sonnet" , "sys" , "hi" )
36 assert url == "https://api.anthropic.com/v1/messages"
37 assert body[ "system" ] == "sys"
38 assert headers[ "anthropic-version" ] == "2023-06-01"
39 assert body[ "max_tokens" ] == sb. MAX_TOKENS
40
41
42 def test_gemini_key_in_header_never_in_url ():
43 _with_keys( GEMINI_API_KEY = "AIza-test" )
44 url, headers, body = sb.build_gemini_request( "gemini-1.5-pro" , "sys" , "hi" )
45 assert "AIza-test" not in url, "key must never be a URL query parameter"
46 assert "key=" not in url
47 assert headers[ "x-goog-api-key" ] == "AIza-test"
48 assert body[ "systemInstruction" ] == { "parts" : [{ "text" : "sys" }]}
49 assert body[ "generationConfig" ][ "maxOutputTokens" ] == sb. MAX_TOKENS
50
51
52 def test_all_provider_urls_are_official_hosts ():
53 # Security note in the skill: the key only ever travels to its own
54 # provider's official endpoint.
55 _with_keys( OPENAI_API_KEY = "a" , ANTHROPIC_API_KEY = "b" , GEMINI_API_KEY = "c" )
56 urls = [
57 sb.build_openai_request( "m" , "" , "x" )[ 0 ],
58 sb.build_anthropic_request( "m" , "" , "x" )[ 0 ],
59 sb.build_gemini_request( "m" , "" , "x" )[ 0 ],
60 ]
61 allowed = ( "https://api.openai.com/" , "https://api.anthropic.com/" ,
62 "https://generativelanguage.googleapis.com/" )
63 for u in urls:
64 assert u.startswith(allowed), u
65
66
67 def test_env_file_loader_ignores_blank_and_malformed_lines (tmp_path: pathlib.Path):
68 p = tmp_path / ".source-provider-env"
69 p.write_text( " \n # comment-ish \n OPENAI_API_KEY=sk-live \n " , encoding = "utf-8" )
70 os.environ.pop( "OPENAI_API_KEY" , None )
71 sb.load_env_file( str (p))
72 assert os.environ[ "OPENAI_API_KEY" ] == "sk-live"
73
74
75 def test_provider_selected_from_file_not_ambient_env (tmp_path):
76 # Review finding: file is authoritative; ambient keys must not win.
77 _with_keys( OPENAI_API_KEY = "sk-ambient" )
78 p = tmp_path / ".source-provider-env"
79 p.write_text( "GEMINI_API_KEY=AIza-file \n " , encoding = "utf-8" )
80 pairs = sb.load_env_file( str (p))
81 provider = next (k for k in sb. PROVIDERS if k in pairs)
82 assert provider == "GEMINI_API_KEY"
83
84
85 def _http_error (code, reason, body: bytes ):
86 import io
87 import urllib.error
88 return urllib.error.HTTPError(
89 "https://api.openai.com/v1/chat/completions" , code, reason,
90 hdrs = None , fp = io.BytesIO(body),
91 )
92
93
94 def test_error_detail_extracts_message_and_param ():
95 # Review finding: the evaluator contract needs the 400 body's
96 # message/param — reason alone is just "Bad Request".
97 e = _http_error( 400 , "Bad Request" , b '{"error": {"message": "Unsupported parameter: max_tokens", "param": "max_tokens", "type": "invalid_request_error"}}' )
98 assert sb.error_detail(e) == "Unsupported parameter: max_tokens (param: max_tokens)"
99
100
101 def test_error_detail_handles_non_json_and_is_bounded ():
102 e = _http_error( 502 , "Bad Gateway" , b "<html>upstream error</html>" * 200 )
103 d = sb.error_detail(e)
104 assert d.startswith( "<html>upstream error" )
105 assert len (d) <= 200
106
107
108 def test_error_detail_never_raises_on_unreadable_body ():
109 import urllib.error
110 e = urllib.error.HTTPError( "https://api.openai.com/x" , 400 , "Bad Request" , None , None )
111 assert sb.error_detail(e) == ""
112
113
114 def test_status_line_keeps_contract_prefix ():
115 # Step-3 classification greps on the "http_<code>" prefix — the appended
116 # detail must not break it.
117 e = _http_error( 400 , "Bad Request" , b '{"error": {"message": "Unsupported parameter"}}' )
118 detail = sb.error_detail(e)
119 status = f "http_ { e.code } : { e.reason } " + ( f " — { detail } " if detail else "" )
120 assert status.startswith( "http_400: Bad Request" )
121 assert "Unsupported parameter" in status
122
123
124 def test_auth_error_bodies_are_suppressed_entirely ():
125 # Review finding: an auth endpoint can echo the submitted credential in
126 # its body, and 401/403 classification uses the code alone — so auth
127 # bodies carry no detail at all.
128 for code, reason in (( 401 , "Unauthorized" ), ( 403 , "Forbidden" )):
129 e = _http_error(code, reason, b '{"error": {"message": "bad key sk-live-SECRETKEY123"}}' )
130 assert sb.error_detail(e, [ "sk-live-SECRETKEY123" ]) == ""
131 status = f "http_ { e.code } : { e.reason } "
132 assert "SECRETKEY123" not in status
133
134
135 def test_echoed_key_never_reaches_detail_or_status ():
136 # Review repro: FULL_SECRET_IN_DETAIL must be impossible. A 400 body that
137 # echoes the key (JSON path) and a non-JSON fallback that echoes it are
138 # both redacted inside error_detail itself.
139 secrets = [ "sk-live-SECRETKEY123" ]
140 e = _http_error( 400 , "Bad Request" , b '{"error": {"message": "invalid key sk-live-SECRETKEY123 for model"}}' )
141 d = sb.error_detail(e, secrets)
142 assert "SECRETKEY123" not in d and "***" in d
143 e2 = _http_error( 500 , "Server Error" , b "upstream said: sk-live-SECRETKEY123 rejected" )
144 d2 = sb.error_detail(e2, secrets)
145 assert "SECRETKEY123" not in d2 and "***" in d2
146
147
148 def test_redact_strips_key_from_exception_status ():
149 # Review finding: http.client rejects an invalid header with the FULL
150 # header value in the ValueError message — 'Bearer sk-live-KEY' would land
151 # in the status JSONL, breaking the never-in-output promise.
152 msg = "error: ValueError: Invalid header value b'Bearer sk-live-SECRET123 \\ rX'"
153 assert "SECRET123" not in sb.redact(msg, [ "sk-live-SECRET123" ])
154 assert "***" in sb.redact(msg, [ "sk-live-SECRET123" ])
155
156
157 def test_redact_tolerates_empty_secrets ():
158 assert sb.redact( "error: boom" , [ "" , None ]) == "error: boom"
159
160
161 def test_source_provider_env_is_authoritative (tmp_path, monkeypatch):
162 # Review finding: a file carrying several provider keys must not fall back
163 # to dict-order guessing (OpenAI-first) — SOURCE_PROVIDER, the helper's
164 # declared input, decides.
165 pairs = { "OPENAI_API_KEY" : "a" , "ANTHROPIC_API_KEY" : "b" }
166 monkeypatch.setenv( "SOURCE_PROVIDER" , "anthropic" )
167 assert sb.pick_provider_key(pairs) == "ANTHROPIC_API_KEY"
168 monkeypatch.setenv( "SOURCE_PROVIDER" , "openai" )
169 assert sb.pick_provider_key(pairs) == "OPENAI_API_KEY"
170 # stated provider whose key is NOT in the file → hard None, never a guess
171 monkeypatch.setenv( "SOURCE_PROVIDER" , "google" )
172 assert sb.pick_provider_key(pairs) is None
173 monkeypatch.delenv( "SOURCE_PROVIDER" )
174 assert sb.pick_provider_key(pairs) == "OPENAI_API_KEY"
175
176
177 def test_redact_catches_escaped_control_chars_in_exception_text ():
178 # Adjudicated finding: a raw CR inside the credential renders ESCAPED in
179 # exception text (one control char -> backslash-r as two characters), so
180 # literal replacement missed it and the key leaked in escaped form.
181 secret = "sk-live-SECRET \r KEY123"
182 escaped_msg = "error: ValueError: Invalid header value b'Bearer sk-live-SECRET \\ rKEY123'"
183 out = sb.redact(escaped_msg, [secret])
184 assert "SECRET" not in out and "KEY123" not in out
185
186
187 def test_redact_catches_fragments_around_control_chars ():
188 # Even a partial echo of either side of the control char must not survive.
189 secret = "sk-live-SECRET \n KEY123456"
190 out = sb.redact( "provider said sk-live-SECRET then KEY123456 rejected" , [secret])
191 assert "sk-live-SECRET" not in out and "KEY123456" not in out