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
@@ -138,14 +138,15 @@
@RenderCheckboxList(_smtpConfigs, s => s.Id, s => s.Host, _selectedSmtpConfigs)
</fieldset>
<fieldset class="mb-4" data-testid="group-api-keys">
<legend class="h6">API Keys</legend>
@RenderCheckboxList(_apiKeys, k => k.Id, k => k.Name, _selectedApiKeys)
</fieldset>
<fieldset class="mb-4" data-testid="group-api-methods">
<legend class="h6">API Methods</legend>
@RenderCheckboxList(_apiMethods, m => m.Id, m => m.Name, _selectedApiMethods)
<div class="alert alert-info small mt-2 mb-0 py-2" role="alert" data-testid="api-keys-not-transported">
<strong>API keys are not part of config transport.</strong> Inbound API keys
live in each environment's own secret store and cannot be exported. After
importing, re-create the keys on the destination and re-grant their method
scopes via the admin UI/CLI.
</div>
</fieldset>
<div class="d-flex justify-content-end gap-2 mt-4">
@@ -261,10 +262,7 @@
{
<li>SmtpConfig: @s.Host</li>
}
@foreach (var k in _resolved.ApiKeys.OrderBy(k => k.Name, StringComparer.OrdinalIgnoreCase))
{
<li>ApiKey: @k.Name</li>
}
@* Inbound API keys are not transported (re-arch C4) — methods only. *@
@foreach (var m in _resolved.ApiMethods.OrderBy(m => m.Name, StringComparer.OrdinalIgnoreCase))
{
<li>ApiMethod: @m.Name</li>
@@ -69,7 +69,7 @@ public partial class TransportExport : ComponentBase
private List<DatabaseConnectionDefinition> _dbConnections = new();
private List<NotificationList> _notificationLists = new();
private List<SmtpConfiguration> _smtpConfigs = new();
private List<ApiKey> _apiKeys = new();
// Inbound API keys are not transported between environments (re-arch C4); only methods.
private List<ApiMethod> _apiMethods = new();
// ---- Step 1: selection state ----
@@ -82,7 +82,7 @@ public partial class TransportExport : ComponentBase
private readonly HashSet<int> _selectedDbConnections = new();
private readonly HashSet<int> _selectedNotificationLists = new();
private readonly HashSet<int> _selectedSmtpConfigs = new();
private readonly HashSet<int> _selectedApiKeys = new();
// No _selectedApiKeys: inbound API keys are not transported (re-arch C4).
private readonly HashSet<int> _selectedApiMethods = new();
private string _filter = string.Empty;
private bool _includeDependencies = true;
@@ -124,7 +124,7 @@ public partial class TransportExport : ComponentBase
_dbConnections = (await ExternalRepo.GetAllDatabaseConnectionsAsync()).ToList();
_notificationLists = (await NotificationRepo.GetAllNotificationListsAsync()).ToList();
_smtpConfigs = (await NotificationRepo.GetAllSmtpConfigurationsAsync()).ToList();
_apiKeys = (await InboundApiRepo.GetAllApiKeysAsync()).ToList();
// Inbound API keys are not transported (re-arch C4) — only methods are loaded.
_apiMethods = (await InboundApiRepo.GetAllApiMethodsAsync()).ToList();
}
catch (Exception ex)
@@ -169,7 +169,6 @@ public partial class TransportExport : ComponentBase
|| _selectedDbConnections.Count > 0
|| _selectedNotificationLists.Count > 0
|| _selectedSmtpConfigs.Count > 0
|| _selectedApiKeys.Count > 0
|| _selectedApiMethods.Count > 0;
private bool PassphraseValid =>
@@ -205,7 +204,7 @@ public partial class TransportExport : ComponentBase
DatabaseConnectionIds: _selectedDbConnections.ToList(),
NotificationListIds: _selectedNotificationLists.ToList(),
SmtpConfigurationIds: _selectedSmtpConfigs.ToList(),
ApiKeyIds: _selectedApiKeys.ToList(),
// Inbound API keys are not transported (re-arch C4) — methods only.
ApiMethodIds: _selectedApiMethods.ToList(),
IncludeDependencies: _includeDependencies);
}
@@ -393,7 +392,6 @@ public partial class TransportExport : ComponentBase
_selectedDbConnections.Clear();
_selectedNotificationLists.Clear();
_selectedSmtpConfigs.Clear();
_selectedApiKeys.Clear();
_selectedApiMethods.Clear();
_filter = string.Empty;
_includeDependencies = true;