Skip to content

fix(test): replace MinIO test image with RustFS - #3470

Merged
jiparis merged 1 commit into
chainloop-dev:mainfrom
jiparis:fix/replace-minio-test-image
Sep 24, 2026
Merged

jiparis merged 1 commit into
chainloop-dev:mainfrom
jiparis:fix/replace-minio-test-image

Conversation

@jiparis

@jiparis jiparis commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

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.2 run).

This change replaces MinIO with RustFS, an S3-compatible server. The image is pinned by digest. The change applies to:

  • the S3 blob backend test suite
  • the artifact-cas end-to-end upload test
  • the optional S3 service of the labs compose environment, and its entry in CLAUDE.md

The 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).

Review in cubic

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
@chainloop-platform

chainloop-platform Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

AI Session Checks — 🟡 83% · ⚠️ 1 failing

Avg score Sessions Failing policies Attribution Files Lines Total Duration
🟡 83% 1 ⚠️ 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)

View session details ↗

Change Summary

  • Replaces the withdrawn MinIO image with pinned rustfs/rustfs in 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.

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.md was 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% Human

Status 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-allowed ai-coding-session-7b251e -
✅ Passed ai-config-no-dangerous-commands ai-coding-session-7b251e -
⚠️ Failed ai-config-no-secrets ai-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.go and app/artifact-cas/internal/service/bytestream_e2e_test.go): the image is now rustfs/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 the invalidBackend / 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 invalidBackend with a wrong [REDACTED:generic-password] and expect it to fail.
✅ Passed ai-config-mcp-servers-allowed ai-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

  • 26a6cec 26a6cec 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.
  • 6a32501 PARTIAL 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

  • 26a6cec 26a6cec 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

  • d1789a9 PARTIAL 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

View attestation ↗


PR validation — ⚠️ 1 failing

Status Policy Material Messages
✅ Passed pr-min-approvals pr-info -
✅ Passed pr-description-required pr-info -
⚠️ Failed 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]+\]"]

View attestation ↗


Powered by Chainloop and Chainloop Trace

@jiparis
jiparis requested a review from a team September 24, 2026 16:58

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

Re-trigger cubic

@jiparis
jiparis merged commit 474629f into chainloop-dev:main Sep 24, 2026
25 of 29 checks passed
@jiparis
jiparis deleted the fix/replace-minio-test-image branch September 24, 2026 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants