BROWSE DOCS
REFERENCE
DOCS / CLI

finowl guard

The gate. It fetches the rules in force for this product and environment, evaluates cost against the change and governance against the bundle, and exits non-zero when a blocking rule is violated.
finowl guard [OPTIONS]

  -b, --bundle PATH          Path to the databricks.yml bundle file.  [default: databricks.yml]
  -t, --target TEXT          Target environment to act on.  [required]
  -o, --output [table|json]  Output format.  [default: table]
  -p, --profile TEXT         Authentication profile to act as.  [env: FINOWL_CONFIG_PROFILE]

Exit codes

CODEMEANINGIN CI
0Every rule in force passed, or warned.The step succeeds.
1At least one rule with action: block was violated.The step fails. This is the gate.
2A check could not run — no credential, unknown target, missing workload words, pricing unavailable, malformed bundle.The step fails, and the reason is a setup problem rather than a cost one.
IMPORTANT
1 and 2 mean different things and deserve different responses. 1 is the product working: something costs too much. 2 means nothing was checked, so treating it as a pass leaves the pipeline ungated.

What it does, in order

  1. Checks the bundle exists. Exits 2 naming the path it looked for.
  2. Checks the target against the bundle's targets: block. Before the platform is contacted at all — naming an environment that does not exist is answerable from the bundle alone.
  3. Resolves the credential.
  4. Verifies the project identity and fails on name drift between finowl.yml and the platform.
  5. Fetches the rules— account and organization policies merged, filtered to this environment, with a budget rule carrying this product's own budget.
  6. Reads the bundle resolved for the target, and applies the workload gate.
  7. Evaluates cost against the diff, and governance against the resolved bundle.
  8. Reports the run, then exits.

The cost check

Cost is evaluated against the change, using the same diff finowl diff produces. The guard evaluates the P90 total, not the midpoint.

$ finowl guard --target prod

                          Product-wide total
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┓
┃ Component                  ┃ Note                  ┃ Amount ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━┩
│ This target (after change) │ estimation            │ 193.49 │
│ Other environments         │ recorded estimations  │ 130.61 │
│ Storage & data transfer    │ not yet measured      │      — │
└────────────────────────────┴───────────────────────┴────────┘

                     Blocked Thresholds
┏━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
┃ Threshold             ┃ Type              ┃ Limit ┃ Actual ┃ Action ┃
┡━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━╇━━━━━━━━┩
│ Max cost increase ($) │ increase_absolute │  50.0 │  58.40 │ BLOCK  │
└───────────────────────┴───────────────────┴───────┴────────┴────────┘

                    Passed Thresholds
┏━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
┃ Threshold        ┃ Type     ┃ Limit ┃ Actual ┃ Action ┃
┡━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━╇━━━━━━━━╇━━━━━━━━┩
│ Budget exceeding │ absolute │ 400.0 │ 324.10 │ BLOCK  │
└──────────────────┴──────────┴───────┴────────┴────────┘

The absolute limit is this product's own budget, not an org default.

✗ BLOCKED — one or more block thresholds exceeded.

When the cost check is skipped

SITUATIONMESSAGEEFFECT
No cost rules reach this productWarning: No cost policy defined — cost check skipped.Governance still runs, and the bundle plan is never run — so this is the one case where guard needs no Databricks workspace access.
No cluster changes in the planNo cluster changes detected — costs are unchanged.Passes. There is nothing to price a movement on.
The product has no committed budgetThe budget rule drops out of the verdict.The total is still reported. A rule cannot invent a ceiling nobody agreed to.

The governance check

Governance rules are evaluated against the target-resolved bundle, not the base declaration. A target overlay can replace job_clusters wholesale, so the guard has to check what is actually being deployed.

                        Governance Policy Results
┏━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━┓
┃ Rule                    ┃ Type                    ┃ Action ┃ Status ┃ Resources ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━┩
│ Team tag on compute     │ required_tag            │ BLOCK  │  FAIL  │         1 │
│ Resource naming         │ naming_convention       │  WARN  │  WARN  │         1 │
│ Compute policy required │ required_compute_policy │ BLOCK  │  PASS  │         — │
└─────────────────────────┴─────────────────────────┴────────┴────────┴───────────┘

✗ BLOCKED — one or more governance rules failed.

One result per scoped surface. A rule with scope: [job, warehouse] produces two results, and each names the resources that failed it. Full reference in Governance rules.

In CI

GitHub Actions
      - name: Cost and governance guard
        run: finowl guard --target "$BUNDLE_TARGET"

That is the whole integration. No API key, no threshold in the workflow file, nothing to redeploy when a rule changes — the rules are fetched at run time, so an administrator tightening a policy takes effect on the next pipeline run.

Put the guard before the deploy step and make the deploy depend on it. A gate that runs after the deployment reports a cost that already exists.

Warn first

Introducing a rule as warn and watching what it would have caught costs nothing and tells you whether the threshold is right. A warn rule can never fail a build. Promote it to block once the noise is gone.

JSON output

finowl guard -t prod -o json
{
  "command": "guard",
  "target": "prod",
  "passed": false,
  "result": {
    "cost": {
      "passed": false,
      "delta": 58.40,
      "cost_before": 265.70,
      "cost_after": 324.10,
      "violations": [ { "name": "Max cost increase ($)", "type": "increase_absolute",
                        "limit": 50.0, "actual": 58.40, "action": "block" } ],
      "warnings": [],
      "checked": [ ... ],
      "resources": [ ... ]
    },
    "governance": {
      "passed": true,
      "results": [ ... ]
    }
  }
}
  • passed appears on the envelope and again on each of cost and governance, so a consumer never has to re-derive which half failed.
  • --output json does not change the exit code. Parse the output and check $?.