Files
truf-server/tests/test_high_only_round6.py
T
2026-09-30 20:30:56 +03:00

579 lines
28 KiB
Python

import contextlib
import builtins
from concurrent.futures import Future
from datetime import datetime, timedelta, timezone
import hashlib
import json
import os
from pathlib import Path
import sqlite3
import sys
import tempfile
import threading
import time
from types import SimpleNamespace
import unittest
import uuid
from unittest import mock
ROOT = Path(__file__).resolve().parents[1]
APP_DIR = ROOT / 'app'
sys.path.insert(0, str(APP_DIR))
import console_runner
import db_backend
from keycheckers import keycheck_common
import optimize_dashboard_db
import postgres_runtime
import runtime_security
import scanner
from scanner_db import ScannerDB
class ControlledExecutor:
def __init__(self):
self.submissions = []
def submit(self, function):
future = Future()
self.submissions.append((function.__name__, future))
return future
class LifecycleBackend:
def __init__(self):
self.closed = False
def probe(self):
raise AssertionError('controlled future should supply probe result')
def start(self):
raise AssertionError('controlled future should supply start result')
def stop(self):
raise AssertionError('controlled future should supply stop result')
def close(self):
self.closed = True
class EndpointAuthorityTests(unittest.TestCase):
def test_endpoint_identity_ignores_role_and_runtime_temp_roots(self):
first = {
'global': {
'runtime_dir': r'D:\copy-one\runtime',
'database_url': 'postgresql://role_one:secret@localhost:5544/shared',
},
}
second = {
'global': {
'runtime_dir': r'E:\copy-two\other-runtime',
'database_url': 'postgresql://role_two:different@127.0.0.1:5544/shared',
},
}
cleared = {
'TRUF_MANAGED_POSTGRES_DSN': '', 'SCANNER_DB_URL': '', 'DATABASE_URL': '',
'TRUF_POSTGRES_DB': '', 'TRUF_POSTGRES_USER': '', 'TRUF_POSTGRES_PORT': '',
}
with mock.patch.dict(os.environ, cleared):
first_dsn = first['global']['database_url']
second_dsn = second['global']['database_url']
identity_one = runtime_security.canonical_cluster_endpoint_identity(first, database_url=first_dsn)
identity_two = runtime_security.canonical_cluster_endpoint_identity(second, database_url=second_dsn)
path_one = runtime_security.cluster_endpoint_authority_lock_path(first, endpoint_dsn=first_dsn)
with mock.patch.dict(os.environ, {'TEMP': r'Z:\attacker-temp', 'TMP': r'Y:\other-temp'}):
path_two = runtime_security.cluster_endpoint_authority_lock_path(second, endpoint_dsn=second_dsn)
self.assertEqual(identity_one, identity_two)
self.assertEqual(path_one, path_two)
self.assertNotIn('user', json.loads(identity_one))
self.assertEqual(json.loads(identity_one)['schema'], 'public')
self.assertTrue(runtime_security.cluster_endpoint_mutex_name(endpoint_identity=identity_one).startswith('Global\\'))
def test_managed_dsn_precedence_is_shared_by_connections_and_locks(self):
managed = 'postgresql://managed:a@127.0.0.1:6001/effective'
conflicting = 'postgresql://other:b@127.0.0.1:6002/wrong'
config = {'global': {'runtime_dir': r'D:\runtime', 'database_url': conflicting}}
with mock.patch.dict(os.environ, {
'TRUF_MANAGED_POSTGRES_DSN': managed,
'SCANNER_DB_URL': conflicting,
'DATABASE_URL': conflicting,
}):
self.assertEqual(db_backend.database_url_from_env(), managed)
identity = json.loads(runtime_security.canonical_cluster_endpoint_identity(config, database_url=managed))
explicit = json.loads(runtime_security.canonical_cluster_endpoint_identity(
config, database_url='postgresql://maintenance:c@127.0.0.1:6003/explicit',
))
self.assertEqual((identity['host'], identity['port'], identity['database']), ('127.0.0.1', 6001, 'effective'))
self.assertEqual((explicit['port'], explicit['database']), (6003, 'explicit'))
class LateStartLifecycleTests(unittest.TestCase):
def _controller_with_start(self, timeout=0.5):
backend = LifecycleBackend()
executor = ControlledExecutor()
controller = postgres_runtime.PostgresController(
backend, executor=executor, shutdown_timeout_sec=timeout,
health_interval_sec=0.1,
)
controller.tick(0)
executor.submissions[0][1].set_result(
postgres_runtime.ProbeResult(postgres_runtime.ProbeKind.STOPPED, 'offline')
)
controller.tick(0)
self.assertEqual([name for name, _ in executor.submissions], ['probe', 'start'])
return controller, backend, executor
def test_close_keeps_unresolved_start_and_marks_authority_unsafe(self):
controller, backend, _ = self._controller_with_start(timeout=0.01)
self.assertFalse(controller.close(timeout_sec=0.01))
self.assertEqual(controller.state, postgres_runtime.PostgresState.STOP_FAILED)
self.assertIsNotNone(controller._future)
self.assertFalse(controller.authority_release_safe)
self.assertFalse(backend.closed)
def test_close_drains_late_acceptance_and_compensating_stop(self):
controller, backend, executor = self._controller_with_start(timeout=1)
def complete_operations():
time.sleep(0.02)
executor.submissions[1][1].set_result(postgres_runtime.StartResult(True, 'late accepted', uncertain=True))
deadline = time.monotonic() + 1
while len(executor.submissions) < 3 and time.monotonic() < deadline:
time.sleep(0.005)
executor.submissions[2][1].set_result(postgres_runtime.StopResult(True, True, 'compensated'))
worker = threading.Thread(target=complete_operations)
worker.start()
self.assertTrue(controller.close(timeout_sec=1))
worker.join(2)
self.assertEqual(controller.state, postgres_runtime.PostgresState.STOPPED)
self.assertTrue(backend.closed)
def test_owned_recovery_disappearance_enters_backoff_not_foreign(self):
class ImmediateExecutor:
def submit(self, function):
future = Future()
try:
future.set_result(function())
except BaseException as exc:
future.set_exception(exc)
return future
class Backend:
def __init__(self):
self.probes = iter([
postgres_runtime.ProbeResult(postgres_runtime.ProbeKind.STOPPED, 'offline'),
postgres_runtime.ProbeResult(postgres_runtime.ProbeKind.RECOVERING, 'owned recovery'),
postgres_runtime.ProbeResult(postgres_runtime.ProbeKind.STOPPED, 'briefly disappeared'),
])
def probe(self):
return next(self.probes)
def start(self):
return postgres_runtime.StartResult(True, 'accepted')
def stop(self):
return postgres_runtime.StopResult(True, True, 'stopped')
def close(self):
pass
controller = postgres_runtime.PostgresController(
Backend(), executor=ImmediateExecutor(), health_interval_sec=0.1,
stable_ready_interval_sec=1,
)
for now in (0, 0, 0, 0, 1, 1):
controller.tick(now)
self.assertEqual(controller.state, postgres_runtime.PostgresState.BACKOFF)
self.assertNotEqual(controller.state, postgres_runtime.PostgresState.FOREIGN_OR_CONFIG_ERROR)
def test_uncertain_owned_start_is_compensated_before_retry(self):
class ImmediateExecutor:
def submit(self, function):
future = Future()
future.set_result(function())
return future
class Backend:
def __init__(self):
self.probes = iter([
postgres_runtime.ProbeResult(postgres_runtime.ProbeKind.STOPPED, 'offline'),
postgres_runtime.ProbeResult(
postgres_runtime.ProbeKind.OWNED_START_UNCERTAIN, 'late side effect uncertain',
),
])
self.starts = 0
self.stops = 0
def probe(self):
return next(self.probes)
def start(self):
self.starts += 1
return postgres_runtime.StartResult(True, 'accepted', uncertain=True)
def stop(self):
self.stops += 1
return postgres_runtime.StopResult(True, True, 'offline confirmed')
def close(self):
pass
backend = Backend()
controller = postgres_runtime.PostgresController(
backend, executor=ImmediateExecutor(), health_interval_sec=0.1,
)
for now in (0, 0, 0, 0, 0):
controller.tick(now)
self.assertEqual(controller.state, postgres_runtime.PostgresState.BACKOFF)
self.assertEqual((backend.starts, backend.stops), (1, 1))
class OutboxRetentionTests(unittest.TestCase):
def test_delivered_payloads_are_compacted_and_rows_bounded(self):
with tempfile.TemporaryDirectory() as temp_dir, mock.patch.dict(os.environ, {
'SCANNER_DB_URL': '', 'DATABASE_URL': '', 'TRUF_MANAGED_POSTGRES_DSN': '',
'SCAN_OUTBOX_DELIVERED_MAX_ROWS': '3',
'SCAN_OUTBOX_DELIVERED_MAX_AGE_DAYS': '30',
}):
db = ScannerDB(db_path=os.path.join(temp_dir, 'scanner.db'))
try:
run_id = db.start_run('test', ['test'])
cycle_id = db.start_source_cycle(run_id, 'source', 'github', 'search', 'q', 1, 1, None, {}, {})
for index in range(8):
target_id = db.record_target_result(
run_id, cycle_id, 'source', 'q', f'target-{index}',
{'scan_event_id': str(uuid.uuid4()), 'target': f'target-{index}', 'findings': [], 'errors': []},
)
owner = f'owner-{index}'
now = datetime.now(timezone.utc).isoformat(timespec='seconds')
outbox_id = db.conn.insert_returning_id(
'''INSERT INTO scan_publication_outbox(
target_scan_id, payload_json, status, attempts, lease_owner,
created_at, updated_at
) VALUES (?, ?, 'delivering', 1, ?, ?, ?)''',
(target_id, json.dumps({'payload': 'x' * (512 * 1024)}), owner, now, now),
)
db.conn.commit()
self.assertTrue(db.finish_scan_publication(outbox_id, owner, True))
row = db.conn.execute(
'''SELECT COUNT(*) AS count, COALESCE(SUM(LENGTH(payload_json)), 0) AS payload_bytes
FROM scan_publication_outbox WHERE status = 'delivered' '''
).fetchone()
self.assertLessEqual(row['count'], 3)
self.assertEqual(row['payload_bytes'], 0)
finally:
db.close()
class DisabledProjectionTests(unittest.TestCase):
def test_postgres_queue_does_not_create_legacy_files_when_disabled(self):
class DB:
postgres_required = True
conn = SimpleNamespace(is_postgres=True)
def require_runtime_safety_schema(self):
return True
def known_target_normalizations_for(self, source, platform, targets):
return set()
def enqueue_targets(self, source, platform, query, targets, **kwargs):
return len(targets) + len(kwargs.get('unresolved_targets') or [])
def claim_targets(self, source, platform, limit, owner, lease_seconds, **kwargs):
return []
def target_queue_counts(self, source):
return {'pending': 1}
class Spool:
def reserve_claims(self, owner, count, lease_seconds):
return 'reservation'
def bind_claims(self, reservation, claims):
return None
with tempfile.TemporaryDirectory() as temp_dir:
args = SimpleNamespace(
save_dir=os.path.join(temp_dir, 'results'),
queue_dir=os.path.join(temp_dir, 'queues'),
platform='github', query='q', workers=1, target_claim_batch_size=1,
max_targets=0, timeout=60, target_retry_max_attempts=3,
sync_file_queues=False,
)
todo = os.path.join(args.queue_dir, 'todo_github.txt')
checked = os.path.join(args.queue_dir, 'checked_github.txt')
with mock.patch.object(console_runner, 'projection_file_lock') as projection_lock, \
mock.patch.object(console_runner, '_append_lines_unlocked') as append, \
mock.patch.object(console_runner, '_write_lines_unlocked') as rewrite:
console_runner.prepare_targets(
args, ['https://github.com/example/repo'], DB(), 1, 1, 'source', spool=Spool(),
)
projection_lock.assert_not_called()
append.assert_not_called()
rewrite.assert_not_called()
self.assertFalse(os.path.exists(todo))
self.assertFalse(os.path.exists(checked))
class JsonlPublicationTests(unittest.TestCase):
@classmethod
def setUpClass(cls):
scanner.initialize_scanner_runtime(preflight_complete=True, register_cleanup=False)
def private_dir(self, root):
scanner.ensure_private_directory(root, reject_reparse=True)
return root
def test_retry_uses_ledger_without_history_scan(self):
with tempfile.TemporaryDirectory() as temp_dir:
self.private_dir(temp_dir)
path = os.path.join(temp_dir, 'scan_results.jsonl')
with mock.patch.object(scanner.scan_config, 'jsonl_rotation_enabled', False):
for index in range(40):
self.assertTrue(scanner.append_rotating_jsonl_once(
path, {'scan_event_id': f'event-{index:016d}', 'value': index},
'scan_event_id', f'event-{index:016d}', 1,
))
with mock.patch.object(scanner, 'projection_segment_paths', side_effect=AssertionError('history scan')):
self.assertTrue(scanner.append_rotating_jsonl_once(
path, {'scan_event_id': 'event-final-00000001', 'value': 99},
'scan_event_id', 'event-final-00000001', 1,
))
self.assertTrue(scanner.append_rotating_jsonl_once(
path, {'scan_event_id': 'event-final-00000001', 'value': 99},
'scan_event_id', 'event-final-00000001', 1,
))
self.assertEqual(len(Path(path).read_text(encoding='utf-8').splitlines()), 41)
def test_torn_tail_is_bounded_quarantined_then_repaired(self):
with tempfile.TemporaryDirectory() as temp_dir:
self.private_dir(temp_dir)
path = os.path.join(temp_dir, 'found_secrets.jsonl')
first = {'finding_uid': 'finding-00000000000001', 'value': 'first'}
second = {'finding_uid': 'finding-00000000000002', 'value': 'second'}
with mock.patch.object(scanner.scan_config, 'jsonl_rotation_enabled', False), \
mock.patch.object(scanner.scan_config, 'jsonl_torn_quarantine_max_bytes', 16):
self.assertTrue(scanner.append_rotating_jsonl_once(path, first, 'finding_uid', first['finding_uid'], 1))
with open(path, 'ab') as handle:
handle.write(b'{"torn":"' + (b'x' * 100))
self.assertTrue(scanner.append_rotating_jsonl_once(path, second, 'finding_uid', second['finding_uid'], 1))
rows = [json.loads(line) for line in Path(path).read_text(encoding='utf-8').splitlines()]
self.assertEqual([row['finding_uid'] for row in rows], [first['finding_uid'], second['finding_uid']])
self.assertLessEqual(os.path.getsize(path + '.torn-tail.bin'), 16)
def test_manifest_failure_keeps_active_history_and_physical_orphan_visible(self):
with tempfile.TemporaryDirectory() as temp_dir:
self.private_dir(temp_dir)
path = os.path.join(temp_dir, 'scan_results.jsonl')
original = b'{"scan_event_id":"event-00000000000001"}\n'
Path(path).write_bytes(original)
scanner.harden_private_file(path)
with mock.patch.object(scanner, 'write_jsonl_manifest', side_effect=OSError('manifest failed')):
with self.assertRaisesRegex(OSError, 'manifest failed'):
scanner.rotate_jsonl_if_needed(path, 1)
self.assertEqual(Path(path).read_bytes(), original)
self.assertEqual(len(scanner.projection_segment_paths(path)), 2)
scanner.reconcile_jsonl_segments(path)
self.assertEqual(Path(path).read_bytes(), b'')
self.assertEqual(len(scanner.projection_segment_paths(path)), 2)
def test_crash_after_append_before_ledger_ack_is_idempotent(self):
with tempfile.TemporaryDirectory() as temp_dir:
self.private_dir(temp_dir)
path = os.path.join(temp_dir, 'scan_results.jsonl')
Path(path).write_bytes(b'')
scanner.harden_private_file(path)
payload = {'scan_event_id': 'event-crash-00000001', 'value': 'fixture'}
real_harden = scanner.harden_private_file
failed = {'value': False}
def fail_after_append(candidate):
if os.path.normcase(os.path.abspath(candidate)) == os.path.normcase(os.path.abspath(path)) and not failed['value']:
failed['value'] = True
raise OSError('crash after append')
return real_harden(candidate)
with mock.patch.object(scanner.scan_config, 'jsonl_rotation_enabled', False), \
mock.patch.object(scanner, 'harden_private_file', side_effect=fail_after_append):
self.assertFalse(scanner.append_rotating_jsonl_once(
path, payload, 'scan_event_id', payload['scan_event_id'], 1,
))
with mock.patch.object(scanner.scan_config, 'jsonl_rotation_enabled', False):
self.assertTrue(scanner.append_rotating_jsonl_once(
path, payload, 'scan_event_id', payload['scan_event_id'], 1,
))
self.assertEqual(len(Path(path).read_text(encoding='utf-8').splitlines()), 1)
def test_crash_after_prepared_state_before_append_retries_once(self):
with tempfile.TemporaryDirectory() as temp_dir:
self.private_dir(temp_dir)
path = os.path.join(temp_dir, 'scan_results.jsonl')
Path(path).write_bytes(b'')
scanner.harden_private_file(path)
payload = {'scan_event_id': 'event-prepared-000001', 'value': 'fixture'}
real_open = builtins.open
failed = {'value': False}
def fail_append(candidate, mode='r', *args, **kwargs):
if (
os.path.normcase(os.path.abspath(os.fspath(candidate))) == os.path.normcase(os.path.abspath(path))
and mode == 'ab'
and not failed['value']
):
failed['value'] = True
raise OSError('crash before append')
return real_open(candidate, mode, *args, **kwargs)
with mock.patch.object(scanner.scan_config, 'jsonl_rotation_enabled', False), \
mock.patch('builtins.open', side_effect=fail_append):
self.assertFalse(scanner.append_rotating_jsonl_once(
path, payload, 'scan_event_id', payload['scan_event_id'], 1,
))
ledger = sqlite3.connect(scanner.jsonl_ledger_path(path))
try:
self.assertEqual(
ledger.execute('SELECT state FROM publication_identity').fetchone()[0],
'prepared',
)
finally:
ledger.close()
with mock.patch.object(scanner.scan_config, 'jsonl_rotation_enabled', False):
self.assertTrue(scanner.append_rotating_jsonl_once(
path, payload, 'scan_event_id', payload['scan_event_id'], 1,
))
self.assertEqual(len(Path(path).read_text(encoding='utf-8').splitlines()), 1)
def test_keycheck_reader_discovers_orphans_and_fails_on_torn_segment(self):
with tempfile.TemporaryDirectory() as temp_dir:
self.private_dir(temp_dir)
output_dir = os.path.join(temp_dir, 'state')
scanner.ensure_private_directory(output_dir, reject_reparse=True)
current = os.path.join(temp_dir, 'found_secrets.jsonl')
segment = os.path.join(temp_dir, 'found_secrets.000001.jsonl')
Path(segment).write_text('{"finding_uid":"one"}\n', encoding='utf-8')
Path(current).write_text('{"finding_uid":"two"}\n', encoding='utf-8')
scanner.harden_private_file(segment)
scanner.harden_private_file(current)
with mock.patch.dict(os.environ, {
'KEYCHECK_OUTPUT_DIR': output_dir,
'KEYCHECK_STATE_DIR': output_dir,
'KEYCHECK_SERVICE': 'fixture',
'KEYCHECK_INPUT_TAIL_BYTES': '0',
}):
rows = list(keycheck_common.iter_jsonl_input(current))
self.assertEqual([row['data']['finding_uid'] for row in rows], ['one', 'two'])
torn = os.path.join(temp_dir, 'found_secrets.000002.jsonl')
Path(torn).write_bytes(b'{"finding_uid":"torn"}')
scanner.harden_private_file(torn)
with self.assertRaisesRegex(RuntimeError, 'torn'):
list(keycheck_common.iter_jsonl_input(current))
class BoundedCacheTests(unittest.TestCase):
def test_cached_occurrence_load_compacts_100k_rows_to_tiny_limits(self):
with tempfile.TemporaryDirectory() as temp_dir:
runtime_security.ensure_private_directory(temp_dir, reject_reparse=True)
path = os.path.join(temp_dir, 'cached_occurrences.tsv')
old = '2000-01-01T00:00:00+00:00'
recent = datetime.now(timezone.utc).isoformat(timespec='seconds')
with open(path, 'w', encoding='utf-8') as handle:
for index in range(99990):
handle.write(f'{index:064x}\t{old}\n')
for index in range(99990, 100000):
handle.write(f'{index:064x}\t{recent}\n')
keycheck_common.harden_private_file(path)
keycheck_common.CACHED_OCCURRENCE_CACHE.clear()
keycheck_common.CACHED_OCCURRENCE_ROWS.clear()
keycheck_common.CACHED_OCCURRENCE_SIGNATURES.clear()
with mock.patch.dict(os.environ, {
'KEYCHECK_OUTPUT_DIR': temp_dir,
'KEYCHECK_CACHED_OCCURRENCE_MAX_ITEMS': '5',
'KEYCHECK_CACHED_OCCURRENCE_MAX_BYTES': '512',
'KEYCHECK_CACHED_OCCURRENCE_TTL_SEC': '3600',
}):
seen = keycheck_common.cached_occurrence_set('fixture')
self.assertLessEqual(len(seen), 5)
self.assertLessEqual(os.path.getsize(path), 512)
def test_postman_pretty_expansion_and_context_amplification_fail_closed(self):
with tempfile.TemporaryDirectory() as temp_dir:
scanner.ensure_private_directory(temp_dir, reject_reparse=True)
cache_dir = os.path.join(temp_dir, 'cache')
scanner.ensure_private_directory(cache_dir, reject_reparse=True)
compact = ('[' + ','.join('"x"' for _ in range(240000)) + ']').encode('ascii')
with mock.patch.object(scanner.scan_config, 'runtime_dir', temp_dir):
path, _, _ = scanner.write_postman_cache(
compact, cache_dir=cache_dir, max_artifact_size_mb=1,
cache_max_items=10, cache_max_bytes=10 * 1024 * 1024,
cache_min_free_bytes=0,
)
self.assertEqual(Path(path).read_bytes(), compact)
context_path = os.path.join(temp_dir, 'context.json')
Path(context_path).write_text(json.dumps({'items': list(range(100))}), encoding='utf-8')
scanner.harden_private_file(context_path)
with mock.patch.object(scanner.scan_config, 'postman_context_max_nodes', 10):
with self.assertRaisesRegex(scanner.PostmanCacheValidationError, 'traversal'):
scanner.load_postman_context(context_path)
def test_dockerhub_cache_has_stable_keys_ttl_and_row_cap(self):
with tempfile.TemporaryDirectory() as temp_dir:
path = os.path.join(temp_dir, 'dockerhub.sqlite')
options = (
mock.patch.object(scanner.scan_config, 'dockerhub_tag_cache_path', path),
mock.patch.object(scanner.scan_config, 'dockerhub_tag_cache_max_rows', 3),
mock.patch.object(scanner.scan_config, 'dockerhub_tag_cache_max_age_sec', 60),
mock.patch.object(scanner.scan_config, 'dockerhub_tag_cache_max_bytes', 1024 * 1024),
mock.patch.object(scanner.scan_config, 'dockerhub_tag_cache_min_free_bytes', 0),
)
with contextlib.ExitStack() as stack:
for option in options:
stack.enter_context(option)
scanner._dockerhub_tag_cache_initialized.discard(path)
first_since = datetime.now(timezone.utc) - timedelta(hours=2)
later_since = first_since + timedelta(hours=1)
self.assertEqual(
scanner.dockerhub_cache_key('owner/repo', first_since, 1),
scanner.dockerhub_cache_key('owner/repo', later_since, 1),
)
for index in range(10):
scanner.put_dockerhub_tag_cache(
f'owner/repo-{index}', first_since, 1, 'ok',
[f'owner/repo-{index}:tag'], 3600,
tag_records=[{'name': 'tag', 'updated_at': first_since.timestamp() + 5400}],
)
conn = sqlite3.connect(path)
try:
self.assertLessEqual(conn.execute('SELECT COUNT(*) FROM dockerhub_tag_cache').fetchone()[0], 3)
conn.execute(
'UPDATE dockerhub_tag_cache SET checked_at = 0, expires_at = ?',
(time.time() + 3600,),
)
conn.commit()
finally:
conn.close()
self.assertIsNone(scanner.get_dockerhub_tag_cache('owner/repo-9', later_since, 1))
conn = sqlite3.connect(path)
try:
self.assertEqual(conn.execute('SELECT COUNT(*) FROM dockerhub_tag_cache').fetchone()[0], 0)
finally:
conn.close()
self.assertLessEqual(scanner.dockerhub_tag_cache_disk_bytes(path), 1024 * 1024)
class RetiredOptimizationCliTests(unittest.TestCase):
def test_direct_dashboard_ddl_cli_is_retired(self):
with self.assertRaisesRegex(SystemExit, 'retired'):
optimize_dashboard_db.main()
source = (APP_DIR / 'optimize_dashboard_db.py').read_text(encoding='utf-8')
self.assertNotIn('sqlite3', source)
self.assertNotIn('CREATE INDEX', source)
if __name__ == '__main__':
unittest.main()