feat(authz): remove SystemPlatform scope + permission-trie walk (Galaxy resolves via Equipment)
This commit is contained in:
@@ -33,16 +33,6 @@ public sealed class PermissionTrieTests
|
||||
Kind = NodeHierarchyKind.Equipment,
|
||||
};
|
||||
|
||||
private static NodeScope GalaxyTag(string cluster, string ns, string[] folders, string tag) =>
|
||||
new()
|
||||
{
|
||||
ClusterId = cluster,
|
||||
NamespaceId = ns,
|
||||
FolderSegments = folders,
|
||||
TagId = tag,
|
||||
Kind = NodeHierarchyKind.SystemPlatform,
|
||||
};
|
||||
|
||||
/// <summary>Verifies cluster-level grant cascades to every tag.</summary>
|
||||
[Fact]
|
||||
public void ClusterLevelGrant_Cascades_ToEveryTag()
|
||||
@@ -111,72 +101,48 @@ public sealed class PermissionTrieTests
|
||||
matches.ShouldBeEmpty();
|
||||
}
|
||||
|
||||
/// <summary>Verifies Galaxy folder segment grant does not leak to sibling folder.</summary>
|
||||
/// <summary>
|
||||
/// Galaxy is now a standard Equipment-kind driver: Galaxy points are ordinary equipment
|
||||
/// tags, so a grant on a Galaxy equipment resolves via the Equipment walk and must not leak
|
||||
/// to a sibling Galaxy equipment.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Galaxy_FolderSegment_Grant_DoesNotLeak_To_Sibling_Folder()
|
||||
public void Galaxy_EquipmentScope_Grant_DoesNotLeak_To_Sibling_Equipment()
|
||||
{
|
||||
var paths = new Dictionary<string, NodeAclPath>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["folder-A"] = new(new[] { "ns-gal", "folder-A" }),
|
||||
["gal-eq-A"] = new(new[] { "ns-gal", "area1", "line1", "gal-eq-A" }),
|
||||
};
|
||||
var rows = new[] { Row("cn=ops", NodeAclScopeKind.Equipment, "folder-A", NodePermissions.Read) };
|
||||
var rows = new[] { Row("cn=ops", NodeAclScopeKind.Equipment, "gal-eq-A", NodePermissions.Read) };
|
||||
var trie = PermissionTrieBuilder.Build("c1", 1, rows, paths);
|
||||
|
||||
var matchA = trie.CollectMatches(GalaxyTag("c1", "ns-gal", ["folder-A"], "tag1"), ["cn=ops"]);
|
||||
var matchB = trie.CollectMatches(GalaxyTag("c1", "ns-gal", ["folder-B"], "tag1"), ["cn=ops"]);
|
||||
var matchA = trie.CollectMatches(EquipmentTag("c1", "ns-gal", "area1", "line1", "gal-eq-A", "tag1"), ["cn=ops"]);
|
||||
var matchB = trie.CollectMatches(EquipmentTag("c1", "ns-gal", "area1", "line1", "gal-eq-B", "tag1"), ["cn=ops"]);
|
||||
|
||||
matchA.Count.ShouldBe(1);
|
||||
matchB.ShouldBeEmpty();
|
||||
matchB.ShouldBeEmpty("grant at gal-eq-A must not apply to sibling gal-eq-B");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Core-003 regression: grants matched during the SystemPlatform (Galaxy) folder walk must
|
||||
/// report <see cref="NodeAclScopeKind.FolderSegment"/> in <see cref="MatchedGrant.Scope"/>,
|
||||
/// not <see cref="NodeAclScopeKind.Equipment"/>. This distinguishes Galaxy folder grants
|
||||
/// from UNS Equipment grants in the audit trail and Admin UI "Probe this permission" panel.
|
||||
/// A grant on a Galaxy equipment tag is reported with its true Equipment-walk structural
|
||||
/// scope (Equipment), not a Galaxy-specific scope — Galaxy now flows through the same
|
||||
/// Equipment permission walk as every other equipment tag.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Galaxy_FolderSegment_Grant_Reports_FolderSegment_Scope_Not_Equipment()
|
||||
public void Galaxy_EquipmentScope_Grant_Reports_Equipment_Scope()
|
||||
{
|
||||
var paths = new Dictionary<string, NodeAclPath>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["section-X"] = new(new[] { "ns-gal", "section-X" }),
|
||||
["gal-eq"] = new(new[] { "ns-gal", "area1", "line1", "gal-eq" }),
|
||||
};
|
||||
var rows = new[] { Row("cn=ops", NodeAclScopeKind.Equipment, "section-X", NodePermissions.Read) };
|
||||
var rows = new[] { Row("cn=ops", NodeAclScopeKind.Equipment, "gal-eq", NodePermissions.Read) };
|
||||
var trie = PermissionTrieBuilder.Build("c1", 1, rows, paths);
|
||||
|
||||
var matches = trie.CollectMatches(GalaxyTag("c1", "ns-gal", ["section-X"], "tag1"), ["cn=ops"]);
|
||||
var matches = trie.CollectMatches(EquipmentTag("c1", "ns-gal", "area1", "line1", "gal-eq", "tag1"), ["cn=ops"]);
|
||||
|
||||
matches.Count.ShouldBe(1);
|
||||
matches[0].Scope.ShouldBe(NodeAclScopeKind.FolderSegment,
|
||||
"the trie walk reports the structural level where the grant was found — FolderSegment for Galaxy, not Equipment");
|
||||
}
|
||||
|
||||
/// <summary>Verifies Galaxy deep folder path all segments report folder segment scope.</summary>
|
||||
[Fact]
|
||||
public void Galaxy_DeepFolderPath_AllSegments_Report_FolderSegment_Scope()
|
||||
{
|
||||
// A three-level folder path — each visited level that carries a grant must report FolderSegment.
|
||||
var paths = new Dictionary<string, NodeAclPath>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["area"] = new(new[] { "ns-gal", "area" }),
|
||||
["area/line"] = new(new[] { "ns-gal", "area", "line" }),
|
||||
["area/line/cell"] = new(new[] { "ns-gal", "area", "line", "cell" }),
|
||||
};
|
||||
var rows = new[]
|
||||
{
|
||||
Row("cn=ops", NodeAclScopeKind.Equipment, "area", NodePermissions.Read),
|
||||
Row("cn=ops", NodeAclScopeKind.Equipment, "area/line", NodePermissions.Read),
|
||||
Row("cn=ops", NodeAclScopeKind.Equipment, "area/line/cell", NodePermissions.Read),
|
||||
};
|
||||
var trie = PermissionTrieBuilder.Build("c1", 1, rows, paths);
|
||||
|
||||
var matches = trie.CollectMatches(
|
||||
GalaxyTag("c1", "ns-gal", ["area", "line", "cell"], "tag1"), ["cn=ops"]);
|
||||
|
||||
matches.Count.ShouldBe(3, "one match per folder level visited");
|
||||
matches.ShouldAllBe(m => m.Scope == NodeAclScopeKind.FolderSegment,
|
||||
"every matched folder level must report FolderSegment, never Equipment");
|
||||
matches[0].Scope.ShouldBe(NodeAclScopeKind.Equipment,
|
||||
"Galaxy equipment grants resolve via the Equipment walk and report Equipment scope");
|
||||
}
|
||||
|
||||
/// <summary>Verifies cross-cluster grant does not leak.</summary>
|
||||
|
||||
Reference in New Issue
Block a user