blob: ec062fc17cc9f35151d1a94f74a425c5086434ce (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'digest'
require 'fileutils'
require 'open3'
if ENV['NO_COLOR']
SHELL_RED = ''
SHELL_GREEN = ''
SHELL_YELLOW = ''
SHELL_CLEAR = ''
else
SHELL_RED = "\e[1;31m"
SHELL_GREEN = "\e[1;32m"
SHELL_YELLOW = "\e[1;33m"
SHELL_CLEAR = "\e[0m"
end
LEFTHOOK_GLOBAL_CONFIG_PATH = File.expand_path("../lefthook.yml", __dir__)
HOOK_PATH = Open3.capture3("git rev-parse --path-format=absolute --git-path hooks/pre-push")[0].strip
HOOK_DATA = <<~HOOK
#!/usr/bin/env bash
set -e
url="$2"
if [[ "$url" != *"gitlab-org/security/"* ]]
then
echo "Pushing to remotes other than gitlab.com/gitlab-org/security has been disabled!"
echo "Run scripts/security-harness to disable this check."
echo
exit 1
fi
HOOK
def hook_exist?
File.exist?(HOOK_PATH)
end
def lefthook_hook_in_place?
hook_exist? && File.foreach(HOOK_PATH).grep(/lefthook/i).any?
end
def lefthook_available?
system('bundle exec lefthook run prepare-commit-msg &>/dev/null') # rubocop:disable GitlabSecurity/SystemCommandInjection
end
def uninstall_lefthook
return unless lefthook_available?
system('bundle exec lefthook uninstall') # rubocop:disable GitlabSecurity/SystemCommandInjection
# `bundle exec lefthook uninstall` removes the `lefthook.yml` file so we checkout it again
system("git checkout -- #{LEFTHOOK_GLOBAL_CONFIG_PATH}") # rubocop:disable GitlabSecurity/SystemCommandInjection
puts "#{SHELL_YELLOW}Lefthook was uninstalled to let the security harness work properly.#{SHELL_CLEAR}"
end
def install_lefthook
return unless lefthook_available?
system('bundle exec lefthook install') # rubocop:disable GitlabSecurity/SystemCommandInjection
puts "#{SHELL_GREEN}Lefthook was re-installed.#{SHELL_CLEAR}"
end
def write_hook
FileUtils.mkdir_p(File.dirname(HOOK_PATH))
File.open(HOOK_PATH, 'w') do |file|
file.write(HOOK_DATA)
end
File.chmod(0755, HOOK_PATH)
puts "#{SHELL_GREEN}Security harness installed -- you will only be able to push to gitlab.com/gitlab-org/security!#{SHELL_CLEAR}"
end
def delete_hook
FileUtils.rm(HOOK_PATH)
puts "#{SHELL_YELLOW}Security harness removed -- you can now push to all remotes.#{SHELL_CLEAR}"
end
def hook_file_sum
Digest::SHA256.file(HOOK_PATH).hexdigest
end
def hook_data_sum
Digest::SHA256.hexdigest(HOOK_DATA)
end
# If we were to change the script and then check for a pre-existing hook before
# writing, the check would fail even if the user had an unmodified version of
# the old hook. Checking previous version hashes allows us to safely overwrite a
# script that differs from the current version, as long as it's an old one and
# not custom.
def upgrade_available?
# SHA256 hashes of previous iterations of the script contained in `HOOK_DATA`
%w[
010bf0363a911ebab2bd5728d80795ed02388da51815f0b2530d08ae8ac574f0
d9866fc672f373d631eed9cd8dc9c920fa3d36ff26d956fb96a4082a0931b371
].include?(hook_file_sum)
end
def current_version?
hook_data_sum == hook_file_sum
end
# Uninstall Lefthook if it's in place
uninstall_lefthook if lefthook_hook_in_place?
if hook_exist?
# Deal with a pre-existing hook
if upgrade_available?
# Upgrading from a previous version, update in-place
write_hook
elsif current_version?
# Delete the hook if we're already using the current version
delete_hook
# Re-install Lefthook pre-push hook
install_lefthook
else
# Pre-existing hook we didn't create; do nothing
puts "#{SHELL_RED}#{HOOK_PATH} exists and is different from our hook!"
puts "Remove it and re-run this script to continue.#{SHELL_CLEAR}"
exit 1
end
else
write_hook
end
|