From fccb7323bf5a9a2db359128164a0b21f0d0fcde5 Mon Sep 17 00:00:00 2001 From: Daz DeBoer Date: Sat, 13 Jun 2026 16:34:44 -0600 Subject: [PATCH] Add resolveAccessKeyForServer for the project-cache trial Resolves the Develocity access key matching a given server URL, for threading into the new develocityAccessToken cache option (next commit). Reuses DevelocityAccessCredentials.parse and fails closed (returns undefined) when the access key is empty/malformed, the server URL is empty/unparseable, or no key matches the server host. Tolerates a bare hostname with no scheme. Extends short-lived-token.test.ts with coverage for full URLs, bare hostnames, host-only matching (ignoring scheme/port/path), multi-key selection, and the fail-closed cases. Co-Authored-By: Claude Opus 4.8 (1M context) --- sources/src/develocity/short-lived-token.ts | 19 +++++++++++ sources/test/jest/short-lived-token.test.ts | 36 ++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/sources/src/develocity/short-lived-token.ts b/sources/src/develocity/short-lived-token.ts index 3708887f..8a3281b8 100644 --- a/sources/src/develocity/short-lived-token.ts +++ b/sources/src/develocity/short-lived-token.ts @@ -174,3 +174,22 @@ export class DevelocityAccessCredentials { return this.accessKeyRegexp.test(allKeys) } } + +/** + * Resolve the access key that matches a given Develocity server, for use as the + * `develocityAccessToken` cache option. Returns `undefined` (fail-closed) when the access key is + * empty/malformed, the server URL is empty/unparseable, or no key matches the server's host. + */ +export function resolveAccessKeyForServer(accessKey: string, serverUrl: string): string | undefined { + const creds = DevelocityAccessCredentials.parse(accessKey) + if (!creds || !serverUrl) { + return undefined + } + let host: string + try { + host = new URL(serverUrl).hostname + } catch { + host = serverUrl // tolerate a bare hostname (no scheme) + } + return creds.keys.find(k => k.hostname === host)?.key +} diff --git a/sources/test/jest/short-lived-token.test.ts b/sources/test/jest/short-lived-token.test.ts index db9867a8..11ba0136 100644 --- a/sources/test/jest/short-lived-token.test.ts +++ b/sources/test/jest/short-lived-token.test.ts @@ -1,7 +1,7 @@ import nock from "nock"; import {describe, expect, it} from '@jest/globals' -import {DevelocityAccessCredentials, getToken} from "../../src/develocity/short-lived-token"; +import {DevelocityAccessCredentials, getToken, resolveAccessKeyForServer} from "../../src/develocity/short-lived-token"; describe('short lived tokens', () => { it('parse valid access key should return an object', async () => { @@ -134,3 +134,37 @@ describe('short lived tokens with retry', () => { .toBeNull() }) }) + +describe('resolveAccessKeyForServer', () => { + it('returns the key matching the server host from a full URL', () => { + expect(resolveAccessKeyForServer('ge.example.com=key1;other=key2', 'https://ge.example.com')).toBe('key1') + }) + + it('matches on hostname, ignoring scheme, port and path', () => { + expect(resolveAccessKeyForServer('ge.example.com=key1', 'https://ge.example.com:8443/path')).toBe('key1') + }) + + it('tolerates a bare hostname with no scheme', () => { + expect(resolveAccessKeyForServer('ge.example.com=key1', 'ge.example.com')).toBe('key1') + }) + + it('selects the matching key when multiple are present', () => { + expect(resolveAccessKeyForServer('dev=key1;ge.example.com=key2', 'https://ge.example.com')).toBe('key2') + }) + + it('returns undefined when no key matches the server host', () => { + expect(resolveAccessKeyForServer('ge.example.com=key1', 'https://other.example.com')).toBeUndefined() + }) + + it('returns undefined for an empty server URL', () => { + expect(resolveAccessKeyForServer('ge.example.com=key1', '')).toBeUndefined() + }) + + it('returns undefined for an empty access key', () => { + expect(resolveAccessKeyForServer('', 'https://ge.example.com')).toBeUndefined() + }) + + it('returns undefined for a malformed access key', () => { + expect(resolveAccessKeyForServer('not-a-valid-access-key', 'https://ge.example.com')).toBeUndefined() + }) +})