Metadata-Version: 2.4
Name: openapi-drift
Version: 0.1.0
Summary: Does the deployed service still do what your OpenAPI document says, and can a machine read it? A drift check, not a fuzzer and not a syntax validator.
Author-email: Vincent Gonzalez <hello@f-keys.com>
License: MIT
Project-URL: Homepage, https://github.com/vince-gonzalez/openapi-drift
Project-URL: Source, https://github.com/vince-gonzalez/openapi-drift
Project-URL: Issues, https://github.com/vince-gonzalez/openapi-drift/issues
Keywords: openapi,swagger,api,drift,contract-testing,ci,schema,function-calling,llm,agents
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: yaml
Requires-Dist: PyYAML>=5.1; extra == "yaml"
Dynamic: license-file

```
╔════════════════════════════════════════════════════════════════════════════════════════════╗
║                                                                                            ║
║                    ██████╗ ██████╗ ███████╗███╗   ██╗ █████╗ ██████╗ ██╗                   ║
║                   ██╔═══██╗██╔══██╗██╔════╝████╗  ██║██╔══██╗██╔══██╗██║                   ║
║                   ██║   ██║██████╔╝█████╗  ██╔██╗ ██║███████║██████╔╝██║                   ║
║                   ██║   ██║██╔═══╝ ██╔══╝  ██║╚██╗██║██╔══██║██╔═══╝ ██║                   ║
║                   ╚██████╔╝██║     ███████╗██║ ╚████║██║  ██║██║     ██║                   ║
║                    ╚═════╝ ╚═╝     ╚══════╝╚═╝  ╚═══╝╚═╝  ╚═╝╚═╝     ╚═╝                   ║
║                                                                                            ║
║                            ██████╗ ██████╗ ██╗███████╗████████╗                            ║
║                            ██╔══██╗██╔══██╗██║██╔════╝╚══██╔══╝                            ║
║                            ██║  ██║██████╔╝██║█████╗     ██║                               ║
║                            ██║  ██║██╔══██╗██║██╔══╝     ██║                               ║
║                            ██████╔╝██║  ██║██║██║        ██║                               ║
║                            ╚═════╝ ╚═╝  ╚═╝╚═╝╚═╝        ╚═╝                               ║
║                                                                                            ║
║                        does the service still do what the spec says                        ║
║                                                                                            ║
╚════════════════════════════════════════════════════════════════════════════════════════════╝
```
Your OpenAPI document is a promise about a service. Nothing keeps the two
together, so it quietly becomes a description of what the service **used to**
do, and every consumer finds out one failed call at a time.

This answers two questions:

- **Does the deployed service still do what this says?**
- **Can a machine read it and act on it?**

```
pip install openapi-drift
```

```
openapi-drift openapi.json                          # static checks
openapi-drift https://api.example.com/openapi.json --live
openapi-drift openapi.json --live --base-url https://api.example.com
```

Exits `0` clean, `1` on drift, `2` when it could not check.

## What it is not

| | |
|---|---|
| **Not a fuzzer.** | `schemathesis` generates traffic hunting for crashes. This calls what you documented and compares. |
| **Not a syntax validator.** | `openapi-spec-validator` tells you the document is well-formed. A perfectly valid document can be unusable. |

## The check nobody else runs

A response schema behind a `$ref` is correct, valid, and **useless to the
tools that turn an operation into a function signature** — they do not
dereference. A validator sees a schema; a converter sees an argument with no
type.

That cost a working week to learn on a real spec that passed every other
check. It is reported as `ref_in_response`, and `--allow-refs` silences it if
nothing consuming your document does function calling.

## What it finds

**Drift** — exits 1:

| | |
|---|---|
| `missing_path` | you document a path the service does not serve |
| `status_drift` | it answered with a status you do not describe |
| `content_type_drift` | it answered in a media type you do not declare |
| `schema_drift` | a required field vanished, or a type changed |
| `ref_in_response` | a schema no function-calling converter can read |
| `dangling_ref` | a pointer to a definition that is not there |
| `duplicate_operation_id` | two operations collide under one name |

**Warnings** — exit 0 unless `--warnings-as-errors`:

`untyped_schema` · `no_operation_id` · `no_description` · `relative_server` ·
`undocumented_field`

## It will not tell you it passed when it did not

An empty document, a document with no paths, and one where every operation
needs an argument all exit **2**, not 0. A pass on something never examined
is the most dangerous sentence a build tool can say, and it is the reason
this exists at all.

## In CI

```yaml
- uses: vince-gonzalez/openapi-drift@v1
  with:
    spec: https://api.example.com/openapi.json
    live: "true"
```

Or directly:

```yaml
- run: pip install openapi-drift
- run: openapi-drift openapi.json --live
```

## Only safe calls

`--live` calls **parameterless GETs only**. A path with a placeholder, or a
required query parameter, is skipped rather than guessed at — a guessed value
reports drift that is the checker's fault. Nothing is written, ever.

## Licence

MIT.
