-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit-crypt.mk
More file actions
309 lines (291 loc) · 11 KB
/
Copy pathgit-crypt.mk
File metadata and controls
309 lines (291 loc) · 11 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
GIT_CRYPT_BIN = git-crypt
GIT_CRYPT_BIN_FULL = $(BINARIES_PATH)/$(GIT_CRYPT_BIN)
_GIT_ATTRIBUTES_PATH = $(CURDIR)/.gitattributes
# GIT_CRYPT_UNLOCKED_INCLUDES - add next sh function:
# is_repo_unlocked - check that git repo already unlocked with git-crypt
# if unlocked - return 0; else return 1
# is_repo_locked - check that git repo locked with git-crypt
# if locked - return 0; else return 1
define GIT_CRYPT_UNLOCKED_INCLUDES
function is_repo_unlocked() { \
if [ -s "$(CURDIR)/.git/git-crypt/keys/default" ] && [ "$$(git config --local --list | grep 'filter.git-crypt' | wc -l)" = "3" ]; then \
return 0; \
fi; \
return 1; \
}; \
function is_repo_locked() { \
if ! is_repo_unlocked; then \
return 0; \
fi; \
return 1; \
};
endef
define _GIT_CRYPT_OP_INCLUDES
${INCLUDE_FS_CONSUME} \
function dirty_state_error() { \
echo_err "ATTENTION!"; \
echo_err "YOU REPO IN DIRTY STATE!"; \
echo_err "DO NOT COMMIT CHANGES OTHERWISE YOU LOST FILES!"; \
echo_err "MANUAL REMOVING IS:"; \
echo "git rm --cached ..."; \
echo "git add ..."; \
echo "git commit ..."; \
exit_with_err "Crypt operation '$$1' FAILED!"; \
}; \
function re_add_files() { \
local fl="$$1"; \
local is_glob_call="$${2:-}"; \
local rm_r_flag=""; \
local msg_suf=""; \
if [[ "$$is_glob_call" != "true" ]]; then \
if [ ! -e "$$fl" ]; then \
return 0; \
fi; \
rm_r_flag="-r"; \
msg_suf=" or dir"; \
fi; \
echo_info "Re-add file$${msg_suf} '$$fl' to git"; \
if ! git rm $${rm_r_flag} --cached "$$fl"; then \
echo_err "Cannot run: git rm $${rm_r_flag} --cached '$$fl'"; \
return 1; \
fi; \
if ! git add "$$fl"; then \
echo_err "Cannot run: git add '$$fl'"; \
return 1; \
fi; \
echo -n "true"; \
return 0; \
}; \
function commit_changes() { \
local attributes_file="$$1"; \
local op_name="$$2"; \
local to_commit="$$3"; \
local skip_re_add="$${4:-}"; \
if [[ "$$skip_re_add" != "true" ]]; then \
local has_files=""; \
if is_glob "$$to_commit"; then \
local to_commit_glob="./**/$$to_commit"; \
if ! has_files="$$(foreach_dir_by_glob "" "$$to_commit_glob" "re_add_files" "true")"; then \
dirty_state_error "$$op_name"; \
fi; \
else \
if ! has_files="$$(re_add_files "$$to_commit")"; then \
dirty_state_error "$$op_name"; \
fi; \
fi; \
if [ -z "$$has_files" ]; then \
echo_info "Cannot found files or dirs to re-add. Skip"; \
fi; \
fi; \
if ! git add "$$attributes_file"; then \
echo_err "Cannot 'git add $$attributes_file'"; \
dirty_state_error "$$op_name"; \
fi; \
if ! git commit -m "git-crypt: $$op_name '$$to_commit'"; then \
exit_with_err "Cannot commit $$op_name"; \
fi; \
}; \
function check_path_for_op() { \
local var_name="$$1"; \
local pt_for_check="$$2"; \
if [ -z "$$pt_for_check" ]; then \
exit_with_err "Path not specify with '$$var_name' param (env)"; \
fi; \
if [[ "$$pt_for_check" == /* ]]; then \
exit_with_err "Path '$$pt_for_check' should not be absolute"; \
fi; \
}; \
function prepare_attributes() { \
local attributes_file="$(_GIT_ATTRIBUTES_PATH)"; \
if [ ! -f "$$attributes_file" ]; then \
touch "$$attributes_file"; \
fi; \
echo -n "$$attributes_file"; \
};
endef
##@ git-crypt. Common
_git-crypt/no-changes:
@$(MAKE) common/git/check/no-changes
install/git-crypt: export INSTALL_BIN_NAME = $(GIT_CRYPT_BIN)
install/git-crypt: export INSTALL_BIN_VERSION = $(GIT_CRYPT_VERSION)
install/git-crypt: export INSTALL_BIN_VERSION_ARG = version
install/git-crypt: export INSTALL_BIN_URL = https://github.com/makefile-inc/git-crypt/releases/download/git-crypt-bin-@BIN_VER@/git-crypt-@BIN_OS@-@BIN_ARCH@
install/git-crypt: ## Install git-crypt from https://github.com/makefile-inc/git-crypt repo
@$(MAKE) install/binary
git-crypt/repo/lock: install/git-crypt _git-crypt/no-changes ## Lock local repository
@${INCLUDE_ECHO} \
if ! $(GIT_CRYPT_BIN_FULL) lock; then \
exit_with_err "Cannot lock repo"; \
fi
clean/git-crypt: ## Remove git-crypt bin
@rm -fv "$(GIT_CRYPT_BIN_FULL)"
##@ git-crypt. Symmetric key
git-crypt/repo/symmetric/init: install/git-crypt _git-crypt/no-changes ## Init local repository with symmetric key and export key. Git repo should be clean
@##~ KEY_PATH=PATH - path to save key. Should be outside the repo (current dir)
@${INCLUDE_ECHO} \
${GIT_CRYPT_UNLOCKED_INCLUDES} \
if [ -z "$$KEY_PATH" ]; then \
exit_with_err "Output key file not specify with 'KEY_PATH' param (env)"; \
fi; \
if [ -e "$$KEY_PATH" ]; then \
exit_with_err "Output key file '$$KEY_PATH' exist"; \
fi; \
cur_dir="$(CURDIR)"; \
if ! cur_dir="$$(realpath "$$cur_dir")"; then \
exit_with_err "Cannot get realpath for $(CURDIR)"; \
fi; \
if ! KEY_PATH="$$(realpath "$$KEY_PATH")"; then \
exit_with_err "Cannot get realpath for KEY_PATH"; \
fi; \
if [[ "$$KEY_PATH" == "$${cur_dir}/"* ]]; then \
exit_with_err "Key destination in repo path. Please choice another destination"; \
fi; \
if is_repo_unlocked; then \
exit_with_err "Repo already unlocked!"; \
fi; \
attributes_file="$(_GIT_ATTRIBUTES_PATH)"; \
if [ -f "$$attributes_file" ]; then \
if grep "filter=git-crypt" "$$attributes_file"; then \
exit_with_err ".gitattributes files contains git-crypt filters. Probably you can init repository not unlocked repo"; \
fi; \
fi; \
if ! $(GIT_CRYPT_BIN_FULL) init; then \
exit_with_err "Cannot init repo"; \
fi; \
if ! $(GIT_CRYPT_BIN_FULL) export-key "$$KEY_PATH"; then \
exit_with_err "Cannot export key to '$$KEY_PATH'"; \
fi; \
if [ ! -s "$$KEY_PATH" ]; then \
exit_with_err "Key file '$$KEY_PATH' is empty"; \
fi; \
echo_info "git-crypt init. Next, lock repo and unlock for verify and init local git config with relative path"; \
if ! $(GIT_CRYPT_BIN_FULL) lock; then \
exit_with_err "Cannot lock repo"; \
fi; \
if ! $(MAKE) git-crypt/repo/symmetric/unlock KEY_PATH="$$KEY_PATH"; then \
exit_with_err "Cannot unlock repo"; \
fi; \
echo_info "git-crypt init fully!"; \
echo_info "For add file use git-crypt/add/file"; \
echo_info "For add dir use git-crypt/add/dir"; \
echo_info "Symmetric key save to $$KEY_PATH"; \
echo_info "Please save key in the security location and use for unlock repo later"
git-crypt/repo/symmetric/unlock: install/git-crypt _git-crypt/no-changes ## Unlock local repository with symmetric key
@##~ KEY_PATH=PATH - path to key file to unlock
@${INCLUDE_ECHO} \
${GIT_CRYPT_UNLOCKED_INCLUDES} \
if is_repo_unlocked; then \
echo_info "Already unlocked!"; \
exit 0; \
fi; \
key="$$KEY_PATH"; \
if [ -z "$$key" ]; then \
exit_with_err "Key file not specify with 'KEY_PATH' param (env)"; \
fi; \
if [ ! -f "$$key" ]; then \
exit_with_err "Key file '$$key' is not file or not found"; \
fi; \
full_bin_path="$(GIT_CRYPT_BIN_FULL)"; \
if ! full_bin_path="$$(realpath "$$full_bin_path")"; then \
exit_with_err "Cannot get realpath for $(GIT_CRYPT_BIN_FULL)"; \
fi; \
cur_dir="$(CURDIR)"; \
if ! cur_dir="$$(realpath "$$cur_dir")"; then \
exit_with_err "Cannot get realpath for $(CURDIR)"; \
fi; \
cur_dir="$${cur_dir}/"; \
relative_crypt_bin="$${full_bin_path#$$cur_dir}"; \
if [ -z "$$relative_crypt_bin" ]; then \
exit_with_err "Relative git-crypt bin path is empty"; \
fi; \
relative_crypt_bin="./$${relative_crypt_bin}"; \
if ! $(GIT_CRYPT_BIN_FULL) unlock "$$key"; then \
exit_with_err "Cannot unlock repo with '$$key'"; \
fi; \
smudge_str="\"$$relative_crypt_bin\" smudge"; \
if ! git config --local filter.git-crypt.smudge "$$smudge_str"; then \
exit_with_err "Failed to set to git config smudge filter"; \
fi; \
clean_str="\"$$relative_crypt_bin\" clean"; \
if ! git config --local filter.git-crypt.clean "$$clean_str"; then \
exit_with_err "Failed to set to git config clean filter"; \
fi; \
if ! git config --local filter.git-crypt.required true; then \
exit_with_err "Failed to set to git config required git crypt filter"; \
fi; \
diff_str="\"$$relative_crypt_bin\" diff"; \
if ! git config --local diff.git-crypt.textconv "$$diff_str"; then \
exit_with_err "Failed to set to git config git crypt diff"; \
fi
git-crypt/repo/symmetric/check/locked: ## Check repo is locked with symmetric key
@${INCLUDE_ECHO} \
${GIT_CRYPT_UNLOCKED_INCLUDES} \
if ! is_repo_locked; then \
exit_with_err "Repo is unlocked!"; \
fi
git-crypt/repo/symmetric/check/unlocked: ## Check repo is unlocked with symmetric key
@${INCLUDE_ECHO} \
${GIT_CRYPT_UNLOCKED_INCLUDES} \
if ! is_repo_unlocked; then \
exit_with_err "Repo is locked!"; \
fi
##@ git-crypt. Add or remove to/from git-crypt
git-crypt/add/file: install/git-crypt _git-crypt/no-changes ## Add file to crypt and commit to git. Git repo should be clean
@##~ FILE=PATH - path to add to crypt. Should not be absolute
@##~ SKIP_RE_ADD=true - if passed, skip re-add files to git
@${_GIT_CRYPT_OP_INCLUDES} \
check_path_for_op "FILE" "$$FILE"; \
attributes_file="$$(prepare_attributes)"; \
trimmed="$${FILE#/}"; \
if grep "^$$trimmed" "$$attributes_file"; then \
echo_info "'$$FILE' already added!"; \
exit 0; \
fi; \
echo "$$trimmed filter=git-crypt diff=git-crypt" >> "$$attributes_file"; \
re_add=""; \
if [ -n "$$SKIP_RE_ADD" ]; then \
re_add="true"; \
fi; \
commit_changes "$$attributes_file" "add file(s)" "$$trimmed" "$$re_add"
git-crypt/add/dir: install/git-crypt _git-crypt/no-changes ## Add dir to crypt and commit to git. Git repo should be clean
@##~ DIR=PATH - dir path to add to crypt. Should not be absolute
@##~ SKIP_RE_ADD=true - if passed, skip re-add files to git
@${_GIT_CRYPT_OP_INCLUDES} \
check_path_for_op "DIR" "$$DIR"; \
attributes_file="$$(prepare_attributes)"; \
dir_path="$${DIR%*}"; \
dir_path="$${dir_path#*}"; \
dir_path="$${dir_path%/}"; \
if grep "^$${dir_path}/**" "$$attributes_file"; then \
echo_info "$$dir_path already added!"; \
exit 0; \
fi; \
echo "$${dir_path}/** filter=git-crypt diff=git-crypt" >> "$$attributes_file"; \
re_add=""; \
if [ -n "$$SKIP_RE_ADD" ]; then \
re_add="true"; \
fi; \
commit_changes "$$attributes_file" "add dir" "$$dir_path" "$$re_add"
git-crypt/remove: install/git-crypt _git-crypt/no-changes ## Remove path from crypt and commit to git. Git repo should be clean
@##~ TO_REMOVE=PATH - path to remove from crypt. Should not be absolute
@##~ SKIP_RE_ADD=true - if passed, skip re-add files to git
@${_GIT_CRYPT_OP_INCLUDES} \
check_path_for_op "TO_REMOVE" "$$TO_REMOVE"; \
attributes_file="$$(prepare_attributes)"; \
trimmed="$${TO_REMOVE%*}"; \
trimmed="$${trimmed%*}"; \
if ! grep "^$$trimmed" "$$attributes_file"; then \
echo_info "$$TO_REMOVE already removed"; \
exit 0; \
fi; \
escaped="$$(printf '%s\n' "$$trimmed" | sed -e 's/[\/&]/\\&/g')"; \
if ! sed -i "/$$escaped\/\?\*\?\*\? /d" "$$attributes_file"; then \
exit_with_err "Cannot remove attribute with sed"; \
fi; \
remove_without_slash="$${trimmed%/}"; \
re_add=""; \
if [ -n "$$SKIP_RE_ADD" ]; then \
re_add="true"; \
fi; \
commit_changes "$$attributes_file" "remove path" "$$remove_without_slash" "$$re_add"
.PHONY: help _git-crypt/no-changes install/git-crypt git-crypt/repo/symmetric/init git-crypt/repo/symmetric/unlock git-crypt/repo/lock git-crypt/add/file git-crypt/add/dir git-crypt/remove clean/git-crypt git-crypt/repo/symmetric/check/locked git-crypt/repo/symmetric/check/unlocked