@@ -8,36 +8,20 @@ import {
88import { describe , expect , it } from 'vitest' ;
99
1010describe ( 'normalizeHeaderName' , ( ) => {
11- it ( 'returns "Authorization" as-is ' , ( ) => {
11+ it ( 'returns "Authorization" for case-insensitive match ' , ( ) => {
1212 expect ( normalizeHeaderName ( 'Authorization' ) ) . toBe ( 'Authorization' ) ;
13- } ) ;
14-
15- it ( 'normalizes case-insensitive "authorization" to "Authorization"' , ( ) => {
1613 expect ( normalizeHeaderName ( 'authorization' ) ) . toBe ( 'Authorization' ) ;
1714 expect ( normalizeHeaderName ( 'AUTHORIZATION' ) ) . toBe ( 'Authorization' ) ;
1815 expect ( normalizeHeaderName ( 'AuThOrIzAtIoN' ) ) . toBe ( 'Authorization' ) ;
1916 } ) ;
2017
21- it ( 'returns full header name with canonical prefix when prefix already present' , ( ) => {
22- const fullHeader = 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader' ;
23- expect ( normalizeHeaderName ( fullHeader ) ) . toBe ( fullHeader ) ;
24- } ) ;
25-
26- it ( 'normalizes prefix casing to canonical form' , ( ) => {
27- expect ( normalizeHeaderName ( 'x-amzn-bedrock-agentcore-runtime-custom-MyHeader' ) ) . toBe (
28- 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader'
18+ it ( 'returns other headers as-is without prefixing' , ( ) => {
19+ expect ( normalizeHeaderName ( 'MyHeader' ) ) . toBe ( 'MyHeader' ) ;
20+ expect ( normalizeHeaderName ( 'X-Custom-Signature' ) ) . toBe ( 'X-Custom-Signature' ) ;
21+ expect ( normalizeHeaderName ( 'X-Api-Key' ) ) . toBe ( 'X-Api-Key' ) ;
22+ expect ( normalizeHeaderName ( 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-Foo' ) ) . toBe (
23+ 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-Foo'
2924 ) ;
30- expect ( normalizeHeaderName ( 'X-AMZN-BEDROCK-AGENTCORE-RUNTIME-CUSTOM-MyHeader' ) ) . toBe (
31- 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader'
32- ) ;
33- } ) ;
34-
35- it ( 'auto-prefixes a bare suffix like "MyHeader"' , ( ) => {
36- expect ( normalizeHeaderName ( 'MyHeader' ) ) . toBe ( 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader' ) ;
37- } ) ;
38-
39- it ( 'auto-prefixes suffix with hyphens like "My-Custom-Header"' , ( ) => {
40- expect ( normalizeHeaderName ( 'My-Custom-Header' ) ) . toBe ( 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-My-Custom-Header' ) ;
4125 } ) ;
4226} ) ;
4327
@@ -50,18 +34,14 @@ describe('parseAndNormalizeHeaders', () => {
5034 expect ( parseAndNormalizeHeaders ( ' , , ' ) ) . toEqual ( [ ] ) ;
5135 } ) ;
5236
53- it ( 'splits comma-separated and normalizes' , ( ) => {
54- const result = parseAndNormalizeHeaders ( 'MyHeader, authorization, Another-Header' ) ;
55- expect ( result ) . toEqual ( [
56- 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader' ,
57- 'Authorization' ,
58- 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-Another-Header' ,
59- ] ) ;
37+ it ( 'splits comma-separated headers' , ( ) => {
38+ const result = parseAndNormalizeHeaders ( 'X-Custom-Signature, authorization, X-Api-Key' ) ;
39+ expect ( result ) . toEqual ( [ 'X-Custom-Signature' , 'Authorization' , 'X-Api-Key' ] ) ;
6040 } ) ;
6141
62- it ( 'deduplicates after normalization ' , ( ) => {
63- const result = parseAndNormalizeHeaders ( 'MyHeader, X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader ' ) ;
64- expect ( result ) . toEqual ( [ 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader ' ] ) ;
42+ it ( 'deduplicates case-insensitively keeping first occurrence ' , ( ) => {
43+ const result = parseAndNormalizeHeaders ( 'My-Header, MY-HEADER, my-header ' ) ;
44+ expect ( result ) . toEqual ( [ 'My-Header ' ] ) ;
6545 } ) ;
6646
6747 it ( 'deduplicates case-insensitive Authorization' , ( ) => {
@@ -70,12 +50,8 @@ describe('parseAndNormalizeHeaders', () => {
7050 } ) ;
7151
7252 it ( 'trims whitespace around values' , ( ) => {
73- const result = parseAndNormalizeHeaders ( ' MyHeader , authorization , Another-Header ' ) ;
74- expect ( result ) . toEqual ( [
75- 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader' ,
76- 'Authorization' ,
77- 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-Another-Header' ,
78- ] ) ;
53+ const result = parseAndNormalizeHeaders ( ' X-Custom , X-Api-Key ' ) ;
54+ expect ( result ) . toEqual ( [ 'X-Custom' , 'X-Api-Key' ] ) ;
7955 } ) ;
8056} ) ;
8157
@@ -85,34 +61,52 @@ describe('validateHeaderAllowlist', () => {
8561 expect ( validateHeaderAllowlist ( ' ' ) ) . toEqual ( { success : true } ) ;
8662 } ) ;
8763
88- it ( 'returns success for valid custom header suffix' , ( ) => {
89- expect ( validateHeaderAllowlist ( 'MyHeader' ) ) . toEqual ( { success : true } ) ;
90- } ) ;
91-
92- it ( 'returns success for valid full header name' , ( ) => {
93- expect ( validateHeaderAllowlist ( 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader' ) ) . toEqual ( { success : true } ) ;
64+ it ( 'returns success for valid custom headers' , ( ) => {
65+ expect ( validateHeaderAllowlist ( 'X-Custom-Signature' ) ) . toEqual ( { success : true } ) ;
66+ expect ( validateHeaderAllowlist ( 'X-Api-Key' ) ) . toEqual ( { success : true } ) ;
67+ expect ( validateHeaderAllowlist ( 'My_Header' ) ) . toEqual ( { success : true } ) ;
9468 } ) ;
9569
96- it ( 'returns success for " Authorization" ' , ( ) => {
70+ it ( 'returns success for Authorization' , ( ) => {
9771 expect ( validateHeaderAllowlist ( 'Authorization' ) ) . toEqual ( { success : true } ) ;
9872 expect ( validateHeaderAllowlist ( 'authorization' ) ) . toEqual ( { success : true } ) ;
9973 } ) ;
10074
75+ it ( 'returns success for the legacy prefix' , ( ) => {
76+ expect ( validateHeaderAllowlist ( 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-Foo' ) ) . toEqual ( { success : true } ) ;
77+ } ) ;
78+
10179 it ( 'returns success for mixed valid headers' , ( ) => {
102- expect ( validateHeaderAllowlist ( 'Authorization, MyHeader, X-Amzn-Bedrock-AgentCore-Runtime-Custom-Another' ) ) . toEqual (
103- { success : true }
104- ) ;
80+ expect ( validateHeaderAllowlist ( 'Authorization, X-Custom-Signature, X-Api-Key' ) ) . toEqual ( { success : true } ) ;
81+ } ) ;
82+
83+ it ( 'returns error for x-amz- prefix' , ( ) => {
84+ const result = validateHeaderAllowlist ( 'x-amz-security-token' ) ;
85+ expect ( result . success ) . toBe ( false ) ;
86+ expect ( result . error ) . toContain ( 'x-amz-' ) ;
87+ } ) ;
88+
89+ it ( 'returns error for x-amzn- prefix without allowed exception' , ( ) => {
90+ const result = validateHeaderAllowlist ( 'x-amzn-something' ) ;
91+ expect ( result . success ) . toBe ( false ) ;
92+ expect ( result . error ) . toContain ( 'x-amzn-' ) ;
93+ } ) ;
94+
95+ it ( 'returns error for restricted headers' , ( ) => {
96+ const result = validateHeaderAllowlist ( 'Content-Type' ) ;
97+ expect ( result . success ) . toBe ( false ) ;
98+ expect ( result . error ) . toContain ( 'restricted' ) ;
10599 } ) ;
106100
107101 it ( 'returns error when exceeding max 20 headers' , ( ) => {
108- const headers = Array . from ( { length : 21 } , ( _ , i ) => `Header${ i } ` ) . join ( ', ' ) ;
102+ const headers = Array . from ( { length : 21 } , ( _ , i ) => `X- Header- ${ i } ` ) . join ( ', ' ) ;
109103 const result = validateHeaderAllowlist ( headers ) ;
110104 expect ( result . success ) . toBe ( false ) ;
111105 expect ( result . error ) . toContain ( '20' ) ;
112106 } ) ;
113107
114108 it ( 'returns success for exactly 20 headers' , ( ) => {
115- const headers = Array . from ( { length : 20 } , ( _ , i ) => `Header${ i } ` ) . join ( ', ' ) ;
109+ const headers = Array . from ( { length : 20 } , ( _ , i ) => `X- Header- ${ i } ` ) . join ( ', ' ) ;
116110 expect ( validateHeaderAllowlist ( headers ) ) . toEqual ( { success : true } ) ;
117111 } ) ;
118112
@@ -127,20 +121,24 @@ describe('validateHeaderAllowlist', () => {
127121 expect ( result . success ) . toBe ( false ) ;
128122 expect ( result . error ) . toContain ( 'Invalid header name' ) ;
129123 } ) ;
124+
125+ it ( 'allows underscores in header names' , ( ) => {
126+ expect ( validateHeaderAllowlist ( 'My_Custom_Header' ) ) . toEqual ( { success : true } ) ;
127+ } ) ;
130128} ) ;
131129
132130describe ( 'parseHeaderFlag' , ( ) => {
133131 it ( 'parses "Key: Value" format' , ( ) => {
134- expect ( parseHeaderFlag ( 'MyHeader: some-value ' ) ) . toEqual ( {
135- name : 'X-Amzn-Bedrock-AgentCore-Runtime- Custom-MyHeader ' ,
136- value : 'some-value ' ,
132+ expect ( parseHeaderFlag ( 'X-Custom-Signature: sha256=abc123 ' ) ) . toEqual ( {
133+ name : 'X-Custom-Signature ' ,
134+ value : 'sha256=abc123 ' ,
137135 } ) ;
138136 } ) ;
139137
140138 it ( 'parses "Key:Value" format without space' , ( ) => {
141- expect ( parseHeaderFlag ( 'MyHeader:some-value ' ) ) . toEqual ( {
142- name : 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-MyHeader ' ,
143- value : 'some-value ' ,
139+ expect ( parseHeaderFlag ( 'X-Api-Key:my-key ' ) ) . toEqual ( {
140+ name : 'X-Api-Key ' ,
141+ value : 'my-key ' ,
144142 } ) ;
145143 } ) ;
146144
@@ -151,7 +149,7 @@ describe('parseHeaderFlag', () => {
151149 } ) ;
152150 } ) ;
153151
154- it ( 'normalizes header names ' , ( ) => {
152+ it ( 'normalizes Authorization casing ' , ( ) => {
155153 expect ( parseHeaderFlag ( 'authorization: token' ) ) . toEqual ( {
156154 name : 'Authorization' ,
157155 value : 'token' ,
@@ -167,18 +165,18 @@ describe('parseHeaderFlag', () => {
167165 } ) ;
168166
169167 it ( 'trims whitespace from key and value' , ( ) => {
170- expect ( parseHeaderFlag ( ' MyHeader : some-value ' ) ) . toEqual ( {
171- name : 'X-Amzn-Bedrock-AgentCore-Runtime- Custom-MyHeader ' ,
168+ expect ( parseHeaderFlag ( ' X-Custom : some-value ' ) ) . toEqual ( {
169+ name : 'X-Custom' ,
172170 value : 'some-value' ,
173171 } ) ;
174172 } ) ;
175173} ) ;
176174
177175describe ( 'parseHeaderFlags' , ( ) => {
178176 it ( 'parses multiple headers' , ( ) => {
179- const result = parseHeaderFlags ( [ 'MyHeader : value1' , 'Authorization: Bearer token' ] ) ;
177+ const result = parseHeaderFlags ( [ 'X-Custom-Signature : value1' , 'Authorization: Bearer token' ] ) ;
180178 expect ( result ) . toEqual ( {
181- 'X-Amzn-Bedrock-AgentCore-Runtime- Custom-MyHeader ' : 'value1' ,
179+ 'X-Custom-Signature ' : 'value1' ,
182180 Authorization : 'Bearer token' ,
183181 } ) ;
184182 } ) ;
@@ -188,9 +186,9 @@ describe('parseHeaderFlags', () => {
188186 } ) ;
189187
190188 it ( 'last value wins for duplicate keys' , ( ) => {
191- const result = parseHeaderFlags ( [ 'MyHeader : first' , 'MyHeader : second' ] ) ;
189+ const result = parseHeaderFlags ( [ 'X-Custom : first' , 'X-Custom : second' ] ) ;
192190 expect ( result ) . toEqual ( {
193- 'X-Amzn-Bedrock-AgentCore-Runtime- Custom-MyHeader ' : 'second' ,
191+ 'X-Custom' : 'second' ,
194192 } ) ;
195193 } ) ;
196194
0 commit comments