fix(mqtt-browser): reject a wildcard rebirth scope before any NCMD leaves
SparkplugRebirthScope (the AdminUI's typed input) rejects '+'/'#' and its own
remarks say it is 'advisory, not the gate' because MqttBrowseSession
.ResolveRebirthTargets 'refuses an unusable one BEFORE any message leaves'. That
claim was false: the bare {group}/{edgeNode} branch — honoured on purpose, since a
node that has not birthed is the prime rebirth target — gated on IsUsableLabel,
which checks length and control characters only. A scope of 'Plant1/#' therefore
published spBv1.0/Plant1/NCMD/# , a PUBLISH the MQTT spec forbids and a conformant
broker answers by closing the browse connection; '+' would have fanned one
operator click across every matching edge node.
The check is a separate IsUsableRebirthSegment rather than a tightening of
IsUsableLabel: that helper also judges Sparkplug METRIC names, which are arbitrary
publisher-chosen UTF-8 and never part of a topic, so tightening it there would drop
legitimate metrics from the tree. Cases 1 and 2 cannot reach this shape — their ids
come off SparkplugTopic.TryParse, which already rejects both characters.
Driver.Mqtt.Tests 724 (was 708).
This commit is contained in:
@@ -854,6 +854,27 @@ public sealed class MqttBrowseSessionTests
|
||||
s.PublishCountForTest.ShouldBe(0);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("Plant1/#")]
|
||||
[InlineData("Plant1/+")]
|
||||
[InlineData("+/EdgeA")]
|
||||
[InlineData("#/EdgeA")]
|
||||
public async Task RequestRebirthAsync_WildcardScope_PublishesNothing(string scope)
|
||||
{
|
||||
// SparkplugRebirthScope (the AdminUI's typed input) rejects a wildcard and its own remarks say
|
||||
// it is "advisory, not the gate" because ResolveRebirthTargets "refuses an unusable one BEFORE
|
||||
// any message leaves". That claim has to be true here: an unobserved `{group}/{edgeNode}` scope
|
||||
// is honoured on purpose (a node that has not birthed is the prime rebirth target), and the
|
||||
// label check behind it looked only at length and control characters. A wildcard segment would
|
||||
// therefore have published `spBv1.0/Plant1/NCMD/#` — a PUBLISH the MQTT spec forbids, which a
|
||||
// conformant broker answers by closing the browse connection.
|
||||
await using var s = new MqttBrowseSession(MqttMode.SparkplugB);
|
||||
|
||||
await Should.ThrowAsync<ArgumentException>(
|
||||
async () => await s.RequestRebirthAsync(scope, TestContext.Current.CancellationToken));
|
||||
s.PublishCountForTest.ShouldBe(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RequestRebirthAsync_InPlainMode_IsRefused()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user