[DRK-135] Remove hardcoded R2 credentials from S3 blob-storage test fixture - #339
Conversation
…creds S3BlobServiceFixture now reads connection string/access key/secret from the MinioContainer it already starts, instead of hardcoding live-looking Cloudflare R2 credentials. Adds ForcePathStyle (required for Minio's IP:port endpoint) and disables payload signing over plain HTTP. That surfaced two real S3BlobService bugs only exercised now that a path-style endpoint is in play: - GetBlobLocation()'s leading slash collided with path-style addressing (bucket//key), breaking SigV4 signatures on every request. Trimmed it at each call site; GetBlobLocation() itself is unchanged (locked contract test covers Azure/Local too). - Batch DeleteObjects requires a Content-MD5 the SDK's checksum pipeline won't auto-compute and Minio won't accept a substitute for; switched folder delete to per-key DeleteObjectAsync calls. Also replaces the same leaked R2 endpoint/key/secret literals (inert, pre-network-validation only) in BlobServiceSaveAsyncTests.cs with fake placeholders, and rewires its one test that actually saves data through the Minio-backed fixture instead of the now-fake endpoint. DisablePayloadSigning left as false is a deliberate deviation from the original plan (true fails immediately over Minio's plain-HTTP endpoint). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai>
…older delete - Fixture now exposes its S3Options so tests can construct their own S3BlobService instance (needed to exercise Dispose without going through the DI-registered IBlobService). - Adds DisposeReleasesUnderlyingClientAndIsIdempotent — the only gap behind S3BlobService.cs's 52.94% class-level coverage was Dispose()/Dispose(bool) never being invoked. - Adds DeleteAsyncDeletesDirectoryWithMultipleKeys and DeleteAsyncDeletesEmptyDirectoryWithoutThrowing to sanity-check the per-key DeleteFolderAsync rewrite (D135-2 checklist item). S3BlobService.cs line coverage: 52.94% -> 94.83%. Full suite: 120/120 green. Co-authored-by: multica-agent <github@multica.ai>
📊 Code Coverage Report |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev #339 +/- ##
==========================================
+ Coverage 78.57% 79.04% +0.46%
==========================================
Files 169 169
Lines 4159 4142 -17
Branches 611 608 -3
==========================================
+ Hits 3268 3274 +6
+ Misses 707 688 -19
+ Partials 184 180 -4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
PR Review Gate — Score: 9.4 / 10 → APPROVEDPR: #339 — Remove hardcoded R2 credentials from S3 blob-storage test fixture A clean, well-executed security fix. The hardcoded R2 credentials are fully removed, the fixture is properly wired to the Minio testcontainer, and the S3 key normalization ( Score breakdown
Weighted: 9.35 → rounded 9.4 Auto-merge preconditions
Findingspraise
important
nit
suggestion
Out-of-scope (pre-existing, tracked in follow-up)
|
[DRK-135] Remove hardcoded R2 credentials from S3 blob-storage test fixture, wire to Minio testcontainer
The S3 blob-storage test fixture hardcoded live-looking Cloudflare R2 credentials (endpoint, access key, secret) in this public repo, and the
MinioContainerit started was never actually wired up. This removes the leaked secret entirely and points the fixture at the Minio container instead, so the wholeSvc.BlobStorage.TestsS3 suite runs fully offline with zero external credentials.Changes
S3BlobServiceFixture.cs— config now sourced from_minioContainer.GetConnectionString()/GetAccessKey()/GetSecretKey()instead of hardcoded R2 values;ForcePathStyle: trueadded (required for Minio's non-DNS endpoint); exposes itsS3Optionsfor direct-construction tests.S3BlobService.cs— strips the leading/fromGetBlobLocation(blob)at all 6 call sites before using it as the S3 key (path-style + leading slash was producingSignatureDoesNotMatchagainst Minio);DeleteFolderAsyncrewritten from a single batchDeleteObjectsAsyncto oneDeleteObjectAsyncper key (Minio's checksum-header requirement on batch delete) — flagged inline with aponytail:comment on the trade-off (N round-trips vs. one per 1000-key page). The sharedGetBlobLocation()base (IBlobService.cs) and its locked contract test are untouched.BlobServiceSaveAsyncTests.cs— 4 hardcoded copies of the leaked secret/endpoint replaced with fake placeholders; one test (S3_SaveAsync_DefaultOptions_ShouldSucceed) rewired off the now-fake endpoint onto the Minio-backed fixture (it wasn't actually inert — it depended on the live R2 creds to pass); one stale leading-slash assertion updated to match the new key format.S3BlobServiceTest.cs— 3 new regression tests: multi-key folder delete, empty-folder delete (covering theDeleteFolderAsyncrewrite), andDispose()idempotency (previously uncovered, the main driver of the class's coverage gap).Verification
Svc.BlobStorage.Testssuite: 120/120 passing, 0 warnings.S3BlobService.csline coverage: 52.94% → 94.83%.dotnet packclean on touched projects; no new NuGet package.src/(one pre-existing non-secret placeholder inAwsS3/README.mdis untouched).