Database

MySQL 8.0 schema, migrations, tables by service, key relationships, and connection configuration.

All services share a single MySQL 8.0 instance with the database name taco. Each service owns specific tables and manages its own migrations.

Migration System

Migrations are plain SQL files mounted into the MySQL container at startup via Docker Compose volumes. They run automatically via the /docker-entrypoint-initdb.d/ mechanism on first database initialization.

Each service has a prefix range to avoid ordering conflicts:

PrefixServiceExample
10xtaco-auth100_auth_001_create_project_tokens.sql
20xtaco-store200_store_001_create_sboms.sql
30xtaco-scanner300_scanner_001_create_findings.sql
40xtaco-alert400_alert_001_create_alert_configs.sql
50xtaco-api500_api_001_create_users.sql
60xtaco-secrets600_secrets_001_create_secrets.sql

Some services (taco-scanner, taco-secrets) also run CREATE TABLE IF NOT EXISTS migrations at startup for tables they need to read from but don't own.

Tables by Service

taco-api (prefix 50x)

TableDescription
usersUser accounts (email, password hash, OAuth links)
subscriptionsMulti-tenant subscriptions (name, plan, limits)
subscription_membersUser-to-subscription membership with roles
projectsProjects within subscriptions
project_membersUser-to-project membership with roles
api_tokensAPI tokens (hashed) for programmatic access
project_finding_statusesPer-component triage statuses (accepted, suppressed, fixed)
finding_audit_logAudit trail for finding status changes
audit_logGeneral audit log
secrets (008)Legacy secrets table (replaced by taco-secrets service)
scan_requestsOn-demand scan request queue
image_scan_requestsContainer image scan request queue
project_risk_configPer-project risk scoring configuration
finding_snapshotsDaily finding count snapshots for trend charts
alert_channelsPer-project alert channel configuration
component_dependenciesComponent dependency relationships

Enrichment columns added to findings by taco-api migrations:

  • cvss_score, cvss_vector (014)
  • known_exploited (014)
  • epss_score, epss_percentile, risk_score (021)
  • enrichment_status (022)
  • expires_at on api_tokens (018)

Billing columns added to subscriptions:

  • stripe_customer_id, stripe_subscription_id, stripe_plan, billing_status (012)

taco-auth (prefix 10x)

TableDescription
project_tokensProject authentication tokens for SBOM ingestion

taco-store (prefix 20x)

TableDescription
sbomsSBOM metadata: event_id, project_id, project_name, format, raw_sbom, created_at
componentsUnique components: purl (unique key), name, version, type, first_seen
sbom_componentsJunction table linking SBOMs to components

taco-scanner (prefix 30x)

TableDescription
findingsVulnerability findings: component_id, cve_id, severity, cvss_score, known_exploited, description, fixed_version, first_detected_at, resolved_at
scan_stateScan run metadata: db_hash, last_scan_at, components_scanned, new_findings, resolved_count, duration_ms

taco-alert (prefix 40x)

TableDescription
alert_configsPer-project alert configuration
alert_historyDispatched alert records

taco-secrets (prefix 60x)

TableDescription
secretsDetected secrets: project_id, sbom_id, namespace, secret_type, severity, category, file_path, file_line, masked_match, confidence
secrets_scan_stateTracks scanned SBOMs: sbom_id, findings_count, scanned_at

Key Relationships

users
  |-- subscription_members --> subscriptions
  |                               |-- projects
  |                               |     |-- sboms
  |                               |     |     |-- sbom_components --> components
  |                               |     |     |-- secrets
  |                               |     |-- project_members
  |                               |     |-- project_finding_statuses
  |                               |     |-- alert_configs
  |                               |     |-- project_risk_config
  |                               |     |-- finding_snapshots
  |                               |     |-- scan_requests
  |                               |     |-- image_scan_requests
  |                               |
  |                               |-- alert_channels
  |
  |-- api_tokens --> projects

components
  |-- findings (component_id FK)
  |-- component_dependencies

Findings Table Detail

The findings table is the most important table in the system. It holds the vulnerability scan results:

sqlCREATE TABLE findings (
    id                BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    component_id      BIGINT UNSIGNED NOT NULL,
    cve_id            VARCHAR(20) NOT NULL,
    severity          ENUM('low', 'medium', 'high', 'critical') NOT NULL,
    cvss_score        FLOAT NOT NULL DEFAULT 0,
    cvss_vector       VARCHAR(255) DEFAULT NULL,
    known_exploited   BOOLEAN NOT NULL DEFAULT FALSE,
    epss_score        FLOAT DEFAULT NULL,
    epss_percentile   FLOAT DEFAULT NULL,
    risk_score        FLOAT DEFAULT NULL,
    enrichment_status ENUM('pending', 'enriched', 'no_source') DEFAULT 'pending',
    description       TEXT NOT NULL,
    fixed_version     VARCHAR(255) NULL,
    first_detected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    resolved_at       TIMESTAMP NULL,
    UNIQUE INDEX idx_component_cve (component_id, cve_id),
    INDEX idx_cve_id (cve_id),
    INDEX idx_resolved (resolved_at),
    FOREIGN KEY (component_id) REFERENCES components(id) ON DELETE CASCADE
);

Secrets Table Detail

sqlCREATE TABLE secrets (
    id           BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    project_id   BIGINT UNSIGNED NOT NULL,
    sbom_id      BIGINT UNSIGNED NOT NULL,
    namespace    VARCHAR(512) NOT NULL DEFAULT '',
    secret_type  VARCHAR(100) NOT NULL,
    severity     ENUM('low', 'medium', 'high', 'critical') NOT NULL,
    category     VARCHAR(50) NOT NULL,
    file_path    VARCHAR(1024) NOT NULL DEFAULT '',
    file_line    INT UNSIGNED NOT NULL DEFAULT 0,
    masked_match VARCHAR(512) NOT NULL,
    confidence   ENUM('low', 'medium', 'high') NOT NULL DEFAULT 'medium',
    created_at   TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE INDEX idx_dedup (sbom_id, secret_type, file_path, file_line),
    INDEX idx_project (project_id),
    INDEX idx_severity (severity),
    INDEX idx_category (category)
);

Connection Configuration

All services connect to MySQL using the MYSQL_DSN environment variable:

taco:taco@tcp(mysql:3306)/taco?parseTime=true

Connection pool defaults vary by service but typically:

  • Max open connections: 10-25
  • Max idle connections: 3-5
  • Connection max lifetime: 5 minutes