import importlib.util import json import os import tempfile import unittest from pathlib import Path from unittest.mock import patch MODULE_PATH = Path(__file__).resolve().parents[1] / 'scripts' / 'siteforge_v817_audit.py' spec = importlib.util.spec_from_file_location('siteforge_audit', MODULE_PATH) a = importlib.util.module_from_spec(spec) import sys sys.modules[spec.name] = a spec.loader.exec_module(a) class DummyArgs: pass class AuditTests(unittest.TestCase): def setUp(self): self.r = a.Report(DummyArgs()) self.temp = tempfile.TemporaryDirectory() self.root = Path(self.temp.name) def tearDown(self): self.temp.cleanup() def statuses(self): return {c.code: c.status for c in self.r.checks} def test_loopback_url(self): self.assertTrue(a._local_host('http://127.0.0.1:8787')) self.assertTrue(a._local_host('http://[::1]:8787')) self.assertTrue(a._local_host('https://localhost')) def test_remote_is_not_loopback(self): for host in ('example.com', '192.168.1.1', '169.254.169.254', '10.0.0.3'): self.assertFalse(a._local_host('http://' + host)) def test_credentials_in_url_forbidden(self): self.assertFalse(a._local_host('http://admin:secret@localhost:8787')) def test_http_remote_refused_without_consent(self): with patch.object(a, '_probe', side_effect=AssertionError('should not send a request')): a.audit_http(self.r, 'https://example.com', False) self.assertEqual(self.statuses()['http.scope'], 'fail') def test_http_health_pass(self): with patch.object(a, '_probe', side_effect=[(200, '{"status":"ok"}', ''), (200, '{"status":"ok"}', ''), (200, 'OK', '')]): a.audit_http(self.r, 'http://127.0.0.1:8787', False) self.assertEqual(self.statuses()['http.ready'], 'pass') def test_http_not_ready_fails(self): with patch.object(a, '_probe', side_effect=[(200, '{"status":"ok"}', ''), (503, '', 'bad'), (200, 'OK', '')]): a.audit_http(self.r, 'http://127.0.0.1:8787', False) self.assertEqual(self.statuses()['http.ready'], 'fail') def test_http_unavailable_status_fails(self): with patch.object(a, '_probe', side_effect=[(200, '{"status":"ok"}', ''), (200, '{"status":"unavailable"}', ''), (200, 'OK', '')]): a.audit_http(self.r, 'http://127.0.0.1:8787', False) self.assertEqual(self.statuses()['http.ready'], 'fail') def test_route_with_path_traversal_rejected(self): self.assertIsNone(a.normalized_route('/../private')) self.assertIsNone(a.normalized_route('/%2e%2e/secret')) self.assertIsNone(a.normalized_route('/bad\\path')) self.assertIsNone(a.normalized_route('/a//b')) def test_route_query_disallowed(self): self.assertIsNone(a.normalized_route('/foo/?hello=1')) self.assertIsNone(a.normalized_route('https://example.com/')) self.assertEqual(a.normalized_route('/product/'), '/product/') def test_static_html_pass(self): (self.root / 'index.html').write_text('
Home') (self.root / 'sitemap.xml').write_text('ok') (self.root / 'robots.txt').write_text('ok') a.audit_build(self.r, self.root, None) self.assertEqual(self.statuses()['build.internal_links'], 'pass') self.assertEqual(self.statuses()['build.canonical_scheme'], 'pass') def test_broken_internal_link_fails(self): (self.root / 'index.html').write_text('Missing') a.audit_build(self.r, self.root, None) self.assertEqual(self.statuses()['build.internal_links'], 'fail') def test_duplicate_canonicals_fail(self): (self.root / 'index.html').write_text('') a.audit_build(self.r, self.root, None) self.assertEqual(self.statuses()['build.canonical_duplicate'], 'fail') def test_url_baseline_coverage(self): (self.root / 'index.html').write_text('') b = self.root / 'urls.txt' b.write_text('/\n/product/\n') a.audit_build(self.r, self.root, b) self.assertEqual(self.statuses()['build.url_baseline'], 'fail') (self.root / 'product').mkdir() (self.root / 'product' / 'index.html').write_text('') r2 = a.Report(DummyArgs()) a.audit_build(r2, self.root, b) self.assertEqual({x.code:x.status for x in r2.checks}['build.url_baseline'], 'pass') def test_invalid_baseline_route_fails(self): (self.root / 'index.html').write_text('') b = self.root / 'urls.txt' b.write_text('/\n/../secret\n') a.audit_build(self.r, self.root, b) self.assertEqual(self.statuses()['build.url_baseline'], 'fail') def test_html_reports_escape_untrusted_text(self): self.r.add('test', 'http', 'warn', '', '