Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assets/data/search-index.json

Large diffs are not rendered by default.

35 changes: 33 additions & 2 deletions docs-src/governance/common-RemediationBacklog.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Implemented in MMCA.Common, ✅ **verified 2026-06-09**: `dotnet build -c Releas
✅ **Verified**: `dotnet build -c Release` clean (0/0) and all 9 test projects pass (1,511 tests, 0 failures).

- ✅ **#32 / #16: supply-chain.** NuGet **lock files** (`RestorePackagesWithLockFile`, 20 committed), `nuget.config` **packageSourceMapping** (`*`→nuget.org), **CycloneDX SBOM** step in `release.yml`, **CHANGELOG.md** + **VERSIONING.md** (SemVer + breaking-change + consumer-sweep policy). With the Wave-1 fitness test, #32 and #16 reach 4.
- ✅ **#11: security.** CI **vuln-audit gate** (`dotnet list package --vulnerable` + `NuGetAudit=all`) and **SECURITY.md** (security model, OWASP note, consumer responsibilities). *Item 13 (NetArchTest security invariants) deferred to consumer suites: infeasible as NetArchTest, and the framework's CORS / anonymous-endpoints are already correct.*
- ✅ **#11: security.** CI **vuln-audit gate** (`dotnet list package --vulnerable` + `NuGetAudit=all`) and **SECURITY.md** (security model, OWASP note, consumer responsibilities). *Item 13 (NetArchTest security invariants) deferred to consumer suites: infeasible as NetArchTest, and the framework's CORS / anonymous-endpoints are already correct.* **(2026-08-22 addendum: the deferral is superseded. The verdict was correct only for NetArchTest's fluent API; the rules landed as a full-name-reflection fitness base plus executable invariant tests over the real registration code. See the security invariants wave below.)**
- ✅ **#13: observability.** `AddMeter("MMCA.Common.Outbox")` (dead-letter counter now exported) + **CQRS RED histograms** (`cqrs.command/query.duration`, tagged by name + outcome) via `CqrsMetrics`, registered in Aspire `WithMetrics`.
- ✅ **#17: DevOps.** `.github/dependabot.yml` (nuget + actions, MassTransit-major ignored); symbols switched to **embedded** (orphan `snupkg` removed: verified via `dotnet pack`).
- ✅ **#34: governance.** Refreshed the stale DB-per-service passages in `Docs/Architecture/ArchitecturalAnalysis.md`; added **ADR-006** (database-per-service) + **ADR-007** (gRPC extraction) + **ADRs/README.md** index.
Expand Down Expand Up @@ -1049,6 +1049,37 @@ package: `Microsoft.Extensions.TimeProvider.Testing` 10.7.0.

---

## Progress - security invariants wave (§11 hardening, 2026-08-22)

Closes the two §11 gaps surfaced by the Article 16 (JWKS dual-fetch) review: the insecure dev
defaults that no two-axis entry named as scheduled work, and the absent security fitness tests.
Landed via MMCA.Common PR #269 (merged 2026-08-22); consumer adoption PRs (ADC #135, Store #93,
Helpdesk #71) are open and merge with the next release's pin-bump sweep.

- ✅ **Secure-by-default `RequireHttpsMetadata`.** `AddForwardedJwtBearer` no longer ships a bare
`false` default: it resolves explicit argument, then the new
`Authentication:JwtBearer:RequireHttpsMetadata` config key, then `true` everywhere except
Development. A resolved `false` outside Development stays legal (the ACA internal-ingress h2c
authorities need it) and logs one startup warning naming the key; ADC and Store bicep now carry
the explicit opt-out with the justification recorded beside each authority entry, converting a
silent insecure default into an auditable decision. A transitional old-signature overload keeps
consumer `main` branches compiling until the sweep lands, then gets deleted.
- ✅ **Security fitness tests exist.** The second-wave "infeasible as NetArchTest" deferral (see
the 2026-08-22 addendum there) is superseded on both halves. `[AllowAnonymous]` posture:
`AnonymousEndpointTestsBase` (Testing.Architecture, full-name reflection, zero ASP.NET
references) fails the build on any occurrence missing from an explicit allow-list, on stale
allow-list entries, and on an empty scan; subclassed in Common (20 types, 4 allow-listed
framework credential-exchange actions) and in all three consumers. CORS and token validation:
executable invariant tests run the real registration code and assert the produced options
(RS256 stays pinned, the permissive policy never supports credentials, the credentialed policy
never widens to any origin and fails closed on empty origins, gateway variant included, and
`RsaJwksProvider` exports only public RSA parameters even when handed a private-key PEM).
Known limitation, documented in the base: minimal-API `.AllowAnonymous()` metadata is not
attribute-based and stays out of static reach; the framework's intentional anonymous surface
(JWKS, OIDC discovery, health) lives there.
- 📎 **Not re-scored here.** §11 (Security, Maturity 4 / Implementation 8) is left for the next
`/update-scorecard` cycle to re-adjudicate with this evidence.

## Deferred - 2026-07-19 full review (recorded, not scheduled)

> The 2026-07-19 full framework review shipped its accepted fixes on the review branch (rollback on
Expand Down Expand Up @@ -1220,7 +1251,7 @@ Soft-delete is the only deletion model: no lawful erasure path. *(All three fix

**Fix**
- [ ] Add a `dotnet list package --vulnerable` (or restore `--audit`) **CI gate**.
- [ ] Add **NetArchTest security invariants** (no stray `[AllowAnonymous]`; no `AllowAnyOrigin` + `AllowCredentials`).
- [x] Add **NetArchTest security invariants** (no stray `[AllowAnonymous]`; no `AllowAnyOrigin` + `AllowCredentials`). → landed 2026-08-22, not as NetArchTest fluent rules (genuinely infeasible there) but as `AnonymousEndpointTestsBase` (full-name reflection, subclassed in Common and every consumer) plus executable CORS/JWT invariant tests running the real registrations; see the security invariants wave section.
- [ ] Commit a **SECURITY.md** with an OWASP Top-10 review note.

### [x] #4 · Domain-Driven Design (3 to 4; now Maturity 4, no confirmed red flags)
Expand Down
35 changes: 33 additions & 2 deletions docs/governance/common-RemediationBacklog.html
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ <h2 id="progress-second-wave-2026-06-09">Progress: second wave (2026-06-09)</h2>
<p>✅ <strong>Verified</strong>: <code>dotnet build -c Release</code> clean (0/0) and all 9 test projects pass (1,511 tests, 0 failures).</p>
<ul>
<li>✅ <strong>#32 / #16: supply-chain.</strong> NuGet <strong>lock files</strong> (<code>RestorePackagesWithLockFile</code>, 20 committed), <code>nuget.config</code> <strong>packageSourceMapping</strong> (<code>*</code>→nuget.org), <strong>CycloneDX SBOM</strong> step in <code>release.yml</code>, <strong>CHANGELOG.md</strong> + <strong>VERSIONING.md</strong> (SemVer + breaking-change + consumer-sweep policy). With the Wave-1 fitness test, #32 and #16 reach 4.</li>
<li>✅ <strong>#11: security.</strong> CI <strong>vuln-audit gate</strong> (<code>dotnet list package --vulnerable</code> + <code>NuGetAudit=all</code>) and <strong>SECURITY.md</strong> (security model, OWASP note, consumer responsibilities). <em>Item 13 (NetArchTest security invariants) deferred to consumer suites: infeasible as NetArchTest, and the framework&#39;s CORS / anonymous-endpoints are already correct.</em></li>
<li>✅ <strong>#11: security.</strong> CI <strong>vuln-audit gate</strong> (<code>dotnet list package --vulnerable</code> + <code>NuGetAudit=all</code>) and <strong>SECURITY.md</strong> (security model, OWASP note, consumer responsibilities). <em>Item 13 (NetArchTest security invariants) deferred to consumer suites: infeasible as NetArchTest, and the framework&#39;s CORS / anonymous-endpoints are already correct.</em> <strong>(2026-08-22 addendum: the deferral is superseded. The verdict was correct only for NetArchTest&#39;s fluent API; the rules landed as a full-name-reflection fitness base plus executable invariant tests over the real registration code. See the security invariants wave below.)</strong></li>
<li>✅ <strong>#13: observability.</strong> <code>AddMeter(&quot;MMCA.Common.Outbox&quot;)</code> (dead-letter counter now exported) + <strong>CQRS RED histograms</strong> (<code>cqrs.command/query.duration</code>, tagged by name + outcome) via <code>CqrsMetrics</code>, registered in Aspire <code>WithMetrics</code>.</li>
<li>✅ <strong>#17: DevOps.</strong> <code>.github/dependabot.yml</code> (nuget + actions, MassTransit-major ignored); symbols switched to <strong>embedded</strong> (orphan <code>snupkg</code> removed: verified via <code>dotnet pack</code>).</li>
<li>✅ <strong>#34: governance.</strong> Refreshed the stale DB-per-service passages in <code>Docs/Architecture/ArchitecturalAnalysis.md</code>; added <strong>ADR-006</strong> (database-per-service) + <strong>ADR-007</strong> (gRPC extraction) + <strong>ADRs/README.md</strong> index.</li>
Expand Down Expand Up @@ -1296,6 +1296,36 @@ <h2 id="progress---twenty-sixth-wave-evidence-re-score-at-v11420-2026-08-07">Pro
acceptance below.</li>
</ul>
<hr>
<h2 id="progress---security-invariants-wave-11-hardening-2026-08-22">Progress - security invariants wave (§11 hardening, 2026-08-22)</h2>
<p>Closes the two §11 gaps surfaced by the Article 16 (JWKS dual-fetch) review: the insecure dev
defaults that no two-axis entry named as scheduled work, and the absent security fitness tests.
Landed via MMCA.Common PR #269 (merged 2026-08-22); consumer adoption PRs (ADC #135, Store #93,
Helpdesk #71) are open and merge with the next release&#39;s pin-bump sweep.</p>
<ul>
<li>✅ <strong>Secure-by-default <code>RequireHttpsMetadata</code>.</strong> <code>AddForwardedJwtBearer</code> no longer ships a bare
<code>false</code> default: it resolves explicit argument, then the new
<code>Authentication:JwtBearer:RequireHttpsMetadata</code> config key, then <code>true</code> everywhere except
Development. A resolved <code>false</code> outside Development stays legal (the ACA internal-ingress h2c
authorities need it) and logs one startup warning naming the key; ADC and Store bicep now carry
the explicit opt-out with the justification recorded beside each authority entry, converting a
silent insecure default into an auditable decision. A transitional old-signature overload keeps
consumer <code>main</code> branches compiling until the sweep lands, then gets deleted.</li>
<li>✅ <strong>Security fitness tests exist.</strong> The second-wave &quot;infeasible as NetArchTest&quot; deferral (see
the 2026-08-22 addendum there) is superseded on both halves. <code>[AllowAnonymous]</code> posture:
<code>AnonymousEndpointTestsBase</code> (Testing.Architecture, full-name reflection, zero ASP.NET
references) fails the build on any occurrence missing from an explicit allow-list, on stale
allow-list entries, and on an empty scan; subclassed in Common (20 types, 4 allow-listed
framework credential-exchange actions) and in all three consumers. CORS and token validation:
executable invariant tests run the real registration code and assert the produced options
(RS256 stays pinned, the permissive policy never supports credentials, the credentialed policy
never widens to any origin and fails closed on empty origins, gateway variant included, and
<code>RsaJwksProvider</code> exports only public RSA parameters even when handed a private-key PEM).
Known limitation, documented in the base: minimal-API <code>.AllowAnonymous()</code> metadata is not
attribute-based and stays out of static reach; the framework&#39;s intentional anonymous surface
(JWKS, OIDC discovery, health) lives there.</li>
<li>📎 <strong>Not re-scored here.</strong> §11 (Security, Maturity 4 / Implementation 8) is left for the next
<code>/update-scorecard</code> cycle to re-adjudicate with this evidence.</li>
</ul>
<h2 id="deferred---2026-07-19-full-review-recorded-not-scheduled">Deferred - 2026-07-19 full review (recorded, not scheduled)</h2>
<blockquote>
<p>The 2026-07-19 full framework review shipped its accepted fixes on the review branch (rollback on
Expand Down Expand Up @@ -1480,7 +1510,7 @@ <h3 id="11--security-3--4-no-confirmed-red-flags">[ ] #11 · Security: 3 → 4 <
<p><strong>Fix</strong></p>
<ul>
<li><input disabled="" type="checkbox"> Add a <code>dotnet list package --vulnerable</code> (or restore <code>--audit</code>) <strong>CI gate</strong>.</li>
<li><input disabled="" type="checkbox"> Add <strong>NetArchTest security invariants</strong> (no stray <code>[AllowAnonymous]</code>; no <code>AllowAnyOrigin</code> + <code>AllowCredentials</code>).</li>
<li><input checked="" disabled="" type="checkbox"> Add <strong>NetArchTest security invariants</strong> (no stray <code>[AllowAnonymous]</code>; no <code>AllowAnyOrigin</code> + <code>AllowCredentials</code>). → landed 2026-08-22, not as NetArchTest fluent rules (genuinely infeasible there) but as <code>AnonymousEndpointTestsBase</code> (full-name reflection, subclassed in Common and every consumer) plus executable CORS/JWT invariant tests running the real registrations; see the security invariants wave section.</li>
<li><input disabled="" type="checkbox"> Commit a <strong>SECURITY.md</strong> with an OWASP Top-10 review note.</li>
</ul>
<h3 id="x-4--domain-driven-design-3-to-4-now-maturity-4-no-confirmed-red-flags">[x] #4 · Domain-Driven Design (3 to 4; now Maturity 4, no confirmed red flags)</h3>
Expand Down Expand Up @@ -1657,6 +1687,7 @@ <h3 id="suggested-sequencing">Suggested sequencing</h3>
<li><a href="#progress---twenty-fourth-wave-evidence-re-score-at-v11310-2026-07-28">Progress - twenty-fourth wave (evidence re-score at v1.131.0, 2026-07-28)</a></li>
<li><a href="#progress---twenty-fifth-wave-evidence-re-score-at-v11350-2026-08-01">Progress - twenty-fifth wave (evidence re-score at v1.135.0, 2026-08-01)</a></li>
<li><a href="#progress---twenty-sixth-wave-evidence-re-score-at-v11420-2026-08-07">Progress - twenty-sixth wave (evidence re-score at v1.142.0, 2026-08-07)</a></li>
<li><a href="#progress---security-invariants-wave-11-hardening-2026-08-22">Progress - security invariants wave (§11 hardening, 2026-08-22)</a></li>
<li><a href="#deferred---2026-07-19-full-review-recorded-not-scheduled">Deferred - 2026-07-19 full review (recorded, not scheduled)</a></li>
<li><a href="#recorded---2026-07-31-consumer-discovered-defect-not-scheduled">Recorded - 2026-07-31 consumer-discovered defect (not scheduled)</a></li>
<li><a href="#priority-6-highest-leverage">🔴 Priority 6: highest leverage</a></li>
Expand Down
2 changes: 1 addition & 1 deletion sitemap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,7 @@
</url>
<url>
<loc>https://ivanball.github.io/docs/governance/common-RemediationBacklog.html</loc>
<lastmod>2026-08-14</lastmod>
<lastmod>2026-08-22</lastmod>
<priority>0.6</priority>
</url>
<url>
Expand Down