fix: populate Privileges on PvePermission from access/permissions (#163)

UserService.GetPermissions unwrapped the path-keyed /access/permissions
response and discarded prop.Value, so every returned PvePermission had a
path but no privilege data. Add a Privileges dictionary populated from
the privilege map; a key's presence means the privilege is granted and
its value is whether the grant propagates to sub-paths, matching PVE's
documented "propagate boolean" contract for that endpoint.

Co-authored-by: goodolclint-claude[bot] <323206664+goodolclint-claude[bot]@users.noreply.github.com>
This commit is contained in:
goodolclint-claude[bot]
2026-09-02 13:19:53 -05:00
committed by GitHub
parent 4cc18f1cc2
commit a7d2b877f5
4 changed files with 65 additions and 5 deletions
@@ -768,16 +768,56 @@ namespace PSProxmoxVE.Core.Tests.Services
_mockClient.Setup(c => c.GetAsync("access/permissions"))
.ReturnsAsync(@"{""data"":{
""/"":{ ""Datastore.Audit"":1, ""VM.Audit"":1 },
""/nodes/pve1"":{ ""Sys.Console"":1 }
""/vms/100"":{ ""VM.Audit"":1, ""VM.PowerMgmt"":0 }
}}");
// Act
var result = _service.GetPermissions(_session);
// Assert
// Assert — a key's presence means the privilege is granted; its value is whether
// that grant propagates to sub-paths (PVE's "propagate boolean" contract).
Assert.Equal(2, result.Length);
Assert.Contains(result, p => p.Path == "/");
Assert.Contains(result, p => p.Path == "/nodes/pve1");
var vmPerm = Assert.Single(result, p => p.Path == "/vms/100");
Assert.NotNull(vmPerm.Privileges);
Assert.True(vmPerm.Privileges!.ContainsKey("VM.Audit"));
Assert.True(vmPerm.Privileges!["VM.Audit"]);
Assert.True(vmPerm.Privileges!.ContainsKey("VM.PowerMgmt"));
Assert.False(vmPerm.Privileges!["VM.PowerMgmt"]);
}
[Fact]
public void GetPermissions_ArrayResponse_LeavesPrivilegesNull()
{
// Arrange — the flat /access/acl-shaped array response carries no privilege map
_mockClient.Setup(c => c.GetAsync("access/permissions"))
.ReturnsAsync(@"{""data"":[
{ ""path"":""/vms/100"", ""roleid"":""PVEVMAdmin"", ""ugid"":""deploy@pve"", ""propagate"":1 }
]}");
// Act
var result = _service.GetPermissions(_session);
// Assert
var perm = Assert.Single(result);
Assert.Equal("/vms/100", perm.Path);
Assert.Null(perm.Privileges);
}
[Fact]
public void GetPermissions_EmptyPrivilegeMap_YieldsNonNullEmptyDictionary()
{
// Arrange
_mockClient.Setup(c => c.GetAsync("access/permissions"))
.ReturnsAsync(@"{""data"":{""/"":{}}}");
// Act
var result = _service.GetPermissions(_session);
// Assert
var perm = Assert.Single(result);
Assert.NotNull(perm.Privileges);
Assert.Empty(perm.Privileges!);
}
[Fact]