Files
rustfs/.github/workflows/mint.yml
T
Zhengchao An 6c99d4fe22 ci: stop the weekly flake.lock bot from running the whole pipeline (#5539)
nix-flake-update opens a PR every Sunday that changes flake.lock and nothing
else. flake.lock is consumed only by Nix packaging — cargo never reads it — yet
it was in no paths filter, so each of those PRs ran the full Continuous
Integration pipeline and the merge then ran Build and Release too. Added to all
four lists that have to agree: ci.yml's push and pull_request paths-ignore,
build.yml's push paths-ignore, and ci-docs-only.yml's paths.

The cron stays. flake.lock still has consumers — anyone running `nix build` or
`nix develop` — so stopping the updates would remove the workflow's output, not
just its CI cost.

Those four lists drifting is a silent failure, so scripts/check_ci_paths_sync.sh
now asserts the pair that matters: ci.yml's pull_request paths-ignore must equal
ci-docs-only.yml's paths. An entry present only in the first means a PR touching
those files triggers neither workflow, nobody reports "Test and Lint" or "Quick
Checks", and the PR waits on a required check forever. It also asserts both
companion job names still exist, since renaming one produces the same hang. The
push list is not compared: no required check is reported for push events.

Also in this cleanup:

- nix-flake-update's GITHUB_TOKEN drops to contents: read. The branch push and
  the pull request are both made by update-flake-lock with the
  FLAKE_UPDATE_TOKEN PAT, so the write scopes were an unused repo-write
  credential on an unattended weekly job.
- build.yml's build_docker dispatch input is documented as advisory. docker.yml
  triggers on workflow_run and requires the triggering event to be a tag push,
  so a manual dispatch never reaches it whatever this input says.
- The nine disabled workflow files get a banner saying so. Their
  disabled_manually state lives in GitHub's UI and is invisible when reading the
  file, which has already misled one audit into treating dead workflows as live.

Refs: rustfs/backlog#1598, rustfs/backlog#1603
2026-08-01 11:28:14 +08:00

277 lines
12 KiB
YAML

# Copyright 2024 RustFS Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# MinIO Mint against RustFS: multi-SDK client compatibility.
#
# ceph/s3-tests (see e2e-s3tests.yml and the ci.yml PR gate) exercises the S3
# API semantics through boto3 only. Mint complements it by running the
# functional test suites of many REAL client SDKs and tools (awscli, mc,
# aws-sdk-java/go/php/ruby, minio-go/java/js/py, s3cmd, ...), which catches
# client-specific signing, encoding, and streaming edge cases a single client
# cannot.
#
# This job is REPORT-ONLY for test failures: RustFS does not pass every mint
# suite yet, so failures are inventoried in the job summary instead of turning
# the run red. The job fails only when mint produces no results at all
# (infrastructure error). Once a suite passes reliably, tightening this into a
# baseline gate (like implemented_tests.txt for s3-tests) is the natural next
# step. Tightening this into a per-suite baseline gate is tracked as ci-3
# (backlog#1149) and is intentionally NOT done here.
#
# Runner infrastructure (ci-2, backlog#1149): this job needs a working Docker
# daemon to (a) build the RustFS source image with buildx and (b) run both the
# RustFS server and the mint image. It previously ran on the self-hosted
# `sm-standard-4` label, which is served by heterogeneous runners; its single
# recorded run (28730530597, 2026-07-05) landed on a minimal pod with no
# `/var/run/docker.sock`, so "Enable buildx" died at `docker buildx create`
# ("failed to connect to the docker API at unix:///var/run/docker.sock") before
# any test executed -- the same root cause ci-1 fixed for the weekly s3-tests
# sweep. The fix is to pin to GitHub-hosted `ubuntu-latest`, which reliably
# ships a running Docker daemon + buildx + python3, instead of trusting the
# drifting self-hosted fleet. Tradeoff: the source Rust build is heavier on a
# GitHub-hosted 4-vCPU runner than on a warm self-hosted host, but it stays
# well inside the 120-minute budget and buys deterministic infra. The
# docker-capable self-hosted `dind-sm-standard-2` label was the alternative but
# has fewer cores and reintroduces fleet-state risk for no reliability gain.
# DISABLED. This workflow is switched off in the repository's Actions settings
# (state: disabled_manually) and does not run on any trigger, including its cron
# and workflow_dispatch. That state lives in GitHub's UI and is invisible when
# reading this file, which has already misled at least one audit — hence this
# banner. Re-enabling is a UI action; anyone doing so should first check that the
# workflow still matches the current CI layout. See rustfs/backlog#1603.
#
name: mint
on:
workflow_dispatch:
inputs:
suites:
description: "Space-separated mint suites to run (empty = all, e.g. 'awscli mc minio-go')"
required: false
default: ""
mode:
description: "Mint mode: core (quick) or full"
required: true
type: choice
default: "core"
options:
- core
- full
mint-image:
description: "Mint image reference"
required: false
default: "minio/mint:edge"
schedule:
# Weekly, after the Sunday s3-tests full sweep (starts 02:00 UTC, up to
# 3h) has finished, so the two never contend for the same runner pool.
- cron: "0 6 * * 0"
env:
S3_ACCESS_KEY: rustfsadmin-ci
S3_SECRET_KEY: rustfssecret-ci
S3_REGION: us-east-1
RUST_LOG: info
PLATFORM: linux/amd64
BUILDX_CACHE_SCOPE: rustfs-e2e-s3tests-source
MINT_SUITES: ${{ github.event.inputs.suites || '' }}
MINT_MODE: ${{ github.event.inputs.mode || 'core' }}
# minio/mint:edge is a rolling tag, so an unpinned run is not reproducible and
# can go red purely from an upstream mint change (ci-2, backlog#1149). Pin the
# default to the linux/amd64 digest resolved on 2026-07-10. workflow_dispatch
# can still override via the `mint-image` input (e.g. to test a newer edge).
# Refresh: docker manifest inspect minio/mint:edge --verbose | grep digest
# (or, without a docker daemon:)
# TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:minio/mint:pull" | jq -r .token)
# curl -sI -H "Authorization: Bearer $TOKEN" \
# -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
# https://registry-1.docker.io/v2/minio/mint/manifests/edge | grep -i docker-content-digest
MINT_IMAGE: ${{ github.event.inputs.mint-image || 'minio/mint:edge@sha256:08a05e68893c68be2a83b6f79556853ed6aa3c6c9e64c823a00853e4e55d2200' }}
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Only alert-on-failure needs more than read access; it declares its own
# job-level `issues: write`.
permissions:
contents: read
defaults:
run:
shell: bash
jobs:
mint:
# GitHub-hosted: reliably provides a running Docker daemon + buildx +
# python3. See the header note (ci-2) for why the self-hosted sm-standard-4
# label was abandoned (no docker.sock on the pod its only run landed on).
# TODO(ci-8): scheduled-failure alerting (auto-open issue on a red weekly
# run) is added by the ci-8 composite action; do not implement it here.
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Enable buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
- name: Build RustFS image (source, cached)
run: |
DOCKER_BUILDKIT=1 docker buildx build --load \
--platform "${PLATFORM}" \
--cache-from "type=gha,scope=${BUILDX_CACHE_SCOPE}" \
--cache-to "type=gha,mode=max,scope=${BUILDX_CACHE_SCOPE}" \
-t rustfs-ci \
-f Dockerfile.source .
- name: Start RustFS
run: |
docker network inspect rustfs-net >/dev/null 2>&1 || docker network create rustfs-net
docker rm -f rustfs-mint >/dev/null 2>&1 || true
# The four disks share one physical device on the runner (a single
# loopback filesystem), so the local physical-disk-independence guard
# would refuse to start. Bypass it — this is the CI use case the guard
# explicitly sanctions via RUSTFS_UNSAFE_BYPASS_DISK_CHECK.
docker run -d --name rustfs-mint \
--network rustfs-net \
-p 9000:9000 \
-e RUSTFS_ADDRESS=0.0.0.0:9000 \
-e RUSTFS_ACCESS_KEY="${S3_ACCESS_KEY}" \
-e RUSTFS_SECRET_KEY="${S3_SECRET_KEY}" \
-e RUSTFS_VOLUMES="/data/rustfs{0...3}" \
-e RUSTFS_UNSAFE_BYPASS_DISK_CHECK=true \
-v /tmp/rustfs-mint:/data \
rustfs-ci
- name: Wait for RustFS ready
run: |
for _ in {1..60}; do
if curl -sf http://127.0.0.1:9000/health >/dev/null 2>&1; then
echo "RustFS is ready"
exit 0
fi
if [ "$(docker inspect -f '{{.State.Running}}' rustfs-mint 2>/dev/null)" != "true" ]; then
echo "RustFS container not running" >&2
docker logs rustfs-mint || true
exit 1
fi
sleep 2
done
echo "Health check timed out" >&2
docker logs rustfs-mint || true
exit 1
- name: Run mint
run: |
mkdir -p artifacts/mint-log
# Mint exits non-zero when any test fails; that is inventory here,
# not a gate (see header comment). Capture the exit code and let the
# summary step decide.
set +e
# shellcheck disable=SC2086 # MINT_SUITES is intentionally word-split
docker run --rm --network rustfs-net \
-e SERVER_ENDPOINT=rustfs-mint:9000 \
-e ACCESS_KEY=${S3_ACCESS_KEY} \
-e SECRET_KEY=${S3_SECRET_KEY} \
-e ENABLE_HTTPS=0 \
-e SERVER_REGION=${S3_REGION} \
-e MINT_MODE=${MINT_MODE} \
-v "${PWD}/artifacts/mint-log:/mint/log" \
"${MINT_IMAGE}" ${MINT_SUITES}
echo "MINT_RC=$?" >> "$GITHUB_ENV"
- name: Summarize results
run: |
python3 - <<'EOF'
import json, os, pathlib, sys
from collections import Counter
log = pathlib.Path("artifacts/mint-log/log.json")
if not log.is_file():
print("mint produced no log.json - infrastructure failure", file=sys.stderr)
sys.exit(int(os.environ.get("MINT_RC", "1")) or 1)
per_suite: dict[str, Counter] = {}
failures: list[tuple[str, str, str]] = []
for line in log.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line:
continue
try:
entry = json.loads(line)
except json.JSONDecodeError:
continue
suite = entry.get("name", "unknown")
status = entry.get("status", "unknown").upper()
per_suite.setdefault(suite, Counter())[status] += 1
if status == "FAIL":
failures.append((suite, entry.get("function", ""), entry.get("error") or entry.get("message") or ""))
lines = ["# Mint results", "", "| Suite | Pass | Fail | N/A |", "|-------|------|------|-----|"]
for suite in sorted(per_suite):
c = per_suite[suite]
lines.append(f"| {suite} | {c.get('PASS', 0)} | {c.get('FAIL', 0)} | {c.get('NA', 0)} |")
lines.append("")
if failures:
lines.append(f"## Failures ({len(failures)})")
lines.append("")
for suite, func, err in failures:
first = err.strip().splitlines()[0] if err.strip() else ""
lines.append(f"- `{suite}` / `{func}` {first}")
lines.append("")
lines.append("_Report-only: failures are inventory, not a gate (see workflow header)._")
report = "\n".join(lines)
print(report)
summary = os.environ.get("GITHUB_STEP_SUMMARY")
if summary:
with open(summary, "a", encoding="utf-8") as fh:
fh.write(report + "\n")
EOF
- name: Collect RustFS logs
if: always()
run: |
mkdir -p artifacts/rustfs-mint
docker logs rustfs-mint > artifacts/rustfs-mint/rustfs.log 2>&1 || true
- name: Upload artifacts
if: always() && env.ACT != 'true'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
with:
name: mint
path: artifacts/**
alert-on-failure:
name: Alert on scheduled failure
needs: [mint]
# `always()` is required: without it this job is skipped when a needed
# job fails. Alerts only for scheduled runs (backlog#1149 ci-8) — manual
# dispatch failures are already watched by a human.
if: always() && github.event_name == 'schedule' && contains(needs.*.result, 'failure')
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- name: Open or update failure-tracking issue
uses: ./.github/actions/schedule-failure-issue
with:
github-token: ${{ secrets.GITHUB_TOKEN }}