mirror of
https://github.com/pewdiepie-archdaemon/odysseus.git
synced 2026-11-06 21:22:23 +01:00
fix(cli): generate live task webhook URLs (#5956)
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
"""odysseus-webhook — shell wrapper for scheduled-task webhook tokens.
|
"""odysseus-webhook — shell wrapper for scheduled-task webhook tokens.
|
||||||
|
|
||||||
Tasks in the scheduled-task system can carry a `webhook_token`. Any
|
Tasks in the scheduled-task system can carry a `webhook_token`. Any
|
||||||
HTTP POST to `/api/webhook/<token>` fires the task. This CLI lists,
|
HTTP POST to `/api/tasks/<task-id>/webhook/<token>` fires the task. This CLI lists,
|
||||||
rotates, and revokes those tokens.
|
rotates, and revokes those tokens.
|
||||||
|
|
||||||
odysseus-webhook list # tasks that have a token
|
odysseus-webhook list # tasks that have a token
|
||||||
@@ -21,6 +21,7 @@ quiet_logs()
|
|||||||
|
|
||||||
import argparse, json, logging, os, secrets, sys
|
import argparse, json, logging, os, secrets, sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from core.database import SessionLocal, ScheduledTask
|
from core.database import SessionLocal, ScheduledTask
|
||||||
@@ -53,6 +54,14 @@ def _summary(t: "ScheduledTask", reveal: bool = False) -> dict:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _task_webhook_url(base: str, task_id: str, token: str) -> str:
|
||||||
|
"""Build the live task-route URL without leaking ids into path syntax."""
|
||||||
|
root = (base or "http://localhost:7000").rstrip("/")
|
||||||
|
task_part = quote(str(task_id), safe="")
|
||||||
|
token_part = quote(str(token), safe="")
|
||||||
|
return f"{root}/api/tasks/{task_part}/webhook/{token_part}"
|
||||||
|
|
||||||
|
|
||||||
def cmd_list(args):
|
def cmd_list(args):
|
||||||
db = SessionLocal()
|
db = SessionLocal()
|
||||||
try:
|
try:
|
||||||
@@ -109,8 +118,7 @@ def cmd_url(args):
|
|||||||
fail(f"no task with id {args.id!r}")
|
fail(f"no task with id {args.id!r}")
|
||||||
if not t.webhook_token:
|
if not t.webhook_token:
|
||||||
fail(f"task {args.id!r} has no webhook token (rotate one first)")
|
fail(f"task {args.id!r} has no webhook token (rotate one first)")
|
||||||
base = (args.base or "http://localhost:7000").rstrip("/")
|
url = _task_webhook_url(args.base, t.id, t.webhook_token)
|
||||||
url = f"{base}/api/webhook/{t.webhook_token}"
|
|
||||||
emit({
|
emit({
|
||||||
"task_id": t.id,
|
"task_id": t.id,
|
||||||
"name": t.name,
|
"name": t.name,
|
||||||
|
|||||||
@@ -10,3 +10,28 @@ def test_mask_token_handles_short_values(monkeypatch):
|
|||||||
assert cli._mask_token("short") == "***"
|
assert cli._mask_token("short") == "***"
|
||||||
assert cli._mask_token("abcdef1234567890") == "abcdef…7890"
|
assert cli._mask_token("abcdef1234567890") == "abcdef…7890"
|
||||||
assert cli._mask_token("short", reveal=True) == "short"
|
assert cli._mask_token("short", reveal=True) == "short"
|
||||||
|
|
||||||
|
|
||||||
|
def test_task_webhook_url_matches_live_route_and_escapes_path_parts(monkeypatch):
|
||||||
|
make_core_db_stub(monkeypatch, models=["ScheduledTask"])
|
||||||
|
cli = load_script("odysseus-webhook")
|
||||||
|
|
||||||
|
url = cli._task_webhook_url(
|
||||||
|
"https://ody.example/",
|
||||||
|
"task/with space",
|
||||||
|
"token/with space",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert url == (
|
||||||
|
"https://ody.example/api/tasks/task%2Fwith%20space/"
|
||||||
|
"webhook/token%2Fwith%20space"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_default_task_webhook_url_uses_current_task_prefix(monkeypatch):
|
||||||
|
make_core_db_stub(monkeypatch, models=["ScheduledTask"])
|
||||||
|
cli = load_script("odysseus-webhook")
|
||||||
|
|
||||||
|
assert cli._task_webhook_url(None, "task-1", "secret") == (
|
||||||
|
"http://localhost:7000/api/tasks/task-1/webhook/secret"
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user