docs(security): id-form matching, ASCII-only name form, one-save pin side-step, rename/device-save race (#848 #849 review)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-11-11 06:35:52 -05:00
parent d68dff0946
commit ea156265a2
2 changed files with 24 additions and 5 deletions
+5 -1
View File
@@ -366,7 +366,11 @@ host logger factory (wired in `DriverFactoryBootstrap`; the FOCAS and TwinCAT fa
(case-insensitive; another-instance match beats an own-name match) is refused at save (`DriverConfigSaveGate.ValidateAsync`),
deploy (`CredentialReferenceOtherInstance`), Test Connect (`TestDriverConnect.DriverInstanceId`) and browse
(`OpenAsync(…, driverInstanceId, …)`; no ConfigDb ⇒ fail closed). One rule: `DriverCredentialPolicy.DescribeOtherInstanceProblems`
+ `DriverInstanceIdentities`. The runtime adds no check (drivers don't know the fleet); `env:` is not instance-scoped.
+ `DriverInstanceIdentities`. The runtime adds no check (drivers don't know the fleet). Since #849 `env:<PREFIX><INSTANCE>_…`
is instance-scoped the same way (INSTANCE = id/name upper-cased, other chars `_`; `_`-bounded prefix match); an id-shaped
part (`DRV_<12 HEX>`, `secret:…/DRV-<12 hex>/`) matches by id only, and id-shaped names (`drv`, `DRV-<12 hex>…`) are
refused. #848: create/rename refuse a name another driver's stored reference uses, and a rename away from a name the
driver's own references use (`DescribeNameChangeProblemsAsync`).
⚠️ Test Connect/browse configs can carry UNSAVED edits: the claimed owner counts only when every endpoint value
(`DriverCredentialRules.EndpointFields`) is one that driver stores (`EffectiveOwnerAsync`, server-side) — a new
credential-sending driver must declare its endpoint keys there. Credential-carrying Test Connect/browse is audited
+19 -4
View File
@@ -1445,6 +1445,17 @@ form or starts with it followed by `_` (so `PLANTB` names `env:OTOPCUA_GALAXY_PL
for secrets, any match against another instance wins — use the id form (`env:OTOPCUA_GALAXY_DRV_1A2B_KEY`) for
per-instance variables. Shared variables that start with no instance's id or name (`GALAXY_MXGW_API_KEY`) keep working.
- **Id-form references are matched by id only.** A reference whose instance part has the shape of a system-generated
id — `secret:…/DRV-<12 hex>/…` or `env:<PREFIX>DRV_<12 HEX>` alone or followed by `_` — is never matched against
driver **names**, so a driver named `drv` (env form `DRV`), or one named like another's id, cannot make every
sibling's id-form variable "another instance's", whether that name was created before or after this rule. New names
of that form are refused outright at create / rename / modal update (`DriverCredentialPolicy.IsReservedInstanceName`:
env form `DRV` or starting with `DRV_<12 HEX>`).
- **Name-form variables are only reliable for ASCII letter/digit names.** Normalisation turns every other character —
including non-ASCII letters — into `_`, so `Linie Süd` and `Linie S_d` share `LINIE_S_D`, and a name with no ASCII
letter or digit at all normalises to empty and gets **no** name protection (only its id does). Use the id form for
per-instance variables.
Rules worth knowing:
- **A match against another instance wins over a match against the owner.** Names are unique per folder, not
@@ -1512,10 +1523,14 @@ re-checked against stored references except when they change.
Residuals (accepted): a **deleted** driver's id and name stop protecting its secrets and variables — after the delete
any driver may reference `secret:galaxy/<deleted-id>/…` — so remove (or rotate) a deleted driver's secrets with it. The
#848 rename pin can be side-stepped by a Designer who first **saves** an edit to the victim driver dropping its
name-scoped reference, renames it, and then uses the freed name; that is the same "may author the victim's config ⇒ may
redirect it" property as a saved endpoint change below (each step is a persisted, visible draft change, and the
credential use is audited) — use id-scoped references where this matters. A variable is node-wide, so the `env:` rule
#848 rename pin does not stop a Designer who may edit the victim driver: a **single** config-modal save can move (or
drop) its name-scoped reference and rename it in the same commit, after which the old name is free for any driver. That
is the same "may author the victim's config ⇒ may redirect it" property as a saved endpoint change below (the save is a
persisted, visible draft change, and the later credential use is audited) — use id-scoped references where this
matters. For the same reason a low-severity race is accepted: a rename and a **concurrent** device save that adds a
reference to the old name are not tied together (the driver's `RowVersion` does not cover its device rows), so both can
commit and leave a device reference named after a name the driver no longer has — again needs a Designer who may author that driver's
config, and audited at use. A variable is node-wide, so the `env:` rule
constrains which driver may *name* it, not who can read the process environment. A reference to a
**shared** name (one no instance is called) is not tied to any owner, so an unsaved endpoint can still be Test-Connected
with it (audited); and a Designer who **saves** a new endpoint on an existing driver can then Test Connect / browse /