docs(code-review): re-review 17 changed modules at 1f9de8a2 — 8 new findings

Re-reviewed the modules whose source changed since the last review baseline
(full-review remediation fd618cf1 + InboundAPI Database-helper fixes b3c90143),
focused on whether the fixes are sound and regression-free. 9 of 17 modules
clean; 8 new findings (0 Critical, 0 High, 4 Medium, 4 Low), all code-verified
by the orchestrator before recording:

- DataConnectionLayer-029 (Med): DCL-023's unsubscribe-clears-in-flight reopens a
  double-subscribe window that leaks an orphaned alarm feed; the alarm completion
  handler overwrites the subscription id without the tag-path guard at line 908.
- InboundAPI-031 (Med): WaitForAttribute's 5s grace backstop is tighter than the
  CommunicationService Ask's timeout+IntegrationTimeout (30s) round-trip slack, so
  a slow-but-valid timed-out 'false' arriving in the 5-30s window is cancelled into
  an unhandled OperationCanceledException/500 (contradicts spec 6 + its own comment).
- SiteRuntime-032 (Med): SiteRuntime-029's wasPresent guard skips the deployed-count
  decrement when deleting a DISABLED instance (absent from both maps), drifting the
  health-dashboard tally; self-heals on singleton restart (observational, hence Med).
- StoreAndForward-028 (Med): StoreAndForward-025 resets the register-guard but not
  _bufferedCount, so a same-instance Stop->Start re-seeds the depth gauge to ~2N.
- AuditLog-017, CentralUI-037, ScriptAnalysis-009, SiteRuntime-033 (Low): a
  test-coverage gap plus stale doc-comments/spec following the remediation.

Header commit/date bumped to 1f9de8a2 / 2026-06-24 on all 17 modules; README
regenerated (8 pending / 576 total).
This commit is contained in:
Joseph Doherty
2026-06-24 09:20:03 -04:00
parent 1f9de8a2b5
commit c42bb48585
18 changed files with 635 additions and 66 deletions
+47 -3
View File
@@ -5,10 +5,10 @@
| Module | `src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis` |
| Design doc | `docs/requirements/Component-ScriptAnalysis.md` |
| Status | Reviewed |
| Last reviewed | 2026-06-20 |
| Last reviewed | 2026-06-24 |
| Reviewer | claude-agent |
| Commit reviewed | `4307c381` |
| Open findings | 0 |
| Commit reviewed | `1f9de8a2` |
| Open findings | 1 |
## Summary
@@ -405,3 +405,47 @@ defence for the compile-running consumers).
Won't Fix 2026-06-20: the static gate is intentionally defence-in-depth, not a runtime
sandbox — this is the explicitly-documented design posture, not a defect. Recorded as a
standing risk for visibility.
## Re-review — 2026-06-24 (commit `1f9de8a2`)
Focused re-review of the changes since the prior review — verifying the code-review remediation + feature fixes are sound and regression-free. Reviewed by a per-module workflow agent; findings code-verified by the orchestrator.
**Changes reviewed:** The diff remediates prior finding ScriptAnalysis-001: when TRUSTED_PLATFORM_ASSEMBLIES is unavailable (single-file/AOT/trimmed host), BuildAnalysisReferences now folds new ForbiddenAnchorAssemblies (Process, Socket, File, Thread, Assembly, Marshal) into the minimal fallback so a bare forbidden type in an allowed namespace still resolves and is flagged, sets an observable AnalysisReferencesDegraded flag plus a Trace.TraceWarning, and refactors per-assembly add into TryAddAssembly. A new BuildMinimalFallbackReferences() helper and a FindViolations(code, baseReferences, extraReferences) overload let tests pin the degraded path; the extraReferences XML-doc was corrected to state extra references only widen resolution and can never whitelist a forbidden API. Test files added 11 adversarial cases (SA-003) covering TPA-fallback, extension methods, verbatim/Unicode-escape identifiers, unsafe blocks, and comment/string-literal false-positive guards.
**Verdict:** The changed code is sound and regression-free. The SA-001 fix is correctly scoped: forbidden-API anchor assemblies are folded in only on the degraded (no-TPA) path and only into the validator's AnalysisReferences, never into DefaultReferences, so the RoslynScriptCompiler compile gate keeps rejecting forbidden types as undefined symbols (its independent second layer of defence is preserved). Static field-initialization order is correct (anchor lists declared before AnalysisReferences), the degradation is now loud, and the new FindViolations overload is fully backward-compatible with all four existing single-arg consumers. The 34 ScriptTrustValidator tests pass, including the 11 new adversarial cases, and the design doc (REQ-SA-2, TPA-fallback section) is fully in sync with the code. The only observations are minor: no test asserts the production non-degraded flag value, and one inline comment is slightly imprecise inside the parameterized overload — neither affects correctness or security.
| # | Category | Examined | Notes |
|---|----------|----------|-------|
| 1 | Correctness & logic bugs | ☑ | Fallback enrichment, tpaAvailable detection (byPath.Count>0), and TryAddAssembly dedup logic are correct. Static init order (DefaultAssemblies/ForbiddenAnchorAssemblies before AnalysisReferences) is safe. No issues found. |
| 2 | Akka.NET conventions | ☑ | Module has no actors/Akka dependency by design; the change adds only static policy/validator members. Not applicable; no issues found. |
| 3 | Concurrency & thread safety | ☑ | AnalysisReferencesDegraded is set once during static initialization of AnalysisReferences (single-threaded type-init) and read-only thereafter; the new overload is stateless and per-call. No shared mutable state introduced. |
| 4 | Error handling & resilience | ☑ | TryAddAssembly swallows per-assembly read errors (fail-open on a single bad assembly, as before) and the degraded fallback is now LOUD via flag + Trace.TraceWarning rather than silent. Fail-safe posture preserved. |
| 5 | Security | ☑ | Core fix verified: anchors added only to AnalysisReferences on the degraded path, never to DefaultReferences, so the compile-gate's undefined-symbol defence is intact. Bare Process/Socket now caught on the minimal set (test-proven). extraReferences cannot produce a false allow. No new bypass introduced. |
| 6 | Performance & resource management | ☑ | Anchor enrichment adds at most 6 MetadataReference.CreateFromFile calls, and only on the degraded path, all at one-time static init. No per-call cost added (the pre-existing no-cache concern, SA-006, is unchanged and out of delta scope). |
| 7 | Design-document adherence | ☑ | Component-ScriptAnalysis.md (lines 86-88) documents DefaultReferences vs AnalysisReferences, ForbiddenAnchorAssemblies, the not-silent fallback, and AnalysisReferencesDegraded exactly as implemented. No drift in either direction. |
| 8 | Code organization & conventions | ☑ | Extraction of TryAddAssembly removes duplication; ForbiddenAnchorAssemblies / BuildMinimalFallbackReferences are well-placed and thoroughly XML-documented. Overload delegation pattern is clean. No issues found. |
| 9 | Testing coverage | ☑ | 11 new adversarial tests close SA-003 gaps and pass (34/34). Minor: no test asserts AnalysisReferencesDegraded==false on a normal (TPA-present) host, so the production non-degraded path is exercised only implicitly. |
| 10 | Documentation & comments | ☑ | New XML-docs are accurate and the corrected extraReferences doc matches verified behaviour. Minor: the inline comment at ScriptTrustValidator.cs:106-111 still says 'Use the full trusted-platform reference set' but the method now resolves against the baseReferences parameter (minimal-enriched on the fallback path). |
**New findings from this re-review (1):**
### ScriptAnalysis-009 — Inline Pass 1 comment no longer reflects parameterized base references
| | |
|--|--|
| Severity | Low |
| Category | Documentation & comments |
| Status | Open |
| Location | `src/ZB.MOM.WW.ScadaBridge.ScriptAnalysis/ScriptTrustValidator.cs:106` |
**Description**
The inline comment at lines 106-111 still asserts 'Use the full trusted-platform reference set (not the minimal runtime-fidelity DefaultReferences)'. After the refactor, Pass 1 now resolves against the baseReferences parameter (line 112), which on the test/degraded path is the minimal anchor-enriched fallback set, not the full TPA set. The comment describes only the default public-entry-point case and is misleading for a maintainer reading the parameterized overload. The overload's own XML-doc (lines 77-89) is correct, so impact is limited to an internal comment.
**Recommendation**
Reword the comment to note that Pass 1 resolves against the supplied baseReferences — full TPA set on the public entry point, minimal anchor-enriched fallback when a caller (e.g. tests) passes BuildMinimalFallbackReferences().
**Resolution**
_Unresolved._