diff --git a/.github/goreleaser.yml b/.github/goreleaser.yml index fe34fd53d..7370223f9 100644 --- a/.github/goreleaser.yml +++ b/.github/goreleaser.yml @@ -4,9 +4,9 @@ env: - CGO_ENABLED=0 builds: - - id: minio + - id: silo main: . - binary: minio + binary: silo goos: - linux - darwin @@ -23,18 +23,50 @@ builds: - "{{ .Env.LDFLAGS }}" archives: - - id: minio + - id: silo ids: - - minio - name_template: "minio_{{ .Env.PKG_VERSION }}_{{ .Os }}_{{ .Arch }}" + - silo + name_template: "silo_{{ .Env.PKG_VERSION }}_{{ .Os }}_{{ .Arch }}" checksum: - name_template: "minio_{{ .Env.PKG_VERSION }}_checksums.txt" + name_template: "silo_{{ .Env.PKG_VERSION }}_checksums.txt" algorithm: sha256 +# Generate one SPDX JSON document per platform archive. SBOMs are created +# before the checksum stage, so the signed checksum manifest covers both the +# archives and their corresponding software bills of materials. +sboms: + - id: silo-archives + artifacts: archive + # Avoid network-backed package enrichment: the release SBOM must be + # reproducible from the artifact alone and the PR gate must work offline. + args: + - "$artifact" + - "--output" + - "spdx-json=$document" + env: + - SYFT_FILE_METADATA_CATALOGER_ENABLED=true + - SYFT_CHECK_FOR_APP_UPDATE=false + +# A keyless Sigstore bundle is the detached signature for the checksum +# manifest. Consumers can verify the whole archive/SBOM set without trusting a +# long-lived project key copied into the repository. +signs: + - id: silo-checksums + cmd: cosign + signature: "${artifact}.sigstore.json" + args: + - sign-blob + - "--bundle=${signature}" + - "${artifact}" + - --yes + artifacts: checksum + output: true + release: github: owner: pgsty + # Transitional until the irreversible GitHub repository rename. name: minio draft: true prerelease: false diff --git a/.github/nfpm.yml b/.github/nfpm.yml index a19e839ea..05182a793 100644 --- a/.github/nfpm.yml +++ b/.github/nfpm.yml @@ -1,4 +1,4 @@ -name: minio +name: silo arch: ${NFPM_ARCH} platform: linux version: ${PKG_VERSION} @@ -7,26 +7,45 @@ release: ${NFPM_RELEASE} section: utils priority: optional maintainer: "Ruohang Feng (@Vonng) " -description: S3-Interface Libre Object Storage, Community-maintained MinIO server fork. +description: S3-Interface Libre Object Storage, a community-maintained S3-compatible server. vendor: PGSTY homepage: https://silo.pgsty.com license: AGPL-3.0-or-later contents: - src: ${NFPM_SOURCE} - dst: /usr/local/bin/minio + dst: /usr/bin/silo expand: true file_info: mode: 0755 owner: root group: root - src: ${NFPM_UNIT} - dst: /usr/lib/systemd/system/minio.service + dst: /usr/lib/systemd/system/silo.service expand: true file_info: mode: 0644 owner: root group: root + - src: ${NFPM_DEFAULTS} + dst: /etc/default/silo + type: config|noreplace + expand: true + file_info: + mode: 0644 + owner: root + group: root + - src: ${NFPM_SYSUSERS} + dst: /usr/lib/sysusers.d/silo.conf + expand: true + file_info: + mode: 0644 + owner: root + group: root + +scripts: + postinstall: buildscripts/package/postinstall.sh + preremove: buildscripts/package/preremove.sh rpm: group: Applications/File diff --git a/.gitignore b/.gitignore index 24f6fb810..25c29ced3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ cover.out *~ minio +silo !*/ site/ **/*.test diff --git a/Makefile b/Makefile index 45017ff8d..02a3e08a7 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,8 @@ GOARCH ?= $(shell go env GOARCH) GOLANGCI_VERSION ?= v2.11.3 VERSION ?= $(shell git describe --tags) -REPO ?= quay.io/minio -TAG ?= $(REPO)/minio:$(VERSION) +REPO ?= docker.io/pgsty +TAG ?= $(REPO)/silo:$(VERSION) GOLANGCI_DIR = .bin/golangci/$(GOLANGCI_VERSION) GOLANGCI = $(GOLANGCI_DIR)/golangci-lint @@ -33,10 +33,15 @@ getdeps: ## fetch necessary dependencies sh "$$script" -b $(GOLANGCI_DIR) $(GOLANGCI_VERSION); \ fi -crosscompile: ## cross compile minio +crosscompile: ## cross compile Silo @(env bash $(PWD)/buildscripts/cross-compile.sh) -verifiers: lint check-gen +verifiers: lint check-gen rebrand-guard + +rebrand-guard: ## verify Silo branding and protected compatibility identifiers + @go run ./buildscripts/rebrand-guard + @env bash $(PWD)/buildscripts/verify-rebrand.sh + @env bash $(PWD)/dockerscripts/docker-entrypoint_test.sh check-gen: ## check for updated autogenerated files @go generate ./... >/dev/null @@ -64,12 +69,12 @@ lint-fix: getdeps ## runs golangci-lint suite of linters with automatic fixes @$(GOLANGCI) run --build-tags kqueue --timeout=10m --config ./.golangci.yml --fix check: test -test: verifiers build ## builds minio, runs linters, tests +test: verifiers build ## builds Silo, runs linters, tests @echo "Running unit tests" @MINIO_API_REQUESTS_MAX=10000 CGO_ENABLED=0 go test -v -tags kqueue,dev ./... test-root-disable: install-race - @echo "Running minio root lockdown tests" + @echo "Running Silo root lockdown tests" @env bash $(PWD)/buildscripts/disable-root.sh test-ilm: install-race @@ -85,7 +90,7 @@ test-pbac: install-race @env bash $(PWD)/docs/iam/policies/pbac-tests.sh test-decom: install-race - @echo "Running minio decom tests" + @echo "Running Silo decom tests" @env bash $(PWD)/docs/distributed/decom.sh @env bash $(PWD)/docs/distributed/decom-encrypted.sh @env bash $(PWD)/docs/distributed/decom-encrypted-sse-s3.sh @@ -93,17 +98,17 @@ test-decom: install-race @env bash $(PWD)/docs/distributed/decom-encrypted-kes.sh test-versioning: install-race - @echo "Running minio versioning tests" + @echo "Running Silo versioning tests" @env bash $(PWD)/docs/bucket/versioning/versioning-tests.sh test-configfile: install-race @env bash $(PWD)/docs/distributed/distributed-from-config-file.sh -test-upgrade: install-race - @echo "Running minio upgrade tests" +test-upgrade: + @echo "Running MinIO-to-Silo upgrade tests" @(env bash $(PWD)/buildscripts/minio-upgrade.sh) -test-race: verifiers build ## builds minio, runs linters, tests (race) +test-race: verifiers build ## builds Silo, runs linters, tests (race) @echo "Running unit tests under -race" @(env bash $(PWD)/buildscripts/race.sh) @@ -151,9 +156,9 @@ test-site-replication-oidc: install-race ## verify automatic site replication @echo "Running tests for automatic site replication of IAM (with OIDC)" @(env bash $(PWD)/docs/site-replication/run-multi-site-oidc.sh) -test-site-replication-minio: install-race ## verify automatic site replication - @echo "Running tests for automatic site replication of IAM (with MinIO IDP)" - @(env bash $(PWD)/docs/site-replication/run-multi-site-minio-idp.sh) +test-site-replication-silo: install-race ## verify automatic site replication + @echo "Running tests for automatic site replication of IAM (with Silo IDP)" + @(env bash $(PWD)/docs/site-replication/run-multi-site-silo-idp.sh) @echo "Running tests for automatic site replication of SSE-C objects" @(env bash $(PWD)/docs/site-replication/run-ssec-object-replication.sh) @echo "Running tests for automatic site replication of SSE-C objects with SSE-KMS enabled for bucket" @@ -169,11 +174,11 @@ test-timeout: install-race ## test multipart @echo "Test server timeout" @(env bash $(PWD)/buildscripts/test-timeout.sh) -verify: install-race ## verify minio various setups +verify: install-race ## verify Silo in various setups @echo "Verifying build with race" @(env bash $(PWD)/buildscripts/verify-build.sh) -verify-healing: install-race ## verify healing and replacing disks with minio binary +verify-healing: install-race ## verify healing and replacing disks with the Silo binary @echo "Verify healing build with race" @(env bash $(PWD)/buildscripts/verify-healing.sh) @(env bash $(PWD)/buildscripts/verify-healing-empty-erasure-set.sh) @@ -194,59 +199,38 @@ verify-healing-inconsistent-versions: install-race ## verify resolving inconsist build-debugging: @(env bash $(PWD)/docs/debugging/build.sh) -build: checks build-debugging ## builds minio to $(PWD) - @echo "Building minio binary to './minio'" - @CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build -tags kqueue -trimpath --ldflags "$(LDFLAGS)" -o $(PWD)/minio 1>/dev/null +build: checks build-debugging ## builds Silo to $(PWD) + @echo "Building Silo binary to './silo'" + @CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build -tags kqueue -trimpath --ldflags "$(LDFLAGS)" -o $(PWD)/silo 1>/dev/null -hotfix-vars: - $(eval LDFLAGS := $(shell MINIO_RELEASE="RELEASE" MINIO_HOTFIX="hotfix.$(shell git rev-parse --short HEAD)" go run buildscripts/gen-ldflags.go $(shell git describe --tags --abbrev=0 | \ - sed 's#RELEASE\.\([0-9]\+\)-\([0-9]\+\)-\([0-9]\+\)T\([0-9]\+\)-\([0-9]\+\)-\([0-9]\+\)Z#\1-\2-\3T\4:\5:\6Z#'))) - $(eval VERSION := $(shell git describe --tags --abbrev=0).hotfix.$(shell git rev-parse --short HEAD)) - -hotfix: hotfix-vars clean install ## builds minio binary with hotfix tags - @wget -q -c https://github.com/minio/pkger/releases/download/v2.3.11/pkger_2.3.11_linux_amd64.deb - @wget -q -c https://raw.githubusercontent.com/minio/minio-service/v1.1.1/linux-systemd/distributed/minio.service - @sudo apt install ./pkger_2.3.11_linux_amd64.deb --yes - @mkdir -p minio-release/$(GOOS)-$(GOARCH)/archive - @cp -af ./minio minio-release/$(GOOS)-$(GOARCH)/minio - @cp -af ./minio minio-release/$(GOOS)-$(GOARCH)/minio.$(VERSION) - @minisign -qQSm minio-release/$(GOOS)-$(GOARCH)/minio.$(VERSION) -s "${CRED_DIR}/minisign.key" < "${CRED_DIR}/minisign-passphrase" - @sha256sum < minio-release/$(GOOS)-$(GOARCH)/minio.$(VERSION) | sed 's, -,minio.$(VERSION),g' > minio-release/$(GOOS)-$(GOARCH)/minio.$(VERSION).sha256sum - @cp -af minio-release/$(GOOS)-$(GOARCH)/minio.$(VERSION)* minio-release/$(GOOS)-$(GOARCH)/archive/ - @pkger -r $(VERSION) --ignore - -hotfix-push: hotfix - @scp -q -r minio-release/$(GOOS)-$(GOARCH)/* minio@dl-0.minio.io:~/releases/server/minio/hotfixes/linux-$(GOOS)/ - @scp -q -r minio-release/$(GOOS)-$(GOARCH)/* minio@dl-0.minio.io:~/releases/server/minio/hotfixes/linux-$(GOOS)/archive - @scp -q -r minio-release/$(GOOS)-$(GOARCH)/* minio@dl-1.minio.io:~/releases/server/minio/hotfixes/linux-$(GOOS)/ - @scp -q -r minio-release/$(GOOS)-$(GOARCH)/* minio@dl-1.minio.io:~/releases/server/minio/hotfixes/linux-$(GOOS)/archive - @echo "Published new hotfix binaries at https://dl.min.io/server/minio/hotfixes/linux-$(GOOS)/archive/minio.$(VERSION)" - -docker-hotfix-push: docker-hotfix - @docker push -q $(TAG) && echo "Published new container $(TAG)" - -docker-hotfix: hotfix-push checks ## builds minio docker container with hotfix tags - @echo "Building minio docker image '$(TAG)'" - @docker build -q --no-cache -t $(TAG) --build-arg RELEASE=$(VERSION) . -f Dockerfile.hotfix - -docker: build ## builds minio docker container - @echo "Building minio docker image '$(TAG)'" - @docker build -q --no-cache -t $(TAG) . -f Dockerfile +docker: checks build-debugging ## builds the local Linux Silo container image + @echo "Building Silo container image '$(TAG)'" + @set -e; \ + context=$$(mktemp -d); \ + trap 'rm -rf "$$context"' EXIT; \ + CGO_ENABLED=0 GOOS=linux GOARCH=$(GOARCH) go build -tags kqueue -trimpath \ + --ldflags "$(LDFLAGS)" -o "$$context/silo"; \ + mkdir -p "$$context/dockerscripts"; \ + cp Dockerfile.goreleaser LICENSE CREDITS "$$context/"; \ + cp dockerscripts/docker-entrypoint.sh dockerscripts/download-static-curl.sh \ + "$$context/dockerscripts/"; \ + docker build -q --no-cache --platform linux/$(GOARCH) -t $(TAG) --build-arg TARGETARCH=$(GOARCH) \ + -f "$$context/Dockerfile.goreleaser" "$$context" test-resiliency: build @echo "Running resiliency tests" @(DOCKER_COMPOSE_FILE=$(PWD)/docs/resiliency/docker-compose.yaml env bash $(PWD)/docs/resiliency/resiliency-tests.sh) -install-race: checks build-debugging ## builds minio to $(PWD) - @echo "Building minio binary with -race to './minio'" - @GORACE=history_size=7 CGO_ENABLED=1 go build -tags kqueue,dev -race -trimpath --ldflags "$(LDFLAGS)" -o $(PWD)/minio 1>/dev/null - @echo "Installing minio binary with -race to '$(GOPATH)/bin/minio'" - @mkdir -p $(GOPATH)/bin && cp -af $(PWD)/minio $(GOPATH)/bin/minio +install-race: checks build-debugging ## builds Silo to $(PWD) + @echo "Building Silo binary with -race to './silo'" + @GORACE=history_size=7 CGO_ENABLED=1 go build -tags kqueue,dev -race -trimpath --ldflags "$(LDFLAGS)" -o $(PWD)/silo 1>/dev/null + @echo "Installing Silo binary with -race to '$(GOPATH)/bin/silo'" + @mkdir -p $(GOPATH)/bin && cp -af $(PWD)/silo $(GOPATH)/bin/silo -install: build ## builds minio and installs it to $GOPATH/bin. - @echo "Installing minio binary to '$(GOPATH)/bin/minio'" - @mkdir -p $(GOPATH)/bin && cp -af $(PWD)/minio $(GOPATH)/bin/minio - @echo "Installation successful. To learn more, try \"minio --help\"." +install: build ## builds Silo and installs it to $GOPATH/bin. + @echo "Installing Silo binary to '$(GOPATH)/bin/silo'" + @mkdir -p $(GOPATH)/bin && cp -af $(PWD)/silo $(GOPATH)/bin/silo + @echo "Installation successful. To learn more, try \"silo --help\"." clean: ## cleanup all generated assets @echo "Cleaning up all the generated files" @@ -254,10 +238,8 @@ clean: ## cleanup all generated assets @find . -name '*~' | xargs rm -fv @find . -name '.#*#' | xargs rm -fv @find . -name '#*#' | xargs rm -fv - @rm -rvf minio + @rm -rvf silo @rm -rvf build @rm -rvf release @rm -rvf .verify* - @rm -rvf minio-release - @rm -rvf minio.RELEASE*.hotfix.* @rm -rvf pkger_*.deb diff --git a/buildscripts/package-release.sh b/buildscripts/package-release.sh index 42cd56726..948449731 100755 --- a/buildscripts/package-release.sh +++ b/buildscripts/package-release.sh @@ -34,11 +34,29 @@ fi # against the config file, so the unit path is passed in absolute. Otherwise # this only works when invoked from the repository root and fails elsewhere on # a message that names the file rather than the cause. -unit_file="${repo_dir}/minio.service" +unit_file="${repo_dir}/silo.service" +defaults_file="${repo_dir}/silo.env" +sysusers_file="${repo_dir}/silo.sysusers" +postinstall_file="${repo_dir}/buildscripts/package/postinstall.sh" +preremove_file="${repo_dir}/buildscripts/package/preremove.sh" if [ ! -f "${unit_file}" ]; then echo "Missing systemd unit: ${unit_file}" >&2 exit 1 fi +if [ ! -f "${defaults_file}" ]; then + echo "Missing defaults file: ${defaults_file}" >&2 + exit 1 +fi +if [ ! -f "${sysusers_file}" ]; then + echo "Missing sysusers file: ${sysusers_file}" >&2 + exit 1 +fi +for lifecycle_script in "${postinstall_file}" "${preremove_file}"; do + if [ ! -x "${lifecycle_script}" ]; then + echo "Missing executable package lifecycle script: ${lifecycle_script}" >&2 + exit 1 + fi +done packages_dir="${dist_dir}/packages" mkdir -p "${packages_dir}" @@ -68,7 +86,7 @@ find_binary() { # variants (an added goamd64 level, a stale dist entry) would silently ship a # package whose contents do not match its name. matches="$(find "${dist_dir}" -maxdepth 2 -type f \ - -path "${dist_dir}/minio_linux_${goarch}*/minio" | sort)" + -path "${dist_dir}/silo_linux_${goarch}*/silo" | sort)" count="$(printf '%s' "${matches}" | grep -c . || true)" if [ "${count}" -eq 0 ]; then @@ -98,16 +116,19 @@ build_arch() { # These names are the public download names and must not drift; RPM carries a # release number, DEB and APK do not, matching what pkger produced. - rpm_file="${packages_dir}/minio-${PKG_VERSION}-1.${rpm_arch}.rpm" - deb_file="${packages_dir}/minio_${PKG_VERSION}_${deb_arch}.deb" - apk_file="${packages_dir}/minio_${PKG_VERSION}_${apk_arch}.apk" + rpm_file="${packages_dir}/silo-${PKG_VERSION}-1.${rpm_arch}.rpm" + deb_file="${packages_dir}/silo_${PKG_VERSION}_${deb_arch}.deb" + apk_file="${packages_dir}/silo_${PKG_VERSION}_${apk_arch}.apk" - PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE=1 NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" NFPM_UNIT="${unit_file}" \ - nfpm package --config "${nfpm_config}" --packager rpm --target "${rpm_file}" - PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE='' NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" NFPM_UNIT="${unit_file}" \ - nfpm package --config "${nfpm_config}" --packager deb --target "${deb_file}" - PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE='' NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" NFPM_UNIT="${unit_file}" \ - nfpm package --config "${nfpm_config}" --packager apk --target "${apk_file}" + ( + cd "${repo_dir}" + PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE=1 NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" NFPM_UNIT="${unit_file}" NFPM_DEFAULTS="${defaults_file}" NFPM_SYSUSERS="${sysusers_file}" \ + nfpm package --config "${nfpm_config}" --packager rpm --target "${rpm_file}" + PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE='' NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" NFPM_UNIT="${unit_file}" NFPM_DEFAULTS="${defaults_file}" NFPM_SYSUSERS="${sysusers_file}" \ + nfpm package --config "${nfpm_config}" --packager deb --target "${deb_file}" + PKG_VERSION="${PKG_VERSION}" NFPM_RELEASE='' NFPM_ARCH="${goarch}" NFPM_SOURCE="${source}" NFPM_UNIT="${unit_file}" NFPM_DEFAULTS="${defaults_file}" NFPM_SYSUSERS="${sysusers_file}" \ + nfpm package --config "${nfpm_config}" --packager apk --target "${apk_file}" + ) sha256_file "${rpm_file}" sha256_file "${deb_file}" diff --git a/buildscripts/package/lifecycle_test.sh b/buildscripts/package/lifecycle_test.sh new file mode 100755 index 000000000..ca444aea0 --- /dev/null +++ b/buildscripts/package/lifecycle_test.sh @@ -0,0 +1,172 @@ +#!/usr/bin/env bash + +set -euo pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +repo_dir="$(cd "${script_dir}/../.." && pwd)" +postinstall="${script_dir}/postinstall.sh" +preremove="${script_dir}/preremove.sh" +test_dir="$(mktemp -d)" +fakebin="${test_dir}/bin" +log_file="${test_dir}/calls.log" +useradd_shell=/usr/sbin/nologin +[ -x "${useradd_shell}" ] || useradd_shell=/sbin/nologin +busybox_shell=/sbin/nologin +[ -x "${busybox_shell}" ] || busybox_shell=/bin/false + +cleanup() { + rm -rf "${test_dir}" +} +trap cleanup EXIT + +mkdir -p "${fakebin}" +touch "${log_file}" + +# One dispatcher represents every external command used by the lifecycle +# scripts. The tested scripts run with no host utilities in PATH, so a green +# result cannot create a real account or touch the host service manager. +cat > "${fakebin}/fake-command" <<'EOF' +#!/bin/sh +set -eu + +command_name=${0##*/} +case "${command_name}" in + id) + [ "${PACKAGE_TEST_USER_EXISTS:-0}" = 1 ] + ;; + getent) + [ "${PACKAGE_TEST_GROUP_EXISTS:-0}" = 1 ] + ;; + systemd-sysusers|useradd|addgroup|adduser|systemctl) + { + printf '%s' "${command_name}" + for argument in "$@"; do + printf ' %s' "${argument}" + done + printf '\n' + } >> "${PACKAGE_TEST_LOG}" + ;; + *) + echo "unexpected fake command: ${command_name}" >&2 + exit 1 + ;; +esac +EOF +chmod +x "${fakebin}/fake-command" + +link_command() { + ln -sf fake-command "${fakebin}/$1" +} + +unlink_optional_commands() { + rm -f \ + "${fakebin}/systemd-sysusers" \ + "${fakebin}/useradd" \ + "${fakebin}/adduser" \ + "${fakebin}/addgroup" +} + +reset_log() { + : > "${log_file}" +} + +run_postinstall() { + PACKAGE_TEST_LOG="${log_file}" \ + PACKAGE_TEST_USER_EXISTS="${1}" \ + PACKAGE_TEST_GROUP_EXISTS="${2}" \ + PATH="${fakebin}" \ + /bin/sh "${postinstall}" +} + +run_preremove() { + PACKAGE_TEST_LOG="${log_file}" PATH="${fakebin}" \ + /bin/sh "${preremove}" "$@" +} + +assert_log_line() { + grep -Fx -- "$1" "${log_file}" >/dev/null +} + +reject_log_text() { + if grep -F -- "$1" "${log_file}" >/dev/null; then + echo "unexpected lifecycle call containing '$1':" >&2 + cat "${log_file}" >&2 + exit 1 + fi +} + +link_command id +link_command getent +link_command systemctl + +# Clean install through systemd-sysusers. Side-by-side safety is represented +# by the fact that the only service-manager operation is daemon-reload: no old +# service is stopped, disabled, enabled, masked, or restarted. +unlink_optional_commands +link_command systemd-sysusers +reset_log +run_postinstall 0 0 +assert_log_line "systemd-sysusers /usr/lib/sysusers.d/silo.conf" +assert_log_line "systemctl daemon-reload" +test "$(wc -l < "${log_file}" | tr -d ' ')" -eq 2 + +# An existing service account is preserved without modification. +reset_log +run_postinstall 1 0 +test "$(cat "${log_file}")" = "systemctl daemon-reload" + +# useradd creates a private group only when one does not already exist. An +# administrator may pre-create group silo with the legacy GID; that group must +# be reused rather than causing installation to fail. +unlink_optional_commands +link_command useradd +reset_log +run_postinstall 0 0 +assert_log_line "useradd --system --user-group --no-create-home --shell ${useradd_shell} --comment Silo object storage service silo" +reject_log_text "--gid silo" + +reset_log +run_postinstall 0 1 +assert_log_line "useradd --system --gid silo --no-create-home --shell ${useradd_shell} --comment Silo object storage service silo" +reject_log_text "--user-group" + +# BusyBox follows the same existing-group contract. +unlink_optional_commands +link_command adduser +link_command addgroup +reset_log +run_postinstall 0 0 +assert_log_line "addgroup -S silo" +assert_log_line "adduser -S -D -H -G silo -s ${busybox_shell} silo" + +reset_log +run_postinstall 0 1 +reject_log_text "addgroup" +assert_log_line "adduser -S -D -H -G silo -s ${busybox_shell} silo" + +# Debian remove, RPM erase, and Alpine deinstall stop the Silo unit. Upgrade +# arguments must leave the running service alone. +for removal_argument in remove 0 20260214120000.0.0-r0; do + reset_log + run_preremove "${removal_argument}" + test "$(cat "${log_file}")" = "systemctl disable --now silo.service" +done + +for upgrade_argument in upgrade 1; do + reset_log + run_preremove "${upgrade_argument}" + test ! -s "${log_file}" +done + +# The package deliberately leaves legacy ownership changes to an explicit +# systemd drop-in. Lifecycle scripts must never rewrite ownership or touch the +# old unit, and the base unit must expose overridable User/Group directives. +grep -Fx 'User=silo' "${repo_dir}/silo.service" >/dev/null +grep -Fx 'Group=silo' "${repo_dir}/silo.service" >/dev/null +if grep -Ein '\b(chown|chgrp|usermod|groupmod)\b|minio\.service' \ + "${postinstall}" "${preremove}"; then + echo "package lifecycle scripts must not mutate data ownership or the legacy service" >&2 + exit 1 +fi + +echo "Silo package lifecycle checks passed" diff --git a/buildscripts/package/postinstall.sh b/buildscripts/package/postinstall.sh new file mode 100755 index 000000000..ce2ce6284 --- /dev/null +++ b/buildscripts/package/postinstall.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +set -eu + +sysusers_file=/usr/lib/sysusers.d/silo.conf + +group_exists() { + if command -v getent >/dev/null 2>&1; then + getent group silo >/dev/null 2>&1 + return + fi + + [ -r /etc/group ] || return 1 + while IFS=: read -r group_name _; do + [ "${group_name}" = silo ] && return 0 + done < /etc/group + return 1 +} + +if ! id -u silo >/dev/null 2>&1; then + if command -v systemd-sysusers >/dev/null 2>&1; then + systemd-sysusers "${sysusers_file}" + elif command -v useradd >/dev/null 2>&1; then + nologin_shell=/usr/sbin/nologin + [ -x "${nologin_shell}" ] || nologin_shell=/sbin/nologin + if group_exists; then + useradd --system --gid silo --no-create-home --shell "${nologin_shell}" --comment "Silo object storage service" silo + else + useradd --system --user-group --no-create-home --shell "${nologin_shell}" --comment "Silo object storage service" silo + fi + elif command -v adduser >/dev/null 2>&1 && command -v addgroup >/dev/null 2>&1; then + nologin_shell=/sbin/nologin + [ -x "${nologin_shell}" ] || nologin_shell=/bin/false + group_exists || addgroup -S silo + adduser -S -D -H -G silo -s "${nologin_shell}" silo + else + echo "Unable to create the silo system account: systemd-sysusers, useradd, or BusyBox adduser is required" >&2 + exit 1 + fi +fi + +if command -v systemctl >/dev/null 2>&1; then + systemctl daemon-reload >/dev/null 2>&1 || true +fi diff --git a/buildscripts/package/preremove.sh b/buildscripts/package/preremove.sh new file mode 100755 index 000000000..8d330e4ce --- /dev/null +++ b/buildscripts/package/preremove.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +set -eu + +# Debian passes "remove" for an actual removal, RPM passes 0 to %preun, and +# Alpine runs pre-deinstall only for removal and passes the old dotted version. +# Upgrade paths deliberately leave the running service untouched. +case "${1:-}" in + remove|0|*.*) + if command -v systemctl >/dev/null 2>&1; then + systemctl disable --now silo.service >/dev/null 2>&1 || true + fi + ;; +esac diff --git a/buildscripts/sign-release-rpms.sh b/buildscripts/sign-release-rpms.sh index 96dcc5567..73aff8634 100755 --- a/buildscripts/sign-release-rpms.sh +++ b/buildscripts/sign-release-rpms.sh @@ -10,12 +10,15 @@ expected_fingerprint="9592A7BC7A682E7333376E09E7935D8DB9BD8B20" expected_vendor="PGSTY" expected_packager="Ruohang Feng (@Vonng) " expected_url="https://silo.pgsty.com" -expected_summary="S3-Interface Libre Object Storage, Community-maintained MinIO server fork." -expected_description="S3-Interface Libre Object Storage, Community-maintained MinIO server fork." +expected_summary="S3-Interface Libre Object Storage, a community-maintained S3-compatible server." +expected_description="S3-Interface Libre Object Storage, a community-maintained S3-compatible server." expected_license="AGPL-3.0-or-later" expected_group="Applications/File" -expected_payload="/usr/lib/systemd/system/minio.service -/usr/local/bin/minio" +expected_payload="/etc/default/silo +/usr/bin/silo +/usr/lib/systemd/system/silo.service +/usr/lib/sysusers.d/silo.conf" +# Transitional until the irreversible GitHub repository rename. repository="${GH_REPO:-pgsty/minio}" container="${DNFUPDATE_CONTAINER:-dnfupdate}" upload=false @@ -122,8 +125,8 @@ mkdir -p "${unsigned_dir}" "${signed_dir}" chmod 700 "${work_dir}" "${unsigned_dir}" "${signed_dir}" rpm_files=( - "minio-${package_version}-1.x86_64.rpm" - "minio-${package_version}-1.aarch64.rpm" + "silo-${package_version}-1.x86_64.rpm" + "silo-${package_version}-1.aarch64.rpm" ) download_patterns=() @@ -159,7 +162,7 @@ for rpm_file in "${rpm_files[@]}"; do done safe_tag="$(printf '%s' "${release_tag}" | tr -c 'A-Za-z0-9._-' '_')" -container_dir="/tmp/minio-sign-${safe_tag}-$$" +container_dir="/tmp/silo-sign-${safe_tag}-$$" docker exec "${container}" mkdir -p "${container_dir}" cleanup_container() { @@ -203,7 +206,7 @@ for rpm_file in "${rpm_files[@]}"; do docker cp "${unsigned_dir}/${rpm_file}" "${container}:${container_dir}/${rpm_file}" >/dev/null container_rpm="${container_dir}/${rpm_file}" - assert_rpm_tag "${container_rpm}" NAME minio + assert_rpm_tag "${container_rpm}" NAME silo assert_rpm_tag "${container_rpm}" VERSION "${package_version}" assert_rpm_tag "${container_rpm}" RELEASE 1 assert_rpm_tag "${container_rpm}" ARCH "${expected_arch}" diff --git a/buildscripts/verify-build-provenance.sh b/buildscripts/verify-build-provenance.sh index 5679a283e..fa4178dcc 100755 --- a/buildscripts/verify-build-provenance.sh +++ b/buildscripts/verify-build-provenance.sh @@ -41,7 +41,7 @@ while IFS= read -r binary; do grep -F 'vcs.' <<< "${info}" >&2 || true exit 1 fi -done < <(find "${dist_dir}" -maxdepth 2 -type f \( -name 'minio' -o -name 'minio.exe' \) | sort) +done < <(find "${dist_dir}" -maxdepth 2 -type f \( -name 'silo' -o -name 'silo.exe' \) | sort) if [ "${count}" -ne "${expected_count}" ]; then echo "Expected ${expected_count} release binaries, found ${count}" >&2 diff --git a/silo.env b/silo.env new file mode 100644 index 000000000..5c78cdacb --- /dev/null +++ b/silo.env @@ -0,0 +1,9 @@ +# Silo keeps the MINIO_* environment variable interface for compatibility. +# This packaged file intentionally contains no active assignments so values in +# the legacy /etc/default/minio continue to work until an administrator chooses +# to override them here. +# +# MINIO_VOLUMES="/data" +# MINIO_OPTS="--console-address :9001" +# MINIO_ROOT_USER="silo-admin" +# MINIO_ROOT_PASSWORD="replace-with-a-long-random-secret" diff --git a/minio.service b/silo.service similarity index 68% rename from minio.service rename to silo.service index ec765cc06..c49416d53 100644 --- a/minio.service +++ b/silo.service @@ -1,21 +1,23 @@ [Unit] -Description=MinIO +Description=Silo Object Storage Server Documentation=https://silo.pgsty.com/docs/ Wants=network-online.target -After=network-online.target -AssertFileIsExecutable=/usr/local/bin/minio +After=network-online.target minio.service +Conflicts=minio.service +AssertFileIsExecutable=/usr/bin/silo [Service] Type=notify WorkingDirectory=/usr/local -User=minio-user -Group=minio-user +User=silo +Group=silo ProtectProc=invisible EnvironmentFile=-/etc/default/minio -ExecStart=/usr/local/bin/minio server $MINIO_OPTS $MINIO_VOLUMES +EnvironmentFile=-/etc/default/silo +ExecStart=/usr/bin/silo server $MINIO_OPTS $MINIO_VOLUMES # Let systemd restart this service always Restart=always @@ -32,7 +34,7 @@ TasksMax=infinity # Disable timeout logic and wait until process is stopped TimeoutSec=infinity -# Disable killing of MinIO by the kernel's OOM killer +# Disable killing of Silo by the kernel's OOM killer OOMScoreAdjust=-1000 SendSIGKILL=no diff --git a/silo.sysusers b/silo.sysusers new file mode 100644 index 000000000..41bd0d7e5 --- /dev/null +++ b/silo.sysusers @@ -0,0 +1 @@ +u silo - "Silo object storage service" - -