Skip to content

Commit e006995

Browse files
committed
Add integration-auth workflow
1 parent 8ca9cdf commit e006995

3 files changed

Lines changed: 162 additions & 0 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com>
2+
#
3+
# SPDX-License-Identifier: BSL-1.0
4+
5+
name: Integration auth
6+
7+
on:
8+
push:
9+
branches: [main, develop]
10+
pull_request:
11+
branches: [main, develop]
12+
13+
jobs:
14+
integration-auth:
15+
runs-on: ubuntu-latest
16+
timeout-minutes: 10
17+
steps:
18+
# actions/checkout v6.0.2
19+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
20+
with:
21+
persist-credentials: false
22+
23+
# actions/setup-python v6.2.0
24+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
25+
with:
26+
python-version: '3.12'
27+
28+
- name: Run integration auth tests
29+
run: bash scripts/integration-auth.sh
30+
31+
- name: Upload logs on failure
32+
if: failure()
33+
# actions/upload-artifact v4.6.2
34+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
35+
with:
36+
name: integration-auth-logs
37+
path: /tmp/compose-logs.txt

scripts/integration-auth.sh

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env bash
2+
# SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com>
3+
# SPDX-License-Identifier: BSL-1.0
4+
5+
# Integration auth test entrypoint.
6+
# Builds the stack, waits for health, creates a token, runs auth tests.
7+
# On exit (success or failure): collects logs and tears down the stack.
8+
9+
set -euo pipefail
10+
11+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
12+
# shellcheck source=lib/weblate-stack.sh
13+
source "${SCRIPT_DIR}/lib/weblate-stack.sh"
14+
15+
cleanup() {
16+
local exit_code=$?
17+
set +e
18+
echo "--- Collecting logs ---"
19+
stack_logs /tmp/compose-logs.txt
20+
echo "--- Tearing down stack ---"
21+
stack_down
22+
exit "$exit_code"
23+
}
24+
trap cleanup EXIT
25+
26+
echo "=== Building stack ==="
27+
stack_build
28+
29+
echo "=== Starting stack ==="
30+
stack_up
31+
32+
echo "=== Waiting for Weblate ==="
33+
stack_wait_healthy "${HEALTH_TIMEOUT:-120}"
34+
35+
echo "=== Creating API token ==="
36+
WEBLATE_API_TOKEN="$(stack_create_token admin)"
37+
export WEBLATE_API_TOKEN
38+
export WEBLATE_LIVE_BASE_URL="${WEBLATE_LIVE_BASE_URL:-http://localhost:${WEBLATE_PORT:-8080}}"
39+
export WEBLATE_COMPOSE_FILE="${COMPOSE_FILE}"
40+
export WEBLATE_COMPOSE_PROJECT="${COMPOSE_PROJECT_NAME}"
41+
42+
echo "=== Running auth tests ==="
43+
pip install --quiet pytest
44+
python -m pytest --confcutdir=tests/integration --override-ini addopts= \
45+
tests/integration/test_auth.py -v

tests/integration/test_auth.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# SPDX-FileCopyrightText: 2026 Andrew Zhang <whisper67265@outlook.com>
2+
#
3+
# SPDX-License-Identifier: BSL-1.0
4+
5+
"""P2 integration auth tests.
6+
7+
Verifies authentication and authorization behavior across all
8+
Boost endpoint routes:
9+
- Valid token grants access to protected endpoints
10+
- Invalid/missing tokens are rejected
11+
- Unauthenticated endpoints remain accessible without a token
12+
"""
13+
14+
from __future__ import annotations
15+
16+
import pytest
17+
18+
from tests.integration.lib.http import http_get, http_json
19+
20+
pytestmark = pytest.mark.integration
21+
22+
_VALID_ADD_OR_UPDATE_BODY = {
23+
"organization": "test-org",
24+
"version": "test-1.0.0",
25+
"add_or_update": {"zh_Hans": ["test-submodule"]},
26+
}
27+
28+
_FAKE_TOKEN = "wlu_this_token_does_not_exist_in_weblate"
29+
30+
31+
class TestBoostEndpointAuth:
32+
"""Authentication and authorization across all Boost endpoint routes."""
33+
34+
def test_valid_token_on_info(self, api_token: str) -> None:
35+
code, body = http_get("/boost-endpoint/info/", token=api_token)
36+
assert code == 200, f"expected 200: {code} {body}"
37+
assert isinstance(body, dict)
38+
assert "module" in body
39+
40+
def test_valid_token_on_add_or_update(self, api_token: str) -> None:
41+
code, body = http_json(
42+
"POST",
43+
"/boost-endpoint/add-or-update/",
44+
token=api_token,
45+
body=_VALID_ADD_OR_UPDATE_BODY,
46+
)
47+
assert code == 202, f"expected 202: {code} {body}"
48+
assert isinstance(body, dict)
49+
assert body.get("status") == "accepted"
50+
assert body.get("task_id")
51+
52+
def test_invalid_token_rejected(self) -> None:
53+
code, _ = http_get("/boost-endpoint/info/", token=_FAKE_TOKEN)
54+
assert code in (401, 403), f"expected 401/403: {code}"
55+
56+
def test_no_token_rejected(self) -> None:
57+
code, _ = http_get("/boost-endpoint/info/")
58+
assert code in (401, 403), f"expected 401/403: {code}"
59+
60+
def test_invalid_token_on_add_or_update(self) -> None:
61+
code, _ = http_json(
62+
"POST",
63+
"/boost-endpoint/add-or-update/",
64+
token=_FAKE_TOKEN,
65+
body=_VALID_ADD_OR_UPDATE_BODY,
66+
)
67+
assert code in (401, 403), f"expected 401/403: {code}"
68+
69+
def test_no_token_on_add_or_update(self) -> None:
70+
code, _ = http_json(
71+
"POST",
72+
"/boost-endpoint/add-or-update/",
73+
body=_VALID_ADD_OR_UPDATE_BODY,
74+
)
75+
assert code in (401, 403), f"expected 401/403: {code}"
76+
77+
def test_ping_no_auth_required(self) -> None:
78+
code, body = http_get("/boost-endpoint/plugin-ping/")
79+
assert code == 200
80+
assert body == "ok" or body == b"ok"

0 commit comments

Comments
 (0)