mirror of
https://github.com/rustfs/rustfs.git
synced 2026-10-27 14:27:10 +00:00
Compare commits
6 Commits
1.0.2-preview.2
...
1.0.4
| Author | SHA1 | Date | |
|---|---|---|---|
| 46337942d5 | |||
| 46e56019eb | |||
| e02c27feaf | |||
| 440f831d12 | |||
| 0ad3afcf0a | |||
| 331fb89628 |
@@ -27,6 +27,7 @@ script-tests: ## Run shell script tests
|
||||
trap 'status=$$?; printf "ERROR: script-tests failed (exit %s): %s\n" "$$status" "$$BASH_COMMAND" >&2; exit "$$status"' ERR
|
||||
./scripts/test_build_rustfs_options.sh
|
||||
./scripts/test_docker_runtime_timezone.sh
|
||||
sh ./scripts/test_ca_bundle.sh
|
||||
./scripts/test_entrypoint_credentials.sh
|
||||
./scripts/test_internode_grpc_ab_bench.sh
|
||||
./scripts/test_object_batch_bench_enhanced.sh
|
||||
|
||||
@@ -322,7 +322,8 @@ jobs:
|
||||
download_console_assets() {
|
||||
local curl_bin="curl"
|
||||
local python_bin="python3"
|
||||
local console_api="https://api.github.com/repos/rustfs/console/releases/latest"
|
||||
# Preserve the reviewed 1.0.3 Console in this security-only release branch.
|
||||
local console_api="https://api.github.com/repos/rustfs/console/releases/tags/v0.1.37"
|
||||
local console_json="console-release.json"
|
||||
local console_url
|
||||
local console_sha256
|
||||
@@ -359,12 +360,15 @@ jobs:
|
||||
release = json.load(handle)
|
||||
|
||||
tag = release.get("tag_name", "") or "unknown"
|
||||
if tag != "v0.1.37":
|
||||
raise SystemExit("Console release does not match the security-release pin")
|
||||
expected_digest = "sha256:e6ff2c7e7695de824ec4cda91d8611d1aba5d8462e6809592c92a50b23f5b9ab"
|
||||
|
||||
for asset in release.get("assets", []):
|
||||
name = asset.get("name", "")
|
||||
digest = asset.get("digest", "")
|
||||
url = asset.get("browser_download_url", "")
|
||||
if name.startswith("rustfs-console-") and name.endswith(".zip") and digest.startswith("sha256:") and url:
|
||||
if name == "rustfs-console-v0.1.37.zip" and digest == expected_digest and url:
|
||||
sha256 = digest.split(":", 1)[1]
|
||||
if not re.fullmatch(r"[0-9a-fA-F]{64}", sha256):
|
||||
raise SystemExit(f"console zip asset has invalid sha256 digest: {sha256}")
|
||||
|
||||
Generated
+341
-382
File diff suppressed because it is too large
Load Diff
+81
-81
@@ -74,7 +74,7 @@ edition = "2024"
|
||||
license = "Apache-2.0"
|
||||
repository = "https://github.com/rustfs/rustfs"
|
||||
rust-version = "1.99.0"
|
||||
version = "1.0.2"
|
||||
version = "1.0.4"
|
||||
homepage = "https://rustfs.com"
|
||||
description = "RustFS is a high-performance distributed object storage software built using Rust, one of the most popular languages worldwide. "
|
||||
keywords = ["RustFS", "Minio", "object-storage", "filesystem", "s3"]
|
||||
@@ -91,62 +91,62 @@ redundant_clone = "warn"
|
||||
|
||||
[workspace.dependencies]
|
||||
# RustFS Internal Crates
|
||||
rustfs = { path = "./rustfs", version = "1.0.2" }
|
||||
rustfs-heal = { path = "crates/heal", version = "1.0.2" }
|
||||
rustfs-heal-contracts = { path = "crates/heal-contracts", version = "1.0.2" }
|
||||
rustfs-scanner-metrics = { path = "crates/scanner-metrics", version = "1.0.2" }
|
||||
rustfs-audit = { path = "crates/audit", version = "1.0.2" }
|
||||
rustfs-checksums = { path = "crates/checksums", version = "1.0.2" }
|
||||
rustfs-common = { path = "crates/common", version = "1.0.2" }
|
||||
rustfs-data-usage = { path = "crates/data-usage", version = "1.0.2" }
|
||||
rustfs-config = { path = "./crates/config", version = "1.0.2" }
|
||||
rustfs-concurrency = { path = "./crates/concurrency", version = "1.0.2" }
|
||||
rustfs-credentials = { path = "crates/credentials", version = "1.0.2" }
|
||||
rustfs-crypto = { path = "crates/crypto", version = "1.0.2" }
|
||||
rustfs-ecstore = { path = "crates/ecstore", version = "1.0.2" }
|
||||
rustfs-filemeta = { path = "crates/filemeta", version = "1.0.2" }
|
||||
rustfs-iam = { path = "crates/iam", version = "1.0.2" }
|
||||
rustfs-keystone = { path = "crates/keystone", version = "1.0.2" }
|
||||
rustfs-license = { path = "crates/license", version = "1.0.2" }
|
||||
rustfs-lifecycle = { path = "crates/lifecycle", version = "1.0.2" }
|
||||
rustfs-kms = { path = "crates/kms", version = "1.0.2" }
|
||||
rustfs-lock = { path = "crates/lock", version = "1.0.2" }
|
||||
rustfs-madmin = { path = "crates/madmin", version = "1.0.2" }
|
||||
rustfs-notify = { path = "crates/notify", version = "1.0.2" }
|
||||
rustfs-io-metrics = { path = "crates/io-metrics", version = "1.0.2" }
|
||||
rustfs-io-core = { path = "crates/io-core", version = "1.0.2" }
|
||||
rustfs-object-capacity = { path = "crates/object-capacity", version = "1.0.2" }
|
||||
rustfs-object-data-cache = { path = "crates/object-data-cache", version = "1.0.2", default-features = false }
|
||||
rustfs-log-analyzer = { path = "crates/log-analyzer", version = "1.0.2" }
|
||||
rustfs-obs = { path = "crates/obs", version = "1.0.2" }
|
||||
rustfs-policy = { path = "crates/policy", version = "1.0.2" }
|
||||
rustfs-protos = { path = "crates/protos", version = "1.0.2" }
|
||||
rustfs-protocols = { path = "crates/protocols", version = "1.0.2" }
|
||||
rustfs-replication = { path = "crates/replication", version = "1.0.2" }
|
||||
rustfs-rio = { path = "crates/rio", version = "1.0.2" }
|
||||
rustfs-rio-v2 = { path = "crates/rio-v2", version = "1.0.2" }
|
||||
rustfs-s3-client = { path = "crates/s3-client", version = "1.0.2" }
|
||||
rustfs-s3-types = { path = "crates/s3-types", version = "1.0.2" }
|
||||
rustfs-s3-ops = { path = "crates/s3-ops", version = "1.0.2" }
|
||||
rustfs-s3select-api = { path = "crates/s3select-api", version = "1.0.2" }
|
||||
rustfs-s3select-query = { path = "crates/s3select-query", version = "1.0.2" }
|
||||
rustfs-scanner = { path = "crates/scanner", version = "1.0.2" }
|
||||
rustfs-security-governance = { path = "crates/security-governance", version = "1.0.2" }
|
||||
rustfs-extension-schema = { path = "crates/extension-schema", version = "1.0.2" }
|
||||
rustfs-signer = { path = "crates/signer", version = "1.0.2" }
|
||||
rustfs-storage-api = { path = "crates/storage-api", version = "1.0.2" }
|
||||
rustfs-trusted-proxies = { path = "crates/trusted-proxies", version = "1.0.2" }
|
||||
rustfs-targets = { path = "crates/targets", version = "1.0.2" }
|
||||
rustfs-test-utils = { path = "crates/test-utils", version = "1.0.2" }
|
||||
rustfs-tls-runtime = { path = "crates/tls-runtime", version = "1.0.2" }
|
||||
rustfs-utils = { path = "crates/utils", version = "1.0.2" }
|
||||
rustfs-zip = { path = "./crates/zip", version = "1.0.2" }
|
||||
rustfs = { path = "./rustfs", version = "1.0.4" }
|
||||
rustfs-heal = { path = "crates/heal", version = "1.0.4" }
|
||||
rustfs-heal-contracts = { path = "crates/heal-contracts", version = "1.0.4" }
|
||||
rustfs-scanner-metrics = { path = "crates/scanner-metrics", version = "1.0.4" }
|
||||
rustfs-audit = { path = "crates/audit", version = "1.0.4" }
|
||||
rustfs-checksums = { path = "crates/checksums", version = "1.0.4" }
|
||||
rustfs-common = { path = "crates/common", version = "1.0.4" }
|
||||
rustfs-data-usage = { path = "crates/data-usage", version = "1.0.4" }
|
||||
rustfs-config = { path = "./crates/config", version = "1.0.4" }
|
||||
rustfs-concurrency = { path = "./crates/concurrency", version = "1.0.4" }
|
||||
rustfs-credentials = { path = "crates/credentials", version = "1.0.4" }
|
||||
rustfs-crypto = { path = "crates/crypto", version = "1.0.4" }
|
||||
rustfs-ecstore = { path = "crates/ecstore", version = "1.0.4" }
|
||||
rustfs-filemeta = { path = "crates/filemeta", version = "1.0.4" }
|
||||
rustfs-iam = { path = "crates/iam", version = "1.0.4" }
|
||||
rustfs-keystone = { path = "crates/keystone", version = "1.0.4" }
|
||||
rustfs-license = { path = "crates/license", version = "1.0.4" }
|
||||
rustfs-lifecycle = { path = "crates/lifecycle", version = "1.0.4" }
|
||||
rustfs-kms = { path = "crates/kms", version = "1.0.4" }
|
||||
rustfs-lock = { path = "crates/lock", version = "1.0.4" }
|
||||
rustfs-madmin = { path = "crates/madmin", version = "1.0.4" }
|
||||
rustfs-notify = { path = "crates/notify", version = "1.0.4" }
|
||||
rustfs-io-metrics = { path = "crates/io-metrics", version = "1.0.4" }
|
||||
rustfs-io-core = { path = "crates/io-core", version = "1.0.4" }
|
||||
rustfs-object-capacity = { path = "crates/object-capacity", version = "1.0.4" }
|
||||
rustfs-object-data-cache = { path = "crates/object-data-cache", version = "1.0.4", default-features = false }
|
||||
rustfs-log-analyzer = { path = "crates/log-analyzer", version = "1.0.4" }
|
||||
rustfs-obs = { path = "crates/obs", version = "1.0.4" }
|
||||
rustfs-policy = { path = "crates/policy", version = "1.0.4" }
|
||||
rustfs-protos = { path = "crates/protos", version = "1.0.4" }
|
||||
rustfs-protocols = { path = "crates/protocols", version = "1.0.4" }
|
||||
rustfs-replication = { path = "crates/replication", version = "1.0.4" }
|
||||
rustfs-rio = { path = "crates/rio", version = "1.0.4" }
|
||||
rustfs-rio-v2 = { path = "crates/rio-v2", version = "1.0.4" }
|
||||
rustfs-s3-client = { path = "crates/s3-client", version = "1.0.4" }
|
||||
rustfs-s3-types = { path = "crates/s3-types", version = "1.0.4" }
|
||||
rustfs-s3-ops = { path = "crates/s3-ops", version = "1.0.4" }
|
||||
rustfs-s3select-api = { path = "crates/s3select-api", version = "1.0.4" }
|
||||
rustfs-s3select-query = { path = "crates/s3select-query", version = "1.0.4" }
|
||||
rustfs-scanner = { path = "crates/scanner", version = "1.0.4" }
|
||||
rustfs-security-governance = { path = "crates/security-governance", version = "1.0.4" }
|
||||
rustfs-extension-schema = { path = "crates/extension-schema", version = "1.0.4" }
|
||||
rustfs-signer = { path = "crates/signer", version = "1.0.4" }
|
||||
rustfs-storage-api = { path = "crates/storage-api", version = "1.0.4" }
|
||||
rustfs-trusted-proxies = { path = "crates/trusted-proxies", version = "1.0.4" }
|
||||
rustfs-targets = { path = "crates/targets", version = "1.0.4" }
|
||||
rustfs-test-utils = { path = "crates/test-utils", version = "1.0.4" }
|
||||
rustfs-tls-runtime = { path = "crates/tls-runtime", version = "1.0.4" }
|
||||
rustfs-utils = { path = "crates/utils", version = "1.0.4" }
|
||||
rustfs-zip = { path = "./crates/zip", version = "1.0.4" }
|
||||
|
||||
# Async Runtime and Networking
|
||||
async-channel = "2.5.0"
|
||||
async_zip = { default-features = false, version = "0.0.19" }
|
||||
mysql_async = { default-features = false, version = "0.37.1" }
|
||||
async-compression = { version = "0.4.50" }
|
||||
async-compression = { version = "0.4.51" }
|
||||
async-trait = "0.1.92"
|
||||
async-nats = { version = "0.50.0", default-features = false }
|
||||
axum = "0.8.9"
|
||||
@@ -155,8 +155,8 @@ futures-core = "0.3.34"
|
||||
futures-lite = "2.6.1"
|
||||
futures-util = "0.3.34"
|
||||
pollster = "1.0.1"
|
||||
pulsar = { default-features = false, version = "6.9.0" }
|
||||
lapin = { default-features = false, version = "4.12.2" }
|
||||
pulsar = { default-features = false, version = "=6.9.0" }
|
||||
lapin = { default-features = false, version = "4.12.3" }
|
||||
hyper = { version = "1.12.0" }
|
||||
h2 = { version = "0.4.20" }
|
||||
hyper-rustls = { default-features = false, version = "0.27.10" }
|
||||
@@ -169,7 +169,7 @@ minlz = "1.2.3"
|
||||
reqwest = "0.13.5"
|
||||
rustfs-kafka-async = { version = "1.4.0" }
|
||||
socket2 = { version = "0.6.5" }
|
||||
tokio = { version = "1.53.3" }
|
||||
tokio = { version = "1.54.1" }
|
||||
tokio-rustls = { default-features = false, version = "0.26.6" }
|
||||
tokio-stream = { version = "0.1.19" }
|
||||
tokio-test = "0.4.6"
|
||||
@@ -220,7 +220,7 @@ openidconnect = { default-features = false, version = "4.0" }
|
||||
pbkdf2 = "0.13.0"
|
||||
p256 = { version = "0.14.0", features = ["ecdsa", "pkcs8"] }
|
||||
rsa = { version = "=0.10.0-rc.18" }
|
||||
rustls = { default-features = false, version = "0.23.45" }
|
||||
rustls = { default-features = false, version = "0.23.46" }
|
||||
rustls-native-certs = "0.8"
|
||||
rustls-pki-types = "1.15.1"
|
||||
x509-parser = "0.18.1"
|
||||
@@ -243,22 +243,22 @@ tokio-postgres-rustls = "0.14.0"
|
||||
|
||||
# Utilities and Tools
|
||||
anyhow = "1.0.104"
|
||||
arc-swap = "1.9.2"
|
||||
arc-swap = "1.9.3"
|
||||
rustfs-tokio-tar = { version = "0.7.1" }
|
||||
# Candidate Snowball parser versions exercised by rustfs-zip compatibility fixtures.
|
||||
tar-codec = "0.0.14"
|
||||
tar-framing = "0.0.14"
|
||||
atoi = "3.1.0"
|
||||
atoi = "3.1.1"
|
||||
atomic_enum = "0.3.0"
|
||||
aws-config = { version = "1.12.0" }
|
||||
aws-credential-types = { version = "1.3.0" }
|
||||
aws-sdk-kms = { default-features = false, version = "1.123.0" }
|
||||
aws-sdk-s3 = { default-features = false, version = "1.152.0" }
|
||||
aws-sdk-sts = { default-features = false, version = "1.119.0" }
|
||||
aws-smithy-async = { version = "1.3.0" }
|
||||
aws-smithy-http-client = { default-features = false, version = "1.5.0" }
|
||||
aws-smithy-runtime-api = { version = "1.19.0" }
|
||||
aws-smithy-types = { version = "1.8.1" }
|
||||
aws-config = { version = "1.13.0" }
|
||||
aws-credential-types = { version = "1.3.1" }
|
||||
aws-sdk-kms = { default-features = false, version = "1.126.0" }
|
||||
aws-sdk-s3 = { default-features = false, version = "1.155.0" }
|
||||
aws-sdk-sts = { default-features = false, version = "1.122.0" }
|
||||
aws-smithy-async = { version = "1.3.1" }
|
||||
aws-smithy-http-client = { default-features = false, version = "1.5.1" }
|
||||
aws-smithy-runtime-api = { version = "1.19.1" }
|
||||
aws-smithy-types = { version = "1.9.0" }
|
||||
base64-simd = "0.8.0"
|
||||
brotli = "9.0.0"
|
||||
clap = { version = "4.6.7" }
|
||||
@@ -272,12 +272,12 @@ crossbeam-utils = "0.8.23"
|
||||
datafusion = { default-features = false, version = "55.2.0" }
|
||||
derive_builder = "0.20.2"
|
||||
ed25519-dalek = "3.0.0"
|
||||
enumset = "1.1.14"
|
||||
enumset = "1.1.15"
|
||||
faster-hex = "1.0.0"
|
||||
flate2 = "1.1.10"
|
||||
glob = "0.3.4"
|
||||
google-cloud-storage = "1.20.0"
|
||||
google-cloud-auth = "1.17.0"
|
||||
google-cloud-storage = "1.21.0"
|
||||
google-cloud-auth = "1.18.0"
|
||||
hashbrown = { version = "0.17.1" }
|
||||
# Base32 for RFC 6238 TOTP shared secrets (RFC 4648 unpadded, the alphabet
|
||||
# every authenticator app expects). Already in the graph transitively.
|
||||
@@ -287,11 +287,11 @@ highway = { version = "1.3.0" }
|
||||
hostname = "0.4.2"
|
||||
ipnetwork = { version = "0.21.1" }
|
||||
lazy_static = "1.5.1"
|
||||
libc = "0.2.190"
|
||||
libc = "0.2.191"
|
||||
libsystemd = "0.7.2"
|
||||
local-ip-address = "0.6.13"
|
||||
log = "0.4"
|
||||
memmap2 = "0.9.11"
|
||||
memmap2 = "0.9.12"
|
||||
lz4 = "1.28.1"
|
||||
matchit = "0.9.2"
|
||||
md-5 = "0.11.0"
|
||||
@@ -317,7 +317,7 @@ rustfs-erasure-codec = { version = "9.0.0" }
|
||||
reed-solomon-simd = "3.1.0"
|
||||
regex = { version = "1.13.1" }
|
||||
rumqttc = { package = "rumqttc-next", version = "0.34.0" }
|
||||
redis = { version = "1.7.1" }
|
||||
redis = { version = "1.8.0" }
|
||||
rustify = { version = "0.7", default-features = false }
|
||||
rustix = { version = "1.1.5" }
|
||||
rust-embed = { version = "8.13.0" }
|
||||
@@ -327,7 +327,7 @@ s3s-sigv4 = { git = "https://github.com/s3s-project/s3s", rev = "5761ddfe4c509fc
|
||||
serial_test = "4.0.1"
|
||||
shadow-rs = { default-features = false, version = "2.0.0" }
|
||||
siphasher = "1.0.4"
|
||||
smallvec = { version = "1.16.3" }
|
||||
smallvec = { version = "1.16.4" }
|
||||
compact_str = "0.10.0"
|
||||
snap = "1.1.2"
|
||||
starshard = { version = "2.4.0" }
|
||||
@@ -346,7 +346,7 @@ tracing-subscriber = { version = "0.3.23" }
|
||||
transform-stream = "0.3.1"
|
||||
url = "2.5.8"
|
||||
urlencoding = "2.1.3"
|
||||
uuid = { version = "1.28.0" }
|
||||
uuid = { version = "1.29.0" }
|
||||
vaultrs = { version = "0.8.0" }
|
||||
tar = "0.4.46"
|
||||
walkdir = "2.5.0"
|
||||
@@ -354,13 +354,13 @@ winapi-util = "0.1.11"
|
||||
windows = { version = "0.62.2" }
|
||||
windows-sys = "0.61.2"
|
||||
xxhash-rust = { version = "0.8.19" }
|
||||
zip = "9.0.3"
|
||||
zstd = "0.14.2"
|
||||
zip = "9.1.0"
|
||||
zstd = "0.14.3"
|
||||
|
||||
# Observability and Metrics
|
||||
metrics = "0.24.6"
|
||||
metrics-util = "0.20"
|
||||
dial9 = { version = "0.5.4", default-features = false }
|
||||
dial9 = { version = "0.5.5", default-features = false }
|
||||
opentelemetry = { version = "0.33.1" }
|
||||
opentelemetry-appender-tracing = { version = "0.33.1" }
|
||||
opentelemetry-otlp = { version = "0.33.1" }
|
||||
@@ -368,12 +368,12 @@ opentelemetry-proto = { version = "0.33.1", default-features = false, features =
|
||||
opentelemetry_sdk = { version = "0.33.1" }
|
||||
opentelemetry-semantic-conventions = { version = "0.33.1" }
|
||||
opentelemetry-stdout = { version = "0.33.1" }
|
||||
pyroscope = { version = "2.1.2" }
|
||||
pyroscope = { version = "2.1.5" }
|
||||
|
||||
# FTP and SFTP
|
||||
libunftp = { version = "0.23.1" }
|
||||
unftp-core = "0.1.0"
|
||||
suppaftp = { version = "12.2.0" }
|
||||
suppaftp = { version = "12.2.1" }
|
||||
rcgen = { version = "0.14.10", default-features = false, features = ["aws_lc_rs", "crypto", "pem"] }
|
||||
russh = { version = "0.64.1" }
|
||||
russh-sftp = "3.0.1"
|
||||
@@ -384,7 +384,7 @@ dav-server = "0.11.0"
|
||||
# Performance Analysis and Memory Profiling
|
||||
rustfs-mimalloc = { version = "0.5.6" }
|
||||
# Preserve Unicode focus filters until rustfs/backlog#2302 is resolved.
|
||||
hotpath = { version = "0.28.6", default-features = false }
|
||||
hotpath = { version = "0.28.7", default-features = false }
|
||||
# Snapshot testing for output format regression detection
|
||||
insta = { version = "1.49" }
|
||||
|
||||
|
||||
+14
-1
@@ -18,6 +18,13 @@ ARG TARGETARCH
|
||||
ARG RELEASE=latest
|
||||
|
||||
RUN apk add --no-cache ca-certificates curl jq unzip
|
||||
# Keep the native store safe even if the distribution CA package lags distrust.
|
||||
COPY scripts/check_ca_bundle.sh /tmp/check_ca_bundle.sh
|
||||
RUN sed -i '/^mozilla\/emSign_ECC_Root_CA_-_G3.crt$/s/^/!/' /etc/ca-certificates.conf && \
|
||||
update-ca-certificates --fresh && \
|
||||
sh /tmp/check_ca_bundle.sh /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs && \
|
||||
rm /tmp/check_ca_bundle.sh
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
RUN set -eux; \
|
||||
@@ -98,7 +105,13 @@ RUN apk upgrade --no-cache && \
|
||||
tzdata \
|
||||
&& test "$(TZ=Asia/Kolkata date +%z)" = "+0530"
|
||||
|
||||
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
|
||||
# Keep the native store safe even if the distribution CA package lags distrust.
|
||||
COPY scripts/check_ca_bundle.sh /tmp/check_ca_bundle.sh
|
||||
RUN sed -i '/^mozilla\/emSign_ECC_Root_CA_-_G3.crt$/s/^/!/' /etc/ca-certificates.conf && \
|
||||
update-ca-certificates --fresh && \
|
||||
sh /tmp/check_ca_bundle.sh /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs && \
|
||||
rm /tmp/check_ca_bundle.sh
|
||||
|
||||
COPY --from=build /build/rustfs /usr/bin/rustfs
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
|
||||
@@ -24,6 +24,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
unzip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Keep the native store safe even if the distribution CA package lags distrust.
|
||||
COPY scripts/check_ca_bundle.sh /tmp/check_ca_bundle.sh
|
||||
RUN sed -i '/^mozilla\/emSign_ECC_Root_CA_-_G3.crt$/s/^/!/' /etc/ca-certificates.conf && \
|
||||
update-ca-certificates --fresh && \
|
||||
sh /tmp/check_ca_bundle.sh /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs && \
|
||||
rm /tmp/check_ca_bundle.sh
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
RUN set -eux; \
|
||||
@@ -103,6 +110,13 @@ RUN apt-get update && apt-get upgrade -y \
|
||||
&& test "$(TZ=Asia/Kolkata date +%z)" = "+0530" \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Keep the native store safe even if the distribution CA package lags distrust.
|
||||
COPY scripts/check_ca_bundle.sh /tmp/check_ca_bundle.sh
|
||||
RUN sed -i '/^mozilla\/emSign_ECC_Root_CA_-_G3.crt$/s/^/!/' /etc/ca-certificates.conf && \
|
||||
update-ca-certificates --fresh && \
|
||||
sh /tmp/check_ca_bundle.sh /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs && \
|
||||
rm /tmp/check_ca_bundle.sh
|
||||
|
||||
COPY --from=build /build/rustfs /usr/bin/rustfs
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
|
||||
@@ -1206,7 +1206,9 @@ mod tests {
|
||||
let interval = interval
|
||||
.filter(|interval| *interval != 0)
|
||||
.ok_or("scanner schedule has no positive interval")?;
|
||||
let next_cycle = cycle_end
|
||||
// A new leader may already be sleeping before completing its first cycle.
|
||||
let schedule_start = if cycle_end == 0 { now } else { cycle_end };
|
||||
let next_cycle = schedule_start
|
||||
.checked_add(interval)
|
||||
.ok_or("scanner schedule timestamp overflows")?;
|
||||
let budget = next_cycle
|
||||
@@ -1223,6 +1225,11 @@ mod tests {
|
||||
Ok(Duration::from_secs(259)),
|
||||
);
|
||||
assert_eq!(scanner_cycle_completion_budget(100, Some(1), 110, false), Ok(Duration::from_secs(60)));
|
||||
// A newly elected leader can advertise a sleep before its first completed cycle.
|
||||
assert_eq!(
|
||||
scanner_cycle_completion_budget(0, Some(289), 1_792_913_211, false),
|
||||
Ok(Duration::from_secs(349)),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1243,7 +1250,7 @@ mod tests {
|
||||
previous_cycle_end: u64,
|
||||
) -> Result<u64, Box<dyn Error + Send + Sync>> {
|
||||
let mut deadline = Instant::now() + Duration::from_secs(60);
|
||||
let mut schedule_accounted = false;
|
||||
let mut accounted_schedules = HashSet::new();
|
||||
loop {
|
||||
let mut latest_cycle_end = 0;
|
||||
let mut versions_observed = false;
|
||||
@@ -1290,15 +1297,27 @@ mod tests {
|
||||
return Err("scanner cycle timestamp is in the future".into());
|
||||
}
|
||||
let schedule = &status["cycle_schedule"];
|
||||
if !schedule_accounted && schedule["execution_role"].as_str() == Some("leader") {
|
||||
if schedule["execution_role"].as_str() == Some("leader") {
|
||||
let active = metrics["current_cycle_active"]
|
||||
.as_bool()
|
||||
.ok_or("scanner status is missing its active-cycle flag")?;
|
||||
if active || (cycle_end != 0 && schedule["effective_interval_available"].as_bool() == Some(true)) {
|
||||
let interval = schedule["effective_interval_seconds"].as_u64();
|
||||
let budget = scanner_cycle_completion_budget(cycle_end, interval, now, active)?;
|
||||
deadline = Instant::now().checked_add(budget).ok_or("scanner deadline overflows")?;
|
||||
schedule_accounted = true;
|
||||
if active || schedule["effective_interval_available"].as_bool() == Some(true) {
|
||||
let interval = if active {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
schedule["effective_interval_seconds"]
|
||||
.as_u64()
|
||||
.ok_or("scanner schedule is missing its effective interval")?,
|
||||
)
|
||||
};
|
||||
// Reconsider a changed leader or retry plan, but never renew
|
||||
// the deadline on repeated observations of the same sleep.
|
||||
if accounted_schedules.insert((node_index, cycle_end, interval)) {
|
||||
let budget = scanner_cycle_completion_budget(cycle_end, interval, now, active)?;
|
||||
let scheduled_deadline = Instant::now().checked_add(budget).ok_or("scanner deadline overflows")?;
|
||||
deadline = deadline.max(scheduled_deadline);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Superseded walks complete all sets while withholding quota authority.
|
||||
|
||||
@@ -51,7 +51,7 @@ thiserror = { workspace = true }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
# Keep XZ decoding self-contained in macOS binaries instead of linking Homebrew liblzma.
|
||||
liblzma = { version = "0.4.8", features = ["static"] }
|
||||
liblzma = { version = "0.4.9", features = ["static"] }
|
||||
|
||||
[dev-dependencies]
|
||||
rustfs-tokio-tar = { workspace = true }
|
||||
|
||||
Generated
+345
-288
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
# Reject the distrusted emSign ECC Root CA - G3 in native trust stores.
|
||||
set -eu
|
||||
|
||||
bundle=${1:?Usage: check_ca_bundle.sh BUNDLE CERT_DIRECTORY}
|
||||
cert_directory=${2:?Usage: check_ca_bundle.sh BUNDLE CERT_DIRECTORY}
|
||||
distrusted_sha256=86a1ecba089c4a8d3bbe2734c612ba341d813e043cf9e8a862cd5c57a36bbe6b
|
||||
scratch=$(mktemp -d)
|
||||
trap 'rm -rf "$scratch"' EXIT HUP INT TERM
|
||||
|
||||
check_file() {
|
||||
# Hash DER, not subject text or PEM formatting. Also inspect hashed links:
|
||||
# native trust consumers may use the directory rather than the bundle.
|
||||
awk '
|
||||
/-----BEGIN CERTIFICATE-----/ { if (inside) exit 1; inside=1; cert=""; next }
|
||||
/-----END CERTIFICATE-----/ { if (!inside) exit 1; print cert; inside=0; next }
|
||||
inside { gsub(/[[:space:]]/, ""); cert=cert $0 }
|
||||
END { if (inside) exit 1 }
|
||||
' "$1" > "$scratch/certificates"
|
||||
while IFS= read -r encoded; do
|
||||
printf '%s' "$encoded" | base64 -d > "$scratch/certificate.der"
|
||||
if [ ! -s "$scratch/certificate.der" ]; then
|
||||
echo "Empty certificate in $1" >&2
|
||||
return 1
|
||||
fi
|
||||
digest=$(sha256sum "$scratch/certificate.der")
|
||||
digest=${digest%% *}
|
||||
if [ "$digest" = "$distrusted_sha256" ]; then
|
||||
echo "Distrusted emSign ECC Root CA - G3 found in $1" >&2
|
||||
return 1
|
||||
fi
|
||||
done < "$scratch/certificates"
|
||||
}
|
||||
|
||||
check_file "$bundle"
|
||||
if [ ! -s "$scratch/certificates" ]; then
|
||||
echo "CA bundle contains no certificates: $bundle" >&2
|
||||
exit 1
|
||||
fi
|
||||
find -L "$cert_directory" -type f > "$scratch/files"
|
||||
while IFS= read -r file; do
|
||||
check_file "$file"
|
||||
done < "$scratch/files"
|
||||
@@ -0,0 +1,15 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG
|
||||
EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo
|
||||
bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g
|
||||
RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ
|
||||
TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s
|
||||
b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw
|
||||
djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0
|
||||
WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS
|
||||
fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB
|
||||
zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq
|
||||
hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB
|
||||
CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD
|
||||
+JbNR6iC8hZVdyR+EhCVBCyj
|
||||
-----END CERTIFICATE-----
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
repo_root=$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
scratch=$(mktemp -d)
|
||||
trap 'rm -rf "$scratch"' EXIT HUP INT TERM
|
||||
mkdir "$scratch/certs"
|
||||
# A public root from webpki-roots 1.0.9, not a private key or active trust anchor.
|
||||
distrusted="$repo_root/scripts/fixtures/distrusted-emsign-g3.pem"
|
||||
openssl req -x509 -newkey rsa:2048 -nodes -days 1 -subj /CN=ca-bundle-test \
|
||||
-keyout "$scratch/key.pem" -out "$scratch/valid.pem" >/dev/null 2>&1
|
||||
cp "$scratch/valid.pem" "$scratch/bundle.pem"
|
||||
check() {
|
||||
sh "$repo_root/scripts/check_ca_bundle.sh" "$scratch/bundle.pem" "$scratch/certs"
|
||||
}
|
||||
reject() {
|
||||
if check > "$scratch/output" 2>&1; then
|
||||
echo "Expected CA rejection: $1" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
check
|
||||
cat "$distrusted" >> "$scratch/bundle.pem"
|
||||
reject 'G3 after a valid certificate in the bundle'
|
||||
cp "$scratch/valid.pem" "$scratch/bundle.pem"
|
||||
cp "$distrusted" "$scratch/certs/renamed-root.pem"
|
||||
reject 'G3 in directory with an unrelated name'
|
||||
rm "$scratch/certs/renamed-root.pem"
|
||||
ln -s "$distrusted" "$scratch/certs/12345678.0"
|
||||
reject 'G3 through a hashed trust-directory symlink'
|
||||
rm "$scratch/certs/12345678.0"
|
||||
# Equivalent PEM encodings must not defeat DER-based detection.
|
||||
printf '%s\n' '-----BEGIN CERTIFICATE-----' > "$scratch/bundle.pem"
|
||||
sed '/-----/d' "$distrusted" | tr -d '\n' >> "$scratch/bundle.pem"
|
||||
printf '\n%s\n' '-----END CERTIFICATE-----' >> "$scratch/bundle.pem"
|
||||
reject 'G3 with unwrapped PEM body'
|
||||
printf '%s\n' '-----BEGIN CERTIFICATE-----' > "$scratch/bundle.pem"
|
||||
reject 'truncated bundle'
|
||||
printf '%s\n' '-----BEGIN CERTIFICATE-----' '-----END CERTIFICATE-----' > "$scratch/bundle.pem"
|
||||
reject 'empty PEM body'
|
||||
: > "$scratch/bundle.pem"
|
||||
reject 'empty bundle'
|
||||
cp "$scratch/valid.pem" "$scratch/bundle.pem"
|
||||
check
|
||||
printf '%s\n' 'CA bundle regression checks passed'
|
||||
@@ -45,6 +45,32 @@ def archive(path, members, binary):
|
||||
|
||||
|
||||
class ReleaseBuildTests(unittest.TestCase):
|
||||
def test_security_release_console_pin(self):
|
||||
script = shell_body(STEPS['Download static console assets'])
|
||||
self.assertIn('releases/tags/v0.1.37', script)
|
||||
self.assertNotIn('console/releases/latest', script)
|
||||
parser = re.search(r"<<'PY'\n(.*?)\nPY", script, re.S)[1]
|
||||
expected_digest = 'sha256:e6ff2c7e7695de824ec4cda91d8611d1aba5d8462e6809592c92a50b23f5b9ab'
|
||||
asset = {'name': 'rustfs-console-v0.1.37.zip', 'digest': expected_digest,
|
||||
'browser_download_url': 'https://github.com/rustfs/console/releases/download/v0.1.37/rustfs-console-v0.1.37.zip'}
|
||||
cases = [
|
||||
('exact pin', 'v0.1.37', asset, True),
|
||||
('different tag', 'v0.1.38', asset, False),
|
||||
('different name', 'v0.1.37', {**asset, 'name': 'rustfs-console-v0.1.38.zip'}, False),
|
||||
('different digest', 'v0.1.37', {**asset, 'digest': 'sha256:' + '0' * 64}, False),
|
||||
('missing URL', 'v0.1.37', {**asset, 'browser_download_url': ''}, False),
|
||||
]
|
||||
for name, tag, entry, accepted in cases:
|
||||
with self.subTest(name=name), tempfile.TemporaryDirectory() as directory:
|
||||
metadata = Path(directory) / 'release.json'
|
||||
metadata.write_text(json.dumps({'tag_name': tag, 'assets': [entry]}))
|
||||
result = subprocess.run([sys.executable, '-c', parser, str(metadata)],
|
||||
capture_output=True, text=True)
|
||||
self.assertEqual(result.returncode == 0, accepted, result.stderr)
|
||||
if accepted:
|
||||
self.assertEqual(result.stdout.split(),
|
||||
['v0.1.37', asset['browser_download_url'], expected_digest.split(':')[1]])
|
||||
|
||||
def test_every_matrix_target_builds_only_server(self):
|
||||
mock_cargo = r'''
|
||||
cargo() {
|
||||
|
||||
Reference in New Issue
Block a user