fix: remove custom command from setAlarm to prevent command injection

This commit is contained in:
2026-06-18 15:23:14 +02:00
parent 75b56e2f1e
commit 124a6a4916
3 changed files with 21 additions and 7 deletions
+1 -1
View File
@@ -78,7 +78,6 @@ query {
``` ```
**Set an alarm:** **Set an alarm:**
*(Note: `command` is optional. If omitted, the API will automatically figure out the correct command to start `wecker.py`)*
```graphql ```graphql
mutation { mutation {
setAlarm( setAlarm(
@@ -91,6 +90,7 @@ mutation {
} }
} }
``` ```
*(Note: The `command` is managed automatically by the API and cannot be overridden, to prevent command injection into the system crontab.)*
**Delete an alarm:** **Delete an alarm:**
```graphql ```graphql
-2
View File
@@ -70,11 +70,9 @@ class Mutation:
def set_alarm( def set_alarm(
self, self,
cron_expression: str, cron_expression: str,
command: Optional[str] = None,
is_enabled: bool = True, is_enabled: bool = True,
id: Optional[str] = None, id: Optional[str] = None,
) -> Alarm: ) -> Alarm:
if command is None:
command = _default_command() command = _default_command()
manager = get_manager() manager = get_manager()
+19 -3
View File
@@ -121,6 +121,22 @@ def test_set_alarm_default_command_append():
client.post("/graphql", json={"query": mutation_delete}, headers=headers) client.post("/graphql", json={"query": mutation_delete}, headers=headers)
def test_set_alarm_rejects_custom_command():
"""Custom command argument must be rejected to prevent crontab injection."""
headers = {"X-API-Key": "test-secret"}
mutation = """
mutation {
setAlarm(cronExpression: "0 9 * * *", command: "rm -rf /") {
id
}
}
"""
res = client.post("/graphql", json={"query": mutation}, headers=headers)
assert res.status_code == 200
assert "errors" in res.json()
assert "command" in str(res.json()["errors"])
def test_graphql_workflow(): def test_graphql_workflow():
headers = {"X-API-Key": "test-secret"} headers = {"X-API-Key": "test-secret"}
@@ -139,7 +155,7 @@ def test_graphql_workflow():
# 2. Set alarm # 2. Set alarm
mutation_set = """ mutation_set = """
mutation { mutation {
setAlarm(cronExpression: "30 7 * * *", command: "python wecker.py", isEnabled: true) { setAlarm(cronExpression: "30 7 * * *", isEnabled: true) {
id id
cronExpression cronExpression
command command
@@ -151,7 +167,7 @@ def test_graphql_workflow():
assert res.status_code == 200 assert res.status_code == 200
alarm = res.json()["data"]["setAlarm"] alarm = res.json()["data"]["setAlarm"]
assert alarm["cronExpression"] == "30 7 * * *" assert alarm["cronExpression"] == "30 7 * * *"
assert alarm["command"] == "python wecker.py" assert "wecker.py" in alarm["command"]
assert alarm["isEnabled"] is True assert alarm["isEnabled"] is True
alarm_id = alarm["id"] alarm_id = alarm["id"]
@@ -176,7 +192,7 @@ def test_graphql_workflow():
# 5. Update alarm # 5. Update alarm
mutation_update = f""" mutation_update = f"""
mutation {{ mutation {{
setAlarm(id: "{alarm_id}", cronExpression: "0 8 * * *", command: "python wecker.py", isEnabled: false) {{ setAlarm(id: "{alarm_id}", cronExpression: "0 8 * * *", isEnabled: false) {{
id id
cronExpression cronExpression
isEnabled isEnabled