UNPKG

zephyr-agent

Version:
213 lines (212 loc) • 11.4 kB
"use strict"; var __webpack_require__ = {}; (()=>{ __webpack_require__.d = (exports1, getters, values)=>{ var define = (defs, kind)=>{ for(var key in defs)if (__webpack_require__.o(defs, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, { enumerable: true, [kind]: defs[key] }); }; define(getters, "get"); define(values, "value"); }; })(); (()=>{ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop); })(); (()=>{ __webpack_require__.r = (exports1)=>{ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, { value: 'Module' }); Object.defineProperty(exports1, '__esModule', { value: true }); }; })(); var __webpack_exports__ = {}; __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { cleanTokens: ()=>cleanTokens, getToken: ()=>getToken, removeToken: ()=>removeToken, saveToken: ()=>saveToken }); const external_node_crypto_namespaceObject = require("node:crypto"); const external_secret_token_js_namespaceObject = require("./secret-token.js"); const external_storage_js_namespaceObject = require("./storage.js"); const external_storage_keys_js_namespaceObject = require("./storage-keys.js"); const external_storage_lock_js_namespaceObject = require("./storage-lock.js"); const http_request_js_namespaceObject = require("../http/http-request.js"); const external_ci_token_js_namespaceObject = require("./ci-token.js"); const external_server_token_js_namespaceObject = require("./server-token.js"); const external_zephyr_edge_contract_namespaceObject = require("zephyr-edge-contract"); const external_user_email_js_namespaceObject = require("./user-email.js"); const debug_js_namespaceObject = require("../logging/debug.js"); const external_ci_token_identity_js_namespaceObject = require("./ci-token-identity.js"); const index_js_namespaceObject = require("../errors/index.js"); const auth_flags_js_namespaceObject = require("../auth/auth-flags.js"); const token_expiry_js_namespaceObject = require("../auth/token-expiry.js"); const CI_TOKEN_CACHE_VERSION = 1; const CI_TOKEN_SCOPE_CONTEXT = 'zephyr-ci-token-cache\0'; const activeCiTokenCacheKeys = new Set(); const TOKEN_LOCK = { whenUnavailable: 'proceed' }; async function saveToken(token) { await (0, external_storage_lock_js_namespaceObject.withStorageLock)('auth-token', ()=>(0, external_storage_js_namespaceObject.setPrivateItem)(external_storage_keys_js_namespaceObject.StorageKeys.ze_auth_token, token), TOKEN_LOCK); } async function getToken(git_config) { const tokenFromEnv = (0, external_secret_token_js_namespaceObject.getSecretToken)(); const server_token = (0, external_server_token_js_namespaceObject.getServerToken)(); const ci_token = (0, external_ci_token_js_namespaceObject.getCiToken)(); if (tokenFromEnv) return tokenFromEnv; if (ci_token) { const ciIdentity = await (0, external_ci_token_identity_js_namespaceObject.inferCiTokenIdentity)(); if (ciIdentity) { debug_js_namespaceObject.ze_log.auth(`Using ${ciIdentity.provider} ${ciIdentity.source} identity for CI token attribution`); return await getTokenFromCiToken(ci_token, ciIdentity); } throwCiTokenAuthError(void 0, `${external_storage_keys_js_namespaceObject.StorageKeys.ze_ci_token} was provided, but no supported CI identity was detected.`); } if (server_token && git_config) return await getTokenFromServerToken(server_token, git_config.git.email); const token = await (0, external_storage_lock_js_namespaceObject.withStorageLock)('auth-token', async ()=>{ await external_storage_js_namespaceObject.storage; return (0, external_storage_js_namespaceObject.getItem)(external_storage_keys_js_namespaceObject.StorageKeys.ze_auth_token); }, TOKEN_LOCK); if (token) return token; if (server_token) return void debug_js_namespaceObject.ze_log.error('No git config provided, skipping server token check'); } async function removeToken(expectedToken) { await (0, external_storage_lock_js_namespaceObject.withStorageLock)('auth-token', async ()=>{ await external_storage_js_namespaceObject.storage; const storedToken = await (0, external_storage_js_namespaceObject.getItem)(external_storage_keys_js_namespaceObject.StorageKeys.ze_auth_token); if (void 0 === expectedToken || storedToken === expectedToken) await (0, external_storage_js_namespaceObject.removeItem)(external_storage_keys_js_namespaceObject.StorageKeys.ze_auth_token); }, TOKEN_LOCK); } async function cleanTokens(rejectedToken) { await removeToken(rejectedToken); const cacheKeys = Array.from(activeCiTokenCacheKeys); await Promise.all(cacheKeys.map((cacheKey)=>(0, external_storage_lock_js_namespaceObject.withStorageLock)(getCiTokenLockName(cacheKey), async ()=>{ await external_storage_js_namespaceObject.storage; const cached = await (0, external_storage_js_namespaceObject.getItem)(cacheKey); if (void 0 === rejectedToken || isStoredCiAccessToken(cached) && cached.accessToken === rejectedToken) await (0, external_storage_js_namespaceObject.removeItem)(cacheKey); }, TOKEN_LOCK))); } async function getTokenFromServerToken(server_token, git_email) { const email = (0, external_user_email_js_namespaceObject.getUserEmail)() ?? git_email; const [ok, cause, data] = await (0, http_request_js_namespaceObject.makeRequest)({ path: external_zephyr_edge_contract_namespaceObject.ze_api_gateway.get_access_token_by_server_token, base: (0, external_zephyr_edge_contract_namespaceObject.ZE_API_ENDPOINT)(), query: { email } }, { headers: { Authorization: `Bearer ${server_token}` }, credentialToken: server_token }); if (!ok) { if (cause instanceof Error) debug_js_namespaceObject.ze_log.error('Failed to get token from server token:', cause.message); else debug_js_namespaceObject.ze_log.error('Failed to get token from server token:', cause); return; } await saveToken(data?.access_token ?? ''); return data?.access_token; } async function getTokenFromCiToken(ci_token, identity) { const scope = getCiTokenScope(ci_token, identity); const cacheKey = `${external_storage_keys_js_namespaceObject.StorageKeys.ze_ci_auth_token}:${scope}`; activeCiTokenCacheKeys.add(cacheKey); return (0, external_storage_lock_js_namespaceObject.withStorageLock)(getCiTokenLockName(cacheKey), async ()=>{ await external_storage_js_namespaceObject.storage; const cached = await (0, external_storage_js_namespaceObject.getItem)(cacheKey); if (isReusableCiAccessToken(cached, scope)) return cached.accessToken; const [ok, cause, data] = await (0, http_request_js_namespaceObject.makeRequest)({ path: external_zephyr_edge_contract_namespaceObject.ze_api_gateway.ci_token_exchange, base: (0, external_zephyr_edge_contract_namespaceObject.ZE_API_ENDPOINT)(), query: {} }, { method: 'POST', headers: { Authorization: `Bearer ${ci_token}`, 'Content-Type': 'application/json' }, credentialToken: ci_token, skipTokenCleanup: true }, JSON.stringify(identity)); if (!ok) { await (0, external_storage_js_namespaceObject.removeItem)(cacheKey); throwCiTokenAuthError(identity, cause); } const accessToken = data?.access_token; if (!accessToken || !(0, token_expiry_js_namespaceObject.isTokenStillValid)(accessToken, auth_flags_js_namespaceObject.TOKEN_EXPIRY.SHORT_VALIDITY_CHECK_SEC)) { await (0, external_storage_js_namespaceObject.removeItem)(cacheKey); throwCiTokenAuthError(identity, new Error('CI token exchange returned an invalid or expiring access token')); } const expiresAtMs = (0, token_expiry_js_namespaceObject.getTokenExpirationMs)(accessToken) ?? Date.now(); await (0, external_storage_js_namespaceObject.setPrivateItem)(cacheKey, { version: CI_TOKEN_CACHE_VERSION, scope, accessToken }, { ttl: expiresAtMs - Date.now() }); return accessToken; }, TOKEN_LOCK); } function getCiTokenScope(ciToken, identity) { const identityScope = [ (0, external_zephyr_edge_contract_namespaceObject.ZE_API_ENDPOINT)(), identity.provider, identity.source, identity.issuer ?? '', identity.providerSubject ?? '', identity.username ?? '', identity.providerActorType ?? '', identity.email ?? '', [ ...identity.emails ?? [] ].sort() ]; return (0, external_node_crypto_namespaceObject.createHash)('sha256').update(CI_TOKEN_SCOPE_CONTEXT).update(ciToken).update('\0').update(JSON.stringify(identityScope)).digest('hex'); } function getCiTokenLockName(cacheKey) { return `ci-auth-${cacheKey.substring(cacheKey.lastIndexOf(':') + 1)}`; } function isReusableCiAccessToken(value, scope) { return isStoredCiAccessToken(value) && value.scope === scope && (0, token_expiry_js_namespaceObject.isTokenStillValid)(value.accessToken, auth_flags_js_namespaceObject.TOKEN_EXPIRY.SHORT_VALIDITY_CHECK_SEC); } function isStoredCiAccessToken(value) { return Boolean(value && 'object' == typeof value && value.version === CI_TOKEN_CACHE_VERSION && 'string' == typeof value.scope && 'string' == typeof value.accessToken); } function throwCiTokenAuthError(identity, cause) { const details = cause instanceof Error ? cause.message : String(cause); debug_js_namespaceObject.ze_log.error('Failed to get token from CI token:', details); throw new index_js_namespaceObject.ZephyrError(index_js_namespaceObject.ZeErrors.ERR_CI_TOKEN_AUTH, { cause, provider: identity?.provider ?? 'unknown', username: identity?.username ?? 'unknown', source: identity?.source ?? 'unknown', issuer: identity?.issuer ?? 'unknown', actorType: identity?.providerActorType ?? 'unknown', resolution: identity?.providerActorType === 'bot' ? 'This bot is authorized by the CI token creator. Check that the token creator is still an active member of the Zephyr organization.' : "Link this CI actor's Git provider account in Zephyr Cloud, then rerun the workflow. Zephyr uses linked Git provider identities to map provider-native CI actor data, such as GitHub actor IDs or GitLab user IDs/emails, to a Zephyr user.", details }); } exports.cleanTokens = __webpack_exports__.cleanTokens; exports.getToken = __webpack_exports__.getToken; exports.removeToken = __webpack_exports__.removeToken; exports.saveToken = __webpack_exports__.saveToken; for(var __rspack_i in __webpack_exports__)if (-1 === [ "cleanTokens", "getToken", "removeToken", "saveToken" ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i]; Object.defineProperty(exports, '__esModule', { value: true }); //# sourceMappingURL=token.js.map