feat(auth): ScadaBridge TransportExport excludes inbound API keys (re-arch C4; methods-only, import ignores legacy key sections); keys re-issued per environment

This commit is contained in:
Joseph Doherty
2026-06-02 05:06:40 -04:00
parent d1191fddf9
commit 731cfd3bfc
34 changed files with 212 additions and 190 deletions
@@ -13,6 +13,8 @@ namespace ZB.MOM.WW.ScadaBridge.Transport.Serialization;
/// ignorant POCO types — what <see cref="EntitySerializer"/> consumes/produces
/// on the application side of the bundle boundary.
/// </summary>
// ApiKeys is intentionally absent: inbound API keys are not transported between
// environments (re-arch C4). The aggregate only carries API methods.
public sealed record EntityAggregate(
IReadOnlyList<TemplateFolder> TemplateFolders,
IReadOnlyList<Template> Templates,
@@ -22,7 +24,6 @@ public sealed record EntityAggregate(
IReadOnlyList<DatabaseConnectionDefinition> DatabaseConnections,
IReadOnlyList<NotificationList> NotificationLists,
IReadOnlyList<SmtpConfiguration> SmtpConfigurations,
IReadOnlyList<ApiKey> ApiKeys,
IReadOnlyList<ApiMethod> ApiMethods);
/// <summary>
@@ -30,6 +31,14 @@ public sealed record EntityAggregate(
/// order so importers can apply them inline. Lists are never null on the wire
/// — empty arrays are preferred over nulls so JSON consumers can rely on each
/// property being present.
/// <para>
/// <see cref="ApiKeys"/> is a <b>legacy, read-only</b> field retained purely for
/// backward-compatible deserialization of bundles produced before the
/// inbound-API-key re-architecture (C4). New exports never populate it (it stays
/// <c>null</c> and is dropped from the JSON by the serializer's
/// <c>WhenWritingNull</c> policy); the importer counts any keys present in an old
/// bundle, ignores them, and surfaces a note — keys are re-created per environment.
/// </para>
/// </summary>
public sealed record BundleContentDto(
IReadOnlyList<TemplateFolderDto> TemplateFolders,
@@ -39,8 +48,8 @@ public sealed record BundleContentDto(
IReadOnlyList<DatabaseConnectionDto> DatabaseConnections,
IReadOnlyList<NotificationListDto> NotificationLists,
IReadOnlyList<SmtpConfigDto> SmtpConfigs,
IReadOnlyList<ApiKeyDto> ApiKeys,
IReadOnlyList<ApiMethodDto> ApiMethods);
IReadOnlyList<ApiMethodDto> ApiMethods,
IReadOnlyList<ApiKeyDto>? ApiKeys = null);
/// <summary>
/// Carved-off secret values for an entity. The outer DTO carries all non-
@@ -144,16 +153,20 @@ public sealed record SmtpConfigDto(
TimeSpan RetryDelay,
SecretsBlock? Secrets);
// Legacy DTO: only deserialized from pre-C4 bundles so the importer can count and
// ignore the keys they contain. New exports never emit an ApiKeys array.
public sealed record ApiKeyDto(
string Name,
string KeyHash,
bool IsEnabled,
SecretsBlock? Secrets);
// ApprovedApiKeyIds is intentionally absent: it linked methods to keys that are no
// longer transported (re-arch C4). Scopes are re-granted per environment. The field
// in any old bundle is simply ignored on read.
public sealed record ApiMethodDto(
string Name,
string Script,
string? ApprovedApiKeyIds,
string? ParameterDefinitions,
string? ReturnDefinition,
int TimeoutSeconds);