Skip to content
Snippets Groups Projects
Commit 4848f7d4 authored by Martin Lowe's avatar Martin Lowe :flag_ca:
Browse files

update: switch ECA GL check to check all commits instead of just project

This change sets the ECA to process all commits, dropping the allowances
for forks and non-project repositories that existed previously. This
also adds Wiki commit checking support, as well as adds tentative Group
Wiki support.
parent 590afd87
No related branches found
No related tags found
1 merge request!213update: switch ECA GL check to check all commits instead of just project
Pipeline #59628 failed
......@@ -58,6 +58,12 @@ To enable the Git hook that makes use of this service, a running GitLab instance
1. In the GitLab shell once again, ensure that the newly copied script matches the folders ownership, and that the file permissions are `755`. This allows the server to properly run the hook when needed.
#### Updating allow-listed project groups
In the script, there is a variable near the top of the file named `ALLOW_LIST_GROUPS` that contains a list of GitLab namespaces. These namespaces are used in matching incoming requests, and if the start of the namespace of a request matches one of the values in the list, the ECA validation will not run on that change. To add other groups as 'allow-listed', all one has to do as add another element to the array of the group that should be matched with a trailing slash.
e.g. `ALLOW_LIST_GROUPS = ['eclipsefdn/it/webdev/eclipse.org-php-archives/', 'eclipse-wg/']`
### Configure environment
Export the following environment variables. Note that you might need to alter the values based on your environment.
......
......@@ -4,7 +4,6 @@
require 'json'
require 'httparty'
require 'multi_json'
WIKI_REGEX_MATCH = /.*\.wiki$/
HOST_URL='https://gitlab.eclipse.org'
API_URL='https://api.eclipse.org'
LARGE_COMMIT_SET_THRESHOLD=15
......@@ -58,6 +57,43 @@ def nil_or_empty(o)
return o.nil? || o.empty?
end
def get_project_url(id, access_token)
## Get data about project from API
project_response = HTTParty.get("#{HOST_URL}/api/v4/projects/#{id}",
:headers => {
'Authorization' => 'Bearer ' + access_token
})
## Format data to be able to easily read and process it
project_json_data = MultiJson.load(project_response.body)
if (nil_or_empty(project_json_data) || project_json_data.class.name == 'Array') then
puts "Couldn't load project data, there may be errors with Gitlab at this time. Please try again later."
exit 1
end
## Get the web URL, checking if project is a fork to get original project URL
if (!nil_or_empty(project_json_data['forked_from_project'])) then
puts "Fork detected, using forked from project's URL for better commit validation."
return project_json_data['forked_from_project']['web_url']
end
return project_json_data['web_url']
end
def get_group_url(id, access_token)
## Get data about group from API
group_response = HTTParty.get("#{HOST_URL}/api/v4/groups/#{id}",
:headers => {
'Authorization' => 'Bearer ' + access_token
})
## Format data to be able to easily read and process it
group_json_data = MultiJson.load(group_response.body)
if (nil_or_empty(group_json_data) || group_json_data.class.name == 'Array') then
puts "Couldn't load group data, there may be errors with Gitlab at this time. Please try again later."
exit 1
end
## Get the web URL for the group, which will be used for project matching if possible
return group_json_data['web_url']
end
## read in the access token from secret file
if (!File.file?("/etc/gitlab/eca-access-token"))
puts "GL-HOOK-ERR: Internal server error, please contact administrator. Error, secret not found"
......@@ -81,43 +117,25 @@ new_head_commit = stdin_args[1]
gl_repo = ENV['GL_REPOSITORY']
if (nil_or_empty(gl_repo)) then
## This will always be called by Gitaly when triggered which sets this var, should never happen
puts "No Gitlab repository set, likely dealing with non-repo commit, skipping"
exit 0
elsif (gl_repo =~ /^wiki-/ || gl_repo =~ /^group-\d+-wiki$/) then
puts "Commit is associated with a wiki, and does not need to be validated. Skipping."
exit 0
elsif (gl_repo !~ /^project-/) then
puts "GL_REPOSITORY envvar is improperly set does not match expected format (#{gl_repo}), cannot validate"
exit 1
end
## Get the project ID from env var, extracting from pattern 'project-###'
project_id = gl_repo[8..-1]
## Get data about project from API
project_response = HTTParty.get("#{HOST_URL}/api/v4/projects/#{project_id}",
:headers => {
'Authorization' => 'Bearer ' + access_token
})
## Format data to be able to easily read and process it
project_json_data = MultiJson.load(project_response.body)
if (nil_or_empty(project_json_data) || project_json_data.class.name == 'Array') then
puts "Couldn't load project data, assumed non-tracked project and skipping validation."
exit 0
end
## Get the web URL, checking if project is a fork to get original project URL
if (!nil_or_empty(project_json_data['forked_from_project'])) then
puts "Fork detected, using forked from project's URL for better commit validation."
project_url = project_json_data['forked_from_project']['web_url']
is_forked_project = true
else
project_url = project_json_data['web_url']
elsif (gl_repo =~ /^wiki-/ ) then
## get project ID from wiki project string
asset_url = get_project_url(gl_repo[5..-1], access_token)
elsif (gl_repo =~ /^group-\d+-wiki$/) then
## Retrieve the group ID from the middle of the expected pattern
asset_url = get_group_url(gl_repo[6..-6], access_token)
else
## Get the project ID from env var, extracting from pattern 'project-###'
asset_url = get_project_url(gl_repo[8..-1], access_token)
end
## This can happen for group wikis by inference from some production-only issues
if (nil_or_empty(project_url)) then
if (nil_or_empty(asset_url)) then
puts "Could not determine a web URL for project, likely not a fully-qualified project, skipping"
exit 0
elsif (ALLOW_LIST_PROJECTS.any? {|repo_namespace| "#{HOST_URL}#{repo_namespace}" == project_url}) then
elsif (ALLOW_LIST_PROJECTS.any? {|repo_namespace| "#{HOST_URL}#{repo_namespace}" == asset_url}) then
puts "Found allow listed project, skipping validation"
exit 0
elsif (ALLOW_LIST_GROUPS.any? {|group_namespace| project_json_data['path_with_namespace'].start_with?(group_namespace)}) then
......@@ -151,7 +169,7 @@ end
is_strict_enforced = use_strict_mode(project_json_data['path_with_namespace'])
## Create the JSON payload
json_data = {
:repoUrl => project_url,
:repoUrl => asset_url,
:provider => 'gitlab',
:commits => processed_git_data,
:strictMode => is_strict_enforced
......@@ -226,17 +244,8 @@ else
else
puts "More information is available at https://api.eclipse.org/git/eca/status/#{parsed_response['fingerprint']}/ui"
end
## after parsing
if (!parsed_response.nil? && parsed_response['trackedProject'] == false && !is_strict_enforced) then
if (contained_warnings_errors) then
puts "Errors or warnings were encountered while validating sign-off in current request for non-project repository.\n\nValidation is currently not required for non-project repositories, continuing."
end
exit 0
end
end
## If error, exit as status 1
if (response.code == 403 && is_forked_project && !is_strict_enforced) then
puts "Errors detected, but commits will be allowed for forked repository. Commit errors reported in this push will block merge into origin repository until resolved."
elsif (response.code == 403) then
if (response.code == 403) then
exit 1
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment