diff --git a/src/test/groovy/HasCommentAuthorWritePermissionsTests.groovy b/src/test/groovy/HasCommentAuthorWritePermissionsTests.groovy new file mode 100644 index 000000000..6ccbf530f --- /dev/null +++ b/src/test/groovy/HasCommentAuthorWritePermissionsTests.groovy @@ -0,0 +1,57 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import org.junit.Before +import org.junit.Test +import static org.junit.Assert.assertTrue + +class HasCommentAuthorWritePermissionsTests extends ApmBasePipelineTest { + + @Override + @Before + void setUp() throws Exception { + super.setUp() + script = loadScript('vars/hasCommentAuthorWritePermissions.groovy') + helper.registerAllowedMethod('githubRepoGetUserPermission', [Map.class], { m -> [ permission: "write" ] }) + helper.registerAllowedMethod('githubApiCall', [Map.class], { m -> [ user: [ login: "foo" ] ] }) + } + + @Test + void test() throws Exception { + def ret = script.call(repoName: "owner/repo", commentId: "1") + printCallStack() + assertTrue(ret) + assertTrue(assertMethodCallContainsPattern('githubApiCall', 'url=https://api.github.com/repos/owner/repo/issues/comments/1')) + assertTrue(assertMethodCallContainsPattern('githubRepoGetUserPermission', 'repo=owner/repo')) + assertTrue(assertMethodCallContainsPattern('githubRepoGetUserPermission', 'user=foo')) + assertJobStatusSuccess() + } + + @Test + void testNoRepo() throws Exception { + testError("hasCommentAuthorWritePermissions: repoName params is required"){ + script.call(commentId: "1") + } + } + + @Test + void testNoCommentID() throws Exception { + testError("hasCommentAuthorWritePermissions: commentId params is required"){ + script.call(repoName: "owner/repo") + } + } +} diff --git a/vars/README.md b/vars/README.md index fbcef0838..6594dd9e0 100644 --- a/vars/README.md +++ b/vars/README.md @@ -1310,6 +1310,19 @@ Wrapper to interact with the gsutil command line. It returns the stdout output. * command: The gsutil command to be executed. Mandatory * credentialsId: The credentials to access the repo (repo permissions). Mandatory. +## hasCommentAuthorWritePermissions + +Check if the author of a GitHub comment has admin or write permissions in the repository. + +``` +if(!hasCommentAuthorWritePermissions(repoName: "elastic/beats", commentId: env.GT_COMMENT_ID)){ + error("Only Elasticians can do this action.") +} +``` + +* *repoName:* organization and name of the repository (Organization/Repository) +* *commentId:* ID of the comment we want to check. + ## httpRequest Step to make HTTP request and get the result. If the return code is >= 400, it would throw an error. @@ -2966,4 +2979,3 @@ writeVaultSecret(secret: 'secret/apm-team/ci/temp/github-comment', data: ['secre * secret: Name of the secret on the the vault root path. Mandatory * data: What's the data to be written. Mandatory - diff --git a/vars/hasCommentAuthorWritePermissions.groovy b/vars/hasCommentAuthorWritePermissions.groovy new file mode 100644 index 000000000..889d44cd2 --- /dev/null +++ b/vars/hasCommentAuthorWritePermissions.groovy @@ -0,0 +1,29 @@ +// Licensed to Elasticsearch B.V. under one or more contributor +// license agreements. See the NOTICE file distributed with +// this work for additional information regarding copyright +// ownership. Elasticsearch B.V. licenses this file to you under +// the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +/** + Check if the author of a GitHub comment has admin or write permissions in the repository. +*/ +def call(Map args = [:]){ + def repoName = args.containsKey('repoName') ? args.repoName : error('hasCommentAuthorWritePermissions: repoName params is required') + def commentId = args.containsKey('commentId') ? args.commentId : error('hasCommentAuthorWritePermissions: commentId params is required') + def token = getGithubToken() + def url = "https://api.github.com/repos/${repoName}/issues/comments/${commentId}" + def comment = githubApiCall(token: token, url: url, noCache: true) + def json = githubRepoGetUserPermission(token: token, repo: repoName, user: comment?.user?.login) + return json?.permission == 'admin' || json?.permission == 'write' +} diff --git a/vars/hasCommentAuthorWritePermissions.txt b/vars/hasCommentAuthorWritePermissions.txt new file mode 100644 index 000000000..765c7d102 --- /dev/null +++ b/vars/hasCommentAuthorWritePermissions.txt @@ -0,0 +1,11 @@ + +Check if the author of a GitHub comment has admin or write permissions in the repository. + +``` +if(!hasCommentAuthorWritePermissions(repoName: "elastic/kibana", commentId: env.GT_COMMENT_ID)){ + error("Only Elasticians can deploy Docker images") +} +``` + +* *repoName:* organization and name of the repository (Organization/Repository) +* *commentId:* ID of the comment we want to check.