@codefresh-io/cf-git-providers
Version:
An NPM module/CLI for interacting with various git providers
771 lines • 32.2 kB
JavaScript
;
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