MEDIUM:
- M1: JsonSerializerOptions.MaxDepth = 32 on the consolidated
JsonDefaults.Options (referenced from both ForgeClient and
RunResult.AsJson<T>) so the result payload's arbitrary upstream JSON
cannot stack-walk the runtime.
- M2: JsonDocumentOptions.MaxDepth = 32 in SummarizeBody for parsing
error-body summaries — defensive belt alongside the existing 8 MiB
body cap.
- M3: UploadStreamAsync doc updated to match reality — the input stream
IS disposed when the request completes (matches HttpClient /
MultipartFormDataContent / StreamContent convention). Old doc was
incorrect; chose doc-update over a non-disposing wrapper to stay
closest to standard .NET stream semantics.
LOW:
- L2: RunResult.AsJson<T>() now guards JsonValueKind.Undefined and
returns default(T) instead of throwing InvalidOperationException
(e.g. when RunResult is constructed without a server payload).
- L4: IsNullOrWhiteSpace consistent across RunRequest.Prompt,
CreateTokenRequest.Name, RevokeTokenAsync.name, UploadFileAsync.path,
UploadStreamAsync.fileName (was IsNullOrEmpty letting space through).
Nit polish:
- BaseUrl cached in ctor instead of rebuilt per access.
- JsonDefaults moved to its own file (Models/JsonDefaults.cs) and is
now the single source of truth for serializer options across the
client.
- examples/Basic/Program.cs comment fixed: '60s' → '120s' to match
TimeSpan.FromSeconds(120).
README:
- HTTPS / WireGuard recommendation in the Notes section — SDK does not
enforce HTTPS, callers off-LAN should tunnel.
- .NET 8.0.10+ runtime recommendation with cref to CVE-2024-30105 and
CVE-2024-43485 (SDK does not exercise the affected code paths;
belt-and-suspenders).
- UploadStream section reflects the corrected disposal contract.
Tests (12 → 19, all passing):
- JsonOpts_MaxDepth_RejectsDeeplyNested — 200-deep result rejected via
ForgeTransportException wrapping JsonException, no stack overflow.
- SummarizeBody_DeeplyNestedHandled — 200-deep error body still
produces ForgeAuthException with raw body intact; summary parse
fails closed without crashing.
- UploadStreamAsync_DisposesCallerStream — DisposeObservingStream
helper verifies the contract change.
- AsJson_OnUndefinedResult_DefaultReturned — reference + value type.
- RunRequest_PromptWithOnlyWhitespace_Rejected.
- CreateToken_NameWithOnlyWhitespace_Rejected.
- BaseUrl_Cached_ReusesString — Assert.Same identity check.
Build: dotnet build -c Release -m:1 clean (0 warnings, 0 errors).
Tests: dotnet test -c Release -m:1 → 19 passed, 0 failed.
Pack: dotnet pack -c Release -o dist -m:1 clean.
Vulns: dotnet list package --vulnerable --include-transitive → 0.
Audit: memory/clawdforge-audits/csharp-09aca58.md