docs(audit): apply global term/path substitutions across living docs
This commit is contained in:
@@ -19,7 +19,7 @@ The worker must do all MXAccess COM calls on its dedicated STA thread, and the S
|
||||
|
||||
```powershell
|
||||
# Full solution build (gateway, worker, contracts, tests)
|
||||
dotnet build src/MxGateway.sln
|
||||
dotnet build src/ZB.MOM.WW.MxGateway.slnx
|
||||
|
||||
# Worker must be built x86 — the gateway looks for MxGateway.Worker.exe under bin\x86
|
||||
dotnet build src/MxGateway.Worker/MxGateway.Worker.csproj -p:Platform=x86
|
||||
@@ -29,10 +29,10 @@ dotnet test src/MxGateway.Tests/MxGateway.Tests.csproj
|
||||
dotnet test src/MxGateway.Worker.Tests/MxGateway.Worker.Tests.csproj -p:Platform=x86
|
||||
|
||||
# Run gateway locally (defaults bound under MxGateway:* in src/MxGateway.Server/appsettings.json)
|
||||
dotnet run --project src/MxGateway.Server/MxGateway.Server.csproj
|
||||
dotnet run --project src/ZB.MOM.WW.MxGateway.Server/ZB.MOM.WW.MxGateway.Server.csproj
|
||||
|
||||
# API-key admin CLI (same exe, "apikey" subcommand)
|
||||
dotnet run --project src/MxGateway.Server/MxGateway.Server.csproj -- apikey create --display-name "dev" --scopes session,invoke,event,metadata,admin
|
||||
dotnet run --project src/ZB.MOM.WW.MxGateway.Server/ZB.MOM.WW.MxGateway.Server.csproj -- apikey create --display-name "dev" --scopes session,invoke,event,metadata,admin
|
||||
```
|
||||
|
||||
Single test by name (xUnit `--filter`):
|
||||
@@ -54,7 +54,7 @@ Live LDAP tests use `MXGATEWAY_RUN_LIVE_LDAP_TESTS=1`. See `docs/GatewayTesting.
|
||||
|
||||
Each language client is in `clients/<lang>/` with its own README. They all consume the shared `.proto` files in `src/MxGateway.Contracts/Protos`:
|
||||
|
||||
- `clients/dotnet`: `dotnet build clients/dotnet/MxGateway.Client.sln`
|
||||
- `clients/dotnet`: `dotnet build clients/dotnet/ZB.MOM.WW.MxGateway.Client.slnx`
|
||||
- `clients/python`: `python -m pip install -e ".[dev]"; python -m pytest`
|
||||
- `clients/rust`: `cargo test --workspace; cargo clippy --workspace --all-targets -- -D warnings`
|
||||
- `clients/java`: `gradle test` (Java 21)
|
||||
@@ -90,7 +90,7 @@ When source code changes, build and test the affected component before reporting
|
||||
| Contracts or `.proto` files | regenerate generated code, then build gateway, worker, and every generated client touched by the contract |
|
||||
| Gateway server, sessions, workers, gRPC, dashboard, metrics | `dotnet build src/MxGateway.Server` and run affected gateway / fake-worker tests |
|
||||
| Worker IPC, STA, MXAccess, conversion | `dotnet build src/MxGateway.Worker -p:Platform=x86` and run worker tests |
|
||||
| .NET client | `dotnet build clients/dotnet/MxGateway.Client.sln` and run its tests |
|
||||
| .NET client | `dotnet build clients/dotnet/ZB.MOM.WW.MxGateway.Client.slnx` and run its tests |
|
||||
| Go client | `gofmt`, `go build ./...`, `go test ./...` from `clients/go` |
|
||||
| Rust client | `cargo fmt`, `cargo check --workspace`, `cargo test --workspace`, `cargo clippy --all-targets -- -D warnings` from `clients/rust` |
|
||||
| Python client | `python -m pytest` from `clients/python` |
|
||||
@@ -116,7 +116,7 @@ External analysis sources referenced by design docs:
|
||||
|
||||
Gateway gRPC clients authenticate with an API key in metadata: `authorization: Bearer mxgw_<key-id>_<secret>`. Keys are stored hashed (with a peppered SHA) in a gateway-owned SQLite DB (default `C:\ProgramData\MxGateway\gateway-auth.db`). Scopes (`session`, `invoke`, `event`, `metadata`, `admin`) gate specific RPCs; missing → `Unauthenticated`, insufficient → `PermissionDenied`. The `apikey` subcommand on the server exe manages keys; see `src/MxGateway.Server/Security/Authentication/`.
|
||||
|
||||
Dashboard auth is LDAP-backed (separate from the gRPC API-key model). `/login` binds against `MxGateway:Ldap` and maps the user's LDAP groups to `Admin` or `Viewer` via `MxGateway:Dashboard:GroupToRole`, then issues an HTTP-only secure `__Host-MxGatewayDashboard` cookie. SignalR hubs at `/hubs/{snapshot,alarms,events}` accept either the cookie or a 30-minute bearer minted at `/hubs/token`. `Dashboard:AllowAnonymousLocalhost` bypasses auth on loopback when enabled.
|
||||
Dashboard auth is LDAP-backed (separate from the gRPC API-key model). `/login` binds against `MxGateway:Ldap` and maps the user's LDAP groups to `Administrator` or `Viewer` via `MxGateway:Dashboard:GroupToRole`, then issues an HTTP-only secure `MxGatewayDashboard` cookie. SignalR hubs at `/hubs/{snapshot,alarms,events}` accept either the cookie or a 30-minute bearer minted at `/hubs/token`. `Dashboard:AllowAnonymousLocalhost` bypasses auth on loopback when enabled.
|
||||
|
||||
## Process / Platform Notes
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ Use bounded smoke flow and always attempt `close_session` in `finally`.
|
||||
Use `pyproject.toml`. Publishable package name should be stable, for example:
|
||||
|
||||
```text
|
||||
mxaccess-gateway-client
|
||||
zb-mom-ww-mxaccess-gateway-client
|
||||
```
|
||||
|
||||
Generated protobuf code should be regenerated through a documented command, not
|
||||
|
||||
@@ -407,7 +407,7 @@ The stable client proto manifest defines the generated-code directories:
|
||||
clients/dotnet/generated
|
||||
clients/go/internal/generated
|
||||
clients/rust/src/generated
|
||||
clients/python/src/mxgateway/generated
|
||||
clients/python/src/zb_mom_ww_mxgateway/generated
|
||||
clients/java/src/main/generated
|
||||
```
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ Pop-Location
|
||||
|
||||
## Rust
|
||||
|
||||
The Rust workspace builds the `mxgateway-client` library crate and the `mxgw`
|
||||
The Rust workspace builds the `zb-mom-ww-mxgateway-client` library crate and the `mxgw`
|
||||
CLI crate. `build.rs` generates `tonic` and `prost` modules into Cargo build
|
||||
output on each build that needs updated protobuf output.
|
||||
|
||||
@@ -156,8 +156,8 @@ Pop-Location
|
||||
|
||||
## Python
|
||||
|
||||
The Python package is `mxaccess-gateway-client`. Generated modules live under
|
||||
`clients/python/src/mxgateway/generated`.
|
||||
The Python package is `zb-mom-ww-mxaccess-gateway-client`. Generated modules live under
|
||||
`clients/python/src/zb_mom_ww_mxgateway/generated`.
|
||||
|
||||
Regenerate the Python bindings:
|
||||
|
||||
@@ -184,7 +184,7 @@ Push-Location clients/python
|
||||
mxgw-py version --json
|
||||
mxgw-py smoke --endpoint $env:MXGATEWAY_ENDPOINT --plaintext --api-key-env MXGATEWAY_API_KEY --item $env:MXGATEWAY_TEST_ITEM --json
|
||||
mxgw-py smoke --endpoint mxgateway.example.local:5001 --tls --ca-file C:\certs\mxgateway-ca.pem --server-name-override mxgateway.example.local --api-key-env MXGATEWAY_API_KEY --item $env:MXGATEWAY_TEST_ITEM --json
|
||||
python -m mxgateway_cli version --json
|
||||
python -m zb_mom_ww_mxgateway_cli version --json
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
@@ -198,7 +198,7 @@ Regenerate Java bindings:
|
||||
|
||||
```powershell
|
||||
Push-Location clients/java
|
||||
gradle :mxgateway-client:generateProto
|
||||
gradle :zb-mom-ww-mxgateway-client:generateProto
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
@@ -214,7 +214,7 @@ Create local library and CLI artifacts:
|
||||
|
||||
```powershell
|
||||
Push-Location clients/java
|
||||
gradle :mxgateway-client:jar :mxgateway-cli:installDist
|
||||
gradle :zb-mom-ww-mxgateway-client:jar :zb-mom-ww-mxgateway-cli:installDist
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
@@ -222,9 +222,9 @@ Run the CLI through Gradle:
|
||||
|
||||
```powershell
|
||||
Push-Location clients/java
|
||||
gradle :mxgateway-cli:run --args="version --json"
|
||||
gradle :mxgateway-cli:run --args="smoke --endpoint $env:MXGATEWAY_ENDPOINT --plaintext --api-key-env MXGATEWAY_API_KEY --item $env:MXGATEWAY_TEST_ITEM --json"
|
||||
gradle :mxgateway-cli:run --args="smoke --endpoint mxgateway.example.local:5001 --ca-file C:\certs\mxgateway-ca.pem --server-name-override mxgateway.example.local --api-key-env MXGATEWAY_API_KEY --item $env:MXGATEWAY_TEST_ITEM --json"
|
||||
gradle :zb-mom-ww-mxgateway-cli:run --args="version --json"
|
||||
gradle :zb-mom-ww-mxgateway-cli:run --args="smoke --endpoint $env:MXGATEWAY_ENDPOINT --plaintext --api-key-env MXGATEWAY_API_KEY --item $env:MXGATEWAY_TEST_ITEM --json"
|
||||
gradle :zb-mom-ww-mxgateway-cli:run --args="smoke --endpoint mxgateway.example.local:5001 --ca-file C:\certs\mxgateway-ca.pem --server-name-override mxgateway.example.local --api-key-env MXGATEWAY_API_KEY --item $env:MXGATEWAY_TEST_ITEM --json"
|
||||
Pop-Location
|
||||
```
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ The manifest declares these generated-code directories:
|
||||
| .NET | `clients/dotnet/generated` |
|
||||
| Go | `clients/go/internal/generated` |
|
||||
| Rust | `clients/rust/src/generated` |
|
||||
| Python | `clients/python/src/mxgateway/generated` |
|
||||
| Python | `clients/python/src/zb_mom_ww_mxgateway/generated` |
|
||||
| Java | `clients/java/src/main/generated` |
|
||||
|
||||
Only generator output belongs in these directories. Handwritten client wrappers
|
||||
@@ -142,7 +142,7 @@ cargo check --workspace
|
||||
```
|
||||
|
||||
Python clients should use `grpc_tools.protoc` and write generated modules under
|
||||
`clients/python/src/mxgateway/generated` so imports stay separate from
|
||||
`clients/python/src/zb_mom_ww_mxgateway/generated` so imports stay separate from
|
||||
handwritten async wrappers.
|
||||
|
||||
The Python scaffold provides a repo-local generation script:
|
||||
|
||||
@@ -288,7 +288,7 @@ Use this checklist when applying the design to another project:
|
||||
- Use top-bordered sections for page groups instead of nested cards.
|
||||
- Centralize formatting and redaction outside Razor markup.
|
||||
- Hide every destructive admin affordance from viewers; render it only for
|
||||
the `Admin` role and re-check the role server-side on every invocation.
|
||||
the `Administrator` role and re-check the role server-side on every invocation.
|
||||
- Route every destructive action (Close session, Kill worker, Rotate /
|
||||
Revoke / Delete API key) through the shared `ConfirmDialog` component so
|
||||
the operator always gets one explicit confirmation step before the call
|
||||
|
||||
+2
-2
@@ -162,7 +162,7 @@ public static IApplicationBuilder UseGatewayRequestLoggingScope(this IApplicatio
|
||||
{
|
||||
ILogger logger = context.RequestServices
|
||||
.GetRequiredService<ILoggerFactory>()
|
||||
.CreateLogger("ZB.MOM.WW.MxGateway.Request");
|
||||
.CreateLogger("MxGateway.Request");
|
||||
|
||||
using IDisposable? scope = logger.BeginGatewayScope(new GatewayLogScope(
|
||||
SessionId: ReadHeader(context, SessionIdHeaderName),
|
||||
@@ -188,7 +188,7 @@ The scope is keyed off four custom headers and the standard `authorization` head
|
||||
|
||||
The numeric headers use `int.TryParse` and `ulong.TryParse`; missing or unparseable values become `null` and are dropped by `GatewayLogScope.ToDictionary`. This keeps the middleware tolerant of clients that do not yet emit every header, which matters because the earliest call in a session (`OpenSession`) has no `SessionId` to send.
|
||||
|
||||
The logger category is `ZB.MOM.WW.MxGateway.Request`, which lets operators filter the request scope events independently from per-component categories.
|
||||
The logger category is `MxGateway.Request`, which lets operators filter the request scope events independently from per-component categories.
|
||||
|
||||
### Pipeline ordering
|
||||
|
||||
|
||||
@@ -419,17 +419,17 @@ embedded in the status detail.
|
||||
|
||||
The gateway's Blazor dashboard surfaces a Galaxy summary in two places:
|
||||
|
||||
- An overview card on `/dashboard` showing connectivity status, last deploy
|
||||
- An overview card on `/` showing connectivity status, last deploy
|
||||
timestamp, object count (with area count), attribute total, historized and
|
||||
alarm counts, and last successful refresh.
|
||||
- A dedicated `/dashboard/galaxy` page with object-category and top-template
|
||||
- A dedicated `/galaxy` page with object-category and top-template
|
||||
breakdowns plus a Sync Info table covering last successful refresh, last
|
||||
attempt, refresh interval, redacted connection string, and command timeout.
|
||||
|
||||
Both views are projected from the same `IGalaxyHierarchyCache` that backs the
|
||||
gRPC service. The dashboard does not run its own refresh — when the
|
||||
background `GalaxyHierarchyRefreshService` updates the cache, both the
|
||||
overview card and the `/dashboard/galaxy` page pick up the new state on the
|
||||
overview card and the `/galaxy` page pick up the new state on the
|
||||
next dashboard tick. When SQL is unreachable, the cache retains the previous
|
||||
data and flips `Status` to `Stale` or `Unavailable`; the dashboard surfaces
|
||||
that as a yellow or red status badge plus the truncated error.
|
||||
|
||||
@@ -52,7 +52,7 @@ paths, timeouts, queue sizes, enum values, or protocol values are invalid.
|
||||
"RecentSessionLimit": 200,
|
||||
"ShowTagValues": false,
|
||||
"GroupToRole": {
|
||||
"GwAdmin": "Admin",
|
||||
"GwAdmin": "Administrator",
|
||||
"GwReader": "Viewer"
|
||||
}
|
||||
},
|
||||
@@ -153,7 +153,7 @@ the affected stream while the MXAccess session remains active.
|
||||
| `MxGateway:Dashboard:RecentFaultLimit` | `100` | Maximum number of fault summaries projected into each dashboard snapshot. |
|
||||
| `MxGateway:Dashboard:RecentSessionLimit` | `200` | Maximum number of session summaries projected into each dashboard snapshot. |
|
||||
| `MxGateway:Dashboard:ShowTagValues` | `false` | Reserved display control for tag values. The dashboard does not show full tag values by default. |
|
||||
| `MxGateway:Dashboard:GroupToRole` | _(empty)_ | LDAP group → dashboard role mapping. Keys are LDAP group names (short CN or full DN — leading-RDN match). Values must be `Admin` (read/write, API-key CRUD) or `Viewer` (read-only). A user whose LDAP groups don't intersect this map cannot sign in; with no mapping at all, only the loopback bypass admits anyone. |
|
||||
| `MxGateway:Dashboard:GroupToRole` | _(empty)_ | LDAP group → dashboard role mapping. Keys are LDAP group names (short CN or full DN — leading-RDN match). Values must be `Administrator` (read/write, API-key CRUD) or `Viewer` (read-only). A user whose LDAP groups don't intersect this map cannot sign in; with no mapping at all, only the loopback bypass admits anyone. |
|
||||
|
||||
`SnapshotIntervalMilliseconds` must be greater than zero. `RecentFaultLimit`
|
||||
and `RecentSessionLimit` must be greater than or equal to zero.
|
||||
@@ -166,10 +166,10 @@ users) but practical deployments populate at least one Admin group.
|
||||
Three authorization policies are registered out of these options:
|
||||
|
||||
- `MxGateway.Dashboard.Viewer` — gates the Razor component routes. Satisfied by
|
||||
either dashboard role (Admin or Viewer), by `AllowAnonymousLocalhost` on
|
||||
either dashboard role (Administrator or Viewer), by `AllowAnonymousLocalhost` on
|
||||
loopback, or by `Authentication.Mode = Disabled`.
|
||||
- `MxGateway.Dashboard.Admin` — gates write-capable surfaces (API-key CRUD).
|
||||
Satisfied only by the Admin role (same environmental bypasses).
|
||||
Satisfied only by the Administrator role (same environmental bypasses).
|
||||
- `MxGateway.Dashboard.HubClients` — attached to the SignalR hubs. Accepts
|
||||
either the dashboard cookie scheme or the `MxGateway.Dashboard.HubToken`
|
||||
bearer scheme (used by SignalR's WebSocket upgrade path where the HttpOnly
|
||||
|
||||
@@ -288,7 +288,7 @@ it opt-in and redacted.
|
||||
|
||||
### Browse page
|
||||
|
||||
`/dashboard/browse` lets an operator explore the Galaxy tag hierarchy and watch
|
||||
`/browse` lets an operator explore the Galaxy tag hierarchy and watch
|
||||
live values. The tree is built in-process by `DashboardBrowseTreeBuilder` from
|
||||
`IGalaxyHierarchyCache.Current` — the same cache the Galaxy page reads — so a
|
||||
render costs no gRPC call and no SQL round-trip. Each node shows its child
|
||||
@@ -306,7 +306,7 @@ diagnostic session/worker views.
|
||||
|
||||
### Alarms page
|
||||
|
||||
`/dashboard/alarms` lists the alarms the gateway's central alarm monitor
|
||||
`/alarms` lists the alarms the gateway's central alarm monitor
|
||||
currently holds as Active or ActiveAcked, refreshed every three seconds. It
|
||||
defaults to showing unacknowledged `Active` alarms; filters add acknowledged
|
||||
alarms and narrow by area, severity range, and a reference/source/description
|
||||
@@ -335,7 +335,7 @@ the monitor never starts and the cache stays empty.
|
||||
|
||||
### API keys page
|
||||
|
||||
`/dashboard/apikeys` lists the gateway's API keys and, for authorized
|
||||
`/apikeys` lists the gateway's API keys and, for authorized
|
||||
operators, manages them. It reads key metadata through the same
|
||||
`IApiKeyAdminStore` the `apikey` CLI uses, so the dashboard and the CLI act
|
||||
on one source of truth.
|
||||
@@ -421,7 +421,7 @@ Implemented behavior:
|
||||
`ClaimTypes.Role` claims, alongside the per-group `mxgateway:ldap_group`
|
||||
claims;
|
||||
- a successful login signs in the `MxGateway.Dashboard` cookie scheme
|
||||
(`__Host-MxGatewayDashboard`, HttpOnly, SameSite=Strict, Secure);
|
||||
(`MxGatewayDashboard`, HttpOnly, SameSite=Strict, Secure);
|
||||
- a user with no matching group cannot sign in — the login screen returns the
|
||||
generic credential-rejected message;
|
||||
- antiforgery tokens guard the login and logout POSTs.
|
||||
|
||||
@@ -247,12 +247,12 @@ Technology:
|
||||
Suggested routes:
|
||||
|
||||
```text
|
||||
/dashboard
|
||||
/dashboard/sessions
|
||||
/dashboard/sessions/{sessionId}
|
||||
/dashboard/workers
|
||||
/dashboard/events
|
||||
/dashboard/settings
|
||||
/
|
||||
/sessions
|
||||
/sessions/{sessionId}
|
||||
/workers
|
||||
/events
|
||||
/settings
|
||||
```
|
||||
|
||||
Dashboard pages:
|
||||
|
||||
@@ -320,7 +320,7 @@ writes its `{"error":...}` envelope and the loop continues; the harness treats
|
||||
that envelope as the operation failure (used by the parity and auth phases).
|
||||
|
||||
Before the per-client phases run, the script builds the .NET CLI
|
||||
(`dotnet build`) and installs the Java CLI (`gradle :mxgateway-cli:installDist`)
|
||||
(`dotnet build`) and installs the Java CLI (`gradle :zb-mom-ww-mxgateway-cli:installDist`)
|
||||
once, so the `batch` process launches straight from the compiled exe / the
|
||||
installed launcher. The Go, Rust, and Python batch processes are launched via
|
||||
`go run` / `cargo run` / `python -m`, which compile-or-start once when that
|
||||
|
||||
@@ -251,7 +251,7 @@ The loop should update a heartbeat timestamp after:
|
||||
- processing an MXAccess event.
|
||||
|
||||
`StaRuntime` implements this runtime boundary in the worker. It starts one
|
||||
background thread named `ZB.MOM.WW.MxGateway.Worker.STA`, sets it to `ApartmentState.STA`,
|
||||
background thread named `MxGateway.Worker.STA`, sets it to `ApartmentState.STA`,
|
||||
initializes COM through `StaComApartmentInitializer`, and runs
|
||||
`StaMessagePump`. Commands are scheduled through `InvokeAsync`; the command
|
||||
queue signals an `AutoResetEvent` so `MsgWaitForMultipleObjectsEx` can wake the
|
||||
|
||||
+2
-2
@@ -20,13 +20,13 @@ The installed MXAccess interop assembly declares an `Apartment` threading model
|
||||
|
||||
## STA Thread Initialization
|
||||
|
||||
`StaRuntime`'s constructor configures a background `Thread` named `ZB.MOM.WW.MxGateway.Worker.STA` and forces it into `ApartmentState.STA` before the thread starts. `Start()` releases the thread and then blocks on `startedEvent` so callers observe a fully-initialized apartment (or a captured `startupException`) before the first `InvokeAsync` call:
|
||||
`StaRuntime`'s constructor configures a background `Thread` named `MxGateway.Worker.STA` and forces it into `ApartmentState.STA` before the thread starts. `Start()` releases the thread and then blocks on `startedEvent` so callers observe a fully-initialized apartment (or a captured `startupException`) before the first `InvokeAsync` call:
|
||||
|
||||
```csharp
|
||||
staThread = new Thread(ThreadMain)
|
||||
{
|
||||
IsBackground = true,
|
||||
Name = "ZB.MOM.WW.MxGateway.Worker.STA"
|
||||
Name = "MxGateway.Worker.STA"
|
||||
};
|
||||
staThread.SetApartmentState(ApartmentState.STA);
|
||||
```
|
||||
|
||||
@@ -22,7 +22,7 @@ library, CLI, and tests.
|
||||
|
||||
## Packages
|
||||
|
||||
- Use lowercase package names under `com.dohertylan.mxgateway`.
|
||||
- Use lowercase package names under `com.zb.mom.ww.mxgateway`.
|
||||
- Keep client library code separate from CLI code.
|
||||
- Keep generated protobuf classes in a generated package.
|
||||
- Do not expose implementation-only transport helpers as public API.
|
||||
|
||||
@@ -24,8 +24,8 @@ CLI, and tests.
|
||||
|
||||
## Package Structure
|
||||
|
||||
- Put library code under `src/mxgateway/`.
|
||||
- Put CLI entry points under `src/mxgateway_cli/`.
|
||||
- Put library code under `src/zb_mom_ww_mxgateway/`.
|
||||
- Put CLI entry points under `src/zb_mom_ww_mxgateway_cli/`.
|
||||
- Keep generated protobuf modules under a clearly named `generated` package.
|
||||
- Avoid import side effects that open channels, read environment variables, or
|
||||
start background tasks.
|
||||
|
||||
Reference in New Issue
Block a user