Skip to content

MetaMask/action-security-code-scanner

Repository files navigation

Security Code Scanner Monorepo

Unified security code scanning system with CodeQL and Semgrep

πŸ—οΈ Architecture

This monorepo provides a reusable security scanning workflow with automatic language detection and parallel execution:

  • .github/workflows/security-scan.yml - Main reusable workflow (orchestrator)
  • packages/language-detector/ - Detects languages and creates scan matrix
  • packages/codeql-action/ - Custom CodeQL analysis with repo-specific configs
  • packages/semgrep-action/ - Semgrep pattern-based scanner

πŸš€ Quick Start

Using the Scanner (Recommended)

Add to your repository's .github/workflows/security.yml:

name: 'Security Scan'
on: [push, pull_request]

jobs:
  security-scan:
    uses: MetaMask/action-security-code-scanner/.github/workflows/security-scan.yml@v2
    with:
      scanner-ref: v2

The workflow will:

  1. Auto-detect languages in your repository
  2. Load repo-specific config from repo-configs/ (or use defaults)
  3. Run CodeQL and Semgrep scans in parallel
  4. Upload SARIF results to GitHub Security tab

Custom Configuration

Option 1: File-based config (recommended)

Create repo-configs/<your-repo-name>.js in this monorepo:

const config = {
  pathsIgnored: ['test', 'docs'],
  rulesExcluded: ['js/log-injection'],
  languages_config: [
    {
      language: 'java-kotlin',
      build_mode: 'manual',
      build_command: './gradlew build',
      version: '21',
      distribution: 'temurin',
    },
  ],
  queries: [
    { name: 'Security queries', uses: './query-suites/base.qls' },
    {
      name: 'Custom queries',
      uses: './custom-queries/query-suites/custom-queries.qls',
    },
  ],
};

export default config;

Option 2: Workflow input (overrides file config)

jobs:
  security-scan:
    uses: metamask/security-codescanner-monorepo/.github/workflows/security-scan.yml@main
    with:
      repo: ${{ github.repository }}
      languages_config: |
        [
          {
            "language": "java-kotlin",
            "build_mode": "manual",
            "build_command": "./gradlew build",
            "version": "21"
          }
        ]
      paths_ignored: 'test,docs'
      rules_excluded: 'js/log-injection,py/sql-injection'

Testing from Dev Branch

When testing changes to the security scanner itself from a dev branch, you must explicitly pass the ref input:

jobs:
  security-scan:
    uses: metamask/security-codescanner-monorepo/.github/workflows/security-scan.yml@dev-branch
    with:
      repo: ${{ github.repository }}
      ref: dev-branch # Must explicitly pass the branch name

Note: The @branch in the uses: statement only affects which workflow file is used. The ref input ensures all internal monorepo checkouts use the same branch.

πŸ“¦ Package Structure

security-scanner-monorepo/
β”œβ”€β”€ .github/workflows/
β”‚   └── security-scan.yml        # Main reusable workflow
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ language-detector/       # Language detection & matrix creation
β”‚   β”œβ”€β”€ codeql-action/          # CodeQL scanner
β”‚   β”‚   β”œβ”€β”€ repo-configs/       # Repository-specific configs
β”‚   β”‚   β”œβ”€β”€ query-suites/       # CodeQL query suites
β”‚   β”‚   β”œβ”€β”€ scripts/            # Config generation scripts
β”‚   β”‚   └── src/                # Shared utilities
β”‚   └── semgrep-action/         # Semgrep scanner
└── SECURITY.md                  # Security model documentation

πŸ”§ Development

Setup

# Install dependencies
yarn install

# Run linting
yarn lint

# Fix formatting
yarn lint:fix

Testing

# Test language detector
yarn workspace @metamask/language-detector test

# Test with integration tests
yarn workspace @metamask/language-detector test:integration

Workspace Commands

# Run command in specific package
yarn workspace @metamask/language-detector <command>

# Run command in all packages
yarn workspaces foreach run <command>

πŸ“š Configuration Schema

Repo Config File (repo-configs/<repo-name>.js)

{
  // Paths to ignore during scan
  pathsIgnored: ['test', 'vendor'],

  // Rule IDs to exclude
  rulesExcluded: ['js/log-injection'],

  // Per-language configuration
  languages_config: [
    {
      language: 'java-kotlin',      // CodeQL language
      ignore: false,                 // Skip this language (optional)
      build_mode: 'manual',          // 'none', 'autobuild', or 'manual'
      build_command: './gradlew build',
      version: '21',                 // Language/runtime version
      distribution: 'temurin'        // Distribution (Java/Node.js)
    }
  ],

  // CodeQL query suites
  queries: [
    { name: 'Base queries', uses: './query-suites/base.qls' }
  ]
}

Supported Languages

CodeQL:

  • JavaScript/TypeScript β†’ javascript-typescript
  • Python β†’ python
  • Java/Kotlin β†’ java-kotlin
  • Go β†’ go
  • C/C++ β†’ cpp
  • C# β†’ csharp
  • Ruby β†’ ruby

Semgrep: All languages (language-agnostic pattern matching)

🎯 Key Features

βœ… Automatic Language Detection

  • Detects languages via GitHub API
  • Maps to appropriate scanners
  • Configurable per-repository

βœ… Optimized Execution

  • Parallel scanning per language
  • Matrix-based job strategy
  • Fail-fast for ignored languages

βœ… Flexible Configuration

  • File-based configs (single source of truth)
  • Workflow input overrides
  • Per-language build settings

βœ… Security First

  • Minimal token permissions (contents: read, security-events: write)
  • Input validation and sanitization
  • See SECURITY.md for threat model

πŸ” Troubleshooting

Language not detected

  • Check GitHub's language detection (repo insights β†’ languages)
  • Ensure language is in LANGUAGE_MAPPING in language-detector/src/job-configurator.js
  • Add manual languages_config in workflow input

Build failures

  • Verify build_command in repo config
  • Check if correct version and distribution are specified
  • Review CodeQL build logs in Actions

Config not loading

  • Repo config filename must match repo name: owner/repo β†’ repo.js
  • Ensure config file exports with export default config
  • Check config-loader logs in workflow output

Permissions errors

  • Add required permissions to calling workflow:
    permissions:
      actions: read
      contents: read
      security-events: write

πŸ“„ License

ISC

🀝 Contributing

See SECURITY.md for security model and REVIEW_TRACKING.md for current development status.

Package Documentation

About

A GitHub action aggregating SAST tools to scan code for vulnerabilities

Resources

Code of conduct

Security policy

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published

Contributors 7