Skip to content

Releases: SharkableIO/Sharkable

v0.5.5

Choose a tag to compare

@charleypeng charleypeng released this 02 Jul 16:48

security

  • Add MaxFingerprintBodySize (default 64 KiB) to SharkIdempotencyOptions — prevent OOM via attacker-controlled Content-Length header in idempotency middleware fingerprinting. Fixed chunked-transfer bypass where all Transfer-Encoding: chunked requests hashed to the same fingerprint (now hashes body incrementally with -1 sentinel for unknown length); setter rejects <= 0
  • Replace Thread.Sleep polling with await Task.Delay in graceful shutdown drain — prevent ApplicationStopping thread block (SHARK-SEC-003). Initial fix used .GetAwaiter().GetResult() on the drain task which still blocked the callback; corrected to true fire-and-forget so ApplicationStopping returns immediately.
  • Make SagaExecutor.LockTtl configurable; add LockRenewalInterval with periodic lock extension — prevent split-brain sagas when step duration exceeds lock TTL (SHARK-SEC-004, cross-repo with Sharkable.Cache.Redis). ISagaStore.RenewLockAsync converted from a required interface member to a default interface method (DIM) so existing third-party implementations keep compiling unchanged.
  • Replace unconditional KeyDelete in RedisSagaStore.ReleaseLockAsync and RedisCronJobStore.ReleaseJobLockAsync with check-and-delete Lua script — prevent split-brain when LockTtl expires mid-work (SHARK-SEC-005, cross-repo with Sharkable.Cache.Redis)
  • Add ICronJobStore.RenewJobLockAsync plus CronScheduler.CronLockTtl (default 10 min) and a background renewal task mirroring SagaExecutor — prevent split-brain cron jobs when job duration exceeds lock TTL (SHARK-SEC-005 follow-up, cross-repo with Sharkable.Cache.Redis)
  • BREAKING: Add [CrudAllow] attribute for explicit field allowlist on AutoCrud insertable/updateable — endpoints with Create | Update enabled and zero [CrudAllow] properties now throw InvalidOperationException at startup. Existing entities must mark every writable field with [CrudAllow]. Prevents mass-assignment privilege escalation (SHARK-SEC-006)
  • BREAKING (SHARK-SEC-006 follow-up): Exclude the configured soft-delete column (SqlSugarOptions.SoftDeleteFieldName, default "IsDeleted") from the [CrudAllow] allow-list even when explicitly marked — otherwise an attacker can revive soft-deleted rows by sending the field in a PUT body. Honors [SugarColumn(ColumnName = "...")] renames
  • BREAKING (SHARK-SEC-006 follow-up): AutoCrud POST / and PUT /{id} now return the persisted row re-read from the database instead of the user-controlled request body — previous behavior silently hid server-side defaults (timestamps, identity-generated PK, server-set soft-delete state) from the client
  • Require API key on profiler endpoint /_sharkable/profiler by default; return 404 if no API keys configured (SHARK-SEC-015). Adds SharkOption.ProfilerRequireApiKey (default true); also caps the top slow-requests surface at 50 to bound data exposure
  • Require API key on cron admin endpoint /_sharkable/jobs; redact LastError field to its first 100 characters + ... to prevent business-logic leakage (SHARK-SEC-016). Adds SharkOption.CronAdminRequireApiKey (default true); returns 404 if no API keys are configured
  • BREAKING: Make CronScheduler.Register async — eliminate sync-over-async deadlock risk with distributed stores (SHARK-SEC-017). ICronScheduler.Register is replaced by RegisterAsync returning Task; SharkOption.ConfigureCronJobs callback type changes from Action<ICronScheduler> to Func<ICronScheduler, Task> so the hosted service can await it without blocking on startup. Internal await _store.LoadStateAsync(...) replaces .GetAwaiter().GetResult().
  • Add SharkOption.RequireAuthenticatedByDefault opt-in flag — enforce auth on framework endpoints via fallback policy (SHARK-SEC-011, closes both H-4 and H-6)
  • Add ETagOptions.MaxResponseSize (default 10 MiB) + counting stream + incremental hashing — prevent OOM via huge response bodies (SHARK-SEC-012)
  • Add IMemoryCache SizeLimit (100k) + periodic eviction sweep to MemoryRateLimitStore — prevent slow-loris DoS via unique path explosion (SHARK-SEC-013)
  • Add IMemoryCache SizeLimit (10k) + entry.Size tracking to MemoryIdempotencyStore — prevent TB-DoS via unique idempotency keys (SHARK-SEC-014)
  • Add JWT algorithm allowlist + RequireSignedTokens + RequireExpirationTime + reduce ClockSkew to 30s — prevent algorithm confusion attacks (SHARK-SEC-007)
  • Use CryptographicOperations.FixedTimeEquals for API key comparison — prevent timing oracle (SHARK-SEC-008)
  • Gate ScalarJwtToken / ScalarApiKeyValue to IHostEnvironment.IsDevelopment() — prevent token leakage to public /scalar/v1 UI (SHARK-SEC-009)
  • Implement AuditTrailMiddleware header redaction per RedactHeaders list — credential-bearing headers (Authorization, X-Api-Key, Cookie by default) have their values replaced with *** in audit log output. Header names preserved so reviewers see which credentials were presented (SHARK-SEC-010)
  • Redact RedisHealthCheck description — never expose topology or exception messages on public /healthz (SHARK-SEC-018)
  • Validate connection string at AddSharkableRedis — null-check + default abortConnect=false + optional TLS enforcement (SHARK-SEC-019)
  • Replace JsonSerializer.Serialize<T> with source-generated JsonSerializerContext in RedisIdempotencyStore — Cache.Redis is now AOT-compatible (SHARK-SEC-020 follow-up, cross-repo with Sharkable.Cache.Redis)
  • Remove auto-registration of RedisHealthCheck as IHealthCheck in AddSharkableRedisUseSharkableRedisHealthCheck() is the only way to wire it (SHARK-SEC-021 follow-up, cross-repo with Sharkable.Cache.Redis)
  • Connection string: only override abortConnect=false when the key is absent — respect an explicit abortConnect=true (SHARK-SEC-019 follow-up, cross-repo with Sharkable.Cache.Redis)
  • Replace empty catch in RedisIdempotencyStore deserialization with typed exception handling + tombstone record — prevent silent double-execution on corruption (SHARK-SEC-020)
  • Add UseSharkableRedisHealthCheck() extension — explicit opt-in to wire health check into /healthz (SHARK-SEC-021)
  • Set TTL on RedisSagaStore progress records via RedisStoreOptions.SagaProgressTtl (default 7d) — prevent unbounded memory growth (SHARK-SEC-022)
  • Add AutoCrudSqlSugar.AutoCrudRequireAuthorization opt-in flag — auto-attach .RequireAuthorization() to generated CRUD endpoints. Default false for backward compat; production deployments MUST enable. (SHARK-SEC-023, cross-repo with Sharkable.AutoCrud.SqlSugar)
  • Defense-in-depth: also exclude SafeSoftDeleteField from [CrudAllow] allow-list by case-insensitive name match — protects against entities whose C# property name matches the configured soft-delete column but lacks [SugarColumn] rename (SHARK-SEC-024, cross-repo with Sharkable.AutoCrud.SqlSugar)
  • Add AutoCrudSqlSugar.MaxPageNumber (default 1M) + overflow check on (page - 1) * pageSize — prevent pagination DoS via page=int.MaxValue producing a negative OFFSET (SHARK-SEC-025, cross-repo with Sharkable.AutoCrud.SqlSugar)
  • Redact SqlSugarHealthCheck description — never expose dbType or ex.Message on public /healthz; full diagnostic detail logged at LogWarning for operators only (SHARK-SEC-026, cross-repo with Sharkable.AutoCrud.SqlSugar)
  • Escape SQL LIKE wildcards + cap filter value length (200) + cap IN array size (100) in AutoCrud search — prevent LIKE wildcard DoS and large-IN clause DoS (SHARK-SEC-027, cross-repo with Sharkable.AutoCrud.SqlSugar)
  • Fix ETag CountingResponseBody.FlushAsync duplicate body write on over-cap responses (SHARK-SEC-012 follow-up)
  • Fix MemoryRateLimitStore.IncrementAsync non-atomic increment allowing concurrent bypass (SHARK-SEC-013 follow-up)
  • Replace AuditTrailMiddleware.CaptureHeaders JsonSerializer.Serialize with hand-rolled formatter — AOT-compatible (SHARK-SEC-010 follow-up)
  • Make JWT audience validation mandatory when ConfigureJwt is called — reject empty audience list at config time (SHARK-SEC-007 follow-up)
  • Strip assembly-qualified type name from ExceptionHandlerOptions.GetErrorMessage dev output — prevent fingerprinting of Sharkable.X.Y, Version=1.0.0.0 over the wire (SHARK-SEC-M003)
  • Redact JwtHealthCheck description on /healthz — replace authority URL + ex.Message echoes with generic descriptions; full URL + exception now surface via ILogger.LogWarning for operators only (SHARK-SEC-M004)
  • Pin CultureInfo.InvariantCulture for string.Format in HttpContext.Localize(key, args) — prevent culture-dependent format-string growth attacks via malicious translations (SHARK-SEC-M005)
  • Implement IDisposable on AdaptiveLimitMonitor + wrap Adjust() in try/catch — prevent timer-callback exception tearing the process down + close the Process handle leak (SHARK-SEC-M010)
  • Cap CronExpression.GetNext iteration count at 2.2 M — bound CPU on non-matching patterns (e.g. 0 0 30 2 *) that previously looped 2.1 M times per hosted-service tick (SHARK-SEC-M011)
  • Link SharkCronHostedService host stoppingToken to a per-job CancellationTokenSource — prevent orphaned long-running cron jobs surviving app.StopAsync() and tripping k8s termination grace periods (SHARK-SEC-M012)
  • Collapse CronScheduler three correlated dictionaries (_jobs / _states / _expressions) into one Dictionary<string, JobEntry> under a single lock — eliminate TOCTOU between Register and GetDueJobsAsync (SHARK-SEC-M013)
  • Bound /healthz aggregate HealthCheckService.CheckHealthAsync with a 10 s CancellationTokenSource — prevent a single hung check from keeping the endpoint open and tripping k8s probes (SHARK-SEC-M015)
  • JwtHealthCheck now accepts IHttpClientFactory via DI — reuse a pooled HttpMessageHandler instead of opening a new socket per probe (SHARK-SEC-M016)
  • Default rate-...
Read more

v0.5.4

Choose a tag to compare

@charleypeng charleypeng released this 02 Jul 14:36

security

  • Add 100ms regex timeout to FormatAsGroupName / GetVersionFormat — prevent ReDoS via malicious GroupNameSuffixPattern / VersionFormatPattern
  • Add SafeSoftDeleteField validation in AutoCrudGenerator — reject non-alphanumeric field names to prevent SQL injection

Full Changelog: v0.5.3...v0.5.4

v0.5.3

Choose a tag to compare

@charleypeng charleypeng released this 30 Jun 15:34

feat

  • Add HttpContext.Localize(string key, params object[] args) overload — format args in localized strings
  • Add HttpContext.GetCulture() extension — resolve client culture from Accept-Language header
  • ApiKeyFilter automatically skipped when AuthorizationInterceptorFactory is set — interceptor owns auth entirely
  • Add SqlSugarOptions.MaxPageSize / DefaultPageSize — configurable AutoCrud pagination limits (defaults: 100 / 20)
  • Add SqlSugarOptions.SoftDeleteFieldName — configurable soft delete field (default: "IsDeleted")
  • Add SharkOption.ETagOptions.CacheableMethods / CacheControlHeader / ShouldSkipStatus — ETag method set, cache header, and cacheable status logic are now configurable
  • Add SharkOption.ApiKeyHeaderName — configurable API key request header
  • Add GracefulShutdownOptions.ShutdownStatusCode / DrainPollingInterval — configurable 503 status code and drain polling interval
  • Add SharkOption.ProblemDetailsTypeFactory / ProblemDetailsTitleFactory — delegates for customizing RFC 7807 type URI and title
  • Add SharkOption.DefaultCulture — configurable default locale for error localizer
  • Add SharkRateLimiterOptions.AdaptiveGcHighThreshold / AdaptiveGcLowThreshold / AdaptiveReductionDivisor — GC pressure thresholds and reduction factor for adaptive rate limiting
  • Add ProfilerOptions.MaxEntries — configurable profiler ring buffer size
  • Add SharkIdempotencyOptions.RetryAfterSeconds / ShouldCacheStatus — configurable Retry-After and cacheable status predicate
  • Add SharkOption.HealthCheckPath — configurable health check endpoint path
  • Add TracingOptions.ActivitySourceName — configurable ActivitySource name (separate from ServiceName)
  • Add SharkOption.GroupNameSuffixPattern / VersionFormatPattern / VersionFormatReplacement — customizable endpoint URL naming regexes
  • Remove hardcoded "Sharkable" ActivitySourceName in TracingMiddleware — now uses TracingOptions.ActivitySourceName
  • Add HttpContext.Localize(string key) extension method — easy localization in user endpoints
  • Add LocalizationExtensions — public scaffolding for endpoint-level error translation
  • Add SharkOption.EnableAuthorization (default true) — allows users to opt out of authorization service registration
  • Add SharkOption.ConfigureAuthorization — delegate for customizing AuthorizationOptions (policies, fallback, etc.)
  • Add SharkOption.ScalarJwtToken / SharkOption.ScalarApiKeyValue — configure pre-filled credentials in Scalar UI

docs

  • Add complete error localization guide with IErrorLocalizer implementation example, HttpContext.Localize() usage, and middleware integration pattern (EN + ZH)

fix

  • Fix InvalidOperationException when UseAuthorization is called without AddAuthorization — register AddAuthorization by default (configurable via EnableAuthorization), with factory support via ConfigureAuthorization delegate
  • Fix UnifiedResultWrapFilter always wrapping with status 200 — now uses actual HttpContext.Response.StatusCode
  • Fix AuditTrailMiddleware response header hardcoded to "X-Correlation-Id" — now respects AuditTrailOptions.CorrelationIdHeader

v0.5.1

Choose a tag to compare

@charleypeng charleypeng released this 29 Jun 14:47

Full Changelog: v0.5.0...v0.5.1

v0.3.2

Choose a tag to compare

@charleypeng charleypeng released this 27 Jun 11:00

Full Changelog: v0.3.1...v0.3.2

v0.3.1

Choose a tag to compare

@charleypeng charleypeng released this 27 Jun 10:10

Full Changelog: v0.3.0...v0.3.1

v0.3.0

Choose a tag to compare

@charleypeng charleypeng released this 30 Jun 15:35

What's Changed

Full Changelog: https://github.com/SharkableIO/Sharkable/blob/main/CHANGELOG.md

v0.2.0

Choose a tag to compare

@charleypeng charleypeng released this 26 Jun 15:18

What's Changed

Full Changelog: v0.1.0...v0.2.0

v0.1.0

Choose a tag to compare

@charleypeng charleypeng released this 08 Jun 03:58

What's Changed

  • update nuget dependency to avoid downgrade warning/invoke method as nullable by @charleypeng in #59
  • add unifiedresults factory and code refactor by @charleypeng in #60
  • feat: add global exception handler + auto unified result wrap by @charleypeng in #61
  • refactor: pluggable UnifiedResult with IUnifiedResultFactory by @charleypeng in #63
  • update AGENTS.md: add branch sync & rebase workflow by @charleypeng in #64
  • feat: add FluentValidation integration with auto-validate filter by @charleypeng in #65
  • docs: add XML doc comments to validation code + coding standard to AG… by @charleypeng in #66
  • fix: audit XML comments, fix bugs, remove dead code by @charleypeng in #67
  • feat: upgrade to .NET 10, replace Swagger with Scalar by @charleypeng in #68
  • Feat/endpoint grouping tags by @charleypeng in #70

Full Changelog: v0.0.25...v0.1.0

v0.0.25

v0.0.25 Pre-release
Pre-release

Choose a tag to compare

@charleypeng charleypeng released this 03 Oct 15:29

What's Changed

Full Changelog: v0.0.24...v0.0.25