openapi-cli4ai 0.5.1__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openapi_cli4ai-0.7.0/.github/CODEOWNERS +7 -0
- openapi_cli4ai-0.7.0/.github/pull_request_template.md +22 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/.github/workflows/ci.yml +10 -8
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/.github/workflows/codeql.yml +3 -3
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/.github/workflows/publish.yml +4 -4
- openapi_cli4ai-0.7.0/.github/workflows/validate-profiles.yml +26 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/CHANGELOG.md +39 -0
- openapi_cli4ai-0.7.0/CONTRIBUTING.md +78 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/PKG-INFO +5 -2
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/README.md +2 -0
- openapi_cli4ai-0.7.0/profiles/README.md +114 -0
- openapi_cli4ai-0.7.0/profiles/community/.gitkeep +2 -0
- openapi_cli4ai-0.7.0/profiles/community/xquik.toml +11 -0
- openapi_cli4ai-0.7.0/profiles/index.json +33 -0
- openapi_cli4ai-0.7.0/profiles/verified/petstore.toml +11 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/pyproject.toml +22 -1
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/src/openapi_cli4ai/__init__.py +1 -1
- openapi_cli4ai-0.7.0/src/openapi_cli4ai/_state.py +22 -0
- openapi_cli4ai-0.7.0/src/openapi_cli4ai/_ui.py +16 -0
- openapi_cli4ai-0.7.0/src/openapi_cli4ai/catalog.py +247 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/src/openapi_cli4ai/cli.py +384 -249
- openapi_cli4ai-0.7.0/src/openapi_cli4ai/config.py +254 -0
- openapi_cli4ai-0.7.0/src/openapi_cli4ai/validator.py +253 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/conftest.py +13 -3
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_auth_flow_security.py +2 -2
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_auth_flows.py +5 -8
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_caching.py +1 -1
- openapi_cli4ai-0.7.0/tests/test_catalog.py +387 -0
- openapi_cli4ai-0.7.0/tests/test_catalog_remote.py +162 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_device_flow.py +0 -1
- openapi_cli4ai-0.7.0/tests/test_domain_verified.py +122 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_error_handling.py +10 -8
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_features.py +52 -51
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_foundation.py +12 -10
- openapi_cli4ai-0.7.0/tests/test_profile_anywhere.py +79 -0
- openapi_cli4ai-0.7.0/tests/test_profiles_d.py +119 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_schema_composition.py +0 -1
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_security.py +5 -7
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_v040_hardening.py +11 -10
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/uv.lock +181 -126
- openapi_cli4ai-0.5.1/.github/CODEOWNERS +0 -2
- openapi_cli4ai-0.5.1/CONTRIBUTING.md +0 -50
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/.github/dependabot.yml +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/.github/release.yml +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/.gitignore +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/.pre-commit-config.yaml +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/LICENSE +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/SECURITY.md +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/demo.gif +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/examples/profiles.toml.example +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/openapi-cli4ai +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/src/openapi_cli4ai/__main__.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/src/openapi_cli4ai/py.typed +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/__init__.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/fixtures/petstore_spec.json +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_auth.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_cli_commands.py +1 -1
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_commands.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_coverage_gaps.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_integration.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_oidc.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_profile_management.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_run_command.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_spec_parsing.py +0 -0
- {openapi_cli4ai-0.5.1 → openapi_cli4ai-0.7.0}/tests/test_sse_streaming.py +0 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Default: all PRs require review from a maintainer
|
|
2
|
+
* @dbgorilla/maintainers
|
|
3
|
+
|
|
4
|
+
# Catalog profiles. Both tiers require maintainer approval for now; the
|
|
5
|
+
# community tier can later point at a broader reviewer team.
|
|
6
|
+
/profiles/verified/ @dbgorilla/maintainers
|
|
7
|
+
/profiles/community/ @dbgorilla/maintainers
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!-- Thanks for contributing! Describe your change below. -->
|
|
2
|
+
|
|
3
|
+
## What & why
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<!-- ▼ Delete this whole section if you are NOT adding a catalog profile ▼ -->
|
|
10
|
+
|
|
11
|
+
### Adding a catalog profile — please confirm
|
|
12
|
+
|
|
13
|
+
- [ ] The profile is for a **publicly accessible** API with a stable OpenAPI spec.
|
|
14
|
+
- [ ] I am the API owner, or have the owner's permission.
|
|
15
|
+
- [ ] `source` is the API's **own** developer/docs URL (same registrable domain as `base_url`).
|
|
16
|
+
- [ ] No secrets are inlined — credentials are referenced via `*_env_var` fields only.
|
|
17
|
+
- [ ] `description` is factual (no marketing copy).
|
|
18
|
+
- [ ] I ran `uv run openapi-cli4ai catalog validate profiles/community/<slug>.toml` locally and it passed.
|
|
19
|
+
|
|
20
|
+
> **Reviewer:** independently verify that `base_url` resolves to the claimed
|
|
21
|
+
> service (typosquats and look-alike domains are the main risk), and that the
|
|
22
|
+
> auth shape can't leak a credential to an unexpected host.
|
|
@@ -16,8 +16,8 @@ jobs:
|
|
|
16
16
|
matrix:
|
|
17
17
|
python-version: ["3.11", "3.12", "3.13"]
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
20
|
-
- uses: astral-sh/setup-uv@
|
|
19
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
20
|
+
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
21
21
|
with:
|
|
22
22
|
enable-cache: true
|
|
23
23
|
- name: Set up Python ${{ matrix.python-version }}
|
|
@@ -30,18 +30,20 @@ jobs:
|
|
|
30
30
|
lint:
|
|
31
31
|
runs-on: ubuntu-latest
|
|
32
32
|
steps:
|
|
33
|
-
- uses: actions/checkout@
|
|
34
|
-
- uses: astral-sh/setup-uv@
|
|
33
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
34
|
+
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
35
|
+
- name: Sync dependencies
|
|
36
|
+
run: uv sync --locked
|
|
35
37
|
- name: Ruff check
|
|
36
|
-
run:
|
|
38
|
+
run: uv run ruff check .
|
|
37
39
|
- name: Ruff format check
|
|
38
|
-
run:
|
|
40
|
+
run: uv run ruff format --check .
|
|
39
41
|
|
|
40
42
|
typecheck:
|
|
41
43
|
runs-on: ubuntu-latest
|
|
42
44
|
steps:
|
|
43
|
-
- uses: actions/checkout@
|
|
44
|
-
- uses: astral-sh/setup-uv@
|
|
45
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
46
|
+
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
45
47
|
- name: Sync dependencies
|
|
46
48
|
run: uv sync --locked
|
|
47
49
|
- name: Run mypy
|
|
@@ -16,8 +16,8 @@ jobs:
|
|
|
16
16
|
analyze:
|
|
17
17
|
runs-on: ubuntu-latest
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
20
|
-
- uses: github/codeql-action/init@
|
|
19
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
20
|
+
- uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
|
|
21
21
|
with:
|
|
22
22
|
languages: python
|
|
23
|
-
- uses: github/codeql-action/analyze@
|
|
23
|
+
- uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8
|
|
@@ -13,8 +13,8 @@ jobs:
|
|
|
13
13
|
permissions:
|
|
14
14
|
contents: read
|
|
15
15
|
steps:
|
|
16
|
-
- uses: actions/checkout@
|
|
17
|
-
- uses: astral-sh/setup-uv@
|
|
16
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
17
|
+
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
18
18
|
- name: Build sdist and wheel
|
|
19
19
|
run: uv build
|
|
20
20
|
- name: Upload artifacts
|
|
@@ -42,8 +42,8 @@ jobs:
|
|
|
42
42
|
name: dist
|
|
43
43
|
path: dist/
|
|
44
44
|
- name: Generate attestations
|
|
45
|
-
uses: actions/attest-build-provenance@
|
|
45
|
+
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
|
46
46
|
with:
|
|
47
47
|
subject-path: dist/*
|
|
48
48
|
- name: Publish to PyPI
|
|
49
|
-
uses: pypa/gh-action-pypi-publish@
|
|
49
|
+
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Validate profiles
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- "profiles/**"
|
|
8
|
+
- ".github/workflows/validate-profiles.yml"
|
|
9
|
+
pull_request:
|
|
10
|
+
paths:
|
|
11
|
+
- "profiles/**"
|
|
12
|
+
- ".github/workflows/validate-profiles.yml"
|
|
13
|
+
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
validate:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
22
|
+
- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
|
|
23
|
+
- name: Validate catalog profiles
|
|
24
|
+
run: uv run --locked openapi-cli4ai catalog validate --all
|
|
25
|
+
- name: Check profiles/index.json is current
|
|
26
|
+
run: uv run --locked openapi-cli4ai catalog index --check
|
|
@@ -4,6 +4,45 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
6
6
|
|
|
7
|
+
## [0.7.0] - 2026-09-11
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `--profile` is accepted after the subcommand (`openapi-cli4ai endpoints --profile x`); long form only, since `-p` is reused by subcommands (#52)
|
|
12
|
+
- `catalog install --dry-run` prints the exact profile file that would be written and changes nothing (#53)
|
|
13
|
+
- `catalog uninstall <name>` removes an installed catalog profile plus its cached spec and token, with confirm prompt and `--force` (#54)
|
|
14
|
+
- Drop-in profiles: one file per profile under `~/.openapi-cli4ai/profiles.d/<name>.toml`, read alongside `~/.openapi-cli4ai.toml` (a drop-in overrides a same-named entry). `catalog install` writes there. No migration needed (#56)
|
|
15
|
+
- Remote catalog index: `catalog list`/`search`/`show`/`install` merge `profiles/index.json` from `main` over the bundled catalog (3 s timeout, cached one hour, silent fallback to cache then bundled; every remote entry is re-validated). `OAC_CATALOG_OFFLINE=1` disables it. New `catalog index` command generates the committed index; CI checks it is current (#57)
|
|
16
|
+
- DNS TXT domain verification: a profile may set `domain_verified = true`; `catalog validate` resolves `_openapi-cli4ai.<domain>` and requires `github=<maintainer>`. Shown as a `✓ dns` badge, separate from the tier (#58)
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- `cli.py` split into `config.py`, `catalog.py`, `validator.py` plus small state/UI modules; behavior unchanged (#55)
|
|
21
|
+
- Adopted ruff 0.16's default rule set; the rule selection is no longer implicit (#50, #51)
|
|
22
|
+
- Dependency updates: `typer` 0.27.2, `click` 8.5, `python-dotenv`, `mypy`, `types-PyYAML`, and the GitHub Actions group (#49, #50)
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- Rich swallowed TOML table headers such as `[profiles.x]` in `profile show` output; now rendered as plain text (#53)
|
|
27
|
+
- File paths in install output are never wrapped across lines (#56)
|
|
28
|
+
|
|
29
|
+
## [0.6.0] - 2026-07-31
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **Profile catalog** — browse and install ready-made API profiles: `catalog search` / `show` / `list` / `install` / `validate`. Bundled into the wheel, so it works offline, with two trust tiers (`verified` / `community`) (#25)
|
|
34
|
+
- Global `--profile` / `-p` flag to select a profile for a single invocation (precedence: flag > `OAC_PROFILE` > active profile) (#25)
|
|
35
|
+
- Community-contributed profile: Xquik (#23)
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Dependency updates: `typer` 0.27, `mypy` 2.3, `types-PyYAML`, and the GitHub Actions group (#38, #37)
|
|
40
|
+
- Pin `ruff` and run the locked version in CI so lint is deterministic (no more `uvx`-latest drift) (#39)
|
|
41
|
+
|
|
42
|
+
### Security
|
|
43
|
+
|
|
44
|
+
- Catalog validation hardening: SSRF guard on spec fetches (rejects cloud-metadata/private/loopback hosts, pre- and post-redirect), Public Suffix List domain-ownership check, spec size/redirect/timeout limits, prompt-injection scan of descriptions, and an explicit confirmation before installing unverified community profiles (#25)
|
|
45
|
+
|
|
7
46
|
## [0.5.1] - 2026-07-04
|
|
8
47
|
|
|
9
48
|
### Fixed
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Contributing to openapi-cli4ai
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in contributing!
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
1. Fork the repository
|
|
8
|
+
2. Clone your fork
|
|
9
|
+
3. Install [uv](https://docs.astral.sh/uv/) if you don't have it
|
|
10
|
+
4. Install in editable mode: `uv pip install -e .`
|
|
11
|
+
5. Run `openapi-cli4ai --help` to verify everything works
|
|
12
|
+
|
|
13
|
+
## Project Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
src/openapi_cli4ai/
|
|
17
|
+
__init__.py # Package exports
|
|
18
|
+
__main__.py # python -m support
|
|
19
|
+
cli.py # Typer commands, HTTP/auth flows, spec fetching
|
|
20
|
+
config.py # Config file, cache dir, active-profile precedence
|
|
21
|
+
catalog.py # Bundled profile catalog: load, find, map to a profile
|
|
22
|
+
validator.py # Catalog profile validator (shared by `catalog validate` and CI)
|
|
23
|
+
_state.py # Runtime flags set by the root command (--verbose, --profile, ...)
|
|
24
|
+
_ui.py # Shared Rich consoles and the verbose logger
|
|
25
|
+
openapi-cli4ai # Standalone shim (imports from package)
|
|
26
|
+
tests/ # pytest tests
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Commands live in `src/openapi_cli4ai/cli.py`; it imports the helpers it needs from the service modules, so tests can patch either the service module or the `cli` binding. The standalone `openapi-cli4ai` script is a thin shim that imports from the package.
|
|
30
|
+
|
|
31
|
+
## Testing
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pytest tests/ -m "not integration" -v
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Submitting a Pull Request
|
|
38
|
+
|
|
39
|
+
1. Create a feature branch (`git checkout -b my-feature`)
|
|
40
|
+
2. Make your changes
|
|
41
|
+
3. Run the tests
|
|
42
|
+
4. Commit with a clear message
|
|
43
|
+
5. Push and open a PR
|
|
44
|
+
|
|
45
|
+
## Contributing a Profile to the Catalog
|
|
46
|
+
|
|
47
|
+
`openapi-cli4ai` ships a community catalog of ready-made API profiles under
|
|
48
|
+
[`profiles/`](profiles/README.md). To add one:
|
|
49
|
+
|
|
50
|
+
1. Create `profiles/community/<slug>.toml` following the format in
|
|
51
|
+
[`profiles/README.md`](profiles/README.md).
|
|
52
|
+
2. Reference secrets only via `*_env_var` fields — never commit a token.
|
|
53
|
+
3. Keep the `description` factual. `source` must be the API's own developer or
|
|
54
|
+
docs URL (same domain as `base_url`).
|
|
55
|
+
4. Validate locally: `uv run openapi-cli4ai catalog validate profiles/community/<slug>.toml`
|
|
56
|
+
5. Regenerate the index and commit it: `uv run openapi-cli4ai catalog index`
|
|
57
|
+
6. Optional: claim the domain-verified badge by setting `domain_verified = true`
|
|
58
|
+
and publishing a `_openapi-cli4ai.<domain>` TXT record naming you; see
|
|
59
|
+
"Domain verification" in [`profiles/README.md`](profiles/README.md).
|
|
60
|
+
|
|
61
|
+
CI runs `catalog validate --all` and `catalog index --check` on every PR touching
|
|
62
|
+
`profiles/`, checking the fields, a live spec fetch, ownership, absence of inline
|
|
63
|
+
secrets, any `domain_verified` claim against DNS, and that `profiles/index.json`
|
|
64
|
+
is current — errors appear inline on the PR. Once merged, the profile is visible to every installed CLI within an hour
|
|
65
|
+
via the remote index (see `profiles/README.md`, "Freshness"). Profiles that are primarily promotional will be closed
|
|
66
|
+
without review.
|
|
67
|
+
|
|
68
|
+
## Reporting Issues
|
|
69
|
+
|
|
70
|
+
Open an issue on GitHub. Include:
|
|
71
|
+
- What you tried
|
|
72
|
+
- What happened
|
|
73
|
+
- What you expected
|
|
74
|
+
- The API spec you were using (if relevant)
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: openapi-cli4ai
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Turn any REST API with an OpenAPI spec into an AI-ready CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/dbgorilla/openapi-cli4ai
|
|
6
6
|
Project-URL: Repository, https://github.com/dbgorilla/openapi-cli4ai
|
|
@@ -19,6 +19,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
19
19
|
Classifier: Topic :: Software Development :: Libraries
|
|
20
20
|
Requires-Python: >=3.11
|
|
21
21
|
Requires-Dist: httpx<1,>=0.28
|
|
22
|
+
Requires-Dist: publicsuffix2<3,>=2.2
|
|
22
23
|
Requires-Dist: python-dotenv<2,>=1.0
|
|
23
24
|
Requires-Dist: pyyaml<7,>=6
|
|
24
25
|
Requires-Dist: rich<16,>=13
|
|
@@ -236,6 +237,8 @@ openapi-cli4ai logout
|
|
|
236
237
|
|
|
237
238
|
Profiles are stored in `~/.openapi-cli4ai.toml`. Secrets are referenced via environment variables — never stored in the config file.
|
|
238
239
|
|
|
240
|
+
Profiles can also live one-per-file under `~/.openapi-cli4ai/profiles.d/<name>.toml`, where the file holds the profile's keys directly (no `[profiles.<name>]` header) and the file name is the profile name. `catalog install` writes there so installing, upgrading and uninstalling a profile touch only that file. Both locations are read; a drop-in overrides a same-named entry in `~/.openapi-cli4ai.toml`. `active_profile` is only read from `~/.openapi-cli4ai.toml`.
|
|
241
|
+
|
|
239
242
|
```toml
|
|
240
243
|
active_profile = "myapi"
|
|
241
244
|
|
|
@@ -208,6 +208,8 @@ openapi-cli4ai logout
|
|
|
208
208
|
|
|
209
209
|
Profiles are stored in `~/.openapi-cli4ai.toml`. Secrets are referenced via environment variables — never stored in the config file.
|
|
210
210
|
|
|
211
|
+
Profiles can also live one-per-file under `~/.openapi-cli4ai/profiles.d/<name>.toml`, where the file holds the profile's keys directly (no `[profiles.<name>]` header) and the file name is the profile name. `catalog install` writes there so installing, upgrading and uninstalling a profile touch only that file. Both locations are read; a drop-in overrides a same-named entry in `~/.openapi-cli4ai.toml`. `active_profile` is only read from `~/.openapi-cli4ai.toml`.
|
|
212
|
+
|
|
211
213
|
```toml
|
|
212
214
|
active_profile = "myapi"
|
|
213
215
|
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Profile catalog
|
|
2
|
+
|
|
3
|
+
Ready-made **profiles** for public APIs. A profile is the small bit of config
|
|
4
|
+
`openapi-cli4ai` needs to talk to an API: a base URL, where its OpenAPI spec
|
|
5
|
+
lives, and how it authenticates. The catalog is bundled into the package, so
|
|
6
|
+
these commands work offline; when online they also pick up profiles merged to
|
|
7
|
+
`main` since your release (see [Freshness](#freshness)):
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
openapi-cli4ai catalog search cov # find profiles
|
|
11
|
+
openapi-cli4ai catalog show codecov # preview one
|
|
12
|
+
openapi-cli4ai catalog install codecov # add it to your config, with next steps
|
|
13
|
+
openapi-cli4ai --profile codecov endpoints # use it (no activation needed)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`install` maps the catalog entry into your `~/.openapi-cli4ai.toml`, tells you
|
|
17
|
+
exactly which environment variable to set for auth, and hands you the next
|
|
18
|
+
command — no docs required.
|
|
19
|
+
|
|
20
|
+
## Tiers
|
|
21
|
+
|
|
22
|
+
Listing a profile here is not an endorsement of the product behind it. Trust is
|
|
23
|
+
a **tier**, shown next to every entry, not a gate on being listed.
|
|
24
|
+
|
|
25
|
+
| Tier | Directory | What it means |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| **Verified** | `verified/` | A maintainer confirmed the spec loads and the auth flow works. |
|
|
28
|
+
| **Community** | `community/` | Contributed via PR and passed automated validation. Not manually vetted. |
|
|
29
|
+
|
|
30
|
+
Independently of the tier, a profile can carry a **domain-verified** badge
|
|
31
|
+
(`✓ dns` in listings): the owner of the API's domain has published a DNS TXT
|
|
32
|
+
record naming the maintainer, so the listing is backed by domain control, not
|
|
33
|
+
just a self-declared `source`. See [Domain verification](#domain-verification).
|
|
34
|
+
|
|
35
|
+
New submissions go to `community/`; a maintainer may promote a profile to
|
|
36
|
+
`verified/` after checking it end to end. Installing a **community** profile
|
|
37
|
+
prompts for confirmation (it shows the `base_url` your credentials would be
|
|
38
|
+
sent to); **verified** profiles install without a prompt. Use `--yes` to skip
|
|
39
|
+
the prompt in scripts.
|
|
40
|
+
|
|
41
|
+
## Freshness
|
|
42
|
+
|
|
43
|
+
The bundled catalog is the offline baseline. On top of it, `catalog list`,
|
|
44
|
+
`search`, `show` and `install` fetch [`index.json`](index.json) from this
|
|
45
|
+
repository's `main` branch (3 s timeout, cached for an hour under
|
|
46
|
+
`~/.cache/openapi-cli4ai/`) and merge it in, so a profile is usable as soon as
|
|
47
|
+
its PR merges. Any failure falls back to the cached index, then to the bundled
|
|
48
|
+
copy, silently. Every remote entry is re-checked with the offline validator
|
|
49
|
+
before use; a bad one is skipped. Set `OAC_CATALOG_OFFLINE=1` to never fetch.
|
|
50
|
+
|
|
51
|
+
`index.json` is generated from the TOML files by `openapi-cli4ai catalog index`
|
|
52
|
+
and committed; CI fails a PR whose index is stale.
|
|
53
|
+
|
|
54
|
+
## Profile format
|
|
55
|
+
|
|
56
|
+
One profile per file, named `<slug>.toml`:
|
|
57
|
+
|
|
58
|
+
```toml
|
|
59
|
+
name = "example" # must match the file name
|
|
60
|
+
description = "Example REST API" # one factual line, no marketing
|
|
61
|
+
maintainer = "your-github-username"
|
|
62
|
+
source = "https://example.com/docs" # the API's official docs (same domain as base_url)
|
|
63
|
+
|
|
64
|
+
base_url = "https://api.example.com"
|
|
65
|
+
openapi_url = "https://api.example.com/openapi.json" # or: openapi_path = "/openapi.json"
|
|
66
|
+
|
|
67
|
+
domain_verified = true # optional: see "Domain verification" below
|
|
68
|
+
|
|
69
|
+
[auth]
|
|
70
|
+
type = "api-key" # none | bearer | oidc | device | api-key | basic
|
|
71
|
+
env_var = "EXAMPLE_API_KEY" # reference secrets by env var — never inline them
|
|
72
|
+
header = "x-api-key"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Auth field names match the CLI's runtime config; see
|
|
76
|
+
[`../examples/profiles.toml.example`](../examples/profiles.toml.example) for
|
|
77
|
+
each auth type.
|
|
78
|
+
|
|
79
|
+
## Domain verification
|
|
80
|
+
|
|
81
|
+
To claim the `✓ dns` badge, set `domain_verified = true` in the profile and have
|
|
82
|
+
the API's domain owner publish this TXT record (registrable domain of
|
|
83
|
+
`base_url`, e.g. `api.acme.co.uk` → `acme.co.uk`):
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
_openapi-cli4ai.acme.co.uk. IN TXT "github=<maintainer>"
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`<maintainer>` must equal the profile's `maintainer` field (case-insensitive).
|
|
90
|
+
`catalog validate` resolves the record and fails the PR if it is missing or
|
|
91
|
+
names someone else; the claim is re-checked on every profile change. Remove the
|
|
92
|
+
claim (or the record) to drop the badge. The lookup needs `dnspython`, which
|
|
93
|
+
`uv sync` installs for contributors; end users never resolve DNS.
|
|
94
|
+
|
|
95
|
+
## Contributing a profile
|
|
96
|
+
|
|
97
|
+
1. Create `community/<slug>.toml` in the format above.
|
|
98
|
+
2. Reference secrets only via `*_env_var` fields — **never commit a token**.
|
|
99
|
+
3. Keep `description` factual. `source` must be the API's own developer/docs
|
|
100
|
+
URL (same registrable domain as `base_url`).
|
|
101
|
+
|
|
102
|
+
Validate before opening the PR — the CLI is the single source of truth — and
|
|
103
|
+
regenerate the index:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv run openapi-cli4ai catalog validate profiles/community/<slug>.toml
|
|
107
|
+
uv run openapi-cli4ai catalog index
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
CI runs `catalog validate --all` on every PR touching `profiles/`. It checks the
|
|
111
|
+
fields and (Public Suffix List-based) domain ownership, fetches the OpenAPI spec
|
|
112
|
+
behind SSRF guards with size/redirect/timeout limits, rejects inlined secrets,
|
|
113
|
+
and flags prompt-injection markers in the description. Errors are posted inline
|
|
114
|
+
on the PR.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
name = "xquik"
|
|
2
|
+
description = "Xquik REST API"
|
|
3
|
+
maintainer = "kriptoburak"
|
|
4
|
+
source = "https://xquik.com"
|
|
5
|
+
base_url = "https://xquik.com"
|
|
6
|
+
openapi_url = "https://xquik.com/openapi.json"
|
|
7
|
+
|
|
8
|
+
[auth]
|
|
9
|
+
type = "api-key"
|
|
10
|
+
env_var = "XQUIK_API_KEY"
|
|
11
|
+
header = "x-api-key"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"profiles": [
|
|
3
|
+
{
|
|
4
|
+
"auth": {
|
|
5
|
+
"env_var": "XQUIK_API_KEY",
|
|
6
|
+
"header": "x-api-key",
|
|
7
|
+
"type": "api-key"
|
|
8
|
+
},
|
|
9
|
+
"base_url": "https://xquik.com",
|
|
10
|
+
"description": "Xquik REST API",
|
|
11
|
+
"maintainer": "kriptoburak",
|
|
12
|
+
"name": "xquik",
|
|
13
|
+
"openapi_url": "https://xquik.com/openapi.json",
|
|
14
|
+
"slug": "xquik",
|
|
15
|
+
"source": "https://xquik.com",
|
|
16
|
+
"tier": "community"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"auth": {
|
|
20
|
+
"type": "none"
|
|
21
|
+
},
|
|
22
|
+
"base_url": "https://petstore3.swagger.io/api/v3",
|
|
23
|
+
"description": "Swagger Petstore \u2014 the OpenAPI 3 sample API",
|
|
24
|
+
"maintainer": "dbgorilla",
|
|
25
|
+
"name": "petstore",
|
|
26
|
+
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json",
|
|
27
|
+
"slug": "petstore",
|
|
28
|
+
"source": "https://petstore3.swagger.io",
|
|
29
|
+
"tier": "verified"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"version": 1
|
|
33
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Verified catalog profile. Validated by a maintainer against a live spec.
|
|
2
|
+
name = "petstore"
|
|
3
|
+
description = "Swagger Petstore — the OpenAPI 3 sample API"
|
|
4
|
+
maintainer = "dbgorilla"
|
|
5
|
+
source = "https://petstore3.swagger.io"
|
|
6
|
+
|
|
7
|
+
base_url = "https://petstore3.swagger.io/api/v3"
|
|
8
|
+
openapi_url = "https://petstore3.swagger.io/api/v3/openapi.json"
|
|
9
|
+
|
|
10
|
+
[auth]
|
|
11
|
+
type = "none"
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "openapi-cli4ai"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.7.0"
|
|
8
8
|
description = "Turn any REST API with an OpenAPI spec into an AI-ready CLI"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -30,6 +30,7 @@ dependencies = [
|
|
|
30
30
|
"pyyaml>=6,<7",
|
|
31
31
|
"python-dotenv>=1.0,<2",
|
|
32
32
|
"tomli-w>=1.0,<2",
|
|
33
|
+
"publicsuffix2>=2.2,<3",
|
|
33
34
|
]
|
|
34
35
|
|
|
35
36
|
[project.urls]
|
|
@@ -45,17 +46,37 @@ dev = [
|
|
|
45
46
|
"pytest>=8",
|
|
46
47
|
"pytest-cov>=5",
|
|
47
48
|
"click>=8,<9",
|
|
49
|
+
# CI runs the locked ruff (uv run) instead of uvx-latest so lint is
|
|
50
|
+
# deterministic; a bump comes via Dependabot and is gated by CI.
|
|
51
|
+
"ruff>=0.15,<0.17",
|
|
48
52
|
"mypy>=1.10,<3",
|
|
49
53
|
"types-PyYAML>=6,<7",
|
|
54
|
+
# DNS TXT domain verification in `catalog validate` (CI + contributors);
|
|
55
|
+
# end users never resolve DNS, so this is not a runtime dependency.
|
|
56
|
+
"dnspython>=2.4,<3",
|
|
50
57
|
]
|
|
51
58
|
|
|
52
59
|
[tool.hatch.build.targets.wheel]
|
|
53
60
|
packages = ["src/openapi_cli4ai"]
|
|
54
61
|
|
|
62
|
+
# Bundle the profile catalog into the wheel so `catalog` commands work offline.
|
|
63
|
+
[tool.hatch.build.targets.wheel.force-include]
|
|
64
|
+
"profiles/verified" = "openapi_cli4ai/_catalog/verified"
|
|
65
|
+
"profiles/community" = "openapi_cli4ai/_catalog/community"
|
|
66
|
+
|
|
55
67
|
[tool.ruff]
|
|
56
68
|
line-length = 120
|
|
57
69
|
target-version = "py311"
|
|
58
70
|
|
|
71
|
+
[tool.ruff.lint]
|
|
72
|
+
# Rule set = ruff's defaults for the locked version. Drift is guarded by the
|
|
73
|
+
# version cap on the dev dependency plus uv.lock; a ruff bump arrives via
|
|
74
|
+
# Dependabot and is gated by CI, so new rules are adopted deliberately.
|
|
75
|
+
# RUF059 (unused unpacked variable) is ignored in tests: fixtures return
|
|
76
|
+
# tuples like `mod, tmp_path, cache_dir = tmp_config` and unpacking the
|
|
77
|
+
# full shape is clearer than `_`-prefixing whichever half a test skips.
|
|
78
|
+
per-file-ignores = { "tests/**" = ["RUF059"] }
|
|
79
|
+
|
|
59
80
|
[tool.pytest.ini_options]
|
|
60
81
|
testpaths = ["tests"]
|
|
61
82
|
markers = ["integration: live API tests (may be slow)"]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Runtime settings set once by the root command and read by every layer.
|
|
2
|
+
|
|
3
|
+
Module globals on purpose: the CLI is a single process handling one command,
|
|
4
|
+
and tests set these directly (``_state._verbose_mode = True``).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
_insecure_mode = False
|
|
10
|
+
_verbose_mode = False
|
|
11
|
+
_timeout_seconds = 60.0
|
|
12
|
+
_max_retries = 0
|
|
13
|
+
_profile_override: str | None = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def set_insecure_mode(insecure: bool) -> None:
|
|
17
|
+
global _insecure_mode
|
|
18
|
+
_insecure_mode = insecure
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_verify_ssl() -> bool:
|
|
22
|
+
return not _insecure_mode
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Shared Rich consoles and the verbose logger."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
|
|
7
|
+
from openapi_cli4ai import _state
|
|
8
|
+
|
|
9
|
+
console = Console()
|
|
10
|
+
err_console = Console(stderr=True)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _verbose(msg: str) -> None:
|
|
14
|
+
"""Print a verbose message to stderr if verbose mode is enabled."""
|
|
15
|
+
if _state._verbose_mode:
|
|
16
|
+
err_console.print(f"[dim]> {msg}[/dim]")
|