diff --git a/code-reviews/IntegrationTests/findings.md b/code-reviews/IntegrationTests/findings.md index d631476..942c301 100644 --- a/code-reviews/IntegrationTests/findings.md +++ b/code-reviews/IntegrationTests/findings.md @@ -7,7 +7,7 @@ | Review date | 2026-05-18 | | Commit reviewed | `6c64030` | | Status | Reviewed | -| Open findings | 10 | +| Open findings | 8 | ## Checklist coverage @@ -33,13 +33,13 @@ | Severity | High | | Category | Design-document adherence | | Location | `src/MxGateway.IntegrationTests/Galaxy/LiveGalaxyRepositoryFactAttribute.cs:7`, `src/MxGateway.IntegrationTests/Galaxy/GalaxyRepositoryLiveTests.cs` | -| Status | Open | +| Status | Resolved | **Description:** The Galaxy Repository live test suite and its gating env var `MXGATEWAY_RUN_LIVE_GALAXY_TESTS` (plus connection-string override `MXGATEWAY_LIVE_GALAXY_CONN`) are completely absent from `docs/GatewayTesting.md`. CLAUDE.md mandates updating docs in the same change as the source. The opt-in matrix documents only the MXAccess and LDAP env vars, so an operator running the documented matrix has no way to know these tests exist or how to enable them. **Recommendation:** Add a "Live Galaxy Repository" section to `docs/GatewayTesting.md` documenting `MXGATEWAY_RUN_LIVE_GALAXY_TESTS=1`, `MXGATEWAY_LIVE_GALAXY_CONN`, the `ZB` database prerequisite, and the covered RPCs, mirroring the existing "Live MXAccess Smoke" section. -**Resolution:** _(open)_ +**Resolution:** Resolved 2026-05-18: Added a "Live Galaxy Repository" section to `docs/GatewayTesting.md` documenting `MXGATEWAY_RUN_LIVE_GALAXY_TESTS`, `MXGATEWAY_LIVE_GALAXY_CONN`, the deployed-`ZB` prerequisite, and the covered `GalaxyRepository` RPCs. ### IntegrationTests-002 @@ -48,13 +48,13 @@ | Severity | High | | Category | Design-document adherence | | Location | `src/MxGateway.IntegrationTests/DashboardLdapLiveTests.cs:13`, `src/MxGateway.Server/Configuration/LdapOptions.cs:27` | -| Status | Open | +| Status | Resolved | **Description:** `DashboardLdapLiveTests` builds the authenticator with `new GatewayOptions()`, so it relies on `LdapOptions.RequiredGroup` defaulting to `GwAdmin` and asserts the `admin` user is a member of a `GwAdmin` LDAP group. `glauth.md` does not list `GwAdmin` as a provisioned group — it lists `admin` only in the five role groups and describes `GwAdmin` as a group to add "when reuse isn't enough." If GLAuth has only the documented baseline groups, `AuthenticateAsync_AdminInGwAdminGroup_Succeeds` fails (not skips) on any box where the env var is set. This is an undocumented hard prerequisite beyond "LDAP is up." **Recommendation:** Either document the required `GwAdmin` GLAuth provisioning step in `glauth.md` and `GatewayTesting.md`, or have the test set `RequiredGroup` to a baseline group `glauth.md` guarantees `admin` belongs to (e.g. `WriteOperate`). -**Resolution:** _(open)_ +**Resolution:** Resolved 2026-05-18: Took the documentation fix — promoted the `glauth.md` "Adding a gw-specific group" section into a concrete "Provisioning the GwAdmin group" step that grants `GwAdmin` to `admin`, cross-referenced it from the groups/verification sections, and added a "Live LDAP" section to `docs/GatewayTesting.md` calling out `GwAdmin` as a hard prerequisite. Alternative considered: weaken the test to a baseline group (`WriteOperate`) — rejected because `GwAdmin` is the real default `LdapOptions.RequiredGroup` and the test should exercise it. ### IntegrationTests-003 diff --git a/docs/GatewayTesting.md b/docs/GatewayTesting.md index f7c83ce..ad13863 100644 --- a/docs/GatewayTesting.md +++ b/docs/GatewayTesting.md @@ -74,6 +74,58 @@ The test output includes session id, worker process id, command status, HRESULT/status diagnostics, event sequence and handles, close status, and worker stdout/stderr lines emitted during the run. +## Live Galaxy Repository + +`GalaxyRepositoryLiveTests` in `src/MxGateway.IntegrationTests/Galaxy/` exercises +`GalaxyRepository` directly against the `ZB` Galaxy Repository SQL database. It is +skipped unless `MXGATEWAY_RUN_LIVE_GALAXY_TESTS=1` is set because it depends on a +reachable SQL Server instance and deployed Galaxy state — fake-worker tests cannot +cover the SQL browse RPCs. + +The suite covers `TestConnectionAsync`, `GetLastDeployTimeAsync`, +`GetHierarchyAsync`, and `GetAttributesAsync`. `GetHierarchyAsync` and +`GetAttributesAsync` assert a non-empty result, so the connected `ZB` database +must contain a deployed Galaxy, not just an empty schema. + +Run the Galaxy live tests explicitly: + +```bash +$env:MXGATEWAY_RUN_LIVE_GALAXY_TESTS = "1" +dotnet test src/MxGateway.IntegrationTests/MxGateway.IntegrationTests.csproj --filter FullyQualifiedName~GalaxyRepositoryLiveTests +``` + +Optional live Galaxy variables: + +| Variable | Default | Description | +|----------|---------|-------------| +| `MXGATEWAY_LIVE_GALAXY_CONN` | `Server=localhost;Database=ZB;Integrated Security=True;TrustServerCertificate=True;Encrypt=False;` | Galaxy Repository connection string. Set this when the `ZB` database is on a non-default instance or needs SQL authentication. | + +The default connection string targets `ZB` on `localhost` with Windows +authentication, which matches the Galaxy Repository conventions in CLAUDE.md. + +## Live LDAP + +`DashboardLdapLiveTests` in `src/MxGateway.IntegrationTests/` exercises +`DashboardAuthenticator` against the live GLAuth directory. It is skipped unless +`MXGATEWAY_RUN_LIVE_LDAP_TESTS=1` is set because it binds against the GLAuth +service described in `glauth.md`. + +The suite builds the authenticator with a default `GatewayOptions`, so +`LdapOptions.RequiredGroup` keeps its `GwAdmin` default. `GwAdmin` is the +gateway-specific dashboard-admin role and is **not** part of the five baseline +GLAuth role groups — it must be provisioned before the LDAP live tests pass. +`AuthenticateAsync_AdminInGwAdminGroup_Succeeds` fails (rather than skips) when +GLAuth has only the baseline groups, so this is a hard prerequisite beyond "LDAP +is up." See the "Adding a gw-specific group" section of `glauth.md` for the +provisioning step that adds `GwAdmin` and grants it to `admin`. + +Run the LDAP live tests explicitly: + +```bash +$env:MXGATEWAY_RUN_LIVE_LDAP_TESTS = "1" +dotnet test src/MxGateway.IntegrationTests/MxGateway.IntegrationTests.csproj --filter FullyQualifiedName~DashboardLdapLiveTests +``` + ## Client E2E Scripts `scripts/discover-testmachine-tags.ps1` queries the ZB Galaxy Repository for the diff --git a/glauth.md b/glauth.md index 165ba42..9ade93a 100644 --- a/glauth.md +++ b/glauth.md @@ -59,6 +59,14 @@ For mxaccessgw dev, `admin` covers every gw-side capability test; `readonly` is the right "negative" case for proving Browse-OK / Write-denied. +The gateway dashboard adds one role beyond this LmxOpcUa taxonomy: +`GwAdmin`. `LdapOptions.RequiredGroup` defaults to `GwAdmin`, so the +dashboard login and `DashboardLdapLiveTests` require `admin` to be a +member of a `GwAdmin` group. `GwAdmin` is **not** in the baseline +GLAuth config — it must be provisioned before dashboard authn or the +LDAP live tests work. See [Provisioning the GwAdmin +group](#provisioning-the-gwadmin-group) below. + ## Two bind patterns ### 1. Direct bind (simplest) @@ -127,14 +135,18 @@ ldap: should strip the leading `ou=` (or `cn=` against AD) RDN value and look that up in `groupToRole`. -## Adding a gw-specific group (when reuse isn't enough) +## Provisioning the GwAdmin group -If mxaccessgw needs a permission that doesn't fit the existing five -roles (e.g. `GwAdmin` for shutdown/recycle commands), add it to -GLAuth rather than running a separate LDAP server: +`GwAdmin` is the gateway-specific dashboard-admin role. It is the +default `LdapOptions.RequiredGroup`, so the dashboard cookie login and +`DashboardLdapLiveTests` (`MXGATEWAY_RUN_LIVE_LDAP_TESTS=1`) reject +`admin` until a `GwAdmin` group exists and `admin` is a member. +GLAuth's baseline config ships only the five LmxOpcUa role groups, so +`GwAdmin` must be added to GLAuth rather than run from a separate LDAP +server: 1. Edit `C:\publish\glauth\glauth.cfg` -2. Append: +2. Append the group: ```toml [[groups]] @@ -142,8 +154,9 @@ GLAuth rather than running a separate LDAP server: gidnumber = 5510 # pick the next free GID ``` -3. Add the group to whichever existing user(s) should have it via - `othergroups = [..., 5510]`. Or create a new user: +3. Add `5510` to `admin`'s `othergroups` list so `admin` resolves the + `GwAdmin` role. Add it to any other user that needs dashboard-admin + rights. Or create a dedicated user: ```toml [[users]] @@ -158,6 +171,12 @@ GLAuth rather than running a separate LDAP server: 4. `nssm restart GLAuth` +After the restart, `admin`'s `memberOf` includes +`ou=GwAdmin,ou=groups,dc=lmxopcua,dc=local`, which the authenticator +strips to `GwAdmin` and matches against `RequiredGroup`. The same +pattern applies to any future permission that doesn't fit the existing +five roles. + Generate `passsha256` from a plaintext password: ```powershell @@ -196,7 +215,8 @@ ldapsearch -x -H ldap://localhost:3893 \ ``` The response should list `admin`'s entry with `memberOf` populated for -all five role groups. +all five role groups — plus `GwAdmin` once the gateway-specific group +is provisioned. ## Service management