If icon
WorkingDirectory icon
Script icon
Docker icon
Clone icon
Commands icon
Set icon
Request icon
Comment icon
Fail icon
Log icon
Webhook icon

Block breaking OpenAPI changes before they merge

Gate GitHub pull requests on semantic OpenAPI compatibility with oasdiff, exact evidence, PR feedback, commit status and configurable baselines.

Categories
CoreInfrastructure

An OpenAPI file can remain valid YAML while silently breaking every generated client. This blueprint turns API compatibility into a release gate. A GitHub pull-request webhook starts the flow, Kestra resolves immutable base and head commits (including forked PRs), oasdiff performs semantic comparison, and the flow publishes exact evidence before it passes or blocks the release.

This is more than a CLI wrapper. Kestra owns baseline selection, policy, immutable checkout, artifact lifecycle, GitHub feedback, status gating and result history. The same comparison can be replayed later from the recorded SHAs.

Try the two-act demo

No secrets are needed for demo mode.

  1. Run with mode: DEMO_BREAKING. The candidate removes GET /pets/{petId} and makes the response property name optional. The report names the exact operations, paths and oasdiff rules, and the execution ends FAILED only after both artifacts and the KV result exist.
  2. Run again with mode: DEMO_COMPATIBLE. The endpoint is restored and the only change is a new optional avatarUrl response property. The gate returns PASS.
  3. Download json_report for automation or markdown_report for review evidence. The latest summary is also stored at openapi_guardian_petstore in namespace KV storage.

How the GitHub flow works

  1. github_pull_request accepts GitHub pull_request events. relevant_event processes opened, reopened, synchronize and ready_for_review; label, review and close noise is ignored.
  2. resolve_pull_request calls the GitHub API instead of trusting webhook SHAs. It verifies that the event repository matches the configured repository, resolves the selected baseline, and records the actual base and fork-aware head clone URLs.
  3. clone_baseline and clone_candidate use the Git plugin to check out exact immutable commits without submodules. verify_material checks each detached HEAD, confines both spec paths to their clone, removes symlinks and strips .git before analysis.
  4. compare_contracts runs tufin/oasdiff:v1.32.1 in a networkless Docker container. Exit code 1 is captured as a policy decision; parser or infrastructure errors still fail immediately. Remote $ref resolution is disabled to prevent SSRF.
  5. build_evidence parses oasdiff JSON and writes compatibility-report.json plus compatibility-report.md. Findings include severity, HTTP method, API path, explanation, rule ID and source line.
  6. record_latest_result stores the verdict in Kestra KV. In GITHUB_PR mode, set_commit_status writes kestra/openapi-compatibility on the exact head SHA and comment_on_pull_request updates one stable comment rather than adding one per push.
  7. enforce_gate runs last. Incompatible changes fail the execution only after the evidence and feedback are durable; compatible changes pass.

Compatibility policy

  • baseline_strategy: PR_BASE compares with the base SHA recorded by GitHub for the PR. TARGET_BRANCH_HEAD re-resolves the latest target branch, and CUSTOM_REF supports a release tag, branch or SHA.
  • fail_on: ERR blocks definite breaks. WARN is stricter and also blocks changes oasdiff classifies as potentially breaking.
  • stability_level can limit enforcement to draft, alpha, beta or stable operations when your specs use oasdiff stability extensions.
  • stable_deprecation_days and beta_deprecation_days encode removal grace periods.
  • flatten_allof normalizes inherited schemas before comparing them.
  • use_repository_policy automatically uses .oasdiff.yaml from the PR head for custom severity mappings and documented exceptions. Keep referenced ignore files in the repository.

Inputs

  • mode (SELECT, default DEMO_BREAKING): self-contained breaking demo, compatible demo, or real GitHub PR.
  • repository (STRING): configured base repository in owner/name form. It is never accepted from an untrusted payload.
  • pr_number (INT): manual PR number; webhook runs map this from trigger.body.number.
  • spec_path / base_spec_path (STRING): candidate and optional differently named baseline spec paths.
  • baseline_strategy / baseline_ref: how the immutable baseline SHA is selected.
  • fail_on, stability_level, deprecation windows, flatten_allof, use_repository_policy: compatibility policy controls.
  • publish_to_github (BOOL, default true): switch off GitHub writes while testing a real PR.
  • service_id (STRING): scopes the latest-result KV key and PR comment update tag.

Prerequisites

  • Kestra with Docker available to the Worker and the Git, GitHub and Scripts plugins.
  • For real PRs, set repository in the flow and create a GitHub repository webhook for Pull requests. Use JSON content and point it to /api/v1/main/executions/webhook/company.platform/openapi-breaking-change-guardian/<key>.
  • The Docker comparison is deliberately offline. Bundle local $ref files in the repository; remote HTTP $ref values are rejected.

Secrets

  • OPENAPI_GUARDIAN_WEBHOOK_KEY: long random key in the Kestra webhook URL.
  • GITHUB_TOKEN: fine-grained token with Contents: read, Pull requests: read, Issues: write, and Commit statuses: write on the base repository and read access to any private fork. Public fork PRs only need base-repository permissions.

Expected outputs

  • outputs.verdict: PASS, WARN, BLOCK or SKIPPED.
  • outputs.json_report: downloadable compatibility-report.json, schema kestra-openapi-breaking-change-guardian/1.0.
  • outputs.markdown_report: downloadable Markdown evidence and the body of the upserted PR comment.
  • Namespace KV openapi_guardian_<service_id>: latest verdict, SHAs, counts and execution ID.

GitHub setup

Protect the target branch with the required status check kestra/openapi-compatibility. On every relevant PR update, the flow replaces the status for the new head SHA and updates the existing report comment. A failed Kestra execution and a failing GitHub status then represent the same policy decision.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.