feat(exec): require configured secret and header auth for /exec
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import base64
|
||||
import hmac
|
||||
import io
|
||||
import os
|
||||
import subprocess
|
||||
@@ -49,6 +50,7 @@ SETTINGS = {
|
||||
"exec_default_timeout_s": int(os.getenv("CLICKTHROUGH_EXEC_TIMEOUT_S", "30")),
|
||||
"exec_max_timeout_s": int(os.getenv("CLICKTHROUGH_EXEC_MAX_TIMEOUT_S", "120")),
|
||||
"exec_max_output_chars": int(os.getenv("CLICKTHROUGH_EXEC_MAX_OUTPUT_CHARS", "20000")),
|
||||
"exec_secret": os.getenv("CLICKTHROUGH_EXEC_SECRET", "").strip(),
|
||||
}
|
||||
|
||||
|
||||
@@ -299,6 +301,8 @@ def _resolve_exec_program(shell_name: str, command: str) -> list[str]:
|
||||
def _exec_command(req: ExecRequest) -> dict:
|
||||
if not SETTINGS["exec_enabled"]:
|
||||
raise HTTPException(status_code=403, detail="exec endpoint disabled")
|
||||
if not SETTINGS["exec_secret"]:
|
||||
raise HTTPException(status_code=403, detail="exec secret not configured")
|
||||
|
||||
run_dry = SETTINGS["dry_run"] or req.dry_run
|
||||
shell_name = _pick_shell(req.shell)
|
||||
@@ -452,6 +456,7 @@ def health(_: None = Depends(_auth)):
|
||||
"allowed_region": SETTINGS["allowed_region"],
|
||||
"exec": {
|
||||
"enabled": SETTINGS["exec_enabled"],
|
||||
"secret_configured": bool(SETTINGS["exec_secret"]),
|
||||
"default_shell": SETTINGS["exec_default_shell"],
|
||||
"default_timeout_s": SETTINGS["exec_default_timeout_s"],
|
||||
"max_timeout_s": SETTINGS["exec_max_timeout_s"],
|
||||
@@ -575,7 +580,17 @@ def action(req: ActionRequest, _: None = Depends(_auth)):
|
||||
|
||||
|
||||
@app.post("/exec")
|
||||
def exec_command(req: ExecRequest, _: None = Depends(_auth)):
|
||||
def exec_command(
|
||||
req: ExecRequest,
|
||||
x_clickthrough_exec_secret: Optional[str] = Header(default=None),
|
||||
_: None = Depends(_auth),
|
||||
):
|
||||
expected = SETTINGS["exec_secret"]
|
||||
if not expected:
|
||||
raise HTTPException(status_code=403, detail="exec secret not configured")
|
||||
if not x_clickthrough_exec_secret or not hmac.compare_digest(x_clickthrough_exec_secret, expected):
|
||||
raise HTTPException(status_code=401, detail="invalid exec secret")
|
||||
|
||||
result = _exec_command(req)
|
||||
return {
|
||||
"ok": True,
|
||||
|
||||
Reference in New Issue
Block a user