Static Analysis
Linting, type checking, and static application security testing (SAST) for code quality and security.
Static Analysis Categories
| Category | Purpose | When It Runs |
|---|---|---|
| Linting | Style, best practices, potential bugs | Every commit (pre-commit), CI |
| Type Checking | Type safety, contract verification | Every commit, CI |
| SAST | Security vulnerabilities in code | CI, scheduled, pre-merge |
| Dependency Scanning | Vulnerable/outdated dependencies | CI, scheduled, PR |
| Secrets Detection | Hardcoded secrets, API keys | Pre-commit, CI, push |
Language-Specific Tooling
TypeScript / JavaScript
| Tool | Purpose | Config |
|---|---|---|
| Biome | Lint + format (fast, Rust) | biome.json |
| ESLint | Lint (extensible, plugin ecosystem) | eslint.config.js (flat) |
| Prettier | Format (opinionated) | .prettierrc |
| TypeScript | Type check | tsconfig.json |
| tsc --noEmit | Fast type check | — |
Recommended: Biome (replaces ESLint + Prettier + lint-staged)
// biome.json
{
"$schema": "https://biomejs.dev/schemas/1.8.0/schema.json",
"organizeImports": { "enabled": true },
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": { "noUnusedVariables": "error" },
"style": { "useConst": "error", "noNonNullAssertion": "warn" },
"suspicious": { "noExplicitAny": "error" }
}
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"javascript": {
"formatter": { "quoteStyle": "double", "trailingCommas": "es5" }
}
}
TypeScript Strict Config
// tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"strict": true,
"noUncheckedIndexedAccess": true,
"exactOptionalPropertyTypes": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
}
}
Python
| Tool | Purpose |
|---|---|
| Ruff | Lint + format (replaces flake8, black, isort, pyupgrade) |
| mypy | Type checking |
| pyright | Fast type checking (VS Code Pylance) |
Ruff Config
# pyproject.toml
[tool.ruff]
target-version = "py311"
line-length = 100
select = [
"E", # pycodestyle
"F", # pyflakes
"I", # isort
"UP", # pyupgrade
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"PTH", # flake8-use-pathlib
"TRY", # tryceratops
"EM", # flake8-errmsg
"PIE", # flake8-pie
"T20", # flake8-print
]
ignore = ["E501"]
fixable = ["ALL"]
unfixable = []
[tool.ruff.format]
quote-style = "double"
indent-style = "space"
mypy Config
# pyproject.toml
[tool.mypy]
python_version = "3.11"
strict = true
warn_return_any = true
warn_unused_ignores = true
disallow_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_unused_ignores = true
check_untyped_defs = true
Go
| Tool | Purpose |
|---|---|
| golangci-lint | Aggregates 50+ linters |
| go vet | Built-in suspicious code |
| staticcheck | Advanced static analysis |
| govulncheck | Vulnerability scanning |
golangci-lint Config
# .golangci.yml
linters:
enable:
- errcheck
- gosec
- govet
- ineffassign
- staticcheck
- unused
- misspell
- nakedret
- prealloc
- bodyclose
- noctx
- rowserrcheck
- sqlclosecheck
- errorlint
- revive
- goimports
linters-settings:
errcheck:
check-type-assertions: true
check-blank: true
gosec:
excludes: [G104] # errors unhandled
revive:
rules:
- name: exported
disabled: true
issues:
exclude-rules:
- path: _test\.go
linters: [errcheck, gosec, revive]
Rust
| Tool | Purpose |
|---|---|
| clippy | Lint (built-in) |
| rustfmt | Format (built-in) |
| cargo-audit | Vulnerability scanning |
| cargo-deny | License, bans, sources policy |
Clippy Config
# Cargo.toml
[workspace.lints]
rust_2021_incompatible_closure_captures = "warn"
rust_2021_prefixes_incompatible_syntax = "warn"
rust_2021_prelude_collisions = "warn"
# clippy.toml (optional)
# [clippy]
# pedantic = true
# nursery = true
JVM (Kotlin/Java/Scala)
| Tool | Language | Purpose |
|---|---|---|
| detekt | Kotlin | Linting |
| ktlint | Kotlin | Formatting + linting |
| scalafix | Scala | Linting + rewrites |
| scalafmt | Scala | Formatting |
| Checkstyle | Java | Linting |
| SpotBugs | Java | Bug patterns |
| Error Prone | Java | Compile-time error detection |
detekt + ktlint (Kotlin)
// build.gradle.kts
plugins {
id("io.gitlab.arturbosch.detekt") version "1.23.0"
id("org.jlleitschuh.gradle.ktlint") version "12.0.0"
}
detekt {
config = files("config/detekt/detekt.yml")
baseline = file("config/detekt/baseline.xml")
reports {
html.enabled = true
xml.enabled = true
sarif.enabled = true
}
}
ktlint {
reporters {
plain {}
checkstyle.outputFile = file("$buildDir/reports/ktlint/ktlint-checkstyle.xml")
}
}
Security (SAST)
Open Source SAST
| Tool | Languages | Integration |
|---|---|---|
| Semgrep | 30+ | CLI, CI, IDE, rules registry |
| CodeQL | 10+ | GitHub Actions, CLI |
| SonarQube | 25+ | Server, CI, IDE |
| Bearer | JS/TS, Python, Ruby, Go | CLI, CI |
| TruffleHog | Secrets | CLI, CI, pre-commit |
| GitLeaks | Secrets | CLI, CI, pre-commit |
Semgrep (Recommended — Fast, Customizable)
# .semgrep.yml
rules:
- id: no-sql-injection
pattern-either:
- pattern: execute($X, ...)
- pattern: query($X, ...)
message: "Potential SQL injection - use parameterized queries"
languages: [python, javascript, typescript, go, java]
severity: ERROR
- id: hardcoded-secret
pattern-either:
- pattern: $X = "sk-..."
- pattern: $X = "ghp_..."
- pattern: $X = "xoxb-..."
message: "Hardcoded secret detected"
languages: [generic]
severity: ERROR
- id: path-traversal
pattern: open($PATH, ...) where $PATH.contains("..")
message: "Potential path traversal"
languages: [python, go, java]
severity: WARNING
# Run
semgrep ci --config=.semgrep.yml
# Or use registry
semgrep ci --config=p/ci --config=p/secrets --config=p/security-audit
GitHub CodeQL
# .github/workflows/codeql.yml
name: "CodeQL"
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [javascript, typescript, python, go, java, rust]
steps:
- uses: actions/checkout@v4
- uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- uses: github/codeql-action/analyze@v3
Dependency Scanning
| Tool | Ecosystem | Features |
|---|---|---|
| OWASP Dependency Check | All (Java, JS, .NET, etc.) | CVE, NVD, Sonatype OSS Index |
| Snyk | All | CLI, IDE, PR checks, auto-fix |
| Dependabot | GitHub native | Auto-PRs, security alerts |
| Renovate | All platforms | Flexible, auto-merge, group updates |
| Trivy | Containers, FS, Git | Vulns, misconfig, secrets, SBOM |
| Grype | Containers, FS | Syft SBOM input, fast |
| cargo-audit / govulncheck / pip-audit | Lang-specific | Lockfile analysis |
Recommended: Renovate + Trivy
// renovate.json
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["config:recommended"],
"packageRules": [
{ "matchUpdateType": "minor", "matchCurrentVersion": "!/^0\\./", "automerge": true },
{ "matchUpdateType": "patch", "automerge": true },
{ "matchDatasource": "github-releases", "enabled": false }
],
"schedule": ["every weekend"],
"timezone": "UTC",
"prConcurrentLimit": 10
}
# .github/workflows/trivy.yml
name: Trivy Scan
on: [push, pull_request]
jobs:
fs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload to Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
Secrets Detection
Pre-commit (Local)
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
args: [--verbose]
- repo: https://github.com/trufflesecurity/trufflehog
rev: v3.70.0
hooks:
- id: trufflehog
args: [--no-fail, --json]
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: detect-private-key
- id: detect-aws-credentials
CI (Blocking)
# .github/workflows/secrets.yml
name: Secrets Scan
on: [push, pull_request]
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: gitleaks/gitleaks-action@v2
env:
GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }}
CI/CD Integration
Pre-commit Hooks (All Languages)
# .pre-commit-config.yaml
repos:
- repo: local
hooks:
- id: biome
name: Biome (JS/TS)
entry: biome check --write
language: system
types: [javascript, typescript, json]
- id: ruff
name: Ruff (Python)
entry: ruff check --fix
language: system
types: [python]
- id: golangci-lint
name: golangci-lint (Go)
entry: golangci-lint run
language: system
types: [go]
- id: cargo-clippy
name: Clippy (Rust)
entry: cargo clippy --workspace -- -D warnings
language: system
types: [rust]
CI Pipeline Stages
# .github/workflows/ci.yml
jobs:
static-analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Language-specific
- name: Biome
run: biome ci .
- name: TypeScript
run: tsc --noEmit
- name: Ruff
run: ruff check .
- name: mypy
run: mypy src
- name: golangci-lint
run: golangci-lint run ./...
- name: Clippy
run: cargo clippy --workspace -- -D warnings
- name: detekt
run: ./gradlew detekt
# Security
- name: Semgrep
uses: returntocorp/semgrep-action@v1
- name: Trivy FS
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
- name: Secrets
uses: gitleaks/gitleaks-action@v2
Metrics & Quality Gates
Quality Gate Thresholds
| Metric | Warning | Fail |
|---|---|---|
| Code Coverage | < 80% | < 60% |
| Duplicated Lines | > 3% | > 5% |
| Complexity (cyclomatic) | > 15 | > 25 |
| Maintainability Index | < 70 | < 50 |
| Security Hotspots | > 0 | > 0 (critical) |
| Vulnerable Dependencies | Any | Any (high/critical) |
SonarQube / SonarCloud
# sonar-project.properties
sonar.projectKey=my-org_my-service
sonar.sources=src
sonar.tests=tests
sonar.exclusions=**/node_modules/**,**/target/**,**/dist/**
sonar.coverage.exclusions=**/*Test*,**/*Spec*
sonar.typescript.lcov.reportPaths=coverage/lcov.info
sonar.python.coverage.reportPaths=coverage.xml
sonar.go.coverage.reportPaths=coverage.out
Related Notes
- Developer Tools — IDE integration
- Build Tools — Build pipeline integration
- Package Management — Dependency scanning
- Secure Coding — Secure coding practices
- Supply Chain Security — SBOM, signing
- CI CD Best Practices — Pipeline gates
Sources: Biome, ESLint, TypeScript, Ruff, mypy, golangci-lint, clippy, detekt, ktlint, Semgrep, CodeQL, Trivy, Renovate, Dependabot, OWASP, GitHub Security, pre-commit