# Mosaic Quality Rails — gitleaks configuration
# Shared across all project templates. Copied to project root by install.sh.
# Built-in rules: https://github.com/gitleaks/gitleaks/tree/master/config
# This file adds custom rules for patterns the 150+ built-in rules miss.

title = "Mosaic gitleaks config"

[allowlist]
  description = "Global allowlist — skip files that never contain real secrets"
  paths = [
    '''node_modules/''',
    '''dist/''',
    '''build/''',
    '''\.next/''',
    '''\.nuxt/''',
    '''\.output/''',
    '''coverage/''',
    '''__pycache__/''',
    '''\.venv/''',
    '''vendor/''',
    '''pnpm-lock\.yaml$''',
    '''package-lock\.json$''',
    '''yarn\.lock$''',
    '''\.lock$''',
    '''\.snap$''',
    '''\.min\.js$''',
    '''\.min\.css$''',
    '''\.gitleaks\.toml$''',
  ]
  stopwords = [
    "localhost",
    "127.0.0.1",
    "changeme",
    "placeholder",
    "example",
    "example.com",
    "test",
    "dummy",
    "fake",
    "sample",
    "your-",
    "xxx",
    "CHANGEME",
    "PLACEHOLDER",
    "TODO",
    "REPLACE_ME",
  ]

# ──────────────────────────────────────────────
# Custom rules — patterns the built-in rules miss
# ──────────────────────────────────────────────

[[rules]]
  id = "database-url-with-credentials"
  description = "Database connection URL with embedded password"
  regex = '''(?i)(?:postgres(?:ql)?|mysql|mariadb|mongodb(?:\+srv)?|redis|amqp)://[^:\s]+:[^@\s]+@[^/\s]+'''
  tags = ["database", "connection-string"]
  [rules.allowlist]
    stopwords = ["localhost", "127.0.0.1", "changeme", "password", "example", "test_", "placeholder"]

[[rules]]
  id = "alembic-ini-sqlalchemy-url"
  description = "SQLAlchemy URL in alembic.ini with credentials"
  regex = '''sqlalchemy\.url\s*=\s*\S+://[^:\s]+:[^@\s]+@\S+'''
  paths = ['''alembic\.ini$''', '''\.ini$''']
  tags = ["python", "alembic", "database"]
  [rules.allowlist]
    stopwords = ["localhost", "127.0.0.1", "changeme", "driver://user:pass"]

[[rules]]
  id = "dotenv-secret-value"
  description = "High-entropy secret value in .env file"
  regex = '''(?i)(?:SECRET|TOKEN|PASSWORD|KEY|CREDENTIALS|AUTH)[\w]*\s*=\s*['"]?[A-Za-z0-9/+=]{20,}['"]?\s*$'''
  paths = ['''\.env$''', '''\.env\.\w+$''']
  tags = ["dotenv", "secret"]
  [rules.allowlist]
    stopwords = ["changeme", "placeholder", "example", "your_", "REPLACE", "TODO"]

[[rules]]
  id = "jdbc-url-with-password"
  description = "JDBC connection string with embedded password"
  regex = '''jdbc:[a-z]+://[^;\s]+password=[^;\s&]+'''
  tags = ["java", "jdbc", "database"]
  [rules.allowlist]
    stopwords = ["changeme", "placeholder", "example"]

[[rules]]
  id = "dsn-inline-password"
  description = "DSN-style connection string with inline password"
  regex = '''(?i)(?:dsn|connection_string|conn_str)\s*[:=]\s*\S+://[^:\s]+:[^@\s]+@\S+'''
  tags = ["database", "connection-string"]
  [rules.allowlist]
    stopwords = ["localhost", "127.0.0.1", "changeme", "example"]

[[rules]]
  id = "hardcoded-password-variable"
  description = "Hardcoded password assignment in source code"
  regex = '''(?i)(?:password|passwd|pwd)\s*[:=]\s*['"][^'"]{8,}['"]'''
  tags = ["password", "hardcoded"]
  [rules.allowlist]
    stopwords = ["changeme", "placeholder", "example", "test", "dummy", "password123", "your_password"]
    paths = [
      '''test[s]?/''',
      '''spec[s]?/''',
      '''__test__/''',
      '''fixture[s]?/''',
      '''mock[s]?/''',
    ]

[[rules]]
  id = "bearer-token-in-code"
  description = "Hardcoded bearer token in source code"
  regex = '''(?i)['"]Bearer\s+[A-Za-z0-9\-._~+/]+=*['"]'''
  tags = ["auth", "bearer", "token"]
  [rules.allowlist]
    stopwords = ["example", "test", "dummy", "placeholder", "fake"]

[[rules]]
  id = "spring-application-properties-password"
  description = "Password in Spring Boot application properties"
  regex = '''(?i)spring\.\w+\.password\s*=\s*\S+'''
  paths = ['''application\.properties$''', '''application\.yml$''', '''application-\w+\.properties$''', '''application-\w+\.yml$''']
  tags = ["java", "spring", "password"]
  [rules.allowlist]
    stopwords = ["changeme", "placeholder", "${"]

[[rules]]
  id = "docker-compose-env-secret"
  description = "Hardcoded secret in docker-compose environment"
  regex = '''(?i)(?:POSTGRES_PASSWORD|MYSQL_ROOT_PASSWORD|MYSQL_PASSWORD|REDIS_PASSWORD|RABBITMQ_DEFAULT_PASS|MONGO_INITDB_ROOT_PASSWORD)\s*[:=]\s*['"]?[^\s'"$]{8,}['"]?'''
  paths = ['''compose\.ya?ml$''', '''docker-compose\.ya?ml$''']
  tags = ["docker", "compose", "secret"]
  [rules.allowlist]
    stopwords = ["changeme", "placeholder", "example", "${"]

[[rules]]
  id = "terraform-variable-secret"
  description = "Sensitive default value in Terraform variable"
  regex = '''(?i)default\s*=\s*"[^"]{8,}"'''
  paths = ['''variables\.tf$''', '''\.tf$''']
  tags = ["terraform", "secret"]
  [rules.allowlist]
    stopwords = ["changeme", "placeholder", "example", "TODO"]

[[rules]]
  id = "private-key-pem-inline"
  description = "PEM-encoded private key in source"
  regex = '''-----BEGIN\s+(?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----'''
  tags = ["key", "pem", "private-key"]

[[rules]]
  id = "base64-encoded-secret"
  description = "Base64 value assigned to secret-named variable"
  regex = '''(?i)(?:secret|token|key|password|credentials)[\w]*\s*[:=]\s*['"]?[A-Za-z0-9+/]{40,}={0,2}['"]?'''
  tags = ["base64", "encoded", "secret"]
  [rules.allowlist]
    stopwords = ["changeme", "placeholder", "example", "test"]
    paths = [
      '''test[s]?/''',
      '''spec[s]?/''',
      '''fixture[s]?/''',
    ]
