Plugins
Extend pgfence with custom rules and policy checks. Plugins are JavaScript modules that export a PgfencePlugin object.
Usage
pgfence analyze --plugin ./my-rules.js migrations/*.sql
# Multiple plugins
pgfence analyze --plugin ./team-rules.js ./compliance-rules.js migrations/*.sql Writing a Plugin
A plugin exports a default object with a name and optional rules and policies arrays:
// my-rules.js
export default {
name: 'my-team-rules',
rules: [
{
ruleId: 'plugin:no-drop-in-peak-hours',
check(stmt, config) {
// stmt contains the parsed statement
// Return CheckResult[] for any findings
return [];
},
},
],
policies: [
{
ruleId: 'plugin:require-migration-comment',
check(stmts, config) {
// stmts is the full list of parsed statements
// Return PolicyViolation[] for any findings
return [];
},
},
],
}; Plugin API
Rules
A rule's check function receives a single parsed statement and returns an array of CheckResult objects:
interface PgfencePluginRule {
ruleId: string;
check(stmt: ParsedStatement, config: PgfenceConfig): CheckResult[];
} Each rule is called once per statement in the migration. Return an empty array for statements your rule does not apply to.
Policies
A policy's check function receives all parsed statements and returns an array of PolicyViolation objects:
interface PgfencePluginPolicy {
ruleId: string;
check(stmts: ParsedStatement[], config: PgfenceConfig): PolicyViolation[];
} Policies run once per file after all statements are analyzed. Use them for cross-statement checks (e.g., "migration must contain a comment" or "no more than N dangerous statements per file").
Namespacing
Plugin rule IDs and policy IDs must already be prefixed with plugin:. pgfence rejects plugin entries that are not explicitly namespaced, so plugin:no-drop-in-peak-hours is valid and no-drop-in-peak-hours is not.
Supported File Types
Plugins can be .js, .mjs, or .cjs files. If you write plugins in TypeScript, compile them to JavaScript before loading them in pgfence. They are loaded via dynamic import().
Security
Plugin paths are resolved relative to the current working directory and must resolve to a real file within the project directory. Symlink escapes and paths outside the project root are rejected.
Via Config File
Plugins can also be specified in your .pgfence.toml or .pgfence.json config file:
# .pgfence.toml
plugins = ["./rules/team-rules.js", "./rules/compliance.js"]