UNPKG

@codefresh-io/cf-git-providers

Version:

An NPM module/CLI for interacting with various git providers

771 lines 32.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable max-lines */ const lodash_1 = require("lodash"); const https_1 = require("https"); const types_1 = require("./types"); const helpers_1 = require("../helpers"); const request_retry_1 = require("../helpers/request-retry"); const url_1 = require("url"); const gerrit_helpers_1 = require("./helpers/gerrit.helpers"); // eslint-disable-next-line @typescript-eslint/no-var-requires const wildcard = require('wildcard'); // eslint-disable-next-line @typescript-eslint/no-var-requires const CFError = require('cf-errors'); const logger = (0, helpers_1.createNewLogger)('codefresh:infra:git-providers:gerrit'); const GERRIT_CLOUD_HOST = 'https://gerrit.googlesource.com/'; const PROJECT_STATE = { active: 'ACTIVE', readOnly: 'READ_ONLY', hidden: 'HIDDEN', }; const PATH_PRIORITY = { specific: 1, wildcardDoubleStar: 1000, wildcardStar: 100, wildcardQuestion: 10, }; const LIMIT_PER_PAGE = 500; const ApiVersions = { // eslint-disable-next-line @typescript-eslint/naming-convention V1: 'a/', }; const RESPONSE_PREFIX = ')]}\'\n'; const defaultRepoPermission = { read: false, write: false, }; const pluginsJsonFormat = { format: 'JSON' }; const scopesMap = { read: 'repo_read', write: 'repo_write', create: 'repo_create', admin: 'admin_repo_hook', }; const ACCESS_ACTION = { allow: 'ALLOW', deny: 'DENY', block: 'BLOCK', unknown: 'UNKNOWN', }; class Gerrit { baseUrl; hostname; authenticationHeader; timeout; agent; auth; retryConfig; constructor(opts) { const url = new url_1.URL(opts.apiURL || opts.apiUrl || GERRIT_CLOUD_HOST); if (!opts.username) { throw new Error(`Gerrit provider is using Basic authorization, please provide username`); } this.baseUrl = `${url.protocol}//${url.host}`; this.hostname = url.hostname; if (!this.baseUrl.endsWith('/')) { this.baseUrl = `${this.baseUrl}/`; } this.timeout = opts.timeout || 10000; this.auth = { username: opts.username, password: opts.password, refreshToken: opts.refreshToken, }; // eslint-disable-next-line @typescript-eslint/naming-convention this.authenticationHeader = { Authorization: `Basic ${Buffer.from(`${this.auth.username}:${this.auth.password}`).toString('base64')}` }; if (this.baseUrl.startsWith('https') && (process.env.NODE_TLS_REJECT_UNAUTHORIZED === '0' || opts.insecure)) { logger.warn('using insecure mode'); this.agent = new https_1.Agent({ rejectUnauthorized: false }); } this.retryConfig = opts.retryConfig; } async performAPICall(opts) { const method = opts.method || 'GET'; const requestHeaders = { ...this.authenticationHeader, ...opts.headers, }; const jsonFormat = opts.plugin && opts.json ? pluginsJsonFormat : {}; const qs = { ...opts.qs, ...jsonFormat }; const requestOptions = { method, url: `${this.baseUrl}${ApiVersions.V1}${opts.api}`, qs, headers: requestHeaders, timeout: this.timeout, body: opts.data, resolveWithFullResponse: true, agent: this.agent, simple: false, retryConfig: this.retryConfig, json: true }; logger.debug(`${method} ${requestOptions.url} qs: ${JSON.stringify(requestOptions.qs)}`); return request_retry_1.RpRetry.rpRetry(requestOptions, logger) .then(async (res) => { res.body = this._parseBody(res.body); return Promise.resolve(res); }) .then((res) => { const curLogger = res.statusCode >= 400 ? logger.error.bind(logger) : logger.debug.bind(logger); curLogger(`${method} ${requestOptions.url} qs: ${JSON.stringify(requestOptions.qs)} status: ${res.statusCode}`); res.body = this._parseBody(res.body); return res; }); } async paginateForResult(opts) { const limit = opts.limit || LIMIT_PER_PAGE; // gerrit api is 0-based and our api is 1-based const start = (opts.page - 1) * limit; let resBatch = []; const jsonFormat = opts.json ? pluginsJsonFormat : {}; opts.qs = { ...opts.qs, start: start.toString(), limit: limit.toString(), ...jsonFormat }; const [err, res] = await (0, helpers_1.to)(this.performAPICall(opts)); this._handleError(`Failed with status code: ${res.statusCode}`, err, res); resBatch = opts.parseBatch(res.body, opts.parseBatchOpts); return resBatch; } getName() { return 'gerrit'; } async createRepository(opts) { const data = { create_empty_commit: true, ...(opts.owner && { owners: [opts.owner] }) }; const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `projects/${opts.repo}`, method: 'PUT', json: true, data })); this._handleError(`Failed to create repository ${opts.repo}`, err, res); return await this.toRepo(res.body); } async fetchRawFile(opts) { const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `projects/${opts.repo}/branches/${opts.ref}/files/${(0, helpers_1.cleanEncodedFilePath)(opts.path)}/content`, json: true, })); this._handleError(`Failed to retrieve file ${opts.path} on ${opts.repo}`, err, res); const base64Content = res.body.replace(/\n/gi, ''); return Buffer.from(base64Content, 'base64').toString(); } async getBranch(opts) { const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `projects/${opts.repo}/branches/${opts.branch}`, json: true, })); this._handleError(`Failed to get branch ${opts.branch} on ${opts.repo}`, err, res); return await this.toBranch(res.body, opts.repo); } async getRepository(opts) { const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `projects/${opts.repo}`, json: true, })); this._handleError(`Failed to get repository ${opts.repo}`, err, res); return await this.toRepo(res.body); } async listBranches(opts) { const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `projects/${opts.repo}/branches`, json: true, })); this._handleError(`Failed to list branch ${opts.repo}`, err, res); return await Promise.all((0, lodash_1.map)(res.body, async (branch) => await this.toBranch(branch, opts.repo))); } async createBranch() { throw new Error('Method createBranch not implemented.'); } async listRepositoriesForOwner() { throw new Error('Method listRepositoriesForOwner not implemented.'); } async createRepositoryWebhook() { throw new Error('Method createRepositoryWebhook not implemented.'); } async listWebhooks() { throw new Error('Method listWebhooks not implemented.'); } async deleteRepositoryWebhook() { throw new Error('Method deleteRepositoryWebhook not implemented.'); } async listRepositoriesWithAffiliation(opts) { const repos = await this.paginateForResult({ api: `projects/`, json: true, parseBatch: this._parseBatch, parseBatchOpts: { keyName: 'name' }, limit: opts.limit, page: opts.page || 1 }); const filteredRepos = (0, lodash_1.filter)(repos, (repo) => repo.name !== 'All-Projects' && repo.name !== 'All-Users'); return await Promise.all((0, lodash_1.map)(filteredRepos, async (repo) => await this.toRepo(repo))); } // orgs is groups, but there are no part of the repo async listOrganizations(opts) { const { limit = 25, page = 0 } = opts; const start = page * limit; const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `groups/`, qs: { // eslint-disable-next-line @typescript-eslint/naming-convention S: String(start), n: String(limit), // n - limit }, json: true, })); this._handleError(`Failed to list organization`, err, res); return res.body ? Object.keys(res.body) : []; } // acorrding to https://gerrit-review.googlesource.com/Documentation/access-control.html async getRepositoryPermissions(opts) { if (!opts.user) { throw new CFError({ message: `Failed to get ${opts.repo} permission: missing user`, cause: new Error('user is required on gerrit repository permission request') }); } const defaultBranch = await this.getDefaultBranch(opts.repo, true).catch(error => { logger.error(`Failed to check repository permission for user ${opts.user}: Failed to get default branch: ${error.message}`); return defaultRepoPermission; }); const userGroups = await this.getUserGroups(opts.user).catch(error => { logger.error(`Failed to check repository permission for user ${opts.user}: Failed to get user groups: ${error.message}`); return defaultRepoPermission; }); const permissions = await this.getBranchAccess({ repo: opts.repo, user: opts.user, ref: defaultBranch, groups: userGroups }); return permissions; } async getBranchAccess(opts) { const { repo, ref, user, groups, childRefs } = opts; const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `access/`, qs: { project: repo }, json: true, })); if (err || !res || res?.statusCode >= 400) { logger.error(`Failed to check repository permission for user ${user}`); return defaultRepoPermission; } const repositoryRefs = res?.body?.[repo]?.local; const parent = res?.body?.[repo]?.inherits_from; // no parent exist, calculating final permission res const matchingRefs = this._getMatchingRefsForBranch(repositoryRefs, ref); if (!parent) { return this._getFinalBranchPermission(matchingRefs, { user, groups, childRefs }); } const parentOpts = this._getRepoParentAccessInfo(matchingRefs, parent, opts); return await this.getBranchAccess(parentOpts); } async listRepositoriesForOrganization() { throw new Error('Method listRepositoriesForOrganization not implemented.'); } async createCommitStatus() { throw new Error('Method createCommitStatus not implemented.'); } async getUser(opts) { const [err, res] = await (0, helpers_1.to)(this.getPlainUser(opts)); this._handleError(`Failed to get user`, err, res); return await this.toUser(res.body); } async getUserByEmail(email) { return await this.getUser({ username: email }); } async getPullRequestFiles() { throw new Error('Method getPullRequestFiles not implemented.'); } async createPullRequest() { throw new Error('Method createPullRequest not implemented.'); } async getPullRequest() { throw new Error('Method getPullRequest not implemented.'); } async searchMergedPullRequestByCommitSha() { throw new Error('Method searchMergedPullRequestByCommitSha not implemented.'); } async assertApiScopes(opts) { const accountRes = await this.performAPICall({ api: `accounts/self/`, json: true, }).catch(error => { logger.error(`failed assert api scopes with: ${JSON.stringify(error)}`); }); const projectPermissionsRes = await this.performAPICall({ api: 'access/', qs: { project: 'All-Projects', }, json: true, }).catch(error => { logger.error(`failed assert api scopes with: ${JSON.stringify(error)}`); }); const validationErrorMsg = 'ValidationError: check your token permissions'; if (opts.scopes.includes(scopesMap.read) && projectPermissionsRes.statusCode == 401) { throw new CFError(`${validationErrorMsg} token or user is invalid`); } const userGroups = await this.getUserGroups(accountRes.body.name).catch(error => { logger.error(`Failed to get user groups: ${error.message}`); return []; }); // isOwner of this project means that he has all the permission by default const isOwner = projectPermissionsRes.body['All-Projects'].is_owner; if (isOwner) { return; } const hasWritePermissions = userGroups.some((userGroup) => { const rules = (0, lodash_1.get)(projectPermissionsRes, `body['All-Projects'].local['refs/heads/*'].permissions.push.rules`); return rules && rules.hasOwnProperty(userGroup) && rules[userGroup].action === 'ALLOW'; }); const hasCreatePermissions = userGroups.some((userGroup) => { const rules = (0, lodash_1.get)(projectPermissionsRes, `body['All-Projects'].local['GLOBAL_CAPABILITIES'].permissions.createProject.rules`); return rules && rules.hasOwnProperty(userGroup) && rules[userGroup].action === 'ALLOW'; }); if (opts.scopes.includes(scopesMap.create) && !hasCreatePermissions) { throw new CFError(`${validationErrorMsg}, missing createProject permission`); } if (opts.scopes.includes(scopesMap.write) && !hasWritePermissions) { throw new CFError(`${validationErrorMsg}, missing push permission`); } } async validateToken() { const res = await this.getPlainUser().catch(error => { logger.error(`failed validating basic token permissions with ${JSON.stringify(error)}`); }); if (!res) { return; } if (res.statusCode == 401) { throw new CFError(`user token is invalid, failed to get current user with status code: ${res.statusCode}`); } if (res.statusCode >= 400) { logger.error(`failed validating basic token permissions with status code: ${res.statusCode}`); } } skipPermissionsValidation() { return { skip: false }; } async toUser(user, email) { const avatar = await this.getAvatar(user.username).catch((error) => { logger.error(`failed to get avatar for user with ${JSON.stringify(error)}`); }); return { login: user.username, email: email || user.email || '', avatar_url: avatar, web_url: `${this.baseUrl}dashboard/${user.username}`, }; } async toBranch(rawBranch, repo) { const branchName = this._extractBranchName(rawBranch.ref); const lastCommit = await this.getCommit(repo, rawBranch.revision).catch(error => { logger.error(`Failed to get commit info for ${repo} with ${JSON.stringify(error)}`); }); const webUrl = rawBranch.web_links?.[0].url; const url = webUrl ? this.baseUrl + (0, helpers_1.cleanUrlPrefix)(webUrl) : ''; return { id: rawBranch.ref, name: branchName || rawBranch.ref, commit: { sha: rawBranch.revision, commiter_name: lastCommit ? lastCommit.committer?.name : '', message: lastCommit ? lastCommit.message : '', url, } }; } // currently we are not supporting ssh protocol on our platform - open for changes async toRepo(rawRepo) { let lastCommit; const gitliesProjectInfo = await this.getProjectGitliesInfo(rawRepo).catch((error => { logger.error(`Failed to get gitlies info for repoository ${rawRepo.name} with ${JSON.stringify(error)}`); })); const defaultBranch = await this.getDefaultBranch(rawRepo.id).catch((error => { logger.error(`Failed to get default branch for repository ${rawRepo.name} with ${JSON.stringify(error)}`); })); const webUrl = rawRepo.web_links?.[0].url; const commits = defaultBranch ? await this.getCommits(rawRepo.id, defaultBranch, webUrl).catch((error => { logger.error(`Failed to last commit for repository ${rawRepo.name} with ${JSON.stringify(error)}`); })) : undefined; if (commits && commits.length >= 0) lastCommit = commits[0]; const avatar = lastCommit ? await this.getAvatar(lastCommit.author?.name).catch((error => { logger.error(`Failed to get avatar for last committer on repository ${rawRepo.name} with ${JSON.stringify(error)}`); })) : ''; const url = webUrl ? this.baseUrl + (0, helpers_1.cleanUrlPrefix)(webUrl) : ''; return { id: rawRepo.id, provider: 'gerrit', name: rawRepo.name, full_name: rawRepo.name, private: rawRepo.state === PROJECT_STATE.hidden, pushed_at: lastCommit?.committer?.time ? new Date(lastCommit?.committer?.time) : new Date(0), open_issues: 0, clone_url: this.baseUrl + rawRepo.name + '.git', ssh_url: (0, gerrit_helpers_1.getSshCloneUrl)(rawRepo.name, this.auth.username, this.hostname, gitliesProjectInfo?.clone_url), owner: { login: lastCommit?.author?.name || '', avatar_url: avatar, creator: null, }, org: rawRepo.parent, default_branch: defaultBranch || '', permissions: { admin: true, // for now use 'true' to check it on gerrit will require another seperate request }, webUrl: url, }; } // avatar plugin is supported from 3.7 version or need to be configured async getAvatar(account) { const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `accounts/${account}/avatar`, json: true, })); if (err) { throw new CFError({ message: `failed to get avatar for account ${account}`, cause: err }); } // found if (res.statusCode === 302 && res.body) { return res.body.Location || ''; } return ''; } async getProjectGitliesInfo(rawRepo) { const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `plugins/gitiles/${rawRepo.id}`, json: true, plugin: true, })); if (err || res.statusCode >= 400) { throw new CFError({ message: `failed to get project ${rawRepo.name} gitlies info`, cause: err }); } if (rawRepo.state === PROJECT_STATE.hidden) { throw new CFError({ message: `project ${rawRepo.name} is hidden` }); } if (res.body.name != rawRepo.name) { throw new CFError({ message: `failed to get project ${rawRepo.name} gitlies info: not found` }); } return res.body; } async getDefaultBranch(repoId, returnFullRef = false) { const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `projects/${repoId}/HEAD`, json: true, })); if (err) { throw new CFError({ message: `Failed to get default branch for ${repoId}`, cause: err }); } return returnFullRef ? res.body : this._extractBranchName(res.body); } async getCommits(repoId, branch, pluginApiUrl) { const urlPrefix = pluginApiUrl ? (0, helpers_1.cleanUrlPrefix)(pluginApiUrl) : `plugins/gitiles/${repoId}`; const api = `${urlPrefix}/+log/${branch}`; const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api, json: true, plugin: true, })); if (err) { throw new CFError({ message: `Failed to get commits for repo ${repoId} for branch ${branch}`, casue: err }); } return res.body?.log || []; } async getCommit(repoId, sha) { const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `projects/${repoId}/commits/${sha}`, json: true, })); if (err) { throw new CFError({ message: `Failed to get commit ${sha} for repo ${repoId}`, cause: err }); } return res.body; } async getPlainUser(opts) { const user = opts?.username ? opts.username : 'self'; return this.performAPICall({ api: `accounts/${user}`, json: true, }); } async getUserGroups(user) { const [err, res] = await (0, helpers_1.to)(this.performAPICall({ api: `accounts/${user}/groups/`, json: true, })); if (err || !res || res?.statusCode >= 400 || !res.body || !(0, lodash_1.isArray)(res.body)) { throw new CFError({ message: `Failed to check repository permission for user ${user}: failed to get user groups`, cause: err }); } return res.body.map((group) => decodeURIComponent(group.id)); } toOwnerRepo(fullRepoName) { return ['', encodeURIComponent(fullRepoName)]; } getAuth() { return { headers: this.authenticationHeader, }; } isTokenMutable() { return true; } requiresRepoToCheckTokenScopes() { return false; } useAdminForUserPermission() { return true; } // Gerrit helpers _parseBatch(body, opts) { return (0, lodash_1.map)(body, (value, key) => { const { ...rest } = value; return { [opts.keyName]: key, ...rest }; }); } _getGroupHigestAction(old, current) { // in same section if has allow and block, allow will override the block if ([old, current].includes(ACCESS_ACTION.allow)) { return ACCESS_ACTION.allow; } if ([old, current].includes(ACCESS_ACTION.block)) { return ACCESS_ACTION.block; } return current; } _getMatchingRefsForBranch(repositoryRefs, branch) { return (0, lodash_1.pickBy)(repositoryRefs, (_, key) => { return wildcard(key, branch); }); } _getExclusiveResult(action, actionDefinedForUser, isExclusiveRule = false) { // action is unknown and not defined for the user / groups, and rule is exclusice if (action === ACCESS_ACTION.unknown && isExclusiveRule && !actionDefinedForUser) { return ACCESS_ACTION.block; } return action; } _getExclusivesScopes(permissions) { const exclusives = []; for (const rule in permissions) { if (permissions[rule].exclusice) { exclusives.push(rule); } } return exclusives; } _getRepoRefsPermission(refs, user, groups) { const refsScopesPermission = {}; for (const ref in refs) { const refPermissions = refs[ref].permissions; const refScopesPermission = {}; // exclusive scope permission override all other group/user permission that are not permitted exclusivly const exclusives = this._getExclusivesScopes(refPermissions); for (const scope in refPermissions) { const scopeDetails = refPermissions[scope]; const scopeRules = scopeDetails.rules; let scopeAction = ACCESS_ACTION.unknown; const groupsAndUser = [...groups, `user:${user}`]; let actionDefinedForUser = false; for (const group of groupsAndUser) { const groupScopeRule = scopeRules[group]; // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (!groupScopeRule) { // Current group doesnt have defined scopes rules continue; } actionDefinedForUser = true; scopeAction = this._getGroupHigestAction(scopeAction, groupScopeRule.action); } refScopesPermission[scope] = this._getExclusiveResult(scopeAction, actionDefinedForUser, exclusives.includes(scope)); } refsScopesPermission[ref] = refScopesPermission; } return refsScopesPermission; } _getRefsScopesPermission(refsScopesPermission) { const scopesPermission = {}; // refs oreder by less sepecific path to most sepecific path const paths = this._getSortedPathByPriority(refsScopesPermission); for (const path of paths) { for (const [scope, permission] of Object.entries(refsScopesPermission[path])) { // if permission is false or scopes doesnt exist already (from more specific path) // cause less specific path can block permission for more specific path // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (scopesPermission[scope] === ACCESS_ACTION.unknown || !(scopesPermission.hasOwnProperty(scope))) { scopesPermission[scope] = permission; } } } return scopesPermission; } _extractBranchName(branchRef) { return (0, lodash_1.last)((0, lodash_1.split)(branchRef, '/')); } _parseBody(body) { if ((0, lodash_1.isString)(body) && body.startsWith(RESPONSE_PREFIX)) { body = body.slice(RESPONSE_PREFIX.length); } return (0, helpers_1.isJsonString)(body) ? JSON.parse(body) : body; } _handleError(message, err, res) { if (err || !res || res?.statusCode >= 400) { throw new CFError({ message: message, cause: err ?? new types_1.HttpError(res?.statusCode, res?.body) }); } } _mergeRefs(childRef, parentRef) { const newRef = {}; for (const scope in childRef) { // if ref exists in the parent object, merge the two scopes else copy the child over newRef[scope] = scope in parentRef ? this._mergeScope(childRef[scope], parentRef[scope]) : childRef[scope]; } for (const scope in parentRef) { // scope doesn't exist in the child object, copy the parent scope over if (!(scope in childRef)) { newRef[scope] = parentRef[scope]; } } return newRef; } _getInheritRepoRefsPermission(parent, child) { if (!child || (0, lodash_1.isEmpty)(child)) { return parent; } const result = {}; for (const childKey in child) { // if ref exists in the parent object, merge the two Refs else copy the child over result[childKey] = childKey in parent ? this._mergeRefs(child[childKey], parent[childKey]) : child[childKey]; } for (const parentKey in parent) { // ref doesn't exist in the child object, copy the parent ref over if (!(parentKey in child)) { result[parentKey] = parent[parentKey]; } } return result; } _mergeScope(childScope, parentScope) { // between child / parent BLOCK is always override any permission if (childScope === ACCESS_ACTION.block || parentScope === ACCESS_ACTION.block) { return ACCESS_ACTION.block; } // when child is DENY the parent overrides if (childScope === ACCESS_ACTION.deny) { return parentScope; } return childScope; } _mapActionToBool(action) { if (action === ACCESS_ACTION.block || action === ACCESS_ACTION.deny) { return false; } return true; } _getWildCardPriority = (ref) => { let priority = 0; let numNonWildcard = 0; let numSingleWildcard = 0; let numDoubleWildcard = 0; ref.split('/').forEach((segment) => { if (segment === '**') { priority += PATH_PRIORITY.wildcardDoubleStar; numDoubleWildcard++; } else if (segment === '*') { priority += PATH_PRIORITY.wildcardStar; numSingleWildcard++; } else if (segment === '?') { priority += PATH_PRIORITY.wildcardQuestion; } else { numNonWildcard++; priority += PATH_PRIORITY.specific; } }); return [numNonWildcard, numSingleWildcard, numDoubleWildcard, priority]; }; _getSortedPathByPriority = (refsScopesPermission) => { return Object.keys(refsScopesPermission).sort((a, b) => { const [aNonWildcard, aSingleWildcard, aDoubleWildcard, aPriority] = this._getWildCardPriority(a); const [bNonWildcard, bSingleWildcard, bDoubleWildcard, bPriority] = this._getWildCardPriority(b); return bNonWildcard - aNonWildcard || aSingleWildcard - bSingleWildcard || aDoubleWildcard - bDoubleWildcard || bPriority - aPriority; }); }; _getFinalBranchPermission = (refs, opts) => { if ((!opts.childRefs || (0, lodash_1.isEmpty)(opts.childRefs)) && (0, lodash_1.isEmpty)(refs)) { return { read: true, write: true, }; } let permissions; // if current repo (parent) doesnt have refs but his child has - get final refs permission from child if ((0, lodash_1.isEmpty)(refs)) { permissions = opts.childRefs ? this._getRefsScopesPermission(opts.childRefs) : {}; } else { // both matching refs and childRefs exist // calculate repo refs permission for user const currentRefsPermissions = this._getRepoRefsPermission(refs, opts.user, opts.groups); // merge permission of current repo permission and child const permissionsRefs = this._getInheritRepoRefsPermission(currentRefsPermissions, opts.childRefs); // get final refs permission permissions = this._getRefsScopesPermission(permissionsRefs); } return { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition read: permissions.read ? this._mapActionToBool(permissions.read) : true, // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition write: permissions.push ? this._mapActionToBool(permissions.push) : true, }; }; _getRepoParentAccessInfo = (refs, parent, opts) => { const parentOpts = { ...opts }; if ((0, lodash_1.isEmpty)(refs)) { parentOpts.repo = parent.id; } else { const currentPermissions = this._getRepoRefsPermission(refs, opts.user, opts.groups); const permissionsRefs = this._getInheritRepoRefsPermission(currentPermissions, opts.childRefs); parentOpts.repo = parent.id; parentOpts.childRefs = permissionsRefs; } return parentOpts; }; } exports.default = Gerrit; //# sourceMappingURL=gerrit.js.map