Skip to content

Commit d5dd93c

Browse files
iammukeshmmarcelo-macielclaude
committed
docs(changelog): security & reliability audit fixes + Billing grace-period key rename (#235, #230)
From PR #235: the four bullets whose upstream fixes are merged (SSRF guard #1332, SendGrid #1331, audit paging #1335, outbox backoff #1336). The idempotency (#1333) and forwarded-headers (#1334) bullets are held until those land upstream. From PR #230: the GraceWindowDays -> GracePeriodDays rename (#1313, merged), repositioned for date order. Co-Authored-By: Marcelo M. Maciel <4993482+marcelo-maciel@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 544fe98 commit d5dd93c

1 file changed

Lines changed: 13 additions & 0 deletions

File tree

src/content/docs/changelog/index.mdx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ Notable changes to the kit, newest first.
1717

1818
- **The `fsh` CLI and `dotnet new` template are now on NuGet as stable `10.0.0`.** The two distribution packages that 10.0.0 had been waiting on have shipped: `FullStackHero.CLI` (install with `dotnet tool install -g FullStackHero.CLI` - no more `--prerelease`) and `FullStackHero.NET.StarterKit` (`dotnet new install FullStackHero.NET.StarterKit`). Because `fsh new` scaffolds *from* that template, the one-command flow is now end-to-end: `dotnet tool install -g FullStackHero.CLI && fsh new MyApp` produces a fully renamed project - unique JWT signing key, generated Docker secrets, `npm install` run, initial commit on `main`. The [Install](/docs/getting-started/install/) and [CLI](/docs/cli/) pages now lead with the CLI as the recommended path; `git clone` and the GitHub template remain available for reading the source or zero-install runs. See the [10.0.0 release](https://github.com/fullstackhero/dotnet-starter-kit/releases/tag/10.0.0).
1919

20+
## 2026-07-11
21+
22+
A security & reliability audit pass across the backend. Every finding was reproduced with a failing test and adversarially verified before fixing; the suite stays green (warnings-as-errors, Testcontainers integration tests).
23+
24+
- **Webhooks: outbound delivery now blocks SSRF targets (security fix).** A subscription's destination URL is tenant-supplied, but the create validator only checked "absolute URI + http/https scheme" and both delivery sinks POSTed to it with redirects allowed and no address screening. Any tenant with `Webhooks.Create` could point a webhook at `169.254.169.254` (cloud instance metadata), loopback, or an RFC1918 host and read the delivery log as a blind-SSRF oracle. A shared guard now rejects loopback / link-local / private / CGNAT / IPv6-ULA / `localhost` targets at create time, and the `Webhooks` HTTP client screens the **resolved** IP at connect time (defeating DNS rebinding) with redirects disabled. See [Webhooks](/docs/modules/webhooks/).
25+
- **Mailing: a rejected SendGrid send no longer looks like success (fix).** `SendGridMailService` discarded the `Response` from `SendEmailAsync`, and the client runs with `HttpErrorAsException=false`, so a non-2xx reply (invalid API key, rejected recipient, rate limit) returned normally. Every caller - auth e-mail links, webhooks, notifications - treated a failed send as delivered. A non-success status now throws so the failure reaches the global error handler.
26+
- **Auditing: the security/exception audit list endpoints are now bounded (fix).** `GET /api/v1/audits/security` and `/audits/exception` did `ToListAsync` with no paging and no default window, so a no-argument call materialized a tenant's entire audit history - a latent out-of-memory on an active tenant. Both now accept optional `Skip`/`Take` and cap server-side (page size 1-200, default 50), mirroring the session-list convention. The unified `GET /api/v1/audits/` endpoint the console uses was already bounded and is unaffected.
27+
- **Eventing: failed outbox messages now back off, and dead-letters are recoverable and observable (fix).** A failing outbox message was retried on every dispatch cycle (~10s) with no backoff, dead-lettered after 5 attempts in ~50s, and then lost - no replay path, no metric. Retries now use exponential backoff (`NextRetryAt`, base 30s capped at 1h, configurable via `EventingOptions`); `IOutboxStore` gains `GetDeadLetteredAsync` / `RedriveDeadLettersAsync` to inspect and reset dead-lettered messages; and a new OpenTelemetry meter `FSH.Eventing` exposes `outbox.deadlettered` / `outbox.redriven` counters so the condition is alertable. Additive migration (nullable `NextRetryAt`).
28+
29+
## 2026-06-24
30+
31+
- **Config: the tenant billing grace-period setting was renamed `Billing:GraceWindowDays``Billing:GracePeriodDays` (breaking).** The option (bound in both `TenantBillingOptions` and Identity's `TenantGraceOptions`) is now named consistently with the "grace period" term used everywhere else in the kit; the default of 7 days is unchanged. Deployments that set `Billing:GraceWindowDays` (env `Billing__GraceWindowDays`) must rename the key to `Billing:GracePeriodDays`, otherwise the override is silently ignored and the default applies. No public contract change - the `GraceEndsUtc` tenant-status and integration-event fields are untouched. See PR [#1313](https://github.com/fullstackhero/dotnet-starter-kit/pull/1313).
32+
2033
## 2026-06-12
2134

2235
- **Both apps: every nav surface is now permission-gated.** A tenant user whose role lacked a module's permission could still see and open its nav entry, landing on a guaranteed `403` - e.g. the dashboard Files page rendering a `ForbiddenException` error band for a user without `Files.Upload`. The dashboard sidebar now gates Chat, My Files, Subscription, Invoices, the Catalog pages, and Tickets on the same permission each page's API enforces (joining the already-gated Identity/Audits/Sessions/Trash entries), and the **command palette** - previously a second, fully ungated surface - applies the same gates to its Navigate *and* Create actions. In the admin console, the Webhooks nav entry and routes gained the `Webhooks.View` gate the API has required since the webhook permission hardening, and the Role editor's permission catalog now includes the **Webhooks** group so those permissions can actually be granted. Server-side enforcement is unchanged - this is the UX layer catching up.

0 commit comments

Comments
 (0)