A fast, security-focused command-line tool written in Go that analyzes Liquibase changelog files to identify security vulnerabilities, performance issues, and best practice violations.
Database migrations are critical infrastructure code that often contains security vulnerabilities and anti-patterns. Liquibase Linter helps teams:
- Prevent security incidents by detecting SQL injection, hardcoded credentials, and dangerous operations before they reach production
- Improve reliability by ensuring changesets have rollback scripts and proper preconditions
- Optimize performance by identifying missing indexes and problematic operations
- Maintain code quality through automated enforcement of best practices
- 🔒 Security First: Detect SQL injection risks, dangerous operations, hardcoded credentials, and privilege escalation
- ✅ Code Quality: Enforce Liquibase best practices, naming conventions, and proper documentation
- ⚡ Performance: Identify missing indexes, table locks, and large data operations
- 🚀 Fast: Built in Go for optimal performance (<100ms startup for typical changelogs)
- 📊 Multiple Output Formats: Support for text, JSON, SARIF, and JUnit formats
- 🔧 Configurable: Flexible rule configuration via YAML
- 🎯 Inline Suppressions: Disable specific rules for individual changesets via comments
- 🔌 CI/CD Ready: Easy integration with GitHub Actions, GitLab CI, Jenkins, and more
go install github.com/n2jsoft-public-org/liquibase-linter/cmd/liquibase-linter@latestOr download pre-built binaries from the releases page.
# Check a single changelog file
liquibase-linter check db/changelog/db.changelog-master.xml
# Check all changelogs in a directory
liquibase-linter check db/changelog/
# Use a configuration file
liquibase-linter check --config=.liquibase-linter.yaml db/changelog/
# Output in JSON format for CI/CD
liquibase-linter check --format=json db/changelog/ > results.json
# List all available rules
liquibase-linter rules
# Show details about a specific rule
liquibase-linter rules --info=sql-injection
# Initialize a configuration file
liquibase-linter initSometimes you need to intentionally bypass a rule for a specific changeset. Add an inline suppression to the changeset comment:
<changeSet id="1" author="john">
<comment>liquibase-linter:disable sql-injection</comment>
<sql>
-- Known safe parameter from validated config
INSERT INTO settings VALUES (${config_value});
</sql>
</changeSet>See Suppression Documentation for complete details and format-specific examples.
Checking: db/changelog/changelog-1.0.xml
[CRITICAL] sql-injection (line 15, changeset: create-user-1)
Potential SQL injection: String concatenation detected in SQL statement
Use parameterized queries or Liquibase's built-in change types instead.
[WARNING] missing-rollback (line 10, changeset: add-column-1)
Changeset does not include a rollback script
Add a <rollback> block to enable safe rollback of this change.
[INFO] naming-conventions (line 25, changeset: create-table-1)
Table name 'UserData' does not follow naming convention
Use lowercase snake_case for table names: user_data
Summary:
Files checked: 1
Violations: 3 (1 critical, 1 warning, 1 info)
{
"version": "1.0.0",
"timestamp": "2024-02-04T10:30:00Z",
"files": [
{
"path": "db/changelog/changelog-1.0.xml",
"violations": [
{
"rule": "sql-injection",
"severity": "critical",
"message": "Potential SQL injection: String concatenation detected",
"line": 15,
"changeset_id": "create-user-1"
}
]
}
],
"summary": {
"files_checked": 1,
"total_violations": 3,
"critical": 1,
"warning": 1,
"info": 1
}
}The linter automatically discovers .liquibase-linter.yaml configuration files in:
- The target directory (if checking a directory)
- Parent directories up to the project root
- Current working directory
You can also explicitly specify a config file with --config.
Create a .liquibase-linter.yaml file in your changelog directory or project root:
# Enable/disable rules and set severity levels
rules:
sql-injection:
enabled: true
severity: critical
hardcoded-credentials:
enabled: true
severity: critical
dangerous-operations:
enabled: true
severity: critical
missing-rollback:
enabled: true
severity: warning
naming-conventions:
enabled: true
severity: info
# Ignore specific files or patterns (relative to target directory)
ignore:
- "test/fixtures/*.xml"
- "init/**" # Ignore all files in init folder
- "db/changelog/legacy/**"
# Output configuration
output:
format: text # text, json, sarif, junit
colorize: true # Enable colored output (text format only)
# Parser configuration
parser:
max_include_depth: 10 # Maximum nesting for include/includeAll
follow_symlinks: true # Follow symlinks during file discovery
# Minimum severity to report
severity_threshold: warning # info, warning, criticalSee Configuration Guide for all options.
See the docs directory for detailed documentation:
- Usage Guide: Comprehensive guide to using the linter
- Rules Reference: Complete list of available rules with examples
- Configuration Guide: Detailed configuration options
- Suppression Guide: How to suppress rules for specific changesets
- CI/CD Integration: Integration examples for various CI/CD platforms
- Development Guide: Guide for contributors and developers
The linter includes rules in the following categories:
- sql-injection: Detect potential SQL injection vulnerabilities
- hardcoded-credentials: Find hardcoded passwords and API keys
- dangerous-operations: Detect DROP/TRUNCATE without preconditions
- privilege-escalation: Identify excessive privilege grants
- missing-rollback: Ensure changesets have rollback scripts
- non-idempotent: Detect non-idempotent changes
- missing-preconditions: Ensure risky operations have safety checks
- missing-indexes: Detect missing indexes on foreign keys
- table-locks: Identify operations that may cause table locks
- large-data-operations: Detect unbounded data manipulation
- naming-conventions: Enforce consistent naming standards
- changelog-organization: Ensure proper changelog structure
- documentation: Verify changesets are documented
See Rules Reference for detailed descriptions and examples.
name: Liquibase Linting
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download Liquibase Linter
run: |
curl -L -o liquibase-linter https://github.com/n2jsoft-public-org/liquibase-linter/releases/latest/download/liquibase-linter-linux-amd64
chmod +x liquibase-linter
- name: Run Liquibase Linter
run: ./liquibase-linter check --format=sarif db/changelog/ > results.sarif
- name: Upload results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarifliquibase-lint:
stage: test
script:
- curl -L -o liquibase-linter https://github.com/n2jsoft-public-org/liquibase-linter/releases/latest/download/liquibase-linter-linux-amd64
- chmod +x liquibase-linter
- ./liquibase-linter check --format=json db/changelog/See CI/CD Integration Guide for more examples.
# Clone the repository
git clone https://github.com/n2jsoft-public-org/liquibase-linter.git
cd liquibase-linter
# Build
go build -o liquibase-linter ./cmd/liquibase-linter
# Run tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run linters
golangci-lint runSee Development Guide for detailed information on contributing.
- ✅ XML changelogs
- ✅ SQL formatted changelogs
- ⏳ YAML changelogs (planned)
- ⏳ JSON changelogs (planned)
Liquibase Linter is designed for speed:
- Starts in <100ms for typical changelogs
- Processes large changelog directories in seconds
- Uses Go's efficient concurrency for multi-file analysis
- Minimal memory footprint
0: No violations found1: Violations found (based onfail_onseverity threshold)2: Error during execution (file not found, parse error, etc.)
Check out the testdata directory for example changelogs:
- example-good-practices.xml: Well-structured changelog with best practices
- example-good-practices.sql: SQL formatted changelog with good practices
- problematic-changelog.xml: Examples of common issues
- problematic-changelog.sql: SQL examples with violations
MIT License - see LICENSE for details.
Contributions are welcome! Please see:
- Development Guide for setup and architecture
- Open Issues for things to work on
- Pull Request Guidelines for the workflow
Built with ❤️ by n2jsoft
Inspired by the need for better security and quality control in database migrations.
- 📝 Documentation
- 🐛 Report Issues
- 💬 Discussions
- ⭐ Star the project if you find it useful!