Skip to content

CI/CD Integration

noorm supports two CI patterns: a stateless test CI flow (ephemeral database, no secrets) and a vault-aware prod CI flow (real database, encrypted secrets). Both are driven entirely by environment variables — no interactive setup, no files checked into the repo.

Quick Start (Test CI)

For an ephemeral database (spun up inside the CI job), set the connection and run the schema:

bash
export NOORM_CONNECTION_DIALECT=sqlite
export NOORM_CONNECTION_DATABASE=./tmp/test.db
export NOORM_PATHS_SQL=./sql

noorm run build

No identity or ci init required. Use this when templates and changes do not reference vault-backed secrets.

Prod CI (vault-aware)

For a real database where templates read from the vault, use the ci namespace:

bash
# Env: NOORM_IDENTITY_* (private key + name + email) and NOORM_CONNECTION_*
noorm ci init
noorm change ff

noorm ci init reads identity and connection from env vars, writes an ephemeral .noorm/state/state.enc, creates a config (default name ci, override with --name or NOORM_CI_CONFIG_NAME), and marks it active. Later commands in the same job (run build, change ff, ci secrets) operate as if a developer had bootstrapped manually.

One-time setup (developer with vault access):

bash
noorm ci identity enroll --config prod --name "GitHub CI" --email ci@example.com
# Prints NOORM_IDENTITY_PRIVATE_KEY / NAME / EMAIL once — copy to your CI secrets store

The full flow (with diagrams and per-provider examples) lives in the CI automation guide.

Exit Codes

CodeMeaning
0Success
1Configuration, connection, or precondition error (missing env vars, missing state, etc.)
2Partial success (e.g. ci secrets loaded some keys but others errored) or SQL build failure

Environment Variables

Connection

VariableRequiredDescription
NOORM_CONNECTION_DIALECTYessqlite, postgres, mysql, or mssql
NOORM_CONNECTION_DATABASEYesDatabase name or file path
NOORM_CONNECTION_HOSTNoDatabase host
NOORM_CONNECTION_PORTNoDatabase port
NOORM_CONNECTION_USERNoDatabase username
NOORM_CONNECTION_PASSWORDNoDatabase password

Identity (required for ci init and vault-aware flows)

VariableRequiredDescription
NOORM_IDENTITY_PRIVATE_KEYYesX25519 private key, hex PKCS8 DER (96 hex chars)
NOORM_IDENTITY_NAMEYesDisplay name (e.g. "CI Bot")
NOORM_IDENTITY_EMAILYesEmail (e.g. "ci@example.com")
NOORM_CI_CONFIG_NAMENoDefault config name for ci init (override: --name)

Paths

VariableRequiredDescription
NOORM_PATHS_SQLNoSchema directory (default: ./sql)
NOORM_PATHS_CHANGESNoChanges directory (default: ./changes)

GitHub Actions Example (Test CI)

Validates the schema against a fresh SQLite DB, then applies pending changes against Postgres.

yaml
name: Database CI

on:
    push:
        branches: [main]
    pull_request:
        branches: [main]

jobs:
    validate:
        runs-on: ubuntu-latest
        steps:
            - uses: actions/checkout@v4

            - uses: actions/setup-node@v4
              with:
                  node-version: '20'

            - run: npm ci

            - name: Validate schema
              env:
                  NOORM_CONNECTION_DIALECT: sqlite
                  NOORM_CONNECTION_DATABASE: ./tmp/validate.db
                  NOORM_PATHS_SQL: ./sql
              run: |
                  mkdir -p ./tmp
                  npx noorm run build

    deploy:
        runs-on: ubuntu-latest
        needs: validate
        if: github.ref == 'refs/heads/main'
        steps:
            - uses: actions/checkout@v4

            - uses: actions/setup-node@v4
              with:
                  node-version: '20'

            - run: npm ci

            - name: Apply changes
              env:
                  NOORM_CONNECTION_DIALECT: postgres
                  NOORM_CONNECTION_HOST: ${{ secrets.DB_HOST }}
                  NOORM_CONNECTION_DATABASE: ${{ secrets.DB_NAME }}
                  NOORM_CONNECTION_USER: ${{ secrets.DB_USER }}
                  NOORM_CONNECTION_PASSWORD: ${{ secrets.DB_PASSWORD }}
              run: npx noorm change ff

GitHub Actions Example (Prod CI with vault)

Same pipeline, but templates need vault-decrypted secrets:

yaml
- name: Bootstrap CI state
  env:
      NOORM_IDENTITY_PRIVATE_KEY: ${{ secrets.NOORM_CI_KEY }}
      NOORM_IDENTITY_NAME: "GitHub CI"
      NOORM_IDENTITY_EMAIL: "ci@example.com"
      NOORM_CONNECTION_DIALECT: postgres
      NOORM_CONNECTION_HOST: ${{ secrets.DB_HOST }}
      NOORM_CONNECTION_DATABASE: ${{ secrets.DB_NAME }}
      NOORM_CONNECTION_USER: ${{ secrets.DB_USER }}
      NOORM_CONNECTION_PASSWORD: ${{ secrets.DB_PASSWORD }}
  run: npx noorm ci init --name prod

- name: Apply changes
  run: npx noorm change ff

Common Commands

CommandDescription
noorm ci initBootstrap ephemeral state from env vars
noorm ci secrets --file <path>Batch-load secrets from a dotenv file
noorm run buildExecute all SQL in schema directory
noorm change ffApply all pending changes
noorm db teardownDrop all database objects

JSON Output

Use --json for structured output:

bash
noorm --json ci init | jq '.stateFile'
noorm --json run build | jq '.status'

See Also