diff --git a/src/PSProxmoxVE.Core/Models/Users/PvePermission.cs b/src/PSProxmoxVE.Core/Models/Users/PvePermission.cs
index d619097..d1fbdf9 100644
--- a/src/PSProxmoxVE.Core/Models/Users/PvePermission.cs
+++ b/src/PSProxmoxVE.Core/Models/Users/PvePermission.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using Newtonsoft.Json;
namespace PSProxmoxVE.Core.Models.Users;
@@ -33,6 +34,16 @@ public class PvePermission
[JsonProperty("ugid")]
public string? UserId { get; set; }
+ ///
+ /// The privileges granted on , keyed by privilege name (e.g. "VM.Audit").
+ /// A key's presence means the privilege is granted; its value is whether that grant
+ /// propagates to sub-paths, per the PVE /access/permissions contract ("propagate boolean").
+ /// Populated only when this entry comes from the path-keyed /access/permissions response
+ /// with a privilege map for the path; null for entries from the flat /access/acl array,
+ /// or when PVE returned no privilege map for the path.
+ ///
+ public IReadOnlyDictionary? Privileges { get; set; }
+
///
public override string ToString()
{
diff --git a/src/PSProxmoxVE.Core/Services/UserService.cs b/src/PSProxmoxVE.Core/Services/UserService.cs
index e677900..5c07f32 100644
--- a/src/PSProxmoxVE.Core/Services/UserService.cs
+++ b/src/PSProxmoxVE.Core/Services/UserService.cs
@@ -623,7 +623,15 @@ namespace PSProxmoxVE.Core.Services
var result = new List();
foreach (var prop in ((JObject)data).Properties())
{
- var perm = new PvePermission { Path = prop.Name };
+ var privileges = prop.Value is JObject privMap
+ ? privMap.Properties().ToDictionary(
+ p => p.Name,
+ p => p.Value.Type == JTokenType.Boolean
+ ? p.Value.Value()
+ : p.Value.Type == JTokenType.Integer && p.Value.Value() != 0,
+ StringComparer.OrdinalIgnoreCase)
+ : null;
+ var perm = new PvePermission { Path = prop.Name, Privileges = privileges };
result.Add(perm);
}
return result.ToArray();
diff --git a/src/PSProxmoxVE/Cmdlets/Users/GetPvePermissionCmdlet.cs b/src/PSProxmoxVE/Cmdlets/Users/GetPvePermissionCmdlet.cs
index c78af4d..6630dbe 100644
--- a/src/PSProxmoxVE/Cmdlets/Users/GetPvePermissionCmdlet.cs
+++ b/src/PSProxmoxVE/Cmdlets/Users/GetPvePermissionCmdlet.cs
@@ -8,7 +8,8 @@ namespace PSProxmoxVE.Cmdlets.Users
///
/// Lists ACL entries (permissions) in Proxmox VE.
///
- /// Returns Access Control List entries from the Proxmox VE access management system.
+ /// Returns Access Control List entries from the Proxmox VE access management system,
+ /// each carrying the privileges granted on its path in the Privileges property.
/// Optionally filter by path or user/group ID.
///
///
diff --git a/tests/PSProxmoxVE.Core.Tests/Services/UserServiceTests.cs b/tests/PSProxmoxVE.Core.Tests/Services/UserServiceTests.cs
index 3f3c367..9468806 100644
--- a/tests/PSProxmoxVE.Core.Tests/Services/UserServiceTests.cs
+++ b/tests/PSProxmoxVE.Core.Tests/Services/UserServiceTests.cs
@@ -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]