Ad-hoc Approvals for Declarative Schema Migrations Using GitLab CI
Introduction
While pre-approval workflows provide a structured way to review schema changes during CI/CD, they may not catch every scenario. For example, manual changes to the target database can introduce undetected diffs that aren't part of the version-controlled history.
In such cases, ad-hoc approvals act as a final checkpoint. When the component schema-apply runs,
it performs an additional check to detect any remaining, unapproved differences between the desired and target schemas and generates a new plan that must be approved before execution.
Enable ad-hoc approval when:
- Manual changes are made to the database frequently
- You need a last-mile check before production rollout
- You want to ensure that all changes are explicitly approved before they are applied
Overview
Using the lint-review configuration, users may control how the schema-apply
component should behave when it encounters a schema change without a pre-approved plan. The possible values for this configuration are:
| Description | |
|---|---|
ALWAYS | Pauses the migration process and waits for human approval before applying the schema change. |
WARNING | Analyze the proposed schema change and wait for approval if any diagnostics are found. |
ERROR | Analyze the proposed schema change and wait for approval if any severe diagnostics (errors) are found. |
Guide: Using Ad-hoc Approvals
Step 1: Set up a simple GitLab repo with Atlas
Follow the setup instructions from the pre-approval guide.
Step 2: Modify the .gitlab-ci.yml pipeline
After setting up the pre-approval workflow in the previous step, you will have a file named .gitlab-ci.yml in your repository.
This file contains the pipeline that runs on every merge request to check for schema changes.
We will modify this file to add the ad-hoc approval step.
services:
- postgres:latest
variables:
POSTGRES_DB: dev
POSTGRES_USER: postgres
POSTGRES_PASSWORD: pass
stages:
- plan
- deploy
include:
- component: $CI_SERVER_FQDN/arigaio/atlas/schema-plan@~latest
inputs:
stage: plan
env: ci
dev-url: 'postgres://postgres:pass@postgres/dev?sslmode=disable'
atlas-cloud-token: $ATLAS_CLOUD_TOKEN
gitlab-token: $GITLAB_TOKEN
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- component: $CI_SERVER_FQDN/arigaio/atlas/schema-plan-approve@~latest
inputs:
stage: deploy
branches:
- main
env: cd
from: $NEON_DB_URL
atlas-cloud-token: $ATLAS_CLOUD_TOKEN
rules:
- if: $CI_COMMIT_BRANCH == "main"
- component: $CI_SERVER_FQDN/arigaio/atlas/schema-push@~latest
inputs:
stage: deploy
branches:
- main
env: cd
atlas-cloud-token: $ATLAS_CLOUD_TOKEN
rules:
- if: $CI_COMMIT_BRANCH == "main"
- component: $CI_SERVER_FQDN/arigaio/atlas/schema-apply@~latest
inputs:
stage: deploy
branches:
- main
url: $NEON_DB_URL
lint-review: ALWAYS
env: cd
atlas-cloud-token: $ATLAS_CLOUD_TOKEN
rules:
- if: $CI_COMMIT_BRANCH == "main"
In the deploy stage, we added the lint-review: ALWAYS option to the schema-apply component.
This option tells the component to pause and wait for human approval if there are any schema changes that are not pre-approved.
Commit the changes and create merge request for changes:
git checkout -b ad-hoc-approval
git add .
git commit -m "Enable ad-hoc-approval"
git push origin ad-hoc-approval
Step 3: Verify the changes
We currently have an open MR that doesn't include a pre-approval plan, since there are no schema changes. To simulate a diff, we'll manually modify the Neon database.
- Open the Neon SQL editor.
- Add a new column by running the following SQL command:
ALTER TABLE users ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;
At this point, there is a difference between the desired schema and the actual state of the target database.
Now, merge the MR. You'll see that the schema-apply component fails and requires approval.
Visit the link in the failed job output, you'll see that the plan includes statement about dropping the created_at column.
Conclusion
This guide showed how ad-hoc approvals add a final layer of protection against unplanned schema changes by introducing a manual review step before deployment.