fastly-sync 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. fastly_sync-0.1.0/.github/FUNDING.yml +4 -0
  2. fastly_sync-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +77 -0
  3. fastly_sync-0.1.0/.github/ISSUE_TEMPLATE/config.yml +11 -0
  4. fastly_sync-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +37 -0
  5. fastly_sync-0.1.0/.github/dependabot.yml +68 -0
  6. fastly_sync-0.1.0/.github/pull_request_template.md +37 -0
  7. fastly_sync-0.1.0/.github/workflows/ci.yml +308 -0
  8. fastly_sync-0.1.0/.github/workflows/dependabot-rewrite.yml +94 -0
  9. fastly_sync-0.1.0/.gitignore +25 -0
  10. fastly_sync-0.1.0/.multicz/state.json +13 -0
  11. fastly_sync-0.1.0/.pre-commit-config.yaml +90 -0
  12. fastly_sync-0.1.0/.python-version +1 -0
  13. fastly_sync-0.1.0/CHANGELOG.md +31 -0
  14. fastly_sync-0.1.0/CODE_OF_CONDUCT.md +83 -0
  15. fastly_sync-0.1.0/CONTRIBUTING.md +62 -0
  16. fastly_sync-0.1.0/LICENSE +21 -0
  17. fastly_sync-0.1.0/PKG-INFO +240 -0
  18. fastly_sync-0.1.0/README.md +213 -0
  19. fastly_sync-0.1.0/SECURITY.md +47 -0
  20. fastly_sync-0.1.0/docs/index.md +47 -0
  21. fastly_sync-0.1.0/docs/stability.md +33 -0
  22. fastly_sync-0.1.0/multicz.toml +61 -0
  23. fastly_sync-0.1.0/osv-scanner.toml +14 -0
  24. fastly_sync-0.1.0/pyproject.toml +88 -0
  25. fastly_sync-0.1.0/scripts/add_license_header.py +138 -0
  26. fastly_sync-0.1.0/scripts/rewrite-dependabot-commit.sh +67 -0
  27. fastly_sync-0.1.0/src/fastly_sync/__init__.py +6 -0
  28. fastly_sync-0.1.0/src/fastly_sync/blocklist.py +65 -0
  29. fastly_sync-0.1.0/src/fastly_sync/cli.py +457 -0
  30. fastly_sync-0.1.0/src/fastly_sync/config.py +66 -0
  31. fastly_sync-0.1.0/src/fastly_sync/errors.py +30 -0
  32. fastly_sync-0.1.0/src/fastly_sync/fastly.py +303 -0
  33. fastly_sync-0.1.0/src/fastly_sync/loader.py +57 -0
  34. fastly_sync-0.1.0/src/fastly_sync/models.py +86 -0
  35. fastly_sync-0.1.0/src/fastly_sync/show.py +63 -0
  36. fastly_sync-0.1.0/src/fastly_sync/spec.py +172 -0
  37. fastly_sync-0.1.0/src/fastly_sync/sync.py +167 -0
  38. fastly_sync-0.1.0/src/fastly_sync/waf.py +114 -0
  39. fastly_sync-0.1.0/tests/__init__.py +2 -0
  40. fastly_sync-0.1.0/tests/test_blocklist.py +75 -0
  41. fastly_sync-0.1.0/tests/test_cli.py +464 -0
  42. fastly_sync-0.1.0/tests/test_config.py +41 -0
  43. fastly_sync-0.1.0/tests/test_fastly.py +242 -0
  44. fastly_sync-0.1.0/tests/test_show.py +81 -0
  45. fastly_sync-0.1.0/tests/test_spec.py +207 -0
  46. fastly_sync-0.1.0/tests/test_sync.py +222 -0
  47. fastly_sync-0.1.0/tests/test_waf.py +112 -0
  48. fastly_sync-0.1.0/uv.lock +992 -0
  49. fastly_sync-0.1.0/zensical.toml +19 -0
@@ -0,0 +1,4 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Chris <goabonga@pm.me>
3
+
4
+ github: [goabonga]
@@ -0,0 +1,77 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Chris <goabonga@pm.me>
3
+
4
+ name: Bug Report
5
+ description: Report a bug or unexpected behavior
6
+ labels: ["bug"]
7
+ body:
8
+ - type: markdown
9
+ attributes:
10
+ value: |
11
+ Thanks for reporting a bug! Please fill in the details below.
12
+
13
+ - type: input
14
+ id: version
15
+ attributes:
16
+ label: fastly-sync version
17
+ description: "Output of `pip show fastly-sync` or `fastly-sync --version`."
18
+ validations:
19
+ required: true
20
+
21
+ - type: textarea
22
+ id: description
23
+ attributes:
24
+ label: Description
25
+ description: A clear description of the bug.
26
+ validations:
27
+ required: true
28
+
29
+ - type: textarea
30
+ id: steps
31
+ attributes:
32
+ label: Steps to Reproduce
33
+ description: How can we reproduce this issue? Include the exact command line.
34
+ validations:
35
+ required: true
36
+
37
+ - type: textarea
38
+ id: expected
39
+ attributes:
40
+ label: Expected Behavior
41
+ validations:
42
+ required: true
43
+
44
+ - type: textarea
45
+ id: actual
46
+ attributes:
47
+ label: Actual Behavior
48
+ validations:
49
+ required: true
50
+
51
+ - type: dropdown
52
+ id: python-version
53
+ attributes:
54
+ label: Python Version
55
+ options:
56
+ - "3.11"
57
+ - "3.12"
58
+ - "3.13"
59
+ validations:
60
+ required: true
61
+
62
+ - type: dropdown
63
+ id: os
64
+ attributes:
65
+ label: Operating System
66
+ options:
67
+ - Linux
68
+ - macOS
69
+ - Windows
70
+ validations:
71
+ required: true
72
+
73
+ - type: textarea
74
+ id: logs
75
+ attributes:
76
+ label: Logs / Traceback
77
+ render: shell
@@ -0,0 +1,11 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Chris <goabonga@pm.me>
3
+
4
+ blank_issues_enabled: false
5
+ contact_links:
6
+ - name: Code of Conduct
7
+ url: https://github.com/goabonga/fastly-sync/blob/main/CODE_OF_CONDUCT.md
8
+ about: Please read our Code of Conduct before contributing
9
+ - name: Security advisories
10
+ url: https://github.com/goabonga/fastly-sync/security/advisories/new
11
+ about: Report a vulnerability privately (do not open a public issue)
@@ -0,0 +1,37 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Chris <goabonga@pm.me>
3
+
4
+ name: Feature Request
5
+ description: Suggest a new feature or enhancement
6
+ labels: ["enhancement"]
7
+ body:
8
+ - type: markdown
9
+ attributes:
10
+ value: |
11
+ Thanks for suggesting a feature! Please describe your idea below.
12
+
13
+ - type: textarea
14
+ id: problem
15
+ attributes:
16
+ label: Problem
17
+ description: What problem does this feature solve? Is it related to a frustration?
18
+ validations:
19
+ required: true
20
+
21
+ - type: textarea
22
+ id: solution
23
+ attributes:
24
+ label: Proposed Solution
25
+ description: Describe the solution you'd like.
26
+ validations:
27
+ required: true
28
+
29
+ - type: textarea
30
+ id: alternatives
31
+ attributes:
32
+ label: Alternatives Considered
33
+
34
+ - type: textarea
35
+ id: context
36
+ attributes:
37
+ label: Additional Context
@@ -0,0 +1,68 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Chris <goabonga@pm.me>
3
+
4
+ # Dependabot v2 configuration.
5
+
6
+ version: 2
7
+
8
+ updates:
9
+ # Python dependencies via uv.
10
+ - package-ecosystem: "uv"
11
+ directory: "/"
12
+ schedule:
13
+ interval: "weekly"
14
+ day: "monday"
15
+ time: "06:00"
16
+ timezone: "Europe/Paris"
17
+ open-pull-requests-limit: 5
18
+ ignore:
19
+ # `hatchling` lives in [build-system].requires; Dependabot's uv
20
+ # FileUpdater cannot write that table. Bump it by hand; pip-audit and
21
+ # osv-scanner still flag any CVEs.
22
+ - dependency-name: "hatchling"
23
+ groups:
24
+ # Bundle routine dev tooling bumps into a single weekly PR. The
25
+ # signed-rewrite script keys "dev-tools group" -> chore(deps).
26
+ dev-tools:
27
+ applies-to: version-updates
28
+ patterns:
29
+ - "ruff"
30
+ - "mypy"
31
+ - "pytest*"
32
+ - "pre-commit"
33
+ # Runtime deps ship in the package -> fixes; the signed rewrite confirms
34
+ # this from [dependency-groups].dev membership. Dev tooling stays chore.
35
+ commit-message:
36
+ prefix: "fix(deps)"
37
+ prefix-development: "chore(deps)"
38
+ labels:
39
+ - "dependencies"
40
+ - "python"
41
+
42
+ # Pinned versions of GitHub Actions in `.github/workflows/*.yml`.
43
+ - package-ecosystem: "github-actions"
44
+ directory: "/"
45
+ schedule:
46
+ interval: "weekly"
47
+ day: "monday"
48
+ time: "06:00"
49
+ timezone: "Europe/Paris"
50
+ open-pull-requests-limit: 5
51
+ groups:
52
+ ci-actions:
53
+ applies-to: version-updates
54
+ patterns:
55
+ - "actions/*"
56
+ - "astral-sh/*"
57
+ - "google/*"
58
+ - "pypa/*"
59
+ - "codecov/*"
60
+ - "compilerla/*"
61
+ - "pre-commit/*"
62
+ - "docker/*"
63
+ - "softprops/*"
64
+ commit-message:
65
+ prefix: "ci"
66
+ labels:
67
+ - "dependencies"
68
+ - "github-actions"
@@ -0,0 +1,37 @@
1
+ ## Description
2
+
3
+ <!-- Describe what this PR does and why. -->
4
+
5
+ ## Type
6
+
7
+ <!-- Check the one that applies: -->
8
+
9
+ - [ ] `feat` - New feature
10
+ - [ ] `fix` - Bug fix
11
+ - [ ] `docs` - Documentation
12
+ - [ ] `refactor` - Code refactoring
13
+ - [ ] `test` - Adding or updating tests
14
+ - [ ] `chore` - Maintenance
15
+ - [ ] `ci` - CI / release pipeline
16
+
17
+ ## Changes
18
+
19
+ <!-- List the main changes introduced by this PR: -->
20
+
21
+ -
22
+
23
+ ## Related Issues
24
+
25
+ <!-- Link related issues: Closes #123, Fixes #456 -->
26
+
27
+ ## Checklist
28
+
29
+ - [ ] Commits follow [Conventional Commits](https://www.conventionalcommits.org/)
30
+ - [ ] Branch is up to date with `main`
31
+ - [ ] `uv sync` succeeds
32
+ - [ ] `uv run ruff check src tests` and `uv run ruff format --check src tests` are clean
33
+ - [ ] `uv run mypy src` is clean (if the project uses mypy)
34
+ - [ ] `uv run pytest` passes (if the project has tests)
35
+ - [ ] `uv tool run multicz validate --strict` passes
36
+ - [ ] SPDX license headers are present (`python scripts/add_license_header.py --path . --types py,toml --check`)
37
+ - [ ] No `Co-Authored-By` trailer in commit messages
@@ -0,0 +1,308 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Chris <goabonga@pm.me>
3
+
4
+ # Full CI for a PyPI-distributed project. Drop the `type-check` job if the
5
+ # code is not typed, and the `test` job (+ codecov) if there is no suite.
6
+ # Rename to ci.yml in the repo.
7
+
8
+ name: ci
9
+
10
+ on:
11
+ pull_request:
12
+ branches: [main]
13
+ push:
14
+ branches: [main]
15
+
16
+ concurrency:
17
+ group: ${{ github.workflow }}-${{ github.ref }}
18
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
19
+
20
+ permissions:
21
+ contents: read
22
+
23
+ jobs:
24
+ lint:
25
+ name: lint
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v6
29
+ - uses: astral-sh/setup-uv@v7
30
+ with:
31
+ enable-cache: true
32
+ cache-suffix: ${{ github.job }}
33
+ python-version: "3.12"
34
+ - run: uv sync --frozen --only-group dev
35
+ - run: uv run --no-sync ruff check --output-format=github src tests
36
+ - run: uv run --no-sync ruff format --check src tests
37
+
38
+ # Optional: remove if the project does not use mypy.
39
+ type-check:
40
+ name: type-check
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - uses: actions/checkout@v6
44
+ - uses: astral-sh/setup-uv@v7
45
+ with:
46
+ enable-cache: true
47
+ cache-suffix: ${{ github.job }}
48
+ python-version: "3.12"
49
+ - run: uv sync --frozen
50
+ - run: uv run --no-sync mypy src
51
+
52
+ license-headers:
53
+ name: license-headers
54
+ runs-on: ubuntu-latest
55
+ steps:
56
+ - uses: actions/checkout@v6
57
+ - uses: astral-sh/setup-uv@v7
58
+ with:
59
+ enable-cache: true
60
+ cache-suffix: ${{ github.job }}
61
+ python-version: "3.12"
62
+ - name: Check SPDX headers
63
+ run: |
64
+ uv run --no-project python scripts/add_license_header.py --path src --types py --check
65
+ uv run --no-project python scripts/add_license_header.py --path tests --types py --check
66
+ uv run --no-project python scripts/add_license_header.py --path scripts --types py,sh --check
67
+ uv run --no-project python scripts/add_license_header.py --path .github --types yml --check
68
+ uv run --no-project python scripts/add_license_header.py --path . --types toml --check
69
+
70
+ # Optional: remove if there is no test suite.
71
+ test:
72
+ name: test
73
+ runs-on: ubuntu-latest
74
+ steps:
75
+ - uses: actions/checkout@v6
76
+ - uses: astral-sh/setup-uv@v7
77
+ with:
78
+ enable-cache: true
79
+ cache-suffix: ${{ github.job }}
80
+ python-version: "3.12"
81
+ - run: uv sync --frozen
82
+ - name: Run tests with coverage
83
+ run: |
84
+ uv run --no-sync pytest \
85
+ --cov=fastly_sync \
86
+ --cov-report=term-missing \
87
+ --cov-report=xml:coverage.xml \
88
+ --junitxml=junit.xml \
89
+ -o junit_family=legacy
90
+ - name: Upload coverage to Codecov
91
+ uses: codecov/codecov-action@v6
92
+ with:
93
+ files: coverage.xml
94
+ token: ${{ secrets.CODECOV_TOKEN }}
95
+ fail_ci_if_error: false
96
+ disable_search: true
97
+ - name: Upload test results to Codecov
98
+ if: ${{ !cancelled() }}
99
+ uses: codecov/codecov-action@v6
100
+ with:
101
+ files: junit.xml
102
+ report_type: test_results
103
+ token: ${{ secrets.CODECOV_TOKEN }}
104
+ fail_ci_if_error: false
105
+ disable_search: true
106
+
107
+ bandit:
108
+ name: bandit
109
+ runs-on: ubuntu-latest
110
+ steps:
111
+ - uses: actions/checkout@v6
112
+ - uses: astral-sh/setup-uv@v7
113
+ with:
114
+ enable-cache: true
115
+ cache-suffix: ${{ github.job }}
116
+ python-version: "3.12"
117
+ # Drop `--from 'bandit[toml]' ... -c pyproject.toml` to plain
118
+ # `uvx bandit --recursive src` if there is no [tool.bandit] skip list.
119
+ - run: uvx --from 'bandit[toml]' bandit -c pyproject.toml --recursive src
120
+
121
+ pip-audit:
122
+ name: pip-audit
123
+ runs-on: ubuntu-latest
124
+ steps:
125
+ - uses: actions/checkout@v6
126
+ - uses: astral-sh/setup-uv@v7
127
+ with:
128
+ enable-cache: true
129
+ cache-suffix: ${{ github.job }}
130
+ python-version: "3.12"
131
+ - run: uv sync --frozen
132
+ - run: uvx pip-audit --skip-editable --path .venv
133
+
134
+ osv-scanner:
135
+ name: osv-scanner
136
+ runs-on: ubuntu-latest
137
+ steps:
138
+ - uses: actions/checkout@v6
139
+ - name: Install OSV-Scanner
140
+ run: |
141
+ mkdir -p "$HOME/.local/bin"
142
+ curl -sSfL \
143
+ "https://github.com/google/osv-scanner/releases/latest/download/osv-scanner_linux_amd64" \
144
+ -o "$HOME/.local/bin/osv-scanner"
145
+ chmod +x "$HOME/.local/bin/osv-scanner"
146
+ echo "$HOME/.local/bin" >> "$GITHUB_PATH"
147
+ - run: osv-scanner scan source --lockfile=uv.lock
148
+
149
+ release:
150
+ name: release
151
+ needs: [lint, type-check, license-headers, test, bandit, pip-audit, osv-scanner]
152
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
153
+ runs-on: ubuntu-latest
154
+ permissions:
155
+ contents: write
156
+ outputs:
157
+ no_bumps: ${{ steps.bump.outputs.no_bumps }}
158
+ version: ${{ steps.bump.outputs.version }}
159
+ steps:
160
+ - uses: actions/checkout@v6
161
+ with:
162
+ fetch-depth: 0
163
+ persist-credentials: true
164
+ # NOTE: no python-version pin here - multicz needs Python >=3.12 and
165
+ # `uv tool install multicz` fails under 3.11.
166
+ - uses: astral-sh/setup-uv@v7
167
+ with:
168
+ enable-cache: true
169
+ cache-suffix: ${{ github.job }}
170
+ - name: Install multicz
171
+ run: uv tool install multicz
172
+ - name: Configure git author
173
+ run: |
174
+ NAME="${{ github.event.head_commit.author.name }}"
175
+ EMAIL="${{ github.event.head_commit.author.email }}"
176
+ git config user.name "${NAME:-github-actions[bot]}"
177
+ git config user.email "${EMAIL:-41898282+github-actions[bot]@users.noreply.github.com}"
178
+ - name: Detect GPG availability
179
+ id: gpg
180
+ env:
181
+ GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
182
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
183
+ run: |
184
+ if [ -n "$GPG_PRIVATE_KEY" ] && [ -n "$GPG_PASSPHRASE" ]; then
185
+ echo "available=true" >> "$GITHUB_OUTPUT"
186
+ else
187
+ echo "available=false" >> "$GITHUB_OUTPUT"
188
+ fi
189
+ - name: Import and unlock GPG key
190
+ if: steps.gpg.outputs.available == 'true'
191
+ env:
192
+ GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
193
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
194
+ run: |
195
+ echo "$GPG_PRIVATE_KEY" | gpg --batch --import
196
+ echo test | gpg --batch --yes --passphrase "$GPG_PASSPHRASE" \
197
+ --pinentry-mode loopback --sign > /dev/null
198
+ KEY_ID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec/{print $5; exit}')
199
+ git config user.signingkey "$KEY_ID"
200
+ - name: Plan release
201
+ run: uv tool run multicz plan --summary "$GITHUB_STEP_SUMMARY"
202
+ - name: Bump, commit, tag, push (signed)
203
+ id: bump_signed
204
+ if: steps.gpg.outputs.available == 'true'
205
+ run: |
206
+ set -euo pipefail
207
+ PLAN=$(uv tool run multicz bump --commit --tag --push --sign --output json)
208
+ BUMPED=$(echo "$PLAN" | jq -r '.bumps | keys | join(" ")')
209
+ if [ -z "$BUMPED" ]; then echo "no_bumps=true" >> "$GITHUB_OUTPUT";
210
+ else echo "no_bumps=false" >> "$GITHUB_OUTPUT"; echo "version=$(uv tool run multicz get fastly-sync)" >> "$GITHUB_OUTPUT"; fi
211
+ - name: Bump, commit, tag, push
212
+ id: bump_unsigned
213
+ if: steps.gpg.outputs.available != 'true'
214
+ run: |
215
+ set -euo pipefail
216
+ PLAN=$(uv tool run multicz bump --commit --tag --push --output json)
217
+ BUMPED=$(echo "$PLAN" | jq -r '.bumps | keys | join(" ")')
218
+ if [ -z "$BUMPED" ]; then echo "no_bumps=true" >> "$GITHUB_OUTPUT";
219
+ else echo "no_bumps=false" >> "$GITHUB_OUTPUT"; echo "version=$(uv tool run multicz get fastly-sync)" >> "$GITHUB_OUTPUT"; fi
220
+ - name: Resolve release outputs
221
+ id: bump
222
+ run: |
223
+ if [ "${{ steps.gpg.outputs.available }}" = "true" ]; then
224
+ echo 'no_bumps=${{ steps.bump_signed.outputs.no_bumps }}' >> "$GITHUB_OUTPUT"
225
+ echo 'version=${{ steps.bump_signed.outputs.version }}' >> "$GITHUB_OUTPUT"
226
+ else
227
+ echo 'no_bumps=${{ steps.bump_unsigned.outputs.no_bumps }}' >> "$GITHUB_OUTPUT"
228
+ echo 'version=${{ steps.bump_unsigned.outputs.version }}' >> "$GITHUB_OUTPUT"
229
+ fi
230
+
231
+ pypi-publish:
232
+ name: pypi-publish
233
+ needs: [release]
234
+ if: >-
235
+ github.event_name == 'push' && github.ref == 'refs/heads/main'
236
+ && needs.release.result == 'success' && needs.release.outputs.no_bumps == 'false'
237
+ runs-on: ubuntu-latest
238
+ environment:
239
+ name: pypi
240
+ url: https://pypi.org/project/fastly-sync/
241
+ permissions:
242
+ contents: write
243
+ id-token: write # Trusted Publishing (OIDC) - do NOT add a token/password
244
+ steps:
245
+ - uses: actions/checkout@v6
246
+ with:
247
+ fetch-depth: 0
248
+ ref: main
249
+ - uses: astral-sh/setup-uv@v7
250
+ with:
251
+ enable-cache: true
252
+ cache-suffix: ${{ github.job }}
253
+ - name: Install multicz
254
+ run: uv tool install multicz
255
+ - name: Build wheel and sdist
256
+ run: uv build --out-dir dist && ls -l dist
257
+ - name: Publish to PyPI
258
+ uses: pypa/gh-action-pypi-publish@release/v1
259
+ with:
260
+ packages-dir: dist
261
+ skip-existing: true
262
+ - name: Create GitHub release
263
+ env:
264
+ GH_TOKEN: ${{ github.token }}
265
+ run: |
266
+ set -euo pipefail
267
+ version="${{ needs.release.outputs.version }}"
268
+ # Use the SAME tag multicz created: bare history -> tag="${version}".
269
+ tag="v${version}"
270
+ notes=$(uv tool run multicz release-notes --tag "$tag")
271
+ gh release create "$tag" --title "$tag" --notes "$notes" dist/*
272
+
273
+ docs:
274
+ name: docs
275
+ needs: [release]
276
+ if: >-
277
+ github.event_name == 'push'
278
+ && github.ref == 'refs/heads/main'
279
+ && needs.release.result == 'success'
280
+ && needs.release.outputs.no_bumps == 'false'
281
+ runs-on: ubuntu-latest
282
+ environment:
283
+ name: github-pages
284
+ url: ${{ steps.deployment.outputs.page_url }}
285
+ permissions:
286
+ contents: read
287
+ pages: write
288
+ id-token: write
289
+ steps:
290
+ - uses: actions/checkout@v6
291
+ with:
292
+ ref: main
293
+ - uses: actions/configure-pages@v6
294
+ with:
295
+ enablement: true
296
+ - uses: astral-sh/setup-uv@v7
297
+ with:
298
+ enable-cache: true
299
+ cache-suffix: ${{ github.job }}
300
+ - name: Install Zensical (doc group)
301
+ run: uv sync --frozen --only-group doc
302
+ - name: Build site
303
+ run: uv run zensical build --clean
304
+ - uses: actions/upload-pages-artifact@v5
305
+ with:
306
+ path: site
307
+ - id: deployment
308
+ uses: actions/deploy-pages@v5
@@ -0,0 +1,94 @@
1
+ # SPDX-License-Identifier: MIT
2
+ # Copyright (c) 2026 Chris <goabonga@pm.me>
3
+
4
+ name: dependabot-rewrite
5
+
6
+ # `pull_request_target` so the workflow can read GPG_PRIVATE_KEY /
7
+ # GPG_PASSPHRASE (regular `pull_request` runs without secrets on bot events).
8
+ # The workflow body is loaded from `main`, not the PR branch, so no untrusted
9
+ # code runs. The actor gate restricts it to genuine Dependabot PRs.
10
+
11
+ on:
12
+ pull_request_target:
13
+ types: [opened, synchronize, reopened]
14
+
15
+ permissions:
16
+ contents: write
17
+ pull-requests: write
18
+
19
+ jobs:
20
+ rewrite:
21
+ name: rewrite dependabot commits
22
+ if: github.actor == 'dependabot[bot]'
23
+ runs-on: ubuntu-latest
24
+ concurrency:
25
+ group: dependabot-rewrite-${{ github.event.pull_request.number }}
26
+ cancel-in-progress: true
27
+ steps:
28
+ - name: Check GPG availability
29
+ id: gate
30
+ env:
31
+ GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
32
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
33
+ run: |
34
+ if [ -z "$GPG_PRIVATE_KEY" ] || [ -z "$GPG_PASSPHRASE" ]; then
35
+ {
36
+ echo "## Dependabot rewrite: skipped"
37
+ echo ""
38
+ echo "GPG_PRIVATE_KEY and/or GPG_PASSPHRASE are not configured. "
39
+ echo "The Dependabot PR ships with bot-authored, web-signed commits."
40
+ } >> "$GITHUB_STEP_SUMMARY"
41
+ echo "::warning::GPG secrets unset; leaving Dependabot commits as-is"
42
+ echo "skip=true" >> "$GITHUB_OUTPUT"
43
+ fi
44
+
45
+ - name: Checkout PR head branch
46
+ if: steps.gate.outputs.skip != 'true'
47
+ uses: actions/checkout@v6
48
+ with:
49
+ ref: ${{ github.event.pull_request.head.ref }}
50
+ fetch-depth: 0
51
+ persist-credentials: true
52
+
53
+ - name: Configure GPG and git identity from the imported key
54
+ if: steps.gate.outputs.skip != 'true'
55
+ env:
56
+ GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
57
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
58
+ run: |
59
+ set -euo pipefail
60
+ echo "$GPG_PRIVATE_KEY" | gpg --batch --import
61
+ echo test | gpg --batch --yes --passphrase "$GPG_PASSPHRASE" \
62
+ --pinentry-mode loopback --sign > /dev/null
63
+ KEY_ID=$(gpg --list-secret-keys --with-colons | awk -F: '/^sec/{print $5; exit}')
64
+ UID_LINE=$(gpg --list-keys --with-colons "$KEY_ID" | awk -F: '/^uid/{print $10; exit}')
65
+ NAME="${UID_LINE%% <*}"
66
+ EMAIL=$(printf '%s' "$UID_LINE" | sed -nE 's/.*<([^>]+)>.*/\1/p')
67
+ git config user.name "$NAME"
68
+ git config user.email "$EMAIL"
69
+ git config user.signingkey "$KEY_ID"
70
+ git config commit.gpgsign true
71
+
72
+ - name: Rewrite commits with scope-aware messages
73
+ if: steps.gate.outputs.skip != 'true'
74
+ run: |
75
+ set -euo pipefail
76
+ BASE_SHA=$(git merge-base "origin/${{ github.event.pull_request.base.ref }}" HEAD)
77
+ git rebase "$BASE_SHA" --exec "scripts/rewrite-dependabot-commit.sh"
78
+
79
+ - name: Force-push rewritten branch
80
+ if: steps.gate.outputs.skip != 'true'
81
+ run: |
82
+ git push --force-with-lease origin "HEAD:${{ github.event.pull_request.head.ref }}"
83
+
84
+ - name: Write step summary
85
+ if: steps.gate.outputs.skip != 'true' && success()
86
+ run: |
87
+ {
88
+ echo "## Dependabot rewrite: applied"
89
+ echo ""
90
+ echo "PR branch \`${{ github.event.pull_request.head.ref }}\` rewritten:"
91
+ echo ""
92
+ echo "- Conventional-commits scope inferred from changed files / dev-group membership"
93
+ echo "- Authored and GPG-signed as \`$(git config user.name) <$(git config user.email)>\`"
94
+ } >> "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,25 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # Test & coverage artifacts
13
+ .pytest_cache/
14
+ .ruff_cache/
15
+ .mypy_cache/
16
+ .coverage
17
+ coverage.xml
18
+ junit.xml
19
+ htmlcov/
20
+
21
+ # Docs build output
22
+ site/
23
+
24
+ # Dependabot-generated requirements (Debian builds)
25
+ debian/requirements.txt
@@ -0,0 +1,13 @@
1
+ {
2
+ "version": 1,
3
+ "git_head": "afb82b697a77cecfce51e8fd20f6291d835ae9e5",
4
+ "git_head_short": "afb82b6",
5
+ "timestamp": "2026-06-21T18:23:20Z",
6
+ "components": {
7
+ "fastly-sync": {
8
+ "version": "0.1.0",
9
+ "tag": "v0.1.0",
10
+ "tag_sha": null
11
+ }
12
+ }
13
+ }