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

1165 lines
47 KiB
Python

import sys
sys.dont_write_bytecode = True
import argparse
import json
import math
import os
from collections import Counter, defaultdict
RANK_BUCKETS = ('ranks_1_3', 'ranks_4_10')
INVALID_OR_UNKNOWN = 'invalid_or_unknown'
DOCKER_DEPTH_SOURCES = frozenset(('dockerhub',))
EXPERIMENT_STATES = frozenset((
'collecting', 'planned', 'holding', 'resolving', 'active', 'draining',
'completed', 'released', 'held',
))
REPOSITORY_STATES = frozenset((
'pending', 'resolving', 'resolved', 'held', 'failed', 'skipped',
))
TARGET_STATES = frozenset((
'pending', 'reserved', 'scanning', 'done', 'failed', 'held',
'quarantined', 'skipped',
))
BINDING_STATES = frozenset((
'reserved', 'scanning', 'completed', 'failed', 'quarantined', 'released',
))
RESERVATION_STATES = frozenset((
'scanning', 'ready', 'ingesting', 'db_committed', 'acknowledged',
'refunded', 'quarantined',
))
SCAN_STATUSES = frozenset(('clean', 'found', 'skipped', 'error', 'degraded'))
CANDIDATE_STATES = frozenset((
'pending', 'leased', 'deferred', 'completed', 'quarantined',
))
KEYCHECK_STATUSES = frozenset((
'ALIVE', 'VALID', 'VALID_2FA', 'VALID_RATE_LIMITED', 'VERTEX', 'BEDROCK',
'FOUNDRY', 'ADMIN', 'CANARY', 'NO_BALANCE', 'NO_QUOTA',
'LIMITED_OR_NO_BALANCE', 'LIMITED_OR_QUOTA', 'LIMITED', 'RATE_LIMITED',
'NO_CONTEXT', 'NO_USERNAME', 'NO_TARGET', 'NO_TARGET_MODELS',
'NO_GENERATION_MODEL', 'RESTRICTED', 'API_DISABLED', 'ACCESS_DENIED',
'QUARANTINED', 'DISABLED', 'DEAD', 'INVALID', 'EXPIRED',
'LEAKED_REVOKED', 'INVALID_OR_REVOKED', 'NETWORK', 'NETWORK_ERROR',
'FOUNDRY_UNRESOLVED', 'FOUNDRY_BAD_ENDPOINT', 'GENERATION_OK', 'OK',
'OPENAI_BAD_ENDPOINT', 'OPENAI_UNRESOLVED', 'REFRESH_TOKEN', 'UNKNOWN',
))
KEYCHECK_STATUS_GROUPS = frozenset((
'alive', 'dead', 'restricted', 'no_balance', 'no_context', 'limited',
'network', 'unknown',
))
ERROR_CATEGORIES = frozenset((
'secondary_rate_limit', 'rate_limit', 'auth_invalid', 'auth_forbidden',
'query_invalid', 'not_found', 'server_error', 'disk_space', 'timeout',
'extract', 'download', 'network', 'api', 'trufflehog', 'unknown',
))
REPORT_MAX_MATERIALIZED_ROWS = 250000
_RESERVATION_BOUND_BINDINGS_CTE = '''reservation_bound_bindings AS (
SELECT t.id AS target_id, t.target_queue_id, t.manifest_id,
b.id AS binding_id, b.reservation_id, b.attempt,
b.state AS binding_state, reservation.state AS reservation_state,
ts.id AS scan_id,
ts.status AS scan_status, ts.duration_sec,
ts.error_count AS scan_error_count
FROM bounded_targets t
LEFT JOIN target_queue queue ON queue.id = t.target_queue_id
LEFT JOIN docker_depth_experiment_scan_bindings b
ON b.experiment_target_id = t.id
AND EXISTS (
SELECT 1 FROM result_reservations exact_reservation
WHERE exact_reservation.id = b.reservation_id
AND exact_reservation.queue_id = t.target_queue_id
AND exact_reservation.source = queue.source
AND exact_reservation.platform = queue.platform
AND COALESCE(exact_reservation.query, '') = COALESCE(queue.query, '')
AND exact_reservation.target = queue.target
AND exact_reservation.normalized_target = queue.normalized_target
)
LEFT JOIN result_reservations reservation
ON reservation.id = b.reservation_id
AND reservation.queue_id = t.target_queue_id
LEFT JOIN target_scans ts
ON ts.id = b.target_scan_id
AND ts.queue_id = t.target_queue_id
AND ts.queue_id = reservation.queue_id
AND ts.result_reservation_id = reservation.id
AND ts.result_reservation_id = b.reservation_id
AND ts.scan_event_id = reservation.scan_event_id
AND ts.claim_lease_token = reservation.claim_lease_token
AND ts.source = reservation.source
AND COALESCE(ts.query, '') = COALESCE(reservation.query, '')
AND ts.target = reservation.target
AND ts.normalized_target = reservation.normalized_target
AND ts.scan_type = reservation.platform
)'''
def _rows(connection, sql, params, *, max_rows=REPORT_MAX_MATERIALIZED_ROWS):
if isinstance(max_rows, bool) or not isinstance(max_rows, int) or max_rows < 1:
raise ValueError('report row bound must be a positive integer')
cursor = connection.execute(sql, params)
columns = [item[0] for item in cursor.description]
result = []
while True:
batch = cursor.fetchmany(512)
if not batch:
break
for row in batch:
if len(result) >= max_rows:
raise RuntimeError('Docker depth report row bound is exceeded')
if hasattr(row, 'keys'):
result.append({key: row[key] for key in row.keys()})
else:
result.append(dict(zip(columns, row)))
return result
def _row(connection, sql, params):
rows = _rows(connection, sql, params)
return rows[0] if rows else None
def _integer(value, default=0):
try:
return int(value)
except (TypeError, ValueError, OverflowError):
return default
def _duration(value):
try:
result = float(value)
except (TypeError, ValueError, OverflowError):
return None
return result if math.isfinite(result) and result >= 0 else None
def _category(value, allowed):
return value if isinstance(value, str) and value in allowed else INVALID_OR_UNKNOWN
def _experiment_key(value):
if not isinstance(value, str) or not 1 <= len(value) <= 128:
return INVALID_OR_UNKNOWN
allowed = frozenset('abcdefghijklmnopqrstuvwxyz0123456789._-')
if value[0].isalnum() and value[-1].isalnum() and all(char in allowed for char in value):
return value
return INVALID_OR_UNKNOWN
def _sha256(value):
if (
isinstance(value, str) and len(value) == 64
and all(char in '0123456789abcdef' for char in value)):
return value
return INVALID_OR_UNKNOWN
def _counts(values, allowed):
counts = Counter(_category(value, allowed) for value in values)
return {key: counts[key] for key in sorted(counts)}
def _rank_bucket(rank):
rank = _integer(rank, -1)
if 1 <= rank <= 3:
return 'ranks_1_3'
if 4 <= rank <= 10:
return 'ranks_4_10'
return None
def _finding_identity(row):
fingerprint = str(row.get('finding_fingerprint') or '')
detector_hash = str(row.get('detector_secret_hash') or '')
if fingerprint or detector_hash:
return ('identity', fingerprint, detector_hash)
return ('finding_id', _integer(row.get('finding_id')))
def _finding_metrics(rows, layer_rows):
finding_ids = set()
identities = set()
identity_by_finding = {}
detector_hashes = set()
missing_attribution_findings = set()
exact_attribution_count = 0
exact_findings = set()
explicit_unattributed_count = 0
explicit_unattributed_findings = set()
invalid_exact_count = 0
invalid_attribution_count = 0
for row in rows:
finding_id = _integer(row.get('finding_id'))
identity = _finding_identity(row)
finding_ids.add(finding_id)
identities.add(identity)
identity_by_finding[finding_id] = identity
detector_hash = str(row.get('detector_secret_hash') or '')
if detector_hash:
detector_hashes.add(detector_hash)
attribution_count = max(0, _integer(row.get('attribution_count')))
if attribution_count == 0:
missing_attribution_findings.add(finding_id)
exact_count = max(0, _integer(row.get('exact_attribution_count')))
exact_attribution_count += exact_count
if exact_count:
exact_findings.add(finding_id)
unattributed_count = max(
0, _integer(row.get('unattributed_attribution_count')),
)
explicit_unattributed_count += unattributed_count
if unattributed_count:
explicit_unattributed_findings.add(finding_id)
invalid_exact_count += max(
0, _integer(row.get('invalid_exact_attribution_count')),
)
invalid_attribution_count += max(
0, _integer(row.get('invalid_attribution_count')),
)
positions_from_base = Counter()
positions_from_top = Counter()
manifest_layers = set()
for row in layer_rows:
count = max(0, _integer(row.get('attribution_count')))
manifest_layers.add(_integer(row.get('matched_manifest_layer_id')))
positions_from_base[_integer(row.get('position_from_base'))] += count
positions_from_top[_integer(row.get('position_from_top'))] += count
unattributed_findings = finding_ids - exact_findings
exact_identities = {identity_by_finding[item] for item in exact_findings}
unattributed_identities = {
identity_by_finding[item] for item in unattributed_findings
}
return {
'findings': {
'occurrence_count': len(finding_ids),
'deduplicated_count': len(identities),
'detector_secret_identity_count': len(detector_hashes),
'without_detector_secret_hash_count': sum(
1 for identity in identities
if identity[0] == 'finding_id' or not identity[2]
),
},
'layers': {
'exact_attribution_count': exact_attribution_count,
'exact_finding_occurrence_count': len(exact_findings),
'exact_deduplicated_finding_count': len(exact_identities),
'exact_manifest_layer_count': len(manifest_layers),
'unattributed_attribution_count': explicit_unattributed_count,
'unattributed_finding_occurrence_count': len(unattributed_findings),
'unattributed_deduplicated_finding_count': len(unattributed_identities),
'missing_attribution_finding_count': len(missing_attribution_findings),
'invalid_exact_attribution_count': invalid_exact_count,
'invalid_or_unknown_attribution_count': invalid_attribution_count,
'positions_from_base': {
str(key): positions_from_base[key] for key in sorted(positions_from_base)
},
'positions_from_top': {
str(key): positions_from_top[key] for key in sorted(positions_from_top)
},
},
}
def _keycheck_metrics(rows):
candidates = {}
for row in rows:
candidates.setdefault(_integer(row.get('candidate_id')), row)
credentials = {
_integer(row.get('credential_id')) for row in candidates.values()
if row.get('credential_id') is not None
}
frozen_results = set()
frozen_by_credential = {}
current_by_credential = {}
for row in candidates.values():
credential_id = _integer(row.get('credential_id'))
frozen_result_id = row.get('frozen_result_id')
if frozen_result_id is not None:
frozen_result_id = _integer(frozen_result_id)
frozen_results.add(frozen_result_id)
previous = frozen_by_credential.get(credential_id)
if previous is None or frozen_result_id > previous[0]:
frozen_by_credential[credential_id] = (
frozen_result_id,
row.get('frozen_status'),
row.get('frozen_status_group'),
)
if row.get('current_state_credential_id') is not None:
current_by_credential[credential_id] = (
row.get('current_status'),
row.get('current_status_group'),
row.get('matched_current_result_id') is not None,
)
candidate_attempts = sum(
max(0, _integer(row.get('candidate_attempts'))) for row in candidates.values()
)
return {
'credentials': {
'deduplicated_count': len(credentials),
},
'keychecks': {
'candidate_count': len(candidates),
'candidate_state_counts': _counts(
(row.get('candidate_state') for row in candidates.values()),
CANDIDATE_STATES,
),
'attempt_count': candidate_attempts,
'retry_count': sum(
max(0, _integer(row.get('candidate_attempts')) - 1)
for row in candidates.values()
),
'pending_candidate_count': sum(
str(row.get('candidate_state') or '').lower() == 'pending'
for row in candidates.values()
),
'missing_frozen_result_candidate_count': sum(
row.get('frozen_result_id') is None for row in candidates.values()
),
'frozen': {
'result_count': len(frozen_results),
'credential_count': len(frozen_by_credential),
'missing_credential_count': len(credentials - set(frozen_by_credential)),
'status_counts': _counts(
(value[1] for value in frozen_by_credential.values()),
KEYCHECK_STATUSES,
),
'status_group_counts': _counts(
(value[2] for value in frozen_by_credential.values()),
KEYCHECK_STATUS_GROUPS,
),
},
'current': {
'credential_count': len(current_by_credential),
'missing_credential_count': len(credentials - set(current_by_credential)),
'missing_backing_result_count': sum(
not value[2] for value in current_by_credential.values()
),
'status_counts': _counts(
(value[0] for value in current_by_credential.values()),
KEYCHECK_STATUSES,
),
'status_group_counts': _counts(
(value[1] for value in current_by_credential.values()),
KEYCHECK_STATUS_GROUPS,
),
},
},
}
def _aggregate(
target_ids, physical_rows, finding_rows, layer_rows,
candidate_rows, error_rows):
target_ids = set(target_ids)
target_records = {}
bindings = {}
scans = {}
for row in physical_rows:
target_id = _integer(row.get('target_id'))
if target_id not in target_ids:
continue
target_records.setdefault(target_id, row)
if row.get('binding_id') is not None:
bindings.setdefault(_integer(row.get('binding_id')), row)
if row.get('scan_id') is not None:
scans.setdefault(_integer(row.get('scan_id')), row)
selected_findings = [
row for row in finding_rows if _integer(row.get('target_id')) in target_ids
]
selected_candidates = [
row for row in candidate_rows if _integer(row.get('target_id')) in target_ids
]
selected_errors = [
row for row in error_rows if _integer(row.get('target_id')) in target_ids
]
selected_layers = [
row for row in layer_rows if _integer(row.get('target_id')) in target_ids
]
durations = {
scan_id: value for scan_id, row in scans.items()
if (value := _duration(row.get('duration_sec'))) is not None
}
errors = {
_integer(row.get('error_id')): row for row in selected_errors
if row.get('error_id') is not None
}
error_ids = set(errors)
scans_with_error_rows = {
_integer(row.get('scan_id')) for row in selected_errors
if row.get('error_id') is not None
}
scans_with_reported_errors = {
scan_id for scan_id, row in scans.items()
if _integer(row.get('scan_error_count')) > 0
}
finding_metrics = _finding_metrics(selected_findings, selected_layers)
keycheck_metrics = _keycheck_metrics(selected_candidates)
duration_values = list(durations.values())
duration_total = sum(duration_values)
targets_with_bindings = {
_integer(row.get('target_id')) for row in bindings.values()
}
targets_with_scans = {
_integer(row.get('target_id')) for row in scans.values()
}
return {
'target_count': len(target_ids),
'manifest_count': len({
_integer(row.get('matched_manifest_id')) for row in target_records.values()
if row.get('matched_manifest_id') is not None
}),
'declared_manifest_layer_count': sum(
max(0, _integer(row.get('manifest_layer_count')))
for row in target_records.values()
if row.get('matched_manifest_id') is not None
),
'target_state_counts': _counts(
(row.get('target_state') for row in target_records.values()),
TARGET_STATES,
),
'targets_with_bindings': len(targets_with_bindings),
'targets_without_bindings': len(target_ids - targets_with_bindings),
'targets_with_scans': len(targets_with_scans),
'targets_without_scans': len(target_ids - targets_with_scans),
'scan_bindings': {
'attempt_count': len(bindings),
'retry_count': sum(
_integer(row.get('attempt')) > 1 for row in bindings.values()
),
'refunded_attempt_count': sum(
str(row.get('binding_state') or '') == 'released'
for row in bindings.values()
),
'maximum_attempt': max(
(_integer(row.get('attempt')) for row in bindings.values()),
default=0,
),
'state_counts': _counts(
(row.get('binding_state') for row in bindings.values()),
BINDING_STATES,
),
'reservation_state_counts': _counts(
(row.get('reservation_state') for row in bindings.values()),
RESERVATION_STATES,
),
},
'scans': {
'count': len(scans),
'status_counts': _counts(
(row.get('scan_status') for row in scans.values()),
SCAN_STATUSES,
),
'duration': {
'count': len(duration_values),
'missing_count': len(scans) - len(duration_values),
'total_seconds': duration_total,
'average_seconds': (
duration_total / len(duration_values) if duration_values else 0.0
),
'minimum_seconds': min(duration_values, default=0.0),
'maximum_seconds': max(duration_values, default=0.0),
},
'errors': {
'row_count': len(error_ids),
'category_counts': _counts(
(row.get('error_category') for row in errors.values()),
ERROR_CATEGORIES,
),
'reported_count': sum(
max(0, _integer(row.get('scan_error_count')))
for row in scans.values()
),
'scan_count': len(
scans_with_error_rows | scans_with_reported_errors
),
},
},
**finding_metrics,
**keycheck_metrics,
}
def _marginal_minimum_rank_yield(target_ranks, finding_rows, candidate_rows):
minimum_finding_rank = {}
minimum_detector_rank = {}
minimum_credential_rank = {}
def record_minimum(mapping, identity, rank):
if rank is None:
mapping.setdefault(identity, None)
elif mapping.get(identity) is None or rank < mapping[identity]:
mapping[identity] = rank
for row in finding_rows:
target_id = _integer(row.get('target_id'))
if target_id not in target_ranks:
continue
rank = target_ranks[target_id]
record_minimum(minimum_finding_rank, _finding_identity(row), rank)
detector_hash = str(row.get('detector_secret_hash') or '')
if detector_hash:
record_minimum(minimum_detector_rank, detector_hash, rank)
for row in candidate_rows:
target_id = _integer(row.get('target_id'))
if target_id not in target_ranks or row.get('credential_id') is None:
continue
record_minimum(
minimum_credential_rank,
_integer(row.get('credential_id')),
target_ranks[target_id],
)
def distribution(mapping):
buckets = Counter(_rank_bucket(rank) or 'unranked' for rank in mapping.values())
return {
'deduplicated_total': len(mapping),
'ranks_1_3': buckets['ranks_1_3'],
'ranks_4_10': buckets['ranks_4_10'],
'unranked': buckets['unranked'],
}
return {
'findings': distribution(minimum_finding_rank),
'detector_secret_identities': distribution(minimum_detector_rank),
'credentials': distribution(minimum_credential_rank),
}
def _scope_report(
target_ranks, physical_rows, finding_rows, layer_rows,
candidate_rows, error_rows):
target_ids = set(target_ranks)
bucket_targets = {
bucket: {
target_id for target_id, rank in target_ranks.items()
if _rank_bucket(rank) == bucket
}
for bucket in RANK_BUCKETS
}
return {
'totals': _aggregate(
target_ids, physical_rows, finding_rows, layer_rows,
candidate_rows, error_rows,
),
'rank_buckets': {
bucket: _aggregate(
bucket_targets[bucket], physical_rows, finding_rows,
layer_rows, candidate_rows, error_rows,
)
for bucket in RANK_BUCKETS
},
'unranked_target_count': sum(
_rank_bucket(rank) is None for rank in target_ranks.values()
),
'marginal_minimum_rank_yield': _marginal_minimum_rank_yield(
target_ranks, finding_rows, candidate_rows,
),
}
def _overlap_summary(item_queries):
credits = sum(len(query_ids) for query_ids in item_queries.values())
attributed = sum(bool(query_ids) for query_ids in item_queries.values())
return {
'physical_count': len(item_queries),
'attributed_physical_count': attributed,
'unattributed_physical_count': len(item_queries) - attributed,
'attribution_credit_count': credits,
'overlap_credit_count': credits - attributed,
'shared_physical_count': sum(
len(query_ids) > 1 for query_ids in item_queries.values()
),
}
def _repository_overlap_summary(repository_queries):
summary = _overlap_summary(repository_queries)
return {
'physical_count': summary['physical_count'],
'query_membership_credit_count': summary['attribution_credit_count'],
'overlap_credit_count': summary['overlap_credit_count'],
'shared_physical_count': summary['shared_physical_count'],
}
def _report_connection(connection):
if not hasattr(connection, 'execute'):
connection = getattr(connection, 'conn', None)
if connection is None or not hasattr(connection, 'execute'):
raise ValueError('a database connection is required')
module = str(type(connection).__module__ or '').lower()
if module.startswith(('psycopg', 'psycopg2')) and not hasattr(
connection, 'is_postgres',
):
raise ValueError(
'raw PostgreSQL connections are unsupported; use DatabaseConnection'
)
return connection
def _begin_report_snapshot(connection):
is_postgres = bool(getattr(connection, 'is_postgres', False))
raw_connection = getattr(connection, '_conn', connection)
if is_postgres:
transaction_status = getattr(
getattr(raw_connection, 'info', None), 'transaction_status', None,
)
if transaction_status is not None and int(transaction_status) != 0:
raise RuntimeError('Docker depth report requires an idle database connection')
statement = (
'BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ READ ONLY'
)
else:
if bool(getattr(raw_connection, 'in_transaction', False)):
raise RuntimeError('Docker depth report requires an idle database connection')
statement = 'BEGIN'
try:
connection.execute(statement)
except Exception:
connection.rollback()
raise
return 'repeatable_read' if is_postgres else 'sqlite_transaction'
def _build_docker_depth_report_snapshot(
connection, *, experiment_id=None, experiment_key=None):
"""Return secret-safe aggregates for one durable Docker depth experiment."""
connection = _report_connection(connection)
if (experiment_id is None) == (experiment_key is None):
raise ValueError('provide exactly one of experiment_id or experiment_key')
if experiment_id is not None:
if isinstance(experiment_id, bool) or not isinstance(experiment_id, int):
raise ValueError('experiment_id must be a positive integer')
if experiment_id < 1:
raise ValueError('experiment_id must be a positive integer')
where = 'id = ?'
selector = experiment_id
else:
experiment_key = str(experiment_key or '').strip()
if not experiment_key:
raise ValueError('experiment_key must be non-empty')
where = 'experiment_key = ?'
selector = experiment_key
experiment = _row(
connection,
f'''SELECT id, experiment_key, source, state, query_count,
target_count, selection_count
FROM docker_depth_experiments
WHERE {where}''',
(selector,),
)
if experiment is None:
raise LookupError('Docker depth experiment was not found')
experiment_id = _integer(experiment['id'])
query_rows = _rows(
connection,
'''WITH bounded_queries AS (
SELECT id, experiment_id, source, query_ordinal, query,
query_sha256, required_repository_count,
selected_repository_count
FROM docker_depth_experiment_queries
WHERE experiment_id = ?
)
SELECT q.id AS query_id, q.query_ordinal, q.query_sha256, q.source,
q.required_repository_count, q.selected_repository_count,
r.id AS repository_id,
COALESCE(r.replacement_repository_queue_id,
r.repository_queue_id) AS repository_queue_id,
r.repository_queue_id AS planned_repository_queue_id,
r.repository_rank,
r.work_state AS repository_state, r.resolver_attempts,
s.id AS selection_id, s.image_rank,
t.id AS target_id
FROM bounded_queries q
LEFT JOIN docker_depth_experiment_repositories r
ON r.experiment_id = q.experiment_id
AND r.query_ordinal = q.query_ordinal
AND r.source = q.source AND r.query = q.query
LEFT JOIN docker_depth_experiment_selections s
ON s.experiment_id = q.experiment_id
AND s.query_ordinal = q.query_ordinal
AND s.experiment_repository_id = r.id
LEFT JOIN docker_depth_experiment_targets t
ON t.experiment_id = q.experiment_id
AND t.id = s.experiment_target_id
ORDER BY q.query_ordinal, q.id, r.id, s.id''',
(experiment_id,),
)
physical_rows = _rows(
connection,
f'''WITH bounded_targets AS (
SELECT id, experiment_id, target_queue_id, manifest_id, state
FROM docker_depth_experiment_targets
WHERE experiment_id = ?
), target_ranks AS (
SELECT experiment_target_id, MIN(image_rank) AS image_rank
FROM docker_depth_experiment_selections
WHERE experiment_id = ?
GROUP BY experiment_target_id
), {_RESERVATION_BOUND_BINDINGS_CTE}
SELECT t.id AS target_id, t.state AS target_state,
tr.image_rank,
m.id AS matched_manifest_id,
m.layer_count AS manifest_layer_count,
rb.binding_id, rb.attempt, rb.binding_state,
rb.reservation_state,
rb.scan_id, rb.scan_status, rb.duration_sec,
rb.scan_error_count
FROM bounded_targets t
LEFT JOIN target_ranks tr ON tr.experiment_target_id = t.id
LEFT JOIN docker_image_manifests m
ON m.id = t.manifest_id AND m.target_queue_id = t.target_queue_id
LEFT JOIN reservation_bound_bindings rb ON rb.target_id = t.id
ORDER BY t.id, rb.binding_id''',
(experiment_id, experiment_id),
)
finding_rows = _rows(
connection,
f'''WITH bounded_targets AS (
SELECT id, target_queue_id, manifest_id
FROM docker_depth_experiment_targets
WHERE experiment_id = ?
), {_RESERVATION_BOUND_BINDINGS_CTE}
SELECT rb.target_id, rb.binding_id, rb.scan_id,
f.id AS finding_id, f.finding_fingerprint,
f.detector_secret_hash,
COUNT(a.id) AS attribution_count,
SUM(CASE WHEN a.attribution_state = 'exact'
AND ml.id IS NOT NULL THEN 1 ELSE 0 END)
AS exact_attribution_count,
SUM(CASE WHEN a.attribution_state = 'exact'
AND ml.id IS NULL THEN 1 ELSE 0 END)
AS invalid_exact_attribution_count,
SUM(CASE WHEN a.attribution_state = 'unattributed'
THEN 1 ELSE 0 END)
AS unattributed_attribution_count,
SUM(CASE WHEN a.id IS NOT NULL
AND a.attribution_state NOT IN ('exact','unattributed')
THEN 1 ELSE 0 END)
AS invalid_attribution_count
FROM reservation_bound_bindings rb
JOIN findings f ON f.target_scan_id = rb.scan_id
LEFT JOIN docker_finding_layer_attributions a
ON a.scan_binding_id = rb.binding_id AND a.finding_id = f.id
LEFT JOIN docker_manifest_layers ml
ON ml.id = a.manifest_layer_id
AND ml.manifest_id = rb.manifest_id
AND ml.position_from_base = a.position_from_base
AND ml.position_from_top = a.position_from_top
AND ml.layer_digest = a.reported_layer_digest
GROUP BY rb.target_id, rb.binding_id, rb.scan_id, f.id,
f.finding_fingerprint, f.detector_secret_hash
ORDER BY rb.target_id, f.id''',
(experiment_id,),
)
layer_rows = _rows(
connection,
f'''WITH bounded_targets AS (
SELECT id, target_queue_id, manifest_id
FROM docker_depth_experiment_targets
WHERE experiment_id = ?
), {_RESERVATION_BOUND_BINDINGS_CTE}
SELECT rb.target_id, ml.id AS matched_manifest_layer_id,
ml.position_from_base, ml.position_from_top,
COUNT(a.id) AS attribution_count
FROM reservation_bound_bindings rb
JOIN findings f ON f.target_scan_id = rb.scan_id
JOIN docker_finding_layer_attributions a
ON a.scan_binding_id = rb.binding_id AND a.finding_id = f.id
AND a.attribution_state = 'exact'
JOIN docker_manifest_layers ml
ON ml.id = a.manifest_layer_id
AND ml.manifest_id = rb.manifest_id
AND ml.position_from_base = a.position_from_base
AND ml.position_from_top = a.position_from_top
AND ml.layer_digest = a.reported_layer_digest
GROUP BY rb.target_id, ml.id, ml.position_from_base,
ml.position_from_top
ORDER BY rb.target_id, ml.id''',
(experiment_id,),
)
candidate_rows = _rows(
connection,
f'''WITH bounded_targets AS (
SELECT id, target_queue_id, manifest_id
FROM docker_depth_experiment_targets
WHERE experiment_id = ?
), {_RESERVATION_BOUND_BINDINGS_CTE}, bounded_findings AS (
SELECT rb.target_id, rb.scan_id, f.id AS finding_id
FROM reservation_bound_bindings rb
JOIN findings f ON f.target_scan_id = rb.scan_id
)
SELECT bf.target_id, bf.scan_id, bf.finding_id,
c.id AS candidate_id, kc.id AS credential_id,
c.state AS candidate_state, c.attempts AS candidate_attempts,
frozen.id AS frozen_result_id,
frozen.status AS frozen_status,
frozen.status_group AS frozen_status_group,
current_state.credential_id AS current_state_credential_id,
current_result.status AS current_status,
current_result.status_group AS current_status_group,
current_result.id AS matched_current_result_id
FROM bounded_findings bf
JOIN keycheck_candidates c
ON c.finding_id = bf.finding_id
AND c.target_scan_id = bf.scan_id
JOIN keycheck_credentials kc ON kc.id = c.credential_id
LEFT JOIN keycheck_results frozen
ON frozen.id = c.keycheck_result_id
AND frozen.candidate_id = c.id
AND frozen.credential_id = kc.id
LEFT JOIN keycheck_current_state current_state
ON current_state.credential_id = kc.id
LEFT JOIN keycheck_results current_result
ON current_result.id = current_state.last_result_id
AND current_result.credential_id = current_state.credential_id
AND current_result.status = current_state.status
AND current_result.status_group = current_state.status_group
ORDER BY bf.target_id, c.id''',
(experiment_id,),
)
error_rows = _rows(
connection,
f'''WITH bounded_targets AS (
SELECT id, target_queue_id, manifest_id
FROM docker_depth_experiment_targets
WHERE experiment_id = ?
), {_RESERVATION_BOUND_BINDINGS_CTE}
SELECT rb.target_id, rb.binding_id, rb.scan_id,
e.id AS error_id, e.category AS error_category
FROM reservation_bound_bindings rb
JOIN errors e ON e.target_scan_id = rb.scan_id
ORDER BY rb.target_id, rb.scan_id, e.id''',
(experiment_id,),
)
query_contexts = {}
for row in query_rows:
query_id = _integer(row.get('query_id'))
context = query_contexts.setdefault(query_id, {
'query_id': query_id,
'query_ordinal': _integer(row.get('query_ordinal')),
'query_sha256': _sha256(row.get('query_sha256')),
'source': str(row.get('source') or ''),
'required_repository_count': _integer(
row.get('required_repository_count')
),
'cohort_repository_count': _integer(
row.get('selected_repository_count')
),
'repository_attempts': {},
'repository_states': {},
'repository_queue_ids': {},
'selected_repositories': set(),
'selection_ids': set(),
'target_ranks': {},
})
repository_id = row.get('repository_id')
if repository_id is not None:
repository_id = _integer(repository_id)
context['repository_attempts'].setdefault(
repository_id, max(0, _integer(row.get('resolver_attempts'))),
)
context['repository_states'].setdefault(
repository_id, row.get('repository_state'),
)
if row.get('repository_queue_id') is not None:
context['repository_queue_ids'].setdefault(
repository_id, _integer(row.get('repository_queue_id')),
)
if row.get('selection_id') is not None and row.get('target_id') is not None:
context['selection_ids'].add(_integer(row.get('selection_id')))
if row.get('repository_queue_id') is not None:
context['selected_repositories'].add(
_integer(row.get('repository_queue_id'))
)
target_id = _integer(row.get('target_id'))
rank = _integer(row.get('image_rank'))
previous = context['target_ranks'].get(target_id)
if previous is None or rank < previous:
context['target_ranks'][target_id] = rank
physical_target_ranks = {}
for row in physical_rows:
target_id = _integer(row.get('target_id'))
rank = row.get('image_rank')
physical_target_ranks.setdefault(
target_id, _integer(rank) if rank is not None else None,
)
physical = _scope_report(
physical_target_ranks, physical_rows, finding_rows, layer_rows,
candidate_rows, error_rows,
)
repository_queries = defaultdict(set)
selected_repository_queries = defaultdict(set)
all_selections = set()
for query_id, context in query_contexts.items():
for repository_queue_id in set(context['repository_queue_ids'].values()):
repository_queries[repository_queue_id].add(query_id)
for repository_queue_id in context['selected_repositories']:
selected_repository_queries[repository_queue_id].add(query_id)
all_selections.update(context['selection_ids'])
repository_coverage = _repository_overlap_summary(repository_queries)
selected_repository_coverage = _repository_overlap_summary(
selected_repository_queries
)
skipped_repository_queue_ids = {
context['repository_queue_ids'][repository_id]
for context in query_contexts.values()
for repository_id, state in context['repository_states'].items()
if state == 'skipped' and repository_id in context['repository_queue_ids']
}
skipped_repository_memberships = sum(
state == 'skipped'
for context in query_contexts.values()
for state in context['repository_states'].values()
)
physical['coverage'] = {
'query_count': len(query_contexts),
'queries_with_repositories': sum(
bool(item['repository_attempts']) for item in query_contexts.values()
),
'queries_with_selections': sum(
bool(item['selection_ids']) for item in query_contexts.values()
),
'repository_count': repository_coverage['physical_count'],
'repository_query_membership_credit_count': (
repository_coverage['query_membership_credit_count']
),
'repository_overlap_credit_count': repository_coverage['overlap_credit_count'],
'shared_repository_count': repository_coverage['shared_physical_count'],
'selected_repository_count': selected_repository_coverage['physical_count'],
'selected_repository_query_membership_credit_count': (
selected_repository_coverage['query_membership_credit_count']
),
'selected_repository_overlap_credit_count': (
selected_repository_coverage['overlap_credit_count']
),
'shared_selected_repository_count': (
selected_repository_coverage['shared_physical_count']
),
'image_unavailable_repository_count': len(skipped_repository_queue_ids),
'image_unavailable_repository_membership_count': (
skipped_repository_memberships
),
'queries_with_image_unavailable_repositories': sum(
any(state == 'skipped' for state in item['repository_states'].values())
for item in query_contexts.values()
),
'selection_count': len(all_selections),
'target_attribution_credit_count': sum(
len(item['target_ranks']) for item in query_contexts.values()
),
}
per_query = {}
for context in sorted(
query_contexts.values(),
key=lambda item: (item['query_ordinal'], item['query_id'])):
scope = _scope_report(
context['target_ranks'], physical_rows, finding_rows, layer_rows,
candidate_rows, error_rows,
)
resolver_attempts = context['repository_attempts'].values()
scope['query'] = {
'id': context['query_id'],
'ordinal': context['query_ordinal'],
'sha256': context['query_sha256'],
'source': _category(context['source'], DOCKER_DEPTH_SOURCES),
}
scope['coverage'] = {
'required_repository_count': context['required_repository_count'],
'cohort_repository_count': context['cohort_repository_count'],
'unavailable_repository_count': max(
0,
context['required_repository_count']
- context['cohort_repository_count'],
),
'repository_count': len(context['repository_attempts']),
'missing_cohort_repository_count': max(
0,
context['cohort_repository_count']
- len(context['repository_attempts']),
),
'selected_repository_count': len(context['selected_repositories']),
'image_unavailable_repository_count': sum(
state == 'skipped'
for state in context['repository_states'].values()
),
'selection_count': len(context['selection_ids']),
'target_count': len(context['target_ranks']),
'repository_state_counts': _counts(
context['repository_states'].values(), REPOSITORY_STATES,
),
'resolver_attempt_count': sum(resolver_attempts),
'resolver_retry_count': sum(
max(0, attempts - 1)
for attempts in context['repository_attempts'].values()
),
}
per_query[str(context['query_id'])] = scope
target_queries = {target_id: set() for target_id in physical_target_ranks}
for query_id, context in query_contexts.items():
for target_id in context['target_ranks']:
target_queries.setdefault(target_id, set()).add(query_id)
scan_queries = {}
for row in physical_rows:
if row.get('scan_id') is not None:
scan_queries.setdefault(
_integer(row.get('scan_id')),
set(target_queries.get(_integer(row.get('target_id')), set())),
)
finding_queries = defaultdict(set)
for row in finding_rows:
finding_queries[_finding_identity(row)].update(
target_queries.get(_integer(row.get('target_id')), set())
)
credential_queries = defaultdict(set)
for row in candidate_rows:
if row.get('credential_id') is not None:
credential_queries[_integer(row.get('credential_id'))].update(
target_queries.get(_integer(row.get('target_id')), set())
)
return {
'experiment': {
'id': experiment_id,
'key': _experiment_key(experiment.get('experiment_key')),
'source': _category(experiment.get('source'), DOCKER_DEPTH_SOURCES),
'state': _category(experiment.get('state'), EXPERIMENT_STATES),
'persisted_counts': {
'queries': _integer(experiment.get('query_count')),
'targets': _integer(experiment.get('target_count')),
'selections': _integer(experiment.get('selection_count')),
},
},
'physical': physical,
'per_query': per_query,
'counting_semantics': {
'physical_totals_are_deduplicated': True,
'per_query_totals_are_attribution_credits': True,
'per_query_totals_are_summable_to_physical': False,
},
'overlap': {
'repositories': repository_coverage,
'selected_repositories': selected_repository_coverage,
'targets': _overlap_summary(target_queries),
'scans': _overlap_summary(scan_queries),
'findings': _overlap_summary(finding_queries),
'credentials': _overlap_summary(credential_queries),
},
}
def build_docker_depth_report(
connection, *, experiment_id=None, experiment_key=None,
allow_live=True):
"""Build one aggregate report from a clean, read-only database snapshot."""
connection = _report_connection(connection)
consistency = _begin_report_snapshot(connection)
try:
report = _build_docker_depth_report_snapshot(
connection, experiment_id=experiment_id,
experiment_key=experiment_key,
)
terminal = report['experiment']['state'] in ('completed', 'released')
if not allow_live and not terminal:
raise RuntimeError(
'Docker depth report is live; pass allow_live=True explicitly'
)
report['snapshot'] = {
'read_only': True,
'consistency': consistency,
'experiment_terminal': terminal,
}
return report
finally:
connection.rollback()
def main(argv=None):
parser = argparse.ArgumentParser(
description='Build a secret-safe read-only Docker depth experiment report.',
)
parser.add_argument('--config', required=True)
selector = parser.add_mutually_exclusive_group(required=True)
selector.add_argument('--experiment-id', type=int)
selector.add_argument('--experiment-key')
parser.add_argument(
'--allow-live', action='store_true',
help='Allow a coherent snapshot before the experiment is completed.',
)
args = parser.parse_args(argv)
connection = None
try:
import yaml
from db_backend import (
connect_postgres, database_url_from_env, is_postgres_url,
)
from paths import apply_path_config
with open(os.path.abspath(args.config), 'r', encoding='utf-8') as handle:
config = apply_path_config(yaml.safe_load(handle) or {}, args.config)
global_config = config.get('global') or {}
database_url = (
global_config.get('dashboard_db_url')
or global_config.get('database_url')
or database_url_from_env()
)
if not is_postgres_url(database_url):
raise RuntimeError('Docker depth report requires PostgreSQL')
connection = connect_postgres(
database_url, connect_timeout_sec=5, statement_timeout_ms=120000,
lock_timeout_ms=5000, idle_in_transaction_timeout_ms=120000,
tcp_user_timeout_ms=10000,
)
connection.execute("SET application_name = 'truf-docker-depth-report'")
connection.execute('SET default_transaction_read_only = on')
connection.commit()
report = build_docker_depth_report(
connection,
experiment_id=args.experiment_id,
experiment_key=args.experiment_key,
allow_live=args.allow_live,
)
print(json.dumps(report, ensure_ascii=True, sort_keys=True))
return 0
except Exception as exc:
raise SystemExit(
f'Docker depth report failed closed: {type(exc).__name__}'
) from None
finally:
if connection is not None:
connection.close()
if __name__ == '__main__':
main()