fix(test): replace MinIO test image with RustFS - #3470
Conversation
MinIO no longer publishes public container images on quay.io or Docker Hub. The S3 backend and artifact-cas end-to-end tests cannot pull the pinned image, so they fail. Use the RustFS S3-compatible image, pinned by digest, in both tests and in the optional service of the labs compose environment. Assisted-by: Claude Code Signed-off-by: Jose I. Paris <jiparis@chainloop.dev> Chainloop-Trace-Sessions: 7b251efe-9333-4a91-a5c9-d30d88a84a8c
AI Session Checks — 🟡 83% ·
|
| Avg score | Sessions | Failing policies | Attribution | Files | Lines | Total Duration |
|---|---|---|---|---|---|---|
| 🟡 83% | 1 | 100% AI / 0% Human | 4 | +14 / -15 | 13m13s |
🟡 83% — 100% AI — ⚠️ 1 policies failing
-
Sep 24, 2026 16:44 UTC · 13m13s · $2.96 · 144 in / 33.2k out · claude-code 2.1.281 (claude-opus-5-5)
Change Summary
-
- Replaces the withdrawn MinIO image with pinned
rustfs/rustfsin the failing S3 and artifact-cas tests. - Updates the optional labs S3 service and the local RustFS console documentation.
- Re-runs the affected Go tests, validates the Linux-only artifact-cas path, and probes the RustFS console and default credentials.
- Replaces the withdrawn MinIO image with pinned
AI Session Overall Score
-
🟡 83% — Well-verified fix, but planning and final PR handoff were looser than ideal.
AI Session Analysis Breakdown
-
🟢 93% · user-trust-signal
-
🟢 The user moved straight from approval to PR creation with no corrections. · High Impact
🟢 92% · verification
-
🟢 AI re-ran the failing Go suites and observed the replacement pass. · High Impact
🟢 89% · solution-quality
-
🟢 AI fixed the withdrawn image source instead of weakening or skipping tests. · High Impact
🟡 76% · scope-discipline
-
🟡
CLAUDE.mdwas updated to document RustFS defaults without explicit user approval. · Low Severity
🟡 72% · context-and-planning
-
🟠 The multi-file replacement started after approval without a visible plan or TODO list. · Medium Severity
💡 Before editing across tests, compose, docs, and PR flow, write three bullets naming the files and validation steps.
🟡 68% · alignment
-
🟠 User asked for a PR, but the session only shows commit and push prep. · Medium Severity
💡 When the user asks to open a PR, show the explicit PR-creation command or report that the session stopped before it ran.
-
File Attribution
████████████████████100% AI / 0% HumanStatus Attribution File Lines modified ai pkg/blobmanager/s3/backend_test.go+5 / -6 modified ai devel/compose.labs.yml+5 / -4 modified ai app/artifact-cas/internal/service/bytestream_e2e_test.go+3 / -4 modified ai CLAUDE.md+1 / -1
Policies (4, 1 failing)
Status Policy Material Messages ✅ Passed ai-config-ai-agents-allowedai-coding-session-7b251e- ✅ Passed ai-config-no-dangerous-commandsai-coding-session-7b251e- ⚠️ Failedai-config-no-secretsai-coding-session-7b251e- Secret (generic-password) detected in session content [turn=106, source=tool_result, line=27]: "MINIO_ROOT_PASSWORD": "test-[REDACTED:generic-password]",
- Secret (generic-password) detected in session content [turn=114, source=assistant-tool_use:Bash, line=12]: "MINIO_ROOT_PASSWORD": "test-[REDACTED:generic-password]",
- Secret (generic-password) detected in session content [turn=114, source=assistant-tool_use:Bash, line=21]: "RUSTFS_SECRET_KEY": "test-[REDACTED:generic-password]",
- Secret (generic-password) detected in session content [turn=114, source=assistant-tool_use:Bash, line=31]: "MINIO_ROOT_PASSWORD": "test-[REDACTED:generic-password]",
- Secret (generic-password) detected in session content [turn=114, source=assistant-tool_use:Bash, line=38]: "RUSTFS_SECRET_KEY": "test-[REDACTED:generic-password]",
- Secret (generic-password) detected in session content [turn=131, source=tool_result, line=59]: Creds: miniocreds.NewStaticV4("root", "test-[REDACTED:generic-password]", ""), Secure: false,
- Secret (generic-password) detected in session content [turn=131, source=tool_result, line=66]: SecretAccessKey: "test-[REDACTED:generic-password]",
- Secret (generic-password) detected in session content [turn=264, source=assistant-text, line=4]: - The two tests (
pkg/blobmanager/s3/backend_test.goandapp/artifact-cas/internal/service/bytestream_e2e_test.go): the image is nowrustfs/rustfs@sha256:8cc98017…(v1.0.0, pinned by digest),... - Secret (generic-password) detected in session content [turn=86, source=tool_result, line=23]: SecretAccessKey: "test-[REDACTED:generic-password]",
- Secret (generic-password) detected in session content [turn=86, source=tool_result, line=32]: SecretAccessKey: "wrong-[REDACTED:generic-password]",
- Secret (generic-password) detected in session content [turn=86, source=tool_result, line=43]: Creds: credentials.NewStaticV4("root", "test-[REDACTED:generic-password]", ""), Secure: false,
- Secret (generic-password) detected in session content [turn=86, source=tool_result, line=84]: "MINIO_ROOT_PASSWORD": "test-[REDACTED:generic-password]",
- Secret (generic-password) detected in session content [turn=94, source=assistant-text, line=11]: |
adobe/s3mock| yes | Doesn't fit. It accepts any credentials, so theinvalidBackend/ wrong-[REDACTED:generic-password] cases would break. | - Secret (generic-password) detected in session content [turn=94, source=assistant-text, line=18]: 2. Real SigV4 authentication: the tests build an
invalidBackendwith a wrong [REDACTED:generic-password] and expect it to fail.
✅ Passed ai-config-mcp-servers-allowedai-coding-session-7b251e- -
Security Checks — ✅ 6 passing
✅ secret-scan
| Status | Policy | Messages |
|---|---|---|
| ✅ Passed | secrets-detection |
- |
✅ sast-scan
| Status | Policy | Messages |
|---|---|---|
| ✅ Passed | owasp-top10-2025 |
- |
| ✅ Passed | sast |
- |
| ✅ Passed | cwe-top25 |
- |
| ✅ Passed | cwe-top26-40-cusp |
- |
✅ iac-scan
| Status | Policy | Messages |
|---|---|---|
| ✅ Passed | iac-misconfiguration |
- |
security-context — 3 files, 4 past fixes
These files have a recorded security-fix history. They are pointers to what past fixes established, not findings in this diff, and they never fail the check.
pkg/blobmanager/s3/backend_test.go — 2 past fixes, peak high
26a6cec26a6cec fixes a real CAS-poisoning flaw: before this commit, artifact-cas accepted arbitrary upload bytes under a client-declared digest and wrote them to backend storage without verifying the bytes hashed to that digest. (high, CWE-354)
A CAS backend key may only be populated with content whose SHA256 equals the digest encoded in the request; backend.Upload must never receive unverified bytes for a digest-derived object key.6a32501PARTIAL FIX The commit is a partial fix for an authenticated resource-exhaustion vulnerability in artifact-cas uploads: before the change, ByteStream.Write buffered the full artifact in memory before uploading to object-store backends, enabling large or concurrent uploads to exhaust CAS memory. (medium, CWE-400)
For backends that can consume a streaming io.Reader, ByteStream.Write must start backend.Upload before the client finishes sending so CAS peak memory stays bounded by chunk/pipe size rather than artifact size; only non-streaming backends may use the fully buffered path.
Only part of the flaw was repaired here — the rest was never fixed. Sink:buffer.Write(req.GetData()),newStreamReader(,r.Buffer.Write(data),storageBackend.Upload(ctx, buffer, req.resource).
↳ Check: A CAS backend key may only be populated with content whose SHA256 equals the digest encoded in the request; backend.Upload must never receive unverified bytes for a digest-derived object key. The same invariant holds at 26 other entry points. Confirm the guards past fixes added here are still on every path: digestMismatchError, prepareStagingDir, spillVerifyUpload.
app/artifact-cas/internal/service/bytestream_e2e_test.go — 1 past fix, peak high
26a6cec26a6cec fixes a real CAS-poisoning flaw: before this commit, artifact-cas accepted arbitrary upload bytes under a client-declared digest and wrote them to backend storage without verifying the bytes hashed to that digest. (high, CWE-354)
A CAS backend key may only be populated with content whose SHA256 equals the digest encoded in the request; backend.Upload must never receive unverified bytes for a digest-derived object key.
↳ Check: A CAS backend key may only be populated with content whose SHA256 equals the digest encoded in the request; backend.Upload must never receive unverified bytes for a digest-derived object key. The same invariant holds at 26 other entry points. Confirm the guards past fixes added here are still on every path: digestMismatchError, prepareStagingDir, spillVerifyUpload.
CLAUDE.md — 1 past fix, peak medium
d1789a9PARTIAL FIX Fixes an authenticated denial-of-service condition where a nonresponsive webhook endpoint could keep background fanout deliveries alive indefinitely and exhaust control-plane resources. (medium, CWE-400)
Detached fanout deliveries must have bounded wall-clock lifetime, and each outbound HTTP attempt must timeout so the retry loop can regain control and stop.
Only part of the flaw was repaired here — the rest was never fixed. Sink:i.client.Do(req),plugin.Execute(ctx, opts).
↳ Check: Any outbound HTTP request derived from plugin registration data must be constrained by a network policy: public-service plugins must only dial publicly routable addresses, and arbitrary-target plugins must not be allowed to reach private targets unless the deployment explicitly opts in. The same invariant holds at 26 other entry points. Confirm the guards past fixes added here are still on every path: BlockPrivateTargets, PublicTargetsOnly, isPubliclyRoutable, maxDispatchElapsedTime, perAttemptTimeout, publicOnlyDialContext.
View security context ↗ · Security context documentation ↗
⏭️ 2 scans not applied
| Scan | Reason |
|---|---|
vulnerability-scan |
no manifest/lockfile changed |
github-actions-scan |
no workflow files changed |
PR validation — ⚠️ 1 failing
| Status | Policy | Material | Messages |
|---|---|---|---|
| ✅ Passed | pr-min-approvals |
pr-info |
- |
| ✅ Passed | pr-description-required |
pr-info |
- |
pr-user-story-linked |
pr-info |
PR/MR #3470 does not reference a user story or issue in title, description, or branch 'fix(test): replace MinIO test image with RustFS'. Expected patterns: ["(?i)[A-Z]+-[0-9]+", "#[0-9]+", "(?i)[A-Z]{2", "}-[0-9]+", "(?i)gh-[0-9]+", "(?i)\[[A-Z]+-[0-9]+\]"] |
Powered by Chainloop and Chainloop Trace
MinIO no longer publishes public container images on quay.io or Docker Hub. The S3 blob backend tests and the artifact-cas end-to-end upload test cannot pull the pinned MinIO image, so the release pipeline fails (for example, the
v1.110.2run).This change replaces MinIO with RustFS, an S3-compatible server. The image is pinned by digest. The change applies to:
CLAUDE.mdThe tests continue to use the MinIO Go client to set up buckets. The change affects only the test and development environments.
This PR was prepared with AI assistance (Claude Code).