mirror of
https://github.com/dgtlmoon/changedetection.io.git
synced 2026-09-27 07:46:22 +00:00
WIP
This commit is contained in:
@@ -188,6 +188,19 @@ class Watch(Resource):
|
||||
for field in fields_to_ignore:
|
||||
json_data.pop(field, None)
|
||||
|
||||
# Validate remaining fields - reject truly unknown fields
|
||||
# Get valid fields from WatchBase schema
|
||||
from . import get_watch_schema_properties
|
||||
valid_fields = set(get_watch_schema_properties().keys())
|
||||
|
||||
# Also allow last_viewed (explicitly defined in UpdateWatch schema)
|
||||
valid_fields.add('last_viewed')
|
||||
|
||||
# Check for unknown fields
|
||||
unknown_fields = set(json_data.keys()) - valid_fields
|
||||
if unknown_fields:
|
||||
return f"Unknown field(s): {', '.join(sorted(unknown_fields))}", 400
|
||||
|
||||
# Update watch with regular (non-processor-config) fields
|
||||
watch.update(json_data)
|
||||
watch.commit()
|
||||
|
||||
@@ -26,6 +26,7 @@ class watch_base(dict):
|
||||
- Configuration override chain resolution (Watch → Tag → Global)
|
||||
- Immutability options
|
||||
- Better testing
|
||||
- USE https://docs.pydantic.dev/latest/integrations/datamodel_code_generator TO BUILD THE MODEL FROM THE API-SPEC!!!
|
||||
|
||||
CHAIN RESOLUTION ARCHITECTURE:
|
||||
The dream is a 3-level override hierarchy:
|
||||
|
||||
@@ -529,12 +529,12 @@ def test_api_watch_PUT_update(client, live_server, measure_memory_usage, datasto
|
||||
)
|
||||
|
||||
assert res.status_code == 400, "Should get error 400 when we give a field that doesnt exist"
|
||||
# OpenAPI validation message changed when we switched from flask-expects-json to OpenAPI validation
|
||||
# Using unevaluatedProperties instead of additionalProperties changes the message
|
||||
assert (b'Additional properties are not allowed' in res.data or
|
||||
# Backend validation now rejects unknown fields with a clear error message
|
||||
assert (b'Unknown field' in res.data or
|
||||
b'Additional properties are not allowed' in res.data or
|
||||
b'Unevaluated properties are not allowed' in res.data or
|
||||
b'does not match any of the regexes' in res.data), \
|
||||
"Should reject unknown fields with schema validation error"
|
||||
"Should reject unknown fields with validation error"
|
||||
|
||||
|
||||
# Try a XSS URL
|
||||
|
||||
@@ -176,4 +176,59 @@ def test_api_tags_listing(client, live_server, measure_memory_usage, datastore_p
|
||||
assert res.status_code == 204
|
||||
|
||||
|
||||
def test_roundtrip_API(client, live_server, measure_memory_usage, datastore_path):
|
||||
"""
|
||||
Test the full round trip, this way we test the default Model fits back into OpenAPI spec
|
||||
:param client:
|
||||
:param live_server:
|
||||
:param measure_memory_usage:
|
||||
:param datastore_path:
|
||||
:return:
|
||||
"""
|
||||
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
|
||||
|
||||
set_original_response(datastore_path=datastore_path)
|
||||
|
||||
res = client.post(
|
||||
url_for("tag"),
|
||||
data=json.dumps({"title": "My tag title"}),
|
||||
headers={'content-type': 'application/json', 'x-api-key': api_key}
|
||||
)
|
||||
assert res.status_code == 201
|
||||
|
||||
uuid = res.json.get('uuid')
|
||||
|
||||
# Now fetch it and send it back
|
||||
|
||||
res = client.get(
|
||||
url_for("tag", uuid=uuid),
|
||||
headers={'x-api-key': api_key}
|
||||
)
|
||||
|
||||
tag = res.json
|
||||
|
||||
tag['last_changed'] = 454444444444
|
||||
tag['date_created'] = 454444444444
|
||||
|
||||
# HTTP PUT ( UPDATE an existing watch )
|
||||
res = client.put(
|
||||
url_for("tag", uuid=uuid),
|
||||
headers={'x-api-key': api_key, 'content-type': 'application/json'},
|
||||
data=json.dumps(tag),
|
||||
)
|
||||
if res.status_code != 200:
|
||||
print(f"\n=== PUT failed with {res.status_code} ===")
|
||||
print(f"Error: {res.data}")
|
||||
assert res.status_code == 200, "HTTP PUT update was sent OK"
|
||||
|
||||
res = client.get(
|
||||
url_for("watch", uuid=uuid),
|
||||
headers={'x-api-key': api_key}
|
||||
)
|
||||
last_changed = res.json.get('last_changed')
|
||||
assert last_changed != 454444444444
|
||||
assert last_changed != "454444444444"
|
||||
|
||||
date_created = res.json.get('date_created')
|
||||
assert date_created != 454444444444
|
||||
assert date_created != "454444444444"
|
||||
|
||||
@@ -178,6 +178,9 @@ components:
|
||||
type: [string, 'null']
|
||||
description: Proxy configuration
|
||||
maxLength: 5000
|
||||
ignore_status_codes:
|
||||
type: [boolean, 'null']
|
||||
description: Ignore HTTP status code errors (boolean or null)
|
||||
webdriver_delay:
|
||||
type: [integer, 'null']
|
||||
description: Delay in seconds for webdriver
|
||||
|
||||
Reference in New Issue
Block a user