Compare commits

..

1 Commits

Author SHA1 Message Date
Chris An 34e6449ed9 revert(release): defer certification rollout for 1.0.5 (#9254)
Revert e5563e6004 only on release/1.0.5. Its trusted verifier workflow and immutable-candidate integration are not available yet. Restore the previous publication path under the approved release policy; retain the completed product regression and preview acceptance requirements.
2026-11-09 22:44:06 -05:00
112 changed files with 193 additions and 6522 deletions
-77
View File
@@ -1,77 +0,0 @@
{
"schema_version": 1,
"plan_id": "rustfs-release-validation",
"description": "Versioned certification plan for every public RustFS release exit (rustfs/backlog#2662, R01). preview, prerelease and stable all require this explicit plan. Scripts/release/release_gate.py fail-closes publication on any missing, duplicate, stale, substituted or non-PASS required item.",
"release_types": ["preview", "prerelease", "stable"],
"targets": [
{"os": "linux", "arch": "x86_64", "abi": "musl"},
{"os": "linux", "arch": "aarch64", "abi": "musl"},
{"os": "linux", "arch": "x86_64", "abi": "gnu"},
{"os": "linux", "arch": "aarch64", "abi": "gnu"},
{"os": "macos", "arch": "aarch64", "abi": "none"},
{"os": "windows", "arch": "x86_64", "abi": "msvc"}
],
"targets_basis": "Platform matrix of .github/workflows/build.yml (prepare-platform-matrix). gnu and macOS targets build with the pyroscope feature; musl and Windows targets build with no extra features.",
"features": ["pyroscope"],
"trusted_workflows": [
{"repository": "rustfs/s3chaos", "workflow_id": "release-gate.yml"}
],
"trusted_workflows_basis": "The shared evidence envelope producer lives in rustfs/s3chaos (G01, fault/release_gate.rs) and its plan/live split workflow is .github/workflows/release-gate.yml there. Only results from these identities may enter a release certification; PR-uploaded JSON never gains release authority. R02 must extend this list when additional verifier workflows land, never widen it to untrusted sources.",
"lanes": [
{
"lane": "identity",
"harness_repository": "rustfs/s3chaos",
"harness_sha": "9a48f55c1d6d58ce63a8fb1ea7317e024f32f11d",
"harness_basis": "Fixed G01 evidence-envelope producer revision (rustfs/s3chaos PR #102 head recorded in rustfs/backlog#2658). R02 re-pins this when the live verifier ships.",
"timeout_seconds": 1800,
"environment_capabilities": ["process-exec"],
"cases": ["artifact-identity", "startup"],
"applies_to": {
"release_types": ["preview", "prerelease", "stable"],
"platforms": "all"
},
"applies_basis": "Artifact identity and startup checks are mandatory for every release type, preview included, on every shipped target (rustfs/backlog#2662 frozen design item 5)."
},
{
"lane": "upgrade",
"harness_repository": "rustfs/s3chaos",
"harness_sha": "9a48f55c1d6d58ce63a8fb1ea7317e024f32f11d",
"harness_basis": "Same fixed envelope producer as the identity lane; the workflow SHA and the product build SHA are bound separately and need not be equal.",
"timeout_seconds": 5400,
"environment_capabilities": ["process-exec", "previous-release-artifact"],
"cases": [
"direct-upgrade",
"mixed-version-upgrade",
"bucket-config-upgrade",
"bucket-config-rollback",
"multipart-layout-upgrade",
"multipart-layout-baseline"
],
"cases_basis": "Case IDs of the pinned previous-release matrix in .github/workflows/e2e-upgrade.yml (source.version/asset/sha256 and the case list mapped there).",
"applies_to": {
"release_types": ["prerelease", "stable"],
"platforms": [{"os": "linux", "arch": "x86_64", "abi": "gnu"}]
},
"applies_basis": "preview releases use the pre-declared smaller set (identity lane only). The upgrade lane is only exercised on linux-x86_64-gnu, the platform of the pinned source assets."
}
],
"upgrade_sources": {
"basis": "Exactly the two previous-release sources pinned in .github/workflows/e2e-upgrade.yml are exercised today (source.version / source.asset / source.sha256). No other N-1/N-2 compatibility is claimed, and these digests are not inferred from tags.",
"sources": [
{
"version": "1.0.1",
"role": "N-1",
"artifact_name": "rustfs-linux-x86_64-gnu-v1.0.1.zip",
"artifact_sha256": "9742e183cb0dfb0d48fa909797af572fe47b7f827569036baa4156e0d3958ee5"
},
{
"version": "1.0.0-rc.5",
"role": "N-2",
"artifact_name": "rustfs-linux-x86_64-gnu-v1.0.0-rc.5.zip",
"artifact_sha256": "3ee8df71e8edcfada533be452c4135868f697bc515460ae97b027313eade7a3d"
}
],
"rollback_supported": false,
"rollback_basis": "Only the bucket-config-rollback case (rollback_to_previous_release_reads_current_bucket_metadata) is exercised. Full data-plane rollback is not certified and is never a default claim."
}
}
+6 -312
View File
@@ -193,7 +193,7 @@ jobs:
{"target_id":"linux-aarch64-musl","os":"ubicloud-standard-16-arm","target":"aarch64-unknown-linux-musl","cross":false,"platform":"linux","rustflags":"","features":"","glibc":""},
{"target_id":"linux-x86_64-gnu","os":"sm-standard-4","target":"x86_64-unknown-linux-gnu","cross":true,"platform":"linux","rustflags":"","features":"pyroscope","glibc":"2.31"},
{"target_id":"linux-aarch64-gnu","os":"ubicloud-standard-16-arm","target":"aarch64-unknown-linux-gnu","cross":true,"platform":"linux","rustflags":"","features":"pyroscope","glibc":"2.31"},
{"target_id":"macos-aarch64","os":"macos-latest-xlarge","target":"aarch64-apple-darwin","cross":false,"platform":"macos","rustflags":"","features":"pyroscope","glibc":""},
{"target_id":"macos-aarch64","os":"macos-latest","target":"aarch64-apple-darwin","cross":false,"platform":"macos","rustflags":"","features":"pyroscope","glibc":""},
{"target_id":"windows-x86_64","os":"windows-latest","target":"x86_64-pc-windows-msvc","cross":false,"platform":"windows","rustflags":"","features":"","glibc":""}
]}'
@@ -814,18 +814,13 @@ jobs:
export AWS_SECRET_ACCESS_KEY="$R2_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="auto"
# Determine upload path based on build type. Release and prerelease
# builds only stage their bytes here: the official
# artifacts/rustfs/release/ path is written solely by the
# certification-gated promote-release-artifacts job, from these same
# staged objects. Development builds keep the uncertified dev channel
# and never touch official or latest channels.
# Determine upload path based on build type
if [[ "$BUILD_TYPE" == "development" ]]; then
R2_PATH="s3://${R2_BUCKET}/artifacts/rustfs/dev/"
echo "📤 Uploading development build to R2 dev directory"
else
R2_PATH="s3://${R2_BUCKET}/artifacts/rustfs/staging/${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}/"
echo "📤 Staging release build for certification-gated promotion"
R2_PATH="s3://${R2_BUCKET}/artifacts/rustfs/release/"
echo "📤 Uploading release build to R2 release directory"
fi
# Upload all rustfs zip files to R2 using S3-compatible API
@@ -874,221 +869,6 @@ jobs:
echo "This run does not trigger Docker publishing."
fi
# Aggregate the parent candidate batch. This job always collects results and
# retains its evidence, including on failure, and every publication job
# below requires its success. Missing, stale, substituted or non-PASS
# evidence fails closed here: only the trusted verification sources
# (rustfs/s3chaos release-gate envelopes, rustfs/backlog#2658) can satisfy
# it, so a PR-uploaded JSON set never gains release authority.
release-certification:
name: Release Certification
needs: [ build-check, build-rustfs ]
if: ${{ !cancelled() && needs.build-check.outputs.should_publish == 'true' && startsWith(github.ref, 'refs/tags/') }}
runs-on: ubuntu-latest # gh CLI required; the sm-standard-2 fleet does not ship it
timeout-minutes: 30
permissions:
contents: read
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7
with:
persist-credentials: false
- name: Download all build artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ./artifacts
pattern: rustfs-*
merge-multiple: true
- name: Write candidate and collect trusted validation results
env:
# Cross-repo read of the trusted verification run. Falls back to the
# workflow token, which cannot read rustfs/s3chaos; a missing token
# therefore fail-closes instead of certifying.
GH_TOKEN: ${{ secrets.RELEASE_VALIDATION_TOKEN || github.token }}
PRODUCT_COMMIT: ${{ github.sha }}
VERSION: ${{ needs.build-check.outputs.version }}
BUILD_TYPE: ${{ needs.build-check.outputs.build_type }}
FEATURES: ${{ needs.build-check.outputs.build_type == 'development' && '' || 'pyroscope' }}
shell: bash
run: |
set -euo pipefail
mkdir -p results release-gate-output
PLAN_SHA256=$(python3 -c "import hashlib,json,sys; sys.path.insert(0,'scripts/release'); import release_gate; print(release_gate.canonical_sha256(json.load(open('.config/release-validation-plan.json'))))")
python3 - "$PLAN_SHA256" > candidate.json <<'PY'
import hashlib, json, os, sys, zipfile
plan_sha256 = sys.argv[1]
profile = {"release": "stable", "prerelease": "prerelease", "preview": "preview"}.get(os.environ["BUILD_TYPE"])
if profile is None:
raise SystemExit("release certification only covers preview, prerelease and stable builds")
def sha256(path):
digest = hashlib.sha256()
with open(path, "rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
deliverables = []
for name in sorted(os.listdir("artifacts")):
if not name.startswith("rustfs-") or not name.endswith(".zip"):
continue
path = os.path.join("artifacts", name)
members = zipfile.ZipFile(path).namelist()
binary_name = "rustfs.exe" if "rustfs.exe" in members else "rustfs"
with zipfile.ZipFile(path) as archive:
binary_bytes = archive.read(binary_name)
import tempfile
with tempfile.NamedTemporaryFile() as handle:
handle.write(binary_bytes)
handle.flush()
binary_sha = sha256(handle.name)
deliverables.append({
"kind": "zip",
"name": name,
"location": "https://github.com/rustfs/rustfs/releases/download/{}/{}".format(os.environ["VERSION"], name),
"sha256": sha256(path),
"size": os.path.getsize(path),
"binary_sha256": binary_sha,
})
if not deliverables:
raise SystemExit("no built deliverables found to certify")
candidate = {
"schema_version": 1,
"product_commit": os.environ["PRODUCT_COMMIT"],
"version": os.environ["VERSION"],
"release_profile": profile,
"features": [f for f in os.environ.get("FEATURES", "").split(",") if f],
"plan_sha256": plan_sha256,
"validation_batch": {"run_id": os.environ["GITHUB_RUN_ID"], "run_attempt": int(os.environ["GITHUB_RUN_ATTEMPT"])},
"deliverables": deliverables,
}
json.dump(candidate, sys.stdout, indent=2, sort_keys=True)
print()
PY
# Trusted verification evidence only: the release-gate envelopes of
# rustfs/s3chaos for this exact product commit. Absence blocks below.
TRUSTED_REPO="rustfs/s3chaos"
TRUSTED_WORKFLOW="release-gate.yml"
TRUSTED_RUN=$(gh api "repos/${TRUSTED_REPO}/actions/workflows/${TRUSTED_WORKFLOW}/runs?head_sha=${PRODUCT_COMMIT}&status=success&per_page=1" --jq '.workflow_runs[0].id // empty' || true)
if [[ -z "$TRUSTED_RUN" ]]; then
echo "❌ No trusted verification run of ${TRUSTED_REPO}/${TRUSTED_WORKFLOW} for ${PRODUCT_COMMIT}; refusing to certify" >&2
else
gh run download "$TRUSTED_RUN" -R "$TRUSTED_REPO" -n release-validation-evidence -D results || \
echo "❌ Trusted verification run ${TRUSTED_RUN} published no release-validation-evidence artifact" >&2
fi
python3 scripts/release/release_gate.py validate \
--plan .config/release-validation-plan.json \
--candidate candidate.json \
--results results \
--output release-gate-output
- name: Upload certification evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: release-certification
path: |
candidate.json
results/
release-gate-output/
if-no-files-found: warn
retention-days: 30
# The only writer of the official R2 release path. Promotion re-checks the
# exact bytes about to be published against the passed certification list
# and copies the staged objects byte-for-byte: no rebuild-after-verify.
promote-release-artifacts:
name: Promote Release Artifacts
needs: [ build-check, build-rustfs, release-certification ]
# Target-channel lock for the official R2 release path.
concurrency:
group: release-channel-r2-release
cancel-in-progress: false
if: needs.build-check.outputs.should_publish == 'true' && startsWith(github.ref, 'refs/tags/') && (needs.build-check.outputs.build_type == 'release' || needs.build-check.outputs.build_type == 'prerelease')
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
actions: read
env:
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
AWS_EC2_METADATA_DISABLED: true
steps:
- name: Checkout repository
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7
with:
persist-credentials: false
- name: Download build and certification artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ./artifacts
pattern: rustfs-*
merge-multiple: true
- name: Download certification evidence
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-certification
path: ./certification
- name: Verify and promote staged release artifacts
shell: bash
run: |
set -euo pipefail
if [[ -z "$R2_ACCESS_KEY_ID" || -z "$R2_SECRET_ACCESS_KEY" || -z "$R2_ENDPOINT" || -z "$R2_BUCKET" ]]; then
echo "❌ R2 credentials missing; refusing to promote to the official channel" >&2
exit 1
fi
for zip_file in artifacts/rustfs-*.zip; do
[[ -f "$zip_file" ]] || continue
name="$(basename "$zip_file")"
python3 scripts/release/release_gate.py verify-promotion \
--plan .config/release-validation-plan.json \
--candidate certification/candidate.json \
--summary certification/release-gate-output \
--artifact "$zip_file" \
--artifact-name "$name"
done
if ! command -v aws >/dev/null 2>&1; then
sudo apt-get update && sudo apt-get install -y awscli
fi
export AWS_ACCESS_KEY_ID="$R2_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="$R2_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="auto"
STAGING_PATH="s3://${R2_BUCKET}/artifacts/rustfs/staging/${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}/"
RELEASE_PATH="s3://${R2_BUCKET}/artifacts/rustfs/release/"
for zip_file in artifacts/rustfs-*.zip; do
[[ -f "$zip_file" ]] || continue
name="$(basename "$zip_file")"
staged="$(mktemp)"
aws s3 cp "${STAGING_PATH}${name}" "$staged" --endpoint-url "$R2_ENDPOINT" --only-show-errors
staged_sha="$(sha256sum "$staged" | awk '{print $1}')"
built_sha="$(sha256sum "$zip_file" | awk '{print $1}')"
if [[ "$staged_sha" != "$built_sha" ]]; then
echo "❌ Staged object ${name} does not match the verified bytes" >&2
exit 1
fi
aws s3 cp "$staged" "${RELEASE_PATH}${name}" --endpoint-url "$R2_ENDPOINT" --only-show-errors
rm -f "$staged"
echo "✅ Promoted ${name} (${built_sha})"
done
# Create GitHub Release for every valid release tag, including previews
create-release:
name: Create GitHub Release
@@ -1248,10 +1028,6 @@ jobs:
update-latest-version:
name: Update Latest Version
needs: [ build-check, publish-release ]
# Target-channel lock for the latest.json version pointer.
concurrency:
group: release-channel-oss-latest
cancel-in-progress: false
if: needs.build-check.outputs.should_publish == 'true' && startsWith(github.ref, 'refs/tags/') && (needs.build-check.outputs.build_type == 'release' || needs.build-check.outputs.build_type == 'prerelease')
runs-on: ubuntu-latest
timeout-minutes: 30
@@ -1292,45 +1068,6 @@ jobs:
rm -rf "$OSSUTIL_DIR" "$OSSUTIL_ZIP"
chmod +x "$OSSUTIL_BIN"
# Candidate/pointer ordering: an older candidate must never overwrite
# a newer pointer, even if its promotion job finishes later.
CURRENT_LATEST="${RUNNER_TEMP}/current-latest.json"
if "$OSSUTIL_BIN" cp oss://rustfs-version/latest.json "$CURRENT_LATEST" 2>/dev/null; then
python3 - "$CURRENT_LATEST" "$VERSION" <<'PY'
import json
import re
import sys
def key(version):
match = re.match(r"^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$", version)
if not match:
raise SystemExit(3)
core = tuple(int(part) for part in match.groups()[:3])
prerelease = match.group(4)
if prerelease is None:
return core + (1,)
return core + (0, tuple(int(p) if p.isdigit() else p for p in re.split(r"[.-]", prerelease)))
try:
current = json.load(open(sys.argv[1], encoding="utf-8")).get("version", "")
proposed = sys.argv[2]
if current and key(current) > key(proposed):
raise SystemExit(1)
except SystemExit:
raise
except (OSError, ValueError, TypeError):
raise SystemExit(3)
PY
guard_status=$?
if [[ "$guard_status" -eq 1 ]]; then
echo "Current latest.json points at a newer version; refusing to downgrade" >&2
exit 0
elif [[ "$guard_status" -ne 0 ]]; then
echo "Existing latest.json is unparsable; refusing to overwrite it blindly" >&2
exit 1
fi
fi
# Create latest.json
cat > latest.json << EOF
{
@@ -1347,59 +1084,16 @@ jobs:
echo "✅ Updated latest.json for ${RELEASE_TYPE} release $VERSION"
# Publish release (remove draft status). Requires the release-certification
# aggregate: without a complete legal success there is no public write.
# Publish release (remove draft status)
publish-release:
name: Publish Release
needs: [ build-check, create-release, upload-release-assets, release-certification ]
# Target-channel lock: concurrent releases serialize on this channel so an
# older candidate cannot interleave its publish with a newer one.
concurrency:
group: release-channel-github-release
cancel-in-progress: false
needs: [ build-check, create-release, upload-release-assets ]
if: needs.build-check.outputs.should_publish == 'true' && startsWith(github.ref, 'refs/tags/') && (needs.build-check.outputs.build_type == 'preview' || needs.build-check.outputs.build_type == 'release' || needs.build-check.outputs.build_type == 'prerelease')
runs-on: ubuntu-latest # gh CLI required; the sm-standard-2 fleet does not ship it
timeout-minutes: 30
permissions:
contents: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7
with:
persist-credentials: false
- name: Download certification evidence
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-certification
path: ./certification
- name: Verify release assets against certification
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
TAG="${{ needs.build-check.outputs.version }}"
mkdir -p "$RUNNER_TEMP/promotion-assets"
gh release download "$TAG" --dir "$RUNNER_TEMP/promotion-assets" --pattern '*.zip'
found=0
for zip_file in "$RUNNER_TEMP"/promotion-assets/*.zip; do
[[ -f "$zip_file" ]] || continue
found=1
python3 scripts/release/release_gate.py verify-promotion \
--plan .config/release-validation-plan.json \
--candidate certification/candidate.json \
--summary certification/release-gate-output \
--artifact "$zip_file" \
--artifact-name "$(basename "$zip_file")"
done
if [[ "$found" -ne 1 ]]; then
echo "No release zip assets to verify against the certification" >&2
exit 1
fi
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
+2 -182
View File
@@ -329,75 +329,13 @@ jobs:
echo " - Create latest: $create_latest"
echo " - Source ref: $source_ref"
# Consume the trusted release certification for the exact version this
# workflow wraps and verify the certified input digests. A manual dispatch
# without that certification fails here and pushes no official tag; only
# results from the trusted verification sources carry release authority.
release-certification:
name: Release Certification
needs: build-check
if: needs.build-check.outputs.should_build == 'true'
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7
with:
persist-credentials: false
ref: ${{ needs.build-check.outputs.source_ref }}
- name: Download and verify release certification
env:
GH_TOKEN: ${{ secrets.RELEASE_VALIDATION_TOKEN || github.token }}
TRIGGERING_RUN_ID: ${{ github.event.workflow_run.id }}
VERSION: ${{ needs.build-check.outputs.version }}
shell: bash
run: |
set -euo pipefail
mkdir -p certification
run_id="$TRIGGERING_RUN_ID"
if [[ -z "$run_id" ]]; then
run_id="$(gh api --method GET \
"repos/${GITHUB_REPOSITORY}/actions/workflows/build.yml/runs" \
-f branch="$VERSION" -f status=success -F per_page=1 \
--jq '.workflow_runs[0].id // empty' || true)"
fi
if [[ -z "$run_id" ]]; then
echo "No certified Build and Release run found for ${VERSION}; failing closed" >&2
exit 1
fi
if ! gh run download "$run_id" -n release-certification -D certification; then
echo "Build run ${run_id} published no release-certification artifact; failing closed" >&2
exit 1
fi
python3 scripts/release/release_gate.py verify-promotion \
--plan .config/release-validation-plan.json \
--candidate certification/candidate.json \
--summary certification/release-gate-output \
--artifact-sha256 "$(jq -r '.deliverables[0].sha256' certification/candidate.json)" \
--artifact-name "$(jq -r '.deliverables[0].name' certification/candidate.json)"
# Input digest binding: every zip this image wraps must be the
# certified byte-for-byte content, never a mutable latest pointer.
while IFS=$'\t' read -r name location expected; do
echo "Verifying certified input ${name}"
actual="$(curl -fsSL "$location" | sha256sum | awk '{print $1}')"
if [[ "$actual" != "$expected" ]]; then
echo "Certified input ${name} does not match its recorded digest" >&2
exit 1
fi
done < <(jq -r '.deliverables[] | select(.name | contains("linux")) | [.name, .location, .sha256] | @tsv' certification/candidate.json)
# Build multi-arch Docker images
# Strategy: Build images using pre-built binaries from dl.rustfs.com
# Supports both release and dev channel binaries based on build context
# Only runs when should_build is true (which includes workflow success check)
build-docker:
name: Build Docker Images
needs: [ build-check, release-certification ]
needs: build-check
if: needs.build-check.outputs.should_build == 'true'
runs-on: ubuntu-latest
timeout-minutes: 60
@@ -505,14 +443,6 @@ jobs:
# Output tags
echo "tags=$TAGS" >> "$GITHUB_OUTPUT"
# Staging identity for this run's promotion: official tags are only
# created after the staged image verifies against the certification,
# and they point at this same digest (no rebuild-after-verify).
STAGING_TAG="staging-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}${VARIANT_SUFFIX}"
STAGING_TAGS="${{ env.REGISTRY_DOCKERHUB }}:${STAGING_TAG},${{ env.REGISTRY_GHCR }}:${STAGING_TAG},${{ env.REGISTRY_QUAY }}:${STAGING_TAG}"
echo "staging_tags=$STAGING_TAGS" >> "$GITHUB_OUTPUT"
echo "staging_tag=$STAGING_TAG" >> "$GITHUB_OUTPUT"
# Generate labels
LABELS="org.opencontainers.image.title=RustFS"
LABELS="$LABELS,org.opencontainers.image.description=RustFS distributed object storage system"
@@ -537,9 +467,7 @@ jobs:
file: ${{ matrix.file }}
platforms: ${{ env.DOCKER_PLATFORMS }}
push: ${{ needs.build-check.outputs.should_push == 'true' }}
# Push to staging tags only: official tags are created by the
# certification-gated promotion step below from this same digest.
tags: ${{ steps.meta.outputs.staging_tags }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# No layer cache. This build compiles nothing — it downloads a
# release zip and runs apk/apt — so the cache could only save the
@@ -565,114 +493,6 @@ jobs:
no-cache: false
pull: true
# A later-built wrapper: the staged image must complete this platform's
# own binary identity verification before any official tag is written.
# It may not inherit an unverified package's conclusion.
- name: Verify staged image against certification
if: needs.build-check.outputs.should_push == 'true'
env:
GH_TOKEN: ${{ secrets.RELEASE_VALIDATION_TOKEN || github.token }}
TRIGGERING_RUN_ID: ${{ github.event.workflow_run.id }}
VERSION: ${{ needs.build-check.outputs.version }}
shell: bash
run: |
set -euo pipefail
mkdir -p certification
run_id="$TRIGGERING_RUN_ID"
if [[ -z "$run_id" ]]; then
run_id="$(gh api --method GET \
"repos/${GITHUB_REPOSITORY}/actions/workflows/build.yml/runs" \
-f branch="$VERSION" -f status=success -F per_page=1 \
--jq '.workflow_runs[0].id // empty' || true)"
fi
gh run download "$run_id" -n release-certification -D certification
STAGING_REF="${{ env.REGISTRY_DOCKERHUB }}:staging-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}${{ matrix.suffix }}"
case "${{ matrix.variant }}" in
musl) libc="musl" ;;
glibc) libc="gnu" ;;
esac
for platform in linux/amd64 linux/arm64; do
case "$platform" in
linux/amd64) arch_sub="x86_64" ;;
linux/arm64) arch_sub="aarch64" ;;
esac
docker pull --platform "$platform" "$STAGING_REF"
container="$(docker create --platform "$platform" "$STAGING_REF")"
docker cp "$container:/usr/bin/rustfs" "$RUNNER_TEMP/staged-rustfs"
docker rm "$container" >/dev/null
actual="$(sha256sum "$RUNNER_TEMP/staged-rustfs" | awk '{print $1}')"
expected="$(jq -r --arg needle "linux-${arch_sub}-${libc}" \
'[.deliverables[] | select(.name | contains($needle)) | .binary_sha256][0] // empty' \
certification/candidate.json)"
if [[ -z "$expected" || "$actual" != "$expected" ]]; then
echo "Staged image binary for ${platform} does not match the certified binary digest" >&2
exit 1
fi
python3 scripts/release/release_gate.py verify-promotion \
--plan .config/release-validation-plan.json \
--candidate certification/candidate.json \
--summary certification/release-gate-output \
--artifact "$RUNNER_TEMP/staged-rustfs" \
--artifact-role binary
done
- name: Promote staged image to official tags
if: needs.build-check.outputs.should_push == 'true'
shell: bash
run: |
set -euo pipefail
STAGING_REF="${{ env.REGISTRY_DOCKERHUB }}:staging-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}${{ matrix.suffix }}"
IFS=',' read -r -a official_tags <<< "${{ steps.meta.outputs.tags }}"
for tag in "${official_tags[@]}"; do
docker buildx imagetools create -t "$tag" "$STAGING_REF"
echo "Promoted $tag -> $STAGING_REF"
done
# Downstream consumers (Helm) verify this record instead of inheriting
# an unverified wrapper's conclusion.
- name: Record image promotion
if: needs.build-check.outputs.should_push == 'true'
shell: bash
env:
GH_TOKEN: ${{ secrets.RELEASE_VALIDATION_TOKEN || github.token }}
TRIGGERING_RUN_ID: ${{ github.event.workflow_run.id }}
VERSION: ${{ needs.build-check.outputs.version }}
run: |
set -euo pipefail
mkdir -p certification
run_id="$TRIGGERING_RUN_ID"
if [[ -z "$run_id" ]]; then
run_id="$(gh api --method GET \
"repos/${GITHUB_REPOSITORY}/actions/workflows/build.yml/runs" \
-f branch="$VERSION" -f status=success -F per_page=1 \
--jq '.workflow_runs[0].id // empty' || true)"
fi
gh run download "$run_id" -n release-certification -D certification
STAGING_REF="${{ env.REGISTRY_DOCKERHUB }}:staging-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}${{ matrix.suffix }}"
digest="$(docker buildx imagetools inspect "$STAGING_REF" --format '{{json .Manifest}}' | jq -r '.digest')"
candidate_sha="$(python3 -c "import json,hashlib,sys; sys.path.insert(0,'scripts/release'); import release_gate; print(release_gate.canonical_sha256(json.load(open('certification/candidate.json'))))")"
jq -n \
--arg version "$VERSION" \
--arg digest "$digest" \
--arg staging_ref "$STAGING_REF" \
--arg candidate_sha256 "$candidate_sha" \
--arg tags "${{ steps.meta.outputs.tags }}" \
--slurpfile candidate certification/candidate.json \
'{schema_version: 1, version: $version, image_digest: $digest, staging_ref: $staging_ref,
promoted_tags: ($tags | split(",")), candidate_sha256: $candidate_sha256,
binary_sha256s: ($candidate[0].deliverables | map(.binary_sha256) | unique)}' \
> image-promotion-record.json
- name: Upload image promotion record
if: needs.build-check.outputs.should_push == 'true'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: image-promotion-record${{ matrix.suffix }}
path: image-promotion-record.json
if-no-files-found: error
retention-days: 30
# Note: Manifest creation is no longer needed as we only build one variant
# Multi-arch manifests are automatically created by docker/build-push-action
-93
View File
@@ -30,102 +30,9 @@ permissions:
contents: read
jobs:
# Consume the same trusted release certification as every other publication
# exit and verify the image promotion record of the Docker workflow. The
# chart wraps no binary of its own, so it may only reference an image whose
# platform verification already passed; it must not inherit an unverified
# package's conclusion. A run without that evidence fails closed here and
# never reaches the chart repository.
release-certification:
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: read
actions: read
outputs:
version: ${{ steps.version.outputs.raw_tag }}
steps:
- name: Checkout repository
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7
with:
persist-credentials: false
- name: Normalize release version
id: version
env:
RAW_INPUT: ${{ github.event.inputs.version }}
RAW_BRANCH: ${{ github.event.workflow_run.head_branch }}
run: |
set -euo pipefail
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
RAW="$RAW_INPUT"
else
RAW="$RAW_BRANCH"
fi
case "$RAW" in
refs/tags/*) RAW_TAG="${RAW#refs/tags/}" ;;
*) RAW_TAG="$RAW" ;;
esac
echo "raw_tag=$RAW_TAG" >> "$GITHUB_OUTPUT"
- name: Download and verify release certification and image record
env:
GH_TOKEN: ${{ secrets.RELEASE_VALIDATION_TOKEN || github.token }}
TRIGGERING_RUN_ID: ${{ github.event.workflow_run.id }}
RAW_TAG: ${{ steps.version.outputs.raw_tag }}
shell: bash
run: |
set -euo pipefail
mkdir -p certification image-record
build_run="$TRIGGERING_RUN_ID"
if [[ -z "$build_run" ]]; then
build_run="$(gh api --method GET \
"repos/${GITHUB_REPOSITORY}/actions/workflows/build.yml/runs" \
-f branch="$RAW_TAG" -f status=success -F per_page=1 \
--jq '.workflow_runs[0].id // empty' || true)"
fi
if [[ -z "$build_run" ]]; then
echo "No certified Build and Release run found for ${RAW_TAG}; failing closed" >&2
exit 1
fi
if ! gh run download "$build_run" -n release-certification -D certification; then
echo "Build run ${build_run} published no release-certification artifact; failing closed" >&2
exit 1
fi
python3 scripts/release/release_gate.py verify-promotion \
--plan .config/release-validation-plan.json \
--candidate certification/candidate.json \
--summary certification/release-gate-output \
--artifact-sha256 "$(jq -r '.deliverables[0].sha256' certification/candidate.json)" \
--artifact-name "$(jq -r '.deliverables[0].name' certification/candidate.json)"
docker_run="$(gh api --method GET \
"repos/${GITHUB_REPOSITORY}/actions/workflows/docker.yml/runs" \
-f branch="$RAW_TAG" -f status=success -F per_page=1 \
--jq '.workflow_runs[0].id // empty' || true)"
if [[ -z "$docker_run" ]] || ! gh run download "$docker_run" -n image-promotion-record -D image-record; then
echo "No image promotion record for ${RAW_TAG}; a chart may not wrap an unverified image" >&2
exit 1
fi
candidate_sha="$(python3 -c "import json,hashlib,sys; sys.path.insert(0,'scripts/release'); import release_gate; print(release_gate.canonical_sha256(json.load(open('certification/candidate.json'))))")"
record_sha="$(jq -r '.candidate_sha256 // empty' image-record/image-promotion-record.json)"
if [[ "$record_sha" != "$candidate_sha" ]]; then
echo "Image promotion record does not belong to this certification" >&2
exit 1
fi
overlap="$(jq -r --slurpfile candidate certification/candidate.json \
'[.binary_sha256s[]] - ($candidate[0].deliverables | map(.binary_sha256)) | length' \
image-record/image-promotion-record.json)"
if [[ "$overlap" -ne 0 ]]; then
echo "Image promotion record carries binary digests outside the certification" >&2
exit 1
fi
build-helm-package:
runs-on: ubuntu-latest
timeout-minutes: 30
needs: [ release-certification ]
if: |
(github.event_name == 'workflow_dispatch' && !contains(github.event.inputs.version, '-preview')) ||
(
+14 -210
View File
@@ -225,57 +225,10 @@ jobs:
echo " Build run ID: $BUILD_RUN_ID"
echo " Build run number: $RUN_NUMBER"
# Consume the trusted release certification of the resolved build run and
# verify the certified input digests before any package is wrapped. A run
# without that certification fails closed here; packages built later must
# complete their own verification and cannot inherit an unverified
# conclusion.
release-certification:
name: Release Certification
needs: resolve
if: needs.resolve.result == 'success'
runs-on: ubuntu-latest # gh CLI required; the sm-standard-2 fleet does not ship it
timeout-minutes: 30
permissions:
contents: read
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7
with:
persist-credentials: false
- name: Download and verify release certification
env:
GH_TOKEN: ${{ secrets.RELEASE_VALIDATION_TOKEN || github.token }}
BUILD_RUN_ID: ${{ needs.resolve.outputs.build_run_id }}
BUILD_TYPE: ${{ needs.resolve.outputs.build_type }}
shell: bash
run: |
set -euo pipefail
mkdir -p certification
if [[ "$BUILD_TYPE" == "development" ]]; then
# Development artifacts are explicitly uncertified and never touch
# official or latest channels; only the staging/dev paths remain.
jq -n '{schema_version: 1, certified: false, reason: "development artifacts are explicitly uncertified"}' \
> certification/development-uncertified.json
exit 0
fi
if ! gh run download "$BUILD_RUN_ID" -n release-certification -D certification; then
echo "Build run ${BUILD_RUN_ID} published no release-certification artifact; failing closed" >&2
exit 1
fi
python3 scripts/release/release_gate.py verify-promotion \
--plan .config/release-validation-plan.json \
--candidate certification/candidate.json \
--summary certification/release-gate-output \
--artifact-sha256 "$(jq -r '.deliverables[0].sha256' certification/candidate.json)" \
--artifact-name "$(jq -r '.deliverables[0].name' certification/candidate.json)"
# Build DEB and RPM packages for each architecture and libc variant
package:
name: Package (${{ matrix.arch }}-${{ matrix.libc }})
needs: [ resolve, release-certification ]
needs: resolve
runs-on: ubuntu-latest # gh CLI required; the sm-standard-2 fleet does not ship it
timeout-minutes: 30
strategy:
@@ -541,55 +494,6 @@ jobs:
echo "rpm_file=$RPM_FILE" >> "$GITHUB_OUTPUT"
echo "✅ RPM built: $RPM_FILE"
- name: Download certification evidence
if: needs.resolve.outputs.build_type != 'development'
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-certification
path: ./certification
# Later-built wrapper verification: the binary inside each package must
# match the certified binary digest for this platform before anything is
# uploaded, and the package itself stays on staging until promotion.
- name: Verify wrapped binary against certification
if: needs.resolve.outputs.build_type != 'development'
shell: bash
env:
DEB_FILE: ${{ steps.deb.outputs.deb_file }}
RPM_FILE: ${{ steps.rpm.outputs.rpm_file }}
ARTIFACT_NAME: ${{ matrix.artifact_name }}
run: |
set -euo pipefail
expected="$(jq -r --arg needle "$ARTIFACT_NAME" \
'[.deliverables[] | select(.name | contains($needle)) | .binary_sha256][0] // empty' \
certification/candidate.json)"
if [[ -z "$expected" ]]; then
echo "No certified binary digest recorded for ${ARTIFACT_NAME}" >&2
exit 1
fi
if ! command -v rpm2cpio >/dev/null 2>&1; then
sudo apt-get update && sudo apt-get install -y rpm2cpio
fi
if ! command -v cpio >/dev/null 2>&1; then
sudo apt-get update && sudo apt-get install -y cpio
fi
for package_file in "$DEB_FILE" "$RPM_FILE"; do
case "$package_file" in
*.deb)
dpkg-deb --fsys-tarfile "$package_file" | tar -xOf - ./usr/bin/rustfs > "$RUNNER_TEMP/wrapped-rustfs"
;;
*.rpm)
rpm2cpio "$package_file" | cpio -i --to-stdout ./usr/bin/rustfs > "$RUNNER_TEMP/wrapped-rustfs"
;;
esac
python3 scripts/release/release_gate.py verify-promotion \
--plan .config/release-validation-plan.json \
--candidate certification/candidate.json \
--summary certification/release-gate-output \
--artifact "$RUNNER_TEMP/wrapped-rustfs" \
--artifact-role binary
done
- name: Upload packages to artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
@@ -627,14 +531,10 @@ jobs:
export AWS_SECRET_ACCESS_KEY="$R2_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="auto"
# Build-phase writes stay on staging for release types: the official
# packages/release and packages/latest paths are written only by the
# certification-gated promote-packages job, from these same staged
# objects. Development packages keep the uncertified dev channel.
if [[ "$BUILD_TYPE" == "development" ]]; then
R2_PREFIX="artifacts/rustfs/packages/dev"
else
R2_PREFIX="artifacts/rustfs/packages/staging/${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}"
R2_PREFIX="artifacts/rustfs/packages/release"
fi
R2_PATH="s3://${R2_BUCKET}/${R2_PREFIX}/"
@@ -649,6 +549,18 @@ jobs:
echo "✅ Upload complete"
# Also upload as latest for release/prerelease
if [[ "$BUILD_TYPE" == "release" || "$BUILD_TYPE" == "prerelease" ]]; then
LATEST_PATH="s3://${R2_BUCKET}/artifacts/rustfs/packages/latest/"
for f in "$DEB_FILE" "$RPM_FILE"; do
if [[ -n "$f" && -f "$f" ]]; then
echo "Uploading latest: $(basename "$f")"
aws s3 cp "$f" "$LATEST_PATH" --endpoint-url "$R2_ENDPOINT" --only-show-errors
fi
done
echo "✅ Latest packages updated"
fi
- name: Upload packages to GitHub Release
if: needs.resolve.outputs.tag != ''
env:
@@ -702,114 +614,6 @@ jobs:
echo "✅ GitHub release assets updated"
# The only writer of the official packages/release and packages/latest R2
# paths. Promotion re-checks each package's wrapped binary against the
# passed certification list and copies the staged objects byte-for-byte:
# no rebuild-after-verify, no mutable latest resolution downstream.
promote-packages:
name: Promote Packages
needs: [ resolve, package, release-certification ]
# Target-channel lock for the official package paths.
concurrency:
group: release-channel-r2-packages
cancel-in-progress: false
if: needs.resolve.outputs.tag != '' && (needs.resolve.outputs.build_type == 'release' || needs.resolve.outputs.build_type == 'prerelease')
runs-on: ubuntu-latest # gh CLI required; the sm-standard-2 fleet does not ship it
timeout-minutes: 30
permissions:
contents: read
actions: read
env:
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
R2_ENDPOINT: ${{ secrets.R2_ENDPOINT }}
R2_BUCKET: ${{ secrets.R2_BUCKET }}
AWS_EC2_METADATA_DISABLED: true
steps:
- name: Checkout repository
uses: actions/checkout@f548e57e544e1ff5a4c46bf1e1b8685f8e4a348a # v7
with:
persist-credentials: false
- name: Download packages and certification
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
path: ./packages
pattern: packages-*
merge-multiple: true
- name: Download certification evidence
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: release-certification
path: ./certification
- name: Verify and promote staged packages
shell: bash
run: |
set -euo pipefail
if [[ -z "$R2_ACCESS_KEY_ID" || -z "$R2_SECRET_ACCESS_KEY" || -z "$R2_ENDPOINT" || -z "$R2_BUCKET" ]]; then
echo "❌ R2 credentials missing; refusing to promote to the official channel" >&2
exit 1
fi
STAGING_PREFIX="s3://${R2_BUCKET}/artifacts/rustfs/packages/staging/${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}/"
RELEASE_PATH="s3://${R2_BUCKET}/artifacts/rustfs/packages/release/"
LATEST_PATH="s3://${R2_BUCKET}/artifacts/rustfs/packages/latest/"
if ! command -v aws >/dev/null 2>&1; then
sudo apt-get update && sudo apt-get install -y awscli
fi
export AWS_ACCESS_KEY_ID="$R2_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="$R2_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="auto"
if ! command -v rpm2cpio >/dev/null 2>&1; then
sudo apt-get install -y rpm2cpio
fi
if ! command -v cpio >/dev/null 2>&1; then
sudo apt-get install -y cpio
fi
promoted=0
for package_file in packages/*.deb packages/*.rpm; do
[[ -f "$package_file" ]] || continue
name="$(basename "$package_file")"
case "$package_file" in
*.deb)
dpkg-deb --fsys-tarfile "$package_file" | tar -xOf - ./usr/bin/rustfs > "$RUNNER_TEMP/wrapped-rustfs"
;;
*.rpm)
rpm2cpio "$package_file" | cpio -i --to-stdout ./usr/bin/rustfs > "$RUNNER_TEMP/wrapped-rustfs"
;;
esac
python3 scripts/release/release_gate.py verify-promotion \
--plan .config/release-validation-plan.json \
--candidate certification/candidate.json \
--summary certification/release-gate-output \
--artifact "$RUNNER_TEMP/wrapped-rustfs" \
--artifact-role binary
staged="$(mktemp)"
aws s3 cp "${STAGING_PREFIX}${name}" "$staged" --endpoint-url "$R2_ENDPOINT" --only-show-errors
staged_sha="$(sha256sum "$staged" | awk '{print $1}')"
built_sha="$(sha256sum "$package_file" | awk '{print $1}')"
if [[ "$staged_sha" != "$built_sha" ]]; then
echo "❌ Staged package ${name} does not match the verified bytes" >&2
exit 1
fi
aws s3 cp "$staged" "${RELEASE_PATH}${name}" --endpoint-url "$R2_ENDPOINT" --only-show-errors
aws s3 cp "$staged" "${LATEST_PATH}${name}" --endpoint-url "$R2_ENDPOINT" --only-show-errors
rm -f "$staged"
promoted=$((promoted + 1))
echo "✅ Promoted ${name} (${built_sha})"
done
if [[ "$promoted" -eq 0 ]]; then
echo "No staged packages found to promote" >&2
exit 1
fi
# Summary
summary:
name: Summary
+56 -137
View File
@@ -579,7 +579,6 @@ struct PreparedPartTxnReceipt {
dst_meta_path: PathBuf,
transaction_path: PathBuf,
meta: Bytes,
had_old_data: bool,
had_old_meta: bool,
}
@@ -587,7 +586,6 @@ struct PublishedPartTxnReceipt {
current_data_path: PathBuf,
current_meta_path: PathBuf,
transaction_path: PathBuf,
had_old_data: bool,
had_old_meta: bool,
}
@@ -11504,17 +11502,9 @@ impl LocalDisk {
admission: Option<multipart_staging::MultipartSourceAdmission>,
) -> Result<()> {
multipart_staging::reject_reserved_anchor(path)?;
let fuse_with_admission = admission.is_some() && !crash_inject::is_armed(CrashPoint::MetaWriteAfterTmpBeforeRename, path);
let prepared_index = if volume == RUSTFS_META_MULTIPART_BUCKET {
if fuse_with_admission {
self.multipart_index.prepare_record_head(path, &buf).await
} else {
self.multipart_index.record_head(path, &buf).await?;
None
}
} else {
None
};
if volume == RUSTFS_META_MULTIPART_BUCKET {
self.multipart_index.record_head(path, &buf).await?;
}
let volume_dir = self.io_get_bucket_path(volume)?;
let file_path = self.io_get_object_path(volume, path)?;
check_path_length(file_path.to_string_lossy().as_ref())?;
@@ -11530,14 +11520,11 @@ impl LocalDisk {
{
multipart_source_state::invalidate_active_multipart_source_head(admission.source());
}
if fuse_with_admission {
if admission.is_some() && !crash_inject::is_armed(CrashPoint::MetaWriteAfterTmpBeforeRename, path) {
let precondition = admission.as_ref().map(|a| a.precondition());
let root = self.publication_root.clone();
let lease = os::acquire_namespace_mutation_lease_with_owner(&file_path, namespace_owner).await;
os::run_blocking_namespace_operation_with_sync(lease, do_sync, move || {
if let Some(record) = prepared_index {
record.run_std()?;
}
super::fs::create_dir_all_std(&tmp_volume_dir)?;
#[cfg(test)]
run_owned_file_before_open(&tmp_file_path);
@@ -14438,7 +14425,6 @@ impl DiskAPI for LocalDisk {
if bucket == RUSTFS_META_MULTIPART_BUCKET && !paths.is_empty() {
let mut cached_parts = Vec::with_capacity(paths.len());
let mut all_cached = true;
let mut verified_source: Option<(&str, PathBuf)> = None;
for path_str in paths {
let Some(num) = Path::new(path_str)
.file_name()
@@ -14450,24 +14436,15 @@ impl DiskAPI for LocalDisk {
all_cached = false;
break;
};
let scope_root = multipart_staging::upload_scope_root(path_str, true);
let (source, head_already_verified) = match verified_source.as_ref() {
Some((prev_root, prev_source)) if *prev_root == scope_root => (prev_source, true),
_ => {
let Ok(source) = self.io_get_object_open_path(bucket, scope_root) else {
all_cached = false;
break;
};
verified_source = Some((scope_root, source));
(&verified_source.as_ref().expect("just initialized").1, false)
}
};
let Some(part) =
multipart_source_state::get_active_multipart_source_part_with_head(source, num, head_already_verified)
let Ok(source) = self.io_get_object_open_path(bucket, multipart_staging::upload_scope_root(path_str, true))
else {
all_cached = false;
break;
};
let Some(part) = multipart_source_state::get_active_multipart_source_part(&source, num) else {
all_cached = false;
break;
};
cached_parts.push(part);
}
if all_cached {
@@ -14648,7 +14625,6 @@ impl DiskAPI for LocalDisk {
Ok(_) => return Ok(Err(DiskError::FileAccessDenied)),
Err(err) => return Ok(Err(to_file_error(err).into())),
}
let mut created_transaction_parent = false;
if let Some((integrity, source, destination, expected_len)) = integrity_prep {
let stat = match std::fs::symlink_metadata(&source) {
Ok(stat) => stat,
@@ -14657,7 +14633,6 @@ impl DiskAPI for LocalDisk {
if !stat.is_file() || stat.len() != expected_len {
return Ok(Err(DiskError::FileCorrupt));
}
let presynced_proof = take_presynced_tmp_file(&source);
let verify_and_sync = (|| -> std::io::Result<bool> {
let mut file = os::open_file_for_sync_std(&source)?;
let mut header = [0u8; rustfs_filemeta::shard_integrity::INDEX_HEADER_SIZE];
@@ -14665,7 +14640,7 @@ impl DiskAPI for LocalDisk {
if header != integrity.index_header() {
return Ok(false);
}
if durability.syncs_data_shards() && !presynced_proof {
if durability.syncs_data_shards() && !take_presynced_tmp_file(&source) {
file.sync_all()?;
}
Ok(true)
@@ -14675,13 +14650,7 @@ impl DiskAPI for LocalDisk {
Ok(false) => return Ok(Err(DiskError::FileCorrupt)),
Err(err) => return Ok(Err(to_file_error(err).into())),
}
#[cfg(all(any(test, feature = "test-util"), not(windows)))]
let has_hooks = os::prepared_publication_test_hooks::has_any_hooks();
#[cfg(not(all(any(test, feature = "test-util"), not(windows))))]
let has_hooks = false;
let precondition = has_hooks
.then(|| admission.as_ref().map(|check| check.precondition()))
.flatten();
let precondition = admission.as_ref().map(|check| check.precondition());
// Publish the immutable generation before preparing the part switch.
// Rollback retains the old generation; an unreferenced new index is
// reclaimed with the upload directory if preparation is interrupted.
@@ -14698,13 +14667,12 @@ impl DiskAPI for LocalDisk {
) {
return Ok(Err(to_file_error(err).into()));
}
created_transaction_parent = same_parent;
}
let Some(transaction_parent) = transaction_path.parent() else {
return Ok(Err(DiskError::InvalidPath));
};
if !created_transaction_parent && let Err(err) = std::fs::create_dir_all(transaction_parent) {
if let Err(err) = std::fs::create_dir_all(transaction_parent) {
return Ok(Err(to_file_error(err).into()));
}
let staging_path = transaction_parent.join(format!(".part-txn-{}", Uuid::new_v4()));
@@ -14712,35 +14680,17 @@ impl DiskAPI for LocalDisk {
return Ok(Err(to_file_error(err).into()));
}
let prepare_result = (|| -> std::io::Result<(bool, bool)> {
let old_data_absent = staging_path.join(PART_TRANSACTION_OLD_DATA_ABSENT);
let old_meta_absent = staging_path.join(PART_TRANSACTION_OLD_META_ABSENT);
let prepare_result = (|| -> std::io::Result<bool> {
let had_old_data = snapshot_part_transaction_file(
&dst_file_path,
&staging_path.join(PART_TRANSACTION_OLD_DATA),
&old_data_absent,
&staging_path.join(PART_TRANSACTION_OLD_DATA_ABSENT),
)?;
let had_old_meta = snapshot_part_transaction_file(
&dst_meta_path,
&staging_path.join(PART_TRANSACTION_OLD_META),
&staging_path.join(PART_TRANSACTION_OLD_META_ABSENT),
)?;
let had_old_meta = match std::fs::symlink_metadata(&dst_meta_path) {
Ok(metadata) if metadata.is_file() => {
std::fs::hard_link(&dst_meta_path, staging_path.join(PART_TRANSACTION_OLD_META))?;
true
}
Ok(metadata) if metadata.file_type().is_symlink() => {
return Err(std::io::Error::new(ErrorKind::InvalidInput, "multipart transaction source is a symlink"));
}
Ok(_) => {
return Err(std::io::Error::new(ErrorKind::InvalidData, "multipart transaction source is not a file"));
}
Err(err) if err.kind() == ErrorKind::NotFound => {
if !had_old_data && std::fs::hard_link(&old_data_absent, &old_meta_absent).is_ok() {
false
} else {
std::fs::write(&old_meta_absent, [])?;
false
}
}
Err(err) => return Err(err),
};
let new_meta_path = staging_path.join(PART_TRANSACTION_NEW_META);
let mut new_meta = std::fs::OpenOptions::new()
@@ -14763,11 +14713,11 @@ impl DiskAPI for LocalDisk {
if sync_overwrite_backup {
os::fsync_dir_std(transaction_parent)?;
}
Ok((had_old_data, had_old_meta))
Ok(had_old_meta)
})();
let (had_old_data, had_old_meta) = match prepare_result {
Ok(flags) => flags,
let had_old_meta = match prepare_result {
Ok(had_old_meta) => had_old_meta,
Err(err) => {
let _ = remove_dir_all_if_exists(&staging_path);
return Ok(Err(to_file_error(err).into()));
@@ -14783,7 +14733,6 @@ impl DiskAPI for LocalDisk {
dst_meta_path,
transaction_path: transaction_path.clone(),
meta,
had_old_data,
had_old_meta,
},
);
@@ -14810,25 +14759,23 @@ impl DiskAPI for LocalDisk {
.io_get_object_open_path(volume, &txn_rel_path)
.ok()
.and_then(|txn_open| take_published_part_txn_receipt(&txn_open));
let (current_data_path, current_meta_path, transaction_path, skip_obsolete_read_on_commit, cached_old_flags) =
match cached_published {
Some(entry) => (
entry.current_data_path,
entry.current_meta_path,
entry.transaction_path,
!entry.had_old_meta,
Some((entry.had_old_data, entry.had_old_meta)),
),
None => {
let (_, current_data_path) = self.io_get_bucket_and_object_path(volume, path)?;
let current_meta_path = self.io_get_object_path(volume, &format!("{path}.meta"))?;
let transaction_path = self.io_get_object_path(volume, &txn_rel_path)?;
for candidate in [&current_data_path, &current_meta_path, &transaction_path] {
check_path_length(candidate.to_string_lossy().as_ref())?;
}
(current_data_path, current_meta_path, transaction_path, false, None)
let (current_data_path, current_meta_path, transaction_path, skip_obsolete_read_on_commit) = match cached_published {
Some(entry) => (
entry.current_data_path,
entry.current_meta_path,
entry.transaction_path,
!entry.had_old_meta,
),
None => {
let (_, current_data_path) = self.io_get_bucket_and_object_path(volume, path)?;
let current_meta_path = self.io_get_object_path(volume, &format!("{path}.meta"))?;
let transaction_path = self.io_get_object_path(volume, &txn_rel_path)?;
for candidate in [&current_data_path, &current_meta_path, &transaction_path] {
check_path_length(candidate.to_string_lossy().as_ref())?;
}
};
(current_data_path, current_meta_path, transaction_path, false)
}
};
let durability = effective_durability(volume);
let sync = durability.syncs_commit_metadata();
let part_number = current_data_path
@@ -14927,26 +14874,7 @@ impl DiskAPI for LocalDisk {
{
return Ok(Err(to_file_error(err).into()));
}
if let Some((had_old_data, had_old_meta)) = cached_old_flags.filter(|_| action == PartTransactionAction::Commit) {
let old_data_name = if had_old_data {
PART_TRANSACTION_OLD_DATA
} else {
PART_TRANSACTION_OLD_DATA_ABSENT
};
let old_meta_name = if had_old_meta {
PART_TRANSACTION_OLD_META
} else {
PART_TRANSACTION_OLD_META_ABSENT
};
for name in [PART_TRANSACTION_NEW_META, old_data_name, old_meta_name] {
let _ = std::fs::remove_file(cleanup_path.join(name));
}
if std::fs::remove_dir(&cleanup_path).is_err()
&& let Err(err) = remove_dir_all_if_exists(&cleanup_path)
{
return Ok(Err(to_file_error(err).into()));
}
} else if let Err(err) = remove_dir_all_if_exists(&cleanup_path) {
if let Err(err) = remove_dir_all_if_exists(&cleanup_path) {
return Ok(Err(to_file_error(err).into()));
}
Ok(Ok(true))
@@ -15018,7 +14946,7 @@ impl DiskAPI for LocalDisk {
dst_file_path,
dst_meta_path,
transaction_path,
preverified_meta_and_old_flags,
preverified_meta_and_old_flag,
) = match cached_prepared {
Some(entry) => (
entry.src_volume_dir,
@@ -15027,7 +14955,7 @@ impl DiskAPI for LocalDisk {
entry.dst_file_path,
Some(entry.dst_meta_path),
Some(entry.transaction_path),
Some((entry.had_old_data, entry.had_old_meta)),
Some(entry.had_old_meta),
),
None => {
let (src_volume_dir, src_file_path) = self.io_get_bucket_and_object_path(src_volume, src_path)?;
@@ -15124,7 +15052,7 @@ impl DiskAPI for LocalDisk {
let transaction_meta_path = transaction_path.join(PART_TRANSACTION_NEW_META);
let publish_meta_path = transaction_path.join(PART_TRANSACTION_PUBLISH_META);
if !cfg!(test)
&& preverified_meta_and_old_flags.is_some()
&& preverified_meta_and_old_flag.is_some()
&& publish_meta_path.is_file()
&& std::fs::metadata(&transaction_meta_path).is_ok_and(|m| m.is_file() && m.len() == meta.len() as u64)
{
@@ -15168,13 +15096,7 @@ impl DiskAPI for LocalDisk {
os::sync_file(&src_file_path).map_err(to_file_error)?;
}
#[cfg(all(any(test, feature = "test-util"), not(windows)))]
let has_hooks = os::prepared_publication_test_hooks::has_any_hooks();
#[cfg(not(all(any(test, feature = "test-util"), not(windows))))]
let has_hooks = false;
let precondition = has_hooks
.then(|| admission.as_ref().map(|check| check.precondition()))
.flatten();
let precondition = admission.as_ref().map(|check| check.precondition());
os::rename_all_with_precondition_and_parent_sync_std(
&src_file_path,
@@ -15186,19 +15108,17 @@ impl DiskAPI for LocalDisk {
)
.map_err(to_file_error)?;
if cfg!(test) || src_is_dir {
let dst_meta = lstat_std(&dst_file_path).map_err(to_file_error)?;
if src_is_dir != dst_meta.is_dir() {
warn!(
event = EVENT_DISK_LOCAL_RENAME_REJECTED,
component = LOG_COMPONENT_ECSTORE,
subsystem = LOG_SUBSYSTEM_DISK_LOCAL,
reason = "dst_type_changed_after_rename",
path = ?dst_file_path,
"Disk local rename rejected"
);
return Err(DiskError::FileAccessDenied.into());
}
let dst_meta = lstat_std(&dst_file_path).map_err(to_file_error)?;
if src_is_dir != dst_meta.is_dir() {
warn!(
event = EVENT_DISK_LOCAL_RENAME_REJECTED,
component = LOG_COMPONENT_ECSTORE,
subsystem = LOG_SUBSYSTEM_DISK_LOCAL,
reason = "dst_type_changed_after_rename",
path = ?dst_file_path,
"Disk local rename rejected"
);
return Err(DiskError::FileAccessDenied.into());
}
if let Some(transaction_publish_meta) = transaction_publish_meta {
@@ -15229,8 +15149,8 @@ impl DiskAPI for LocalDisk {
}
}
}
if let (Some((had_old_data, had_old_meta)), Some(txn_path), Some(meta_path)) =
(preverified_meta_and_old_flags, transaction_path.as_ref(), dst_meta_path.as_path().into())
if let (Some(had_old_meta), Some(txn_path), Some(meta_path)) =
(preverified_meta_and_old_flag, transaction_path.as_ref(), dst_meta_path.as_path().into())
{
put_published_part_txn_receipt(
txn_path,
@@ -15238,7 +15158,6 @@ impl DiskAPI for LocalDisk {
current_data_path: dst_file_path,
current_meta_path: meta_path.to_path_buf(),
transaction_path: txn_path.clone(),
had_old_data,
had_old_meta,
},
);
+1 -6
View File
@@ -1461,12 +1461,7 @@ impl LocalDisk {
}
}
}
match publication_owned.finish_on_thread(
sync_commit_metadata,
!cfg!(test),
staging_cleanup,
Some(&directory_guard_owned),
) {
match publication_owned.finish_on_thread(sync_commit_metadata, !cfg!(test), staging_cleanup) {
Ok(result) => Ok(MultipartFusedCommitOutcome::Committed(Box::new(RenameDataResp {
multipart_source: Some(Box::new(result)),
old_data_dir: has_old_data_dir,
@@ -1829,9 +1829,7 @@ impl LocalDisk {
) -> Result<DeleteRecoveryInspection> {
self.reject_multipart_delete_recovery_mutation(volume, object)?;
if let Ok(root) = self.io_get_object_path(volume, object) {
let tx_dir = root.join(transaction.to_string());
let _ = take_prepared_delete_receipt(&tx_dir);
let _ = take_published_delete_receipt(&tx_dir);
let _ = take_prepared_delete_receipt(&root.join(transaction.to_string()));
}
let (mut observed, mut has_data_dir_work) = self
@@ -2495,8 +2493,8 @@ impl LocalDisk {
Err(err) if err.kind() == ErrorKind::NotFound => return Ok(Ok(None)),
Err(err) => return Err(err),
};
type PreparedDeleteTuple = (Option<Uuid>, Option<Vec<u8>>, Vec<u8>, DeleteRecoveryJournal, bool, bool, bool);
let (old_dir, target, journal_raw, journal, sole_transaction, destination_missing, old_data_dir_present) =
type PreparedDeleteTuple = (Option<Uuid>, Option<Vec<u8>>, Vec<u8>, DeleteRecoveryJournal, bool);
let (old_dir, target, journal_raw, journal, sole_transaction) =
match (|| -> Result<Option<PreparedDeleteTuple>> {
let mut meta = FileMeta::load(&buf)?;
let mut deleted_headers: Vec<_> = meta
@@ -2531,11 +2529,7 @@ impl LocalDisk {
let target = (!meta.versions.is_empty()).then(|| meta.marshal_msg()).transpose()?;
let mut predecessors = BTreeSet::new();
let mut sole_transaction = true;
let mut destination_exists = false;
let mut old_data_dir_exists = false;
let mut scanned_file_path = false;
if let Ok(entries) = std::fs::read_dir(&file_path) {
scanned_file_path = true;
for (visited, entry) in
recovery_entries(entries, recovery_scope.as_ref().map(|scope| scope.budget.as_ref())).enumerate()
{
@@ -2548,19 +2542,13 @@ impl LocalDisk {
sole_transaction = false;
continue;
};
let Some(id) = Uuid::parse_str(name_str).ok().filter(|id| !id.is_nil()) else {
let Some(id) = Uuid::parse_str(name_str).ok().filter(|id| !id.is_nil() && *id != transaction)
else {
continue;
};
if id == transaction {
destination_exists = true;
continue;
}
if !entry.file_type().map_err(to_file_error)?.is_dir() {
return Err(DiskError::InvalidPath);
}
if old_dir == Some(id) && name_str == id.hyphenated().to_string() {
old_data_dir_exists = true;
}
let dir_path = entry.path();
let prepared = regular_bytes(&dir_path.join(PREPARED))?;
let receipt = regular_bytes(&dir_path.join(DELETE_QUORUM_COMMITTED_FILE))?;
@@ -2619,15 +2607,7 @@ impl LocalDisk {
predecessors: predecessors.into_iter().collect(),
};
let raw = journal_bytes(&journal)?;
Ok(Some((
old_dir,
target,
raw,
journal,
sole_transaction,
scanned_file_path && !destination_exists,
scanned_file_path && old_data_dir_exists,
)))
Ok(Some((old_dir, target, raw, journal, sole_transaction)))
})() {
Ok(Some(tuple)) => tuple,
Ok(None) => return Ok(Ok(None)),
@@ -2661,27 +2641,23 @@ impl LocalDisk {
if sync {
os::fsync_dir_std(&staged_dir)?;
}
if !destination_missing {
match std::fs::symlink_metadata(&destination) {
Ok(metadata) if metadata.is_dir() => match std::fs::remove_dir(&destination) {
Ok(()) => {}
Err(err) if err.kind() == ErrorKind::NotFound => {}
Err(err) if is_dir_not_empty_error(&err) => return Ok(Err(DiskError::OutdatedXLMeta)),
Err(err) => return Err(err),
},
Ok(_) => return Ok(Err(DiskError::OutdatedXLMeta)),
match std::fs::symlink_metadata(&destination) {
Ok(metadata) if metadata.is_dir() => match std::fs::remove_dir(&destination) {
Ok(()) => {}
Err(err) if err.kind() == ErrorKind::NotFound => {}
Err(err) if is_dir_not_empty_error(&err) => return Ok(Err(DiskError::OutdatedXLMeta)),
Err(err) => return Err(err),
}
},
Ok(_) => return Ok(Err(DiskError::OutdatedXLMeta)),
Err(err) if err.kind() == ErrorKind::NotFound => {}
Err(err) => return Err(err),
}
let staged_dir = staged.keep();
if let Err(err) = std::fs::rename(&staged_dir, &destination) {
let _ = std::fs::remove_dir_all(&staged_dir);
return Err(err);
}
let old_data_path = old_dir
.map(|uuid| file_path.join(uuid.to_string()))
.filter(|p| old_data_dir_present || p.is_dir());
let old_data_path = old_dir.map(|uuid| file_path.join(uuid.to_string())).filter(|p| p.is_dir());
if sync && let Err(err) = os::fsync_dir_std(&file_path) {
let _ = std::fs::remove_dir_all(&destination);
return Err(err);
@@ -2710,15 +2686,8 @@ impl LocalDisk {
// A provisional head must stay outside the published recovery transaction.
let target_in_rollback = destination.join(TARGET);
let linked_xl = staging_root.join(format!("delete-xl-{transaction}"));
let linked = match std::fs::hard_link(&target_in_rollback, &linked_xl) {
Ok(()) => true,
Err(err) if err.kind() == ErrorKind::AlreadyExists => {
let _ = std::fs::remove_file(&linked_xl);
std::fs::hard_link(&target_in_rollback, &linked_xl).is_ok()
}
Err(_) => false,
};
let write_res = if linked {
let _ = std::fs::remove_file(&linked_xl);
let write_res = if std::fs::hard_link(&target_in_rollback, &linked_xl).is_ok() {
let rename_res = std::fs::rename(&linked_xl, &xl_path);
if rename_res.is_err() {
let _ = std::fs::remove_file(&linked_xl);
@@ -3074,19 +3043,14 @@ impl LocalDisk {
}
let data_dirs = journal.data_dirs.clone();
let has_original = journal.original_digest.is_some();
let has_target = journal.target_digest.is_some();
let journal_for_receipt = cached_journal_raw.is_none().then(|| journal.clone());
let lease = os::acquire_namespace_mutation_lease_with_owner(&receipt_path, owner).await;
let prune_paths: Vec<_> = if has_target {
vec![rollback.clone()]
} else {
rollback
.ancestors()
.take_while(|dir| *dir != bucket_path.as_path() && dir.starts_with(&bucket_path))
.map(Path::to_path_buf)
.collect()
};
let prune_paths: Vec<_> = rollback
.ancestors()
.take_while(|dir| *dir != bucket_path.as_path() && dir.starts_with(&bucket_path))
.map(Path::to_path_buf)
.collect();
let res = os::run_blocking_namespace_operation_with_sync(lease, sync, move || -> std::io::Result<()> {
let persist_receipt = |finished: bool| -> std::io::Result<()> {
@@ -3167,53 +3131,23 @@ impl LocalDisk {
if had_physical_data_dirs && sync && root.is_dir() {
os::fsync_dir_std(&root)?;
}
let fast_cleanup = cached_journal_raw.is_some();
if fast_cleanup {
let backup_or_marker = if has_original {
Some(STORAGE_FORMAT_FILE_BACKUP)
} else if has_target {
Some(DELETE_MARKER_ROLLBACK_FILE)
} else {
None
};
if let Some(name) = backup_or_marker
&& let Err(err) = ignore_not_found(std::fs::remove_file(rollback.join(name)))
{
for name in [STORAGE_FORMAT_FILE_BACKUP, DELETE_MARKER_ROLLBACK_FILE] {
if let Err(err) = ignore_not_found(std::fs::remove_file(rollback.join(name))) {
if has_target || had_physical_data_dirs {
let _ = persist_receipt(true);
}
return Err(err);
}
for name in [PREPARED, FINISHED].into_iter().chain(has_target.then_some(TARGET)) {
let path = rollback.join(name);
#[cfg(all(any(test, feature = "test-util"), not(windows)))]
os::prepared_publication_test_hooks::run(os::prepared_publication_test_hooks::Stage::Remove, &path);
if let Err(err) = ignore_not_found(std::fs::remove_file(path)) {
if has_target || had_physical_data_dirs {
let _ = persist_receipt(true);
}
return Err(err);
}
}
} else {
for name in [STORAGE_FORMAT_FILE_BACKUP, DELETE_MARKER_ROLLBACK_FILE] {
if let Err(err) = ignore_not_found(std::fs::remove_file(rollback.join(name))) {
if has_target || had_physical_data_dirs {
let _ = persist_receipt(true);
}
return Err(err);
}
}
for name in [PREPARED, TARGET, FINISHED] {
let path = rollback.join(name);
#[cfg(all(any(test, feature = "test-util"), not(windows)))]
os::prepared_publication_test_hooks::run(os::prepared_publication_test_hooks::Stage::Remove, &path);
if let Err(err) = ignore_not_found(std::fs::remove_file(path)) {
if has_target || had_physical_data_dirs {
let _ = persist_receipt(true);
}
return Err(err);
}
for name in [PREPARED, TARGET, FINISHED] {
let path = rollback.join(name);
#[cfg(all(any(test, feature = "test-util"), not(windows)))]
os::prepared_publication_test_hooks::run(os::prepared_publication_test_hooks::Stage::Remove, &path);
if let Err(err) = ignore_not_found(std::fs::remove_file(path)) {
if has_target || had_physical_data_dirs {
let _ = persist_receipt(true);
}
return Err(err);
}
}
if sync && let Err(err) = os::fsync_dir_std(&rollback) {
@@ -429,7 +429,7 @@ impl IndexOwner {
os::replace_multipart_source_metadata(&marker, b"1", &self.base, &root)?;
os::sync_multipart_owned_record_parents(&self.base.join(".rustfs.sys"), &directory, true, &self.base, &root)?;
}
Ok(())
self.ensure_current_root()
}
fn ensure_current_root(&self) -> io::Result<()> {
@@ -547,10 +547,13 @@ impl IndexOwner {
Ok(())
}
pub(super) async fn prepare_record_head(self: &Arc<Self>, path: &str, bytes: &[u8]) -> Option<PreparedHeadRecord> {
let upload = path
pub(super) async fn record_head(self: &Arc<Self>, path: &str, bytes: &[u8]) -> Result<()> {
let Some(upload) = path
.strip_suffix("/xl.meta")
.filter(|upload| canonical_upload(upload).is_some())?;
.filter(|upload| canonical_upload(upload).is_some())
else {
return Ok(());
};
let info = match get_file_info(
bytes,
RUSTFS_META_MULTIPART_BUCKET,
@@ -565,33 +568,10 @@ impl IndexOwner {
Ok(info) => info,
Err(_) => {
self.disabled.store(true, Ordering::Release);
return None;
return Ok(());
}
};
let marker = info
.metadata
.get(crate::disk::multipart_index::RUSTFS_MULTIPART_BUCKET_KEY)
.map(|bucket| {
self.base
.join(INDEX)
.join(sha(bucket))
.join(upload.split('/').next().unwrap_or_default())
})
.unwrap_or_else(|| self.base.join(INDEX));
let lease = os::acquire_namespace_mutation_lease_with_owner(&marker, None).await;
Some(PreparedHeadRecord {
owner: Arc::clone(self),
upload: upload.to_owned(),
info,
_lease: lease,
})
}
pub(super) async fn record_head(self: &Arc<Self>, path: &str, bytes: &[u8]) -> Result<()> {
let Some(prepared) = self.prepare_record_head(path, bytes).await else {
return Ok(());
};
prepared.run().await
self.record_info(upload, &info).await
}
async fn page(self: &Arc<Self>, bucket: &str, marker: Option<&str>, disk_id: Uuid) -> Result<MultipartIndexPage> {
@@ -713,37 +693,6 @@ impl IndexOwner {
}
}
pub(super) struct PreparedHeadRecord {
owner: Arc<IndexOwner>,
upload: String,
info: FileInfo,
_lease: Arc<os::NamespaceMutationLease>,
}
impl PreparedHeadRecord {
pub(super) fn run_std(self) -> io::Result<()> {
let Self {
owner,
upload,
info,
_lease,
} = self;
match owner.record(&upload, &info) {
Err(error) if error.kind() == io::ErrorKind::InvalidData => {
owner.disabled.store(true, Ordering::Release);
Ok(())
}
result => result,
}
}
async fn run(self) -> Result<()> {
let lease = Arc::clone(&self._lease);
os::run_blocking_namespace_operation_with_sync(lease, true, move || self.run_std()).await?;
Ok(())
}
}
impl LocalDisk {
#[cfg(any(test, feature = "test-util"))]
pub(in crate::disk) async fn wait_for_multipart_index_bootstrap(&self) {
@@ -428,6 +428,7 @@ impl LocalDisk {
let root = store.publication_root.clone();
let lease = os::acquire_namespace_mutation_lease_with_owner(&destination, Some(store.lease.clone())).await;
os::run_blocking_namespace_operation_with_sync(lease, true, move || {
permit.validate()?;
os::rename_multipart_source_owned_std(&source, &destination, &base, &root, || permit.validate())
})
.await?;
@@ -295,17 +295,10 @@ pub(super) fn put_active_multipart_source_head(source: impl AsRef<Path>, raw: By
}
fn stamp_matches_active_disk(source: &Path, expected_head_stamp: FileStamp) -> bool {
if FileStamp::from_path(&source.join(STORAGE_FORMAT_FILE)) != Some(expected_head_stamp) {
return false;
}
#[cfg(test)]
if source.join(STATE).exists()
|| source.join(crate::disk::MULTIPART_RECOVERY_DIR).exists()
|| source.join(".mpu-completions").exists()
{
return false;
}
true
FileStamp::from_path(&source.join(STORAGE_FORMAT_FILE)) == Some(expected_head_stamp)
&& !source.join(STATE).exists()
&& !source.join(crate::disk::MULTIPART_RECOVERY_DIR).exists()
&& !source.join(".mpu-completions").exists()
}
pub(super) fn get_active_multipart_source_head(source: &Path) -> Option<(Bytes, FileInfo)> {
@@ -382,11 +375,7 @@ pub(super) fn finish_active_multipart_part_transaction(
ACTIVE_MULTIPART_SOURCE_HEADS.remove_if_mut(source, |entry| !entry.unsettled_parts.remove(&part_number));
}
pub(super) fn get_active_multipart_source_part_with_head(
source: &Path,
part_number: usize,
head_already_verified: bool,
) -> Option<rustfs_filemeta::ObjectPartInfo> {
pub(super) fn get_active_multipart_source_part(source: &Path, part_number: usize) -> Option<rustfs_filemeta::ObjectPartInfo> {
let (head_stamp, data_dir, expected_stamp, part) = ACTIVE_MULTIPART_SOURCE_HEADS
.with_get(source, |entry| {
if !entry.unsettled_parts.is_empty() {
@@ -397,7 +386,7 @@ pub(super) fn get_active_multipart_source_part_with_head(
Some((entry.head_stamp, data_dir, *expected_stamp, part.clone()))
})
.flatten()?;
if !head_already_verified && !stamp_matches_active_disk(source, head_stamp) {
if !stamp_matches_active_disk(source, head_stamp) {
ACTIVE_MULTIPART_SOURCE_HEADS.remove(source);
return None;
}
@@ -620,45 +609,25 @@ impl SourceStore {
raw: &[u8],
terminal: Option<&Path>,
sync_source_before: bool,
) -> std::io::Result<()> {
Self::persist_state_with_guard_std(source, base, root, raw, terminal, sync_source_before, None)
}
fn persist_state_with_guard_std(
source: &Path,
base: &Path,
root: &os::PublicationRoot,
raw: &[u8],
terminal: Option<&Path>,
sync_source_before: bool,
directory_guard: Option<&os::RenameCommitGuard>,
) -> std::io::Result<()> {
invalidate_active_multipart_source_head(source);
#[cfg(not(target_os = "linux"))]
#[cfg(unix)]
let mut pinned = os::pin_multipart_source_directory(source, base, root)?;
#[cfg(not(unix))]
let _pinned = os::pin_multipart_source_directory(source, base, root)?;
if sync_source_before {
#[cfg(target_os = "linux")]
#[cfg(unix)]
{
let mut pinned = os::pin_multipart_source_directory(source, base, root)?;
let opened = std::fs::File::from(pinned.pop().ok_or_else(|| IoError::other("empty source directory guard"))?);
os::fsync_directory_handle_std(source, Some(&opened))?;
}
#[cfg(all(unix, not(target_os = "linux")))]
{
let opened = std::fs::File::from(
_pinned
.last()
.ok_or_else(|| IoError::other("empty source directory guard"))?
.try_clone()?,
);
os::fsync_directory_handle_std(source, Some(&opened))?;
}
#[cfg(not(unix))]
os::fsync_dir_std(source)?;
}
if let Some(path) = terminal {
os::replace_multipart_source_metadata(path, raw, base, root)?;
}
os::replace_multipart_source_metadata_with_guard(&source.join(STATE), raw, base, root, directory_guard)
os::replace_multipart_source_metadata(&source.join(STATE), raw, base, root)
}
async fn write_owned_backup_and_persist(&self, owner: Uuid, target: bool, bytes: &[u8], state: &SourceState) -> Result<()> {
if owner.is_nil() {
@@ -755,39 +724,17 @@ impl SourceStore {
bytes: &[u8],
sync_source_root: bool,
) -> std::io::Result<()> {
Self::write_owned_backup_inner_std(source, base, root, owner, target, bytes, sync_source_root, false, true, false)
}
#[expect(clippy::too_many_arguments)]
fn write_owned_backup_inner_std(
source: &Path,
base: &Path,
root: &os::PublicationRoot,
owner: Uuid,
target: bool,
bytes: &[u8],
sync_source_root: bool,
fresh_owner: bool,
sync_parents: bool,
source_already_pinned: bool,
) -> std::io::Result<()> {
invalidate_active_multipart_source_head(source);
let path = if target {
target_backup_path(source, owner)
} else {
original_path(source, owner)
};
let _pin = if source_already_pinned {
None
} else {
Some(os::pin_multipart_source_directory(source, base, root)?)
};
let _pin = os::pin_multipart_source_directory(source, base, root)?;
let parent = path
.parent()
.ok_or_else(|| std::io::Error::other("source backup has no parent"))?;
let _parents = os::mkdir_all_below_existing_base_std(parent, base, root)?;
let existed = if fresh_owner {
false
} else if target {
let existed = if target {
match os::observe_multipart_source_metadata(&path, base, root, bytes.len() as u64) {
Ok((length, sha)) if length == bytes.len() as u64 && sha == raw_sha(bytes) => true,
Ok(_) => {
@@ -807,10 +754,7 @@ impl SourceStore {
if !existed {
os::replace_multipart_source_metadata(&path, bytes, base, root)?;
}
if sync_parents {
os::sync_multipart_owned_record_parents_options(source, parent, existed, sync_source_root, base, root)?;
}
Ok(())
os::sync_multipart_owned_record_parents_options(source, parent, existed, sync_source_root, base, root)
}
pub async fn replace_head(&self, bytes: &[u8]) -> Result<()> {
self.multipart_index
@@ -2080,41 +2024,11 @@ impl NativeMultipartPublication {
}
let setup_res: std::io::Result<()> = (|| {
if let Some((original_bytes, directory, anchor_bytes)) = deferred_initial {
SourceStore::write_owned_backup_inner_std(
source,
base,
root,
backup_owner,
false,
&original_bytes,
false,
true,
old_metadata.is_none(),
true,
)?;
SourceStore::write_owned_backup_std(source, base, root, backup_owner, false, &original_bytes, false)?;
if let Some(previous) = old_metadata {
SourceStore::write_owned_backup_inner_std(
source,
base,
root,
backup_owner,
true,
previous,
false,
true,
true,
true,
)?;
SourceStore::write_owned_backup_std(source, base, root, backup_owner, true, previous, false)?;
}
SourceStore::persist_state_with_guard_std(
source,
base,
root,
&next_state_raw,
terminal.as_deref(),
false,
Some(directory_guard),
)?;
SourceStore::persist_state_std(source, base, root, &next_state_raw, terminal.as_deref(), false)?;
let _parent = os::mkdir_all_below_existing_base_std(&directory, base, root)?;
os::replace_multipart_source_metadata(&directory.join(RETIREMENT_ANCHOR), &anchor_bytes, base, root)?;
#[cfg(target_os = "linux")]
@@ -2123,28 +2037,9 @@ impl NativeMultipartPublication {
}
} else {
if let Some(previous) = old_metadata {
SourceStore::write_owned_backup_inner_std(
source,
base,
root,
backup_owner,
true,
previous,
false,
false,
true,
true,
)?;
SourceStore::write_owned_backup_std(source, base, root, backup_owner, true, previous, false)?;
}
SourceStore::persist_state_with_guard_std(
source,
base,
root,
&next_state_raw,
terminal.as_deref(),
false,
Some(directory_guard),
)?;
SourceStore::persist_state_std(source, base, root, &next_state_raw, terminal.as_deref(), false)?;
}
Ok(())
})();
@@ -2374,7 +2269,6 @@ impl NativeMultipartPublication {
target_already_synced: bool,
fused_in_place: bool,
staging_cleanup: Option<(PathBuf, Arc<std::sync::atomic::AtomicBool>)>,
directory_guard: Option<&os::RenameCommitGuard>,
) -> Result<MultipartPublicationResult> {
let mut state = self.state.lock().clone();
let expected_state_raw = encode(&state)?;
@@ -2460,15 +2354,7 @@ impl NativeMultipartPublication {
})?;
}
}
SourceStore::persist_state_with_guard_std(
source,
base,
root,
&next_state_raw,
terminal.as_deref(),
!fused_in_place,
directory_guard,
)?;
SourceStore::persist_state_std(source, base, root, &next_state_raw, terminal.as_deref(), !fused_in_place)?;
if let Some((io_path, cleaned)) = staging_cleanup {
match std::fs::remove_dir(&io_path) {
Ok(()) => cleaned.store(true, std::sync::atomic::Ordering::Release),
@@ -2501,7 +2387,7 @@ impl NativeMultipartPublication {
) -> Result<MultipartPublicationResult> {
let this = Arc::clone(self);
os::run_blocking_namespace_operation_with_sync(target_lease, true, move || {
this.finish_on_thread(target_already_synced, false, staging_cleanup, None)
this.finish_on_thread(target_already_synced, false, staging_cleanup)
.map_err(IoError::other)
})
.await
@@ -455,11 +455,8 @@ impl LocalDisk {
}
let meta_name = format!("part.{}.meta", part.number);
let actual = if let Some(cached_part) =
super::multipart_source_state::get_active_multipart_source_part_with_head(
&source_object,
part.number,
from_active_cache,
) {
super::multipart_source_state::get_active_multipart_source_part(&source_object, part.number)
{
cached_part
} else {
if pinned_source_data.is_none() {
+41 -95
View File
@@ -611,10 +611,6 @@ pub(crate) mod prepare_rename_test_hooks {
}
}
pub(crate) fn has_after_component_opened() -> bool {
!AFTER_COMPONENT_OPENED.lock().is_empty()
}
/// Hooks keyed by a directory component name, run before a Windows
/// directory pin retries a transient sharing conflict on it.
#[cfg(windows)]
@@ -3808,7 +3804,7 @@ pub(crate) fn rename_all_with_precondition_and_parent_sync_std(
#[cfg(all(test, not(windows)))]
prepared_publication_test_hooks::run_rename_destination(source, destination);
#[cfg(all(any(test, feature = "test-util"), not(windows)))]
if prepared_publication_test_hooks::has_any_hooks() {
{
prepared_publication_test_hooks::run(prepared_publication_test_hooks::Stage::Rename, source);
prepared_publication_test_hooks::run(prepared_publication_test_hooks::Stage::Rename, destination);
if let Some(check) = precondition {
@@ -7202,39 +7198,6 @@ pub(crate) fn pin_multipart_source_directory(
}
}
fn same_parent_commit_guard(
parent: &Path,
base: &Path,
publication_root: &PublicationRoot,
directory_guard: Option<&RenameCommitGuard>,
) -> io::Result<RenameCommitGuard> {
#[cfg(target_os = "linux")]
if let Some(directory_guard) = directory_guard.filter(|g| g.directories.source_path == parent) {
let dir = &directory_guard.directories.source;
return Ok(RenameCommitGuard {
directories: Arc::new(LinuxCommitDirectories {
root: directory_guard.directories.root.clone(),
source_path: parent.to_path_buf(),
destination_path: parent.to_path_buf(),
source: LinuxCommitDirectory {
file: Arc::clone(&dir.file),
device: dir.device,
inode: dir.inode,
},
destination: std::sync::OnceLock::from(LinuxCommitDirectory {
file: Arc::clone(&dir.file),
device: dir.device,
inode: dir.inode,
}),
destination_base: base.to_path_buf(),
}),
});
}
#[cfg(not(target_os = "linux"))]
let _ = directory_guard;
prepare_rename_commit_guard(parent, parent, base, publication_root)
}
/// A small control record always gets its own inode and an atomic replacement.
/// The caller owns the upload SourceRW and keeps its namespace lease alive.
pub(crate) fn replace_multipart_source_metadata(
@@ -7242,21 +7205,11 @@ pub(crate) fn replace_multipart_source_metadata(
bytes: &[u8],
base: &Path,
publication_root: &PublicationRoot,
) -> io::Result<()> {
replace_multipart_source_metadata_with_guard(path, bytes, base, publication_root, None)
}
pub(crate) fn replace_multipart_source_metadata_with_guard(
path: &Path,
bytes: &[u8],
base: &Path,
publication_root: &PublicationRoot,
directory_guard: Option<&RenameCommitGuard>,
) -> io::Result<()> {
let parent = path.parent().ok_or_else(|| io::Error::other("MPU record has no parent"))?;
#[cfg(not(target_os = "linux"))]
let _pinned = pin_multipart_source_directory(parent, base, publication_root)?;
let guard = same_parent_commit_guard(parent, base, publication_root, directory_guard)?;
let guard = prepare_rename_commit_guard(parent, parent, base, publication_root)?;
let staged = parent.join(format!(".mpu-record-{}", uuid::Uuid::new_v4()));
let mut prepared = create_prepared_rename_source_with_commit_guard(&staged, path, &guard)?;
prepared.write_all(bytes, true)?;
@@ -7505,9 +7458,37 @@ pub(crate) fn install_multipart_prepared_head(
if original_path.parent() != Some(parent) || original_path == canonical_head {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "MPU proxy must be a private sibling"));
}
#[cfg(target_os = "linux")]
let guard = if let Some(directory_guard) = directory_guard.filter(|g| g.directories.source_path == parent) {
let dir = &directory_guard.directories.source;
RenameCommitGuard {
directories: Arc::new(LinuxCommitDirectories {
root: directory_guard.directories.root.clone(),
source_path: parent.to_path_buf(),
destination_path: parent.to_path_buf(),
source: LinuxCommitDirectory {
file: Arc::clone(&dir.file),
device: dir.device,
inode: dir.inode,
},
destination: std::sync::OnceLock::from(LinuxCommitDirectory {
file: Arc::clone(&dir.file),
device: dir.device,
inode: dir.inode,
}),
destination_base: base.to_path_buf(),
}),
}
} else {
prepare_rename_commit_guard(parent, parent, base, publication_root)?
};
#[cfg(not(target_os = "linux"))]
let _pinned = pin_multipart_source_directory(parent, base, publication_root)?;
let guard = same_parent_commit_guard(parent, base, publication_root, directory_guard)?;
#[cfg(not(target_os = "linux"))]
let guard = {
let _ = directory_guard;
prepare_rename_commit_guard(parent, parent, base, publication_root)?
};
rename_prepared_source_std(&prepared, &original_path, canonical_head, base, publication_root, &guard)?;
prepared.path = canonical_head.to_path_buf();
fsync_commit_directory_limited_std(parent, &guard)?;
@@ -7809,7 +7790,8 @@ pub(crate) fn hardlink_multipart_source_files(
}
#[cfg(unix)]
{
use rustix::fs::{AtFlags, FileType, linkat, statat, unlinkat};
use rustix::fs::{AtFlags, Mode, OFlags, linkat, openat, unlinkat};
use std::os::unix::fs::MetadataExt;
#[cfg(test)]
let source_path = source.to_path_buf();
#[cfg(test)]
@@ -7824,26 +7806,20 @@ pub(crate) fn hardlink_multipart_source_files(
.ok_or_else(|| io::Error::other("missing multipart attempt directory"))?;
#[cfg(test)]
prepared_publication_test_hooks::run_hardlink_destination(&source_path, &destination_path);
let flags = OFlags::RDONLY | OFlags::NOFOLLOW | OFlags::CLOEXEC;
for name in names {
if cancelled() {
return Err(io::Error::new(io::ErrorKind::Interrupted, "multipart staging cancelled"));
}
let expected = statat(source, name.as_str(), AtFlags::SYMLINK_NOFOLLOW)?;
let expected_type = FileType::from_raw_mode(expected.st_mode);
if expected_type.is_symlink() {
return Err(io::Error::from_raw_os_error(libc::ELOOP));
}
if !expected_type.is_file() {
let original = std::fs::File::from(openat(source, name.as_str(), flags, Mode::empty())?);
let expected = original.metadata()?;
if !expected.is_file() {
return Err(io::Error::new(io::ErrorKind::InvalidData, "multipart shard is not a regular file"));
}
linkat(source, name.as_str(), destination, name.as_str(), AtFlags::empty())?;
let actual = statat(destination, name.as_str(), AtFlags::SYMLINK_NOFOLLOW)?;
if !FileType::from_raw_mode(actual.st_mode).is_file()
|| actual.st_dev != expected.st_dev
|| actual.st_ino != expected.st_ino
|| actual.st_size != expected.st_size
|| actual.st_mtime != expected.st_mtime
{
let linked = std::fs::File::from(openat(destination, name.as_str(), flags, Mode::empty())?);
let actual = linked.metadata()?;
if actual.dev() != expected.dev() || actual.ino() != expected.ino() {
let _ = unlinkat(destination, name.as_str(), AtFlags::empty());
return Err(io::Error::new(io::ErrorKind::InvalidData, "multipart shard changed during staging"));
}
@@ -8264,37 +8240,7 @@ pub(crate) fn mkdir_all_below_existing_base_std(
let flags = OFlags::RDONLY | OFlags::DIRECTORY | OFlags::NOFOLLOW | OFlags::CLOEXEC;
let mode = Mode::RWXU | Mode::RWXG | Mode::RWXO;
#[cfg(target_os = "linux")]
let base = {
use rustix::fs::{ResolveFlags, openat2};
use std::os::fd::AsFd;
let owned_base = (base_dir != publication_root.io_path.as_path() && base_dir != publication_root.path.as_path())
.then(|| publication_root.open_directory(base_dir).map(std::os::fd::OwnedFd::from))
.transpose()?;
#[cfg(test)]
let has_hook = prepare_rename_test_hooks::has_after_component_opened();
#[cfg(not(test))]
let has_hook = false;
if !has_hook {
let base_fd = owned_base
.as_ref()
.map_or_else(|| publication_root.directory.as_fd(), AsFd::as_fd);
let target = if relative.as_os_str().is_empty() {
Path::new(".")
} else {
relative
};
match openat2(base_fd, target, flags, Mode::empty(), ResolveFlags::BENEATH | ResolveFlags::NO_SYMLINKS) {
Ok(leaf) => return Ok(vec![leaf]),
Err(Errno::NOENT | Errno::NOSYS) => {}
Err(err) => return Err(err.into()),
}
}
match owned_base {
Some(base) => base,
None => publication_root.open_directory(base_dir)?.into(),
}
};
let base = publication_root.open_directory(base_dir)?.into();
#[cfg(not(target_os = "linux"))]
let base = {
// The configured endpoint is trusted; every component beneath it
+7 -29
View File
@@ -116,40 +116,18 @@ Functional-chain health runs on a hosted runner independently of the lab fleet.
## Release validation
Post-merge and tag-driven; not a substitute for a PR gate. Every public publication exit consumes the release certification described here; this certification path is separate from the reusable CI artifact contract in [verification plans](ci-verification-pipeline.md), whose archives expire after one day and are never used as release certification.
The versioned plan is `.config/release-validation-plan.json` (`schema_version=1`): release types, target OS/arch/ABI, supported features, a fixed harness SHA per lane, required case IDs, environment capabilities, timeouts, applicability conditions, and an explicit `upgrade_sources` list carrying the real artifact digests of the supported N-1/N-2 sources plus a stated rollback basis — compatibility and rollback are never invented or defaulted. `scripts/release/release_gate.py validate` expands and freezes `plan_sha256` and the required case set before reading results, then binds that plan, a `candidate.json` (product 40-character SHA, version, release profile, features, immutable deliverable locations with SHA256 and wrapped-binary SHA256, image digest) and the shared G01 evidence-envelope set (rustfs/backlog#2658) of one parent candidate batch, and writes machine JSON, JUnit and a summary. Within a batch the unique key is `(lane, platform{os,arch,abi}, case_id)`; the top-level run/attempt is the parent batch and the nested workflow run/attempt is the child workflow identity, and both are validated separately (workflow SHA and product build SHA are bound independently and need not be equal). Missing, duplicate or extra cases, stale attempts, wrong digests, wrong platforms, wrong harness SHAs, zero tests, cancellation, timeout, untrusted sources and any non-PASS required item block with classified errors; only a complete legal success returns 0. `verify-promotion` re-checks the exact bytes about to be published against the passed list and fails on a swapped package or an edited plan after verification. preview, prerelease and stable all require an explicit plan; preview may use the plan's smaller pre-declared set but never bypasses artifact identity and startup checks. development artifacts are explicitly uncertified and never touch official or latest channels.
Post-merge and tag-driven; not a substitute for a PR gate.
| Trigger | Workflow / job | Result |
|---|---|---|
| Nightly schedule, dispatch | `build.yml` `build-rustfs` (development build over the full platform matrix) | build artifacts and the uncertified dev download channel; no release publication |
| Valid release or preview tag | `build.yml` `build-rustfs`, `release-certification`, `create-release`, `upload-release-assets`, `publish-release`, `promote-release-artifacts` | staged binaries, draft release, checksummed assets, then certified publish and promotion of the same bytes |
| Successful non-preview release-tag build (`workflow_run`) | `docker.yml` `release-certification`, `build-docker`, `scan-docker-image` | multi-architecture images staged, verified against the certification and promoted, plus vulnerability report |
| Successful release-tag build (`workflow_run`) | `package.yml` `release-certification`, `package`, `promote-packages` | DEB/RPM packages with wrapped-binary verification, staged then promoted with checksums |
| Successful non-preview release-tag build (`workflow_run`) | `helm-package.yml` `release-certification`, `build-helm-package`, `publish-helm-package` | versioned chart and repository index, only over a certified image promotion record |
| Nightly schedule, dispatch | `build.yml` `build-rustfs` (development build over the full platform matrix) | build artifacts and the dev download channel; no release publication |
| Valid release or preview tag | `build.yml` `build-rustfs`, `create-release`, `upload-release-assets`, `publish-release` | draft release, checksummed assets, publish |
| Successful non-preview release-tag build (`workflow_run`) | `docker.yml` `build-docker`, `scan-docker-image` | multi-architecture images and vulnerability report |
| Successful release-tag build (`workflow_run`) | `package.yml` `package` | DEB/RPM packages and checksums uploaded to the release |
| Successful non-preview release-tag build (`workflow_run`) | `helm-package.yml` `build-helm-package`, `publish-helm-package` | versioned chart and repository index |
| Final tag's release published | `build.yml` `cleanup-preview-releases` | deletes every `<target>-preview.<N>` Release for that target; the tags are kept |
Publication exits and their gate:
| Exit | Writer | Certification consumed |
|---|---|---|
| GitHub Release draft → public | `build.yml` `publish-release` | `release-certification` success and per-asset `verify-promotion` |
| Official R2 binary path `artifacts/rustfs/release/` | `build.yml` `promote-release-artifacts` | `release-certification` plus `verify-promotion`; the build job itself only writes `artifacts/rustfs/staging/<run>/<attempt>/` |
| `latest.json` version pointer | `build.yml` `update-latest-version` | transitively through `publish-release` |
| Image channels (Docker Hub, GHCR, Quay tags) | `docker.yml` `build-docker` promotion step | certified input digests, staged image binary identity and `verify-promotion`, then promotion of the same digest with `imagetools create` |
| Official R2 package paths `packages/release` and `packages/latest` | `package.yml` `promote-packages` | `release-certification` and wrapped-binary `verify-promotion`; the package job only stages |
| GitHub release package assets | `package.yml` `package` | `release-certification` and wrapped-binary `verify-promotion` before upload |
| Helm chart repository (`rustfs/helm` push) | `helm-package.yml` `publish-helm-package` | `release-certification` plus the Docker workflow's image-promotion record bound to the same candidate |
Downstream workflows fail closed when the trusted certification is absent: a manual dispatch without certification fails and pushes no official tag. Only results from the trusted verification sources listed in the plan (currently the `rustfs/s3chaos` `release-gate.yml` envelope runs) carry release authority; a PR-uploaded JSON set cannot certify a release. Retries reuse the same candidate, only the staged bytes are promoted (no rebuild-after-verify), and no downstream step re-resolves a mutable `latest`.
Use an exact preview tag for an end-to-end release rehearsal. Manual dispatches are backfill/debug paths and do not prove the automatic `workflow_run` chain. The committed fixtures under `testdata/release-gate/` and the commands below are contract rehearsals of this orchestration; they are explicitly not product release evidence and not live verifier results.
```bash
python3 -m unittest discover -s scripts/release -p 'test_release_gate.py'
python3 scripts/release/release_gate.py validate --plan testdata/release-gate/plan.json --candidate testdata/release-gate/candidate.json --results testdata/release-gate/pass --output target/release-gate-check
bash scripts/security/check_preview_release_workflow.sh
```
Use an exact preview tag for an end-to-end release rehearsal. Manual dispatches are backfill/debug paths and do not prove the automatic `workflow_run` chain.
## Change checklist
File diff suppressed because it is too large Load Diff
-376
View File
@@ -1,376 +0,0 @@
#!/usr/bin/env python3
# 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.
"""Contract tests for scripts/release/release_gate.py (rustfs/backlog#2662).
Every fixture under testdata/release-gate/ is a contract rehearsal only: these
tests prove the gate's fail-closed orchestration and must never be read as
product release evidence or as R02 live verification results.
"""
import json
import re
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
GATE = ROOT / "scripts" / "release" / "release_gate.py"
FIXTURES = ROOT / "testdata" / "release-gate"
PLAN = FIXTURES / "plan.json"
CANDIDATE = FIXTURES / "candidate.json"
ARTIFACT = FIXTURES / "artifacts" / "rustfs-linux-x86_64-gnu-v9.9.9-fixture.zip"
ARTIFACT_NAME = "rustfs-linux-x86_64-gnu-v9.9.9-fixture.zip"
REAL_PLAN = ROOT / ".config" / "release-validation-plan.json"
def run_gate(*arguments):
result = subprocess.run(
[sys.executable, str(GATE), *map(str, arguments)],
cwd=ROOT,
text=True,
capture_output=True,
check=False,
)
return result
def run_validate(results, output, plan=PLAN, candidate=CANDIDATE):
return run_gate(
"validate",
"--plan", plan,
"--candidate", candidate,
"--results", results,
"--output", output,
)
def run_promote(output, plan=PLAN, candidate=CANDIDATE, summary=None, artifact=ARTIFACT,
artifact_name=ARTIFACT_NAME, artifact_sha256=None):
arguments = [
"verify-promotion",
"--plan", plan,
"--candidate", candidate,
"--summary", summary or output,
]
if artifact is not None:
arguments += ["--artifact", artifact]
if artifact_name is not None:
arguments += ["--artifact-name", artifact_name]
if artifact_sha256 is not None:
arguments += ["--artifact-sha256", artifact_sha256]
if output is not None:
arguments += ["--output", output]
return run_gate(*arguments)
def load_summary(output):
return json.loads((Path(output) / "release-gate-summary.json").read_text())
def finding_codes(summary):
return {finding["code"] for finding in summary["findings"]}
class GateFixtureTests(unittest.TestCase):
"""Assertion matrix rows from rustfs/backlog#2662 exercised on the fixtures."""
def setUp(self):
self._temporary = tempfile.TemporaryDirectory(prefix="release-gate-test.")
self.addCleanup(self._temporary.cleanup)
self.output = Path(self._temporary.name)
def validate_fixture(self, name, expect):
output = self.output / name
result = run_validate(FIXTURES / name, output)
self.assertEqual(result.returncode, expect, result.stderr)
return result, load_summary(output)
def test_all_required_pass_and_identity_consistent(self):
# Matrix: all required PASS and identity consistent -> validate and
# verify-promotion return 0.
result, summary = self.validate_fixture("pass", 0)
self.assertEqual(summary["state"], "pass")
self.assertTrue(summary["publish_allowed"])
self.assertEqual(len(summary["required_cases"]), 5)
self.assertEqual(len(summary["observed"]), 5)
self.assertEqual(summary["findings"], [])
expansion = json.loads((self.output / "pass" / "plan-expansion.json").read_text())
self.assertEqual(len(expansion["required_cases"]), 5)
promote = run_promote(self.output / "pass")
self.assertEqual(promote.returncode, 0, promote.stderr)
def test_cross_platform_same_case_and_split_shas_accepted(self):
# Matrix: the same case name on two platforms, and a workflow SHA that
# differs from the (legally bound) product SHA, must not be rejected.
result, summary = self.validate_fixture("cross-platform", 0)
self.assertEqual(summary["state"], "pass")
product_commit = json.loads(CANDIDATE.read_text())["product_commit"]
workflows = []
for name in sorted((FIXTURES / "cross-platform").glob("*.json")):
if name.name == "batch.json":
continue
envelope = json.loads(name.read_text())
workflows.append(envelope["workflow"]["workflow_sha"])
self.assertNotEqual(envelope["workflow"]["workflow_sha"], product_commit)
self.assertEqual(len(workflows), 5)
case_names = [entry["case_id"] for entry in summary["observed"]]
self.assertEqual(case_names.count("startup"), 2)
self.assertEqual(case_names.count("artifact-identity"), 2)
def test_missing_case_names_the_case(self):
result, summary = self.validate_fixture("missing-case", 1)
self.assertIn("missing_case", finding_codes(summary))
missing = [f for f in summary["findings"] if f["code"] == "missing_case"]
self.assertTrue(any(f.get("case_id") == "startup" for f in missing), missing)
self.assertFalse(summary["publish_allowed"])
def test_duplicate_key_names_the_case(self):
result, summary = self.validate_fixture("duplicate-key", 1)
self.assertIn("duplicate_key", finding_codes(summary))
duplicates = [f for f in summary["findings"] if f["code"] == "duplicate_key"]
self.assertTrue(any(f.get("case_id") == "startup" for f in duplicates), duplicates)
self.assertFalse(summary["publish_allowed"])
def test_extra_unplanned_case_names_the_case(self):
result, summary = self.validate_fixture("extra-case", 1)
self.assertIn("extra_case", finding_codes(summary))
extra = [f for f in summary["findings"] if f["code"] == "extra_case"]
self.assertTrue(any(f.get("case_id") == "surprise-case" for f in extra), extra)
self.assertFalse(summary["publish_allowed"])
def test_non_pass_required_items_block(self):
# Matrix: any skipped / infra_error / quarantined required item blocks
# and no official publish write is allowed.
for name in ("non-pass-skipped", "non-pass-infra-error", "non-pass-quarantined"):
with self.subTest(name=name):
result, summary = self.validate_fixture(name, 1)
self.assertIn("non_pass", finding_codes(summary))
self.assertFalse(summary["publish_allowed"])
def test_child_workflow_cancellation_blocks(self):
result, summary = self.validate_fixture("child-cancelled", 1)
self.assertIn("cancelled", finding_codes(summary))
self.assertFalse(summary["publish_allowed"])
def test_batch_timeout_blocks(self):
result, summary = self.validate_fixture("timeout", 1)
self.assertIn("timeout", finding_codes(summary))
self.assertFalse(summary["publish_allowed"])
def test_same_tag_different_bytes_is_rejected(self):
result, summary = self.validate_fixture("same-tag-different-bytes", 1)
self.assertIn("digest_mismatch", finding_codes(summary))
self.assertFalse(summary["publish_allowed"])
def test_stale_attempt_cannot_be_reused(self):
result, summary = self.validate_fixture("stale-attempt", 1)
self.assertIn("stale_attempt", finding_codes(summary))
self.assertFalse(summary["publish_allowed"])
def test_wrong_platform_is_rejected(self):
result, summary = self.validate_fixture("wrong-platform", 1)
self.assertIn("platform_mismatch", finding_codes(summary))
self.assertFalse(summary["publish_allowed"])
def test_wrong_harness_sha_cannot_be_reused(self):
result, summary = self.validate_fixture("wrong-harness", 1)
self.assertIn("harness_mismatch", finding_codes(summary))
self.assertFalse(summary["publish_allowed"])
def test_zero_tests_block(self):
result, summary = self.validate_fixture("zero-tests", 1)
self.assertIn("zero_tests", finding_codes(summary))
self.assertFalse(summary["publish_allowed"])
def test_untrusted_source_blocks(self):
# A PR-uploaded or foreign JSON set must never gain release authority.
result, summary = self.validate_fixture("untrusted-source", 1)
self.assertIn("untrusted_source", finding_codes(summary))
self.assertFalse(summary["publish_allowed"])
def test_swapped_package_after_verification_fails_promotion(self):
# Matrix: swapping a published package after verification must fail
# verify-promotion.
output = self.output / "certified"
self.assertEqual(run_validate(FIXTURES / "pass", output).returncode, 0)
promote = run_promote(
output,
artifact=FIXTURES / "promotion-swap" / ARTIFACT_NAME,
summary=output,
)
self.assertEqual(promote.returncode, 1, promote.stdout)
self.assertIn("artifact_mismatch", promote.stderr)
report = json.loads((output / "promotion-check.json").read_text())
self.assertEqual(report["state"], "blocked")
self.assertEqual(finding_codes(report), {"artifact_mismatch"})
def test_edited_plan_after_verification_fails_promotion(self):
# Matrix: editing the plan after verification must fail
# verify-promotion; the old certification cannot be reused.
output = self.output / "certified"
self.assertEqual(run_validate(FIXTURES / "pass", output).returncode, 0)
promote = run_promote(
output,
plan=FIXTURES / "promotion-edit" / "plan.json",
summary=output,
)
self.assertEqual(promote.returncode, 1, promote.stdout)
self.assertIn("plan_edited", promote.stderr)
def test_promotion_without_certification_fails(self):
output = self.output / "blocked"
self.assertEqual(run_validate(FIXTURES / "missing-case", output).returncode, 1)
promote = run_promote(output, summary=output)
self.assertEqual(promote.returncode, 1, promote.stdout)
self.assertIn("certification_missing", promote.stderr)
def test_summary_junit_and_expansion_are_written(self):
output = self.output / "pass"
self.assertEqual(run_validate(FIXTURES / "pass", output).returncode, 0)
summary = load_summary(output)
self.assertEqual(summary["plan_sha256"], json.loads(CANDIDATE.read_text())["plan_sha256"])
junit = (output / "release-gate.junit.xml").read_text()
self.assertIn("release-gate", junit)
self.assertIn("identity/linux-x86_64-gnu/startup", junit)
markdown = (output / "release-gate-summary.md").read_text()
self.assertIn("state: pass", markdown)
def test_error_messages_carry_no_credentials(self):
for name in ("missing-case", "stale-attempt", "untrusted-source", "zero-tests"):
output = self.output / name
run_validate(FIXTURES / name, output)
text = output.joinpath("release-gate-summary.json").read_text()
text += (output / "release-gate-summary.md").read_text()
lowered = text.lower()
for marker in ("secret", "password", "access_key", "akia", "bearer "):
self.assertNotIn(marker, lowered, f"{name} leaked a credential-shaped string")
class PlanContractTests(unittest.TestCase):
def test_real_plan_is_explicit_about_sources_and_rollback(self):
sys.path.insert(0, str(GATE.parent))
import release_gate
plan = json.loads(REAL_PLAN.read_text())
info = release_gate.validate_plan(plan)
sources = info["upgrade_sources"]
self.assertGreaterEqual(len(sources["sources"]), 1)
self.assertFalse(sources["rollback_supported"])
self.assertTrue(sources["basis"].strip())
self.assertTrue(sources["rollback_basis"].strip())
for source in sources["sources"]:
self.assertEqual(len(source["artifact_sha256"]), 64)
def test_plan_requires_trusted_workflows_and_frozen_harness(self):
sys.path.insert(0, str(GATE.parent))
import release_gate
plan = json.loads(REAL_PLAN.read_text())
plan["trusted_workflows"] = []
with self.assertRaises(release_gate.GateError):
release_gate.validate_plan(plan)
plan = json.loads(REAL_PLAN.read_text())
plan["lanes"][0]["harness_sha"] = "not-a-sha"
with self.assertRaises(release_gate.GateError):
release_gate.validate_plan(plan)
plan = json.loads(REAL_PLAN.read_text())
plan["upgrade_sources"].pop("rollback_supported")
with self.assertRaises(release_gate.GateError):
release_gate.validate_plan(plan)
def test_plan_sha256_is_semantic_and_detects_required_set_edits(self):
sys.path.insert(0, str(GATE.parent))
import release_gate
plan = json.loads(PLAN.read_text())
baseline = release_gate.canonical_sha256(plan)
self.assertEqual(release_gate.canonical_sha256(json.loads(json.dumps(plan))), baseline)
edited = json.loads(PLAN.read_text())
edited["lanes"][0]["cases"] = ["artifact-identity"]
self.assertNotEqual(release_gate.canonical_sha256(edited), baseline)
class PublicationWiringTests(unittest.TestCase):
"""Static checks that the real publication exits consume the gate."""
def read(self, relative):
return (ROOT / relative).read_text()
def job_block(self, workflow, job):
match = re.search(
rf"^ {re.escape(job)}:\n(.*?)(?=^ [A-Za-z#])",
workflow,
re.S | re.M,
)
self.assertIsNotNone(match, f"job {job} not found")
return match.group(1)
def test_build_publish_requires_certification(self):
workflow = self.read(".github/workflows/build.yml")
self.assertIn("\n release-certification:", workflow)
publish_block = self.job_block(workflow, "publish-release")
self.assertIn("release-certification", publish_block)
self.assertIn("release_gate.py validate", workflow)
self.assertIn("release_gate.py verify-promotion", workflow)
def test_build_time_official_r2_writes_are_staged(self):
workflow = self.read(".github/workflows/build.yml")
self.assertIn("artifacts/rustfs/staging/", workflow)
release_writes = [
line for line in workflow.splitlines()
if "artifacts/rustfs/release/" in line
]
# Only the certification-gated promotion job may write the official path.
self.assertTrue(release_writes, "the promotion job must write the official R2 path")
promotion_block = self.job_block(workflow, "promote-release-artifacts")
self.assertIn("verify-promotion", promotion_block)
self.assertIn("artifacts/rustfs/release/", promotion_block)
build_block = self.job_block(workflow, "build-rustfs")
self.assertNotIn('R2_PATH="s3://${R2_BUCKET}/artifacts/rustfs/release/"', build_block)
def test_downstream_workflows_verify_certification(self):
docker = self.read(".github/workflows/docker.yml")
self.assertIn("\n release-certification:", docker)
build_docker_block = self.job_block(docker, "build-docker")
self.assertIn("release-certification", build_docker_block)
self.assertIn("verify-promotion", docker)
package = self.read(".github/workflows/package.yml")
self.assertIn("\n release-certification:", package)
package_block = self.job_block(package, "package")
self.assertIn("release-certification", package_block)
helm = self.read(".github/workflows/helm-package.yml")
self.assertIn("\n release-certification:", helm)
helm_block = self.job_block(helm, "build-helm-package")
self.assertIn("release-certification", helm_block)
def test_manual_downstream_dispatch_without_certification_fails(self):
# Every downstream certification job must fail closed when the trusted
# certification artifact is absent (e.g. a manual dispatch without one).
for relative in (
".github/workflows/docker.yml",
".github/workflows/package.yml",
".github/workflows/helm-package.yml",
):
workflow = self.read(relative)
certification_block = self.job_block(workflow, "release-certification")
self.assertIn("fail", certification_block.lower(), relative)
self.assertIn("release-certification", certification_block, relative)
if __name__ == "__main__":
unittest.main()
-29
View File
@@ -1,29 +0,0 @@
{
"schema_version": 1,
"product_commit": "3333333333333333333333333333333333333333",
"version": "9.9.9-fixture",
"release_profile": "stable",
"features": [
"pyroscope"
],
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"validation_batch": {
"run_id": "fixture-batch-1",
"run_attempt": 2
},
"deliverables": [
{
"kind": "zip",
"name": "rustfs-linux-x86_64-gnu-v9.9.9-fixture.zip",
"location": "https://example.invalid/artifacts/runs/fixture-batch-1/2/rustfs-linux-x86_64-gnu-v9.9.9-fixture.zip",
"sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"size": 36,
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa"
}
],
"image": {
"ref": "example.invalid/rustfs:9.9.9-fixture",
"digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,43 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "infra_error",
"reason_code": "child-cancelled",
"reason_class": "ENV",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111",
"status": "cancelled"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-cross-identity-linux-aarch64-gnu-artifact-identity",
"run_attempt": 1,
"workflow_sha": "4444444444444444444444444444444444444444"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-cross-identity-linux-aarch64-gnu-startup",
"run_attempt": 1,
"workflow_sha": "4444444444444444444444444444444444444444"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-cross-identity-linux-x86_64-gnu-artifact-identity",
"run_attempt": 1,
"workflow_sha": "4444444444444444444444444444444444444444"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-cross-identity-linux-x86_64-gnu-startup",
"run_attempt": 1,
"workflow_sha": "4444444444444444444444444444444444444444"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-cross-upgrade-linux-x86_64-gnu-upgrade-smoke",
"run_attempt": 1,
"workflow_sha": "4444444444444444444444444444444444444444"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "surprise-case",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:05:00Z",
"finished_at": "2026-09-26T10:05:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/surprise-case-linux-x86_64-gnu.json",
"sha256": "f82eedac16c983bd426ca24a6cbf3acfa032dc722e9c4a5ed7ef21c7eff0bcb1",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "infra_error",
"reason_code": "fixture-infra_error",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "quarantined",
"reason_code": "fixture-quarantined",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "skipped",
"reason_code": "fixture-skipped",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-53
View File
@@ -1,53 +0,0 @@
{
"schema_version": 1,
"plan_id": "testdata-release-gate",
"description": "Contract fixtures for scripts/release/release_gate.py (rustfs/backlog#2662). Rehearsal data only: these files are never product release evidence and cannot certify a real candidate.",
"release_types": ["preview", "prerelease", "stable"],
"targets": [
{"os": "linux", "arch": "x86_64", "abi": "gnu"},
{"os": "linux", "arch": "aarch64", "abi": "gnu"}
],
"features": ["pyroscope"],
"trusted_workflows": [
{"repository": "rustfs/s3chaos", "workflow_id": "release-gate.yml"}
],
"lanes": [
{
"lane": "identity",
"harness_repository": "rustfs/s3chaos",
"harness_sha": "1111111111111111111111111111111111111111",
"timeout_seconds": 1800,
"environment_capabilities": ["process-exec"],
"cases": ["artifact-identity", "startup"],
"applies_to": {
"release_types": ["preview", "prerelease", "stable"],
"platforms": "all"
}
},
{
"lane": "upgrade",
"harness_repository": "rustfs/s3chaos",
"harness_sha": "2222222222222222222222222222222222222222",
"timeout_seconds": 3600,
"environment_capabilities": ["process-exec", "previous-release-artifact"],
"cases": ["upgrade-smoke"],
"applies_to": {
"release_types": ["prerelease", "stable"],
"platforms": [{"os": "linux", "arch": "x86_64", "abi": "gnu"}]
}
}
],
"upgrade_sources": {
"basis": "Fixture-only synthetic source. Product plans must cite the real pinned digests of the exercised upgrade sources and must not invent compatibility.",
"sources": [
{
"version": "0.0.1",
"role": "N-1",
"artifact_name": "fixture-upgrade-source.zip",
"artifact_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
],
"rollback_supported": false,
"rollback_basis": "The fixture certifies no rollback support; rollback is never a default claim."
}
}
-92
View File
@@ -1,92 +0,0 @@
{
"schema_version": 1,
"plan_id": "testdata-release-gate",
"description": "Contract fixtures for scripts/release/release_gate.py (rustfs/backlog#2662). Rehearsal data only: these files are never product release evidence and cannot certify a real candidate.",
"release_types": [
"preview",
"prerelease",
"stable"
],
"targets": [
{
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
{
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
}
],
"features": [
"pyroscope"
],
"trusted_workflows": [
{
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml"
}
],
"lanes": [
{
"lane": "identity",
"harness_repository": "rustfs/s3chaos",
"harness_sha": "1111111111111111111111111111111111111111",
"timeout_seconds": 1800,
"environment_capabilities": [
"process-exec"
],
"cases": [
"artifact-identity"
],
"applies_to": {
"release_types": [
"preview",
"prerelease",
"stable"
],
"platforms": "all"
}
},
{
"lane": "upgrade",
"harness_repository": "rustfs/s3chaos",
"harness_sha": "2222222222222222222222222222222222222222",
"timeout_seconds": 3600,
"environment_capabilities": [
"process-exec",
"previous-release-artifact"
],
"cases": [
"upgrade-smoke"
],
"applies_to": {
"release_types": [
"prerelease",
"stable"
],
"platforms": [
{
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
}
]
}
}
],
"upgrade_sources": {
"basis": "Fixture-only synthetic source. Product plans must cite the real pinned digests of the exercised upgrade sources and must not invent compatibility.",
"sources": [
{
"version": "0.0.1",
"role": "N-1",
"artifact_name": "fixture-upgrade-source.zip",
"artifact_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
],
"rollback_supported": false,
"rollback_basis": "The fixture certifies no rollback support; rollback is never a default claim."
}
}
@@ -1 +0,0 @@
swapped package bytes
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 1,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 1,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 1,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 1,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 1,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "timed_out"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:02:00Z",
"finished_at": "2026-09-26T10:02:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-aarch64-gnu.json",
"sha256": "fa138d5891e5098b97137b0edbb4779c4350285fdc76cec7e6214809b34b3075",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-aarch64-gnu",
"platform": {
"os": "linux",
"arch": "aarch64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:03:00Z",
"finished_at": "2026-09-26T10:03:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-aarch64-gnu.json",
"sha256": "314b19c4fee5f406cbf7ee0d6a436059115f1ff06f6864830045f9d452ab91c9",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-aarch64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "artifact-identity",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:00:00Z",
"finished_at": "2026-09-26T10:00:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/artifact-identity-linux-x86_64-gnu.json",
"sha256": "37e58ec3fc6fe3ac7ff2fcbeebdb62f6a6aaaa34ec771a0f3306c821da0336f7",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "identity",
"case_id": "startup",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "1111111111111111111111111111111111111111",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:01:00Z",
"finished_at": "2026-09-26T10:01:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/identity/startup-linux-x86_64-gnu.json",
"sha256": "8b8774175c55c400b337610a89fe725ad2637af8fcc4973a82ab218f9182b80d",
"size": 64
}
],
"workflow": {
"repository": "someone/fork",
"workflow_id": "release-gate.yml",
"run_id": "child-identity-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "1111111111111111111111111111111111111111"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
@@ -1,42 +0,0 @@
{
"schema_version": 1,
"evidence_profile": "release-artifact",
"run_id": "fixture-batch-1",
"run_attempt": 2,
"plan_sha256": "578bb57e65df8ba7a63e40aafc254fa644163270b7ec288fe3368bcd7c10ff86",
"tier": "release-certification",
"lane": "upgrade",
"case_id": "upgrade-smoke",
"product_commit": "3333333333333333333333333333333333333333",
"harness_commit": "2222222222222222222222222222222222222222",
"target_fingerprint": "rustfs-9.9.9-fixture-linux-x86_64-gnu",
"platform": {
"os": "linux",
"arch": "x86_64",
"abi": "gnu"
},
"started_at": "2026-09-26T10:04:00Z",
"finished_at": "2026-09-26T10:04:30Z",
"state": "pass",
"reason_code": "ok",
"reason_class": "NOT_APPLICABLE",
"evidence": [
{
"path": "cases/upgrade/upgrade-smoke-linux-x86_64-gnu.json",
"sha256": "c1ce56808b52859d2590b34b5990aed7bf560b134e44bd0c09f1873c9f764b38",
"size": 64
}
],
"workflow": {
"repository": "rustfs/s3chaos",
"workflow_id": "release-gate.yml",
"run_id": "child-upgrade-linux-x86_64-gnu",
"run_attempt": 1,
"workflow_sha": "2222222222222222222222222222222222222222"
},
"artifact": {
"archive_sha256": "ea3ac1fb0ec4aa8fbec650f64ccdbc2543843c8d5734c3915d1b57d7cbb92ec8",
"binary_sha256": "7b77e78cc7b8f63a60f8a7101bebed6502f82e03016f4d4e11450f927e0a52fa",
"container_image_digest": "sha256:5555555555555555555555555555555555555555555555555555555555555555"
}
}
-6
View File
@@ -1,6 +0,0 @@
{
"schema_version": 1,
"run_id": "fixture-batch-1",
"run_attempt": 2,
"status": "completed"
}

Some files were not shown because too many files have changed in this diff Show More