python-rundeck 2.0.0__tar.gz → 2.0.1__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.
Files changed (34) hide show
  1. python_rundeck-2.0.1/API_COVERAGE.md +88 -0
  2. python_rundeck-2.0.1/CHANGELOG.md +100 -0
  3. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/PKG-INFO +20 -7
  4. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/README.md +15 -2
  5. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/pyproject.toml +12 -8
  6. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/const.py +3 -2
  7. python_rundeck-2.0.1/src/rundeck/v1/objects/acl.py +37 -0
  8. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/projects.py +4 -4
  9. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/system.py +1 -4
  10. python_rundeck-2.0.0/src/rundeck/v1/objects/acl.py +0 -24
  11. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/LICENSE +0 -0
  12. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/__init__.py +0 -0
  13. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/base.py +0 -0
  14. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/client.py +0 -0
  15. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/config.py +0 -0
  16. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/exceptions.py +0 -0
  17. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/py.typed +0 -0
  18. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/utils.py +0 -0
  19. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/__init__.py +0 -0
  20. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/__init__.py +0 -0
  21. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/adhoc.py +0 -0
  22. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/authorizations.py +0 -0
  23. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/executions.py +0 -0
  24. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/features.py +0 -0
  25. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/jobs.py +0 -0
  26. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/key_storage.py +0 -0
  27. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/metrics.py +0 -0
  28. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/plugins.py +0 -0
  29. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/project_plugins.py +0 -0
  30. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/scheduler.py +0 -0
  31. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/scm.py +0 -0
  32. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/tokens.py +0 -0
  33. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/users.py +0 -0
  34. {python_rundeck-2.0.0 → python_rundeck-2.0.1}/src/rundeck/v1/objects/webhooks.py +0 -0
@@ -0,0 +1,88 @@
1
+ # Rundeck Community API coverage
2
+
3
+ Audited against the Community source tag [v6.3.0](https://github.com/rundeck/rundeck/tree/v6.3.0)
4
+ and the [6.2.1–6.3.0 changes](https://github.com/rundeck/rundeck/compare/v6.2.1...v6.3.0),
5
+ the [API reference](https://docs.rundeck.com/docs/api/), the
6
+ [OpenAPI contract](https://docs.rundeck.com/docs/files/rundeck-api.yml), and the
7
+ [API version history](https://docs.rundeck.com/docs/api/rundeck-api-versions.html).
8
+ The package defaults to API v59 and retains explicit API v14+ selection; each row
9
+ describes the minimum version of the operation rather than the package's oldest
10
+ supported API version. API v60 can be selected explicitly on 6.3.0.
11
+ `Community` means the operation is part of Rundeck Community.
12
+
13
+ ## Community 6.3.0 compatibility (2.0.1)
14
+
15
+ No new Community routes were introduced in the compared route mappings. API v60
16
+ promotes `/enterprise/cluster/info` and `/enterprise/cluster/member/{memberId}`;
17
+ both are excluded. The Community scheduler remains available.
18
+
19
+ | HTTP | Route | Minimum API | Edition | Python interface / change | Official source | Tests |
20
+ |---|---|---:|---|---|---|---|
21
+ | POST, PUT | `/system/acl/{name}`, `/project/{project}/acl/{name}` | 17 system / 13 project | Community | JSON `contents` writes; unchanged YAML reads | API ACL reference; RUN-4790 | `test_community_630.py`, `test_system_acl.py`, `test_project_acl.py` (unit); `test_acl_json_lifecycle`, `test_yaml_request_json_response_regression` (integration) |
22
+ | GET; GET, POST | `/job/{id}/meta`, `/project/{project}/jobs/browse` | 46 | Community | Preserve `executionAclValid` metadata, including false values; added in server 6.3.0 | `JobExecutionAclMetadataComponent` at v6.3.0 | `test_job_metadata_is_raw_for_get_and_browse` (unit); `test_job_acl_metadata` (integration) |
23
+ | GET | `/plugin/list`, `/plugin/detail/{service}/{provider}` | 14 / 49 | Community | Preserve `outputs` and property `outputMetadata` | `PluginApiService` at v6.3.0 | `test_plugin_fields_are_preserved` (unit); existing plugin integrations |
24
+ | PUT | `/project/{project}/import` | 14 | Community | Additional configure permission for configuration or node-source import in server 6.3.0 | `ProjectController.apiProjectImport`, PR #10650 | `test_archive_permission_error_keeps_false_options_and_details` (unit); `test_archive_import_requires_configure` (integration) |
25
+ | POST | `/webhook/{token}` | 30 | Community | Opaque public secret unchanged by server-side token hashing | `WebhookService` and `WebhookTokenSecureMigrationService` at v6.3.0 | `test_webhook_event_send_supports_json_and_data` (unit); `test_project_webhook_lifecycle_and_send` (integration) |
26
+ | GET | `/metrics/*`, `/monitoring/*` | legacy / unversioned | Community | Docker legacy metrics variable honored in server 6.3.0 | RUN-4859 | `test_legacy_metrics_enabled_by_docker_variable`, existing monitoring integrations |
27
+
28
+ Server-version features above are not gated on the selected API version. The
29
+ `executionAclValid` warning does not enforce execution permissions. The source
30
+ tag restores the `${job.serverUrl}` trailing slash (RUN-5051); no URL rewrite is
31
+ performed by this client. Session cookies follow requests' standard behavior.
32
+
33
+ ## Added or corrected in 2.0.0
34
+
35
+ | HTTP | Route | Minimum API | Edition | Python interface | Official reference | Test |
36
+ |---|---|---:|---|---|---|---|
37
+ | GET | `/api/{v}/` | 14 | Community | `Rundeck.api_info()` | API root / API reference | `tests/unit/test_community_v59.py::test_api_info_and_default_api_version` |
38
+ | GET | `/api/{v}/home/summary` | 14 | Community | `rd.system.summary()` | System endpoints | `tests/unit/test_community_v59.py::test_system_summary_scheduler_and_expired_tokens_routes` |
39
+ | GET | `/api/{v}/scheduler/jobs` | 14 | Community | `rd.scheduler.jobs()` | Scheduler endpoints; v6.2.1 route mapping | `tests/unit/test_community_v59.py::test_system_summary_scheduler_and_expired_tokens_routes` |
40
+ | GET | `/api/{v}/scheduler/server/{uuid}/jobs` | 14 | Community | `rd.scheduler.jobs(server_uuid=...)` | Scheduler endpoints; v6.2.1 route mapping | `tests/unit/test_community_v59.py::test_system_summary_scheduler_and_expired_tokens_routes` |
41
+ | PUT | `/api/{v}/scheduler/takeover` | 14 | Community | `rd.scheduler.takeover(job_id=... or job_ids=[...])` | Scheduler endpoints; v6.2.1 route mapping | `tests/unit/test_scheduler.py` |
42
+ | POST | `/api/{v}/tokens/{user}/removeExpired` | 14 | Community | `rd.tokens.remove_expired(user)` | Tokens endpoints | `tests/unit/test_community_v59.py::test_system_summary_scheduler_and_expired_tokens_routes` |
43
+ | GET | `/monitoring/health/readiness` | n/a | Community | `rd.monitoring.readiness()` | Monitoring endpoints | `tests/unit/test_community_v59.py::test_async_export_post_uses_form_and_monitoring_readiness_is_unversioned` |
44
+ | POST | `/api/{v}/project/{project}/jobs/validateOption` | 47 | Community | `rd.jobs.validate_option(...)` / `project.jobs.validate_option(...)` | Jobs endpoints | `tests/unit/test_community_v59.py::test_option_validation_preserves_false_and_project_context` |
45
+ | POST | `/api/{v}/project/{project}/plugins/save` | 55 | Community | `project.plugins.save(...)` | Project plugin configuration | `tests/unit/test_community_v59.py::test_project_plugins_and_browse_post_contracts` |
46
+ | POST | `/api/{v}/project/{project}/jobs/browse` | 46 | Community | `rd.jobs.browse(..., use_post=True)` | Jobs browse endpoint | `tests/unit/test_community_v59.py::test_project_plugins_and_browse_post_contracts` |
47
+ | POST | `/api/{v}/project/{project}/export/async` | 14 | Community | `project.archive.export_async(..., use_post=True)` | Project archive endpoints | `tests/unit/test_community_v59.py::test_async_export_post_uses_form_and_monitoring_readiness_is_unversioned` |
48
+ | GET | `/api/{v}/authorizations/application/{kind}` | 14 | Community, experimental | `rd.authorizations.application_kind(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
49
+ | GET | `/api/{v}/authorizations/application/{type}/{specifier}` | 14 | Community, experimental | `rd.authorizations.application_resource(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
50
+ | GET | `/api/{v}/authorizations/project/{project}/{kind}` | 14 | Community, experimental | `rd.authorizations.project_kind(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
51
+ | GET | `/api/{v}/authorizations/project/{project}/{type}/{specifier}` | 14 | Community, experimental | `rd.authorizations.project_resource(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
52
+ | GET | `/api/{v}/authorizations/project/{project}/job/{id}` | 14 | Community, experimental | `rd.authorizations.project_job(...)` | Authorization evaluation endpoints | `tests/unit/test_community_v59.py::test_authorization_routes_repeat_actions_as_values` |
53
+ | GET | `/api/{v}/system/acl/{name}` | 14 | Community | `rd.system.acl.get(name)` (`Accept: application/yaml`) | System ACL endpoints | `tests/unit/test_system_acl.py` |
54
+ | GET | `/api/{v}/project/{project}/acl/{name}` | 14 | Community | `project.acl.get(name)` (`Accept: application/yaml`) | Project ACL endpoints | `tests/unit/test_project_acl.py` |
55
+
56
+ The authorization evaluation API is documented as experimental. `actions` is
57
+ sent as a repeated query parameter. Job browse POST keeps metadata and path
58
+ parameters in the query and sends search filters as JSON. Async archive POST
59
+ uses form encoding for execution IDs. `Execution.get_output()` returns the
60
+ server payload unchanged in both historical API v58 and compacted API v59 modes.
61
+
62
+ ## Existing Community operations
63
+
64
+ The following endpoint families are also exposed by this package and are checked
65
+ by their focused unit tests. Paths below use `{v}` for the selected `/api/{v}`
66
+ prefix. See each test module for the supported verbs, request fields, response
67
+ handling, and pagination behavior.
68
+
69
+ | HTTP | Route(s) | Minimum API | Edition | Python interface | Official reference | Test |
70
+ |---|---|---:|---|---|---|---|
71
+ | GET, POST, PUT, DELETE | `/project`, `/project/{project}`, `/project/{project}/resources`, `/project/{project}/config`, `/project/{project}/readme`, `/project/{project}/motd`, `/project/{project}/history`, `/project/{project}/acl/{name}` | 14 | Community | `rd.projects` and nested project managers | Projects endpoints | `tests/unit/test_project_*.py`, `tests/unit/test_project_acl.py` |
72
+ | GET, POST, PUT, DELETE | `/project/{project}/jobs`, `/job/{id}`, `/job/{id}/run`, `/job/{id}/executions`, `/project/{project}/jobs/bulk`, `/project/{project}/jobs/delete`, `/project/{project}/jobs/browse` | 14 (browse 46) | Community | `rd.jobs`, `project.jobs`, `Job` | Jobs endpoints | `tests/unit/test_jobs.py`, `tests/unit/test_community_v59.py` |
73
+ | GET, POST, PUT, DELETE | `/execution/{id}`, `/execution/{id}/output`, `/execution/{id}/state`, `/execution/{id}/abort`, `/execution/{id}/retry`, `/project/{project}/executions` | 14 | Community | `rd.executions`, `Execution` | Executions endpoints | `tests/unit/test_executions.py` |
74
+ | GET, POST, PUT, DELETE | `/system/acl`, `/system/executions/{enable,disable,status}`, `/system/logstorage`, `/system/keys/{path}` | 14 | Community | `rd.system`, `rd.keys` | System, key storage endpoints | `tests/unit/test_system_*.py`, `tests/unit/test_key_storage.py` |
75
+ | GET, POST, DELETE | `/tokens`, `/tokens/{id}`, `/tokens/{user}/removeExpired`, `/user`, `/user/{login}` | 14 | Community | `rd.tokens`, `rd.users` | Tokens and user endpoints | `tests/unit/test_tokens.py`, `tests/unit/test_users.py` |
76
+ | GET, POST, PUT, DELETE | `/project/{project}/scm/{plugin}/{action}`, `/plugin/{service}/{name}`, `/project/{project}/webhooks` | 14 | Community | SCM, plugin, and webhook managers | SCM, plugins, webhooks endpoints | `tests/unit/test_project_scm.py`, `tests/unit/test_plugins.py`, `tests/unit/test_webhooks.py` |
77
+ | GET | `/metrics[/metrics|/healthcheck|/ping|/threads]`, `/monitoring[/metrics|/health|/info|/prometheus|/threaddump]` | 14 / unversioned | Community | `rd.metrics`, `rd.monitoring` | Metrics and monitoring endpoints | `tests/unit/test_metrics.py` |
78
+ | POST | `/run/command`, `/project/{project}/run/command` | 14 | Community | `rd.run_command`, `project.run_command` | Command execution endpoint | `tests/unit/test_adhoc.py` |
79
+
80
+ ## Excluded commercial surfaces
81
+
82
+ | Removed interface / route | Reason | Verification |
83
+ |---|---|---|
84
+ | `rd.config_management` (`/config/...`) | Commercial Config Management product surface | `tests/unit/test_community_v59.py::test_api_info_and_default_api_version` |
85
+ | `Job.tags()` (`/job/{id}/tags`) | Commercial endpoint absent from the Community v6.2.1 contract | `tests/unit/test_jobs.py` |
86
+
87
+ Commercial-only calendars, runners, licenses, and other product-specific routes
88
+ are outside this client’s Community API coverage.
@@ -0,0 +1,100 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
6
+ and this project adheres to [Semantic Versioning](https://semver.org/).
7
+
8
+ ## [2.0.1] - 2026-11-08
9
+ ### Fixed
10
+ - Refresh vulnerable locked dependencies to their latest compatible stable releases;
11
+ require Requests 2.33+, Black 26.3.1+ and pytest 9.0.3+.
12
+ - Refresh the virtual environment's pip before auditing cached CI environments.
13
+ - ACL writes use the official JSON `contents` envelope and request JSON responses,
14
+ avoiding raw YAML response errors while retaining YAML reads and public return types.
15
+ - ACL reads unwrap older controllers' JSON envelopes even when YAML was requested.
16
+ - Integration webhook discovery now fails if the created resource disappears.
17
+
18
+ ### Added
19
+ - Rundeck Community 6.3.0 integration coverage in API v59 and v60, alongside
20
+ 6.2.1/v59, 6.0.1/v58 and 5.18.0/v56 compatibility targets.
21
+ - Regression coverage for job execution ACL metadata, plugin output metadata,
22
+ archive import permissions, forwarded session cookies and legacy Docker metrics.
23
+
24
+ ### Changed
25
+ - Current known API is v60; the default remains v59. Enterprise v60 endpoints remain excluded.
26
+ - Local integration image defaults to `rundeck/rundeck:6.3.0-20261022`.
27
+ - Integration containers are isolated by Compose project and cleaned up on failures.
28
+ - Gitflow feature branches run the integration and Python compatibility matrices.
29
+
30
+ ## [2.0.0] - 2026-10-10
31
+ ### Added
32
+ - Community API v59 support, including API discovery, system summary, scheduler job
33
+ listing, expired-token cleanup, monitoring readiness, option validation, project
34
+ plugin configuration, POST job browsing, and asynchronous archive export.
35
+ - Experimental authorization-evaluation endpoints and a Community API coverage matrix.
36
+ - Community integration defaults for Rundeck 6.2.1/API v59, with documented 6.0.1/v58
37
+ and 5.18.0/v56 compatibility runs.
38
+
39
+ ### Changed
40
+ - Default API version is now v59; explicitly selected older versions remain supported.
41
+ - System and project ACL reads explicitly request YAML. HTTP 422 responses map to
42
+ `RundeckValidationError` while retaining the response body.
43
+ - Scheduler cluster takeover accepts one or multiple job IDs. In Community without
44
+ cluster mode, takeover has no scheduling state to transfer.
45
+
46
+ ### Removed
47
+ - Removed commercial Config Management interfaces and `Job.tags()`.
48
+
49
+ ## [1.1.0] - 2026-07-25
50
+ ### Added
51
+ - Support for `user_agent` and `config_section` parameters in the client configuration.
52
+ - API v57/v58 support: execution metrics, job browse, `metaExclude`, modern
53
+ monitoring endpoints, and v56/v57 response metadata coverage.
54
+ - Community endpoints for project history/meta/node tags, execution input and
55
+ output state, job executions, project SCM toggle, and current-user update.
56
+
57
+ ### Changed
58
+ - `__version__` now resolves from the installed package metadata, with a local
59
+ fallback to `pyproject.toml` when the package is not installed.
60
+ - README configuration section updated to include `user_agent` and `config_section`.
61
+ - Default Rundeck API version updated to v58; the client retains v14
62
+ compatibility and documents the current server minimum v17 and v34 deprecation.
63
+ - Corrected Community routes and verbs for job forecasts, resource model
64
+ sources, bulk job actions, bulk job deletion, and job pagination.
65
+ - `Job.tags` and Config Management were incorrectly grouped with scheduler
66
+ cluster operations in this entry. The first two are commercial surfaces;
67
+ scheduler listing and takeover are Community endpoints and remain supported.
68
+
69
+ ## [1.0.1] - 2026-01-21
70
+ ### Changed
71
+ - CI: skip lint/tests on `main` and build only on tags.
72
+ - Classifier updated to `Development Status :: 5 - Production/Stable`.
73
+
74
+ ## [1.0.0] - 2026-01-21
75
+ ### Changed
76
+ - `Job.run` and `Job.retry` now return raw responses by default and support `as_execution=True` for `Execution`.
77
+ - `RundeckObject.refresh` and `Execution.refresh` now return `None` (in-place update).
78
+ - `User.update` now returns the raw response and updates the object in place.
79
+ - Key storage API now uses `StorageKey` objects for `create`/`update`, moves raw content access to `StorageKey.content()`, renames `get_metadata` to `get`, and supports updating via `StorageKey.update()`.
80
+ - System ACL policies are treated as resources and `SystemACL.update()` now updates the object in place.
81
+ - Project webhooks are treated as resources (`project.webhooks`), while event sending remains a utility manager.
82
+
83
+ ## [0.3.0] - 2026-01-14
84
+ ### Added
85
+ - README badges for PyPI version, supported Python versions, license, and downloads.
86
+ - Contributor dev setup note in README.
87
+
88
+ ### Changed
89
+ - README translated to English.
90
+ - Installation section now targets PyPI installs.
91
+ - GitLab CI PyPI deployment uses verbose `twine upload`.
92
+
93
+ ## [0.2.0] - 2026-01-12
94
+ ### Added
95
+ - Project metadata URLs in `pyproject.toml` (Homepage, Repository, Documentation, Issues, Changelog).
96
+ - Changelog file to track releases.
97
+
98
+ ## [0.1.0] - 2026-01-11
99
+ ### Added
100
+ - Initial release of the python-rundeck client library.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-rundeck
3
- Version: 2.0.0
4
- Summary: Python client for the Rundeck Community API (v14-v59).
3
+ Version: 2.0.1
4
+ Summary: Python client for the Rundeck Community API (v14-v60, default v59).
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
7
7
  Keywords: rundeck,api,client
@@ -21,12 +21,12 @@ Classifier: Topic :: System :: Systems Administration
21
21
  Classifier: Typing :: Typed
22
22
  Provides-Extra: dev
23
23
  Requires-Dist: bandit (>=1.7.9,<2.0.0) ; extra == "dev"
24
- Requires-Dist: black (>=25.11.0,<26.0.0) ; extra == "dev"
24
+ Requires-Dist: black (>=26.3.1,<27.0.0) ; extra == "dev"
25
25
  Requires-Dist: flake8 (>=7.0.0,<8.0.0) ; extra == "dev"
26
26
  Requires-Dist: isort (>=7.0.0,<8.0.0) ; extra == "dev"
27
- Requires-Dist: pytest (>=9.0.2,<10.0.0) ; extra == "dev"
27
+ Requires-Dist: pytest (>=9.0.3,<10.0.0) ; extra == "dev"
28
28
  Requires-Dist: pytest-cov (>=5.0.0,<6.0.0) ; extra == "dev"
29
- Requires-Dist: requests (>=2.32.5,<3.0.0)
29
+ Requires-Dist: requests (>=2.33.0,<3.0.0)
30
30
  Requires-Dist: ruff (>=0.7.0,<1.0.0) ; extra == "dev"
31
31
  Requires-Dist: safety (>=3.2.0,<4.0.0) ; extra == "dev"
32
32
  Project-URL: Changelog, https://gitlab.com/pascal.seckinger/python-rundeck/-/blob/main/CHANGELOG.md
@@ -43,7 +43,7 @@ python-rundeck
43
43
  ![License](https://img.shields.io/pypi/l/python-rundeck)
44
44
  ![Downloads](https://static.pepy.tech/badge/python-rundeck)
45
45
 
46
- Python client for the Rundeck Community API (v14-v59), inspired by the python-gitlab architecture. The default API version is v59; current Rundeck servers require v17 or later and versions below v34 are deprecated. Provides typed managers for Community resources (projects, jobs, executions, tokens, users, system) and SCM (import/export).
46
+ Python client for the Rundeck Community API (v14-v60), inspired by the python-gitlab architecture. Rundeck Community 6.3.0 is the integration reference. The default API version remains v59; use `api_version=60` explicitly with 6.3.0. Current Rundeck servers require v17 or later and versions below v34 are deprecated. Provides typed managers for Community resources (projects, jobs, executions, tokens, users, system) and SCM (import/export).
47
47
 
48
48
  Version 2.0 removes commercial-only Config Management and job-tag endpoints. Cluster schedule listing and takeover are Community operations and remain available. The authorization-evaluation endpoints are experimental in Rundeck and are exposed as such by this client.
49
49
 
@@ -158,6 +158,16 @@ Utility managers:
158
158
  Note: `project.webhooks.create(...)` returns the raw API response (e.g., `{"msg": "Saved webhook"}`)
159
159
  because the Rundeck API does not return the created webhook object.
160
160
 
161
+ Compatibility with Community 6.3.0 (2.0.1)
162
+ ---------------------------------------
163
+ - API v60 is recognized; the default stays v59 to retain compatibility with Community 6.2.1. The new v60 cluster endpoints are Enterprise-only and excluded.
164
+ - ACL creation and updates send the YAML text inside a JSON `contents` envelope and request JSON responses. Reads still request YAML and unwrap legacy JSON responses from older project ACL controllers. Python signatures and resource return conventions are unchanged.
165
+ - `job.meta(meta="executionAclValid")` and `project.jobs.browse(meta="executionAclValid")` expose the server's saved-user authorization warning. It does not block execution. Plugin `outputs` and property `outputMetadata` are preserved when returned by the server.
166
+ - Archive imports with `importConfig=True` or `importNodesSources=True` also require project `configure` authorization on 6.3.0. Use explicit `False` values for jobs-only imports. Authorization failures retain the server response in `RundeckAuthenticationError.response_body`.
167
+ - Webhook tokens remain opaque public secrets. The server handles hashing and migration; callers must continue sending the original secret.
168
+ - Session authentication uses standard cookie handling; 6.3.0 fixes direct HTTP authentication when the public URL is HTTPS behind forwarded headers.
169
+ - The stable 6.3.0 sources restore the trailing slash on `${job.serverUrl}` (RUN-5051), despite the earlier release-note wording. The client does not rewrite job context URLs.
170
+
161
171
  Migration from 1.1.0
162
172
  -------------------
163
173
  - Set `api_version=59` explicitly when upgrading a server/client pair gradually; the default is now 59.
@@ -526,8 +536,11 @@ Development and testing
526
536
  - Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
527
537
  - Typing: `mypy src/rundeck/`
528
538
  - Tests: `pytest`
529
- - Local integration tests: `scripts/run-integration.sh` starts Rundeck Community 6.2.1 by default with API v59. Use `RUNDECK_IMAGE=rundeck/rundeck:6.0.1 RUNDECK_API_VERSION=58` or `RUNDECK_IMAGE=rundeck/rundeck:5.18.0 RUNDECK_API_VERSION=56` for compatibility runs. Add `KEEP_STACK=1` to keep the instance running after tests. Dedicated teardown script: `scripts/stop-integration.sh`.
539
+ - Local integration tests: `scripts/run-integration.sh` starts `rundeck/rundeck:6.3.0-20261022` with API v59. Each run has an isolated Compose project and cleans up even when tests fail. With `KEEP_STACK=1`, the script prints the project name needed by `scripts/stop-integration.sh`.
540
+ - GitLab runs five integration targets: 6.3.0/API 59, 6.3.0/API 60, 6.2.1/API 59, 6.0.1/API 58 and 5.18.0/API 56. Set `RUNDECK_IMAGE` and `RUNDECK_API_VERSION` to run each target locally. Python compatibility tests retain 3.11–3.15 (3.15-rc Docker image).
541
+ - To exercise the 6.3.0 session regression and legacy metrics: `RUNDECK_PUBLIC_URL=https://rundeck.example.invalid RUNDECK_METRICS_LEGACY_ENABLED=true scripts/run-integration.sh`. The client still connects to `RUNDECK_URL` (default `http://localhost:4440`). The public URL defaults to the client URL, ensuring session redirects also work on older servers. Optional `RUNDECK_HTTP_PORT` changes the published port; set `RUNDECK_URL` accordingly.
530
542
  - The docker compose stack mounts `tokens.properties` at the repo root to seed a local admin token for integration tests. This file is only intended for local testing.
543
+ - Run local compatibility targets sequentially, stopping each stack before starting the next. This keeps at most one Rundeck JVM and one PostgreSQL container active.
531
544
 
532
545
  Code structure
533
546
  --------------
@@ -5,7 +5,7 @@ python-rundeck
5
5
  ![License](https://img.shields.io/pypi/l/python-rundeck)
6
6
  ![Downloads](https://static.pepy.tech/badge/python-rundeck)
7
7
 
8
- Python client for the Rundeck Community API (v14-v59), inspired by the python-gitlab architecture. The default API version is v59; current Rundeck servers require v17 or later and versions below v34 are deprecated. Provides typed managers for Community resources (projects, jobs, executions, tokens, users, system) and SCM (import/export).
8
+ Python client for the Rundeck Community API (v14-v60), inspired by the python-gitlab architecture. Rundeck Community 6.3.0 is the integration reference. The default API version remains v59; use `api_version=60` explicitly with 6.3.0. Current Rundeck servers require v17 or later and versions below v34 are deprecated. Provides typed managers for Community resources (projects, jobs, executions, tokens, users, system) and SCM (import/export).
9
9
 
10
10
  Version 2.0 removes commercial-only Config Management and job-tag endpoints. Cluster schedule listing and takeover are Community operations and remain available. The authorization-evaluation endpoints are experimental in Rundeck and are exposed as such by this client.
11
11
 
@@ -120,6 +120,16 @@ Utility managers:
120
120
  Note: `project.webhooks.create(...)` returns the raw API response (e.g., `{"msg": "Saved webhook"}`)
121
121
  because the Rundeck API does not return the created webhook object.
122
122
 
123
+ Compatibility with Community 6.3.0 (2.0.1)
124
+ ---------------------------------------
125
+ - API v60 is recognized; the default stays v59 to retain compatibility with Community 6.2.1. The new v60 cluster endpoints are Enterprise-only and excluded.
126
+ - ACL creation and updates send the YAML text inside a JSON `contents` envelope and request JSON responses. Reads still request YAML and unwrap legacy JSON responses from older project ACL controllers. Python signatures and resource return conventions are unchanged.
127
+ - `job.meta(meta="executionAclValid")` and `project.jobs.browse(meta="executionAclValid")` expose the server's saved-user authorization warning. It does not block execution. Plugin `outputs` and property `outputMetadata` are preserved when returned by the server.
128
+ - Archive imports with `importConfig=True` or `importNodesSources=True` also require project `configure` authorization on 6.3.0. Use explicit `False` values for jobs-only imports. Authorization failures retain the server response in `RundeckAuthenticationError.response_body`.
129
+ - Webhook tokens remain opaque public secrets. The server handles hashing and migration; callers must continue sending the original secret.
130
+ - Session authentication uses standard cookie handling; 6.3.0 fixes direct HTTP authentication when the public URL is HTTPS behind forwarded headers.
131
+ - The stable 6.3.0 sources restore the trailing slash on `${job.serverUrl}` (RUN-5051), despite the earlier release-note wording. The client does not rewrite job context URLs.
132
+
123
133
  Migration from 1.1.0
124
134
  -------------------
125
135
  - Set `api_version=59` explicitly when upgrading a server/client pair gradually; the default is now 59.
@@ -488,8 +498,11 @@ Development and testing
488
498
  - Formatting/Lint: `black src/rundeck tests/`, `ruff check src/rundeck tests/`
489
499
  - Typing: `mypy src/rundeck/`
490
500
  - Tests: `pytest`
491
- - Local integration tests: `scripts/run-integration.sh` starts Rundeck Community 6.2.1 by default with API v59. Use `RUNDECK_IMAGE=rundeck/rundeck:6.0.1 RUNDECK_API_VERSION=58` or `RUNDECK_IMAGE=rundeck/rundeck:5.18.0 RUNDECK_API_VERSION=56` for compatibility runs. Add `KEEP_STACK=1` to keep the instance running after tests. Dedicated teardown script: `scripts/stop-integration.sh`.
501
+ - Local integration tests: `scripts/run-integration.sh` starts `rundeck/rundeck:6.3.0-20261022` with API v59. Each run has an isolated Compose project and cleans up even when tests fail. With `KEEP_STACK=1`, the script prints the project name needed by `scripts/stop-integration.sh`.
502
+ - GitLab runs five integration targets: 6.3.0/API 59, 6.3.0/API 60, 6.2.1/API 59, 6.0.1/API 58 and 5.18.0/API 56. Set `RUNDECK_IMAGE` and `RUNDECK_API_VERSION` to run each target locally. Python compatibility tests retain 3.11–3.15 (3.15-rc Docker image).
503
+ - To exercise the 6.3.0 session regression and legacy metrics: `RUNDECK_PUBLIC_URL=https://rundeck.example.invalid RUNDECK_METRICS_LEGACY_ENABLED=true scripts/run-integration.sh`. The client still connects to `RUNDECK_URL` (default `http://localhost:4440`). The public URL defaults to the client URL, ensuring session redirects also work on older servers. Optional `RUNDECK_HTTP_PORT` changes the published port; set `RUNDECK_URL` accordingly.
492
504
  - The docker compose stack mounts `tokens.properties` at the repo root to seed a local admin token for integration tests. This file is only intended for local testing.
505
+ - Run local compatibility targets sequentially, stopping each stack before starting the next. This keeps at most one Rundeck JVM and one PostgreSQL container active.
493
506
 
494
507
  Code structure
495
508
  --------------
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "python-rundeck"
3
- version = "2.0.0"
4
- description = "Python client for the Rundeck Community API (v14-v59)."
3
+ version = "2.0.1"
4
+ description = "Python client for the Rundeck Community API (v14-v60, default v59)."
5
5
  authors = [
6
6
  {name = "Pascal Seckinger",email = "pascal.seckinger@protonmail.com"}
7
7
  ]
@@ -23,7 +23,7 @@ classifiers = [
23
23
  "Typing :: Typed",
24
24
  ]
25
25
  dependencies = [
26
- "requests (>=2.32.5,<3.0.0)"
26
+ "requests (>=2.33.0,<3.0.0)"
27
27
  ]
28
28
 
29
29
  [project.urls]
@@ -36,10 +36,10 @@ Changelog = "https://gitlab.com/pascal.seckinger/python-rundeck/-/blob/main/CHAN
36
36
  [project.optional-dependencies]
37
37
  dev = [
38
38
  "bandit (>=1.7.9,<2.0.0)",
39
- "black (>=25.11.0,<26.0.0)",
39
+ "black (>=26.3.1,<27.0.0)",
40
40
  "flake8 (>=7.0.0,<8.0.0)",
41
41
  "isort (>=7.0.0,<8.0.0)",
42
- "pytest (>=9.0.2,<10.0.0)",
42
+ "pytest (>=9.0.3,<10.0.0)",
43
43
  "pytest-cov (>=5.0.0,<6.0.0)",
44
44
  "ruff (>=0.7.0,<1.0.0)",
45
45
  "safety (>=3.2.0,<4.0.0)",
@@ -47,7 +47,11 @@ dev = [
47
47
 
48
48
  [tool.poetry]
49
49
  packages = [{include = "rundeck", from = "src"}]
50
- include = ["src/rundeck/py.typed"]
50
+ include = [
51
+ "src/rundeck/py.typed",
52
+ {path = "API_COVERAGE.md", format = "sdist"},
53
+ {path = "CHANGELOG.md", format = "sdist"},
54
+ ]
51
55
 
52
56
  [build-system]
53
57
  requires = ["poetry-core>=2.0.0,<3.0.0"]
@@ -56,10 +60,10 @@ build-backend = "poetry.core.masonry.api"
56
60
  [dependency-groups]
57
61
  dev = [
58
62
  "bandit (>=1.7.9,<2.0.0)",
59
- "black (>=25.11.0,<26.0.0)",
63
+ "black (>=26.3.1,<27.0.0)",
60
64
  "flake8 (>=7.0.0,<8.0.0)",
61
65
  "isort (>=7.0.0,<8.0.0)",
62
- "pytest (>=9.0.2,<10.0.0)",
66
+ "pytest (>=9.0.3,<10.0.0)",
63
67
  "pytest-cov (>=5.0.0,<6.0.0)",
64
68
  "ruff (>=0.7.0,<1.0.0)",
65
69
  "safety (>=3.2.0,<4.0.0)"
@@ -40,13 +40,14 @@ FORMAT_JSON = "json"
40
40
 
41
41
  # API versions. The library remains compatible with legacy Rundeck servers
42
42
  # using v14, while current Rundeck servers require at least v17.
43
- API_VERSION_CURRENT = "59"
43
+ API_VERSION_CURRENT = "60"
44
44
  API_VERSION_MIN = "14"
45
45
  API_VERSION_SERVER_MIN = "17"
46
46
  API_VERSION_DEPRECATION = "34"
47
47
 
48
48
  # Defaults
49
- DEFAULT_API_VERSION = API_VERSION_CURRENT
49
+ # v60 adds Enterprise endpoints only; keep the Community-compatible default.
50
+ DEFAULT_API_VERSION = "59"
50
51
  DEFAULT_TIMEOUT = 30
51
52
  USER_AGENT = "python-rundeck"
52
53
 
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from rundeck.utils import build_headers
6
+
7
+
8
+ class YamlPolicyMixin:
9
+ def _get_yaml(self, path: str) -> str:
10
+ response = self.rd.http_get(
11
+ path, raw=True, headers={"Accept": "application/yaml"}
12
+ )
13
+ # Some older project ACL controllers return a JSON envelope despite Accept.
14
+ if (
15
+ "application/json"
16
+ in getattr(response, "headers", {}).get("Content-Type", "").lower()
17
+ ):
18
+ result = response.json()
19
+ if isinstance(result, dict) and isinstance(result.get("contents"), str):
20
+ return result["contents"]
21
+ return response.text
22
+
23
+ def _yaml_headers(self) -> dict[str, str]:
24
+ return (
25
+ build_headers(accept="application/json", content_type="application/json")
26
+ or {}
27
+ )
28
+
29
+ def _post_yaml(self, path: str, content: Any) -> Any:
30
+ return self.rd.http_post(
31
+ path, json={"contents": content}, headers=self._yaml_headers()
32
+ )
33
+
34
+ def _put_yaml(self, path: str, content: Any) -> Any:
35
+ return self.rd.http_put(
36
+ path, json={"contents": content}, headers=self._yaml_headers()
37
+ )
@@ -193,10 +193,7 @@ class ProjectACLManager(YamlPolicyMixin, RundeckObjectManager):
193
193
  def get(self, policy_name: str) -> str:
194
194
  """Récupère une politique ACL projet (contenu texte)."""
195
195
  path = self._build_path(policy_name)
196
- response = self.rd.http_get(
197
- path, raw=True, headers={"Accept": "application/yaml"}
198
- )
199
- return response.text
196
+ return self._get_yaml(path)
200
197
 
201
198
  def create(self, policy_name: str, content: str) -> dict[str, Any]:
202
199
  """Crée une politique ACL projet."""
@@ -484,6 +481,9 @@ class ProjectArchiveManager(RundeckObjectManager):
484
481
  ) -> Any:
485
482
  """
486
483
  Importe une archive ZIP dans le projet.
484
+
485
+ Community 6.3+ exige aussi le droit configure lorsque importConfig ou
486
+ importNodesSources est activé. Les options et refus sont transmis tels quels.
487
487
  """
488
488
  params = compact(
489
489
  component_options,
@@ -67,10 +67,7 @@ class SystemACLManager(YamlPolicyMixin, RundeckObjectManager[SystemACL]):
67
67
  def get(self, policy_name: str) -> SystemACL:
68
68
  """Récupère une politique ACL (contenu texte)."""
69
69
  path = self._build_path(policy_name)
70
- response = self.rd.http_get(
71
- path, raw=True, headers={"Accept": "application/yaml"}
72
- )
73
- return self._wrap({"name": policy_name, "content": response.text})
70
+ return self._wrap({"name": policy_name, "content": self._get_yaml(path)})
74
71
 
75
72
  def create(self, policy_name: str, content: str) -> SystemACL:
76
73
  """Crée une politique ACL système."""
@@ -1,24 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Any
4
-
5
- from rundeck.utils import build_headers
6
-
7
-
8
- class YamlPolicyMixin:
9
- _yaml_content_type = "application/yaml"
10
-
11
- def _yaml_headers(self) -> dict[str, str]:
12
- headers = build_headers(
13
- accept=self._yaml_content_type, content_type=self._yaml_content_type
14
- )
15
- return headers or {
16
- "Accept": self._yaml_content_type,
17
- "Content-Type": self._yaml_content_type,
18
- }
19
-
20
- def _post_yaml(self, path: str, content: Any) -> Any:
21
- return self.rd.http_post(path, data=content, headers=self._yaml_headers())
22
-
23
- def _put_yaml(self, path: str, content: Any) -> Any:
24
- return self.rd.http_put(path, data=content, headers=self._yaml_headers())
File without changes