File tree Expand file tree Collapse file tree 5 files changed +59
-56
lines changed
Expand file tree Collapse file tree 5 files changed +59
-56
lines changed Original file line number Diff line number Diff line change 1818 - run : pnpm install --frozen-lockfile
1919 - run : pnpm run typecheck
2020 - run : pnpm test
21- - name : Verify CSP hash
22- run : node scripts/verify-csp-hash.mjs
21+ - name : Verify CSP inline script hash
22+ run : |
23+ SCRIPT=$(sed -n 's/.*<script>\(.*\)<\/script>.*/\1/p' index.html)
24+ HASH=$(printf '%s' "$SCRIPT" | openssl dgst -sha256 -binary | base64)
25+ if ! grep -q "sha256-$HASH" public/_headers; then
26+ echo "::error::CSP hash mismatch! Inline script hash 'sha256-$HASH' not found in public/_headers"
27+ echo "Update the sha256 hash in public/_headers to match the inline script in index.html"
28+ exit 1
29+ fi
30+ echo "CSP hash verified: sha256-$HASH"
2331 - name : WAF smoke tests
2432 run : pnpm test:waf
2533 - run : pnpm run build
Original file line number Diff line number Diff line change @@ -35,7 +35,7 @@ priority = 0
3535id = " csp-hash"
3636name = " CSP hash verification"
3737language = " system"
38- entry = " node scripts/verify-csp- hash.mjs "
38+ entry = " bash -c 'SCRIPT=$(sed -n \" s/.*<script> \\ (.* \\ )< \\ /script>.*/ \\ 1/p \" index.html) && HASH=$(printf \" %s \" \" $SCRIPT \" | openssl dgst -sha256 -binary | base64) && grep -q \" sha256-$HASH \" public/_headers && echo \" CSP hash OK: sha256-$HASH \" || { echo \" CSP hash mismatch! sha256-$HASH not in public/_headers \" ; exit 1; }' "
3939pass_filenames = false
4040always_run = true
4141priority = 0
Load Diff This file was deleted.
Original file line number Diff line number Diff line change @@ -341,6 +341,47 @@ describe("OAuthCallback", () => {
341341 expect ( sessionStorage . getItem ( OAUTH_RETURN_TO_KEY ) ) . toBe ( "/settings" ) ;
342342 } ) ;
343343
344+ it ( "OAUTH_RETURN_TO_KEY is preserved when validateToken returns false" , async ( ) => {
345+ sessionStorage . setItem ( OAUTH_RETURN_TO_KEY , "/settings" ) ;
346+ setupValidState ( ) ;
347+ setWindowSearch ( { code : "fakecode" , state : "teststate" } ) ;
348+ vi . stubGlobal (
349+ "fetch" ,
350+ vi . fn ( ) . mockResolvedValue ( {
351+ ok : true ,
352+ json : async ( ) => ( { access_token : "tok123" } ) ,
353+ } )
354+ ) ;
355+ vi . mocked ( authStore . validateToken ) . mockResolvedValue ( false ) ;
356+
357+ renderCallback ( ) ;
358+
359+ await waitFor ( ( ) => {
360+ screen . getByText ( / C o u l d n o t v e r i f y t o k e n / i) ;
361+ } ) ;
362+ expect ( sessionStorage . getItem ( OAUTH_RETURN_TO_KEY ) ) . toBe ( "/settings" ) ;
363+ } ) ;
364+
365+ it ( "OAUTH_RETURN_TO_KEY is preserved when token exchange fails" , async ( ) => {
366+ sessionStorage . setItem ( OAUTH_RETURN_TO_KEY , "/settings" ) ;
367+ setupValidState ( ) ;
368+ setWindowSearch ( { code : "fakecode" , state : "teststate" } ) ;
369+ vi . stubGlobal (
370+ "fetch" ,
371+ vi . fn ( ) . mockResolvedValue ( {
372+ ok : false ,
373+ json : async ( ) => ( { error : "bad_verification_code" } ) ,
374+ } )
375+ ) ;
376+
377+ renderCallback ( ) ;
378+
379+ await waitFor ( ( ) => {
380+ screen . getByText ( / F a i l e d t o c o m p l e t e s i g n i n / i) ;
381+ } ) ;
382+ expect ( sessionStorage . getItem ( OAUTH_RETURN_TO_KEY ) ) . toBe ( "/settings" ) ;
383+ } ) ;
384+
344385 it ( "navigates to / when OAUTH_RETURN_TO_KEY is not set" , async ( ) => {
345386 setupSuccessfulCallback ( ) ;
346387 renderCallback ( ) ;
Original file line number Diff line number Diff line change @@ -955,12 +955,18 @@ describe("Worker OAuth endpoint", () => {
955955 expect ( log ! . level ) . toBe ( "warn" ) ;
956956 } ) ;
957957
958- it ( "returns 404 when SENTRY_DSN is not configured " , async ( ) => {
958+ it ( "returns 404 when SENTRY_DSN is empty string " , async ( ) => {
959959 const req = makeTunnelRequest ( makeEnvelope ( VALID_DSN ) ) ;
960960 const res = await worker . fetch ( req , makeEnv ( { SENTRY_DSN : "" } ) ) ;
961961 expect ( res . status ) . toBe ( 404 ) ;
962962 } ) ;
963963
964+ it ( "returns 404 when SENTRY_DSN is undefined" , async ( ) => {
965+ const req = makeTunnelRequest ( makeEnvelope ( VALID_DSN ) ) ;
966+ const res = await worker . fetch ( req , makeEnv ( { SENTRY_DSN : undefined as unknown as string } ) ) ;
967+ expect ( res . status ) . toBe ( 404 ) ;
968+ } ) ;
969+
964970 it ( "returns 502 when Sentry is unreachable" , async ( ) => {
965971 globalThis . fetch = vi . fn ( ) . mockRejectedValue ( new Error ( "connection refused" ) ) ;
966972
You can’t perform that action at this time.
0 commit comments