forked from freedomofpress/securedrop-client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Makefile
231 lines (192 loc) Β· 8.6 KB
/
Makefile
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
.PHONY: all
all: help
# Default to plain "python3"
PYTHON ?= python3
.PHONY: venv
venv: hooks ## Provision a Python 3 virtualenv for development on Linux
$(PYTHON) -m venv .venv
.venv/bin/pip install --upgrade pip wheel
.venv/bin/pip install --require-hashes -r "requirements/dev-requirements.txt"
@echo "#################"
@echo "Make sure to run: source .venv/bin/activate"
.PHONY: venv-sdw
venv-sdw: hooks ## Provision a Python 3 virtualenv for development on a prod-like system that has installed dependencies specified in https://github.com/freedomofpress/securedrop-debian-packaging/blob/main/securedrop-client/debian/control
$(PYTHON) -m venv .venv --system-site-packages
.venv/bin/pip install --upgrade pip wheel
.venv/bin/pip install --require-hashes -r "requirements/dev-sdw-requirements.txt"
@echo "#################"
@echo "Virtualenv with Debian system-packages is complete."
@echo "Make sure to install the apt packages for system Qt."
@echo "Then run: source .venv/bin/activate"
.PHONY: venv-buster
venv-buster: hooks ## Provision a Python 3 virtualenv for development on Linux
$(PYTHON) -m venv .venv
.venv/bin/pip install --upgrade pip wheel
.venv/bin/pip install --require-hashes -r "requirements/dev-buster-requirements.txt"
@echo "#################"
@echo "Make sure to run: source .venv/bin/activate"
.PHONY: venv-mac
venv-mac: hooks ## Provision a Python 3 virtualenv for development on macOS
$(PYTHON) -m venv .venv
.venv/bin/pip install --upgrade pip wheel
.venv/bin/pip install -r "requirements/dev-mac-requirements.in"
@echo "#################"
@echo "Make sure to run: source .venv/bin/activate"
HOOKS_DIR=.githooks
.PHONY: hooks
hooks: ## Configure Git to use the hooks provided by this repository.
git config core.hooksPath "$(HOOKS_DIR)"
SEMGREP_FLAGS := --exclude "tests/" --error --strict --verbose
.PHONY: semgrep
semgrep:semgrep-community semgrep-local
.PHONY: semgrep-community
semgrep-community:
@echo "Running semgrep with semgrep.dev community rules..."
@semgrep $(SEMGREP_FLAGS) --config "p/r2c-security-audit"
.PHONY: semgrep-local
semgrep-local:
@echo "Running semgrep with local rules..."
@semgrep $(SEMGREP_FLAGS) --config ".semgrep"
.PHONY: black
black: ## Format Python source code with black
@black ./
.PHONY: check-black
check-black: ## Check Python source code formatting with black
@black --check --diff ./
.PHONY: isort
isort: ## Run isort to organize Python imports
@isort --skip-glob .venv ./
.PHONY: check-isort
check-isort: ## Check Python import organization with isort
@isort --skip-glob .venv --check-only --diff ./
.PHONY: mypy
mypy: ## Run static type checker
@mypy --ignore-missing-imports \
--disallow-incomplete-defs \
--disallow-untyped-defs \
--show-error-codes \
--warn-unreachable \
--warn-unused-ignores \
securedrop_client \
*.py
.PHONY: clean
clean: ## Clean the workspace of generated resources
@rm -rf .mypy_cache build dist *.egg-info .coverage .eggs docs/_build .pytest_cache lib htmlcov .cache && \
find . \( -name '*.py[co]' -o -name dropin.cache \) -delete && \
find . \( -name '*.bak' -o -name dropin.cache \) -delete && \
find . \( -name '*.tgz' -o -name dropin.cache \) -delete && \
find . -name __pycache__ -print0 | xargs -0 rm -rf
TESTS ?= tests
ITESTS ?= tests/integration
FTESTS ?= tests/functional
TESTOPTS ?= -v --cov-config .coveragerc --cov-report html --cov-report term-missing --cov=securedrop_client --cov-fail-under 100
.PHONY: test
test: ## Run the application tests in parallel (for rapid development)
@TEST_CMD="python -m pytest -v -n 4 --ignore=$(FTESTS) --ignore=$(ITESTS) $(TESTOPTS) $(TESTS)" ; \
if command -v xvfb-run > /dev/null; then \
xvfb-run -a $$TEST_CMD ; else \
$$TEST_CMD ; fi
.PHONY: test-random
test-random: ## Run the application tests in random order
@TEST_CMD="python -m pytest -v --junitxml=test-results/junit.xml --random-order-bucket=global --ignore=$(FTESTS) --ignore=$(ITESTS) $(TESTOPTS) $(TESTS)" ; \
if command -v xvfb-run > /dev/null; then \
xvfb-run -a $$TEST_CMD ; else \
$$TEST_CMD ; fi
.PHONY: test-integration
test-integration: ## Run the integration tests
@TEST_CMD="python -m pytest -v -n 4 $(ITESTS)" ; \
if command -v xvfb-run > /dev/null; then \
xvfb-run -a $$TEST_CMD ; else \
$$TEST_CMD ; fi
.PHONY: test-functional
test-functional: ## Run the functional tests
@./test-functional.sh
.PHONY: lint
lint: ## Run the linters
@flake8 securedrop_client tests
.PHONY: safety
safety: ## Runs `safety check` to check python dependencies for vulnerabilities
pip install --upgrade safety && \
for req_file in `find . -type f -wholename '*requirements.txt'`; do \
echo "Checking file $$req_file" \
&& safety check --full-report -r $$req_file \
&& echo -e '\n' \
|| exit 1; \
done
# Bandit is a static code analysis tool to detect security vulnerabilities in Python applications
# https://wiki.openstack.org/wiki/Security/Projects/Bandit
.PHONY: bandit
bandit: ## Run bandit with medium level excluding test-related folders
pip install --upgrade pip && \
pip install --upgrade bandit && \
bandit -ll --recursive . --exclude ./tests,./.venv
.PHONY: check
check: clean check-black check-isort semgrep bandit lint mypy test-random test-integration test-functional ## Run the full CI test suite
.PHONY: dev-requirements
dev-requirements: ## Update dev-*requirements.txt files if pinned versions do not comply with the dependency specifications in dev-*requirements.in
pip-compile --allow-unsafe --generate-hashes --output-file requirements/dev-requirements.txt requirements/dev-requirements.in
pip-compile --allow-unsafe --generate-hashes --output-file requirements/dev-sdw-requirements.txt requirements/dev-sdw-requirements.in
.PHONY: update-dev-dependencies
update-dev-dependencies: ## Update dev requirements in case there are newer versions of packages or updates to prod dependencies
if test -f "requirements/dev-requirements.txt"; then rm -r requirements/dev-requirements.txt; fi
if test -f "requirements/dev-sdw-requirements.txt"; then rm -r requirements/dev-sdw-requirements.txt; fi
$(MAKE) dev-requirements
.PHONY: requirements
requirements: ## Update *requirements.txt files if pinned versions do not comply with the dependency specifications in *requirements.in
pip-compile --generate-hashes --output-file requirements/requirements.txt requirements/requirements.in
$(MAKE) dev-requirements
# Explaination of the below shell command should it ever break.
# 1. Set the field separator to ": ##" and any make targets that might appear between : and ##
# 2. Use sed-like syntax to remove the make targets
# 3. Format the split fields into $$1) the target name (in blue) and $$2) the target descrption
# 4. Pass this file as an arg to awk
# 5. Sort it alphabetically
# 6. Format columns with colon as delimiter.
.PHONY: help
help: ## Print this message and exit.
@printf "Makefile for developing and testing the SecureDrop client.\n"
@printf "Subcommands:\n\n"
@awk 'BEGIN {FS = ":.*?## "} /^[0-9a-zA-Z_-]+:.*?## / {printf "\033[36m%s\033[0m : %s\n", $$1, $$2}' $(MAKEFILE_LIST) \
| sort \
| column -s ':' -t
.PHONY: version
version:
@python -c "import securedrop_client; print(securedrop_client.__version__)"
.PHONY: docs
docs: ## Generate browsable documentation and call/caller graphs (requires Doxygen and Graphviz)
@which doxygen >> /dev/null || { echo "doxygen(1) is not available in your \$$PATH. Is it installed?"; exit 1; }
@which dot >> /dev/null || { echo "Graphviz's dot(1) is not available in your \$$PATH. Is it installed?"; exit 1; }
@doxygen
@echo "Now open \"$(PWD)/docs/html/index.html\" in your browser."
##############
#
# Localization
#
##############
LOCALE_DIR=securedrop_client/locale
POT=${LOCALE_DIR}/messages.pot
VERSION=$(shell python -c "import securedrop_client; print(securedrop_client.__version__)")
.PHONY: check-strings
check-strings: ## Check that the translation catalog is up to date with source code
@make extract-strings
@git diff --quiet ${LOCALE_DIR} || { echo "Translation catalog is out of date. Please run \"make extract-strings\" and commit the changes."; exit 1; }
.PHONY: extract-strings
extract-strings: ## Extract translatable strings from source code
@make --always-make ${POT}
# Derive POT from sources.
$(POT): securedrop_client
@echo "updating catalog template: $@"
@mkdir -p ${LOCALE_DIR}
@pybabel extract \
--charset=utf-8 \
--output=${POT} \
--project="SecureDrop Client" \
--version=${VERSION} \
--copyright-holder="Freedom of the Press Foundation" \
--add-comments="Translators:" \
--strip-comments \
--add-location=never \
--no-wrap \
$^
@sed -i -e '/^"POT-Creation-Date/d' ${POT}