mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-10-26 00:28:42 +00:00
Build and push containers / metadata (push) Canceled after 0s
Build and push containers / build-push-containers (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/amd64 (alpine) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm64 (alpine) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/amd64 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm/v7 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm/v8 (main) (push) Canceled after 0s
ChangeDetection.io Container Build Test / Build linux/arm64 (main) (push) Canceled after 0s
ChangeDetection.io App Test / lint-code (push) Canceled after 0s
ChangeDetection.io App Test / lint-translations (push) Canceled after 0s
ChangeDetection.io App Test / lint-template-i18n (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-11 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-12 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-13 (push) Canceled after 0s
ChangeDetection.io App Test / test-application-3-14 (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Build distribution 📦 (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Test the built package works basically. (push) Canceled after 0s
Publish Python 🐍distribution 📦 to PyPI and TestPyPI / Publish Python 🐍 distribution 📦 to PyPI (push) Canceled after 0s
* API - Reject broken Jinja2 in url, link_to_open, body and headers, shared validation with the edit form
The edit form validated Jinja2 templates on save but the API did not, so a broken body or
header template saved through the API only failed at fetch time, on every check.
- New jinja2_custom/validate.py: validate_jinja2_fields() renders each value that matches
JINJA2_MARKER_PATTERN and returns {field: translated error}
- The edit form uses it instead of four copies of the same try/except
- API create and update return 400 naming the field
Translations: messages moved to the new file (msgids unchanged); also translated the header
error for fr/it and fixed the cs/es wording.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* rebuild
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
76 lines
3.0 KiB
Python
76 lines
3.0 KiB
Python
"""
|
|
The API rejects broken Jinja2 in url, link_to_open, body and headers, the same as the edit form.
|
|
|
|
Before, a broken template saved through the API was only found at fetch time and the watch then
|
|
failed on every check.
|
|
"""
|
|
|
|
import json
|
|
|
|
from flask import url_for
|
|
|
|
from .util import delete_all_watches
|
|
|
|
|
|
def _headers(live_server):
|
|
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
|
|
return {'x-api-key': api_key, 'content-type': 'application/json'}
|
|
|
|
|
|
def test_api_create_rejects_broken_jinja2(client, live_server, measure_memory_usage, datastore_path):
|
|
test_url = url_for('test_endpoint', _external=True)
|
|
headers = _headers(live_server)
|
|
|
|
res = client.post(url_for("createwatch"), headers=headers,
|
|
data=json.dumps({"url": test_url, "method": "POST", "body": "{{ unclosed"}))
|
|
assert res.status_code == 400
|
|
assert b"body: Invalid template syntax" in res.data
|
|
|
|
res = client.post(url_for("createwatch"), headers=headers,
|
|
data=json.dumps({"url": test_url, "headers": {"x-bad": "{% endfor %}"}}))
|
|
assert res.status_code == 400
|
|
assert '"x-bad" header' in res.get_json()
|
|
|
|
res = client.post(url_for("createwatch"), headers=headers,
|
|
data=json.dumps({"url": test_url + "?q={{ broken("}))
|
|
assert res.status_code == 400
|
|
assert b"url: Invalid template syntax" in res.data
|
|
|
|
assert len(live_server.app.config['DATASTORE'].data['watching']) == 0
|
|
|
|
# Valid templates and text that only looks like Jinja2 are accepted
|
|
res = client.post(url_for("createwatch"), headers=headers,
|
|
data=json.dumps({"url": test_url, "method": "POST",
|
|
"body": 'q={%22key%22:1}',
|
|
"headers": {"x-ok": "{{ 2*2 }}"}}))
|
|
assert res.status_code == 201, res.data
|
|
|
|
delete_all_watches(client)
|
|
|
|
|
|
def test_api_update_rejects_broken_jinja2(client, live_server, measure_memory_usage, datastore_path):
|
|
test_url = url_for('test_endpoint', _external=True)
|
|
headers = _headers(live_server)
|
|
uuid = live_server.app.config['DATASTORE'].add_watch(url=test_url)
|
|
|
|
res = client.put(url_for("watch", uuid=uuid), headers=headers,
|
|
data=json.dumps({"method": "POST", "body": "{{ unclosed"}))
|
|
assert res.status_code == 400
|
|
assert b"body: Invalid template syntax" in res.data
|
|
|
|
res = client.put(url_for("watch", uuid=uuid), headers=headers,
|
|
data=json.dumps({"link_to_open": "https://example.com/{% if %}"}))
|
|
assert res.status_code == 400
|
|
assert b"link_to_open: Invalid template syntax" in res.data
|
|
|
|
watch = live_server.app.config['DATASTORE'].data['watching'][uuid]
|
|
assert not watch.get('body')
|
|
assert not watch.get('link_to_open')
|
|
|
|
res = client.put(url_for("watch", uuid=uuid), headers=headers,
|
|
data=json.dumps({"method": "POST", "body": 'q={%22key%22:1}'}))
|
|
assert res.status_code == 200, res.data
|
|
assert watch.get('body') == 'q={%22key%22:1}'
|
|
|
|
delete_all_watches(client)
|