webgate 0.4.2__tar.gz → 2.3.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.
- webgate-2.3.0/.github/workflows/ci.yml +106 -0
- webgate-2.3.0/.github/workflows/demo.yml +63 -0
- webgate-2.3.0/.github/workflows/release.yml +123 -0
- {webgate-0.4.2 → webgate-2.3.0}/.gitignore +3 -0
- webgate-2.3.0/CHANGELOG.md +847 -0
- webgate-2.3.0/DESIGN.md +103 -0
- webgate-2.3.0/PKG-INFO +845 -0
- webgate-2.3.0/PRODUCT.md +54 -0
- webgate-2.3.0/README.md +796 -0
- webgate-2.3.0/RELEASING.md +109 -0
- webgate-2.3.0/ROADMAP.md +109 -0
- webgate-2.3.0/VERSION +1 -0
- webgate-2.3.0/compose.ha.yml +62 -0
- webgate-2.3.0/compose.playground.yml +152 -0
- webgate-2.3.0/compose.yml +32 -0
- webgate-2.3.0/deploy/nginx-ha.conf +36 -0
- webgate-2.3.0/docs/LOCAL_TESTING.md +239 -0
- webgate-2.3.0/docs/architecture.md +293 -0
- webgate-2.3.0/docs/changelog.md +847 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/getting-started/quickstart.md +4 -4
- webgate-2.3.0/docs/getting-started/upgrade.md +133 -0
- webgate-2.3.0/docs/guide/access-control.md +64 -0
- webgate-2.3.0/docs/guide/advanced.md +102 -0
- webgate-2.3.0/docs/guide/ha.md +59 -0
- webgate-2.3.0/docs/guide/integrations.md +110 -0
- webgate-2.3.0/docs/guide/settings.md +65 -0
- webgate-2.3.0/docs/index.md +86 -0
- webgate-2.3.0/docs/screenshots/playground/01-login.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/02-alice-ldap-empty.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/03-add-server-jump-via.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/04-dashboard-3-servers.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/05-terminal-via-jump-host.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/06-snippet-whoami.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/07-shared-joiner.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/07-shared-owner.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/08-webhook-fired.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/09-recordings-list.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/10-recording-replay.png +0 -0
- webgate-2.3.0/docs/screenshots/playground/11-bob-limited.png +0 -0
- webgate-2.3.0/docs/screenshots/site-manager.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/agent.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/branding.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/light.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/login.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/palette.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/settings.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/sftp.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/site-manager.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/terminal.png +0 -0
- webgate-2.3.0/docs/screenshots/v2/users.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/fly.toml +5 -0
- {webgate-0.4.2 → webgate-2.3.0}/mkdocs.yml +10 -2
- {webgate-0.4.2 → webgate-2.3.0}/pyproject.toml +1 -1
- webgate-2.3.0/scripts/release_notes.py +42 -0
- webgate-2.3.0/src/webgate/__init__.py +29 -0
- webgate-2.3.0/src/webgate/__main__.py +92 -0
- webgate-2.3.0/src/webgate/agent/__init__.py +16 -0
- webgate-2.3.0/src/webgate/agent/cache.py +76 -0
- webgate-2.3.0/src/webgate/agent/conversation.py +189 -0
- webgate-2.3.0/src/webgate/agent/memory.py +174 -0
- webgate-2.3.0/src/webgate/agent/models.py +56 -0
- webgate-2.3.0/src/webgate/agent/provider.py +144 -0
- webgate-2.3.0/src/webgate/agent/routes.py +381 -0
- webgate-2.3.0/src/webgate/agent/service.py +304 -0
- webgate-2.3.0/src/webgate/agent/sftp_tools.py +292 -0
- webgate-2.3.0/src/webgate/agent/store.py +157 -0
- webgate-2.3.0/src/webgate/agent/tools.py +223 -0
- webgate-2.3.0/src/webgate/app.py +150 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/audit/models.py +2 -1
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/auth/ldap.py +18 -15
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/auth/routes.py +71 -32
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/auth/service.py +23 -16
- webgate-2.3.0/src/webgate/backup/__init__.py +9 -0
- webgate-2.3.0/src/webgate/backup/models.py +37 -0
- webgate-2.3.0/src/webgate/backup/routes.py +102 -0
- webgate-2.3.0/src/webgate/backup/service.py +364 -0
- webgate-2.3.0/src/webgate/branding/__init__.py +10 -0
- webgate-2.3.0/src/webgate/branding/routes.py +101 -0
- webgate-2.3.0/src/webgate/branding/store.py +243 -0
- webgate-2.3.0/src/webgate/config.py +81 -0
- webgate-2.3.0/src/webgate/db/engine.py +242 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/demo.py +4 -4
- webgate-2.3.0/src/webgate/files/limits.py +71 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/files/pool.py +22 -14
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/files/routes.py +156 -23
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/files/sftp_service.py +123 -27
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/recordings/models.py +7 -4
- webgate-2.3.0/src/webgate/recordings/recorder.py +105 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/recordings/routes.py +57 -30
- webgate-2.3.0/src/webgate/runtime_config/registry.py +321 -0
- webgate-2.3.0/src/webgate/runtime_config/routes.py +153 -0
- webgate-2.3.0/src/webgate/runtime_config/store.py +219 -0
- webgate-2.3.0/src/webgate/servers/hostkeys.py +127 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/servers/models.py +27 -1
- webgate-2.3.0/src/webgate/servers/monitor.py +267 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/servers/routes.py +88 -17
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/servers/service.py +35 -14
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/snippets/models.py +12 -1
- webgate-2.3.0/src/webgate/snippets/routes.py +127 -0
- webgate-2.3.0/src/webgate/static/index.html +3782 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/terminal/routes.py +60 -25
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/terminal/shared.py +40 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/terminal/ssh_session.py +7 -1
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/terminal/ws_handler.py +25 -12
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/webhooks/dispatcher.py +9 -2
- webgate-2.3.0/tests/__init__.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/tests/conftest.py +40 -2
- webgate-2.3.0/tests/test_agent_conversation.py +192 -0
- webgate-2.3.0/tests/test_agent_memory.py +124 -0
- webgate-2.3.0/tests/test_agent_settings.py +196 -0
- webgate-2.3.0/tests/test_agent_sftp_tools.py +223 -0
- webgate-2.3.0/tests/test_agent_tools.py +142 -0
- {webgate-0.4.2 → webgate-2.3.0}/tests/test_auth.py +4 -1
- webgate-2.3.0/tests/test_backup.py +241 -0
- webgate-2.3.0/tests/test_branding.py +200 -0
- webgate-2.3.0/tests/test_files_listing.py +144 -0
- webgate-2.3.0/tests/test_host_keys.py +223 -0
- webgate-2.3.0/tests/test_idle_sessions.py +110 -0
- webgate-2.3.0/tests/test_limits.py +141 -0
- webgate-2.3.0/tests/test_migrations.py +263 -0
- webgate-2.3.0/tests/test_monitor.py +92 -0
- webgate-2.3.0/tests/test_recordings.py +221 -0
- webgate-2.3.0/tests/test_release_notes.py +83 -0
- webgate-2.3.0/tests/test_secret_key_gate.py +43 -0
- {webgate-0.4.2 → webgate-2.3.0}/tests/test_servers.py +18 -8
- webgate-2.3.0/tests/test_settings.py +282 -0
- webgate-2.3.0/tests/test_snippets.py +133 -0
- {webgate-0.4.2 → webgate-2.3.0}/tests/test_terminal.py +18 -14
- webgate-2.3.0/tests/test_webhook_dispatch.py +111 -0
- {webgate-0.4.2 → webgate-2.3.0}/uv.lock +1 -1
- webgate-0.4.2/CHANGELOG.md +0 -250
- webgate-0.4.2/PKG-INFO +0 -649
- webgate-0.4.2/README.md +0 -600
- webgate-0.4.2/ROADMAP.md +0 -79
- webgate-0.4.2/VERSION +0 -1
- webgate-0.4.2/after-reload.yaml +0 -64
- webgate-0.4.2/compose.yml +0 -29
- webgate-0.4.2/docs/changelog.md +0 -27
- webgate-0.4.2/docs/index.md +0 -63
- webgate-0.4.2/docs/screenshots/site-manager.png +0 -0
- webgate-0.4.2/src/webgate/__init__.py +0 -1
- webgate-0.4.2/src/webgate/__main__.py +0 -18
- webgate-0.4.2/src/webgate/app.py +0 -104
- webgate-0.4.2/src/webgate/config.py +0 -49
- webgate-0.4.2/src/webgate/db/engine.py +0 -67
- webgate-0.4.2/src/webgate/recordings/recorder.py +0 -63
- webgate-0.4.2/src/webgate/servers/monitor.py +0 -117
- webgate-0.4.2/src/webgate/snippets/routes.py +0 -45
- webgate-0.4.2/src/webgate/static/index.html +0 -1647
- {webgate-0.4.2 → webgate-2.3.0}/.dockerignore +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/.github/workflows/docs.yml +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/Dockerfile +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/Dockerfile.demo +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/Dockerfile.ssh-demo +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/LICENSE +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/compose.dev.yml +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/api/auth.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/api/files.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/api/servers.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/api/terminal.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/getting-started/installation.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/guide/files.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/guide/servers.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/guide/split.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/guide/terminal.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/guide/users.md +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/access-control.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/audit.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/edit-access-control.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/editor.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/light-theme.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/login.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/new-server-form.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/sftp-restricted.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/sftp.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/split-view.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/ssh-disabled.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/terminal.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/users.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.3/01-login-demo-banner.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.3/02-dashboard-jump-host.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.3/03-terminal-snippets-jump.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.3/04-snippet-executed.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.3/05-sftp-via-jump.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.3/06-webhooks-modal.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.3/07-webhook-test-fired.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.3/08-add-server-jump-via.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.4/01-shared-terminal-owner.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.4/02-shared-terminal-joiner.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.4/03-recording-replay.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/docs/screenshots/v0.4/04-recordings-modal.png +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/audit/__init__.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/audit/service.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/auth/__init__.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/auth/models.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/db/__init__.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/files/__init__.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/files/models.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/recordings/__init__.py +0 -0
- {webgate-0.4.2/src/webgate/servers → webgate-2.3.0/src/webgate/runtime_config}/__init__.py +0 -0
- {webgate-0.4.2/src/webgate/snippets → webgate-2.3.0/src/webgate/servers}/__init__.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/servers/crypto.py +0 -0
- {webgate-0.4.2/src/webgate/terminal → webgate-2.3.0/src/webgate/snippets}/__init__.py +0 -0
- {webgate-0.4.2/src/webgate/webhooks → webgate-2.3.0/src/webgate/terminal}/__init__.py +0 -0
- {webgate-0.4.2/tests → webgate-2.3.0/src/webgate/webhooks}/__init__.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/webhooks/models.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/src/webgate/webhooks/routes.py +0 -0
- {webgate-0.4.2 → webgate-2.3.0}/tests/test_files.py +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# Everything that must be true before a release can be cut. The release workflow
|
|
4
|
+
# runs this same suite again on the tag rather than trusting that main was green.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
pull_request:
|
|
10
|
+
workflow_call: # release.yml reuses this instead of duplicating it
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: ci-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
test:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
strategy:
|
|
23
|
+
fail-fast: false
|
|
24
|
+
matrix:
|
|
25
|
+
# The floor from requires-python, and what development actually runs on.
|
|
26
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@v5
|
|
32
|
+
with:
|
|
33
|
+
enable-cache: true
|
|
34
|
+
|
|
35
|
+
- name: Install
|
|
36
|
+
run: uv sync --all-extras --dev --python ${{ matrix.python-version }}
|
|
37
|
+
|
|
38
|
+
- name: Lint
|
|
39
|
+
run: uv run ruff check src/ tests/ scripts/
|
|
40
|
+
|
|
41
|
+
- name: Format check
|
|
42
|
+
run: uv run ruff format --check src/ tests/ scripts/
|
|
43
|
+
|
|
44
|
+
- name: Tests
|
|
45
|
+
run: uv run pytest tests/ -q
|
|
46
|
+
|
|
47
|
+
docker:
|
|
48
|
+
# A Dockerfile only breaks when someone builds it, and nobody was.
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
|
|
53
|
+
- uses: docker/setup-buildx-action@v3
|
|
54
|
+
|
|
55
|
+
- name: Build the runtime image
|
|
56
|
+
uses: docker/build-push-action@v6
|
|
57
|
+
with:
|
|
58
|
+
context: .
|
|
59
|
+
file: ./Dockerfile
|
|
60
|
+
push: false
|
|
61
|
+
load: true
|
|
62
|
+
tags: webgate:ci
|
|
63
|
+
cache-from: type=gha
|
|
64
|
+
cache-to: type=gha,mode=max
|
|
65
|
+
|
|
66
|
+
- name: It starts, serves, and refuses the default secret key
|
|
67
|
+
run: |
|
|
68
|
+
set -euo pipefail
|
|
69
|
+
|
|
70
|
+
echo "--- refuses to start with the shipped default key ---"
|
|
71
|
+
# Refusing means a non-zero exit, so the run cannot sit inside a pipeline
|
|
72
|
+
# under `pipefail` -- that would report the refusal as this step failing.
|
|
73
|
+
rc=0
|
|
74
|
+
docker run --rm webgate:ci > /tmp/refusal 2>&1 || rc=$?
|
|
75
|
+
cat /tmp/refusal
|
|
76
|
+
if [ "$rc" -eq 0 ]; then
|
|
77
|
+
echo "FAILED: started under the default key"; exit 1
|
|
78
|
+
fi
|
|
79
|
+
grep -q "WEBGATE_SECRET_KEY is still the shipped default" /tmp/refusal \
|
|
80
|
+
|| { echo "FAILED: refused, but not for the reason we expect"; exit 1; }
|
|
81
|
+
echo "ok: refused, with the message that says what to do"
|
|
82
|
+
|
|
83
|
+
echo "--- starts and answers with a real key ---"
|
|
84
|
+
docker run -d --name wg -p 8443:8443 \
|
|
85
|
+
-e WEBGATE_SECRET_KEY="$(openssl rand -hex 32)" webgate:ci
|
|
86
|
+
for i in $(seq 1 30); do
|
|
87
|
+
if curl -fsS http://localhost:8443/api/health >/dev/null 2>&1; then
|
|
88
|
+
echo "ok: healthy after ${i}s"
|
|
89
|
+
curl -fsS http://localhost:8443/openapi.json | grep -o '"version":"[^"]*"' | head -1
|
|
90
|
+
docker rm -f wg >/dev/null
|
|
91
|
+
exit 0
|
|
92
|
+
fi
|
|
93
|
+
sleep 1
|
|
94
|
+
done
|
|
95
|
+
echo "FAILED: never became healthy"; docker logs wg; docker rm -f wg; exit 1
|
|
96
|
+
|
|
97
|
+
docs:
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
steps:
|
|
100
|
+
- uses: actions/checkout@v4
|
|
101
|
+
- uses: actions/setup-python@v5
|
|
102
|
+
with:
|
|
103
|
+
python-version: "3.13"
|
|
104
|
+
- run: pip install mkdocs-material mkdocstrings mkdocstrings-python
|
|
105
|
+
- name: Build the site (strict — a broken link fails here, not on deploy)
|
|
106
|
+
run: mkdocs build --strict
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Deploy demo
|
|
2
|
+
|
|
3
|
+
# The public demo at webgate-demo.fly.dev. Deployed by hand until now, which is why
|
|
4
|
+
# it spent months serving a version several releases behind the repository.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
release:
|
|
8
|
+
types: [published]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
concurrency:
|
|
15
|
+
group: demo
|
|
16
|
+
cancel-in-progress: true
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
deploy:
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
environment:
|
|
22
|
+
name: demo
|
|
23
|
+
url: https://webgate-demo.fly.dev/
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
|
|
27
|
+
- uses: superfly/flyctl-actions/setup-flyctl@master
|
|
28
|
+
|
|
29
|
+
- name: The demo must already hold a real secret key
|
|
30
|
+
# Without it the app refuses to start, and the deploy would replace a working
|
|
31
|
+
# demo with a crash loop. Checking first turns that into a clear failure here.
|
|
32
|
+
env:
|
|
33
|
+
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
|
34
|
+
run: |
|
|
35
|
+
set -euo pipefail
|
|
36
|
+
if flyctl secrets list --app webgate-demo | grep -q WEBGATE_SECRET_KEY; then
|
|
37
|
+
echo "ok: WEBGATE_SECRET_KEY is set"
|
|
38
|
+
else
|
|
39
|
+
echo "WEBGATE_SECRET_KEY is not set on the demo app. Run once:"
|
|
40
|
+
echo " flyctl secrets set WEBGATE_SECRET_KEY=\$(openssl rand -hex 32) --app webgate-demo"
|
|
41
|
+
exit 1
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
- name: Deploy
|
|
45
|
+
env:
|
|
46
|
+
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
|
47
|
+
run: flyctl deploy --remote-only
|
|
48
|
+
|
|
49
|
+
- name: It is up, and it is the version we just released
|
|
50
|
+
run: |
|
|
51
|
+
set -euo pipefail
|
|
52
|
+
for i in $(seq 1 30); do
|
|
53
|
+
got=$(curl -fsS https://webgate-demo.fly.dev/openapi.json 2>/dev/null \
|
|
54
|
+
| grep -o '"version":"[^"]*"' | head -1 | cut -d'"' -f4) || got=""
|
|
55
|
+
if [ -n "$got" ]; then
|
|
56
|
+
echo "demo reports $got"
|
|
57
|
+
want="$(cat VERSION)"
|
|
58
|
+
[ "$got" = "$want" ] || { echo "expected $want"; exit 1; }
|
|
59
|
+
exit 0
|
|
60
|
+
fi
|
|
61
|
+
sleep 5
|
|
62
|
+
done
|
|
63
|
+
echo "the demo never answered"; exit 1
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Cutting a release is `git tag vX.Y.Z && git push origin vX.Y.Z`. Everything after
|
|
4
|
+
# that happens here, because doing it by hand is how PyPI and Docker Hub ended up
|
|
5
|
+
# three minor versions behind the repository.
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
push:
|
|
9
|
+
tags: ["v*"]
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
inputs:
|
|
12
|
+
tag:
|
|
13
|
+
description: "Existing tag to (re)publish, e.g. v2.2.0"
|
|
14
|
+
required: true
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
# Nothing is published before the version agrees with itself and the tests pass.
|
|
21
|
+
verify:
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
outputs:
|
|
24
|
+
version: ${{ steps.v.outputs.version }}
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
with:
|
|
28
|
+
ref: ${{ inputs.tag || github.ref }}
|
|
29
|
+
|
|
30
|
+
- id: v
|
|
31
|
+
name: The tag, VERSION and pyproject must agree
|
|
32
|
+
run: |
|
|
33
|
+
set -euo pipefail
|
|
34
|
+
tag="${{ inputs.tag || github.ref_name }}"
|
|
35
|
+
version="${tag#v}"
|
|
36
|
+
file="$(cat VERSION)"
|
|
37
|
+
proj="$(grep -m1 '^version = ' pyproject.toml | cut -d'"' -f2)"
|
|
38
|
+
echo "tag=$version VERSION=$file pyproject=$proj"
|
|
39
|
+
[ "$version" = "$file" ] || { echo "tag does not match VERSION"; exit 1; }
|
|
40
|
+
[ "$version" = "$proj" ] || { echo "tag does not match pyproject.toml"; exit 1; }
|
|
41
|
+
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
42
|
+
|
|
43
|
+
- uses: astral-sh/setup-uv@v5
|
|
44
|
+
- name: The changelog has an entry for it
|
|
45
|
+
run: uv run python scripts/release_notes.py "${{ steps.v.outputs.version }}" > /dev/null
|
|
46
|
+
|
|
47
|
+
test:
|
|
48
|
+
needs: verify
|
|
49
|
+
uses: ./.github/workflows/ci.yml
|
|
50
|
+
|
|
51
|
+
pypi:
|
|
52
|
+
needs: [verify, test]
|
|
53
|
+
runs-on: ubuntu-latest
|
|
54
|
+
environment:
|
|
55
|
+
name: pypi
|
|
56
|
+
url: https://pypi.org/project/webgate/${{ needs.verify.outputs.version }}
|
|
57
|
+
permissions:
|
|
58
|
+
id-token: write # trusted publishing: no API token is stored anywhere
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
with:
|
|
62
|
+
ref: ${{ inputs.tag || github.ref }}
|
|
63
|
+
- uses: astral-sh/setup-uv@v5
|
|
64
|
+
- run: uv build
|
|
65
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
66
|
+
|
|
67
|
+
docker:
|
|
68
|
+
needs: [verify, test]
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@v4
|
|
72
|
+
with:
|
|
73
|
+
ref: ${{ inputs.tag || github.ref }}
|
|
74
|
+
|
|
75
|
+
- uses: docker/setup-qemu-action@v3
|
|
76
|
+
- uses: docker/setup-buildx-action@v3
|
|
77
|
+
|
|
78
|
+
- uses: docker/login-action@v3
|
|
79
|
+
with:
|
|
80
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
81
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
82
|
+
|
|
83
|
+
- name: Build and push
|
|
84
|
+
uses: docker/build-push-action@v6
|
|
85
|
+
with:
|
|
86
|
+
context: .
|
|
87
|
+
file: ./Dockerfile
|
|
88
|
+
platforms: linux/amd64,linux/arm64
|
|
89
|
+
push: true
|
|
90
|
+
tags: |
|
|
91
|
+
kalexnolasco/webgate:${{ needs.verify.outputs.version }}
|
|
92
|
+
kalexnolasco/webgate:latest
|
|
93
|
+
cache-from: type=gha
|
|
94
|
+
cache-to: type=gha,mode=max
|
|
95
|
+
|
|
96
|
+
- name: Keep the Docker Hub description in step with the README
|
|
97
|
+
uses: peter-evans/dockerhub-description@v4
|
|
98
|
+
continue-on-error: true
|
|
99
|
+
with:
|
|
100
|
+
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
101
|
+
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
102
|
+
repository: kalexnolasco/webgate
|
|
103
|
+
readme-filepath: ./README.md
|
|
104
|
+
|
|
105
|
+
github_release:
|
|
106
|
+
needs: [verify, pypi, docker]
|
|
107
|
+
runs-on: ubuntu-latest
|
|
108
|
+
permissions:
|
|
109
|
+
contents: write
|
|
110
|
+
steps:
|
|
111
|
+
- uses: actions/checkout@v4
|
|
112
|
+
with:
|
|
113
|
+
ref: ${{ inputs.tag || github.ref }}
|
|
114
|
+
- uses: astral-sh/setup-uv@v5
|
|
115
|
+
|
|
116
|
+
- name: Notes come from CHANGELOG.md, not a second description of the same release
|
|
117
|
+
run: uv run python scripts/release_notes.py "${{ needs.verify.outputs.version }}" > notes.md
|
|
118
|
+
|
|
119
|
+
- uses: softprops/action-gh-release@v2
|
|
120
|
+
with:
|
|
121
|
+
tag_name: ${{ inputs.tag || github.ref_name }}
|
|
122
|
+
name: v${{ needs.verify.outputs.version }}
|
|
123
|
+
body_path: notes.md
|