fix: remove cross-branch security test classes from radio-reliability PR

This commit is contained in:
Stacy Olivas authored and agessaman committed 2026-04-14 10:01:51 -07:00
1 parent fd0875611d
commit b56fa83fe3
1 file changed
-160
-160
View File
@@ -2920,166 +2920,6 @@ class TestDbPathResolutionFromConfigDir:
)
# ===========================================================================
# Security: Restore endpoint path traversal prevention (GAP W1)
# ===========================================================================
class TestRestoreEndpointSecurity:
"""POST /api/maintenance/restore must reject path traversal attacks.
Covers GAP W1: validate_safe_path() added before shutil.copy2().
Dangerous system directories and traversal patterns must return 400.
"""
def test_etc_passwd_path_rejected(self, client):
"""/etc/passwd supplied as db_file must be blocked."""
resp = client.post(
"/api/maintenance/restore",
json={"db_file": "/etc/passwd"},
content_type="application/json",
)
assert resp.status_code == 400
data = resp.get_json()
assert "error" in data
def test_etc_shadow_path_rejected(self, client):
"""/etc/shadow must be blocked (credential file)."""
resp = client.post(
"/api/maintenance/restore",
json={"db_file": "/etc/shadow"},
content_type="application/json",
)
assert resp.status_code == 400
def test_proc_self_environ_rejected(self, client):
"""/proc/self/environ must be blocked (process secrets)."""
resp = client.post(
"/api/maintenance/restore",
json={"db_file": "/proc/self/environ"},
content_type="application/json",
)
assert resp.status_code == 400
def test_empty_db_file_rejected(self, client):
"""Empty db_file must return 400."""
resp = client.post(
"/api/maintenance/restore",
json={"db_file": ""},
content_type="application/json",
)
assert resp.status_code == 400
def test_missing_db_file_key_rejected(self, client):
"""Missing db_file key must return 400."""
resp = client.post(
"/api/maintenance/restore",
json={},
content_type="application/json",
)
assert resp.status_code == 400
def test_validate_safe_path_called_for_restore(self, client):
"""validate_safe_path is invoked — not bypassed — in the restore handler."""
with patch("modules.web_viewer.app.validate_safe_path", return_value=None) as mock_vsp:
resp = client.post(
"/api/maintenance/restore",
json={"db_file": "/tmp/test.db"},
content_type="application/json",
)
mock_vsp.assert_called_once()
assert resp.status_code == 400 # None returned → path rejected
# ===========================================================================
# Security: Feed preview/test SSRF prevention (GAP W2)
# ===========================================================================
class TestFeedPreviewSecurity:
"""POST /api/feeds/preview and /api/feeds/test must reject SSRF-able URLs.
Covers GAP W2: validate_external_url() added before any outbound fetch.
Private IPs, loopback, and file:// schemes must return 400.
"""
def test_metadata_endpoint_blocked_in_preview(self, client):
"""169.254.169.254 (cloud metadata) must be blocked in feed preview."""
resp = client.post(
"/api/feeds/preview",
json={"feed_url": "http://169.254.169.254/latest/meta-data/", "feed_type": "rss"},
content_type="application/json",
)
assert resp.status_code == 400
data = resp.get_json()
assert "error" in data
def test_loopback_blocked_in_preview(self, client):
"""127.0.0.1 loopback must be blocked in feed preview."""
resp = client.post(
"/api/feeds/preview",
json={"feed_url": "http://127.0.0.1/internal", "feed_type": "rss"},
content_type="application/json",
)
assert resp.status_code == 400
def test_file_scheme_blocked_in_preview(self, client):
"""file:// scheme must be blocked in feed preview."""
resp = client.post(
"/api/feeds/preview",
json={"feed_url": "file:///etc/passwd", "feed_type": "rss"},
content_type="application/json",
)
assert resp.status_code == 400
def test_private_network_blocked_in_preview(self, client):
"""10.x.x.x (private RFC1918) must be blocked in feed preview."""
resp = client.post(
"/api/feeds/preview",
json={"feed_url": "http://10.0.0.1/feed.xml", "feed_type": "rss"},
content_type="application/json",
)
assert resp.status_code == 400
def test_missing_feed_url_rejected(self, client):
"""Missing feed_url key must return 400."""
resp = client.post(
"/api/feeds/preview",
json={"feed_type": "rss"},
content_type="application/json",
)
assert resp.status_code == 400
def test_metadata_endpoint_blocked_in_test_route(self, client):
"""169.254.169.254 must be blocked in /api/feeds/test as well."""
resp = client.post(
"/api/feeds/test",
json={"url": "http://169.254.169.254/metadata"},
content_type="application/json",
)
assert resp.status_code == 400
def test_loopback_blocked_in_test_route(self, client):
"""127.0.0.1 must be blocked in /api/feeds/test."""
resp = client.post(
"/api/feeds/test",
json={"url": "http://127.0.0.1/internal"},
content_type="application/json",
)
assert resp.status_code == 400
def test_validate_external_url_called_for_preview(self, client):
"""validate_external_url is invoked — not bypassed — in the preview handler."""
with patch("modules.web_viewer.app.validate_external_url", return_value=False) as mock_veu:
resp = client.post(
"/api/feeds/preview",
json={"feed_url": "http://192.168.1.1/feed.rss", "feed_type": "rss"},
content_type="application/json",
)
mock_veu.assert_called()
assert resp.status_code == 400
class TestRadioDebugConfig:
"""Tests for GET/POST /api/config/radio-debug endpoints."""