Author SHA1 Message Date
Sharang ParnerkarandClaude Fable 5 55b42d7dbe fix(ci): make main deployable again — coverage, CVEs, and the image job
ci / e2e (pull_request) Blocked by required conditions
ci / shared (pull_request) Failing after 13s
ci / test (pull_request) Successful in 10m18s
ci / image (pull_request) Skipped
Found while preparing the tenant-registry enforcement flip: the deployed
portal image is from June 10, so the service-token code merged in #21
never shipped — flipping tenant-registry would have broken every portal
page. Three independent defects:

1. The image job's job-level hashFiles('Dockerfile') condition evaluates
   BEFORE checkout against an empty workspace — always false, job
   silently skipped on every main push. Same bug just fixed in
   tenant-registry (#16).

2. The test job was red on #21's merge: this repo pins 100%
   function/branch coverage and my local run skipped --coverage. Closed
   for real, not lowered: two dead json() arrows removed from mocks the
   code never reads (it throws on !ok before touching the body), and a
   new test exercising the expires_in ?? 300 default-lifetime branch.
   80 tests, 100/100/100/100.

3. The shared job's trivy gate was red on 14 real findings (3 CRITICAL):
   @auth/core 0.37.2 -> 0.41.3 (CVE-2026-73420, Unicode-normalization
   email homoglyph bypass — in the auth library this rollout depends on),
   next 16.2.6 -> 16.2.11, nanoid + postcss via pnpm overrides.
   next-auth 5.0.0-beta.25 -> beta.30; typecheck, lint and build clean
   on the new versions.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 23:16:10 +02:00
sharang f2f9ab74c8 RBAC: send a client_credentials service token to tenant-registry (#21)
ci / shared (push) Failing after 12s
ci / test (push) Failing after 5m3s
ci / e2e (push) Skipped
ci / image (push) Skipped
2026-08-25 09:15:47 +00:00
4 changed files with 121 additions and 102 deletions
+4 -1
View File
@@ -122,7 +122,10 @@ jobs:
# --service breakpilot-portal --branch main
# ) accepts unsigned payloads — orca matches on repo + branch.
needs: [shared, test]
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && hashFiles('Dockerfile') != ''
# NOTE: no hashFiles() here — at job level it evaluates BEFORE checkout
# against an empty workspace, so the old condition was always false and
# this job silently never ran (deployment sat on a June-10 image).
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
runs-on: docker
steps:
- uses: actions/checkout@v4
+10 -3
View File
@@ -23,8 +23,8 @@
"clsx": "^2.1.1",
"geist": "^1.7.2",
"lucide-react": "^1.17.0",
"next": "16.2.6",
"next-auth": "5.0.0-beta.25",
"next": "16.2.11",
"next-auth": "5.0.0-beta.30",
"react": "19.0.0",
"react-dom": "19.0.0",
"tailwind-merge": "^3.6.0"
@@ -48,5 +48,12 @@
"workerDirectory": [
"public"
]
},
"pnpm": {
"overrides": {
"nanoid@<3.3.18": ">=3.3.18",
"postcss@<8.4.31": ">=8.4.31",
"@auth/core@<0.41.3": ">=0.41.3"
}
}
}
}
+82 -96
View File
@@ -4,6 +4,11 @@ settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
overrides:
nanoid@<3.3.18: '>=3.3.18'
postcss@<8.4.31: '>=8.4.31'
'@auth/core@<0.41.3': '>=0.41.3'
importers:
.:
@@ -16,16 +21,16 @@ importers:
version: 2.1.1
geist:
specifier: ^1.7.2
version: 1.7.2(next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
version: 1.7.2(next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))
lucide-react:
specifier: ^1.17.0
version: 1.17.0(react@19.0.0)
next:
specifier: 16.2.6
version: 16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
specifier: 16.2.11
version: 16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
next-auth:
specifier: 5.0.0-beta.25
version: 5.0.0-beta.25(next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
specifier: 5.0.0-beta.30
version: 5.0.0-beta.30(next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
react:
specifier: 19.0.0
version: 19.0.0
@@ -86,12 +91,12 @@ packages:
resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==}
engines: {node: '>=6.0.0'}
'@auth/core@0.37.2':
resolution: {integrity: sha512-kUvzyvkcd6h1vpeMAojK2y7+PAV5H+0Cc9+ZlKYDFhDY31AlvsB+GW5vNO4qE3Y07KeQgvNO9U0QUx/fN62kBw==}
'@auth/core@0.41.3':
resolution: {integrity: sha512-sJ3JMHHkXMD3aOjopv7mOBTO1Ocw4b0fAEXJBz6k7YHLpYQI6C40jCUPc5fNvUKxXRXNE1/sRISA15UrwWJBTw==}
peerDependencies:
'@simplewebauthn/browser': ^9.0.1
'@simplewebauthn/server': ^9.0.2
nodemailer: ^6.8.0
nodemailer: ^7.0.7 || ^8.0.5
peerDependenciesMeta:
'@simplewebauthn/browser':
optional: true
@@ -581,56 +586,56 @@ packages:
'@emnapi/core': ^1.7.1
'@emnapi/runtime': ^1.7.1
'@next/env@16.2.6':
resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==}
'@next/env@16.2.11':
resolution: {integrity: sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==}
'@next/eslint-plugin-next@16.2.6':
resolution: {integrity: sha512-Z8l6o4JWKUl755x4R+wogD86KPeU+Ckw4K+SYG4kHeOJtRenDeK+OSbGcqZpDtbwn9DsJVdir2UxmwXuinUbUw==}
'@next/swc-darwin-arm64@16.2.6':
resolution: {integrity: sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==}
'@next/swc-darwin-arm64@16.2.11':
resolution: {integrity: sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
'@next/swc-darwin-x64@16.2.6':
resolution: {integrity: sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==}
'@next/swc-darwin-x64@16.2.11':
resolution: {integrity: sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
'@next/swc-linux-arm64-gnu@16.2.6':
resolution: {integrity: sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==}
'@next/swc-linux-arm64-gnu@16.2.11':
resolution: {integrity: sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@next/swc-linux-arm64-musl@16.2.6':
resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==}
'@next/swc-linux-arm64-musl@16.2.11':
resolution: {integrity: sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
'@next/swc-linux-x64-gnu@16.2.6':
resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==}
'@next/swc-linux-x64-gnu@16.2.11':
resolution: {integrity: sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@next/swc-linux-x64-musl@16.2.6':
resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==}
'@next/swc-linux-x64-musl@16.2.11':
resolution: {integrity: sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
'@next/swc-win32-arm64-msvc@16.2.6':
resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==}
'@next/swc-win32-arm64-msvc@16.2.11':
resolution: {integrity: sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
'@next/swc-win32-x64-msvc@16.2.6':
resolution: {integrity: sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==}
'@next/swc-win32-x64-msvc@16.2.11':
resolution: {integrity: sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@@ -897,9 +902,6 @@ packages:
'@tybys/wasm-util@0.10.2':
resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==}
'@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
@@ -1315,10 +1317,6 @@ packages:
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
cookie@0.7.1:
resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==}
engines: {node: '>= 0.6'}
cookie@1.1.1:
resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==}
engines: {node: '>=18'}
@@ -1931,8 +1929,8 @@ packages:
resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==}
hasBin: true
jose@5.10.0:
resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==}
jose@6.2.10:
resolution: {integrity: sha512-iiW7J9qRFlGxvCOIBDBDxFePQSn7ZMAnrYGhrrOo6siO/MIqwfyilLR27pkfDgUk+raLuzADS8A3S/KLBisc0g==}
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
@@ -2134,9 +2132,9 @@ packages:
resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==}
engines: {node: ^20.17.0 || >=22.9.0}
nanoid@3.3.12:
resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
nanoid@6.0.1:
resolution: {integrity: sha512-3wVS3i51pE2pi1k5FFL/95BGfVS0kSsvDVuGXHOtxox/TywUmtgq+3qiTOTbs9J7KfHaXPiN171k/A6dBnaXFw==}
engines: {node: ^22 || ^24 || >=26}
hasBin: true
napi-postinstall@0.3.4:
@@ -2147,14 +2145,14 @@ packages:
natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
next-auth@5.0.0-beta.25:
resolution: {integrity: sha512-2dJJw1sHQl2qxCrRk+KTQbeH+izFbGFPuJj5eGgBZFYyiYYtvlrBeUw1E/OJJxTRjuxbSYGnCTkUIRsIIW0bog==}
next-auth@5.0.0-beta.30:
resolution: {integrity: sha512-+c51gquM3F6nMVmoAusRJ7RIoY0K4Ts9HCCwyy/BRoe4mp3msZpOzYMyb5LAYc1wSo74PMQkGDcaghIO7W6Xjg==}
peerDependencies:
'@simplewebauthn/browser': ^9.0.1
'@simplewebauthn/server': ^9.0.2
next: ^14.0.0-0 || ^15.0.0-0
nodemailer: ^6.6.5
react: ^18.2.0 || ^19.0.0-0
next: ^14.0.0-0 || ^15.0.0 || ^16.0.0
nodemailer: ^7.0.7
react: ^18.2.0 || ^19.0.0
peerDependenciesMeta:
'@simplewebauthn/browser':
optional: true
@@ -2163,8 +2161,8 @@ packages:
nodemailer:
optional: true
next@16.2.6:
resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==}
next@16.2.11:
resolution: {integrity: sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==}
engines: {node: '>=20.9.0'}
hasBin: true
peerDependencies:
@@ -2310,21 +2308,18 @@ packages:
resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==}
engines: {node: ^10 || ^12 || >=14}
preact-render-to-string@5.2.3:
resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==}
preact-render-to-string@6.5.11:
resolution: {integrity: sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==}
peerDependencies:
preact: '>=10'
preact@10.11.3:
resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==}
preact@10.24.3:
resolution: {integrity: sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==}
prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
pretty-format@3.8.0:
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
@@ -2813,15 +2808,13 @@ snapshots:
'@jridgewell/gen-mapping': 0.3.13
'@jridgewell/trace-mapping': 0.3.31
'@auth/core@0.37.2':
'@auth/core@0.41.3':
dependencies:
'@panva/hkdf': 1.2.1
'@types/cookie': 0.6.0
cookie: 0.7.1
jose: 5.10.0
jose: 6.2.10
oauth4webapi: 3.8.6
preact: 10.11.3
preact-render-to-string: 5.2.3(preact@10.11.3)
preact: 10.24.3
preact-render-to-string: 6.5.11(preact@10.24.3)
'@babel/code-frame@7.29.0':
dependencies:
@@ -3242,34 +3235,34 @@ snapshots:
'@tybys/wasm-util': 0.10.2
optional: true
'@next/env@16.2.6': {}
'@next/env@16.2.11': {}
'@next/eslint-plugin-next@16.2.6':
dependencies:
fast-glob: 3.3.1
'@next/swc-darwin-arm64@16.2.6':
'@next/swc-darwin-arm64@16.2.11':
optional: true
'@next/swc-darwin-x64@16.2.6':
'@next/swc-darwin-x64@16.2.11':
optional: true
'@next/swc-linux-arm64-gnu@16.2.6':
'@next/swc-linux-arm64-gnu@16.2.11':
optional: true
'@next/swc-linux-arm64-musl@16.2.6':
'@next/swc-linux-arm64-musl@16.2.11':
optional: true
'@next/swc-linux-x64-gnu@16.2.6':
'@next/swc-linux-x64-gnu@16.2.11':
optional: true
'@next/swc-linux-x64-musl@16.2.6':
'@next/swc-linux-x64-musl@16.2.11':
optional: true
'@next/swc-win32-arm64-msvc@16.2.6':
'@next/swc-win32-arm64-msvc@16.2.11':
optional: true
'@next/swc-win32-x64-msvc@16.2.6':
'@next/swc-win32-x64-msvc@16.2.11':
optional: true
'@nodelib/fs.scandir@2.1.5':
@@ -3461,8 +3454,6 @@ snapshots:
tslib: 2.8.1
optional: true
'@types/cookie@0.6.0': {}
'@types/estree@1.0.8': {}
'@types/estree@1.0.9': {}
@@ -3910,8 +3901,6 @@ snapshots:
convert-source-map@2.0.0: {}
cookie@0.7.1: {}
cookie@1.1.1: {}
cross-spawn@7.0.6:
@@ -4415,9 +4404,9 @@ snapshots:
functions-have-names@1.2.3: {}
geist@1.7.2(next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)):
geist@1.7.2(next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)):
dependencies:
next: 16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
next: 16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
generator-function@2.0.1: {}
@@ -4695,7 +4684,7 @@ snapshots:
jiti@2.7.0: {}
jose@5.10.0: {}
jose@6.2.10: {}
js-tokens@4.0.0: {}
@@ -4878,21 +4867,21 @@ snapshots:
mute-stream@3.0.0: {}
nanoid@3.3.12: {}
nanoid@6.0.1: {}
napi-postinstall@0.3.4: {}
natural-compare@1.4.0: {}
next-auth@5.0.0-beta.25(next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0):
next-auth@5.0.0-beta.30(next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0):
dependencies:
'@auth/core': 0.37.2
next: 16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
'@auth/core': 0.41.3
next: 16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
react: 19.0.0
next@16.2.6(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
next@16.2.11(@babel/core@7.29.0)(@playwright/test@1.60.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
'@next/env': 16.2.6
'@next/env': 16.2.11
'@swc/helpers': 0.5.15
baseline-browser-mapping: 2.10.31
caniuse-lite: 1.0.30001793
@@ -4901,14 +4890,14 @@ snapshots:
react-dom: 19.0.0(react@19.0.0)
styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.0.0)
optionalDependencies:
'@next/swc-darwin-arm64': 16.2.6
'@next/swc-darwin-x64': 16.2.6
'@next/swc-linux-arm64-gnu': 16.2.6
'@next/swc-linux-arm64-musl': 16.2.6
'@next/swc-linux-x64-gnu': 16.2.6
'@next/swc-linux-x64-musl': 16.2.6
'@next/swc-win32-arm64-msvc': 16.2.6
'@next/swc-win32-x64-msvc': 16.2.6
'@next/swc-darwin-arm64': 16.2.11
'@next/swc-darwin-x64': 16.2.11
'@next/swc-linux-arm64-gnu': 16.2.11
'@next/swc-linux-arm64-musl': 16.2.11
'@next/swc-linux-x64-gnu': 16.2.11
'@next/swc-linux-x64-musl': 16.2.11
'@next/swc-win32-arm64-msvc': 16.2.11
'@next/swc-win32-x64-msvc': 16.2.11
'@playwright/test': 1.60.0
sharp: 0.34.5
transitivePeerDependencies:
@@ -5034,27 +5023,24 @@ snapshots:
postcss@8.4.31:
dependencies:
nanoid: 3.3.12
nanoid: 6.0.1
picocolors: 1.1.1
source-map-js: 1.2.1
postcss@8.5.15:
dependencies:
nanoid: 3.3.12
nanoid: 6.0.1
picocolors: 1.1.1
source-map-js: 1.2.1
preact-render-to-string@5.2.3(preact@10.11.3):
preact-render-to-string@6.5.11(preact@10.24.3):
dependencies:
preact: 10.11.3
pretty-format: 3.8.0
preact: 10.24.3
preact@10.11.3: {}
preact@10.24.3: {}
prelude-ls@1.2.1: {}
pretty-format@3.8.0: {}
prop-types@15.8.1:
dependencies:
loose-envify: 1.4.0
+25 -2
View File
@@ -107,10 +107,10 @@ describe("serviceToken", () => {
test("surfaces a rejected token request instead of calling unauthenticated", async () => {
configure();
// no json() on the mock: fetchToken throws on !ok before reading the body
vi.spyOn(globalThis, "fetch").mockResolvedValue({
ok: false,
status: 401,
json: async () => ({}),
} as Response);
await expect(serviceToken()).rejects.toThrow("service token request failed: 401");
@@ -130,13 +130,36 @@ describe("serviceToken", () => {
test("a failed fetch does not poison the cache", async () => {
configure();
vi.spyOn(globalThis, "fetch")
.mockResolvedValueOnce({ ok: false, status: 503, json: async () => ({}) } as Response)
.mockResolvedValueOnce({ ok: false, status: 503 } as Response)
.mockResolvedValueOnce(tokenResponse("tok-ok"));
await expect(serviceToken()).rejects.toThrow();
expect(await serviceToken()).toBe("tok-ok");
});
test("a response without expires_in gets the 300s default lifetime", async () => {
configure();
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-08-30T10:00:00Z"));
const fetchSpy = vi
.spyOn(globalThis, "fetch")
.mockResolvedValueOnce({
ok: true,
status: 200,
json: async () => ({ access_token: "tok-default" }),
} as Response)
.mockResolvedValueOnce(tokenResponse("tok-next"));
expect(await serviceToken()).toBe("tok-default");
// 4 minutes in: still inside the defaulted 300s window
vi.setSystemTime(new Date("2026-08-30T10:04:00Z"));
expect(await serviceToken()).toBe("tok-default");
// past the default expiry
vi.setSystemTime(new Date("2026-08-30T10:05:01Z"));
expect(await serviceToken()).toBe("tok-next");
expect(fetchSpy).toHaveBeenCalledTimes(2);
});
test("serviceAuthHeader carries the bearer token when configured", async () => {
configure();
vi.spyOn(globalThis, "fetch").mockResolvedValue(tokenResponse("tok-1"));