{"id":49090540,"url":"https://github.com/jrjsmrtn/pve-openapi","last_synced_at":"2026-04-20T18:04:06.464Z","repository":{"id":347027787,"uuid":"1192498433","full_name":"jrjsmrtn/pve-openapi","owner":"jrjsmrtn","description":"OpenAPI 3.1 specs for the Proxmox VE API (PVE 7.0-9.1) — extracted from official pve-docs packages","archived":false,"fork":false,"pushed_at":"2026-03-27T02:40:55.000Z","size":127,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-27T04:31:06.070Z","etag":null,"topics":["api","elixir","openapi","proxmox","proxmox-ve"],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jrjsmrtn.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"docs/roadmap/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-26T09:23:48.000Z","updated_at":"2026-03-27T02:40:58.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jrjsmrtn/pve-openapi","commit_stats":null,"previous_names":["jrjsmrtn/pve-openapi"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/jrjsmrtn/pve-openapi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jrjsmrtn%2Fpve-openapi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jrjsmrtn%2Fpve-openapi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jrjsmrtn%2Fpve-openapi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jrjsmrtn%2Fpve-openapi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jrjsmrtn","download_url":"https://codeload.github.com/jrjsmrtn/pve-openapi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jrjsmrtn%2Fpve-openapi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32059139,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T11:35:06.609Z","status":"ssl_error","status_checked_at":"2026-04-20T11:34:48.899Z","response_time":94,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","elixir","openapi","proxmox","proxmox-ve"],"created_at":"2026-04-20T18:04:05.589Z","updated_at":"2026-04-20T18:04:06.458Z","avatar_url":"https://github.com/jrjsmrtn.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!-- SPDX-License-Identifier: Apache-2.0 --\u003e\n\u003c!-- Copyright 2026 Georges Martin --\u003e\n# pve-openapi\n\nOpenAPI 3.1 specifications for the Proxmox Virtual Environment (PVE) REST API, extracted from official PVE sources. Versions are discovered dynamically from the Proxmox apt repository (currently PVE 7.0 through 9.1).\n\n## What This Is\n\nPVE's API is defined in Perl via `PVE::RESTHandler::register_method()` and documented through the `extractapi.pl` script that ships with `pve-docs`. This project:\n\n1. **Downloads** `pve-docs` .deb packages from Proxmox apt repos and extracts the API schema (`apidoc.js`) using pure Elixir (no external tools)\n2. **Converts** it to standard OpenAPI 3.1 specifications with links to the [official PVE API viewer](https://pve.proxmox.com/pve-docs/api-viewer/)\n3. **Provides** an Elixir library for querying specs, version matrices, diffs, feature availability, contract testing, and schema quality analysis\n\n## Quick Start\n\n### Setup\n\nOpenAPI specs are generated from Proxmox apt packages (not committed to git). Generate them before compiling:\n\n```bash\nmake setup          # Download, extract, convert, generate metadata + diffs\n```\n\nRequires: Elixir 1.15+ / OTP 26+ and system `liblzma` (for XZ decompression NIF). On macOS with MacPorts:\n\n```bash\nC_INCLUDE_PATH=/opt/local/include LIBRARY_PATH=/opt/local/lib mix deps.compile xz --force\n```\n\n### As a Dependency\n\nAdd to your `mix.exs`:\n\n```elixir\n{:pve_openapi, path: \"../pve-openapi\"}\n```\n\n## Library API\n\n### Querying Specs\n\n```elixir\n# List available versions\nPveOpenapi.versions()\n#=\u003e [\"7.0\", \"7.1\", ..., \"9.1\"]\n\n# Get the full OpenAPI spec for a version\n{:ok, spec} = PveOpenapi.spec(\"8.3\")\n\n# Query endpoints\nPveOpenapi.endpoints(\"8.3\")\n#=\u003e [%PveOpenapi.Endpoint{path: \"/access\", method: :get, ...}, ...]\n\n# Look up a specific operation\n{:ok, operation} = PveOpenapi.Spec.operation(spec, \"/nodes/{node}/qemu\", :post)\n```\n\n### Version Matrix\n\n```elixir\n# Check endpoint availability\nPveOpenapi.VersionMatrix.endpoint_available?(\"/nodes/{node}/qemu\", :get, \"8.3\")\n#=\u003e true\n\n# Find when an endpoint was added\nPveOpenapi.VersionMatrix.endpoint_added_in(\"/cluster/ha/rules\", :get)\n#=\u003e \"9.0\"\n\n# Get all endpoints for a version\nPveOpenapi.VersionMatrix.endpoints_for_version(\"9.0\")\n#=\u003e MapSet of {path, method} tuples\n```\n\n### Feature Matrix\n\nHigh-level feature availability derived from endpoint presence:\n\n```elixir\nPveOpenapi.FeatureMatrix.feature_available?(:sdn_fabrics, \"9.0\")\n#=\u003e true\n\nPveOpenapi.FeatureMatrix.feature_added_in(:notification_system)\n#=\u003e \"8.1\"\n\nPveOpenapi.FeatureMatrix.features_for_version(\"9.0\")\n#=\u003e [:acl_management, :backup_info, ..., :vm_management]\n\nPveOpenapi.FeatureMatrix.feature_diff(\"8.4\", \"9.0\")\n#=\u003e %{added: [:ha_rules, :sdn_fabrics], removed: []}\n```\n\nThe default catalog is extensible:\n\n```elixir\nmy_catalog = PveOpenapi.FeatureMatrix.Catalog.default() ++ [\n  {:my_feature, [\"/my/custom/path\"]}\n]\nPveOpenapi.FeatureMatrix.features_for_version(\"9.0\", my_catalog)\n```\n\n### Version Diffs\n\n```elixir\n# Endpoint-level diffs\nPveOpenapi.Diff.added_endpoints(\"8.3\", \"9.0\")\n#=\u003e [{\"/cluster/ha/rules\", :get}, ...]\n\n# Parameter-level changes\nPveOpenapi.Diff.parameter_changes(\"8.3\", \"8.4\")\n#=\u003e [%{path: \"/access/domains\", method: :post, changes: [%{type: :constraint_changed, ...}]}]\n\n# Breaking changes (removed endpoints, removed params, type changes)\nPveOpenapi.Diff.breaking_changes(\"7.4\", \"8.0\")\n#=\u003e [%{type: :endpoint_removed, path: ..., method: ...}, ...]\n\n# Complete structured diff\nPveOpenapi.Diff.full_diff(\"8.3\", \"9.0\")\n\n# Load pre-computed diff (falls back to runtime if not persisted)\nPveOpenapi.Diff.load_diff(\"8.3\", \"8.4\")\n```\n\n### Spec Queries\n\n```elixir\nspec = PveOpenapi.spec!(\"8.3\")\n\n# Structured parameter list\n{:ok, params} = PveOpenapi.Spec.parameters_for(spec, \"/nodes/{node}/qemu\", :post)\n#=\u003e {:ok, [%{name: \"vmid\", type: \"integer\", required: true, in: \"body\", schema: ...}, ...]}\n\n# Required parameters\n{:ok, required} = PveOpenapi.Spec.required_parameters(spec, \"/nodes/{node}/qemu\", :post)\n#=\u003e {:ok, [\"node\", \"vmid\"]}\n\n# Response schema\n{:ok, schema} = PveOpenapi.Spec.response_schema(spec, \"/version\", :get, 200)\n\n# Response property types\n{:ok, props} = PveOpenapi.Spec.response_properties(spec, \"/version\", :get, 200)\n#=\u003e {:ok, %{\"release\" =\u003e \"string\", \"version\" =\u003e \"string\", ...}}\n```\n\n### Contract Validation\n\nType-aware request validation against OpenAPI parameter schemas:\n\n```elixir\n# Validates presence AND types/constraints\nPveOpenapi.Contract.validate_request(\"8.3\", \"/nodes/{node}/qemu\", :post, %{\n  \"vmid\" =\u003e 100,\n  \"node\" =\u003e \"pve1\"\n})\n#=\u003e :ok\n\nPveOpenapi.Contract.validate_request(\"8.3\", \"/nodes/{node}/qemu\", :post, %{\n  \"vmid\" =\u003e \"not_an_int\",\n  \"node\" =\u003e \"pve1\"\n})\n#=\u003e {:error, [%{param: \"vmid\", error: \"Expected type integer, got \\\"not_an_int\\\"\"}]}\n\n# Coverage analysis\nPveOpenapi.Contract.validate_coverage(\"8.3\", implemented_endpoints)\n#=\u003e {:ok, %{total: 605, covered: 37, missing: [...], coverage_pct: 6.1}}\n```\n\n### Schema Quality Analysis\n\nResponse schema completeness classification:\n\n```elixir\nspec = PveOpenapi.spec!(\"9.0\")\n\nPveOpenapi.SchemaQuality.analyze_endpoint(spec, \"/version\", :get)\n#=\u003e {:rich, %{type: \"object\", property_count: 5}}\n\nPveOpenapi.SchemaQuality.quality_summary(\"9.0\")\n#=\u003e %{rich: 390, partial: 54, opaque: 202, total: 646, version: \"9.0\"}\n```\n\nOr from the command line:\n\n```bash\nmix pve_openapi.quality\n# Response Schema Quality by PVE Version\n# Version   Rich    Partial   Opaque    Total   Rich %\n# 7.0       298     62        147       507     58.8%\n# ...\n# 9.1       390     54        202       646     60.4%\n```\n\n## Mix Tasks\n\n| Task | Description |\n|------|-------------|\n| `mix pve_openapi.extract` | Download and convert all PVE versions |\n| `mix pve_openapi.fetch` | Download pve-docs .deb for a version |\n| `mix pve_openapi.normalize` | Extract JSON from apidoc.js |\n| `mix pve_openapi.convert` | Convert PVE JSON to OpenAPI 3.1 |\n| `mix pve_openapi.validate` | Validate OpenAPI specs structurally |\n| `mix pve_openapi.metadata` | Generate specs/metadata.json |\n| `mix pve_openapi.diff` | Generate version diff JSON files |\n| `mix pve_openapi.quality` | Analyze response schema quality |\n| `mix pve_openapi.fetch_host` | Fetch API schema from a live PVE host |\n| `mix pve_openapi.clean` | Remove all generated artifacts |\n\n## Covered Versions\n\n| Version | Debian | Paths | Operations |\n|---------|--------|-------|------------|\n| 7.0-7.4 | Bullseye | 340-364 | 507-540 |\n| 8.0-8.4 | Bookworm | 368-398 | 549-605 |\n| 9.0-9.1 | Trixie | 428 | 646 |\n\nNew PVE versions are auto-discovered from the Proxmox apt repository. No code changes required.\n\n## License\n\nThis project's source code (extraction scripts, converter, Elixir library) is licensed under [Apache-2.0](LICENSE).\n\nThe generated OpenAPI specifications contain API descriptions extracted from [pve-docs](https://git.proxmox.com/?p=pve-docs.git), which is licensed under [AGPL-3.0-or-later](https://www.gnu.org/licenses/agpl-3.0.html) by [Proxmox Server Solutions GmbH](https://www.proxmox.com). Each operation includes an `externalDocs` link to the [official PVE API viewer](https://pve.proxmox.com/pve-docs/api-viewer/).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjrjsmrtn%2Fpve-openapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjrjsmrtn%2Fpve-openapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjrjsmrtn%2Fpve-openapi/lists"}