You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Changed
All plugin API errors now share one body format {"code", "detail"} — the remaining endpoints (GET secrets/, POST bindings/, DELETE bindings/<id>/, GET audit/) and the NetBox permission checks (not_authenticated / netbox_permission_denied) were aligned with the Passwork-facing ones: detail is always present, the extra param field of invalid_param (audit filters/pagination) is folded into detail, status: "error" is gone. Values of code, routes and successful bodies are unchanged
Passwork-facing endpoints (login/TOTP/detail/copy/picker) answer 405 Method Not Allowed for an unsupported HTTP method before touching the Passwork session (previously 401 without a session), and OPTIONS no longer requires a Passwork session
Picker endpoints (GET picker/folders/, GET picker/search/) now go through the Passwork gateway like the other Passwork-facing views: a Passwork 401 in the picker returns HTTP 401 pw_session_expired and a Passwork 403 returns HTTP 403 pw_access_denied instead of HTTP 200 with an empty list; error bodies are uniform {"code", "detail"} (missing_query gained a detail), successful bodies (arrays of vaults / items) are unchanged
Secret detail (GET secrets/<pw_id>/detail/) and copy (POST secrets/<pw_id>/copy/) endpoints now go through the Passwork gateway (like login/TOTP): the order of checks is unchanged (NetBox permission → reveal_secret for reveal=true → Passwork session → parameters → binding → Passwork → audit), error bodies are uniform {"code", "detail"} (invalid_object_id and binding_not_found gained a detail), successful bodies are unchanged
Package metadata (pyproject.toml): author, PEP 639 license expression, project URLs; tests are no longer shipped in the wheel
First public release. The project is now open source under Apache-2.0; the documentation in docs/, the code comments and the helper scripts are in English
Added
LICENSE (Apache-2.0) and a License section in README
Published on PyPI: pip install netbox-passwork; update.sh now upgrades from PyPI by default
GitHub Actions CI (.github/workflows/ci.yml): ruff, the JS tests and a package build/twine check on every push to main and every pull request (the Python tests still run locally — they need a NetBox installation)
Issue and pull request templates (.github/ISSUE_TEMPLATE/, .github/PULL_REQUEST_TEMPLATE.md) and CI/license badges in the README
scripts/test.sh — single entry point for lint / Python tests / JS tests with a markdown summary for PRs; scripts/release.sh — release preparation (release PR) and publishing (signed tag, sdist/wheel, GitHub Release)
Fixed
Changing SESSION_ENCRYPT_KEY no longer leaves users with a permanent 401: a Passwork session record that cannot be decrypted is dropped (with a warning in the log) and the user is asked to log in to Passwork again (401 pw_not_authenticated); unexpected exceptions while reading the Passwork session are no longer masked as 401
A 403 from Passwork on token refresh (/sessions/refresh) is treated like 401 — the Passwork session is dropped and the client gets 401 pw_session_expired — instead of being silently accepted as a successful refresh
Removed
Unused passwork-python dependency (the plugin uses its own requests-based client; requests is now declared explicitly) and the stale requirements.txt — dev dependencies live only in [project.optional-dependencies].dev
Internal modules/helpers superseded by the Passwork gateway: netbox_passwork/middleware.py (PassworkSessionMiddleware mixin), the Fernet helpers in utils.py (fernet_encrypt/fernet_decrypt), and PassworkAuthClient.encrypt_session/decrypt_session together with its session_encrypt_key constructor argument. No configuration change is required (MIDDLEWARE was never touched); existing Passwork sessions stay valid after the upgrade — the session record format is unchanged
Internal
Passwork gateway (netbox_passwork/gateway.py, see ADR-0001): one deep module owns the Passwork session (reading/decrypting/refreshing/encrypting/writing it in the Django session, the only place that reads the plugin config and the only Fernet implementation) and exposes six operations (login, confirm_totp, get_item, list_vaults, search_items, require_session); Passwork refusals are raised as PassworkError subclasses carrying code/http_status/detail. All Passwork-facing views inherit one base PassworkView (NetBox permission → 405 → gateway → Passwork session → method → PassworkError/ApiError → JSON error). The HTTP client (passwork_client.py) no longer depends on Django (everything via the constructor) and gained public list_vaults/search_items; urllib3.disable_warnings() is called only when SSL verification is off. Within one request the Passwork session record is read and decrypted once. This also removed the duplicated Fernet implementation, the repeated local import json calls and the unconditional urllib3.disable_warnings() at import time
Tests: the gateway is swapped in views through one explicit seam (as_view(gateway_factory=...), FakeGateway in conftest.py); no unittest.mock left in the plugin tests (only responses for HTTP); new end-to-end release scenario on the real gateway (login → TOTP → list → reveal → copy → picker → binding) and a compatibility test for session records written by ≤ 1.2.x