Commit Graph

12815 Commits

Author SHA1 Message Date
Feng Ruohang ffb70eb373 fix: re-encrypt a key rotation the object layer has to rewrite
A key rotation rewraps the object key held in metadata; it never re-encrypts
the stored bytes. CopyObjectHandler took that shortcut whenever the request
looked like a same-object SSE-C rotation, on the assumption that the object
layer would then leave the stored bytes alone. That is the same assumption
copyRewritesObjectData() was added to stop making.

When the source is a null version on a bucket that gained versioning after the
object was written, the object layer cannot reference that version and falls
back to PutObject. The reader at that point holds plaintext decrypted with the
old key and no EncryptFn is set, so the destination ends up storing plaintext
under metadata that claims the object is SSE-C encrypted. A subsequent GET
failed with "sio: unsupported version".

Gate the rotation shortcut on the same prediction the compression metadata
already uses. When the object layer stores new object data the rotation falls
through to the regular re-encrypting copy, which decrypts with the old key and
re-encrypts with the new one. The source version selection moves next to the
gate because both decisions need it.

That fallback authenticates the source key through the source decryptor, which
GetObjectNInfo does not build for a zero byte object. Check the key explicitly
before the destination is written, so the gate cannot turn a rotation that the
shortcut rejected with AccessDenied into one that succeeds. The re-encrypting
copy regenerates the encrypted ETag, unlike an in-place rotation; the test
records that difference.

The other three object layer CopyObject callers that set metadataOnly -
PostRestoreObjectHandler, updateRestoreMetadata and batchKeyRotate - address
the same version on both sides and never set Versioned, so they only reach the
two in-place cases already covered by the copyRewritesObjectData table.

Signed-off-by: Feng Ruohang <rh@vonng.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fk3PAD7DHCYzcyegYWqAmt
2026-08-29 16:00:21 +08:00
Feng Ruohang e73436c99d fix: decrypt CopyObject checksums with destination key
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-29 16:00:21 +08:00
Feng Ruohang 0b0ae2423a fix: keep copy metadata consistent with a rewritten null version
CopyObjectHandler recorded the source compression metadata whenever the copy
was metadata-only, on the assumption that the object layer would then leave
the stored bytes alone. That assumption does not hold. Both
erasureServerPools.CopyObject and erasureSets.CopyObject only skip a data
rewrite in three cases, and otherwise fall back to a full PutObject.

The reachable gap is a copy whose source is a null version on a bucket that
gained versioning after the object was written. Neither version ID is set, so
the self-referential version branch is skipped, the data is rewritten as
plaintext, and the preserved compression metadata then described bytes that
no longer exist. A subsequent GET failed with "s2: corrupt input".

Mirror the object layer's decision in copyRewritesObjectData and record the
compression metadata from it, so the metadata always describes whichever
bytes are finally stored. The source version selection that lets a versioned
metadata-only copy add a self-referential version moves next to the same
decision, since both depend on the effective metadata-only value.

Signed-off-by: Feng Ruohang <rh@vonng.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-29 16:00:21 +08:00
Feng Ruohang 7e079ff05c fix: validate explicit multipart checksum type
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-29 16:00:21 +08:00
Feng Ruohang 229fe2b3c3 fix: authorize group status changes by target status
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-29 16:00:21 +08:00
Feng Ruohang 38ed9d1e1f docs(security): record inherited upstream advisory
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-29 16:00:21 +08:00
Feng Ruohang 47cd7807d3 test: align federated client version
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-29 16:00:21 +08:00
Feng Ruohang 04d3d316d2 Merge pull request #81 from pgsty/codex/issue-75-closeout-tests
test: cover asymmetric CORS site counts
2026-08-29 10:13:38 +08:00
Feng Ruohang 4bb8c813ac test: cover asymmetric CORS site counts
Exercise no-site, local-only, remote-only, and both-site CORS summary accounting through the real siteReplicationStatus seam.

Refs #75

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-29 10:03:01 +08:00
Feng Ruohang b6ef7e430c Merge pull request #80 from pgsty/codex/issue-75-cors-hardening
fix: complete per-bucket CORS release hardening
2026-08-29 09:44:16 +08:00
Feng Ruohang 91d9091758 docs: record final bucket CORS acceptance
Record the frozen B2+B3 commit, combined local gates, raw SigV4 validation, real two-site offline/delete/heal/restart evidence, and the separate public documentation QA boundary.

Refs #75

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-29 09:29:34 +08:00
Feng Ruohang 0eebc928f7 fix: complete bucket CORS protocol validation
Integrate the strict B3 XML, validation, checksum, wildcard, MaxAge, and Origin-null response contract with the C-prime site-replication register from #75.

Preserve fail-closed metadata behavior and rejected-preflight cache variation while keeping legacy-invalid development metadata readable and repairable through a valid CORS PUT or DELETE.

Add combined parser, handler, browser-response, namespace, replication, restart, and legacy-repair regressions, and update the internal design contract.

Refs #75

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-29 09:10:58 +08:00
Feng Ruohang 724f8703d8 fix: make bucket CORS replication converge
Define a deterministic CORS replication register with durable tombstones, strict source timestamps, equal-time conflict ordering, full-state status, and heal convergence.

Serialize local and peer CORS transitions with a distributed namespace lock, validate canonical transport payloads, preserve initial-sync deletes, and fail closed on metadata errors.

Add adversarial, concurrent, restart, status, heal, signed admin-dispatch, protocol, and middleware coverage together with the reviewed site-replication design record.

Refs #75

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-29 01:33:24 +08:00
Feng Ruohang e4e3007da6 Merge pull request #71 from h5vx/feature/per-bucket-cors
feat: per-bucket CORS configuration with S3 ?cors enforcement\n\nRelease hardening and site-replication convergence follow-up: #75.
2026-08-28 10:34:52 +08:00
h5vx 13e6458d90 feat: replicate per-bucket CORS across sites and harden the protocol path
Site replication emitted SRBucketMetaTypeCorsConfig on PutBucketCors, but
the peer receive/apply, initial-sync, status, and heal paths did not carry
the CORS metadata. Replicated sites could therefore diverge on CORS config
even though the originating request succeeded.

Complete every site-replication path for CORS, mirroring the SSEConfig
pattern:
  - peer apply: PeerBucketCorsConfigHandler + item.Cors handling in
    PeerBucketMetadataUpdateHandler, with an updatedAt staleness guard
  - initial sync: push existing CorsConfigXML via BucketMetaHook
  - status: parse per-site CorsConfig, count/compare, surface
    CorsCfgMismatch/HasCorsCfgSet/ReplicatedCorsConfig, and include CORS in
    the bucket-stats aggregation filter
  - heal: healCORSMetadata, including nil -> delete propagation

Also harden the request/config path:
  - PutBucketCors validates the supplied Content-MD5/checksum via
    validateLengthAndChecksum
  - CORS validation rejects more than one wildcard per AllowedOrigin/
    AllowedHeader and enforces the 255-char rule ID limit
  - preflight responses Vary on Origin, Access-Control-Request-Method, and
    Access-Control-Request-Headers

Add focused tests for the CORS SR transport round-trip, the metadata
equality helper, and the new validation constraints.

Signed-off-by: h5vx <h5v@protonmail.com>
2026-08-27 12:46:47 +05:00
Feng Ruohang 590aeaa7d1 Merge pull request #74 from pgsty/codex/issue-48-baddigest
fix: align multipart completion checksum errors
2026-08-27 09:53:41 +08:00
Feng Ruohang 5d152416de fix: align multipart completion checksum errors
Return AWS-compatible errors for CompleteMultipartUpload checksum failures without changing the global streaming checksum mapping. Compare explicit multipart checksum types symmetrically, distinguish missing composite part checksums, and preserve the CRC64NVME canonicalization pending a direct AWS probe.

Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-27 09:05:49 +08:00
Feng Ruohang edc8be6ed1 deps: adopt Silo Go v7.3.1 stack
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-27 02:40:19 +08:00
Feng Ruohang 49c8aeac40 Merge pull request #37 from ycjlin/fix/listobjects-nosuchbucket-prefix
fix: ListObjects should return NoSuchBucket for prefix on missing bucket
2026-08-26 19:13:42 +08:00
Feng Ruohang e9c5340be9 fix: return NoSuchBucket from listing shortcuts
ListObjects shortcuts can return EOF before consulting storage, causing missing buckets to appear as empty listings. Verify bucket existence only on those shortcuts so the normal listing path retains the upstream fan-out optimization.

Cover ListObjects, ListObjectsV2, and ListObjectVersions at the object layer and verify HTTP 404 NoSuchBucket responses.

Fixes #32

Co-authored-by: Jason Lin <jason@JasondeMacBook-Air.local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-26 19:02:25 +08:00
Feng Ruohang 2e2377d1c6 Merge pull request #73 from pgsty/codex/issue-21478
fix: authorize user status changes by target status
2026-08-26 14:28:04 +08:00
Feng Ruohang 58735ee382 fix: authorize user status changes by target status
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-26 14:19:39 +08:00
Feng Ruohang a96116b128 Merge pull request #57 from Dansyuqri/feat-add-checksumtype-completemultipartupload-response
feat: add ChecksumType to CompleteMultipartUpload response struct
2026-08-26 10:27:54 +08:00
Feng Ruohang c4b9d38d8a Merge branch 'main' into feat-add-checksumtype-completemultipartupload-response 2026-08-26 10:15:15 +08:00
Feng Ruohang 8d76a255c4 fix: return the remote part checksum to federated UploadPartCopy (#72)
The legacy etcd federation branch of CopyObjectPartHandler forwards copied
bytes with minio-go Core.PutObjectPart, which can only recover a checksum
from response headers. After the server-side part checksum work, the remote
computes and persists the checksum, but an AWS-compatible UploadPart response
correctly omits a checksum the request did not supply, so the proxy had
nothing to put in CopyPartResult.

The destination now returns the non-empty checksum fields of the PartInfo
produced by that exact write, but only when the request carries the
minio-federated application token that getRemoteInstanceClient already
attaches. Ordinary UploadPart responses are unchanged, and the checksum type
is deliberately not returned because UploadPart does not carry it. The
User-Agent is a response-shape hint only: it never gates authorization,
visibility or validation, and it can expose nothing beyond the checksum of
the body the caller just uploaded.

Reading the checksum from the same PartInfo that produced the response ETag
also keeps the pair bound to one write, so a concurrent overwrite of the same
part number cannot publish another writer's checksum.

Tests cover the application token gating matrix including lookalike tokens,
the real minio-go response parser, concurrent overwrites of one part number,
and an in-process two-deployment probe that drives the federation branch
through the real getRemoteInstanceClient into a real PutObjectPartHandler for
both FULL_OBJECT and COMPOSITE uploads.

Fixes #64

Signed-off-by: Feng Ruohang <rh@vonng.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 01:06:50 +08:00
h5vx c5bc57b7a3 fix: gofumpt formatting and record CORS symbols in rebrand baseline
Reformat cors_test.go per gofumpt and regenerate the rebrand-guard
compatibility baseline to record the per-bucket CORS feature's new
exported symbols (internal/bucket/cors types and BucketMetadata/
BucketMetadataSys additions).

Signed-off-by: h5vx <h5v@protonmail.com>
2026-08-25 19:24:44 +05:00
h5vx 3814818537 fix: address CORS final-review findings (multi-rule preflight, raw GET, e2e test)
Signed-off-by: h5vx <h5v@protonmail.com>
2026-08-25 19:24:44 +05:00
h5vx 7a49a7a3da feat: enforce per-bucket CORS with global fallback
Signed-off-by: h5vx <h5v@protonmail.com>
2026-08-25 19:24:44 +05:00
h5vx ff3395d3c6 feat: implement S3 per-bucket CORS handlers
Signed-off-by: h5vx <h5v@protonmail.com>
2026-08-25 19:24:44 +05:00
h5vx ce4525632f feat: persist per-bucket CORS config in bucket metadata
Signed-off-by: h5vx <h5v@protonmail.com>
2026-08-25 19:24:44 +05:00
h5vx 1c9a2431fe feat: add internal/bucket/cors CORS config type and matching
Signed-off-by: h5vx <h5v@protonmail.com>
2026-08-25 19:24:44 +05:00
Feng Ruohang f2520f3346 fix: return checksums from CopyObject
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-24 20:59:27 +08:00
Feng Ruohang 05df6e70d7 fix: preserve transform state on metadata-only copies
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-24 20:46:31 +08:00
Feng Ruohang c0e7159771 fix: checksum CopyObject data before compression
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-24 20:33:54 +08:00
Feng Ruohang 56c67dacf1 Document bare ARN policy hardening
Record the new strict named-policy and service-account write behavior, the additional admin-policy validation it activates, the compatibility boundaries retained for stored/imported/replicated policies, and the required manual rewrite for legacy bare ARN prefixes.
2026-08-24 18:01:22 +08:00
Feng Ruohang eee05a17c3 Reject bare ARN policies on admin writes
Use silo-pkg v3.12 strict validation when creating named policies and when creating or updating service-account session policies. Keep stored policy loads, IAM import, site replication, and STS inline policies on the permissive compatibility path.
2026-08-24 17:59:13 +08:00
Feng Ruohang 45eb2e423d fix(ci): align compatibility fixtures and generated credits 2026-08-24 15:03:45 +08:00
Feng Ruohang 6b0998157c fix: harden config environment file parsing
Trim whitespace around assignments, preserve whitespace inside matching quotes, validate portable variable names, and report redacted file-and-line diagnostics. Check config-file Setenv failures instead of silently ignoring invalid entries.\n\nFixes #65
2026-08-24 13:43:44 +08:00
Feng Ruohang 7fea6d5a5f fix: compute multipart part checksums server-side
Accept checksum-enabled UploadPart and UploadPartCopy requests when clients omit optional per-part checksum headers. Compute over the logical plaintext stream, persist the result, and return it from CopyPartResult while preserving client checksum validation.\n\nRefs #46; follow-ups #63 and #64 remain out of scope.
2026-08-24 12:20:52 +08:00
Feng Ruohang 68eeb002f6 chore: record notification migration compatibility symbols 2026-08-24 12:20:13 +08:00
Feng Ruohang c565987b9c docs: align database notification migration guidance 2026-08-24 02:29:22 +08:00
Feng Ruohang f1ba683582 fix: require DSNs for legacy database notifications
Reject pre-KV PostgreSQL and MySQL targets that lack a canonical connection string, propagate the typed migration error to the fatal startup boundary, and stop emitting unregistered discrete connection keys.\n\nCloses the implementation for #53; release and issue closure remain separate gates.
2026-08-24 02:22:20 +08:00
Feng Ruohang 43f4bb7ed4 chore(deps): align the SILO Go dependency stack
Standardize the related SILO components on Go 1.27 tooling, etcd 3.7.1, current Go-maintained modules, shared runtime versions, and explicit security and portability pins.

Keep the shared package Go 1.26 consumer floor, isolate lint tooling from product dependency selection, and preserve upstream-compatible import paths.
2026-08-24 01:08:46 +08:00
Shooks d014a12cff feat: add ChecksumType to CompleteMultipartUpload response struct
Signed-off-by: Shooks <justanormalme@gmail.com>
2026-08-09 17:52:38 +08:00
Feng Ruohang 100e2e57a7 docs: restore the legacy-user drop-in path in both READMEs
Condensing the READMEs dropped the systemd drop-in that keeps data ownership
stable when silo.service takes over an existing minio.service, which the
rebrand guard pins in both files precisely so it cannot vanish quietly. The
path is back as a clause in the install note rather than a section, so the
guard is satisfied and the migration-critical detail stays discoverable in
the repository, not only on the portal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-07 19:46:28 +08:00
Feng Ruohang 6e20e74774 docs: record contributors and rework the READMEs around them
GitHub generates no contributor graph for forks, so this fork had no
attribution record at all. CONTRIBUTORS.md becomes that record, in three
tiers: the four contributors with code merged into main, each listed with
the pull request and the commit that carries their authorship; the five who
opened pull requests; and the twenty-two who filed the bug reports and
compatibility findings that shaped the releases.

Both READMEs are condensed and gain a Contributors section that shows the
avatars and points at the full record, with README_ZH realigned to README
section for section.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Feng Ruohang <rh@vonng.com>
2026-08-07 19:34:16 +08:00
Feng Ruohang 3be10fcc1a feat(ci): add a manual finalize lane for signed Draft packages
GPG-signing the RPMs rewrites their bytes after release.yml has already
generated SBOMs, the packages checksum manifest, and attestations from
the as-built files. The new workflow_dispatch-only finalize-release lane
runs between signing and publishing: it refuses non-Draft releases,
verifies the signed RPMs against their sha256 sidecars and the committed
PGSTY public key, confirms every other package still matches the
original manifest, regenerates the RPM SBOMs and the manifest from the
published bytes, cosign-signs the manifest under the workflow identity,
and attests the finalized set before replacing the assets in place.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
RELEASE.2026-08-06T00-00-00Z
2026-08-06 22:21:17 +08:00
Feng Ruohang b14ea22aa8 fix(ci): match checksum manifest entries exactly in docker-release
The substring grep for the archive line also captured the archive's
.sbom.json entry, whose file is deliberately not downloaded in this
lane, so the sha256sum check failed on every run. awk now matches the
manifest filename column exactly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 22:21:17 +08:00
Feng Ruohang 86a7782900 docs(readme): update the docker pulls badge
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 22:19:41 +08:00
Feng Ruohang 4679314556 build(packages): unify the rpm and deb release segment as 1PGSTY
The rpm carried a bare -1 release while the deb carried none. Both now
ship the PGDG-style 1PGSTY segment: silo-VER-1PGSTY.arch.rpm and
silo_VER-1PGSTY_arch.deb, with nfpm rendering it as the RPM Release tag
and the Debian revision respectively. The apk stays bare because Alpine
pkgrel admits only -r<integer>.

sign-release-rpms.sh declares the value once as expected_release;
package-release.sh names artifacts from its own PKG_RELEASE copy, and
test-release.yml evals the signing script's value and asserts both the
download names and the packaged RPM Release/DEB Version against it, so
the copies cannot drift apart silently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 21:02:15 +08:00