mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-09-17 13:42:21 +02:00
Squash Odysseus development history
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""Pin the auth exemption for task webhook-trigger URLs.
|
||||
|
||||
The task router exposes ``POST /api/tasks/{task_id}/webhook/{token}`` as a
|
||||
public webhook entrypoint — the path-embedded ``webhook_token`` is the
|
||||
credential, and the route handler in ``routes/task_routes.py`` validates
|
||||
it against the row and returns 404 on mismatch. The UI advertises the
|
||||
URL as "no auth needed" because external callers (Zapier, n8n, curl)
|
||||
can't supply a session cookie.
|
||||
|
||||
Without an entry in ``AUTH_EXEMPT_PATTERNS`` ``AuthMiddleware`` rejected
|
||||
every POST with 401 before the token was ever checked (issue #621).
|
||||
This test re-reads the exemption logic out of ``app.py`` and confirms a
|
||||
representative webhook path is treated as exempt, while neighbouring
|
||||
non-public task paths are NOT.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
|
||||
def _read_app_source() -> str:
|
||||
app_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"app.py",
|
||||
)
|
||||
with open(app_path, encoding="utf-8") as fh:
|
||||
return fh.read()
|
||||
|
||||
|
||||
def test_webhook_trigger_path_is_in_exempt_patterns():
|
||||
"""The dynamic webhook trigger path must match an AUTH_EXEMPT_PATTERNS
|
||||
entry. Pull every regex literal compiled inside the block out of the
|
||||
source and apply it directly — extraction has to tolerate nested
|
||||
brackets inside each character class (e.g. ``[^/]+``)."""
|
||||
src = _read_app_source()
|
||||
# Find the start of the list, then walk character-by-character to the
|
||||
# matching closing bracket. A regex would have to count brackets,
|
||||
# which is more painful than just doing the count by hand.
|
||||
start = src.find("AUTH_EXEMPT_PATTERNS")
|
||||
assert start != -1, "AUTH_EXEMPT_PATTERNS not declared in app.py"
|
||||
lb = src.find("[", start)
|
||||
assert lb != -1
|
||||
depth = 0
|
||||
end = -1
|
||||
for i in range(lb, len(src)):
|
||||
ch = src[i]
|
||||
if ch == "[":
|
||||
depth += 1
|
||||
elif ch == "]":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
end = i
|
||||
break
|
||||
assert end != -1, "could not find closing bracket for AUTH_EXEMPT_PATTERNS"
|
||||
body = src[lb + 1 : end]
|
||||
# Pull each compiled regex literal: _re.compile(r"...").
|
||||
patterns = re.findall(r'_re\.compile\(\s*r"([^"]+)"\s*\)', body)
|
||||
assert patterns, (
|
||||
"expected at least one compiled regex in AUTH_EXEMPT_PATTERNS"
|
||||
)
|
||||
compiled = [re.compile(p) for p in patterns]
|
||||
|
||||
sample = "/api/tasks/abc123/webhook/" + "x" * 43
|
||||
assert any(c.match(sample) for c in compiled), (
|
||||
f"webhook trigger path {sample!r} must be auth-exempt - issue #621"
|
||||
)
|
||||
|
||||
# Negative: routes that are NOT meant to be public must not match.
|
||||
for not_public in (
|
||||
"/api/tasks",
|
||||
"/api/tasks/abc123",
|
||||
"/api/tasks/abc123/webhook-regenerate",
|
||||
"/api/tasks/abc123/run",
|
||||
):
|
||||
assert not any(c.match(not_public) for c in compiled), (
|
||||
f"{not_public!r} must NOT be auth-exempt"
|
||||
)
|
||||
|
||||
|
||||
def test_webhook_trigger_handler_still_validates_token():
|
||||
"""The exemption is only safe because the route handler in
|
||||
routes/task_routes.py still checks the token against the row and
|
||||
returns 404 on mismatch. Pin that behaviour so a refactor of the
|
||||
handler doesn't quietly make the endpoint truly anonymous. Read the
|
||||
source directly — importing task_routes pulls in SQLAlchemy and
|
||||
fails under the conftest stubs."""
|
||||
routes_path = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"routes",
|
||||
"task",
|
||||
"task_routes.py",
|
||||
)
|
||||
with open(routes_path, encoding="utf-8") as fh:
|
||||
src = fh.read()
|
||||
assert "ScheduledTask.webhook_token == token" in src
|
||||
assert '@router.post("/{task_id}/webhook/{token}")' in src
|
||||
Reference in New Issue
Block a user