fix(security): id-form credential references match by id only; id-shaped driver names refused (#849 review)

A driver named 'drv' (env form DRV) matched every sibling's id-form variable
env:<PREFIX>DRV_<12HEX>_... as 'another instance', breaking the recommended id
convention fleet-wide - including for a name that pre-dates the rule.
ReferenceNames is split into ReferenceNamesId / ReferenceNamesName; a reference
whose instance part is id-shaped (secret: DRV-<12 hex>, env: DRV_<12 HEX>[_...])
is matched by id only. DescribeNameChangeProblemsAsync also refuses new names
whose env form is DRV or starts with an id form (IsReservedInstanceName) at
create, /raw rename and config-modal update.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-11-11 06:35:52 -05:00
parent 780da7528a
commit d68dff0946
5 changed files with 186 additions and 16 deletions
@@ -140,4 +140,28 @@ public sealed class CredentialNameClaimSavePathTests
renamed.Ok.ShouldBeTrue(renamed.Error);
}
/// <summary>
/// #849 review: a name in the system-generated id form ('drv', 'DRV-&lt;12 hex&gt;…') would shadow every driver's
/// id-form references — refused at create, the /raw rename and the config modal, even with no reference stored.
/// </summary>
[Theory]
[InlineData("drv")]
[InlineData("DRV")]
[InlineData("DRV-0123456789ab")]
[InlineData("drv-0123456789AB-line")]
public async Task An_id_shaped_name_is_refused_on_every_name_path(string newName)
{
var (svc, db, sharerId) = await WithSharerAsync("env:OTOPCUA_GALAXY_DRV_0123456789AB_KEY");
var create = await svc.CreateDriverAsync(RawTreeTestDb.ClusterId, null, newName, DriverTypeNames.Galaxy, "{}", Ct);
create.Ok.ShouldBeFalse();
create.Error!.ShouldContain("system-generated driver id");
(await svc.RenameDriverAsync(sharerId, newName, RowVersion(db, sharerId), Ct)).Ok.ShouldBeFalse();
(await svc.UpdateDriverAsync(sharerId, newName, "{}", null, RowVersion(db, sharerId), Ct)).Ok.ShouldBeFalse();
// A type without credential rules is not affected.
(await svc.CreateDriverAsync(RawTreeTestDb.ClusterId, null, newName, DriverTypeNames.Modbus, "{}", Ct)).Ok.ShouldBeTrue();
}
}