zephyr-agent
Version:
Zephyr plugin agent
113 lines (112 loc) • 4.08 kB
JavaScript
import "node:module";
import { claimMatchesEnv, decodeJwtPayload, getEmail, getEmailClaims, getEmails, getStringClaim, stringifyId } from "./utils.mjs";
const GITLAB_JOB_FETCH_TIMEOUT_MS = 10000;
const gitLabCiIdentityProvider = {
provider: 'gitlab',
detect: isGitLabCi,
infer: inferGitLabIdentity
};
function isGitLabCi(env) {
return 'true' === env['GITLAB_CI'] || 'GitLab' === env['CI_SERVER_NAME'];
}
async function inferGitLabIdentity(env) {
const payload = decodeJwtPayload(env['CI_JOB_TOKEN']);
const jwtEmails = getEmailClaims(payload, [
'user_email',
'email'
]);
if (payload && jwtEmails.length > 0 && gitLabClaimsMatchEnvironment(payload, env)) return {
provider: 'gitlab',
email: jwtEmails[0],
emails: jwtEmails,
issuer: getGitLabIssuer(env),
providerSubject: getStringClaim(payload, [
'user_id',
'user_login',
'sub'
]),
username: getStringClaim(payload, [
'user_login',
'username'
]),
source: 'jwt'
};
const apiIdentity = await inferGitLabIdentityFromApi(env);
if (apiIdentity) return apiIdentity;
const envEmail = getEmail(env['GITLAB_USER_EMAIL']);
if (envEmail) return {
provider: 'gitlab',
email: envEmail,
emails: [
envEmail
],
issuer: getGitLabIssuer(env),
providerSubject: env['GITLAB_USER_ID']?.trim(),
username: env['GITLAB_USER_LOGIN']?.trim() || void 0,
source: 'env'
};
}
async function inferGitLabIdentityFromApi(env) {
const apiUrl = getGitLabApiUrl(env);
const jobToken = env['CI_JOB_TOKEN']?.trim();
if (!apiUrl || !jobToken) return;
try {
const job = await fetchGitLabJob(apiUrl, jobToken);
if (!gitLabJobMatchesEnvironment(job, env)) return;
const emails = getEmails([
job.user?.email,
job.user?.public_email,
job.commit?.author_email
]);
if (0 === emails.length) return;
return {
provider: 'gitlab',
email: emails[0],
emails,
issuer: getGitLabIssuer(env),
providerSubject: stringifyId(job.user?.id) ?? env['GITLAB_USER_ID']?.trim(),
username: job.user?.username?.trim() || void 0,
source: 'api'
};
} catch {
return;
}
}
function getGitLabIssuer(env) {
const serverUrl = env['CI_SERVER_URL']?.trim();
if (serverUrl) return serverUrl.replace(/\/+$/, '').toLowerCase();
const apiUrl = env['CI_API_V4_URL']?.trim();
return apiUrl ? apiUrl.replace(/\/api\/v4\/?$/, '').replace(/\/+$/, '').toLowerCase() : void 0;
}
function getGitLabApiUrl(env) {
const apiUrl = env['CI_API_V4_URL']?.trim();
if (apiUrl) return apiUrl;
const serverUrl = env['CI_SERVER_URL']?.trim();
return serverUrl ? `${serverUrl.replace(/\/$/, '')}/api/v4` : void 0;
}
async function fetchGitLabJob(apiUrl, jobToken) {
const url = new URL('job', apiUrl.endsWith('/') ? apiUrl : `${apiUrl}/`);
const response = await fetch(url.toString(), {
headers: {
'JOB-TOKEN': jobToken
},
signal: AbortSignal.timeout(GITLAB_JOB_FETCH_TIMEOUT_MS)
});
if (!response.ok) return {};
return await response.json();
}
function gitLabClaimsMatchEnvironment(payload, env) {
if (!payload) return false;
return claimMatchesEnv(payload, 'job_id', env['CI_JOB_ID']) && claimMatchesEnv(payload, 'project_id', env['CI_PROJECT_ID']) && claimMatchesEnv(payload, 'pipeline_id', env['CI_PIPELINE_ID']);
}
function gitLabJobMatchesEnvironment(job, env) {
return claimMatchesEnv({
job_id: job.id
}, 'job_id', env['CI_JOB_ID']) && claimMatchesEnv({
project_id: job.pipeline?.project_id
}, 'project_id', env['CI_PROJECT_ID']) && claimMatchesEnv({
pipeline_id: job.pipeline?.id
}, 'pipeline_id', env['CI_PIPELINE_ID']);
}
export { gitLabCiIdentityProvider };
//# sourceMappingURL=gitlab.mjs.map