docs(code-review): record SMS-feature review findings + reconcile NotificationService doc
Per-module code review of the SMS notifications feature (reviewed at d6ead8ae) following
code-reviews/REVIEW-PROCESS.md. 19 findings across 7 modules — 1 High, 5 Medium, 13 Low:
- ManagementService-024 (High): provider-config updates Admin-gated to match the UI.
- ConfigurationDatabase-025, CentralUI-034/035, ManagementService-025 (Medium): migration
data-safety guard, type-aware recipient badge, FromNumber-optional (Messaging-Service-only),
empty-token-clear guard.
- Remaining Low: secret-encryption + diff + dispatch + factory + contract tests, truncation,
ctor guard, reserved retry-field docs.
- Won't Fix: Transport-015/016 (shared repo-wide import patterns, not SMS-specific),
Commons-026 (breaking ergonomics-only change). Deferred: ConfigurationDatabase-027 (live-SQL
migration test).
All findings closed (0 pending). README.md regenerated; Component-NotificationService.md
updated for the FromNumber-optional + reserved-retry-fields outcomes.
This commit is contained in:
@@ -5,9 +5,9 @@
|
||||
| Module | `src/ZB.MOM.WW.ScadaBridge.ManagementService` |
|
||||
| Design doc | `docs/requirements/Component-ManagementService.md` |
|
||||
| Status | Reviewed |
|
||||
| Last reviewed | 2026-05-28 |
|
||||
| Last reviewed | 2026-06-19 |
|
||||
| Reviewer | claude-agent |
|
||||
| Commit reviewed | `1eb6e97` |
|
||||
| Commit reviewed | `d6ead8ae` |
|
||||
| Open findings | 0 (1 Deferred — see ManagementService-012) |
|
||||
|
||||
## Summary
|
||||
@@ -1131,3 +1131,88 @@ entirely.
|
||||
|
||||
Defer until a noticeable hot path emerges, but track it: this is the only N+1 in
|
||||
`ManagementActor` once 002 / 014 are folded in.
|
||||
|
||||
#### Re-review 2026-06-19 (commit `d6ead8ae`) — SMS notifications feature
|
||||
|
||||
Per-module review of the `ManagementActor` SMS surface: the SMS/SMTP provider-config command gating,
|
||||
`HandleUpdateSmsConfig`, and the `SmsConfigPublicShape` secret projection. The secret-redaction chain
|
||||
(`SmsConfigPublicShape` exposes `HasAuthToken` only; the AuthToken never reaches the response or audit
|
||||
afterState) is correct and tested. One High authorization finding, one Medium secret-clear footgun, one
|
||||
Low stale comment; all Resolved.
|
||||
|
||||
### ManagementService-024 — SMS/SMTP provider-config updates were Designer-gated despite Admin-only UI
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| Severity | High |
|
||||
| Category | Security |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs:189-190` |
|
||||
|
||||
**Description**
|
||||
|
||||
`UpdateSmsConfigCommand` (and the pre-existing `UpdateSmtpConfigCommand`) were placed in the Designer
|
||||
arm of `GetRequiredRole`, but both the `/notifications/sms` and `/notifications/smtp` Central UI pages
|
||||
enforce `RequireAdmin`. This split-brain let a Designer who is blocked in the UI still rotate a
|
||||
production credential (the Twilio Auth Token / SMTP password) via the CLI / Management API. The design
|
||||
(D8) specifies SMS config management as Admin-only.
|
||||
|
||||
**Recommendation**
|
||||
|
||||
Move `UpdateSmsConfigCommand` (and `UpdateSmtpConfigCommand`, whose UI page is also RequireAdmin) to the
|
||||
Administrator arm so the actor gate matches the UI.
|
||||
|
||||
**Resolution**
|
||||
|
||||
Resolved 2026-06-19 (commit `cd8e4872`): both update commands moved to the Administrator arm. Locked by
|
||||
`UpdateSmsConfig_WithDesignerRole_ReturnsUnauthorized` and updated success-case tests (commit `a9393c89`).
|
||||
|
||||
### ManagementService-025 — Empty-string `--auth-token` silently clears the stored Twilio token
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| Severity | Medium |
|
||||
| Category | Security |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs:1859` |
|
||||
|
||||
**Description**
|
||||
|
||||
`HandleUpdateSmsConfig` used `if (cmd.AuthToken is not null)` for preserve-if-omitted. An explicit empty
|
||||
/ whitespace `--auth-token ""` passes the null check and overwrites the stored token with empty, silently
|
||||
clearing the credential and 401-ing every subsequent send. A Twilio Auth Token is always required, so an
|
||||
empty value is never a valid rotation.
|
||||
|
||||
**Recommendation**
|
||||
|
||||
Guard on `IsNullOrWhiteSpace` so an empty token is treated as omitted (preserve). (SMTP `Credentials`
|
||||
keeps its null-only guard, since empty may be valid for anonymous SMTP.)
|
||||
|
||||
**Resolution**
|
||||
|
||||
Resolved 2026-06-19 (commit `cd8e4872`): the guard is now `!string.IsNullOrWhiteSpace(cmd.AuthToken)`.
|
||||
Locked by `UpdateSmsConfig_WithEmptyAuthToken_PreservesExistingToken` (commit `a9393c89`).
|
||||
|
||||
### ManagementService-026 — Stale "Admin-only" comment on `HandleListSmtpConfigs`
|
||||
|
||||
| | |
|
||||
|--|--|
|
||||
| Severity | Low |
|
||||
| Category | Documentation & comments |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.ManagementService/ManagementActor.cs:1788-1790` |
|
||||
|
||||
**Description**
|
||||
|
||||
The comment on `HandleListSmtpConfigs` called the `UpdateSmtpConfig` path "Admin-only", which did not
|
||||
match its (then) Designer gating; the SMS counterpart comment said "Designer-gated". The two were
|
||||
inconsistent.
|
||||
|
||||
**Recommendation**
|
||||
|
||||
Make the comments accurate after fixing the gating.
|
||||
|
||||
**Resolution**
|
||||
|
||||
Resolved 2026-06-19 (commit `cd8e4872`): with both update commands moved to Administrator (MS-024), the
|
||||
SMTP "Admin-only" comment is now accurate and the SMS list comment was updated to "Admin-only".
|
||||
|
||||
Reference in New Issue
Block a user