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

2582 lines
114 KiB
Python

import sys
sys.dont_write_bytecode = True
if not sys.dont_write_bytecode:
raise RuntimeError('dashboard could not disable bytecode writes')
import argparse
from collections import Counter
from datetime import datetime, timedelta, timezone
import hashlib
import html
import ipaddress
import json
import os
import re
import shutil
import sqlite3
import time
import pandas as pd
import plotly.express as px
import streamlit as st
from scanner_db import DB_FILENAME, get_database_path, queue_counts, sanitize_endpoint
from paths import apply_path_config, default_project_paths, resolve_optional_path
from db_backend import connect_postgres, connect_sqlite, database_url_from_env, is_postgres_url
from lifecycle_authority import CHILD_KIND_ENV, LifecycleAuthorityError, require_active_supervisor_child
DEFAULT_PATHS = default_project_paths()
DEFAULT_RESULTS_DIR = os.getenv('SCAN_RESULTS_DIR', DEFAULT_PATHS['results_dir'])
DEFAULT_QUEUE_DIR = DEFAULT_PATHS['queue_dir']
DEFAULT_STATE_FILE = DEFAULT_PATHS['state_file']
DEFAULT_LOG_DIR = DEFAULT_PATHS['log_dir']
SOURCES = ['github', 'github_archive', 'github_archive_files', 'github_gists', 'gitlab', 'github_actions', 'gitlab_ci', 'docker', 'dockerhub', 'npm', 'pypi', 'package_git', 'huggingface', 'postman']
RUNTIME_SOURCES = ['github', 'github_archive', 'github_archive_files', 'github_gists', 'gitlab', 'github_actions', 'gitlab_ci', 'huggingface', 'dockerhub', 'npm', 'package_git', 'postman', 'keychecks', 'pypi']
VALIDATION_SERVICES = ['anthropic', 'aws', 'azure', 'deepseek', 'dockerhub', 'gcp', 'gemini', 'github', 'gitlab', 'groq', 'huggingface', 'kimi', 'openai', 'openrouter', 'provider_resolver', 'qwen', 'replicate', 'xai', 'zai']
VALIDATION_STATUS_GROUPS = ['alive', 'dead', 'restricted', 'no_balance', 'no_context', 'limited', 'network', 'unknown']
VALIDATION_STATUSES = [
'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_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', 'UNKNOWN',
]
VALIDATION_ACCESS_TIERS = ['usable_llm', 'alive_unproven_llm', 'no_quota', 'quota_limited', 'missing_context', 'dead', 'restricted', 'network', 'unknown']
VALIDATION_PRESETS = [
'Usable LLM keys',
'Ever usable LLM keys',
'Ever alive / LLM candidates',
'Quota / no balance',
'Alive but not proven LLM',
'Unattributed alive',
'All latest validation',
'Latest rows',
]
UNATTRIBUTED = '(unattributed)'
ARCHIVE_INTERESTING_DETECTORS = {
'googleai', 'googleaistudio', 'openai', 'anthropic', 'deepseek', 'openrouter', 'groq',
'replicate', 'xai', 'huggingface', 'qwendashscope', 'kimimoonshot', 'zaiglm', 'github', 'githuboauth2',
'gitlab', 'aws', 'gcp', 'gcpapplicationdefaultcredentials', 'azure', 'azureopenai',
'azurecontainerregistry', 'dockerhub', 'npmtoken', 'sentrytoken', 'weightsandbiases',
'twilio', 'scalewaykey', 'fastlypersonaltoken', 'sonarcloud', 'honeycomb', 'rapidapi',
}
DASHBOARD_DB_DIALECT = 'sqlite'
DASHBOARD_QUERY_TIMEOUT_SEC = 10
MAX_LOG_TAIL_BYTES = 1024 * 1024
LOOKUP_MAX_INPUT_CHARS = 65536
LOOKUP_METADATA_LIMIT = 100000
REPORTING_PRESETS = {
'1 hour': timedelta(hours=1),
'24 hours': timedelta(hours=24),
'7 days': timedelta(days=7),
'30 days': timedelta(days=30),
}
CORE_RUNTIME_SOURCES = {
'result-ingester', 'jsonl-projector', 'janitor', 'worker-api',
'github', 'gitlab', 'huggingface', 'dockerhub', 'package_git', 'keychecks',
}
FORBIDDEN_DASHBOARD_QUERY_COLUMNS = (
'raw_secret', 'raw_result_json', 'raw_finding_json', 'config_json', 'evidence_json',
)
def parse_args():
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument('--config')
parser.add_argument('--db')
parser.add_argument('--db-url')
parser.add_argument('--immutable-db', action='store_true')
parser.add_argument('--results-dir', default=DEFAULT_RESULTS_DIR)
parser.add_argument('--queue-dir', default=DEFAULT_QUEUE_DIR)
parser.add_argument('--state-file', default=DEFAULT_STATE_FILE)
parser.add_argument('--log-dir', default=DEFAULT_LOG_DIR)
parser.add_argument('--work-dir', default=DEFAULT_PATHS['work_dir'])
parser.add_argument('--keycheck-dir', default=DEFAULT_PATHS['keycheck_dir'])
parser.add_argument('--scan-limiter-db', default=os.path.join(DEFAULT_PATHS['state_dir'], 'scan_limiter.db'))
parser.add_argument('--max-active-scans', type=int, default=0)
args, _ = parser.parse_known_args(sys.argv[1:])
if not args.config:
cwd_config = os.path.join(os.getcwd(), 'config.yaml')
if os.path.exists(cwd_config):
args.config = cwd_config
if args.config:
try:
import yaml
with open(args.config, 'r', encoding='utf-8') as f:
config = apply_path_config(yaml.safe_load(f) or {}, args.config)
global_config = config.get('global') or {}
args.results_dir = global_config.get('results_dir', args.results_dir)
args.queue_dir = global_config.get('queue_dir', args.queue_dir)
args.state_file = global_config.get('state_file', args.state_file)
args.log_dir = global_config.get('log_dir', args.log_dir)
args.work_dir = global_config.get('work_dir', args.work_dir)
args.keycheck_dir = global_config.get('keycheck_dir', args.keycheck_dir)
args.scan_limiter_db = global_config.get('scan_limiter_db', args.scan_limiter_db)
base_scans = int(global_config.get('max_active_scans', args.max_active_scans) or 0)
bonus_scans = max(0, min(1, int(global_config.get('opportunistic_scan_slots', 0) or 0)))
args.max_active_scans = base_scans + bonus_scans
if not args.db_url:
args.db_url = global_config.get('dashboard_db_url') or global_config.get('database_url') or database_url_from_env()
if not args.db:
args.db = resolve_optional_path(global_config.get('dashboard_db_path') or global_config.get('database_path'), global_config)
elif args.db:
args.db = resolve_optional_path(args.db, global_config)
args.immutable_db = bool(global_config.get('dashboard_immutable_db', args.immutable_db))
except Exception as e:
if os.getenv(CHILD_KIND_ENV) == 'dashboard':
raise SystemExit(f'Managed dashboard config failed closed: {type(e).__name__}') from e
print(f'Unable to load dashboard config {args.config}: {e}')
return args
def resolve_db_path(args):
if args.db:
return args.db
return get_database_path(args.results_dir)
def resolve_db_url(args):
return args.db_url or database_url_from_env()
def connect_db(path, db_url=None, immutable=False):
global DASHBOARD_DB_DIALECT
if is_postgres_url(db_url):
conn = connect_postgres(
db_url,
connect_timeout_sec=3,
statement_timeout_ms=10000,
lock_timeout_ms=2000,
idle_in_transaction_timeout_ms=10000,
tcp_user_timeout_ms=5000,
)
try:
conn.execute("SET application_name = 'truf-dashboard'")
conn.execute('SET default_transaction_read_only = on')
conn.commit()
except BaseException:
conn.close()
raise
DASHBOARD_DB_DIALECT = 'postgres'
return conn
if not path or not os.path.exists(path):
return None
conn = connect_sqlite(path, timeout_sec=5, read_only=True, immutable=immutable, check_same_thread=False)
conn.execute('PRAGMA query_only=ON')
conn.execute('PRAGMA busy_timeout=5000')
DASHBOARD_DB_DIALECT = 'sqlite'
return conn
def query_df(conn, sql, params=None):
if conn is None:
return pd.DataFrame()
if any(re.search(rf'\b{re.escape(column)}\b', str(sql), re.IGNORECASE) for column in FORBIDDEN_DASHBOARD_QUERY_COLUMNS):
st.error('Dashboard query refused because it requested a sensitive payload column.')
return pd.DataFrame()
raw_sqlite = getattr(conn, '_conn', None) if getattr(conn, 'is_sqlite', False) is True else None
if raw_sqlite is not None:
deadline = time.monotonic() + DASHBOARD_QUERY_TIMEOUT_SEC
raw_sqlite.set_progress_handler(lambda: 1 if time.monotonic() >= deadline else 0, 10000)
try:
rows = conn.execute(sql, params or []).fetchall()
if getattr(conn, 'is_postgres', False):
conn.commit()
return pd.DataFrame([dict(row) for row in rows])
except Exception as e:
if getattr(conn, 'is_postgres', False):
try:
conn.rollback()
except Exception:
pass
st.error(f'Database query failed ({type(e).__name__}). Retry after database recovery.')
return pd.DataFrame()
finally:
if raw_sqlite is not None:
raw_sqlite.set_progress_handler(None, 0)
def table_columns(conn, table):
if conn is None:
return set()
raw_sqlite = getattr(conn, '_conn', None) if getattr(conn, 'is_sqlite', False) is True else None
if raw_sqlite is not None:
deadline = time.monotonic() + DASHBOARD_QUERY_TIMEOUT_SEC
raw_sqlite.set_progress_handler(lambda: 1 if time.monotonic() >= deadline else 0, 10000)
try:
columns = conn.table_columns(table)
if getattr(conn, 'is_postgres', False):
conn.commit()
return columns
except Exception:
if getattr(conn, 'is_postgres', False):
try:
conn.rollback()
except Exception:
pass
return set()
finally:
if raw_sqlite is not None:
raw_sqlite.set_progress_handler(None, 0)
def table_exists(conn, table):
if conn is None:
return False
raw_sqlite = getattr(conn, '_conn', None) if getattr(conn, 'is_sqlite', False) is True else None
if raw_sqlite is not None:
deadline = time.monotonic() + DASHBOARD_QUERY_TIMEOUT_SEC
raw_sqlite.set_progress_handler(lambda: 1 if time.monotonic() >= deadline else 0, 10000)
try:
exists = conn.table_exists(table)
if getattr(conn, 'is_postgres', False):
conn.commit()
return exists
except Exception:
if getattr(conn, 'is_postgres', False):
try:
conn.rollback()
except Exception:
pass
return False
finally:
if raw_sqlite is not None:
raw_sqlite.set_progress_handler(None, 0)
def json_extract_sql(column, path):
if DASHBOARD_DB_DIALECT == 'postgres':
parts = str(path or '').lstrip('$.').split('.')
pg_path = ','.join(part for part in parts if part)
return f"(NULLIF({column}, '')::jsonb #>> '{{{pg_path}}}')"
return f"json_extract({column}, '{path}')"
def today_sql():
return "CURRENT_DATE::text" if DASHBOARD_DB_DIALECT == 'postgres' else "date('now')"
def finding_classification_sql(alias='f'):
prefix = f'{alias}.' if alias else ''
detector = f"LOWER(COALESCE({prefix}detector_name, ''))"
credential = f"LOWER(COALESCE({prefix}credential_kind, ''))"
return f'''
CASE
WHEN {detector} IN ('googleai', 'googleaistudio', 'openai', 'anthropic', 'deepseek', 'openrouter', 'groq', 'replicate', 'xai', 'huggingface', 'qwendashscope', 'qwen_dashscope', 'qwen', 'dashscope', 'kimimoonshot', 'moonshotai', 'moonshot', 'kimi', 'zaiglm', 'github', 'githuboauth2', 'gitlab', 'aws', 'gcp', 'gcpapplicationdefaultcredentials', 'azure', 'azureopenai', 'azurecontainerregistry') THEN 1
WHEN {credential} IN ('google_ai_api_key', 'google_ai_studio_api_key', 'qwen_dashscope_api_key', 'kimi_moonshot_api_key', 'glm_api_key', 'dockerhub_pat') THEN 1
ELSE 0
END
'''
def finding_service_sql(alias='f'):
prefix = f'{alias}.' if alias else ''
detector = f"LOWER(COALESCE({prefix}detector_name, ''))"
credential = f"LOWER(COALESCE({prefix}credential_kind, ''))"
return f'''
CASE
WHEN {detector} IN ('googleai', 'googleaistudio') THEN 'gemini'
WHEN {credential} IN ('google_ai_api_key', 'google_ai_studio_api_key') THEN 'gemini'
WHEN {detector} = 'openai' THEN 'openai'
WHEN {detector} = 'anthropic' THEN 'anthropic'
WHEN {detector} = 'deepseek' THEN 'deepseek'
WHEN {detector} = 'openrouter' THEN 'openrouter'
WHEN {detector} = 'groq' THEN 'groq'
WHEN {detector} = 'replicate' THEN 'replicate'
WHEN {detector} = 'xai' THEN 'xai'
WHEN {detector} = 'huggingface' THEN 'huggingface'
WHEN {detector} IN ('qwendashscope', 'qwen_dashscope', 'qwen', 'dashscope') THEN 'qwen'
WHEN {credential} = 'qwen_dashscope_api_key' THEN 'qwen'
WHEN {detector} IN ('kimimoonshot', 'moonshotai', 'moonshot', 'kimi') THEN 'kimi'
WHEN {credential} = 'kimi_moonshot_api_key' THEN 'kimi'
WHEN {detector} = 'zaiglm' THEN 'zai'
WHEN {credential} = 'glm_api_key' THEN 'zai'
WHEN {detector} IN ('github', 'githuboauth2') THEN 'github'
WHEN {detector} = 'gitlab' THEN 'gitlab'
WHEN {detector} = 'aws' THEN 'aws'
WHEN {detector} IN ('gcp', 'gcpapplicationdefaultcredentials') THEN 'gcp'
WHEN {detector} IN ('azure', 'azureopenai', 'azurecontainerregistry') THEN 'azure'
WHEN {credential} = 'dockerhub_pat' THEN 'dockerhub'
ELSE 'noise'
END
'''
def finding_noise_reason_sql(alias='f'):
prefix = f'{alias}.' if alias else ''
detector = f"LOWER(COALESCE({prefix}detector_name, ''))"
secret_hash = f"COALESCE({prefix}secret_hash, '')"
return f'''
CASE
WHEN {finding_classification_sql(alias)} = 1 THEN 'keycheckable'
WHEN {detector} = 'dockerhub' THEN 'dockerhub_non_pat_or_missing_username'
WHEN {detector} IN ('uri', 'jdbc', 'postgres', 'mongodb', 'sqlserver') THEN 'connection_string_or_url'
WHEN {detector} IN ('box', 'circle', 'flatio', 'roaring', 'linkpreview') THEN 'generic_detector_noise'
WHEN {secret_hash} = '' THEN 'missing_secret_identity'
ELSE 'no_checker_or_generic_secret'
END
'''
def keycheckable_findings_view_sql():
return f'''
SELECT
f.id, f.source, f.query, f.detector_name, f.secret_hash,
{finding_classification_sql('f')} AS is_keycheckable,
{finding_service_sql('f')} AS validation_service,
{finding_noise_reason_sql('f')} AS noise_reason
FROM findings f
'''
def keycheckable_backlog_sql(where=''):
where_clause = f'WHERE {where}' if where else ''
latest_keychecks = latest_keycheck_view_sql()
return f'''
WITH classified AS ({keycheckable_findings_view_sql()}),
checked_hashes AS (
SELECT service,
COALESCE(NULLIF(secret_hash, ''), NULLIF(key_hash, ''), NULLIF(key_masked, '')) AS checked_hash,
MAX(CASE WHEN status_group = 'alive' THEN 1 ELSE 0 END) AS has_alive
FROM ({latest_keychecks})
WHERE COALESCE(NULLIF(secret_hash, ''), NULLIF(key_hash, ''), NULLIF(key_masked, '')) IS NOT NULL
GROUP BY service, checked_hash
)
SELECT source, query, validation_service, detector_name,
COUNT(*) AS raw_findings,
COUNT(DISTINCT NULLIF(secret_hash, '')) AS unique_secrets,
COUNT(DISTINCT CASE WHEN is_keycheckable = 1 THEN NULLIF(secret_hash, '') END) AS keycheckable_unique,
COUNT(DISTINCT CASE WHEN is_keycheckable = 0 THEN NULLIF(secret_hash, '') END) AS noise_unique,
COUNT(DISTINCT CASE WHEN is_keycheckable = 1 AND checked_hashes.checked_hash IS NOT NULL THEN NULLIF(secret_hash, '') END) AS checked_unique,
COUNT(DISTINCT CASE WHEN is_keycheckable = 1 AND checked_hashes.has_alive = 1 THEN NULLIF(secret_hash, '') END) AS alive_unique,
COUNT(DISTINCT CASE WHEN is_keycheckable = 1 AND checked_hashes.checked_hash IS NULL THEN NULLIF(secret_hash, '') END) AS pending_unique
FROM classified
LEFT JOIN checked_hashes
ON checked_hashes.service = classified.validation_service
AND checked_hashes.checked_hash = classified.secret_hash
{where_clause}
GROUP BY source, query, validation_service, detector_name
'''
def scalar(conn, sql, params=None, default=0):
df = query_df(conn, sql, params)
if df.empty:
return default
return df.iloc[0, 0]
def current_queue_counts(queue_dir):
rows = []
for source in SOURCES:
platform = 'docker' if source == 'dockerhub' else source
todo_file = os.path.join(queue_dir, f'todo_{platform}.txt')
checked_file = os.path.join(queue_dir, f'checked_{platform}.txt')
counts = queue_counts(todo_file, checked_file)
if counts['todo_count'] or counts['checked_count'] or os.path.exists(todo_file) or os.path.exists(checked_file):
rows.append({
'source': source,
'todo': counts['todo_count'],
'checked': counts['checked_count'],
'todo_file': todo_file,
'checked_file': checked_file,
})
return pd.DataFrame(rows)
def queue_backlog(queue_dir):
df = current_queue_counts(queue_dir)
if df.empty:
return 0
return int(df['todo'].fillna(0).sum())
def disk_free_gb(path):
target = path if path and os.path.exists(path) else os.path.abspath(os.path.splitdrive(path or os.getcwd())[0] + os.sep)
try:
return round(shutil.disk_usage(target).free / (1024 ** 3), 2)
except OSError:
return 0
def scan_slots_df(scan_limiter_db):
if not scan_limiter_db or not os.path.exists(scan_limiter_db):
return pd.DataFrame()
try:
uri = 'file:' + scan_limiter_db.replace('\\', '/') + '?mode=ro'
conn = sqlite3.connect(uri, uri=True)
conn.row_factory = sqlite3.Row
columns = {row[1] for row in conn.execute('PRAGMA table_info(scan_slots)').fetchall()}
slot_kind = "COALESCE(slot_kind, 'base') AS slot_kind" if 'slot_kind' in columns else "'base' AS slot_kind"
rows = pd.read_sql_query(f'''
SELECT owner_source, owner_pid, owner_thread, {slot_kind}, command,
acquired_at, updated_at
FROM scan_slots
ORDER BY acquired_at
''', conn)
conn.close()
if not rows.empty:
now = datetime.now().timestamp()
rows['age_sec'] = (now - rows['acquired_at']).round(0).astype(int)
return rows
except Exception:
return pd.DataFrame()
def load_runner_state(state_file):
path = state_file
if not os.path.exists(path):
return {}, path
try:
with open(path, 'r', encoding='utf-8') as f:
return json.load(f), path
except (OSError, json.JSONDecodeError):
return {}, path
def parse_datetime(value):
if not value:
return None
text = str(value).strip()
for candidate in (text, text.replace('Z', '+00:00')):
try:
return datetime.fromisoformat(candidate)
except ValueError:
continue
return None
def human_age(value):
dt = parse_datetime(value)
if not dt:
return ''
now = datetime.now(dt.tzinfo) if dt.tzinfo else datetime.now()
seconds = max(0, int((now - dt).total_seconds()))
if seconds < 60:
return f'{seconds}s ago'
minutes = seconds // 60
if minutes < 60:
return f'{minutes}m ago'
hours = minutes // 60
if hours < 48:
return f'{hours}h {minutes % 60}m ago'
days = hours // 24
return f'{days}d {hours % 24}h ago'
def read_tail(path, lines=80):
if not path or not os.path.exists(path):
return []
max_lines = max(1, int(lines or 80))
try:
with open(path, 'rb') as f:
f.seek(0, os.SEEK_END)
size = f.tell()
position = max(0, size - MAX_LOG_TAIL_BYTES)
f.seek(position)
data = f.read(MAX_LOG_TAIL_BYTES)
if position and data:
newline = data.find(b'\n')
data = data[newline + 1:] if newline >= 0 else b''
text = data.decode('utf-8', errors='replace')
return text.splitlines(keepends=True)[-max_lines:]
except OSError:
return []
def parse_supervisor_status(log_dir):
path = os.path.join(log_dir, 'supervisor.status.txt')
rows = []
if not os.path.exists(path):
return pd.DataFrame(rows), path
headers = None
for line in read_tail(path, 80):
if '|' not in line or line.lstrip().startswith('-'):
continue
parts = [part.strip() for part in line.split('|')]
lowered = [part.lower() for part in parts]
if lowered and lowered[0] == 'source' and 'status' in lowered:
headers = lowered
continue
if headers and len(parts) >= len(headers):
item = dict(zip(headers, parts))
rows.append({
'source': item.get('source', ''),
'runtime_status': item.get('status', ''),
'desired': item.get('desired', ''),
'pid': item.get('pid', ''),
'mode': item.get('mode', ''),
'up': item.get('up', ''),
'exit': item.get('exit', ''),
'next': item.get('next', ''),
'restarts': item.get('rs', item.get('restarts', '')),
'auth': item.get('auth', ''),
})
continue
if len(parts) < 9 or parts[0] in ('', 'Type `help` for commands. Use `command <source>` for full log/state paths.'):
continue
source = parts[0]
if source == 'source':
continue
has_auth_column = len(parts) >= 10
rows.append({
'source': source,
'runtime_status': parts[1],
'desired': '',
'pid': parts[2],
'mode': parts[3],
'up': parts[4],
'exit': parts[5],
'next': parts[6],
'restarts': parts[7],
'auth': parts[8] if has_auth_column else '',
})
return pd.DataFrame(rows), path
def load_per_source_states(log_dir):
state_dir = os.path.normpath(os.path.join(log_dir, '..', 'state'))
rows = []
for source in RUNTIME_SOURCES:
path = os.path.join(state_dir, f'runner_state_{source}.json')
if not os.path.exists(path):
continue
try:
with open(path, 'r', encoding='utf-8') as f:
state = json.load(f)
except (OSError, json.JSONDecodeError):
continue
item = (state.get('sources') or {}).get(source) or {}
rows.append({
'source': source,
'last_query': item.get('last_query'),
'state_status': item.get('last_status'),
'last_started_at': item.get('last_started_at'),
'last_started_age': human_age(item.get('last_started_at')),
'last_completed_at': item.get('last_completed_at'),
'last_completed_age': human_age(item.get('last_completed_at')),
'cycles': item.get('cycles'),
'last_scanned': item.get('last_scanned'),
'last_auth': item.get('last_auth'),
})
return pd.DataFrame(rows)
def latest_cycle_df(conn):
return query_df(conn, '''
SELECT source, status AS db_status, query AS db_query, started_at AS db_started_at,
ended_at AS db_ended_at, scanned_count AS db_scanned, findings_count AS db_findings,
error_count AS db_errors, skipped_count AS db_skipped, duration_sec AS db_duration_sec
FROM source_cycles
WHERE id IN (SELECT MAX(id) FROM source_cycles GROUP BY source)
''')
def runtime_source_health(conn, log_dir):
runtime_df, status_path = parse_supervisor_status(log_dir)
states_df = load_per_source_states(log_dir)
latest_df = latest_cycle_df(conn)
sources = sorted(set(RUNTIME_SOURCES)
| set(runtime_df['source'].tolist() if not runtime_df.empty else [])
| set(states_df['source'].tolist() if not states_df.empty else [])
| set(latest_df['source'].tolist() if not latest_df.empty else []))
rows = pd.DataFrame({'source': sources})
for df in (runtime_df, states_df, latest_df):
if not df.empty:
rows = rows.merge(df, on='source', how='left')
log_rows = []
for source in sources:
log_path = os.path.join(log_dir, f'{source}.log')
log_rows.append({
'source': source,
'log_path': log_path if os.path.exists(log_path) else '',
'log_updated': datetime.fromtimestamp(os.path.getmtime(log_path)).isoformat(timespec='seconds') if os.path.exists(log_path) else '',
'log_age': human_age(datetime.fromtimestamp(os.path.getmtime(log_path)).isoformat(timespec='seconds')) if os.path.exists(log_path) else '',
'log_bytes': os.path.getsize(log_path) if os.path.exists(log_path) else 0,
})
rows = rows.merge(pd.DataFrame(log_rows), on='source', how='left')
def classify(row):
runtime = str(row.get('runtime_status') or '').lower()
if runtime in ('running', 'waiting', 'blocked', 'paused', 'backoff', 'done', 'failed', 'stopped', 'disabled'):
return runtime
if row.get('log_path'):
return 'has logs'
return 'no data'
rows['health'] = rows.apply(classify, axis=1)
preferred = [
'source', 'health', 'runtime_status', 'desired', 'pid', 'mode', 'up', 'exit', 'next', 'restarts', 'auth',
'state_status', 'last_query', 'last_started_age', 'last_completed_age', 'last_scanned',
'db_status', 'db_query', 'db_scanned', 'db_findings', 'db_errors', 'log_age', 'log_bytes',
]
existing = [column for column in preferred if column in rows.columns]
return rows[existing], status_path
def show_metrics(metrics):
cols = st.columns(len(metrics))
for col, (label, value) in zip(cols, metrics):
col.metric(label, value)
def format_pct(value):
try:
return f'{float(value) * 100:.2f}%'
except (TypeError, ValueError):
return '0.00%'
def display_df(df, height=None):
if df.empty:
st.info('No data yet')
return
safe_secret_metadata = {
'redacted_secret', 'secret_hash', 'detector_secret_hash', 'unique_secrets',
'unique_secrets_count', 'secrets_found', 'credential_kind',
'credential_confidence', 'required_context_missing',
}
blocked = []
for column in df.columns:
name = str(column).lower()
if name in safe_secret_metadata:
continue
if (
name.startswith('raw')
or name in {'config_json', 'evidence_json', 'credential', 'credential_value'}
or 'password' in name
or name == 'token'
or name.endswith('_token')
):
blocked.append(column)
df = df.drop(columns=blocked, errors='ignore')
endpoint_columns = [
column for column in df.columns
if str(column).lower() == 'endpoint' or str(column).lower().endswith('_endpoint')
]
if endpoint_columns:
df = df.copy()
for column in endpoint_columns:
df[column] = df[column].map(
lambda value: value if pd.isna(value) else sanitize_endpoint(value)
)
if 'resource' in df.columns:
adc_rows = pd.Series(False, index=df.index)
for detector_column in ('detector_name', 'detector'):
if detector_column in df.columns:
adc_rows |= df[detector_column].fillna('').astype(str).str.lower().eq(
'gcpapplicationdefaultcredentials'
)
if 'credential_kind' in df.columns:
adc_rows |= df['credential_kind'].fillna('').astype(str).str.lower().eq(
'application_default_credentials'
)
if adc_rows.any():
df = df.copy()
df.loc[adc_rows, 'resource'] = ''
if 'redacted_secret' in df.columns:
df = df.copy()
df['redacted_secret'] = df['redacted_secret'].map(
lambda value: '***REDACTED***' if pd.notna(value) and str(value) else ''
)
if height is None:
st.dataframe(df, width='stretch')
else:
st.dataframe(df, width='stretch', height=height)
def latest_keycheck_view_sql():
return '''
SELECT kr.*,
COALESCE(NULLIF(kr.key_hash, ''), NULLIF(kr.secret_hash, ''), NULLIF(kr.key_masked, '')) AS key_identity,
1 AS latest_rank
FROM keycheck_current_state state
JOIN keycheck_results kr ON kr.id = state.last_result_id
'''
def validation_access_tier_sql(alias='kr'):
prefix = f'{alias}.' if alias else ''
service = f"LOWER(COALESCE({prefix}service, ''))"
status = f"UPPER(COALESCE({prefix}status, ''))"
group = f"LOWER(COALESCE({prefix}status_group, ''))"
metadata = f"COALESCE({prefix}metadata_json, '{{}}')"
llm_probe_status = json_extract_sql(metadata, '$.llm_probe_status')
probe_status = json_extract_sql(metadata, '$.probe.status')
deployment_count = json_extract_sql(metadata, '$.deployment_count')
route_probe = json_extract_sql(metadata, '$.route_probe')
foundry_route_probe = json_extract_sql(metadata, '$.foundry_route_probe')
return f'''
CASE
WHEN {group} = 'no_balance' THEN 'no_quota'
WHEN {status} IN ('LIMITED', 'RATE_LIMITED', 'VALID_RATE_LIMITED') THEN 'quota_limited'
WHEN {service} = 'openai' AND {status} = 'ALIVE' THEN 'usable_llm'
WHEN {service} IN ('anthropic', 'deepseek', 'kimi', 'openrouter') AND {status} = 'VALID' THEN 'usable_llm'
WHEN {service} IN ('groq', 'qwen', 'xai') AND {status} = 'VALID'
AND {llm_probe_status} = 'GENERATION_OK' THEN 'usable_llm'
WHEN {service} = 'gemini' AND {status} = 'VALID'
AND {probe_status} = 'GENERATION_OK' THEN 'usable_llm'
WHEN {service} = 'gcp' AND {status} = 'VERTEX' THEN 'usable_llm'
WHEN {service} = 'aws' AND {status} = 'BEDROCK' THEN 'usable_llm'
WHEN {service} = 'azure' AND {status} = 'VALID'
AND COALESCE(CAST({deployment_count} AS INTEGER), 0) > 0
AND {route_probe} = 'accepted_auth_route' THEN 'usable_llm'
WHEN {service} = 'azure' AND {status} = 'FOUNDRY'
AND {foundry_route_probe} = 'accepted' THEN 'usable_llm'
WHEN {group} = 'alive' THEN 'alive_unproven_llm'
WHEN {group} = 'limited' THEN 'quota_limited'
WHEN {group} = 'no_context' THEN 'missing_context'
ELSE {group}
END
'''
def as_utc(value):
if not isinstance(value, datetime):
raise ValueError('Reporting timestamps must be datetime values.')
if value.tzinfo is None:
return value.replace(tzinfo=timezone.utc)
return value.astimezone(timezone.utc)
def reporting_window(preset, now=None, custom_start=None, custom_end=None):
end = as_utc(now or datetime.now(timezone.utc))
if preset in REPORTING_PRESETS:
start = end - REPORTING_PRESETS[preset]
elif preset == 'Custom':
if custom_start is None or custom_end is None:
raise ValueError('Choose both custom UTC timestamps.')
start = as_utc(custom_start)
end = as_utc(custom_end)
else:
raise ValueError('Unknown reporting window.')
if end <= start:
raise ValueError('The end of the reporting window must be later than the start.')
return start, end
def utc_parameter(value):
return as_utc(value).isoformat(timespec='seconds')
def _secret_from_payload(value, depth=0):
if depth > 4:
return None
if isinstance(value, dict):
lowered = {str(key).lower(): item for key, item in value.items()}
for name in ('rawv2', 'raw_v2', 'raw', 'secret', 'api_key', 'apikey', 'access_token'):
candidate = lowered.get(name)
if isinstance(candidate, str) and candidate.strip():
return candidate.strip()
for item in value.values():
candidate = _secret_from_payload(item, depth + 1)
if candidate:
return candidate
elif isinstance(value, list):
for item in value[:100]:
candidate = _secret_from_payload(item, depth + 1)
if candidate:
return candidate
return None
def _credential_like(text):
lowered = text.lower()
known_prefixes = (
'sk-', 'sk_', 'ghp_', 'github_pat_', 'glpat-', 'hf_', 'gsk_', 'xai-',
'sk-or-', 'r8_', 'npm_', 'akia', 'asia', 'aiza', 'eyj',
)
if lowered.startswith(known_prefixes):
return True
if len(text) < 20 or any(character.isspace() for character in text):
return False
if text.startswith(('http://', 'https://', 'git@')) or any(character in text for character in ('/', '\\', '@')):
return False
if re.fullmatch(r'[0-9a-fA-F]{40}', text) or re.fullmatch(
r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}', text):
return False
return bool(re.fullmatch(r'[A-Za-z0-9_.:+\-=]+', text))
def normalize_lookup(text):
value = str(text or '').strip()
if not value:
raise ValueError('Paste a key, hash, finding ID/UID, target, path, or commit.')
if len(value) > LOOKUP_MAX_INPUT_CHARS:
raise ValueError('Lookup input is too large.')
extracted = None
if value[:1] in ('{', '['):
try:
extracted = _secret_from_payload(json.loads(value))
except (TypeError, ValueError, json.JSONDecodeError):
extracted = None
if not extracted and ('\n' in value or '\r' in value):
match = re.search(r'(?im)^\s*(?:rawv2|raw|secret|api[_ -]?key)\s*[:=]\s*["\']?([^\s"\']+)', value)
extracted = match.group(1) if match else None
if extracted:
return {'kind': 'digest', 'digest': hashlib.sha256(extracted.encode('utf-8')).hexdigest()}
finding_id = re.fullmatch(r'(?i)(?:finding\s*[:#]?\s*)?(\d+)', value)
if finding_id:
return {'kind': 'finding_id', 'finding_id': int(finding_id.group(1))}
if re.fullmatch(r'[0-9a-fA-F]{64}', value):
return {'kind': 'digest', 'digest': value.lower()}
if re.fullmatch(r'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}', value):
return {'kind': 'identity', 'identity': value}
if _credential_like(value):
return {'kind': 'digest', 'digest': hashlib.sha256(value.encode('utf-8')).hexdigest()}
if '\n' in value or '\r' in value:
raise ValueError('Could not identify a credential in the pasted finding.')
if len(value) < 3:
raise ValueError('Metadata lookup needs at least three characters.')
if len(value) > 512:
raise ValueError('Metadata lookup is limited to 512 characters.')
return {'kind': 'metadata', 'text': value}
def escaped_like(value):
return '%' + str(value).replace('!', '!!').replace('%', '!%').replace('_', '!_') + '%'
def period_summary_df(conn, start, end):
access_tier = validation_access_tier_sql('r')
return query_df(conn, f'''
WITH bounds AS (
SELECT CAST(? AS timestamptz) AS start_at, CAST(? AS timestamptz) AS end_at
), period_scans AS (
SELECT COUNT(*) AS scans,
COALESCE(SUM(ts.findings_count), 0) AS findings,
COALESCE(SUM(ts.error_count), 0) AS errors
FROM target_scans ts CROSS JOIN bounds b
WHERE ts.ended_at::timestamptz >= b.start_at
AND ts.ended_at::timestamptz < b.end_at
), period_checks AS (
SELECT COUNT(*) AS checks
FROM keycheck_results kr CROSS JOIN bounds b
WHERE kr.checked_at::timestamptz >= b.start_at
AND kr.checked_at::timestamptz < b.end_at
), period_discovery AS (
SELECT COALESCE(SUM(sc.queued_new_count), 0) AS queued_new,
COALESCE(SUM(sc.queued_updated_count), 0) AS queued_updated
FROM source_cycles sc CROSS JOIN bounds b
WHERE sc.started_at::timestamptz >= b.start_at
AND sc.started_at::timestamptz < b.end_at
), ranked_alive AS (
SELECT r.id, r.credential_id, r.checked_at,
ROW_NUMBER() OVER (
PARTITION BY r.credential_id
ORDER BY r.checked_at::timestamptz, r.id
) AS alive_rank
FROM keycheck_results r
WHERE r.credential_id IS NOT NULL
AND r.status_group = 'alive'
), ranked_usable AS (
SELECT r.id, r.credential_id, r.checked_at,
ROW_NUMBER() OVER (
PARTITION BY r.credential_id
ORDER BY r.checked_at::timestamptz, r.id
) AS usable_rank
FROM keycheck_results r
WHERE r.credential_id IS NOT NULL
AND ({access_tier}) = 'usable_llm'
), period_new_alive AS (
SELECT COUNT(*) AS credentials
FROM ranked_alive r CROSS JOIN bounds b
WHERE r.alive_rank = 1
AND r.checked_at::timestamptz >= b.start_at
AND r.checked_at::timestamptz < b.end_at
), period_new_usable AS (
SELECT COUNT(*) AS credentials
FROM ranked_usable r CROSS JOIN bounds b
WHERE r.usable_rank = 1
AND r.checked_at::timestamptz >= b.start_at
AND r.checked_at::timestamptz < b.end_at
)
SELECT ps.scans, ps.findings, ps.errors, pc.checks,
pd.queued_new, pd.queued_updated,
pna.credentials AS new_alive, pnu.credentials AS new_usable,
(SELECT COUNT(*) FROM keycheck_current_state WHERE status_group = 'alive') AS alive_now,
(SELECT COUNT(*)
FROM keycheck_current_state s
JOIN keycheck_results r ON r.id = s.last_result_id
WHERE s.status_group = 'alive' AND ({access_tier}) = 'usable_llm') AS usable_llm_now,
(SELECT COUNT(*) FROM target_queue WHERE status IN ('pending', 'deferred')) AS target_backlog,
(SELECT COUNT(*) FROM keycheck_candidates WHERE state IN ('pending', 'deferred', 'leased')) AS keycheck_backlog
FROM period_scans ps CROSS JOIN period_checks pc CROSS JOIN period_discovery pd
CROSS JOIN period_new_alive pna CROSS JOIN period_new_usable pnu
''', [utc_parameter(start), utc_parameter(end)])
def source_activity_df(conn, start, end):
return query_df(conn, '''
WITH bounds AS (
SELECT CAST(? AS timestamptz) AS start_at, CAST(? AS timestamptz) AS end_at
), scan_activity AS (
SELECT ts.source, COUNT(*) AS scans,
COALESCE(SUM(ts.findings_count), 0) AS findings,
COALESCE(SUM(ts.error_count), 0) AS errors,
MAX(ts.ended_at) AS latest_scan
FROM target_scans ts CROSS JOIN bounds b
WHERE ts.ended_at::timestamptz >= b.start_at
AND ts.ended_at::timestamptz < b.end_at
GROUP BY ts.source
), cycle_activity AS (
SELECT sc.source,
COALESCE(SUM(sc.queued_new_count), 0) AS queued_new,
COALESCE(SUM(sc.queued_updated_count), 0) AS queued_updated,
MAX(sc.started_at) AS latest_cycle
FROM source_cycles sc CROSS JOIN bounds b
WHERE sc.started_at::timestamptz >= b.start_at
AND sc.started_at::timestamptz < b.end_at
GROUP BY sc.source
), sources AS (
SELECT source FROM scan_activity
UNION
SELECT source FROM cycle_activity
)
SELECT s.source, COALESCE(sa.scans, 0) AS scans,
COALESCE(sa.findings, 0) AS findings,
COALESCE(sa.errors, 0) AS errors,
COALESCE(ca.queued_new, 0) AS queued_new,
COALESCE(ca.queued_updated, 0) AS queued_updated,
GREATEST(sa.latest_scan, ca.latest_cycle) AS latest
FROM sources s
LEFT JOIN scan_activity sa ON sa.source = s.source
LEFT JOIN cycle_activity ca ON ca.source = s.source
ORDER BY findings DESC, scans DESC, s.source
LIMIT 50
''', [utc_parameter(start), utc_parameter(end)])
def new_alive_breakdown_df(conn, start, end):
access_tier = validation_access_tier_sql('kr')
return query_df(conn, f'''
WITH bounds AS (
SELECT CAST(? AS timestamptz) AS start_at, CAST(? AS timestamptz) AS end_at
), ranked_alive AS (
SELECT kr.credential_id AS id, kr.service, kr.status, kr.checked_at,
ROW_NUMBER() OVER (
PARTITION BY kr.credential_id
ORDER BY kr.checked_at::timestamptz, kr.id
) AS alive_rank,
{access_tier} AS access_tier
FROM keycheck_results kr
WHERE kr.credential_id IS NOT NULL
AND kr.status_group = 'alive'
), recent AS (
SELECT ra.id, ra.service, ra.status, ra.checked_at, ra.access_tier
FROM ranked_alive ra CROSS JOIN bounds b
WHERE ra.alive_rank = 1
AND ra.checked_at::timestamptz >= b.start_at
AND ra.checked_at::timestamptz < b.end_at
)
SELECT r.service, r.status, r.access_tier,
COALESCE(origin.source, '(unknown)') AS source,
COUNT(*) AS credentials, MAX(r.checked_at) AS latest
FROM recent r
LEFT JOIN LATERAL (
SELECT kc.source
FROM keycheck_candidates kc
WHERE kc.credential_id = r.id
ORDER BY kc.id
LIMIT 1
) origin ON TRUE
GROUP BY r.service, r.status, r.access_tier, origin.source
ORDER BY credentials DESC, r.service, r.status, r.access_tier, source
LIMIT 100
''', [utc_parameter(start), utc_parameter(end)])
def pipeline_snapshot_df(conn):
return query_df(conn, '''
SELECT bundle_items, projection_items, keycheck_items, quarantine_items,
bundle_bytes, projection_bytes, keycheck_bytes, quarantine_bytes, updated_at
FROM pipeline_capacity
WHERE id = 1
''')
def lookup_findings_df(conn, lookup, limit=200):
kind = lookup.get('kind')
params = []
if kind == 'finding_id':
where = 'f.id = ?'
params.append(int(lookup['finding_id']))
elif kind == 'digest':
where = '''(
f.secret_hash = ? OR f.detector_secret_hash = ?
OR f.finding_uid = ? OR f.finding_fingerprint = ?
)'''
params.extend([lookup['digest']] * 4)
elif kind == 'identity':
where = '(f.finding_uid = ? OR f.finding_fingerprint = ?)'
params.extend([lookup['identity']] * 2)
elif kind == 'metadata':
pattern = escaped_like(lookup['text'])
where = '''
f.id >= (SELECT GREATEST(COALESCE(MAX(id), 0) - ?, 0) FROM findings)
AND (
f.source ILIKE ? ESCAPE '!' OR f.query ILIKE ? ESCAPE '!'
OR f.target ILIKE ? ESCAPE '!' OR f.detector_name ILIKE ? ESCAPE '!'
OR f.redacted_secret ILIKE ? ESCAPE '!' OR f.file_path ILIKE ? ESCAPE '!'
OR f.commit_hash ILIKE ? ESCAPE '!' OR f.provider ILIKE ? ESCAPE '!'
OR f.credential_kind ILIKE ? ESCAPE '!' OR ts.package_name ILIKE ? ESCAPE '!'
OR ts.package_version ILIKE ? ESCAPE '!' OR ts.package_filename ILIKE ? ESCAPE '!'
)
'''
params.extend([LOOKUP_METADATA_LIMIT, *([pattern] * 12)])
else:
return pd.DataFrame()
params.append(max(1, min(int(limit or 200), 500)))
return query_df(conn, f'''
SELECT f.id AS finding_id, f.finding_uid, f.created_at AS found_at,
f.source, f.query, f.target, f.detector_name, f.provider,
f.file_path, f.line_number, f.commit_hash, f.secret_hash,
ts.package_name, ts.package_version, ts.package_filename, ts.package_type
FROM findings f
LEFT JOIN target_scans ts ON ts.id = f.target_scan_id
WHERE {where}
ORDER BY f.id DESC
LIMIT ?
''', params)
def lookup_status_df(conn, lookup, findings=None, limit=100):
findings = findings if isinstance(findings, pd.DataFrame) else pd.DataFrame()
hashes = set()
finding_ids = set()
if not findings.empty:
if 'secret_hash' in findings:
hashes.update(str(value) for value in findings['secret_hash'].dropna() if str(value))
if 'finding_id' in findings:
finding_ids.update(int(value) for value in findings['finding_id'].dropna())
if lookup.get('kind') == 'digest':
hashes.add(lookup['digest'])
if lookup.get('kind') == 'finding_id':
finding_ids.add(int(lookup['finding_id']))
clauses = []
params = []
if hashes:
values = sorted(hashes)
placeholders = ','.join('?' for _ in values)
clauses.append(f"(r.secret_hash IN ({placeholders}) OR r.key_hash IN ({placeholders}))")
params.extend(values)
params.extend(values)
clauses.append(f'''EXISTS (
SELECT 1 FROM keycheck_candidates kc
WHERE kc.credential_id = s.credential_id AND kc.secret_hash IN ({placeholders})
)''')
params.extend(values)
if finding_ids:
values = sorted(finding_ids)
placeholders = ','.join('?' for _ in values)
clauses.append(f'r.finding_id IN ({placeholders})')
params.extend(values)
clauses.append(f'''EXISTS (
SELECT 1 FROM keycheck_candidates kc
WHERE kc.credential_id = s.credential_id AND kc.finding_id IN ({placeholders})
)''')
params.extend(values)
if lookup.get('kind') == 'metadata':
pattern = escaped_like(lookup['text'])
clauses.append('''(
r.key_masked ILIKE ? ESCAPE '!' OR r.source ILIKE ? ESCAPE '!'
OR r.query ILIKE ? ESCAPE '!' OR r.target ILIKE ? ESCAPE '!'
OR r.detector_name ILIKE ? ESCAPE '!'
)''')
params.extend([pattern] * 5)
if not clauses:
return pd.DataFrame()
access_tier = validation_access_tier_sql('r')
params.append(max(1, min(int(limit or 100), 200)))
return query_df(conn, f'''
SELECT s.credential_id, s.service, s.status, s.status_group,
{access_tier} AS access_tier, s.checked_at, s.recheck_after,
r.key_masked,
COALESCE(r.source, origin.source) AS source,
COALESCE(r.query, origin.query) AS query,
COALESCE(r.target, origin.target) AS target,
COALESCE(r.finding_id, origin.finding_id) AS finding_id,
COALESCE(r.detector_name, origin.detector_name) AS detector_name,
COALESCE(r.found_at, origin.found_at) AS found_at
FROM keycheck_current_state s
JOIN keycheck_results r ON r.id = s.last_result_id
LEFT JOIN LATERAL (
SELECT kc.source, kc.query, kc.target, kc.finding_id, kc.detector_name, kc.found_at
FROM keycheck_candidates kc
WHERE kc.credential_id = s.credential_id
ORDER BY (kc.finding_id IS NOT NULL) DESC, kc.id DESC
LIMIT 1
) origin ON TRUE
WHERE {' OR '.join(f'({clause})' for clause in clauses)}
ORDER BY s.checked_at DESC, s.credential_id
LIMIT ?
''', params)
def dashboard_search_is_safe(text):
text = str(text or '').strip()
return bool(
not text
or re.fullmatch(r'[0-9a-fA-F]{64}', text)
or len(text) < 20
or any(character.isspace() for character in text)
or '***' in text
or '...' in text
)
def finding_metadata_search(conn, text, limit=500):
text = str(text or '').strip()
if not text or not dashboard_search_is_safe(text):
return pd.DataFrame()
digest = text.lower() if re.fullmatch(r'[0-9a-fA-F]{64}', text) else ''
like = f'%{text}%'
hash_clause = 'f.secret_hash = ? OR' if digest else ''
params = ([digest] if digest else []) + [like] * 9 + [int(limit)]
return query_df(conn, f'''
SELECT f.id AS finding_id, f.created_at, f.source, f.query, f.target,
f.detector_name, f.redacted_secret, f.secret_hash,
f.file_path, f.line_number, f.commit_hash, f.source_timestamp,
ts.package_name, ts.package_version, ts.package_filename, ts.package_type,
f.target_scan_id, f.cycle_id, f.run_id
FROM (
SELECT id, created_at, source, query, target, detector_name, redacted_secret,
secret_hash, file_path, line_number, commit_hash, source_timestamp,
target_scan_id, cycle_id, run_id
FROM findings
ORDER BY id DESC
LIMIT 50000
) f
LEFT JOIN target_scans ts ON ts.id = f.target_scan_id
WHERE {hash_clause} f.redacted_secret LIKE ?
OR f.secret_hash LIKE ?
OR f.detector_name LIKE ?
OR f.source LIKE ?
OR f.query LIKE ?
OR f.target LIKE ?
OR f.file_path LIKE ?
OR f.commit_hash LIKE ?
OR ts.package_name LIKE ?
ORDER BY f.id DESC
LIMIT ?
''', params)
def github_archive_yield(conn, limit=2000):
rows = query_df(conn, '''
SELECT id, target, ended_at, findings_count, verified_findings_count
FROM target_scans
WHERE source = 'github_archive' AND status = 'found'
ORDER BY id DESC
LIMIT ?
''', [int(limit or 2000)])
if rows.empty:
return {}, pd.DataFrame(), pd.DataFrame()
scan_ids = [int(value) for value in rows['id'].dropna().tolist()]
finding_rows = query_df(conn, f'''
SELECT target_scan_id, detector_name
FROM findings
WHERE target_scan_id IN ({','.join('?' for _ in scan_ids)})
''', scan_ids) if scan_ids else pd.DataFrame()
findings_by_scan = {}
if not finding_rows.empty:
for scan_id, group in finding_rows.groupby('target_scan_id'):
findings_by_scan[int(scan_id)] = [str(value or '') for value in group['detector_name'].tolist()]
detectors = Counter()
target_rows = []
total_findings = 0
total_verified = 0
interesting_rows = 0
for _, row in rows.iterrows():
findings_count = int(row.get('findings_count') or 0)
verified_count = int(row.get('verified_findings_count') or 0)
total_findings += findings_count
total_verified += verified_count
target_interesting = 0
for detector in findings_by_scan.get(int(row.get('id') or 0), []):
detectors[detector] += 1
if detector.lower() in ARCHIVE_INTERESTING_DETECTORS:
interesting_rows += 1
target_interesting += 1
target_rows.append({
'target_scan_id': int(row.get('id') or 0),
'target': row.get('target'),
'ended_at': row.get('ended_at'),
'findings': findings_count,
'interesting_findings': target_interesting,
'verified_findings': verified_count,
})
detector_df = pd.DataFrame([
{
'detector': detector,
'rows': count,
'kind': 'interesting' if str(detector).lower() in ARCHIVE_INTERESTING_DETECTORS else 'noise_or_generic',
}
for detector, count in detectors.most_common(50)
])
target_df = pd.DataFrame(target_rows).sort_values(['interesting_findings', 'findings'], ascending=False).head(100)
summary = {
'found_targets': int(len(rows)),
'raw_findings': int(total_findings),
'interesting_findings': int(interesting_rows),
'noise_or_generic_findings': int(max(0, total_findings - interesting_rows)),
'verified_findings': int(total_verified),
}
return summary, detector_df, target_df
def keycheck_summary_df(keycheck_dir):
path = os.path.join(keycheck_dir, 'summary.tsv')
if not os.path.exists(path):
return pd.DataFrame(), path
try:
df = pd.read_csv(path, sep='\t')
except Exception:
return pd.DataFrame(), path
if 'updated_at' in df.columns:
df['file_updated_at'] = df['updated_at']
return df, path
def recent_keycheck_db_summary(conn, limit=10000):
result_source_expr = json_extract_sql('metadata_json', '$.result_source')
rows = query_df(conn, '''
SELECT id, service, status_group, status, checked_at, created_at,
{result_source_expr} AS result_source
FROM keycheck_results
ORDER BY id DESC
LIMIT ?
'''.format(result_source_expr=result_source_expr), [int(limit or 10000)])
if rows.empty:
return pd.DataFrame()
rows['result_source'] = rows['result_source'].fillna('api_check')
grouped = rows.groupby('service', dropna=False).agg(
db_recent_rows=('id', 'count'),
db_latest_id=('id', 'max'),
db_latest_checked=('checked_at', 'max'),
db_latest_created=('created_at', 'max'),
db_cached_rows=('result_source', lambda s: int((s == 'cached_status').sum())),
db_alive_rows=('status_group', lambda s: int((s == 'alive').sum())),
).reset_index()
return grouped
def keycheck_db_metric_summary(keycheck_dir):
rows = []
if not keycheck_dir or not os.path.isdir(keycheck_dir):
return pd.DataFrame(rows)
for service in sorted(os.listdir(keycheck_dir)):
path = os.path.join(keycheck_dir, service, 'db_write_metrics.jsonl')
if not os.path.exists(path):
continue
ok = failed = cached = total = 0
latest = ''
for line in read_tail(path, 2000):
try:
item = json.loads(line)
except ValueError:
continue
total += 1
ok += 1 if item.get('ok') else 0
failed += 0 if item.get('ok') else 1
cached += 1 if item.get('result_source') == 'cached_status' else 0
latest = max(latest, str(item.get('created_at') or ''))
rows.append({
'service': service,
'metric_rows_tail': total,
'db_write_ok_tail': ok,
'db_write_failed_tail': failed,
'cached_occurrence_tail': cached,
'db_metric_latest': latest,
})
return pd.DataFrame(rows)
def keycheck_pipeline_health(log_dir):
path = os.path.join(log_dir, 'keychecks.log')
lines = read_tail(path, 600)
if not lines:
return pd.DataFrame(), path
latest_start = ''
latest_exit = ''
current_service = ''
last_service = ''
db_locks = 0
processed = 0
skipped = 0
for line in lines:
text = line.strip()
if text.startswith('=== supervisor start') and 'source=keychecks' in text:
latest_start = text.replace('=== supervisor start ', '').split(' source=', 1)[0]
current_service = ''
processed = 0
skipped = 0
db_locks = 0
elif text.startswith('=== supervisor exit') and 'source=keychecks' in text:
latest_exit = text.replace('=== supervisor exit ', '').split(' source=', 1)[0]
current_service = ''
elif ': ' in text and 'keycheckers' in text and '.py' in text:
current_service = text.split(':', 1)[0]
last_service = current_service
elif 'Observability DB locked' in text or 'database is locked' in text:
db_locks += 1
elif text.startswith('Done. Processed=') or text.startswith('Processed='):
numbers = re.findall(r'(?:Processed|skipped)=([0-9]+)', text)
if numbers:
processed += int(numbers[0])
if len(numbers) > 1:
skipped += int(numbers[1])
row = {
'latest_start': latest_start,
'latest_exit': latest_exit,
'current_or_last_service': current_service or last_service,
'db_lock_messages_tail': db_locks,
'processed_tail': processed,
'skipped_tail': skipped,
'log_path': path,
}
return pd.DataFrame([row]), path
def _integer(value):
try:
if pd.isna(value):
return 0
return int(value)
except (TypeError, ValueError):
return 0
def _submit_dashboard_lookup():
submitted = st.session_state.get('dashboard_lookup_input', '')
try:
st.session_state['dashboard_lookup_request'] = normalize_lookup(submitted)
st.session_state['dashboard_lookup_error'] = ''
except ValueError as exc:
st.session_state.pop('dashboard_lookup_request', None)
st.session_state['dashboard_lookup_error'] = str(exc)
st.session_state['dashboard_lookup_input'] = ''
def _clear_dashboard_lookup():
st.session_state.pop('dashboard_lookup_request', None)
st.session_state.pop('dashboard_lookup_error', None)
st.session_state['dashboard_lookup_input'] = ''
def _dashboard_styles():
st.markdown('''
<style>
.block-container { max-width: 1440px; padding-top: 1.6rem; padding-bottom: 3rem; }
[data-testid="stSidebar"], [data-testid="stSidebarCollapsedControl"] { display: none; }
[data-testid="stToolbar"], .stDeployButton { display: none; }
div[data-testid="stMetric"] {
background: #f7f8f6;
border: 1px solid #dfe3dc;
border-top: 3px solid #405c46;
padding: 0.85rem 1rem;
min-height: 6.2rem;
}
div[data-testid="stMetricLabel"] { color: #536057; }
div[data-testid="stMetricValue"] { color: #172019; }
.truf-metrics {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(145px, 1fr));
gap: 0.65rem;
margin: 0.65rem 0;
}
.truf-metric {
background: #f7f8f6;
border: 1px solid #dfe3dc;
border-top: 3px solid #405c46;
padding: 0.72rem 0.85rem;
min-height: 4.7rem;
}
.truf-metric-label { color: #536057; font-size: 0.82rem; line-height: 1.15; }
.truf-metric-value { color: #172019; font-size: 1.55rem; font-weight: 650; line-height: 1.3; }
[data-testid="stForm"] { border: 1px solid #d8ddd6; background: #fbfcfa; padding: 0.65rem 0.8rem; }
h1, h2, h3 { letter-spacing: -0.025em; }
hr { border-color: #e1e5df; margin: 1.5rem 0; }
@media (max-width: 700px) {
.block-container { padding: 0.8rem 0.75rem 2rem; }
div[data-testid="stMetric"] { min-height: 5rem; padding: 0.65rem 0.75rem; }
.truf-metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem; }
.truf-metric { min-height: 4.2rem; padding: 0.6rem 0.7rem; }
.truf-metric-value { font-size: 1.3rem; }
}
</style>
''', unsafe_allow_html=True)
def _metric_grid(metrics):
cards = ''.join(
'<div class="truf-metric">'
f'<div class="truf-metric-label">{html.escape(str(label))}</div>'
f'<div class="truf-metric-value">{html.escape(str(value))}</div>'
'</div>'
for label, value in metrics
)
st.markdown(f'<div class="truf-metrics">{cards}</div>', unsafe_allow_html=True)
def page_simple_dashboard(conn, log_dir, work_dir, scan_limiter_db, max_active_scans):
_dashboard_styles()
title_col, refresh_col = st.columns([8, 1])
with title_col:
st.title('TRUF')
st.caption('Scanner and credential status / PostgreSQL read-only / UTC')
with refresh_col:
if st.button('Refresh', width='stretch'):
st.rerun()
st.subheader('Find a credential or finding')
with st.form('dashboard_lookup_form', clear_on_submit=False, border=False):
input_col, submit_col = st.columns([8, 1])
with input_col:
st.text_input(
'Lookup',
key='dashboard_lookup_input',
placeholder='Paste a key, SHA-256, finding ID/UID, URL, path, or commit',
label_visibility='collapsed',
)
with submit_col:
st.form_submit_button('Find', width='stretch', on_click=_submit_dashboard_lookup)
st.caption('Credential-like input is hashed immediately, cleared, and never queried as raw text.')
lookup_error = st.session_state.get('dashboard_lookup_error')
lookup = st.session_state.get('dashboard_lookup_request')
if lookup_error:
st.warning(lookup_error)
if lookup:
findings = lookup_findings_df(conn, lookup)
statuses = lookup_status_df(conn, lookup, findings)
result_col, clear_col = st.columns([8, 1])
with result_col:
st.markdown(f'**Lookup result:** {len(statuses)} current status row(s), {len(findings)} origin(s)')
with clear_col:
st.button('Clear', width='stretch', on_click=_clear_dashboard_lookup)
if statuses.empty and findings.empty:
st.info('No current status or finding origin matched this lookup.')
if not statuses.empty:
st.markdown('**Current status**')
status_columns = [
'service', 'status', 'status_group', 'access_tier', 'checked_at',
'source', 'query', 'target', 'detector_name', 'finding_id', 'found_at',
]
display_df(statuses[[column for column in status_columns if column in statuses]], height=260)
if not findings.empty:
st.markdown('**Origins**')
origins = findings.copy()
origins['identity'] = origins['secret_hash'].map(
lambda value: (str(value)[:12] + '...') if pd.notna(value) and str(value) else ''
)
origin_columns = [
'finding_id', 'identity', 'found_at', 'source', 'query', 'target',
'detector_name', 'provider', 'file_path', 'line_number', 'commit_hash',
'package_name', 'package_version', 'package_filename', 'finding_uid',
]
display_df(origins[[column for column in origin_columns if column in origins]], height=360)
st.divider()
st.subheader('Activity')
period = st.radio(
'Reporting window',
[*REPORTING_PRESETS, 'Custom'],
index=1,
horizontal=True,
label_visibility='collapsed',
)
now = datetime.now(timezone.utc).replace(microsecond=0)
custom_start = None
custom_end = None
if period == 'Custom':
default_start = now - timedelta(hours=24)
start_date_col, start_time_col, end_date_col, end_time_col = st.columns(4)
with start_date_col:
start_date = st.date_input('Start date (UTC)', value=default_start.date())
with start_time_col:
start_time = st.time_input('Start time (UTC)', value=default_start.time())
with end_date_col:
end_date = st.date_input('End date (UTC)', value=now.date())
with end_time_col:
end_time = st.time_input('End time (UTC)', value=now.time())
custom_start = datetime.combine(start_date, start_time, tzinfo=timezone.utc)
custom_end = datetime.combine(end_date, end_time, tzinfo=timezone.utc)
try:
start, end = reporting_window(period, now=now, custom_start=custom_start, custom_end=custom_end)
except ValueError as exc:
st.error(str(exc))
return
st.caption(f'{start:%Y-%m-%d %H:%M} to {end:%Y-%m-%d %H:%M} UTC')
summary = period_summary_df(conn, start, end)
summary_row = summary.iloc[0] if not summary.empty else {}
_metric_grid([
('Scans', _integer(summary_row.get('scans', 0))),
('Findings', _integer(summary_row.get('findings', 0))),
('Errors', _integer(summary_row.get('errors', 0))),
('Checks', _integer(summary_row.get('checks', 0))),
('New targets', _integer(summary_row.get('queued_new', 0))),
('Updated rescans', _integer(summary_row.get('queued_updated', 0))),
('New alive', _integer(summary_row.get('new_alive', 0))),
('New usable', _integer(summary_row.get('new_usable', 0))),
])
_metric_grid([
('Alive now', _integer(summary_row.get('alive_now', 0))),
('Usable LLM now', _integer(summary_row.get('usable_llm_now', 0))),
('Target queue now', _integer(summary_row.get('target_backlog', 0))),
('Keycheck queue now', _integer(summary_row.get('keycheck_backlog', 0))),
])
source_activity = source_activity_df(conn, start, end)
new_alive = new_alive_breakdown_df(conn, start, end)
source_col, alive_col = st.columns([1.2, 1], gap='large')
with source_col:
st.markdown('**Sources in period**')
if not source_activity.empty:
source_activity = source_activity.copy()
source_activity['findings / scan'] = source_activity.apply(
lambda row: round(_integer(row.get('findings')) / max(1, _integer(row.get('scans'))), 2),
axis=1,
)
display_df(source_activity, height=340)
with alive_col:
st.markdown('**Alive discovered in period**')
display_df(new_alive, height=340)
st.divider()
st.subheader('Runtime now')
st.caption('Current state is not restricted by the reporting window.')
slots = scan_slots_df(scan_limiter_db)
pipeline = pipeline_snapshot_df(conn)
pipeline_row = pipeline.iloc[0] if not pipeline.empty else {}
drive = os.path.splitdrive(work_dir or '')[0] or 'Scratch'
_metric_grid([
('Scan slots', f"{len(slots)}/{max_active_scans or '?'}"),
(f'{drive} free', f'{disk_free_gb(work_dir):.2f} GiB'),
('Bundle backlog', _integer(pipeline_row.get('bundle_items', 0))),
('Projection lag', _integer(pipeline_row.get('projection_items', 0))),
('Candidate capacity', _integer(pipeline_row.get('keycheck_items', 0))),
('Quarantine capacity', _integer(pipeline_row.get('quarantine_items', 0))),
])
runtime, _ = parse_supervisor_status(log_dir)
if not runtime.empty:
runtime = runtime[runtime['source'].isin(CORE_RUNTIME_SOURCES)].copy()
order = {name: index for index, name in enumerate([
'result-ingester', 'jsonl-projector', 'janitor', 'worker-api', 'github', 'gitlab',
'huggingface', 'dockerhub', 'package_git', 'keychecks',
])}
runtime['_order'] = runtime['source'].map(order).fillna(len(order))
runtime = runtime.sort_values('_order').drop(columns=['_order'])
runtime_columns = ['source', 'runtime_status', 'up', 'next', 'restarts']
display_df(runtime[[column for column in runtime_columns if column in runtime]], height=360)
else:
st.info('Supervisor status is not available yet.')
def page_overview(conn, results_dir, queue_dir, log_dir, work_dir, keycheck_dir, scan_limiter_db, max_active_scans):
st.header('Overview')
today_expr = today_sql()
totals = query_df(conn, '''
SELECT
COUNT(*) AS cycles,
COALESCE(SUM(scanned_count), 0) AS scanned,
COALESCE(SUM(found_count), 0) AS found_targets,
COALESCE(SUM(error_count), 0) AS error_targets,
COALESCE(SUM(skipped_count), 0) AS skipped,
COALESCE(SUM(findings_count), 0) AS findings
FROM source_cycles
''')
finding_totals = query_df(conn, 'SELECT COUNT(*) AS finding_rows FROM findings')
today = query_df(conn, '''
SELECT COALESCE(SUM(scanned_count), 0) AS scanned_today,
COALESCE(SUM(findings_count), 0) AS findings_today,
COALESCE(SUM(error_count), 0) AS errors_today
FROM source_cycles
WHERE started_at >= {today_expr}
'''.format(today_expr=today_expr))
runtime_health, status_path = runtime_source_health(conn, log_dir)
active_sources = int(runtime_health['runtime_status'].astype(str).str.lower().eq('running').sum()) if not runtime_health.empty and 'runtime_status' in runtime_health else 0
slots = scan_slots_df(scan_limiter_db)
validation_available = table_exists(conn, 'keycheck_current_state')
load_unique_totals = st.checkbox('Load unique scanner totals (slower)', value=False)
load_alive_total = st.checkbox('Load all-time alive key count (slower)', value=False)
if load_unique_totals:
unique_totals = query_df(conn, '''
SELECT COUNT(DISTINCT NULLIF(secret_hash, '')) AS unique_secrets,
COUNT(DISTINCT NULLIF(finding_fingerprint, '')) AS unique_findings
FROM findings
''')
urow = unique_totals.iloc[0] if not unique_totals.empty else {}
unique_secrets = int(urow.get('unique_secrets', 0))
unique_findings = int(urow.get('unique_findings', 0))
else:
unique_secrets = 'off'
unique_findings = 'off'
if validation_available:
alive_total = scalar(conn, "SELECT COUNT(*) FROM keycheck_current_state WHERE status_group = 'alive'") if load_alive_total else 'off'
alive_today = scalar(conn, f"SELECT COUNT(*) FROM keycheck_current_state WHERE status_group = 'alive' AND checked_at >= {today_expr}")
else:
alive_total = 0
alive_today = 0
row = totals.iloc[0] if not totals.empty else {}
frow = finding_totals.iloc[0] if not finding_totals.empty else {}
trow = today.iloc[0] if not today.empty else {}
authoritative_queue_backlog = (
scalar(conn, "SELECT COUNT(*) FROM target_queue WHERE status IN ('pending','deferred')")
if table_exists(conn, 'target_queue') else queue_backlog(queue_dir)
)
show_metrics([
('Active sources', active_sources),
('Scan slots', f"{len(slots)}/{max_active_scans or '?'}"),
('Queue backlog', int(authoritative_queue_backlog or 0)),
('Scanned today', int(trow.get('scanned_today', 0))),
('Findings today', int(trow.get('findings_today', 0))),
('Alive keys total', alive_total if isinstance(alive_total, str) else int(alive_total or 0)),
('Alive rows today', int(alive_today or 0)),
('Errors today', int(trow.get('errors_today', 0))),
])
if table_exists(conn, 'pipeline_capacity'):
pipeline = query_df(conn, 'SELECT * FROM pipeline_capacity WHERE id = 1')
prow = pipeline.iloc[0] if not pipeline.empty else {}
show_metrics([
('Bundle backlog', int(prow.get('bundle_items', 0))),
('Projection lag', int(prow.get('projection_items', 0))),
('Keycheck candidates', int(prow.get('keycheck_items', 0))),
('Pipeline quarantine', int(prow.get('quarantine_items', 0))),
])
if table_exists(conn, 'pipeline_leases'):
leases = query_df(conn, '''
SELECT worker_name, state, heartbeat_at, lease_expires_at, last_error
FROM pipeline_leases ORDER BY worker_name
''')
st.caption('Pipeline worker leases')
display_df(leases, height=150)
st.caption(f"Scanner totals: cycles={int(row.get('cycles', 0))}, scanned={int(row.get('scanned', 0))}, findings={int(frow.get('finding_rows', 0))}, unique secrets={unique_secrets}, unique findings={unique_findings}. D free: {disk_free_gb(work_dir)} GB")
archive_summary, archive_detectors, archive_targets = github_archive_yield(conn)
if archive_summary:
st.subheader('GitHub Archive Yield')
show_metrics([
('Archive found targets', archive_summary['found_targets']),
('Archive raw findings', archive_summary['raw_findings']),
('Archive interesting', archive_summary['interesting_findings']),
('Archive noise/generic', archive_summary['noise_or_generic_findings']),
('Archive verified', archive_summary['verified_findings']),
])
col_archive_1, col_archive_2 = st.columns(2)
with col_archive_1:
st.caption('Detector split from redacted findings metadata; raw result payloads are not loaded.')
display_df(archive_detectors, height=320)
with col_archive_2:
st.caption('Targets ranked by interesting detector rows.')
display_df(archive_targets, height=320)
st.subheader('Keycheck PostgreSQL Current State And Compatibility Lag')
summary_df, summary_path = keycheck_summary_df(keycheck_dir)
db_summary = recent_keycheck_db_summary(conn)
metric_summary = keycheck_db_metric_summary(keycheck_dir)
if not summary_df.empty:
merged = summary_df.merge(db_summary, on='service', how='left') if not db_summary.empty else summary_df
if not metric_summary.empty:
merged = merged.merge(metric_summary, on='service', how='left')
preferred = [
'service', 'alive', 'alive_rate_limited', 'no_balance', 'no_quota', 'limited', 'network', 'dead', 'restricted',
'file_updated_at', 'db_latest_checked', 'db_latest_created', 'db_recent_rows', 'db_cached_rows',
'db_write_failed_tail', 'cached_occurrence_tail', 'output_dir',
]
display_df(merged[[column for column in preferred if column in merged.columns]], height=420)
st.caption(f'Current-state summary: {summary_path}')
else:
st.info('No keycheck summary.tsv found')
health_df, health_path = keycheck_pipeline_health(log_dir)
st.subheader('Keycheck Pipeline Health')
st.caption(health_path)
display_df(health_df, height=160)
if st.checkbox('Load keycheckable/noise totals (slower)', value=False):
classified_totals = query_df(conn, f'''
SELECT COUNT(*) AS raw_findings,
COUNT(DISTINCT NULLIF(secret_hash, '')) AS raw_unique,
COUNT(DISTINCT CASE WHEN is_keycheckable = 1 THEN NULLIF(secret_hash, '') END) AS keycheckable_unique,
COUNT(DISTINCT CASE WHEN is_keycheckable = 0 THEN NULLIF(secret_hash, '') END) AS noise_unique
FROM ({keycheckable_findings_view_sql()})
''')
crow = classified_totals.iloc[0] if not classified_totals.empty else {}
show_metrics([
('Raw unique findings', int(crow.get('raw_unique', 0))),
('Keycheckable unique', int(crow.get('keycheckable_unique', 0))),
('Noise unique', int(crow.get('noise_unique', 0))),
('Noise share', format_pct((int(crow.get('noise_unique', 0)) / int(crow.get('raw_unique', 1))) if int(crow.get('raw_unique', 0)) else 0)),
])
st.subheader('Runtime Source Health')
st.caption(f'Runtime status file: {status_path}')
display_df(runtime_health, height=420)
st.subheader('Active Scan Slots')
st.caption(scan_limiter_db)
display_df(slots[['owner_source', 'owner_pid', 'age_sec', 'command']] if not slots.empty else slots, height=260)
st.subheader('Per Source DB Aggregates')
source_df = query_df(conn, '''
SELECT
source,
COUNT(*) AS cycles,
SUM(fetched_count) AS fetched,
SUM(queued_new_count) AS queued_new,
SUM(queued_updated_count) AS queued_updated,
SUM(scanned_count) AS scanned,
SUM(found_count) AS found_targets,
SUM(error_count) AS error_targets,
SUM(skipped_count) AS skipped,
SUM(findings_count) AS findings,
SUM(verified_findings_count) AS verified_findings,
AVG(hit_rate) AS avg_hit_rate,
AVG(error_rate) AS avg_error_rate,
AVG(targets_per_hour) AS avg_targets_per_hour,
MAX(started_at) AS latest_cycle
FROM source_cycles
GROUP BY source
ORDER BY latest_cycle DESC
''')
if not source_df.empty:
source_df['avg_hit_rate'] = source_df['avg_hit_rate'].map(format_pct)
source_df['avg_error_rate'] = source_df['avg_error_rate'].map(format_pct)
display_df(source_df)
st.subheader('Current Queues')
display_df(current_queue_counts(queue_dir))
colv1, colv2 = st.columns(2)
with colv1:
st.subheader('Top Detectors (Recent)')
display_df(query_df(conn, '''
SELECT source, detector_name, COUNT(*) AS findings,
COUNT(DISTINCT NULLIF(secret_hash, '')) AS unique_secrets
FROM (
SELECT source, detector_name, secret_hash
FROM findings
ORDER BY id DESC
LIMIT 20000
)
GROUP BY source, detector_name
ORDER BY findings DESC
LIMIT 20
'''), height=360)
with colv2:
st.subheader('Top Useful Sources By Alive Keys (Recent)')
if validation_available:
display_df(query_df(conn, '''
SELECT source, service, COUNT(DISTINCT key_hash) AS alive_keys, COUNT(*) AS linked_findings
FROM (
SELECT source, service, key_hash, status_group
FROM keycheck_results
ORDER BY id DESC
LIMIT 20000
)
WHERE status_group = 'alive' AND source IS NOT NULL AND key_hash != ''
GROUP BY source, service
ORDER BY alive_keys DESC, linked_findings DESC
LIMIT 20
'''), height=360)
else:
st.info('No keycheck_results yet')
col1, col2 = st.columns(2)
with col1:
st.subheader('Recent Source Cycles')
display_df(query_df(conn, '''
SELECT started_at, ended_at, status, source, mode, query, fetched_count,
queued_new_count, queued_updated_count,
scanned_count, findings_count, error_count, skipped_count
FROM source_cycles
ORDER BY id DESC
LIMIT 20
'''), height=420)
with col2:
st.subheader('Top Error Categories')
errors = query_df(conn, '''
SELECT source, category, COUNT(*) AS count
FROM errors
GROUP BY source, category
ORDER BY count DESC
LIMIT 20
''')
display_df(errors, height=420)
def page_runtime(conn, queue_dir, log_dir, work_dir, scan_limiter_db, max_active_scans):
st.header('Runtime')
runtime_health, status_path = runtime_source_health(conn, log_dir)
slots = scan_slots_df(scan_limiter_db)
active_sources = int(runtime_health['runtime_status'].astype(str).str.lower().eq('running').sum()) if not runtime_health.empty and 'runtime_status' in runtime_health else 0
waiting_sources = int(runtime_health['runtime_status'].astype(str).str.lower().isin(('waiting', 'blocked', 'backoff')).sum()) if not runtime_health.empty and 'runtime_status' in runtime_health else 0
show_metrics([
('Running sources', active_sources),
('Waiting sources', waiting_sources),
('Active scan slots', f"{len(slots)}/{max_active_scans or '?'}"),
('Queue backlog', queue_backlog(queue_dir)),
('D/free GB', disk_free_gb(work_dir)),
])
st.subheader('Source Health')
st.caption(f'Runtime status file: {status_path}')
display_df(runtime_health, height=440)
col1, col2 = st.columns(2)
with col1:
st.subheader('Active Scan Slots')
st.caption(scan_limiter_db)
display_df(slots[['owner_source', 'owner_pid', 'age_sec', 'command']] if not slots.empty else slots, height=360)
with col2:
st.subheader('Current Queues')
display_df(current_queue_counts(queue_dir), height=360)
st.subheader('Log Metadata')
rows = []
if os.path.isdir(log_dir):
for name in sorted(item for item in os.listdir(log_dir) if item.lower().endswith('.log')):
path = os.path.join(log_dir, name)
rows.append({
'log': name,
'age': human_age(datetime.fromtimestamp(os.path.getmtime(path)).isoformat(timespec='seconds')) if os.path.exists(path) else '',
'bytes': os.path.getsize(path) if os.path.exists(path) else 0,
})
display_df(pd.DataFrame(rows), height=360)
def page_scanner_results(conn):
st.header('Scanner Results')
cycles = query_df(conn, '''
SELECT id AS cycle_id, started_at, ended_at, source, mode, query, status,
fetched_count, queued_new_count, queued_updated_count, scanned_count, clean_count, found_count,
skipped_count, error_count, findings_count, verified_findings_count,
unique_secrets_count, unique_findings_count, hit_rate, error_rate, duration_sec
FROM source_cycles
ORDER BY id DESC
LIMIT 5000
''')
if cycles.empty:
st.info('No source cycle data yet')
return
col1, col2, col3, col4 = st.columns(4)
with col1:
source_filter = st.multiselect('Sources', sorted(cycles['source'].dropna().unique()), default=sorted(cycles['source'].dropna().unique()))
with col2:
status_filter = st.multiselect('Cycle statuses', sorted(cycles['status'].dropna().unique()), default=sorted(cycles['status'].dropna().unique()))
with col3:
query_contains = st.text_input('Query contains')
with col4:
days = st.number_input('Last N days (0 = all loaded)', min_value=0, max_value=365, value=0, step=1)
filtered = cycles
if source_filter:
filtered = filtered[filtered['source'].isin(source_filter)]
if status_filter:
filtered = filtered[filtered['status'].isin(status_filter)]
if query_contains:
filtered = filtered[filtered['query'].astype(str).str.contains(query_contains, case=False, na=False)]
if days:
cutoff = pd.Timestamp.utcnow() - pd.Timedelta(days=int(days))
started = pd.to_datetime(filtered['started_at'], errors='coerce', utc=True)
filtered = filtered[started >= cutoff]
show_metrics([
('Cycles', len(filtered)),
('Scanned', int(filtered['scanned_count'].fillna(0).sum())),
('Findings', int(filtered['findings_count'].fillna(0).sum())),
('Errors', int(filtered['error_count'].fillna(0).sum())),
('Skipped', int(filtered['skipped_count'].fillna(0).sum())),
('Hit rate', format_pct((filtered['found_count'].fillna(0).sum() / filtered['scanned_count'].fillna(0).sum()) if filtered['scanned_count'].fillna(0).sum() else 0)),
])
section = st.selectbox('Scanner results section', ['By Source', 'By Query', 'By Cycle', 'Detectors', 'Keycheckable vs Noise', 'Targets'])
if section == 'By Source':
by_source = filtered.groupby('source', dropna=False).agg(
cycles=('cycle_id', 'count'),
scanned=('scanned_count', 'sum'),
findings=('findings_count', 'sum'),
errors=('error_count', 'sum'),
skipped=('skipped_count', 'sum'),
).reset_index().sort_values(['findings', 'scanned'], ascending=False)
display_df(by_source, height=420)
if not by_source.empty:
st.plotly_chart(px.bar(by_source, x='source', y='findings', title='Findings By Source'), width='stretch')
elif section == 'By Query':
by_query = filtered.groupby(['source', 'query'], dropna=False).agg(
cycles=('cycle_id', 'count'),
scanned=('scanned_count', 'sum'),
findings=('findings_count', 'sum'),
errors=('error_count', 'sum'),
).reset_index().sort_values(['findings', 'scanned'], ascending=False)
display_df(by_query, height=520)
elif section == 'By Cycle':
display_df(filtered.sort_values('started_at', ascending=False), height=620)
chart_df = filtered.sort_values('started_at')
if not chart_df.empty:
st.plotly_chart(px.line(chart_df, x='started_at', y='findings_count', color='source', markers=True, title='Findings By Cycle'), width='stretch')
elif section == 'Detectors':
clauses = []
params = []
if source_filter:
clauses.append('source IN ({})'.format(','.join('?' for _ in source_filter)))
params.extend(source_filter)
if query_contains:
clauses.append('query LIKE ?')
params.append(f'%{query_contains}%')
where = ('WHERE ' + ' AND '.join(clauses)) if clauses else ''
detectors = query_df(conn, f'''
SELECT detector_name, source, validation_service, noise_reason, is_keycheckable,
COUNT(*) AS findings, COUNT(DISTINCT NULLIF(secret_hash, '')) AS unique_secrets
FROM ({keycheckable_findings_view_sql()})
{where}
GROUP BY detector_name, source, validation_service, noise_reason, is_keycheckable
ORDER BY findings DESC
LIMIT 200
''', params)
display_df(detectors, height=620)
elif section == 'Keycheckable vs Noise':
st.warning('This diagnostic query scans findings and can be slow on the active DB.')
if not st.button('Run keycheckable/noise query'):
st.info('Press the button to calculate keycheckable/noise backlog.')
return
clauses = []
params = []
if source_filter:
clauses.append('source IN ({})'.format(','.join('?' for _ in source_filter)))
params.extend(source_filter)
if query_contains:
clauses.append('query LIKE ?')
params.append(f'%{query_contains}%')
where = ' AND '.join(clauses)
backlog = query_df(conn, f'''
SELECT source, query, validation_service, detector_name,
SUM(raw_findings) AS raw_findings,
SUM(unique_secrets) AS unique_secrets,
SUM(keycheckable_unique) AS keycheckable_unique,
SUM(noise_unique) AS noise_unique,
MAX(checked_unique) AS checked_unique,
MAX(alive_unique) AS alive_unique,
MAX(pending_unique) AS pending_unique
FROM ({keycheckable_backlog_sql(where)})
GROUP BY source, query, validation_service, detector_name
ORDER BY keycheckable_unique DESC, noise_unique DESC, raw_findings DESC
LIMIT 500
''', params)
display_df(backlog, height=620)
elif section == 'Targets':
targets = query_df(conn, '''
SELECT ended_at, source, query, status, target, normalized_target, duration_sec,
findings_count, verified_findings_count, error_count,
package_name, package_version, package_filename, package_type, package_size
FROM target_scans
ORDER BY id DESC
LIMIT 5000
''')
if not targets.empty:
if source_filter:
targets = targets[targets['source'].isin(source_filter)]
if query_contains:
targets = targets[targets['query'].astype(str).str.contains(query_contains, case=False, na=False)]
display_df(targets, height=620)
def page_runs(conn):
st.header('Historical Runs (Legacy / Debug)')
st.caption('Loop-mode sources usually do not finish runs, so these totals are not the source of truth for scanner metrics.')
runs = query_df(conn, '''
SELECT id, started_at, ended_at, duration_sec, status, invocation_mode, selected_source,
selected_platform, config_path, total_fetched, total_queued_new, total_scanned,
total_clean, total_found, total_skipped, total_errors, total_findings,
total_verified_findings, total_unique_secrets, total_unique_findings
FROM runs
ORDER BY id DESC
''')
display_df(runs)
if not runs.empty:
run_id = st.selectbox('Inspect run', runs['id'].tolist())
config = query_df(conn, 'SELECT scope, source, captured_at FROM config_snapshots WHERE run_id = ? ORDER BY id', [int(run_id)])
display_df(config)
def page_sources(conn):
st.header('Sources')
cycles = query_df(conn, '''
SELECT started_at, source, mode, query, status, fetched_count, queued_new_count,
queued_updated_count, scanned_count,
clean_count, found_count, skipped_count, error_count, findings_count, verified_findings_count,
unique_secrets_count, unique_findings_count, targets_per_hour, hit_rate, error_rate
FROM source_cycles
ORDER BY id DESC
''')
if cycles.empty:
st.info('No source cycle data yet')
return
source_filter = st.multiselect('Sources', sorted(cycles['source'].dropna().unique()), default=sorted(cycles['source'].dropna().unique()))
filtered = cycles[cycles['source'].isin(source_filter)] if source_filter else cycles
display_df(filtered)
chart_df = filtered.sort_values('started_at')
if not chart_df.empty:
st.plotly_chart(px.line(chart_df, x='started_at', y='scanned_count', color='source', markers=True, title='Scanned targets by cycle'), width='stretch')
st.plotly_chart(px.line(chart_df, x='started_at', y='error_rate', color='source', markers=True, title='Error rate by cycle'), width='stretch')
def page_queries(conn):
st.header('Queries')
queries = query_df(conn, '''
SELECT source, query, COUNT(*) AS cycles, SUM(fetched_count) AS fetched,
SUM(queued_new_count) AS queued_new,
SUM(queued_updated_count) AS queued_updated, SUM(scanned_count) AS scanned,
SUM(findings_count) AS findings, SUM(error_count) AS errors,
AVG(hit_rate) AS avg_hit_rate, AVG(error_rate) AS avg_error_rate,
AVG(duration_sec) AS avg_duration_sec
FROM source_cycles
GROUP BY source, query
ORDER BY findings DESC, scanned DESC
''')
if not queries.empty:
queries['avg_hit_rate'] = queries['avg_hit_rate'].map(format_pct)
queries['avg_error_rate'] = queries['avg_error_rate'].map(format_pct)
display_df(queries)
def page_findings(conn):
st.header('Findings')
st.caption('Redacted scanner metadata. Raw secret columns are never queried by this dashboard.')
desired_columns = [
'id', 'created_at', 'source', 'query', 'target', 'detector_name', 'detector_type', 'verified',
'provider', 'credential_kind', 'credential_confidence', 'required_context_missing',
'principal', 'username', 'email', 'project_id', 'organization', 'registry', 'endpoint', 'scope', 'resource',
'file_path', 'line_number', 'commit_hash', 'secret_hash', 'detector_secret_hash',
'finding_fingerprint', 'redacted_secret',
]
existing = table_columns(conn, 'findings')
columns = ', '.join(column for column in desired_columns if column in existing)
if not columns:
st.info('No findings columns available')
return
findings = query_df(conn, f'SELECT {columns} FROM findings ORDER BY id DESC LIMIT 1000')
if findings.empty:
st.info('No findings yet')
return
col1, col2, col3, col4 = st.columns(4)
col1.metric('Rows shown', len(findings))
col2.metric('Unique secrets', findings['secret_hash'].replace('', pd.NA).dropna().nunique())
col3.metric('Unique findings', findings['finding_fingerprint'].replace('', pd.NA).dropna().nunique())
col4.metric('Verified', int(findings['verified'].sum()))
detectors = query_df(conn, 'SELECT detector_name, COUNT(*) AS count FROM findings GROUP BY detector_name ORDER BY count DESC LIMIT 30')
if not detectors.empty:
st.plotly_chart(px.bar(detectors, x='detector_name', y='count', title='Findings by detector'), width='stretch')
display_df(findings)
def page_validation(conn):
st.header('Validation / Keychecks')
if not table_exists(conn, 'keycheck_results'):
st.info('No keycheck_results table yet. New keycheck runs will create it and populate validation data.')
return
preset = st.selectbox('Preset', VALIDATION_PRESETS, index=0)
historical_preset = preset in ('Ever usable LLM keys', 'Ever alive / LLM candidates')
preset_uses_latest = preset != 'Latest rows' and not historical_preset
if preset == 'Unattributed alive':
default_status_groups = ['alive']
default_access_tiers = ['alive_unproven_llm', 'usable_llm']
elif preset == 'Latest rows':
default_status_groups = ['alive']
default_access_tiers = VALIDATION_ACCESS_TIERS
elif preset == 'Usable LLM keys':
default_status_groups = VALIDATION_STATUS_GROUPS
default_access_tiers = ['usable_llm']
elif preset == 'Ever usable LLM keys':
default_status_groups = VALIDATION_STATUS_GROUPS
default_access_tiers = ['usable_llm']
elif preset == 'Ever alive / LLM candidates':
default_status_groups = ['alive']
default_access_tiers = ['usable_llm', 'alive_unproven_llm']
elif preset == 'Quota / no balance':
default_status_groups = VALIDATION_STATUS_GROUPS
default_access_tiers = ['no_quota', 'quota_limited']
elif preset == 'Alive but not proven LLM':
default_status_groups = VALIDATION_STATUS_GROUPS
default_access_tiers = ['alive_unproven_llm']
else:
default_status_groups = VALIDATION_STATUS_GROUPS
default_access_tiers = VALIDATION_ACCESS_TIERS
col1, col2, col3, col4 = st.columns(4)
with col1:
services = st.multiselect('Services', VALIDATION_SERVICES, default=VALIDATION_SERVICES)
with col2:
status_groups = st.multiselect('Status groups', VALIDATION_STATUS_GROUPS, default=default_status_groups)
source_options = [UNATTRIBUTED, *SOURCES]
with col3:
sources = st.multiselect('Sources', source_options, default=source_options)
with col4:
row_limit = st.number_input('Rows limit', min_value=500, max_value=50000, value=5000, step=500)
col5, col6, col7 = st.columns([1, 1, 2])
with col5:
checked_axis = st.selectbox('Time axis', ['checked_at', 'found_at'])
with col6:
dedupe_latest = st.checkbox('Dedupe latest per key (slower)', value=preset_uses_latest)
with col7:
query_text = st.text_input('Source query contains')
access_tiers = st.multiselect('Access tiers', VALIDATION_ACCESS_TIERS, default=default_access_tiers)
exact_statuses = st.multiselect('Exact provider statuses', VALIDATION_STATUSES, default=[])
search_text = st.text_input(
'Search hash / masked key / target',
help='Use a SHA-256 hash, masked value, or non-secret metadata. Raw credentials are not accepted or queried.',
)
if search_text and not dashboard_search_is_safe(search_text):
st.warning('Search refused: use a SHA-256 hash or masked/non-secret metadata.')
search_text = ''
if historical_preset:
st.caption('Historical preset: uses all matching keycheck rows, not latest current-state. This answers “which source ever produced this alive/usable key”.')
search_like = f'%{search_text}%' if search_text else ''
search_hash = search_text.lower() if re.fullmatch(r'[0-9a-fA-F]{64}', search_text or '') else ''
clauses = []
params = []
id_window = None
if not dedupe_latest and not search_text and not historical_preset:
max_id_df = query_df(conn, 'SELECT MAX(id) AS max_id FROM keycheck_results')
max_id = int(max_id_df.iloc[0]['max_id'] or 0) if not max_id_df.empty else 0
id_window = max(0, max_id - int(row_limit) * 20)
clauses.append('kr.id >= ?')
params.append(id_window)
if services and set(services) != set(VALIDATION_SERVICES):
clauses.append('kr.service IN ({})'.format(','.join('?' for _ in services)))
params.extend(services)
if status_groups and set(status_groups) != set(VALIDATION_STATUS_GROUPS):
clauses.append('kr.status_group IN ({})'.format(','.join('?' for _ in status_groups)))
params.extend(status_groups)
if sources and set(sources) != set(source_options):
source_clauses = []
concrete_sources = [item for item in sources if item != UNATTRIBUTED]
if concrete_sources:
source_clauses.append('COALESCE(kr.source, f.source, fh.source) IN ({})'.format(','.join('?' for _ in concrete_sources)))
params.extend(concrete_sources)
if UNATTRIBUTED in sources:
source_clauses.append('COALESCE(kr.source, f.source, fh.source) IS NULL')
if source_clauses:
clauses.append('(' + ' OR '.join(source_clauses) + ')')
if query_text:
clauses.append("COALESCE(kr.query, f.query, fh.query, '') LIKE ?")
params.append(f'%{query_text}%')
access_tier_sql = validation_access_tier_sql('kr')
if access_tiers and set(access_tiers) != set(VALIDATION_ACCESS_TIERS):
clauses.append(f"({access_tier_sql}) IN ({','.join('?' for _ in access_tiers)})")
params.extend(access_tiers)
if exact_statuses:
clauses.append('UPPER(kr.status) IN ({})'.format(','.join('?' for _ in exact_statuses)))
params.extend(exact_statuses)
if preset == 'Unattributed alive':
clauses.append("kr.status_group = 'alive'")
clauses.append("COALESCE(kr.source, kr.finding_id, kr.target_scan_id) IS NULL")
if search_text:
clauses.append('''(
kr.key_masked LIKE ?
OR kr.key_hash = ?
OR kr.secret_hash = ?
OR kr.detector_name LIKE ?
OR kr.target LIKE ?
OR COALESCE(kr.source, f.source, fh.source, '') LIKE ?
OR COALESCE(kr.query, f.query, fh.query, '') LIKE ?
OR COALESCE(kr.target, f.target, fh.target, ts.target, '') LIKE ?
OR COALESCE(f.redacted_secret, fh.redacted_secret, '') LIKE ?
OR COALESCE(f.detector_name, fh.detector_name, '') LIKE ?
OR COALESCE(f.file_path, fh.file_path, '') LIKE ?
OR COALESCE(f.commit_hash, fh.commit_hash, '') LIKE ?
OR ts.package_name LIKE ?
OR ts.package_version LIKE ?
OR ts.package_filename LIKE ?
)''')
params.extend([
search_like, search_hash, search_hash,
search_like, search_like, search_like, search_like,
search_like, search_like, search_like, search_like,
search_like, search_like, search_like, search_like,
])
where = ('WHERE ' + ' AND '.join(clauses)) if clauses else ''
if dedupe_latest:
source_sql = f'({latest_keycheck_view_sql()})'
else:
source_sql = 'keycheck_results'
meta_source = json_extract_sql('kr.metadata_json', '$.source')
meta_backfill_source = json_extract_sql('kr.metadata_json', '$.backfill_source_file')
meta_result_source = json_extract_sql('kr.metadata_json', '$.result_source')
meta_llm_probe_status = json_extract_sql('kr.metadata_json', '$.llm_probe_status')
meta_probe_status = json_extract_sql('kr.metadata_json', '$.probe.status')
meta_llm_probe_model = json_extract_sql('kr.metadata_json', '$.llm_probe_model')
meta_probe_model = json_extract_sql('kr.metadata_json', '$.probe.model')
meta_remaining_credits = json_extract_sql('kr.metadata_json', '$.remaining_credits')
meta_balance_usd = json_extract_sql('kr.metadata_json', '$.balance_usd')
meta_vertex_enabled = json_extract_sql('kr.metadata_json', '$.vertex_enabled')
meta_bedrock_enabled = json_extract_sql('kr.metadata_json', '$.bedrock_enabled')
meta_route_probe = json_extract_sql('kr.metadata_json', '$.route_probe')
meta_foundry_route_probe = json_extract_sql('kr.metadata_json', '$.foundry_route_probe')
rows = query_df(conn, f'''
SELECT kr.id, kr.checked_at, kr.found_at, kr.service, kr.status_group, kr.status,
{validation_access_tier_sql('kr')} AS access_tier,
kr.key_hash, kr.secret_hash, kr.key_masked,
COALESCE(kr.source, f.source, fh.source) AS source,
COALESCE(kr.query, f.query, fh.query) AS query,
COALESCE(kr.cycle_id, f.cycle_id, fh.cycle_id) AS cycle_id,
COALESCE(kr.target_scan_id, f.target_scan_id, fh.target_scan_id) AS target_scan_id,
COALESCE(kr.finding_id, fh.id) AS finding_id,
COALESCE(kr.detector_name, f.detector_name, fh.detector_name) AS detector_name,
COALESCE(kr.target, f.target, fh.target, ts.target) AS target,
COALESCE(f.file_path, fh.file_path) AS file_path,
COALESCE(f.line_number, fh.line_number) AS line_number,
COALESCE(f.commit_hash, fh.commit_hash) AS commit_hash,
ts.package_name, ts.package_version, ts.package_filename, ts.package_type,
CASE
WHEN f.id IS NOT NULL THEN 'finding_id'
WHEN fh.id IS NOT NULL THEN 'secret_hash'
WHEN COALESCE(kr.source, kr.query, kr.target) IS NOT NULL THEN 'keycheck_metadata'
ELSE 'missing_finding'
END AS attribution_status,
{meta_source} AS keycheck_source_line,
{meta_backfill_source} AS backfill_source_file,
COALESCE({meta_result_source}, 'api_check') AS result_source,
COALESCE({meta_llm_probe_status}, {meta_probe_status}) AS llm_probe_status,
COALESCE({meta_llm_probe_model}, {meta_probe_model}) AS llm_probe_model,
{meta_remaining_credits} AS remaining_credits,
{meta_balance_usd} AS balance_usd,
{meta_vertex_enabled} AS vertex_enabled,
{meta_bedrock_enabled} AS bedrock_enabled,
{meta_route_probe} AS azure_route_probe,
{meta_foundry_route_probe} AS foundry_route_probe
FROM {source_sql} kr
LEFT JOIN findings f ON f.id = kr.finding_id
LEFT JOIN findings fh ON f.id IS NULL AND fh.id = (
SELECT id
FROM findings
WHERE secret_hash = COALESCE(NULLIF(kr.secret_hash, ''), NULLIF(kr.key_hash, ''))
ORDER BY id DESC
LIMIT 1
)
LEFT JOIN target_scans ts ON ts.id = COALESCE(kr.target_scan_id, f.target_scan_id, fh.target_scan_id)
{where}
ORDER BY kr.id DESC
LIMIT ?
''', [*params, int(row_limit)])
if rows.empty:
st.info('No validation rows match current filters.')
if search_text:
st.subheader('Finding Metadata Matches')
st.caption('Fallback hash/redacted/metadata search in findings.')
display_df(finding_metadata_search(conn, search_text), height=520)
return
filtered = rows.copy()
if 'source' in filtered:
filtered['source'] = filtered['source'].fillna(UNATTRIBUTED)
if 'query' in filtered:
filtered['query'] = filtered['query'].fillna(UNATTRIBUTED)
if 'key_hash' in filtered:
filtered['key_identity'] = filtered['key_hash'].where(filtered['key_hash'].astype(str) != '', filtered['secret_hash']).fillna(filtered['key_masked'])
else:
filtered['key_identity'] = filtered.get('key_masked', pd.Series(dtype='object'))
usable_keys = int(filtered.loc[filtered['access_tier'] == 'usable_llm', 'key_identity'].replace('', pd.NA).dropna().nunique()) if 'access_tier' in filtered else 0
unproven_keys = int(filtered.loc[filtered['access_tier'] == 'alive_unproven_llm', 'key_identity'].replace('', pd.NA).dropna().nunique()) if 'access_tier' in filtered else 0
quota_keys = int(filtered.loc[filtered['access_tier'].isin(['no_quota', 'quota_limited']), 'key_identity'].replace('', pd.NA).dropna().nunique()) if 'access_tier' in filtered else 0
unattributed_rows = int((filtered['attribution_status'] == 'missing_finding').sum()) if 'attribution_status' in filtered else 0
show_metrics([
('Rows', len(filtered)),
('Usable LLM keys', usable_keys),
('Alive unproven keys', unproven_keys),
('No quota / limited keys', quota_keys),
('Unattributed rows', unattributed_rows),
])
if not filtered.empty:
status_by_service = filtered.groupby(['service', 'access_tier']).size().reset_index(name='count')
st.plotly_chart(px.bar(status_by_service, x='service', y='count', color='access_tier', title='Validation Access Tier By Service'), width='stretch')
usable_rows = filtered[filtered['access_tier'] == 'usable_llm'].copy()
usable_rows['source'] = usable_rows['source'].fillna(UNATTRIBUTED)
usable_rows['query'] = usable_rows['query'].fillna(UNATTRIBUTED)
usable_rows['target'] = usable_rows['target'].fillna(UNATTRIBUTED)
usable = usable_rows.groupby(['source', 'query', 'target', 'service', 'status', 'attribution_status'], dropna=False).agg(
rows=('id', 'count'),
keys=('key_identity', 'nunique'),
latest_checked=('checked_at', 'max'),
).reset_index().sort_values(['keys', 'rows'], ascending=False).head(100)
st.subheader('Usable LLM By Source / Query / Target')
display_df(usable, height=420)
unproven_rows = filtered[filtered['access_tier'] == 'alive_unproven_llm'].copy()
if not unproven_rows.empty:
unproven_rows['source'] = unproven_rows['source'].fillna(UNATTRIBUTED)
unproven = unproven_rows.groupby(['source', 'query', 'service', 'status'], dropna=False).agg(
rows=('id', 'count'),
keys=('key_identity', 'nunique'),
latest_checked=('checked_at', 'max'),
).reset_index().sort_values(['keys', 'rows'], ascending=False).head(100)
st.subheader('Alive But Not Proven LLM')
display_df(unproven, height=300)
st.subheader('Usable LLM Origins')
origin_columns = [
'checked_at', 'found_at', 'service', 'status', 'access_tier', 'result_source', 'source', 'query', 'target',
'attribution_status',
'llm_probe_status', 'llm_probe_model', 'remaining_credits', 'balance_usd',
'vertex_enabled', 'bedrock_enabled', 'azure_route_probe', 'foundry_route_probe',
'keycheck_source_line', 'backfill_source_file',
'detector_name', 'file_path', 'line_number', 'commit_hash',
'package_name', 'package_version', 'package_filename', 'package_type',
'finding_id', 'target_scan_id', 'cycle_id', 'id',
]
display_df(
usable_rows[[column for column in origin_columns if column in usable_rows.columns]].head(int(row_limit)),
height=520,
)
if search_text:
st.subheader('Finding Metadata Matches')
st.caption('Direct hash/redacted/metadata matches, including rows without keycheck results.')
display_df(finding_metadata_search(conn, search_text), height=420)
cycle = filtered.groupby(['source', 'query', 'cycle_id', 'service', 'status_group']).size().reset_index(name='count').sort_values('count', ascending=False).head(200)
st.subheader('Validation By Found Cycle')
display_df(cycle, height=420)
timeline = filtered.dropna(subset=[checked_axis]).copy()
if not timeline.empty:
timeline['day'] = timeline[checked_axis].astype(str).str.slice(0, 10)
timeline_df = timeline.groupby(['day', 'status_group']).size().reset_index(name='count')
st.plotly_chart(px.line(timeline_df, x='day', y='count', color='status_group', markers=True, title=f'Validation Timeline By {checked_axis}'), width='stretch')
st.subheader('Keycheckable Backlog By Source / Query')
st.caption('Optional diagnostic. Runs a heavier query over findings and keycheck_results.')
if st.button('Calculate keycheckable backlog'):
clauses = ['is_keycheckable = 1']
params = []
if services:
clauses.append('validation_service IN ({})'.format(','.join('?' for _ in services)))
params.extend(services)
concrete_sources = [item for item in sources if item != UNATTRIBUTED]
if concrete_sources:
clauses.append('source IN ({})'.format(','.join('?' for _ in concrete_sources)))
params.extend(concrete_sources)
if query_text:
clauses.append('query LIKE ?')
params.append(f'%{query_text}%')
backlog = query_df(conn, f'''
SELECT source, query, validation_service,
SUM(raw_findings) AS raw_findings,
SUM(unique_secrets) AS unique_secrets,
SUM(keycheckable_unique) AS keycheckable_unique,
MAX(checked_unique) AS checked_unique,
MAX(alive_unique) AS alive_unique,
MAX(pending_unique) AS pending_unique
FROM ({keycheckable_backlog_sql(' AND '.join(clauses))})
GROUP BY source, query, validation_service
ORDER BY pending_unique DESC, keycheckable_unique DESC, alive_unique DESC
LIMIT 200
''', params)
display_df(backlog, height=420)
st.subheader('Latest Validation Rows')
display_df(filtered, height=620)
def page_errors(conn):
st.header('Errors')
grouped = query_df(conn, '''
SELECT source, category, COUNT(*) AS count, MAX(created_at) AS latest
FROM errors
GROUP BY source, category
ORDER BY count DESC, latest DESC
LIMIT 200
''')
display_df(grouped)
recent = query_df(conn, '''
SELECT created_at, source, query, target, category
FROM errors
ORDER BY id DESC
LIMIT 300
''')
st.subheader('Recent Errors')
display_df(recent)
def page_targets(conn):
st.header('Targets')
targets = query_df(conn, '''
SELECT ended_at, source, query, status, target, normalized_target, duration_sec,
findings_count, verified_findings_count, error_count,
package_name, package_version, package_filename, package_type, package_size
FROM target_scans
ORDER BY id DESC
LIMIT 2000
''')
if targets.empty:
st.info('No target scan data yet')
return
statuses = st.multiselect('Statuses', sorted(targets['status'].dropna().unique()), default=sorted(targets['status'].dropna().unique()))
source_values = st.multiselect('Sources', sorted(targets['source'].dropna().unique()), default=sorted(targets['source'].dropna().unique()))
text = st.text_input('Target contains')
filtered = targets
if statuses:
filtered = filtered[filtered['status'].isin(statuses)]
if source_values:
filtered = filtered[filtered['source'].isin(source_values)]
if text:
filtered = filtered[filtered['target'].str.contains(text, case=False, na=False)]
display_df(filtered)
def page_queues_state(conn, queue_dir, state_file):
st.header('Queues And State')
st.subheader('Current Queue Files')
display_df(current_queue_counts(queue_dir))
st.subheader('Queue Snapshots')
snapshots = query_df(conn, '''
SELECT captured_at, source, phase, todo_count, checked_count, todo_file, checked_file
FROM queue_snapshots
ORDER BY captured_at DESC
LIMIT 1000
''')
display_df(snapshots)
state, path = load_runner_state(state_file)
st.subheader('Runner State')
st.caption(path)
if state:
state_rows = []
for source, item in (state.get('sources') or {}).items():
state_rows.append({
'source': source,
'query_index': item.get('query_index'),
'last_query': item.get('last_query'),
'last_auth': item.get('last_auth'),
'last_status': item.get('last_status'),
'cycles': item.get('cycles'),
'last_scanned': item.get('last_scanned'),
})
display_df(pd.DataFrame(state_rows))
else:
st.info('runner_state.json not found or empty')
def page_config(conn):
st.header('Config Snapshots')
st.caption('Payloads are unavailable because historical snapshots may contain credentials.')
configs = query_df(conn, '''
SELECT captured_at, run_id, cycle_id, scope, source
FROM config_snapshots
ORDER BY captured_at DESC, id DESC
LIMIT 500
''')
display_df(configs)
def page_logs(log_dir):
st.header('Logs')
st.caption('Only file metadata is exposed. Log contents are never rendered or downloaded.')
if not os.path.isdir(log_dir):
st.info('Log directory not found')
return
log_files = sorted(name for name in os.listdir(log_dir) if name.lower().endswith('.log'))
if not log_files:
st.info('No .log files found')
return
rows = []
for name in log_files:
path = os.path.join(log_dir, name)
updated = datetime.fromtimestamp(os.path.getmtime(path)).isoformat(timespec='seconds')
rows.append({
'log': name,
'bytes': os.path.getsize(path),
'updated_at': updated,
'age': human_age(updated),
})
display_df(pd.DataFrame(rows), height=520)
def page_package_repos(conn):
st.header('Package Git Candidates')
candidates = query_df(conn, '''
SELECT last_seen_at, package_source, package_name, package_version, query,
provider, repo_url, confidence
FROM package_repo_candidates
ORDER BY last_seen_at DESC
LIMIT 2000
''')
display_df(candidates)
def managed_config_argument(argv=None):
values = list(sys.argv[1:] if argv is None else argv)
for index, value in enumerate(values):
if value == '--config' and index + 1 < len(values):
return values[index + 1]
if str(value).startswith('--config='):
return str(value).split('=', 1)[1]
return None
def main():
try:
require_active_supervisor_child(
managed_config_argument(),
child_kind='dashboard',
require_dsn=True,
)
dashboard_host = str(os.getenv('TRUF_DASHBOARD_HOST') or '')
if os.getenv('TRUF_DASHBOARD_CANONICAL_LAUNCH') != '1' or not ipaddress.ip_address(dashboard_host).is_loopback:
raise LifecycleAuthorityError('dashboard requires canonical loopback supervisor launch authority')
except (LifecycleAuthorityError, ValueError) as exc:
raise SystemExit(str(exc)) from exc
args = parse_args()
db_path = resolve_db_path(args)
db_url = resolve_db_url(args)
st.set_page_config(
page_title='TRUF Status',
page_icon='T',
layout='wide',
initial_sidebar_state='collapsed',
)
try:
conn = connect_db(db_path, db_url, args.immutable_db)
except Exception as exc:
_dashboard_styles()
st.title('TRUF')
st.warning(f'PostgreSQL observability is temporarily unavailable ({type(exc).__name__}). The dashboard will retry on refresh.')
runtime_health, _ = parse_supervisor_status(args.log_dir)
display_df(runtime_health, height=360)
return
if conn is None:
_dashboard_styles()
st.title('TRUF')
st.info(f'No observability database found. Start a configured source through supervisor.py to create {DB_FILENAME}.')
return
try:
page_simple_dashboard(
conn,
args.log_dir,
args.work_dir,
args.scan_limiter_db,
args.max_active_scans,
)
finally:
try:
conn.close()
except Exception:
pass
if __name__ == '__main__':
main()