fix(heidenhain): refuse literal credentials and writable/mistyped tags at the save path (#803 review)
- Review 1: RawTreeService Create/UpdateDriver and Create/UpdateDevice refuse a Heidenhain config whose password fields are not blank / secret:heidenhain/... / env:OTOPCUA_HEIDENHAIN_... (DriverConfigSaveGate over HeidenhainOptionsParser.DescribeCredentialProblems: top level, Access, Devices[], case-insensitive keys; the value is never echoed), so a literal password never reaches the draft DB. The driver and device modals show the reason and disable Save. - Review 8: CreateTag/UpdateTag/ImportTags (tag modal, manual entry, CSV import, browse commit) refuse a ReadWrite Heidenhain tag or a Tag.DataType that disagrees with what the driver publishes (HeidenhainTagRules: catalog type, Float64 => Double, or the binding's dataType). The tag modal and manual-entry grid fix the access level at Read and derive the data type from the address (RawTagRowDefaults). New deploy gate HeidenhainTagDataTypeMismatch. - docs/drivers/Heidenhain.md: credential namespace convention + why, the save-path and deploy enforcement, optional-role credential behaviour, BadConfigurationError, backoff/ordering notes. Tests: HeidenhainSavePathTests (service save path; red with the gates disabled) and new DraftValidatorHeidenhainTests cases.
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.Heidenhain;
|
||||
|
||||
/// <summary>
|
||||
/// Rules about the Tag ROW (not its TagConfig) for a Heidenhain tag: the one authority shared by every AdminUI
|
||||
/// authoring path (RawTagModal, manual entry, CSV import, browse commit — all through <c>RawTreeService</c>)
|
||||
/// and the deploy gate, so authoring and deploy can never disagree.
|
||||
/// </summary>
|
||||
public static class HeidenhainTagRules
|
||||
{
|
||||
/// <summary>
|
||||
/// The <c>Tag.DataType</c> (OPC UA built-in type name) a Heidenhain tag must carry for the value the driver
|
||||
/// publishes, or null when the TagConfig does not resolve (the TagConfig gate reports that).
|
||||
/// </summary>
|
||||
/// <param name="tagConfig">The TagConfig JSON.</param>
|
||||
/// <returns>e.g. <c>Int32</c>, <c>Double</c>, <c>String</c>; null when unresolvable.</returns>
|
||||
public static string? ExpectedTagDataType(string? tagConfig) =>
|
||||
HeidenhainTagDefinitionFactory.TryFromTagConfig("rule", "", tagConfig, out var def, out _)
|
||||
? OpcTypeName(def.DataType)
|
||||
: null;
|
||||
|
||||
/// <summary>The OPC UA built-in type name (the <c>Tag.DataType</c> vocabulary) for a published data type.</summary>
|
||||
/// <param name="type">The driver data type.</param>
|
||||
/// <returns>The type name.</returns>
|
||||
public static string OpcTypeName(DriverDataType type) => type switch
|
||||
{
|
||||
DriverDataType.Boolean => "Boolean",
|
||||
DriverDataType.Int16 => "Int16",
|
||||
DriverDataType.Int32 => "Int32",
|
||||
DriverDataType.Int64 => "Int64",
|
||||
DriverDataType.Float64 => "Double",
|
||||
DriverDataType.String => "String",
|
||||
_ => type.ToString(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Why a Heidenhain tag row may not be saved / deployed: a writable access level (the driver is read-only),
|
||||
/// or a <c>Tag.DataType</c> that disagrees with what the driver publishes for its address.
|
||||
/// </summary>
|
||||
/// <param name="readWrite">Whether the row's access level is ReadWrite.</param>
|
||||
/// <param name="tagDataType">The row's <c>Tag.DataType</c>.</param>
|
||||
/// <param name="tagConfig">The row's TagConfig.</param>
|
||||
/// <returns>The reason, or null when the row is acceptable.</returns>
|
||||
public static string? DescribeRowProblem(bool readWrite, string? tagDataType, string? tagConfig)
|
||||
{
|
||||
if (readWrite)
|
||||
return "Heidenhain tags are read-only — set the access level to Read (the driver never writes to the control).";
|
||||
var expected = ExpectedTagDataType(tagConfig);
|
||||
if (expected is not null && !string.Equals(expected, tagDataType, StringComparison.OrdinalIgnoreCase))
|
||||
return $"Data type {tagDataType} does not match what the driver publishes for this address ({expected}).";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user