Custom Policy Checks
Custom Policy Checks are Python scripts that let you specify advanced policies using the Liquibase Policy Checks framework. Using custom policy checks, you can enforce compliance for a wide array of security, code standards, data quality, and more.
While it's possible to configure the behavior of many built-in Liquibase policy checks using regular expressions (such as PatternAFollowedByPatternB
), those checks may not be robust enough for complex governance requirements. In contrast, you can use custom policy checks to create unique checks for any situation in your Liquibase workflow.
Note: This is a Liquibase Pro feature, so you need a Liquibase Pro License Key to use it.
Business benefits
- Ensure compliance to your specific issues and tech stack
- Develop at your own cadence
- Share easily across your entire organization
- Easily customize from a base template
Quickstart: Create a custom policy check
For a detailed, step-by-step tutorial of creating and deploying a check, see Create a Custom Policy Check. This tutorial explains:
- Prerequisites for using custom policy checks
- Downloading the Liquibase Checks extension
- Creating your first custom policy check based on a template
- Configuring your check in the Liquibase checks framework
- Running your check using Liquibase commands
If you use Docker, see Use Custom Policy Checks with Docker for guidance on configuring the Liquibase image.
Sample custom policy checks
For sample Python scripts that you can run as policy checks, see Sample Custom Policy Check Scripts.
For even more samples, see this GitHub repository: liquibase/custom_policychecks. Liquibase provides a number of real-world samples of custom policy checks in this repository.
If you need help deploying your check, see Create a Custom Policy Check.
Liquibase checks framework
The logic of a custom policy check goes in a Python (.py
) script file:
- You can associate each custom policy check with one Python script. (Your Python script can reference modules and helper scripts.)
- You can write and modify that script without using Liquibase commands: it's just a Python file.
- You should store all your Python scripts in the Liquibase working directory or other accessible location.
- You should keep the logic for different checks in different Python files.
Liquibase commands
You can integrate your Python file into Liquibase by using the same Policy Checks Commands you would use to copy a built-in policy check. Specifically, there is a built-in policy check called CustomChecksTemplate
that you can copy and customize to specify your own logic. In the CLI, you specify a short name for your custom check in Liquibase, the Python script containing the check logic to run, and other configurations like the check's severity level.
You should write your Python script to test one changeset or database object. Like other checks, you can deploy custom policy checks by using the run
command. Liquibase then runs your Python script over all the objects in the domain you specify:
- Once per changeset in your changelog (if you set
--checks-scope=changelog
) - Once per object in a database snapshot (if you set
--checks-scope=database
)
Custom policy checks are disabled by default. You can enable them by setting the checks run
command parameter --checks-scripts-enabled=true
using any of the standard methods to set Liquibase parameters.
Automation
You can deploy custom policy checks into your CI/CD automation the same way as built-in checks. This allows your code to be robust but keeps your processes simple.
When you configure your custom policy check, specify a severity code (exit code) for that check. Your external CI/CD tools can use this exit code to know how to react when a check triggers in your pipeline.
Python runtime dependencies
Liquibase is a Java application. On the back-end, Liquibase uses the GraalPy API to run all custom policy check Python scripts via Java. Liquibase runs custom policy checks in a built-in Python virtual environment that comes with the Liquibase checks extension JAR. GraalVM also provides "patches" for some Python packages, such as replacing some C extensions with Java implementations. This optimizes performance to ensure your Python scripts run efficiently.
Optionally, you can run your Python scripts in a custom virtual environment. To learn how to configure one, see Create a Python Virtual Environment.
Python script pseudocode
Any Python script you use in the custom policy check framework includes:
- Imports of useful Liquibase modules to access the Liquibase API.
- Clearly named variables that call on functions in the Liquibase modules (for ease of use).
- The logic of your custom check; the code for Liquibase to run against a changeset or database object.
- A default return code (
False
).
To demonstrate that structure, here's some Python pseudocode:
import modules
define a reusable variable = use Liquibase modules to get changelog object information
for each change type in the changeset:
if this condition is met, then do the following:
tell liquibase = the check triggered!
send this message as output = "NOOOOO"
exit script with return code 1
otherwise, return false
Note: Your Python script should test a single changeset. Liquibase runs it iteratively across your entire changelog.
Tip: In your changelog, it is a best practice to use only one change per changeset. However, if you have multiple changes within a single changeset, this pseudocode loops through all of them.
import modules
define a reusable variable = use Liquibase modules to get database object information
if this condition is met, then do the following:
tell liquibase = the check triggered!
send this message as output = "NOOOOO"
exit script with return code 1
otherwise, return false
Note: Your Python script should test a single database object. Liquibase runs it iteratively across your entire database.
For executable code samples, see Sample Custom Policy Check Scripts.
To configure your Python script in the Liquibase policy checks framework, see Create a Custom Policy Check.
To display more advanced output when checks trigger, see Write Dynamic Status Messages for Custom Policy Checks.
Limitations
- The
loadData
Change Type is not supported. - When you run
checks run --checks-scope=database
(or if you tell Liquibase to require a snapshot on a changelog-scoped check), Liquibase generates a database snapshot. If your database contains a very large number of complex objects, thesnapshot
command may take a long time to execute.- If you experience memory limitations while trying to generate the snapshot for database-scoped checks, see Memory Limits of Inspecting Large Schemas.
- If you want to manually create a snapshot to run database-scoped checks against an offline version of your database, see the instructions on
checks-scope
.
- As of Liquibase 4.30.0, you can use the custom policy checks framework only to analyze your changelog and database. You cannot natively use custom policy checks against other Liquibase resources like properties files and flow files.