1032 lines
46 KiB
Python
1032 lines
46 KiB
Python
import copy
|
|
import itertools
|
|
import os
|
|
from pathlib import Path
|
|
import re
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from unittest import mock
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
APP_DIR = ROOT / 'app'
|
|
sys.path.insert(0, str(APP_DIR))
|
|
|
|
import docker_depth_experiment as depth
|
|
import scanner_db
|
|
from scanner_db import ScanEventConflictError, ScannerDB
|
|
|
|
|
|
QUERIES = tuple(f'cohort-query-{index:02d}' for index in range(61))
|
|
CONFIG_SHA256 = 'a' * 64
|
|
POLICY_SHA256 = 'b' * 64
|
|
PLAN_SHA256 = 'c' * 64
|
|
HOLD_SHA256 = 'd' * 64
|
|
|
|
|
|
def experiment_config(enabled=False):
|
|
config = {
|
|
'global': {
|
|
'database_url': 'postgresql://example.invalid/truf',
|
|
'sync_file_queues': False,
|
|
},
|
|
'sources': {'dockerhub': {
|
|
'mode': 'search',
|
|
'require_digest': True,
|
|
'queries': list(QUERIES),
|
|
'docker_platform_candidate_tags': 20,
|
|
'docker_images_per_repository': 3,
|
|
'docker_depth_experiment': {
|
|
'experiment_key': 'cohort-hold-test-v1',
|
|
'enabled': enabled,
|
|
'queries': list(QUERIES),
|
|
'repositories_per_query': 10,
|
|
'shallow_images_per_repository': 1,
|
|
'deep_repositories_per_query': 1,
|
|
'deep_images_per_repository': 10,
|
|
'target_limit': 1200,
|
|
'selector_version': depth.DOCKER_DEPTH_SELECTOR_VERSION,
|
|
},
|
|
}},
|
|
}
|
|
return depth.validate_docker_depth_config(config).experiment
|
|
|
|
|
|
def breadth_experiment_config(enabled=False):
|
|
config = {
|
|
'global': {
|
|
'database_url': 'postgresql://example.invalid/truf',
|
|
'sync_file_queues': False,
|
|
},
|
|
'sources': {'dockerhub': {
|
|
'mode': 'search',
|
|
'require_digest': True,
|
|
'queries': list(QUERIES),
|
|
'docker_platform_candidate_tags': 20,
|
|
'docker_images_per_repository': 3,
|
|
'docker_depth_experiment': {
|
|
'experiment_key': 'rank1-breadth-test-v1',
|
|
'enabled': enabled,
|
|
'queries': list(QUERIES),
|
|
'repositories_per_query': 39,
|
|
'shallow_images_per_repository': 1,
|
|
'deep_repositories_per_query': 1,
|
|
'deep_images_per_repository': 1,
|
|
'target_limit': 2000,
|
|
'selector_version': depth.DOCKER_RANK1_BREADTH_SELECTOR_VERSION,
|
|
},
|
|
}},
|
|
}
|
|
return depth.validate_docker_depth_config(config).experiment
|
|
|
|
|
|
def cohort_candidates(reverse=False):
|
|
candidates = {}
|
|
for query_ordinal, query in enumerate(QUERIES):
|
|
rows = [
|
|
{
|
|
'repository_queue_id': query_ordinal * 100 + index + 1,
|
|
'eligibility_page_id': query_ordinal * 100 + index + 10001,
|
|
'best_search_rank': index + 1,
|
|
'valid_distinct_graph_count': 20 if index == 6 else index % 3,
|
|
}
|
|
for index in range(12)
|
|
]
|
|
candidates[query] = list(reversed(rows)) if reverse else rows
|
|
return dict(reversed(list(candidates.items()))) if reverse else candidates
|
|
|
|
|
|
class SQLitePostgresShape:
|
|
"""Execute PostgreSQL locking shapes against SQLite for focused unit tests."""
|
|
|
|
is_postgres = True
|
|
is_sqlite = False
|
|
|
|
def __init__(self, connection):
|
|
self.connection = connection
|
|
|
|
def execute(self, sql, params=None):
|
|
sql = re.sub(
|
|
r'\s+FOR UPDATE(?:\s+OF\s+[a-z0-9_,.\s]+)?\s*$',
|
|
'', str(sql).strip(), flags=re.IGNORECASE,
|
|
)
|
|
return self.connection.execute(sql, params)
|
|
|
|
def commit(self):
|
|
return self.connection.commit()
|
|
|
|
def rollback(self):
|
|
return self.connection.rollback()
|
|
|
|
def __getattr__(self, name):
|
|
return getattr(self.connection, name)
|
|
|
|
|
|
class DockerDepthCohortUnitTests(unittest.TestCase):
|
|
def test_plan_is_deterministic_ranked_and_round_robin(self):
|
|
experiment = experiment_config()
|
|
first = depth.build_docker_depth_cohort_plan(
|
|
experiment, POLICY_SHA256, cohort_candidates(),
|
|
)
|
|
second = depth.build_docker_depth_cohort_plan(
|
|
experiment, POLICY_SHA256, cohort_candidates(reverse=True),
|
|
)
|
|
|
|
self.assertEqual(first, second)
|
|
self.assertEqual(
|
|
depth.canonical_docker_depth_plan_hash(first),
|
|
depth.canonical_docker_depth_plan_hash(second),
|
|
)
|
|
first_manifest = depth.build_docker_depth_cohort_manifest(
|
|
experiment, POLICY_SHA256, cohort_candidates(),
|
|
)
|
|
second_manifest = depth.build_docker_depth_cohort_manifest(
|
|
experiment, POLICY_SHA256, cohort_candidates(reverse=True),
|
|
)
|
|
self.assertEqual(first_manifest, second_manifest)
|
|
self.assertEqual(
|
|
depth.validate_docker_depth_cohort_manifest(
|
|
first_manifest, experiment, POLICY_SHA256,
|
|
)[1],
|
|
depth.validate_docker_depth_cohort_manifest(
|
|
second_manifest, experiment, POLICY_SHA256,
|
|
)[1],
|
|
)
|
|
self.assertEqual(len(first['queries']), 61)
|
|
self.assertEqual(len(first['repository_round_robin']), 610)
|
|
for query_plan in first['queries']:
|
|
self.assertEqual(
|
|
[row['repository_rank'] for row in query_plan['repositories']],
|
|
list(range(1, 11)),
|
|
)
|
|
self.assertEqual(
|
|
[row['repository_rank'] for row in query_plan['repositories']
|
|
if row['is_deep_probe']],
|
|
[7],
|
|
)
|
|
self.assertEqual(
|
|
[(row['query_ordinal'], row['repository_rank'])
|
|
for row in first['repository_round_robin'][:61]],
|
|
[(ordinal, 1) for ordinal in range(61)],
|
|
)
|
|
self.assertEqual(
|
|
[(row['query_ordinal'], row['repository_rank'])
|
|
for row in first['repository_round_robin'][61:122]],
|
|
[(ordinal, 2) for ordinal in range(61)],
|
|
)
|
|
|
|
def test_plan_preserves_honest_per_query_scarcity(self):
|
|
candidates = cohort_candidates()
|
|
candidates[QUERIES[17]] = candidates[QUERIES[17]][:9]
|
|
candidates[QUERIES[33]] = []
|
|
plan = depth.build_docker_depth_cohort_plan(
|
|
experiment_config(), POLICY_SHA256, candidates,
|
|
)
|
|
|
|
self.assertEqual(plan['queries'][17]['selected_repository_count'], 9)
|
|
self.assertEqual(plan['queries'][33]['selected_repository_count'], 0)
|
|
self.assertEqual(len(plan['queries'][17]['repositories']), 9)
|
|
self.assertEqual(plan['queries'][33]['repositories'], [])
|
|
self.assertEqual(
|
|
sum(row['is_deep_probe'] for row in plan['queries'][17]['repositories']),
|
|
1,
|
|
)
|
|
self.assertFalse(any(
|
|
row['query_ordinal'] == 33 for row in plan['repository_round_robin']
|
|
))
|
|
self.assertEqual(len(plan['repository_round_robin']), 599)
|
|
manifest = depth.build_docker_depth_cohort_manifest(
|
|
experiment_config(), POLICY_SHA256, candidates,
|
|
)
|
|
self.assertEqual(manifest['repository_count'], 599)
|
|
depth.validate_docker_depth_cohort_manifest(
|
|
manifest, experiment_config(), POLICY_SHA256,
|
|
)
|
|
|
|
def test_rank1_breadth_plan_is_exact_balanced_and_physically_unique(self):
|
|
candidates = {}
|
|
shared_queue_id = 9000000
|
|
for ordinal, query in enumerate(QUERIES):
|
|
if ordinal < 9:
|
|
candidates[query] = []
|
|
continue
|
|
candidates[query] = [{
|
|
'repository_queue_id': shared_queue_id,
|
|
'eligibility_page_id': ordinal * 1000 + 1,
|
|
'best_search_rank': 1,
|
|
'valid_distinct_graph_count': 1,
|
|
}] + [{
|
|
'repository_queue_id': ordinal * 1000 + rank + 100,
|
|
'eligibility_page_id': ordinal * 1000 + rank + 500,
|
|
'best_search_rank': rank + 1,
|
|
'valid_distinct_graph_count': rank % 5,
|
|
} for rank in range(1, 51)]
|
|
|
|
experiment = breadth_experiment_config()
|
|
plan = depth.build_docker_depth_cohort_plan(
|
|
experiment, POLICY_SHA256, candidates,
|
|
)
|
|
selected = [
|
|
row['repository_queue_id']
|
|
for query in plan['queries'] for row in query['repositories']
|
|
]
|
|
counts = [query['selected_repository_count'] for query in plan['queries']]
|
|
|
|
self.assertEqual(len(selected), 2000)
|
|
self.assertEqual(len(set(selected)), 2000)
|
|
self.assertEqual(counts[:9], [0] * 9)
|
|
self.assertEqual(counts[9:33], [39] * 24)
|
|
self.assertEqual(counts[33:], [38] * 28)
|
|
self.assertEqual(len(plan['repository_round_robin']), 2000)
|
|
manifest = depth.build_docker_depth_cohort_manifest(
|
|
experiment, POLICY_SHA256, candidates,
|
|
)
|
|
depth.validate_docker_depth_cohort_manifest(
|
|
manifest, experiment, POLICY_SHA256,
|
|
)
|
|
|
|
def test_review_manifest_binds_provenance_even_when_membership_is_unchanged(self):
|
|
experiment = experiment_config()
|
|
candidates = cohort_candidates()
|
|
first = depth.build_docker_depth_cohort_manifest(
|
|
experiment, POLICY_SHA256, candidates,
|
|
)
|
|
changed = copy.deepcopy(candidates)
|
|
changed[QUERIES[0]][6]['valid_distinct_graph_count'] += 1
|
|
second = depth.build_docker_depth_cohort_manifest(
|
|
experiment, POLICY_SHA256, changed,
|
|
)
|
|
|
|
self.assertEqual(first['type'], depth.DOCKER_DEPTH_COHORT_MANIFEST_TYPE)
|
|
self.assertEqual(first['version'], 2)
|
|
self.assertEqual(first['plan'], second['plan'])
|
|
self.assertNotEqual(
|
|
first['provenance_snapshot_sha256'],
|
|
second['provenance_snapshot_sha256'],
|
|
)
|
|
self.assertNotEqual(depth._canonical_sha256(first), depth._canonical_sha256(second))
|
|
|
|
def test_reviewed_hold_manifest_is_canonical_and_tamper_evident(self):
|
|
experiment = experiment_config()
|
|
entries = [{
|
|
'queue_id': 11,
|
|
'source': 'dockerhub',
|
|
'platform': 'docker',
|
|
'query': QUERIES[0],
|
|
'prior_status': 'deferred',
|
|
'prior_updated_at': '2026-09-10T00:00:00+00:00',
|
|
}]
|
|
conflicts = [{
|
|
'queue_id': 12,
|
|
'source': 'dockerhub',
|
|
'platform': 'docker',
|
|
'query': QUERIES[0],
|
|
'status': 'cold',
|
|
'prior_updated_at': '2026-09-10T00:00:00+00:00',
|
|
'reason': 'independently_cold',
|
|
}]
|
|
manifest = {
|
|
'schema': 1,
|
|
'type': depth.DOCKER_DEPTH_HOLD_MANIFEST_TYPE,
|
|
'experiment_id': 7,
|
|
'experiment_key': experiment.experiment_key,
|
|
'source': 'dockerhub',
|
|
'config_sha256': experiment.config_hash,
|
|
'ordered_queries_sha256': experiment.ordered_query_hash,
|
|
'selector_sha256': experiment.selector_hash,
|
|
'provenance_policy_sha256': POLICY_SHA256,
|
|
'plan_sha256': PLAN_SHA256,
|
|
'reason_code': depth.DOCKER_DEPTH_HOLD_REASON,
|
|
'entry_count': 1,
|
|
'conflict_count': 1,
|
|
'selection_sha256': depth._canonical_sha256(entries),
|
|
'conflicts_sha256': depth._canonical_sha256(conflicts),
|
|
'entries': entries,
|
|
'conflicts': conflicts,
|
|
}
|
|
normalized, manifest_sha256 = depth.validate_docker_depth_hold_manifest(
|
|
manifest, experiment, POLICY_SHA256,
|
|
)
|
|
self.assertEqual(normalized, manifest)
|
|
self.assertEqual(manifest_sha256, depth._canonical_sha256(manifest))
|
|
|
|
tampered = copy.deepcopy(manifest)
|
|
tampered['entries'][0]['queue_id'] = 13
|
|
with self.assertRaisesRegex(ValueError, 'evidence conflicts'):
|
|
depth.validate_docker_depth_hold_manifest(
|
|
tampered, experiment, POLICY_SHA256,
|
|
)
|
|
|
|
def test_review_manifest_bound_and_chunks_cover_more_than_one_hundred_thousand(self):
|
|
configured_bound = (
|
|
depth.DOCKER_DEPTH_QUERY_COUNT
|
|
* depth.DOCKERHUB_DISCOVERY_MAX_PAGES
|
|
* depth.DOCKERHUB_DISCOVERY_MAX_PER_PAGE
|
|
)
|
|
self.assertEqual(configured_bound, 183000)
|
|
self.assertLess(configured_bound, depth.DOCKER_DEPTH_REVIEW_MANIFEST_MAX_ROWS)
|
|
chunks = list(ScannerDB._target_queue_policy_chunks(range(configured_bound)))
|
|
self.assertEqual(sum(map(len, chunks)), configured_bound)
|
|
self.assertEqual(
|
|
list(itertools.chain.from_iterable(chunks)), list(range(configured_bound)),
|
|
)
|
|
entries = [{
|
|
'queue_id': index + 1,
|
|
'source': 'dockerhub',
|
|
'platform': 'docker',
|
|
'query': QUERIES[index % len(QUERIES)],
|
|
'prior_status': 'deferred',
|
|
'prior_updated_at': '2026-09-10T00:00:00+00:00',
|
|
} for index in range(100001)]
|
|
normalized = depth._normalize_hold_entries(
|
|
entries, depth.DOCKER_DEPTH_REVIEW_MANIFEST_MAX_ROWS,
|
|
)
|
|
self.assertEqual((len(normalized), normalized[-1]['queue_id']), (100001, 100001))
|
|
|
|
|
|
class DockerDepthSQLiteShapeTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.environment = mock.patch.dict(
|
|
os.environ, {'SCANNER_DB_URL': '', 'DATABASE_URL': ''},
|
|
)
|
|
self.environment.start()
|
|
self.temp = tempfile.TemporaryDirectory()
|
|
self.db = ScannerDB(db_path=os.path.join(self.temp.name, 'scanner.db'))
|
|
|
|
def tearDown(self):
|
|
self.db.close()
|
|
self.temp.cleanup()
|
|
self.environment.stop()
|
|
|
|
def postgres_shape(self):
|
|
self.db.conn = SQLitePostgresShape(self.db.conn)
|
|
|
|
def insert_experiment(
|
|
self, key='cohort-hold-test-v1', state='holding',
|
|
plan_sha256=PLAN_SHA256, hold_sha256=HOLD_SHA256,
|
|
):
|
|
experiment = experiment_config()
|
|
now = scanner_db.utc_now_iso()
|
|
row = self.db.conn.execute(
|
|
'''INSERT INTO docker_depth_experiments(
|
|
experiment_key, source, state, config_sha256,
|
|
ordered_queries_sha256, selector_version, selector_sha256,
|
|
provenance_policy_sha256, query_count, repositories_per_query,
|
|
images_per_repository, target_limit, plan_sha256,
|
|
hold_manifest_sha256, created_at, updated_at
|
|
) VALUES (?, 'dockerhub', ?, ?, ?, ?, ?, ?, 61, 10, 10, 1200,
|
|
?, ?, ?, ?) RETURNING id''',
|
|
(
|
|
key, state, experiment.config_hash, experiment.ordered_query_hash,
|
|
experiment.selector_version, experiment.selector_hash,
|
|
POLICY_SHA256, plan_sha256, hold_sha256, now, now,
|
|
),
|
|
).fetchone()
|
|
self.db.conn.commit()
|
|
return int(row['id'])
|
|
|
|
def insert_queue(self, target, query=QUERIES[0], status='deferred'):
|
|
now = scanner_db.utc_now_iso()
|
|
row = self.db.conn.execute(
|
|
'''INSERT INTO target_queue(
|
|
source, platform, query, target, normalized_target, status,
|
|
resolver_state, created_at, updated_at
|
|
) VALUES ('dockerhub', 'docker', ?, ?, ?, ?, 'pending', ?, ?)
|
|
RETURNING id, updated_at''',
|
|
(query, target, target, status, now, now),
|
|
).fetchone()
|
|
self.db.conn.commit()
|
|
return dict(row)
|
|
|
|
def test_mutating_planner_requires_reviewed_manifest(self):
|
|
with self.assertRaisesRegex(RuntimeError, 'reviewed cohort manifest'):
|
|
depth.plan_docker_depth_experiment(
|
|
self.db, experiment_config(), POLICY_SHA256,
|
|
)
|
|
count = self.db.conn.execute(
|
|
'SELECT COUNT(*) FROM docker_depth_experiments'
|
|
).fetchone()[0]
|
|
self.assertEqual(count, 0)
|
|
|
|
def test_cohort_generation_is_read_only_when_coverage_is_incomplete(self):
|
|
self.postgres_shape()
|
|
for _ in range(2):
|
|
with self.assertRaisesRegex(RuntimeError, 'complete fresh deep discovery pass'):
|
|
depth.generate_docker_depth_cohort_manifest(
|
|
self.db, experiment_config(), POLICY_SHA256,
|
|
)
|
|
counts = self.db.conn.execute(
|
|
'''SELECT
|
|
(SELECT COUNT(*) FROM docker_depth_experiments) AS experiments,
|
|
(SELECT COUNT(*) FROM docker_depth_experiment_queries) AS queries,
|
|
(SELECT COUNT(*) FROM docker_depth_experiment_repositories) AS repositories''',
|
|
).fetchone()
|
|
self.assertEqual(tuple(counts), (0, 0, 0))
|
|
|
|
def test_cold_and_reactivation_require_exact_experiment_owner(self):
|
|
experiment_id = self.insert_experiment()
|
|
other_experiment_id = self.insert_experiment(key='other-experiment-v1')
|
|
queue = self.insert_queue('owner/experiment-owned')
|
|
self.postgres_shape()
|
|
cold_entry = {
|
|
'queue_id': queue['id'],
|
|
'source': 'dockerhub',
|
|
'platform': 'docker',
|
|
'query': QUERIES[0],
|
|
'prior_status': 'deferred',
|
|
'prior_updated_at': queue['updated_at'],
|
|
}
|
|
applied = self.db.cold_target_queue_rows(
|
|
[cold_entry], reason_code=depth.DOCKER_DEPTH_HOLD_REASON,
|
|
config_sha256=experiment_config().config_hash,
|
|
policy_sha256=POLICY_SHA256, manifest_sha256=HOLD_SHA256,
|
|
experiment_id=experiment_id,
|
|
)
|
|
self.assertEqual(applied['transitioned'], 1)
|
|
cold_event = self.db.conn.execute(
|
|
'''SELECT event.id, event.experiment_id, queue.updated_at
|
|
FROM target_queue_policy_events event
|
|
JOIN target_queue queue ON queue.id = event.queue_id
|
|
WHERE event.queue_id = ?''',
|
|
(queue['id'],),
|
|
).fetchone()
|
|
reactivation = {
|
|
'queue_id': queue['id'],
|
|
'source': 'dockerhub',
|
|
'platform': 'docker',
|
|
'query': QUERIES[0],
|
|
'cold_event_id': int(cold_event['id']),
|
|
'restore_status': 'deferred',
|
|
'prior_updated_at': str(cold_event['updated_at']),
|
|
}
|
|
for wrong_owner in (None, other_experiment_id):
|
|
with self.subTest(wrong_owner=wrong_owner), self.assertRaises(
|
|
ScanEventConflictError,
|
|
):
|
|
self.db.reactivate_cold_target_queue_rows(
|
|
[reactivation], reason_code=depth.DOCKER_DEPTH_RELEASE_REASON,
|
|
config_sha256=experiment_config().config_hash,
|
|
policy_sha256=POLICY_SHA256, manifest_sha256='e' * 64,
|
|
experiment_id=wrong_owner,
|
|
)
|
|
restored = self.db.reactivate_cold_target_queue_rows(
|
|
[reactivation], reason_code=depth.DOCKER_DEPTH_RELEASE_REASON,
|
|
config_sha256=experiment_config().config_hash,
|
|
policy_sha256=POLICY_SHA256, manifest_sha256='e' * 64,
|
|
experiment_id=experiment_id,
|
|
)
|
|
self.assertEqual(restored['transitioned'], 1)
|
|
row = self.db.conn.execute(
|
|
'SELECT status FROM target_queue WHERE id = ?', (queue['id'],),
|
|
).fetchone()
|
|
owners = self.db.conn.execute(
|
|
'''SELECT action, experiment_id FROM target_queue_policy_events
|
|
WHERE queue_id = ? ORDER BY id''',
|
|
(queue['id'],),
|
|
).fetchall()
|
|
self.assertEqual(row['status'], 'deferred')
|
|
self.assertEqual(
|
|
[(item['action'], item['experiment_id']) for item in owners],
|
|
[('cold', experiment_id), ('reactivate', experiment_id)],
|
|
)
|
|
|
|
def test_reviewed_hold_preserves_legacy_query_outside_pinned_set(self):
|
|
experiment_id = self.insert_experiment()
|
|
queue = self.insert_queue(
|
|
'owner/legacy-unconfigured', query='legacy-unconfigured-query',
|
|
)
|
|
self.postgres_shape()
|
|
self.db.cold_target_queue_rows(
|
|
[{
|
|
'queue_id': queue['id'],
|
|
'source': 'dockerhub',
|
|
'platform': 'docker',
|
|
'query': 'legacy-unconfigured-query',
|
|
'prior_status': 'deferred',
|
|
'prior_updated_at': queue['updated_at'],
|
|
}],
|
|
reason_code=depth.DOCKER_DEPTH_HOLD_REASON,
|
|
config_sha256=experiment_config().config_hash,
|
|
policy_sha256=POLICY_SHA256,
|
|
manifest_sha256=HOLD_SHA256,
|
|
experiment_id=experiment_id,
|
|
)
|
|
experiment = self.db.conn.execute(
|
|
'SELECT * FROM docker_depth_experiments WHERE id = ?',
|
|
(experiment_id,),
|
|
).fetchone()
|
|
authority = depth.docker_depth_resolver_authority(
|
|
experiment_config(True), POLICY_SHA256,
|
|
)
|
|
|
|
self.assertIsNone(
|
|
self.db._docker_depth_hold_event_drift_reason_locked(
|
|
experiment, authority,
|
|
)
|
|
)
|
|
|
|
def test_new_noncohort_admission_is_held_in_the_page_transaction(self):
|
|
experiment_id = self.insert_experiment()
|
|
now = scanner_db.utc_now_iso()
|
|
self.db.conn.execute(
|
|
'''INSERT INTO docker_depth_experiment_queries(
|
|
experiment_id, source, query_ordinal, query, query_sha256,
|
|
required_repository_count, selected_repository_count, created_at
|
|
) VALUES (?, 'dockerhub', 0, ?, ?, 10, 10, ?)''',
|
|
(experiment_id, QUERIES[0], depth._canonical_sha256(QUERIES[0]), now),
|
|
)
|
|
self.db.conn.commit()
|
|
self.postgres_shape()
|
|
self.db.conn.execute(
|
|
'''INSERT OR REPLACE INTO runtime_final_cutover(
|
|
id, marker, checked_at, evidence_sha256
|
|
) VALUES (1, ?, ?, ?)''',
|
|
(scanner_db.FINAL_CUTOVER_MARKER, now, 'e' * 64),
|
|
)
|
|
self.db.conn.commit()
|
|
authority = depth.docker_depth_resolver_authority(
|
|
experiment_config(True), POLICY_SHA256,
|
|
)
|
|
observation = {
|
|
'cycle_id': None,
|
|
'query_ordinal': 0,
|
|
'query_count': 61,
|
|
'page_number': 1,
|
|
'page_limit': 30,
|
|
'per_page': 100,
|
|
'total_count': 200,
|
|
'policy_sha256': POLICY_SHA256,
|
|
'pass_kind': 'deep',
|
|
'collection_generation': depth.DOCKER_DEPTH_COLLECTION_GENERATION,
|
|
'ordered_query_hash': experiment_config().ordered_query_hash,
|
|
'query_complete': False,
|
|
}
|
|
with mock.patch.object(
|
|
self.db, '_docker_depth_persisted_drift_reason_locked',
|
|
return_value=None,
|
|
):
|
|
result = self.db.persist_dockerhub_discovery_page(
|
|
'dockerhub', QUERIES[0], ['owner/dynamic-hold'],
|
|
observation=observation, experiment_authority=authority,
|
|
final_cutover=True,
|
|
)
|
|
self.assertEqual(result['dynamic_hold_count'], 1)
|
|
held = self.db.conn.execute(
|
|
'''SELECT queue.status, event.reason_code, event.experiment_id
|
|
FROM target_queue queue
|
|
JOIN target_queue_policy_events event ON event.queue_id = queue.id
|
|
WHERE queue.normalized_target = 'owner/dynamic-hold' ''',
|
|
).fetchone()
|
|
self.assertEqual(tuple(held), (
|
|
'cold', depth.DOCKER_DEPTH_DYNAMIC_HOLD_REASON, experiment_id,
|
|
))
|
|
|
|
with mock.patch.object(
|
|
depth, 'DOCKER_DEPTH_REVIEW_MANIFEST_MAX_ROWS', 1,
|
|
), mock.patch.object(
|
|
self.db, '_docker_depth_persisted_drift_reason_locked',
|
|
return_value=None,
|
|
), self.assertRaisesRegex(
|
|
ScanEventConflictError, 'dynamic hold capacity is exhausted',
|
|
):
|
|
self.db.persist_dockerhub_discovery_page(
|
|
'dockerhub', QUERIES[0], ['owner/dynamic-hold-overflow'],
|
|
observation=dict(observation, page_number=2, total_count=300),
|
|
experiment_authority=authority, final_cutover=True,
|
|
)
|
|
overflow = self.db.conn.execute(
|
|
"SELECT 1 FROM target_queue WHERE normalized_target = 'owner/dynamic-hold-overflow'"
|
|
).fetchone()
|
|
self.assertIsNone(overflow)
|
|
|
|
drifted_authority = dict(authority, config_sha256='f' * 64)
|
|
with mock.patch.object(
|
|
self.db, '_docker_depth_persisted_drift_reason_locked',
|
|
return_value=None,
|
|
), self.assertRaisesRegex(ScanEventConflictError, 'config_hash_drift'):
|
|
self.db.persist_dockerhub_discovery_page(
|
|
'dockerhub', QUERIES[0], ['owner/must-roll-back'],
|
|
observation=dict(observation, page_number=2, total_count=300),
|
|
experiment_authority=drifted_authority, final_cutover=True,
|
|
)
|
|
absent = self.db.conn.execute(
|
|
"SELECT 1 FROM target_queue WHERE normalized_target = 'owner/must-roll-back'"
|
|
).fetchone()
|
|
self.assertIsNone(absent)
|
|
held = self.db.conn.execute(
|
|
'''SELECT state, hold_reason_code FROM docker_depth_experiments
|
|
WHERE id = ?''',
|
|
(experiment_id,),
|
|
).fetchone()
|
|
self.assertEqual(tuple(held), ('held', 'config_hash_drift'))
|
|
|
|
def test_malformed_page_authority_rejects_without_holding_experiment(self):
|
|
experiment_id = self.insert_experiment(state='resolving')
|
|
self.postgres_shape()
|
|
authority = depth.docker_depth_resolver_authority(
|
|
experiment_config(True), POLICY_SHA256,
|
|
)
|
|
malformed = dict(authority, selector_sha256='0' * 64)
|
|
observation = {
|
|
'cycle_id': None,
|
|
'query_ordinal': 0,
|
|
'query_count': 61,
|
|
'page_number': 1,
|
|
'page_limit': 30,
|
|
'per_page': 100,
|
|
'total_count': 0,
|
|
'policy_sha256': POLICY_SHA256,
|
|
'pass_kind': 'deep',
|
|
'collection_generation': depth.DOCKER_DEPTH_COLLECTION_GENERATION,
|
|
'ordered_query_hash': experiment_config().ordered_query_hash,
|
|
'query_complete': True,
|
|
}
|
|
|
|
with self.assertRaisesRegex(
|
|
ScanEventConflictError, 'authority_payload_invalid',
|
|
):
|
|
self.db.persist_dockerhub_discovery_page(
|
|
'dockerhub', QUERIES[0], [], observation=observation,
|
|
experiment_authority=malformed, final_cutover=True,
|
|
)
|
|
|
|
experiment = self.db.conn.execute(
|
|
'''SELECT state, hold_reason_code FROM docker_depth_experiments
|
|
WHERE id = ?''',
|
|
(experiment_id,),
|
|
).fetchone()
|
|
self.assertEqual(tuple(experiment), ('resolving', None))
|
|
|
|
def test_unique_target_capacity_locks_deduplicates_and_counts_once(self):
|
|
experiment_id = self.insert_experiment(
|
|
state='resolving', hold_sha256=HOLD_SHA256,
|
|
)
|
|
target = self.insert_queue(
|
|
'owner/image@sha256:' + ('1' * 64), status='pending',
|
|
)
|
|
now = scanner_db.utc_now_iso()
|
|
manifest = self.db.conn.execute(
|
|
'''INSERT INTO docker_image_manifests(
|
|
target_queue_id, source, repository, manifest_digest,
|
|
manifest_media_type, graph_sha256, layer_count,
|
|
resolved_at, created_at
|
|
) VALUES (?, 'dockerhub', 'owner/image', ?,
|
|
'application/vnd.oci.image.manifest.v1+json', ?, 1, ?, ?)
|
|
RETURNING id''',
|
|
(target['id'], 'sha256:' + ('2' * 64), '3' * 64, now, now),
|
|
).fetchone()
|
|
self.db.conn.commit()
|
|
self.postgres_shape()
|
|
first = self.db.reserve_docker_depth_experiment_target_capacity_locked(
|
|
experiment_id, target['id'], manifest['id'], 1, 1, now,
|
|
)
|
|
second = self.db.reserve_docker_depth_experiment_target_capacity_locked(
|
|
experiment_id, target['id'], manifest['id'], 1, 1, now,
|
|
)
|
|
self.db.conn.commit()
|
|
self.assertTrue(first['inserted'])
|
|
self.assertFalse(second['inserted'])
|
|
experiment = self.db.conn.execute(
|
|
'SELECT target_count FROM docker_depth_experiments WHERE id = ?',
|
|
(experiment_id,),
|
|
).fetchone()
|
|
physical = self.db.conn.execute(
|
|
'''SELECT COUNT(*) AS count FROM docker_depth_experiment_targets
|
|
WHERE experiment_id = ?''',
|
|
(experiment_id,),
|
|
).fetchone()
|
|
self.assertEqual((experiment['target_count'], physical['count']), (1, 1))
|
|
|
|
def test_reviewed_release_rejects_every_noncompleted_phase(self):
|
|
experiment_id = self.insert_experiment(state='holding')
|
|
self.postgres_shape()
|
|
for state in ('holding', 'resolving', 'active', 'draining', 'held'):
|
|
self.db.conn.execute(
|
|
'UPDATE docker_depth_experiments SET state = ? WHERE id = ?',
|
|
(state, experiment_id),
|
|
)
|
|
self.db.conn.commit()
|
|
with self.subTest(state=state), self.assertRaisesRegex(
|
|
RuntimeError, 'requires a completed experiment',
|
|
):
|
|
depth.generate_docker_depth_reactivation_manifest(
|
|
self.db, experiment_config(), POLICY_SHA256,
|
|
)
|
|
|
|
|
|
class DockerDepthPlannerSQLiteShapeTests(unittest.TestCase):
|
|
def test_complete_pass_sparse_cohort_persists_once_and_replays_immutable_hash(self):
|
|
with mock.patch.dict(os.environ, {'SCANNER_DB_URL': '', 'DATABASE_URL': ''}):
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
db = ScannerDB(db_path=os.path.join(directory, 'scanner.db'))
|
|
try:
|
|
now = scanner_db.utc_now_iso()
|
|
discovery_pass = db.conn.execute(
|
|
'''INSERT INTO docker_discovery_passes(
|
|
pass_token, source, pass_kind, policy_sha256,
|
|
ordered_queries_sha256, expected_query_count,
|
|
completed_query_count, state, started_at, completed_at,
|
|
created_at, updated_at
|
|
) VALUES (?, 'dockerhub', 'deep', ?, ?, 61, 61,
|
|
'complete', ?, ?, ?, ?) RETURNING id''',
|
|
(
|
|
'planner-pass-token-0001', POLICY_SHA256,
|
|
experiment_config().ordered_query_hash,
|
|
now, now, now, now,
|
|
),
|
|
).fetchone()
|
|
for query_ordinal, query in enumerate(QUERIES):
|
|
repository_count = 9 if query_ordinal == 0 else (
|
|
0 if query_ordinal == 1 else 10
|
|
)
|
|
page = db.conn.execute(
|
|
'''INSERT INTO docker_discovery_pages(
|
|
pass_id, query, query_ordinal, page_number,
|
|
result_count, admitted_count, query_complete,
|
|
admission_kind, page_sha256, observed_at, created_at
|
|
) VALUES (?, ?, ?, 1, ?, ?, 1, 'main', ?, ?, ?)
|
|
RETURNING id''',
|
|
(
|
|
discovery_pass['id'], query, query_ordinal,
|
|
repository_count, repository_count,
|
|
f'{query_ordinal + 1:064x}', now, now,
|
|
),
|
|
).fetchone()
|
|
for rank in range(1, repository_count + 1):
|
|
repository = f'owner/q{query_ordinal:02d}-repo-{rank:02d}'
|
|
queue = db.conn.execute(
|
|
'''INSERT INTO target_queue(
|
|
source, platform, query, target, normalized_target,
|
|
status, resolver_state, created_at, updated_at
|
|
) VALUES ('dockerhub', 'docker', ?, ?, ?, 'deferred',
|
|
'pending', ?, ?) RETURNING id''',
|
|
(query, repository, repository, now, now),
|
|
).fetchone()
|
|
db.conn.execute(
|
|
'''INSERT INTO docker_repository_query_provenance(
|
|
source, query, repository_queue_id, provenance_kind,
|
|
first_observed_at, last_observed_at,
|
|
first_search_rank, best_search_rank, last_search_rank,
|
|
first_page_id, last_page_id, first_policy_sha256,
|
|
last_policy_sha256, observation_count,
|
|
fresh_observation_count,
|
|
fresh_complete_observation_count,
|
|
fresh_coverage_eligible, created_at, updated_at
|
|
) VALUES ('dockerhub', ?, ?, 'fresh_page', ?, ?, ?, ?, ?,
|
|
?, ?, ?, ?, 1, 1, 1, 1, ?, ?)''',
|
|
(
|
|
query, queue['id'], now, now, rank, rank, rank,
|
|
page['id'], page['id'], POLICY_SHA256, POLICY_SHA256,
|
|
now, now,
|
|
),
|
|
)
|
|
db.conn.execute(
|
|
'''INSERT INTO docker_repository_query_observations(
|
|
page_id, repository_queue_id, source, query,
|
|
search_rank, observed_at
|
|
) VALUES (?, ?, 'dockerhub', ?, ?, ?)''',
|
|
(page['id'], queue['id'], query, rank, now),
|
|
)
|
|
db.conn.commit()
|
|
db.conn = SQLitePostgresShape(db.conn)
|
|
|
|
cohort_manifest, cohort_manifest_sha256 = (
|
|
depth.generate_docker_depth_cohort_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
)
|
|
)
|
|
with self.assertRaisesRegex(ValueError, 'hash conflicts'):
|
|
depth.apply_docker_depth_cohort_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
cohort_manifest, 'f' * 64,
|
|
)
|
|
stale_queue_id = (
|
|
cohort_manifest['plan']['queries'][0]['repositories'][0][
|
|
'repository_queue_id'
|
|
]
|
|
)
|
|
db.conn.execute(
|
|
"UPDATE target_queue SET status = 'cold' WHERE id = ?",
|
|
(stale_queue_id,),
|
|
)
|
|
db.conn.commit()
|
|
with self.assertRaisesRegex(RuntimeError, 'selection drifted after review'):
|
|
depth.apply_docker_depth_cohort_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
cohort_manifest, cohort_manifest_sha256,
|
|
)
|
|
self.assertEqual(db.conn.execute(
|
|
'SELECT COUNT(*) FROM docker_depth_experiments'
|
|
).fetchone()[0], 0)
|
|
db.conn.execute(
|
|
"UPDATE target_queue SET status = 'deferred' WHERE id = ?",
|
|
(stale_queue_id,),
|
|
)
|
|
db.conn.commit()
|
|
first = depth.apply_docker_depth_cohort_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
cohort_manifest, cohort_manifest_sha256,
|
|
)
|
|
replay = depth.apply_docker_depth_cohort_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
cohort_manifest, cohort_manifest_sha256,
|
|
)
|
|
self.assertTrue(first['planned'])
|
|
self.assertFalse(replay['planned'])
|
|
self.assertEqual(first['plan_sha256'], replay['plan_sha256'])
|
|
self.assertEqual(first['plan'], replay['plan'])
|
|
self.assertEqual(
|
|
[(row['query_ordinal'], row['repository_rank']) for row in
|
|
first['plan']['repository_round_robin']
|
|
if row['repository_rank'] == 1],
|
|
[(ordinal, 1) for ordinal in range(61) if ordinal != 1],
|
|
)
|
|
counts = db.conn.execute(
|
|
'''SELECT
|
|
(SELECT COUNT(*) FROM docker_depth_experiment_queries) AS queries,
|
|
(SELECT COUNT(*) FROM docker_depth_experiment_repositories) AS repositories,
|
|
(SELECT COUNT(*) FROM docker_depth_experiments) AS experiments''',
|
|
).fetchone()
|
|
self.assertEqual(tuple(counts), (61, 599, 1))
|
|
selected_counts = db.conn.execute(
|
|
'''SELECT query_ordinal, required_repository_count,
|
|
selected_repository_count
|
|
FROM docker_depth_experiment_queries
|
|
WHERE query_ordinal IN (0, 1)
|
|
ORDER BY query_ordinal'''
|
|
).fetchall()
|
|
self.assertEqual(
|
|
[tuple(row) for row in selected_counts],
|
|
[(0, 10, 9), (1, 10, 0)],
|
|
)
|
|
|
|
hold_target = 'owner/reviewed-noncohort'
|
|
independent_target = 'owner/independently-cold'
|
|
held_queue = db.conn.execute(
|
|
'''INSERT INTO target_queue(
|
|
source, platform, query, target, normalized_target,
|
|
status, resolver_state, created_at, updated_at
|
|
) VALUES ('dockerhub', 'docker', ?, ?, ?, 'deferred',
|
|
'pending', ?, ?) RETURNING id''',
|
|
(QUERIES[0], hold_target, hold_target, now, now),
|
|
).fetchone()
|
|
independent_queue = db.conn.execute(
|
|
'''INSERT INTO target_queue(
|
|
source, platform, query, target, normalized_target,
|
|
status, resolver_state, created_at, updated_at
|
|
) VALUES ('dockerhub', 'docker', ?, ?, ?, 'cold',
|
|
'pending', ?, ?) RETURNING id''',
|
|
(QUERIES[0], independent_target, independent_target, now, now),
|
|
).fetchone()
|
|
db.conn.commit()
|
|
hold_manifest, hold_manifest_sha256 = (
|
|
depth.generate_docker_depth_hold_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
)
|
|
)
|
|
self.assertEqual(
|
|
[entry['queue_id'] for entry in hold_manifest['entries']],
|
|
[held_queue['id']],
|
|
)
|
|
self.assertEqual(
|
|
[(item['queue_id'], item['reason'])
|
|
for item in hold_manifest['conflicts']],
|
|
[(independent_queue['id'], 'independently_cold')],
|
|
)
|
|
applied_hold = depth.apply_docker_depth_hold_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
hold_manifest, hold_manifest_sha256,
|
|
)
|
|
replayed_hold = depth.apply_docker_depth_hold_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
hold_manifest, hold_manifest_sha256,
|
|
)
|
|
self.assertEqual(
|
|
(applied_hold['transitioned'], replayed_hold['duplicates']),
|
|
(1, 1),
|
|
)
|
|
experiment = db.conn.execute(
|
|
'SELECT * FROM docker_depth_experiments WHERE id = ?',
|
|
(first['experiment_id'],),
|
|
).fetchone()
|
|
members = db.conn.execute(
|
|
'''SELECT * FROM docker_depth_experiment_repositories
|
|
WHERE experiment_id = ? ORDER BY id''',
|
|
(first['experiment_id'],),
|
|
).fetchall()
|
|
for member in members:
|
|
repository_queue_id = int(
|
|
member['replacement_repository_queue_id']
|
|
or member['repository_queue_id']
|
|
)
|
|
db._record_docker_depth_candidate_skip_locked(
|
|
experiment, member, repository_queue_id, 'repository',
|
|
int(member['replacement_count']) + 1,
|
|
{'repository_queue_id': repository_queue_id},
|
|
depth.DOCKER_DEPTH_REPOSITORY_SKIP_REASON, now,
|
|
)
|
|
db.conn.execute(
|
|
'''UPDATE docker_depth_experiment_repositories
|
|
SET work_state = 'skipped', is_deep_probe = 0,
|
|
selected_image_count = 0, last_error_code = ?,
|
|
resolved_at = ?, updated_at = ?
|
|
WHERE experiment_id = ?''',
|
|
(
|
|
depth.DOCKER_DEPTH_REPOSITORY_SKIP_REASON,
|
|
now, now, first['experiment_id'],
|
|
),
|
|
)
|
|
db.conn.execute(
|
|
"UPDATE docker_depth_experiments SET state = 'completed' "
|
|
'WHERE id = ?',
|
|
(first['experiment_id'],),
|
|
)
|
|
db.conn.commit()
|
|
release_manifest, release_manifest_sha256 = (
|
|
depth.generate_docker_depth_reactivation_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
)
|
|
)
|
|
db.conn.execute(
|
|
"UPDATE docker_depth_experiments SET state = 'active' "
|
|
'WHERE id = ?',
|
|
(first['experiment_id'],),
|
|
)
|
|
db.conn.commit()
|
|
with self.assertRaisesRegex(
|
|
RuntimeError, 'requires a completed experiment',
|
|
):
|
|
depth.apply_docker_depth_reactivation_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
release_manifest, release_manifest_sha256,
|
|
)
|
|
self.assertEqual(db.conn.execute(
|
|
'SELECT state FROM docker_depth_experiments WHERE id = ?',
|
|
(first['experiment_id'],),
|
|
).fetchone()['state'], 'active')
|
|
self.assertEqual(db.conn.execute(
|
|
'SELECT status FROM target_queue WHERE id = ?',
|
|
(held_queue['id'],),
|
|
).fetchone()['status'], 'cold')
|
|
db.conn.execute(
|
|
"UPDATE docker_depth_experiments SET state = 'completed' "
|
|
'WHERE id = ?',
|
|
(first['experiment_id'],),
|
|
)
|
|
db.conn.commit()
|
|
released = depth.apply_docker_depth_reactivation_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
release_manifest, release_manifest_sha256,
|
|
)
|
|
replayed_release = depth.apply_docker_depth_reactivation_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
release_manifest, release_manifest_sha256,
|
|
)
|
|
self.assertEqual(
|
|
(released['transitioned'], replayed_release['duplicates']),
|
|
(1, 1),
|
|
)
|
|
final_rows = db.conn.execute(
|
|
'''SELECT normalized_target, status FROM target_queue
|
|
WHERE id IN (?, ?) ORDER BY id''',
|
|
(held_queue['id'], independent_queue['id']),
|
|
).fetchall()
|
|
final_experiment = db.conn.execute(
|
|
'''SELECT state FROM docker_depth_experiments
|
|
WHERE id = ?''',
|
|
(first['experiment_id'],),
|
|
).fetchone()
|
|
owned_events = db.conn.execute(
|
|
'''SELECT action, experiment_id FROM target_queue_policy_events
|
|
WHERE queue_id = ? ORDER BY id''',
|
|
(held_queue['id'],),
|
|
).fetchall()
|
|
self.assertEqual(
|
|
[(row['normalized_target'], row['status']) for row in final_rows],
|
|
[(hold_target, 'deferred'), (independent_target, 'cold')],
|
|
)
|
|
self.assertEqual(final_experiment['state'], 'released')
|
|
self.assertEqual(
|
|
[(row['action'], row['experiment_id']) for row in owned_events],
|
|
[('cold', first['experiment_id']),
|
|
('reactivate', first['experiment_id'])],
|
|
)
|
|
db.conn.execute(
|
|
'''DELETE FROM target_queue_policy_events
|
|
WHERE queue_id = ? AND action = 'reactivate' ''',
|
|
(held_queue['id'],),
|
|
)
|
|
db.conn.commit()
|
|
with self.assertRaisesRegex(RuntimeError, 'released hold set changed'):
|
|
depth.apply_docker_depth_reactivation_manifest(
|
|
db, experiment_config(), POLICY_SHA256,
|
|
release_manifest, release_manifest_sha256,
|
|
)
|
|
finally:
|
|
db.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|