Policy configuration

Complete reference for the Backstop policy file — every field, its behavior, and recommended values for development and production.

The policy file is a JSON document that controls all of Backstop's enforcement behavior. You pass it to the gateway on startup. There is no hot-reload — restart the gateway to apply changes.

Policy file location

# Pass via environment variable
BACKSTOP_POLICY=/etc/backstop/policy.json

# Or as a CLI flag
backstop-gateway --policy /etc/backstop/policy.json

Full reference

{
  "require_approval_for_risks": ["HIGH", "IMPACT_CRITICAL", "CRITICAL"],
  "block_operations": ["DROP DATABASE", "DROP SCHEMA"],
  "require_recovery_for_critical": true,
  "block_unknown_or_parse_failure": true,
  "block_unrecoverable_operations": true,
  "max_snapshot_age_seconds": 300,
  "require_sidecar_heartbeat": true,
  "max_sidecar_heartbeat_seconds": 120,
  "impact_analysis_enabled": true,
  "max_write_rows_without_critical": 1000,
  "max_write_percent_without_critical": 50,
  "protected_tables": ["users", "payments"],
  "protected_columns": {
    "users": ["password", "api_key", "mfa_secret"],
    "payments": ["card_number", "cvv"]
  },
  "max_blocked_attempts_per_window": 3,
  "quarantine_duration_seconds": 1800,
  "dangerous_retry_window_seconds": 600
}

Field reference

ParameterTypeDescription
require_approval_for_risksOPTIONAL
default: ["HIGH","IMPACT_CRITICAL","CRITICAL"]
string[]Risk levels that require operator approval before execution. SAFE reads execute immediately.
block_operationsOPTIONAL
default: ["DROP DATABASE","DROP SCHEMA"]
string[]Specific SQL operations to block unconditionally, regardless of approval. These operations cannot be snapshotted and are too destructive to allow.
require_recovery_for_criticalOPTIONAL
default: true
booleanIf true, CRITICAL operations require a verified snapshot before approval is accepted. Set to false only in development environments.
block_unknown_or_parse_failureOPTIONAL
default: true
booleanIf true, SQL that cannot be parsed is treated as CRITICAL. Strongly recommended for production.
block_unrecoverable_operationsOPTIONAL
default: true
booleanIf true, operations classified as unrecoverable (e.g., DROP DATABASE) are blocked even with explicit approval.
max_snapshot_age_secondsOPTIONAL
default: 300
numberMaximum age of a snapshot (in seconds) for it to be considered valid for the recovery gate.
require_sidecar_heartbeatOPTIONAL
default: true
booleanIf true, the sidecar must have reported a heartbeat within max_sidecar_heartbeat_seconds or CRITICAL operations are blocked.
max_sidecar_heartbeat_secondsOPTIONAL
default: 120
numberMaximum age of the sidecar heartbeat in seconds.
impact_analysis_enabledOPTIONAL
default: true
booleanIf true, Backstop asks PostgreSQL for an EXPLAIN plan estimate for UPDATE/DELETE operations and may escalate HIGH to IMPACT_CRITICAL.
max_write_rows_without_criticalOPTIONAL
default: 1000
numberThreshold for escalating to IMPACT_CRITICAL based on estimated affected row count.
max_write_percent_without_criticalOPTIONAL
default: 50
numberThreshold for escalating to IMPACT_CRITICAL based on estimated percentage of table affected (0–100).
protected_tablesOPTIONAL
default: []
string[]Tables that receive additional scrutiny. Any write to a protected table is escalated to at least HIGH.
protected_columnsOPTIONAL
default: {}
objectMap of table name to column names. Writes to protected columns trigger escalation and alert.
max_blocked_attempts_per_windowOPTIONAL
default: 3
numberNumber of blocked/denied queries an agent can submit within dangerous_retry_window_seconds before being quarantined.
quarantine_duration_secondsOPTIONAL
default: 1800
numberHow long a quarantined agent is blocked from submitting any queries.
dangerous_retry_window_secondsOPTIONAL
default: 600
numberThe time window (in seconds) over which blocked attempt counts are tracked for quarantine purposes.

Development (permissive)

{
  "require_approval_for_risks": ["CRITICAL"],
  "block_operations": ["DROP DATABASE"],
  "require_recovery_for_critical": false,
  "block_unknown_or_parse_failure": false,
  "impact_analysis_enabled": false,
  "max_blocked_attempts_per_window": 10
}

Production (strict)

{
  "require_approval_for_risks": ["HIGH", "IMPACT_CRITICAL", "CRITICAL"],
  "block_operations": ["DROP DATABASE", "DROP SCHEMA"],
  "require_recovery_for_critical": true,
  "block_unknown_or_parse_failure": true,
  "block_unrecoverable_operations": true,
  "max_snapshot_age_seconds": 300,
  "require_sidecar_heartbeat": true,
  "max_sidecar_heartbeat_seconds": 120,
  "impact_analysis_enabled": true,
  "max_write_rows_without_critical": 1000,
  "max_write_percent_without_critical": 50,
  "protected_tables": ["users", "payments"],
  "protected_columns": { "users": ["password", "api_key"] },
  "max_blocked_attempts_per_window": 3,
  "quarantine_duration_seconds": 3600,
  "dangerous_retry_window_seconds": 600
}