feat(legacy): session-auth write adapter — port-forwards, firewall, networks#12
Conversation
|
Note: this branch also includes a bundled fix — |
457044f to
ca9e1d7
Compare
|
Update: split the CI fix out into #13 as requested. This branch is now the legacy adapter only (force-pushed to drop the kiota commit).
|
…etworks
Add UnifiLegacyClient, an [Obsolete], thin, deletion-ready write path over the
classic controller REST API (/proxy/network/api/s/<site>/rest/...) for the
resources the official integration API can't write yet (rolling out through
2026): port-forwards, firewall groups, and networks/VLANs. Per ADR-0003.
Auth is the classic controller SESSION (POST /api/auth/login → TOKEN cookie +
X-CSRF-Token), not X-API-KEY: it works against the .containers/unifi UniFi OS
Server (which exposes no scriptable key mint) and any UniFi OS gateway. The
generated integration client (X-API-KEY) is untouched.
- UnifiLegacyOptions: session config from UNIFI_LEGACY_BASE_URL / UNIFI_USERNAME
/ UNIFI_PASSWORD / UNIFI_VERIFY_TLS; ControllerRoot derived for login.
- UnifiLegacySession: login, cookie/CSRF management, auto re-auth on 401.
- UnifiLegacyClient: List/Create/Delete per resource over the {meta,data}
envelope; DTOs match real API shapes (snake_case, create omits server fields).
- CLI: `unifisharp legacy <list|create|delete> <resource> [id] [--json '<body>']`.
- Tests: 14 unit (URL/serialization/envelope/redaction) + 3 skippable-live
round-trips (create→list→delete) against the test container. All green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ca9e1d7 to
251dde3
Compare
Adds the legacy write path UnifiSharp has been missing — the #102 / ADR-0003 stopgap until Ubiquiti ships official integration-API write endpoints (rolling out through 2026).
What
UnifiLegacyClient— an[Obsolete], thin, deletion-ready write client over the classic controller REST API (/proxy/network/api/s/<site>/rest/...) for the resources the integration API can't write yet:List/Create/DeleteList/Create/DeleteList/Create/DeleteThe Kiota-generated integration client is untouched; this is an additive, isolated namespace (
UnifiSharp.Legacy). When the official write endpoints land, delete the namespace and switch callers.Auth: session, not X-API-KEY
The legacy API uses the classic controller session —
POST /api/auth/login→TOKENcookie +X-CSRF-Token, reused (and auto-rotated) on subsequent calls, with one transparent re-auth on a 401. This works against the.containers/unifiUniFi OS Server test container (which exposes no scriptable API-key mint) and any UniFi OS gateway. Config viaUNIFI_LEGACY_BASE_URL/UNIFI_USERNAME/UNIFI_PASSWORD/UNIFI_VERIFY_TLS.DTOs
Records matching the real API shapes (captured from live round-trips): snake_case
[JsonPropertyName],WhenWritingNullso a create sends only set fields and omits server-assigned_id/site_id. Envelope{meta:{rc},data:[]}parsed centrally; non-okrcsurfaces the API'smsg(e.g.api.err.InvalidPayload).CLI
Tests — all green
UNIFI_LEGACY_*). One shared session per class viaIClassFixture— the controller rate-limits logins (429), so we log in once.Notes
Homelab/.containers/unifi→./bootstrap.shthenset -a && . ./credentials.env.InvalidPayload— live test uses 3990.🤖 Generated with Claude Code