fix(gateway): resolve array attribute constraints by bare name via [] fallback
This commit is contained in:
@@ -207,6 +207,62 @@ public sealed class ConstraintEnforcerTests
|
||||
Assert.Equal("read_historized_only", failure.ConstraintName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A bare array attribute address (no trailing <c>[]</c>) resolves through the Galaxy index
|
||||
/// even though arrays are keyed by their suffixed FullTagReference (e.g. "Pump_001.Levels[]").
|
||||
/// Without the <c>[]</c> fallback in ResolveTarget the bare name misses the index and a
|
||||
/// read-constrained key gets a spurious tag_metadata denial for an AddItem it should allow.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task CheckReadTagAsync_WithBareArrayName_ResolvesViaArraySuffixFallback()
|
||||
{
|
||||
ConstraintEnforcer enforcer = CreateEnforcer(out _);
|
||||
ApiKeyIdentity identity = CreateIdentity(ApiKeyConstraints.Empty with
|
||||
{
|
||||
// A read constraint that covers the Pump_001 subtree; the array attribute is inside it.
|
||||
ReadTagGlobs = ["Pump_001.*"],
|
||||
});
|
||||
|
||||
ConstraintFailure? failure = await enforcer.CheckReadTagAsync(
|
||||
identity,
|
||||
"Pump_001.Levels",
|
||||
CancellationToken.None);
|
||||
|
||||
// Before the fix: bare "Pump_001.Levels" misses the index (keyed "Pump_001.Levels[]") and
|
||||
// returns a tag_metadata failure. After the fix: it resolves and is within scope -> null.
|
||||
Assert.Null(failure);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A bare non-array name that is genuinely absent from the index still resolves to null:
|
||||
/// the <c>[]</c> probe must not manufacture a false positive for a scalar/missing tag.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task CheckReadTagAsync_WithMissingNonArrayName_StillFailsToResolve()
|
||||
{
|
||||
ConstraintEnforcer enforcer = CreateEnforcer(out _);
|
||||
ApiKeyIdentity identity = CreateIdentity(ApiKeyConstraints.Empty with
|
||||
{
|
||||
ReadTagGlobs = ["Pump_001.*"],
|
||||
});
|
||||
|
||||
// "Pump_001.Scalar" is not in the index, and "Pump_001.Scalar[]" is not either, so the
|
||||
// suffix probe must not resolve it. A genuinely-unknown name behaves the same.
|
||||
ConstraintFailure? missingScalar = await enforcer.CheckReadTagAsync(
|
||||
identity,
|
||||
"Pump_001.Scalar",
|
||||
CancellationToken.None);
|
||||
Assert.NotNull(missingScalar);
|
||||
Assert.Equal("tag_metadata", missingScalar.ConstraintName);
|
||||
|
||||
ConstraintFailure? unknown = await enforcer.CheckReadTagAsync(
|
||||
identity,
|
||||
"DoesNotExist_999.Whatever",
|
||||
CancellationToken.None);
|
||||
Assert.NotNull(unknown);
|
||||
Assert.Equal("tag_metadata", unknown.ConstraintName);
|
||||
}
|
||||
|
||||
private static ConstraintEnforcer CreateEnforcer(out FakeAuditWriter auditWriter)
|
||||
{
|
||||
auditWriter = new FakeAuditWriter();
|
||||
@@ -276,6 +332,14 @@ public sealed class ConstraintEnforcerTests
|
||||
AttributeName = "NonHistorized",
|
||||
FullTagReference = "Pump_001.NonHistorized",
|
||||
},
|
||||
new GalaxyAttribute
|
||||
{
|
||||
// Galaxy SQL keys array attributes by their suffixed FullTagReference,
|
||||
// so the index entry is "Pump_001.Levels[]", not the bare name.
|
||||
AttributeName = "Levels",
|
||||
FullTagReference = "Pump_001.Levels[]",
|
||||
IsArray = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
new GalaxyObject
|
||||
|
||||
Reference in New Issue
Block a user