forked from bugsink/bugsink
-
Notifications
You must be signed in to change notification settings - Fork 0
238 lines (215 loc) · 8.4 KB
/
ci.yml
File metadata and controls
238 lines (215 loc) · 8.4 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
name: Continuous Integration
# we use the fact that MySQL and Postgres are part of the ubuntu image, which saves us from
# "service container" complexities (but gives no choices in the version); this is also where
# the confured username/passwords for mysql come from
# approach inspired by https://blog.healthchecks.io/2020/11/using-github-actions-to-run-django-tests/
on:
push:
# hardcoded list; GitHub does not support wildcards in branch names AFAICT
branches: [ "main", "1.4.x", "1.5.x", "1.6.x", "1.7.x", "2.0.x", "2.1.x", "2.2.x", "2.3.x", "2.4.x", "2.5.x", "2.6.x", "2.7.x", "2.8.x"]
pull_request:
branches: [ "main" ]
workflow_dispatch: # Enables manual invocation via "Run workflow" button in the Actions UI
inputs:
target_branch:
description: 'Branch to run workflow on'
required: false
default: 'main'
env:
DJANGO_SETTINGS_MODULE: "bugsink.settings.development"
jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: "Set up Python 3.12"
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Ruff
run: |
python -m pip install --upgrade ruff
- name: Run Ruff
run: |
ruff check .
bandit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: 3.12
- name: Install Bandit and Plugins
run: |
pip install bandit spoils
- name: Run Bandit and format results
shell: bash
run: |
# set +e disables "exit on any non-zero command" behavior
# set +o pipefail disables GH's default "fail the whole pipeline if any stage fails"
set +e +o pipefail
# Note: .py files only; at the time of writing I checked the conf_templates/*.template
# also; but they had 2 False positives only (SECRET_KEY lives there by design) and I
# don't want to pollute templates that other people deal with with "nosec".
bandit_json_output=$( \
git ls-files \
| grep '\.py$' \
| xargs bandit -q -f json --ini .bandit \
)
bandit_exit_code=$?
echo "$bandit_json_output" \
| jq -r '
.results[]
| [ .filename
, .line_number
, .test_id
, .issue_confidence
, .issue_severity
, .test_name
]
| @tsv
' \
| column -t
if [[ $bandit_exit_code -ne 0 ]]; then
echo "Bandit found issues (exit code $bandit_exit_code)"
exit $bandit_exit_code
fi
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
db: [sqlite, mysql, postgres]
include:
- db: mysql
db_user: root
db_password: root
- db: postgres
db_user: bugsink
db_password: bugsink
env:
DB: ${{ matrix.db }}
DB_USER: ${{ matrix.db_user }}
DB_PASSWORD: ${{ matrix.db_password }}
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Start MySQL If Needed
if: matrix.db == 'mysql'
run: sudo systemctl start mysql.service
- name: Start PostgreSQL
if: matrix.db == 'postgres'
run: |
sudo systemctl start postgresql.service
sudo -u postgres psql -c "CREATE ROLE bugsink PASSWORD 'bugsink' NOSUPERUSER CREATEDB CREATEROLE INHERIT LOGIN;" postgres
- name: Install build
run: |
python -m pip install --upgrade pip
pip install build
- name: Build wheel
run: |
python -m build --wheel
- name: Install from wheel
run: |
python -m pip install dist/*.whl
- name: Install development dependencies
run: |
pip install -r requirements.development.txt
pip install mysqlclient psycopg2
- name: Check out event-samples
uses: actions/checkout@master
with:
repository: bugsink/event-samples
path: "event-samples"
- name: Create separate dir to avoid accidentally using non-packaged code
run: |
mkdir separate_dir
- name: Run Makemigrations --check
working-directory: separate_dir
run: |
bugsink-manage makemigrations --check
- name: Check bugsink-manage in settingless mode
working-directory: separate_dir
shell: bash
run: |
# Run the console entry in the most trivial way (--help), but with DJANGO_SETTINGS_MODULE truly unset
env -u DJANGO_SETTINGS_MODULE bugsink-manage --help >/dev/null
- name: Run Tests
working-directory: separate_dir
env:
SAMPLES_DIR: "${{ github.workspace }}/event-samples"
PYTHONWARNINGS: all
run: |
# because we're outside the project directory, the test discovery won't find our packages. We simply enumerate
# them using some shell-magic. Note that the only non-apps that we still care about are 'bugsink' (project, not
# app), and sentry_sdk_extensions, which we mention separately
bugsink-manage test `bugsink-manage shell -v0 -c 'from django.conf import settings; print(" ".join(settings.BUGSINK_APPS))'` bugsink sentry_sdk_extensions -v2
# bugsink-manage test ${GITHUB_WORKSPACE} -v2 # fails with the following, which I don't understand:
# ImportError: 'tests' module incorrectly imported from '/opt/hostedtoolcache/Python/3.10.15/x64/lib/python3.10/site-packages/alerts'. Expected '/home/runner/work/bugsink-private/bugsink-private/alerts'. Is this module globally installed?
docker:
runs-on: ubuntu-latest
# Build the Docker image, start it, wait for readiness, log in at /accounts/login/,
# and verify that / redirects to /teams/.
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t bugsink-ci .
- name: Run container (admin:admin)
run: |
docker rm -f bugsink-ci || true
docker run -d --name bugsink-ci \
-e SECRET_KEY=UtdHATKzQKLkz3izFFpxCKamhEdspeHmCQFvLx1DAwskqEuyKL \
-e CREATE_SUPERUSER=admin:admin \
-e PORT=8000 \
-p 8000:8000 \
bugsink-ci
- name: Wait for health
run: |
for i in {1..20}; do
if curl -sf http://localhost:8000/health/ready >/dev/null; then
echo "Service is ready"
exit 0
fi
sleep 1
done
echo "Service did not become healthy in time"
docker logs bugsink-ci
exit 1
- name: Login via /accounts/login/ and expect redirect from /
shell: bash
run: |
rm -f cookies.txt headers_root.txt
# 1) Get the login page and receive csrftoken
curl -sS -c cookies.txt http://localhost:8000/accounts/login/ >/dev/null
CSRF=$(awk '$6=="csrftoken"{print $7}' cookies.txt | tail -n1)
if [ -z "$CSRF" ]; then
echo "No csrftoken from /accounts/login/"
exit 1
fi
# 2) POST credentials (plain Django fields)
CODE=$(curl -sS -b cookies.txt -c cookies.txt \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Referer: http://localhost:8000/accounts/login/" \
-d "username=admin&password=admin&csrfmiddlewaretoken=${CSRF}&next=/" \
-o /dev/null -w "%{http_code}" \
http://localhost:8000/accounts/login/)
if [ "$CODE" != "302" ]; then
echo "Login failed (status: $CODE)"
exit 1
fi
# 3) HEAD / and check redirect to /teams/
curl -sS -b cookies.txt -I http://localhost:8000/ > headers_root.txt
if ! grep -qi '^Location: /teams/' headers_root.txt; then
echo "Expected redirect to /teams/ not found"
echo "--- / (status + Location):"
sed -n '1p;/^Location:/Ip' headers_root.txt
echo "--- cookies (names):"
awk '{print $6}' cookies.txt | sort -u || true
exit 1
fi
echo "Login OK and / redirects to /teams/"