Skip to content
Closed
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions lib/resolve-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default (
CI_PROJECT_URL,
CI_PROJECT_PATH,
CI_API_V4_URL,
CI_API_GRAPHQL_URL,
GL_TOKEN,
GITLAB_TOKEN,
GL_URL,
Expand Down Expand Up @@ -59,6 +60,11 @@ export default (
: service === "gitlab" && CI_API_V4_URL
? CI_API_V4_URL
: urlJoin(defaultedGitlabUrl, isNil(userGitlabApiPathPrefix) ? "/api/v4" : userGitlabApiPathPrefix),
gitlabGraphQlApiUrl: userGitlabUrl
? urlJoin(userGitlabUrl, "/graphql")
: service === "gitlab" && CI_API_GRAPHQL_URL
? CI_API_GRAPHQL_URL
: urlJoin(defaultedGitlabUrl, "/graphql"),
assets: assets ? castArray(assets) : assets,
milestones: milestones ? castArray(milestones) : milestones,
successComment,
Expand Down
64 changes: 49 additions & 15 deletions lib/verify.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ export default async (pluginConfig, context) => {
options: { repositoryUrl },
logger,
} = context;
const { gitlabToken, gitlabUrl, gitlabApiUrl, proxy, ...options } = resolveConfig(pluginConfig, context);
const { gitlabToken, gitlabUrl, gitlabApiUrl, gitlabGraphQlApiUrl, proxy, ...options } = resolveConfig(
pluginConfig,
context
);
const { projectPath, projectApiUrl } = getProjectContext(context, gitlabUrl, gitlabApiUrl, repositoryUrl);

debug("apiUrl: %o", gitlabApiUrl);
Expand All @@ -54,28 +57,59 @@ export default async (pluginConfig, context) => {
}

if (gitlabToken && projectPath) {
let projectAccess;
let groupAccess;

logger.log("Verify GitLab authentication (%s)", gitlabApiUrl);

try {
({
permissions: { project_access: projectAccess, group_access: groupAccess },
} = await got
// First, get basic project information to ensure the project exists
await got
.get(projectApiUrl, {
headers: { "PRIVATE-TOKEN": gitlabToken },
...proxy,
})
.json());
if (
context.options.dryRun &&
!((projectAccess && projectAccess.access_level >= 10) || (groupAccess && groupAccess.access_level >= 10))
) {
.json();

// Use GraphQL to check user permissions
debug("Checking permissions via GraphQL");
const query = `
query {
project(fullPath: "${projectPath}") {
userPermissions {
pushToRepository
readRepository
}
}
}
`;

const graphqlResponse = await got
.post(gitlabGraphQlApiUrl, {
headers: {
"Private-Token": gitlabToken,
"Content-Type": "application/json",
Accept: "application/graphql-response+json",
},
json: { query },
...proxy,
})
.json();

if (graphqlResponse.errors) {
debug("GraphQL query returned errors: %O", graphqlResponse.errors);
throw new Error(`GraphQL query failed: ${graphqlResponse.errors.map((e) => e.message).join(", ")}`);
}

const permissions = graphqlResponse.data?.project?.userPermissions;
if (!permissions) {
debug("No permissions data returned from GraphQL query");
throw new Error("Unable to determine permissions from GraphQL response");
}

debug("GraphQL permissions: %O", permissions);

// Check permissions based on GraphQL response
if (context.options.dryRun && !permissions.readRepository) {
errors.push(getError("EGLNOPULLPERMISSION", { projectPath }));
} else if (
!((projectAccess && projectAccess.access_level >= 30) || (groupAccess && groupAccess.access_level >= 30))
) {
} else if (!permissions.pushToRepository) {
errors.push(getError("EGLNOPUSHPERMISSION", { projectPath }));
}
} catch (error) {
Expand Down
11 changes: 11 additions & 0 deletions test/resolve-config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const defaultOptions = {
gitlabToken: undefined,
gitlabUrl: "https://gitlab.com",
gitlabApiUrl: urlJoin("https://gitlab.com", "/api/v4"),
gitlabGraphQlApiUrl: urlJoin("https://gitlab.com", "/graphql"),
assets: undefined,
milestones: undefined,
successComment: undefined,
Expand Down Expand Up @@ -41,6 +42,7 @@ test("Returns user config", (t) => {
gitlabToken,
gitlabUrl,
gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix),
gitlabGraphQlApiUrl: urlJoin(gitlabUrl, "/graphql"),
assets,
labels: false,
retryLimit,
Expand All @@ -54,6 +56,7 @@ test("Returns user config", (t) => {
gitlabToken,
gitlabUrl,
gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix),
gitlabGraphQlApiUrl: urlJoin(gitlabUrl, "/graphql"),
assets,
proxy,
}
Expand All @@ -77,6 +80,7 @@ test("Returns user config via environment variables", (t) => {
gitlabToken,
gitlabUrl,
gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix),
gitlabGraphQlApiUrl: urlJoin(gitlabUrl, "/graphql"),
assets,
milestones,
}
Expand All @@ -96,6 +100,7 @@ test("Returns user config via alternative environment variables", (t) => {
gitlabToken,
gitlabUrl,
gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix),
gitlabGraphQlApiUrl: urlJoin(gitlabUrl, "/graphql"),
assets,
milestones: undefined,
successComment: undefined,
Expand Down Expand Up @@ -223,6 +228,7 @@ test("Returns user config via alternative environment variables with mismatching
gitlabToken: "TOKEN",
gitlabUrl: "http://host.com",
gitlabApiUrl: "http://host.com/api/prefix",
gitlabGraphQlApiUrl: "http://host.com/graphql",
assets: ["file.js"],
}
);
Expand All @@ -245,6 +251,7 @@ test("Returns user config via alternative environment variables with mismatching
gitlabToken: "TOKEN",
gitlabUrl: "https://host.com",
gitlabApiUrl: "https://host.com/api/prefix",
gitlabGraphQlApiUrl: "https://host.com/graphql",
assets: ["file.js"],
}
);
Expand Down Expand Up @@ -387,6 +394,7 @@ test("Returns default config via GitLab CI/CD environment variables", (t) => {
gitlabToken,
gitlabUrl: "http://ci-host.com",
gitlabApiUrl: CI_API_V4_URL,
gitlabGraphQlApiUrl: "http://ci-host.com/graphql",
}
);
});
Expand Down Expand Up @@ -415,6 +423,7 @@ test("Returns user config over GitLab CI/CD environment variables", (t) => {
gitlabToken,
gitlabUrl,
gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix),
gitlabGraphQlApiUrl: urlJoin(gitlabUrl, "/graphql"),
assets,
failTitle: "The automated release unfortunately failed!",
labels: "bot,release-failed",
Expand Down Expand Up @@ -450,6 +459,7 @@ test("Returns user config via environment variables over GitLab CI/CD environmen
gitlabToken,
gitlabUrl,
gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix),
gitlabGraphQlApiUrl: urlJoin(gitlabUrl, "/graphql"),
}
);
});
Expand Down Expand Up @@ -482,6 +492,7 @@ test("Returns user config via alternative environment variables over GitLab CI/C
gitlabToken,
gitlabUrl,
gitlabApiUrl: urlJoin(gitlabUrl, gitlabApiPathPrefix),
gitlabGraphQlApiUrl: urlJoin(gitlabUrl, "/graphql"),
}
);
});
Expand Down
Loading