Skip to content
Back to skills

Openapi Contract Diff

ASecurity

Diffs two OpenAPI versions for breaking changes (removed endpoints, deleted schemas, narrowed enums, response shape changes) using `oasdiff breaking`, severity-classifies the findings (ERR / WARN / INFO), and gates CI with `--fail-on`. Use when reviewing an OpenAPI spec change in a PR or on a release tag.

  • 10 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 12, 2026
testinggobashdockertestinggitapi

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 12 files and shows the line behind each finding

Scanned October 12, 2026

npx -y skills add testland/qa --skill openapi-contract-diff --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Openapi Contract Diff?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Openapi Contract Diff
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/testland-openapi-contract-diff/badge)](https://www.skillsdirectory.com/skills/testland-openapi-contract-diff)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: openapi-contract-diff
description: "Diffs two OpenAPI versions for breaking changes (removed endpoints, deleted schemas, narrowed enums, response shape changes) using `oasdiff breaking`, severity-classifies the findings (ERR / WARN / INFO), and gates CI with `--fail-on`. Use when reviewing an OpenAPI spec change in a PR or on a release tag."
---

# openapi-contract-diff

## Overview

`oasdiff` is the canonical CLI for comparing two OpenAPI specifications
and reporting **breaking changes** ([oasdiff-readme][readme]). It runs
over 250 checks against the diff and classifies each finding into one
of three severity tiers ([oasdiff-breaking][breaking]):

| Severity | Meaning                                                        |
|----------|----------------------------------------------------------------|
| `ERR`    | Definite breaking change - should be avoided.                 |
| `WARN`   | Potential breaking change - developers should be aware.        |
| `INFO`   | Non-breaking change.                                           |

[readme]: https://github.com/oasdiff/oasdiff
[breaking]: https://github.com/oasdiff/oasdiff/blob/main/docs/BREAKING-CHANGES.md

This is the schema-driven counterpart to
`pact-contract-testing`: use
oasdiff when **you don't control the consumers** (public APIs, third-
party integrations) and need to gate breaking-change shipment based on
the spec alone.

## When to use

- The repo defines an OpenAPI 3 spec (`openapi.yaml`, `openapi.json`,
  or split-file equivalent).
- The team wants a CI gate that fails the build on breaking spec
  changes between the PR and the deployed version.
- The API has external consumers (no Pact possible) or the team isn't
  ready to invest in consumer-driven contracts yet.
- You need a one-shot review tool for "is this PR going to break
  consumers?"

## Authoring (no authoring - the spec is the contract)

Unlike Pact, oasdiff doesn't add tests to the repo. Instead it consumes
two OpenAPI specs and emits a diff. Authoring effort goes into
**keeping the spec authoritative** - i.e. ensuring the OpenAPI file in
the repo accurately describes the implementation. Tools that close the
spec-vs-implementation gap (Schemathesis, Spectral lint) pair well with
this skill but are out of scope.

## Install

```bash
# Go install (preferred for native CLI)
go install github.com/oasdiff/oasdiff@latest

# Docker (CI-friendly, no Go toolchain required)
docker pull tufin/oasdiff
```

(Per [oasdiff-readme][readme].)

## Running

### Local diff

```bash
oasdiff breaking openapi-old.yaml openapi-new.yaml
```

(Per [oasdiff-breaking][breaking].)

By default oasdiff prints colorized text. For machine consumption, use
`--format`:

```bash
oasdiff breaking --format json openapi-old.yaml openapi-new.yaml > breaking.json
oasdiff breaking --format yaml openapi-old.yaml openapi-new.yaml
oasdiff breaking --format markdown openapi-old.yaml openapi-new.yaml
oasdiff breaking --format html openapi-old.yaml openapi-new.yaml > breaking.html
```

Available formats: text (default), JSON, YAML, markdown, HTML, plus
single-line ([oasdiff-breaking][breaking]).

### Comparing remote specs

The CLI accepts URLs directly:

```bash
oasdiff breaking \
  https://raw.githubusercontent.com/.../openapi-test1.yaml \
  https://raw.githubusercontent.com/.../openapi-test3.yaml
```

(Adapted from [oasdiff-readme][readme].)

### Docker variant

```bash
docker run --rm -t -v "$PWD:/specs" tufin/oasdiff breaking \
  /specs/openapi-old.yaml /specs/openapi-new.yaml
```

### `--fail-on` for CI gating

The exit code is the gate signal ([oasdiff-breaking][breaking]):

```bash
oasdiff breaking --fail-on ERR  ...   # exit 1 on ERR; default behavior most teams want
oasdiff breaking --fail-on WARN ...   # exit 1 on ERR or WARN; stricter
oasdiff breaking --fail-on INFO ...   # exit 1 on any reported change
```

Default for production gates: `--fail-on ERR`. Use `--fail-on WARN` for
stricter projects (financial APIs, public SDKs) where even potentially-
breaking changes need explicit acceptance.

## What counts as breaking

oasdiff ships 250+ checks. The headline breaking patterns
([oasdiff-breaking][breaking]):

- **Endpoint deletion** - removing a path or HTTP method.
- **Removed success response** - e.g. dropping the 200 from a `responses` block.
- **Deleted schemas from `components.schemas`** - even if no longer referenced.
- **Enum value removal** - removing a value from an `enum` array.
  Mark the enum `x-extensible-enum: true` to treat removals as
  non-breaking (clients should ignore unknown values).
- **Response shape narrowing** - changing a property type from `string`
  to `integer`, removing a `required` array entry, etc.
- **Request shape widening into `required`** - making a previously-
  optional request field required.

For the full list, run `oasdiff checks` to dump the active rule set.

## Reading the report

Text output (default) example:

```
1 changes: 1 error, 0 warning, 0 info
error	[response-success-status-removed] at openapi-new.yaml
	in API GET /pets
	the success response status '200' was removed
```

JSON output (for downstream parsing):

```json
[
  {
    "id": "response-success-status-removed",
    "level": 3,
    "operation": "GET",
    "operationId": "listPets",
    "path": "/pets",
    "source": "openapi-new.yaml",
    "section": "paths",
    "text": "the success response status '200' was removed"
  }
]
```

`level: 3` is `ERR`, `2` is `WARN`, `1` is `INFO` per the standard
oasdiff convention. Pipe to `jq` for triage:

```bash
jq -r '.[] | select(.level==3) | "ERR " + .operation + " " + .path + " :: " + .text' breaking.json
```

## CI integration

GitHub Actions example using the Docker image and the `--fail-on ERR`
default:

```yaml
# .github/workflows/openapi-diff.yml
name: openapi-diff

on:
  pull_request:

jobs:
  oasdiff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0   # need merge-base SHA for `git show <base>:openapi.yaml`

      - name: Extract base spec
        run: |
          BASE_SHA=$(git merge-base origin/main HEAD)
          git show $BASE_SHA:openapi.yaml > /tmp/openapi-base.yaml

      - name: Run oasdiff
        run: |
          docker run --rm -v "$PWD:/specs" -v /tmp:/tmp tufin/oasdiff breaking \
            --fail-on ERR \
            --format text \
            /tmp/openapi-base.yaml \
            /specs/openapi.yaml | tee oasdiff-report.txt

      - name: Upload report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: openapi-breaking-report
          path: oasdiff-report.txt
          retention-days: 14
```

`fetch-depth: 0` is required so the merge-base of the PR resolves; the
shallow clone GitHub uses by default doesn't include the merge-base
commit.

For a PR comment workflow, generate `--format markdown` and post via
`actions/github-script@v7` - the markdown table format includes a
clickable per-finding rationale.

## References

- [oasdiff-readme][readme] - install (Go + Docker), output formats, key
  flags.
- [oasdiff-breaking][breaking] - `breaking` subcommand, severity tiers,
  `--fail-on` semantics, breaking-change categories.
- `pact-contract-testing` - the
  consumer-driven counterpart for cases where you control consumers.
- `contract-compatibility-gate` - the gate skill that aggregates oasdiff output with Pact and
  Protobuf verdicts.

Files in this skill

  • .tessl-plugin/plugin.json443 B
  • SKILL.md7.3 KB
  • evals/clean-diff-on-a-route-that-was-never-documented/criteria.json5.4 KB
  • evals/clean-diff-on-a-route-that-was-never-documented/task.md11.8 KB
  • evals/every-additive-change-fails-the-build/criteria.json5 KB
  • evals/every-additive-change-fails-the-build/task.md10.8 KB
  • evals/friday-spec-pr-the-api-team-calls-cosmetic/criteria.json5 KB
  • evals/friday-spec-pr-the-api-team-calls-cosmetic/task.md8.3 KB
  • evals/partner-integration-broke-while-the-check-stayed-green/criteria.json5.4 KB
  • evals/partner-integration-broke-while-the-check-stayed-green/task.md10.1 KB
  • evals/release-gate-printed-go-on-a-removed-200/criteria.json5.2 KB
  • evals/release-gate-printed-go-on-a-removed-200/task.md8.6 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.