feat(controller): add PUT /api/v1/humans/{name} route — fixes #729 - #796
feat(controller): add PUT /api/v1/humans/{name} route — fixes #729#796hlgone wants to merge 2 commits into
Conversation
📊 CI Metrics ReportSummary
By Role
Per-Test Breakdown
Trends✅ 4 test(s) improved (fewer LLM calls) Generated by HiClaw CI on 2026-05-11 23:41:18 UTC |
|
After looking at the job log, the failure is not test-14 itself but the pre-test orchestrator setup failing to verify Higress AI Gateway authorization for the Manager: Preceded by a 300s timeout on Manager welcome-message: So Matrix evidence still holds — same shard's Re-running this single matrix cell should be enough to confirm. Happy to push an empty commit if a maintainer prefers that over a manual rerun. |
|
Friendly ping — this PR has been ready for ~3 days. The failing CI cell ( @shiyiyue1102 acknowledged the API gap in #729; the change here is small and confined to the controller's Human route + spec-field echo. Could a maintainer trigger a rerun, or let me know if you'd prefer I push an empty commit to retrigger? Happy to follow whichever convention the project prefers. |
Stock v1.2.0 registers POST/GET/DELETE for humans but no PUT, so `agt apply -f` against an existing Human fails with 405 Method Not Allowed (apply.go sends PUT for resources that already exist). Workers, teams and managers all have the route; humans is the only gap. Adds the minimal surface to close it, mirroring UpdateWorker: - UpdateHumanRequest with nil-skip semantics — an omitted field leaves the stored value untouched; an empty non-nil slice clears it - UpdateHuman handler with the same conflict-retry loop as UpdateWorker - PUT route registration under ActionUpdate authz Covers accessibleTeams and accessibleWorkers, which are the fields a partial update needs in order to grant or revoke access without rewriting the rest of the spec. Tests pin all three layers: field update, preservation of unsent fields, and the route table itself (a handler with no route still answers 405). Refs agentscope-ai#729
The DTO documents "omitted preserves, empty array clears" but only the non-empty replace path was covered. Revoking the last team or worker grant sends [], so a regression there would silently leave access in place — a security-relevant gap, not a cosmetic one. The test passes against the current nil-check implementation, so it was validated by mutation: swapping `!= nil` for `len(...) > 0` (the most likely wrong implementation) makes it fail with the sets still populated. Restored afterwards; suite green.
8cdae1d to
73b4661
Compare
|
Rebuilt this PR's head on current What changed vs. the previous version of this PR
Three of the original changes turned out to be unnecessary against current
What remains is only the server-side gap:
Why this matters: That makes it impossible to grant or revoke a Human's team/worker access without rewriting the whole spec. Tests (4, all in
Also verified end to end against a v1.2.0 embedded image with only the controller binary replaced: the partial-spec Happy to split the tests out or adjust the DTO surface if you'd prefer a different shape. |
Summary
Adds the missing PUT route for Human resources so the REST API can update an existing Human without forcing DELETE+CREATE.
PUT /api/v1/humans/{name}handler + route registration (pattern matchingUpdateWorker/UpdateTeam)UpdateHumanRequestpartial-update body with nil-vs-[] semantic for slice fields and*intforPermissionLevelto disambiguate "field absent" from "set to 0"hiclaw update humanCLI subcommand alongsideupdate worker/update team/update managerHumanResponsenow echoes spec-level fields (Email,PermissionLevel,AccessibleTeams,AccessibleWorkers,Note) so read-modify-write callers can avoid raw kubectlWhy
HumanReconcileralready supports declarative reconcile viabuildDesiredHumanRooms, but no transport surface invoked it on spec changes.hiclaw apply -f human.yamlon an existing Human returned HTTP 405. The only way to changeaccessibleTeamswas DELETE+CREATE, which resetsinitialPasswordand is fragile across BFF / Matrix credential caches.This is the natural sibling of
UpdateWorker/UpdateTeamand the same partial-update + optimistic-lock-retry pattern.Test plan
5 new tests in
hiclaw-controller/internal/server/resource_handler_test.go:TestUpdateHumanAccessibleTeams— PUT new accessibleTeams replaces the slice; unrelated fields preservedTestUpdateHumanRemoveAccessibleTeams— PUT[]clears the slice (revoke-all path)TestUpdateHumanPermissionLevel— PUT permissionLevel replaces value via*intpointerTestUpdateHumanNotFound— PUT non-existent → 404 via writeK8sErrorTestGetHumanEchoesSpecFields— GET response carries all spec fieldsAll pass in
go test ./internal/server/against Go 1.25. The unrelated pre-existingTestResolveAndExtract_ZipWithoutSoulmd_Succeedsfailure in thegolang:1.25slim image (missing systemunzipbinary) is not introduced by this PR.