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:
Joseph Doherty
2026-06-19 15:30:32 -04:00
parent 33e1802e6d
commit 4307c38117
9 changed files with 579 additions and 26 deletions
+90 -2
View File
@@ -5,9 +5,9 @@
| Module | `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase` |
| Design doc | `docs/requirements/Component-ConfigurationDatabase.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 |
## Summary
@@ -1373,3 +1373,91 @@ later months. This pins down the resolution of CD-019. (2) Add a
`DeploymentRecord`, clear the change tracker, call `DeleteDeploymentRecordAsync`,
and assert the row is gone — pinning the resolution of CD-018. Both tests should be
`[SkippableFact]` so the suite still passes when no MS SQL Server is available.
#### Re-review 2026-06-19 (commit `d6ead8ae`) — SMS notifications feature
Per-module review of the SMS (Twilio) notifications data layer: the `SmsConfiguration` EF mapping +
encrypted `AuthToken`, the `AddSmsNotifications` migration, and the `NotificationRecipient` nullable
contact change. The encryption wiring (`EncryptedStringConverter` on `AuthToken` via
`ApplySecretColumnEncryption` + `GuardSecretWritesHaveAKeyRing`) mirrors `SmtpConfiguration.Credentials`
and is correct. Two Medium findings (one data-safety, one test gap) and one Low test gap; the two
Mediums are Resolved.
### ConfigurationDatabase-025 — `AddSmsNotifications.Down()` silently corrupts SMS-only recipients
| | |
|--|--|
| Severity | Medium |
| Category | Correctness & logic bugs |
| Status | Resolved |
| Location | `src/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase/Migrations/20260619135543_AddSmsNotifications.cs:52-66` |
**Description**
The `Down()` migration drops the `PhoneNumber` column and backfills every NULL `EmailAddress` to `''`
so the column can revert to NOT NULL. An SMS-only recipient (PhoneNumber set, EmailAddress
legitimately NULL) is therefore corrupted on rollback: its phone is dropped and its email becomes an
invalid empty string. In a database where SMS lists have been created, the rollback destroys contact data.
**Recommendation**
Before dropping `PhoneNumber`, guard the rollback: throw if any SMS-only recipient (PhoneNumber set,
EmailAddress NULL) exists, so the operator must reassign/remove them first instead of losing data silently.
**Resolution**
Resolved 2026-06-19 (commit `cd8e4872`): `Down()` now runs a `THROW`-on-`IF EXISTS` guard for
SMS-only recipients as its first statement (while `PhoneNumber` is still queryable), refusing the
rollback instead of corrupting data. Comments document the invariant.
### ConfigurationDatabase-026 — No encryption-at-rest regression test for `SmsConfiguration.AuthToken`
| | |
|--|--|
| Severity | Medium |
| Category | Testing coverage |
| Status | Resolved |
| Location | `tests/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests/SecretEncryptionTests.cs` |
**Description**
`SecretEncryptionTests` covered the database-connection, SMTP-credentials, and external-system secrets
with "stored-encrypted / raw != plaintext / round-trips" tests, but had no parallel test for the
Twilio `AuthToken`. A refactor dropping `SmsConfiguration` from `ApplySecretColumnEncryption` would go
uncaught.
**Recommendation**
Add `SmsConfiguration_AuthToken_StoredEncrypted_RoundTrips` and a null-round-trip test mirroring the
SMTP shape.
**Resolution**
Resolved 2026-06-19 (commit `a9393c89`): added both tests; the encrypted test also asserts the raw
column is ciphertext and that `AccountSid` stays plaintext.
### ConfigurationDatabase-027 — No MS SQL migration integration test for `AddSmsNotifications`
| | |
|--|--|
| Severity | Low |
| Category | Testing coverage |
| Status | Deferred |
| Location | `tests/ZB.MOM.WW.ScadaBridge.ConfigurationDatabase.Tests/Migrations/` |
**Description**
Prior structural migrations have MS SQL integration tests asserting the resulting columns/types/nullability.
`AddSmsNotifications` (and the follow-up `SmsFromNumberOptional`) have none, so the column shapes and the
idempotency of the `ALTER COLUMN` statements are unverified against a real SQL Server.
**Recommendation**
Add an `AddSmsNotificationsMigrationTests` using the `MsSqlMigrationFixture` pattern.
**Resolution**
Deferred (2026-06-19): the migrations are standard idempotent `ALTER`/guarded-`CREATE` statements
verified by the model snapshot and the build, and `AddSmsNotifications` was applied to the real
docker MS SQL during the feature's integration pass. A live-SQL migration test is tracked for a
future ConfigurationDatabase test-stability pass.