docs(security): credential-reference namespaces + migration note (#815)

docs/security.md gains the canonical table of per-driver namespaces, the five
enforcement seams, the out-of-scope cases (appsettings ${secret:}, Sql
connectionStringRef) and the migration steps for existing configs. Galaxy,
OpcUaClient, Heidenhain, Configuration and driver-specs docs, the Galaxy
options XML docs, the drivers rule file and the docker-dev compose comment
point at it. docker-dev's env:GALAXY_MXGW_API_KEY stays valid (allowed legacy
prefix), so no rig change is needed.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-11-11 01:37:25 -05:00
parent a224fd6391
commit 9742a66a9e
9 changed files with 102 additions and 22 deletions
@@ -64,9 +64,11 @@ public sealed record GalaxyDriverOptions(
/// </list>
/// </para>
/// <para>
/// <see cref="FallbackPasswordSecretRef"/> must be a reference — <c>secret:NAME</c> (production),
/// <c>env:NAME</c>, <c>file:PATH</c> or <c>dev:VALUE</c> (rigs only). A bare literal is rejected so a
/// Galaxy password can never sit in cleartext in the DriverConfig JSON / config DB.
/// <see cref="FallbackPasswordSecretRef"/> must be a Galaxy-namespaced reference (lmxopcua#815) —
/// <c>secret:galaxy/NAME</c> / <c>secret:otopcua/galaxy/NAME</c> (production), <c>env:OTOPCUA_GALAXY_NAME</c>
/// / <c>env:GALAXY_MXGW_NAME</c>, or <c>dev:VALUE</c> (rigs only). A bare literal, <c>file:</c> and any other
/// reference are rejected so a Galaxy password never sits in cleartext in the config DB and the field can
/// never name another subsystem's secret.
/// </para>
/// </remarks>
/// <param name="FallbackUser">Galaxy user the fallback acknowledges as; null/empty = no fallback.</param>
@@ -84,20 +86,16 @@ public sealed record GalaxyAlarmAckOptions(
/// <summary>
/// Connection details for the MxAccess gateway. <see cref="ApiKeySecretRef"/> is
/// resolved by <see cref="GalaxySecretRef.ResolveApiKeyAsync"/> at InitializeAsync time. Five forms
/// supported, in priority order:
/// resolved by <see cref="GalaxySecretRef.ResolveApiKeyAsync"/> at InitializeAsync time. References are confined
/// to the Galaxy namespace (lmxopcua#815 — the key is sent to the authored <c>Endpoint</c>):
/// <list type="bullet">
/// <item><c>env:NAME</c> — read from an environment variable (recommended for
/// production; the central config DB holds only the indirection, not the key).</item>
/// <item><c>file:PATH</c> — read from an ACL'd file outside the repo.</item>
/// <item><c>secret:NAME</c> — resolved through the shared <c>ZB.MOM.WW.Secrets</c>
/// <item><c>secret:galaxy/NAME</c> (or <c>secret:otopcua/galaxy/NAME</c>) — the shared <c>ZB.MOM.WW.Secrets</c>
/// encrypted store; fail-closed if absent (the production path).</item>
/// <item><c>dev:KEY</c> — explicit cleartext opt-in for dev rigs / parity tests;
/// no startup warning.</item>
/// <item>Anything else — treated as a literal cleartext API key for back-compat.
/// The resolver emits a <c>Warning</c> at startup so an operator who accidentally
/// committed a cleartext key sees it; production should migrate to <c>env:</c>
/// or <c>file:</c>.</item>
/// <item><c>env:OTOPCUA_GALAXY_NAME</c> (or legacy <c>env:GALAXY_MXGW_NAME</c>) — an environment variable.</item>
/// <item><c>dev:KEY</c> — explicit cleartext opt-in for dev rigs / parity tests; no startup warning.</item>
/// <item>Any other unprefixed string — a literal cleartext API key for back-compat, with a startup
/// <c>Warning</c>.</item>
/// <item>Any other <c>secret:</c>/<c>env:</c> reference, and every <c>file:</c> reference — refused.</item>
/// </list>
/// </summary>
// PR 6.5 tuning notes: