Merge remote-tracking branch 'origin/main' into feature/guest-links

This commit is contained in:
Ralf Haferkamp
2026-05-13 14:35:54 +02:00
139 changed files with 6441 additions and 1502 deletions
-2
View File
@@ -3,5 +3,3 @@ module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT
go 1.23.4
require github.com/gosexy/gettext v0.0.0-20160830220431-74466a0a0c4a // go-xgettext
require github.com/jessevdk/go-flags v1.6.1 // indirect
+1 -1
View File
@@ -1,4 +1,4 @@
# The test runner source for UI tests
WEB_COMMITID=6818f0d09b145720ef31737b84284239545d1eb8
WEB_COMMITID=909f9915b39cb736467d02a9afdc7e9bfa99de53
WEB_BRANCH=main
+1 -1
View File
@@ -371,7 +371,7 @@ config = {
"skip": False,
"suites": [
"user-settings",
"file-action",
#"fileaction",
"embed",
],
},
+39
View File
@@ -1,5 +1,44 @@
# Changelog
## [6.2.0](https://github.com/opencloud-eu/opencloud/releases/tag/v6.2.0) - 2026-05-11
### ❤️ Thanks to all contributors! ❤️
@JammingBen, @ScharfViktor, @Sweeistaken, @aduffeck, @dragonchaser, @dschmidt, @fschade, @pedropintosilva, @rhafer, @schweigisito
### 📈 Enhancement
- feat: enable EnableRemoteLinkPicker WOPI flag for Collabora Online [[#2663](https://github.com/opencloud-eu/opencloud/pull/2663)]
- feat(kql): support dotted keys in property restrictions [[#2632](https://github.com/opencloud-eu/opencloud/pull/2632)]
### 🐛 Bug Fixes
- Set new defaults for caches and stores [[#2702](https://github.com/opencloud-eu/opencloud/pull/2702)]
- fix: remove typo in error message [[#2701](https://github.com/opencloud-eu/opencloud/pull/2701)]
- fix(search): preserve value case for non-lowercased bleve fields [[#2633](https://github.com/opencloud-eu/opencloud/pull/2633)]
- More graceful shutdown fixes [[#2690](https://github.com/opencloud-eu/opencloud/pull/2690)]
- Hotfix for https://github.com/opencloud-eu/opencloud/issues/2282 [[#2631](https://github.com/opencloud-eu/opencloud/pull/2631)]
- fix(search): read --force-rescan flag with its registered name [[#2639](https://github.com/opencloud-eu/opencloud/pull/2639)]
- fix(search): parse tika xmpDM:duration as a float [[#2638](https://github.com/opencloud-eu/opencloud/pull/2638)]
### ✅ Tests
- [api-tests] delete PROPATCH favorite tests [[#2689](https://github.com/opencloud-eu/opencloud/pull/2689)]
### 📚 Documentation
- enhancement: increase display size of graph flow diagram [[#2620](https://github.com/opencloud-eu/opencloud/pull/2620)]
### 📦️ Dependencies
- build(deps): bump go.opentelemetry.io/contrib/zpages from 0.67.0 to 0.68.0 [[#2666](https://github.com/opencloud-eu/opencloud/pull/2666)]
- build(deps): bump @types/node from 22.19.17 to 25.6.0 in /services/idp [[#2687](https://github.com/opencloud-eu/opencloud/pull/2687)]
- build(deps): bump go.opentelemetry.io/otel/exporters/stdout/stdouttrace from 1.42.0 to 1.43.0 [[#2601](https://github.com/opencloud-eu/opencloud/pull/2601)]
- build(deps): bump github.com/davidbyttow/govips/v2 from 2.17.0 to 2.18.0 [[#2656](https://github.com/opencloud-eu/opencloud/pull/2656)]
- build(deps): bump i18next from 25.10.10 to 26.0.4 in /services/idp [[#2609](https://github.com/opencloud-eu/opencloud/pull/2609)]
- build(deps): bump github.com/testcontainers/testcontainers-go/modules/opensearch from 0.41.0 to 0.42.0 [[#2645](https://github.com/opencloud-eu/opencloud/pull/2645)]
- build(deps): bump github.com/open-policy-agent/opa from 1.15.1 to 1.15.2 [[#2602](https://github.com/opencloud-eu/opencloud/pull/2602)]
## [6.1.0](https://github.com/opencloud-eu/opencloud/releases/tag/v6.1.0) - 2026-04-20
### ❤️ Thanks to all contributors! ❤️
+1 -1
View File
@@ -29,7 +29,7 @@ COPY --from=generate /opencloud /opencloud
WORKDIR /opencloud/opencloud
RUN make go-generate build ENABLE_VIPS=true
FROM alpine:3.20
FROM alpine:3.23
RUN apk add --no-cache attr ca-certificates curl mailcap tree vips && \
echo 'hosts: files dns' >| /etc/nsswitch.conf
+9 -8
View File
@@ -57,10 +57,9 @@ require (
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/nats-io/nats-server/v2 v2.14.0
github.com/nats-io/nats.go v1.51.0
github.com/oklog/run v1.2.0
github.com/olekukonko/tablewriter v1.1.4
github.com/onsi/ginkgo v1.16.5
github.com/onsi/ginkgo/v2 v2.28.1
github.com/onsi/ginkgo/v2 v2.28.3
github.com/onsi/gomega v1.40.0
github.com/open-policy-agent/opa v1.15.2
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
@@ -106,7 +105,7 @@ require (
golang.org/x/crypto v0.50.0
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
golang.org/x/image v0.38.0
golang.org/x/net v0.52.0
golang.org/x/net v0.53.0
golang.org/x/oauth2 v0.36.0
golang.org/x/sync v0.20.0
golang.org/x/term v0.42.0
@@ -239,14 +238,14 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-tpm v0.9.8 // indirect
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect
github.com/google/renameio/v2 v2.0.2 // indirect
github.com/gookit/goutil v0.7.4 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/schema v1.4.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-plugin v1.7.0 // indirect
github.com/hashicorp/go-plugin v1.8.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
@@ -288,7 +287,7 @@ require (
github.com/minio/crc64nvme v1.1.1 // indirect
github.com/minio/highwayhash v1.0.4 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/minio-go/v7 v7.0.99 // indirect
github.com/minio/minio-go/v7 v7.1.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
@@ -308,6 +307,7 @@ require (
github.com/nats-io/nkeys v0.4.15 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/oklog/run v1.2.0 // indirect
github.com/olekukonko/cat v0.0.0-20250911104152-50322a0618f6 // indirect
github.com/olekukonko/errors v1.2.0 // indirect
github.com/olekukonko/ll v0.1.6 // indirect
@@ -376,6 +376,7 @@ require (
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/zeebo/xxh3 v1.1.0 // indirect
go.etcd.io/etcd/api/v3 v3.6.10 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.6.10 // indirect
go.etcd.io/etcd/client/v3 v3.6.10 // indirect
@@ -388,10 +389,10 @@ require (
go.uber.org/zap v1.27.0 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/mod v0.34.0 // indirect
golang.org/x/mod v0.35.0 // indirect
golang.org/x/sys v0.43.0 // indirect
golang.org/x/time v0.15.0 // indirect
golang.org/x/tools v0.43.0 // indirect
golang.org/x/tools v0.44.0 // indirect
google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d // indirect
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
+18 -14
View File
@@ -576,8 +576,8 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc=
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 h1:EwtI+Al+DeppwYX2oXJCETMO23COyaKGP6fHVpkpWpg=
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/renameio/v2 v2.0.2 h1:qKZs+tfn+arruZZhQ7TKC/ergJunuJicWS6gLDt/dGw=
github.com/google/renameio/v2 v2.0.2/go.mod h1:OX+G6WHHpHq3NVj7cAOleLOwJfcQ1s3uUJQCrr78SWo=
@@ -626,8 +626,8 @@ github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA=
github.com/hashicorp/go-plugin v1.7.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/go-plugin v1.8.0 h1:ie8S6RRY8RvB2usYZv+AAZ/wBvx2AU5p5QeP5j/FORs=
github.com/hashicorp/go-plugin v1.8.0/go.mod h1:BExt6KEaIYx804z8k4gRzRLEvxKVb+kn0NMcihqOqb8=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
@@ -843,8 +843,8 @@ github.com/minio/highwayhash v1.0.4 h1:asJizugGgchQod2ja9NJlGOWq4s7KsAWr5XUc9Clg
github.com/minio/highwayhash v1.0.4/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.99 h1:2vH/byrwUkIpFQFOilvTfaUpvAX3fEFhEzO+DR3DlCE=
github.com/minio/minio-go/v7 v7.0.99/go.mod h1:EtGNKtlX20iL2yaYnxEigaIvj0G0GwSDnifnG8ClIdw=
github.com/minio/minio-go/v7 v7.1.0 h1:QEt5IStDpxgGjEdtOgpiZ5QhmSl3ax7qy61vi2SwHO8=
github.com/minio/minio-go/v7 v7.1.0/go.mod h1:Dm7WS1AgLmBa0NcQD6SeJnJf+K/EUW3GR7Ks6olB3OA=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
@@ -935,8 +935,8 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI=
github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE=
github.com/onsi/ginkgo/v2 v2.28.3 h1:4JvMdwtFU0imd8fHx25OJXoDMRexnf8v5NHKYSTTji4=
github.com/onsi/ginkgo/v2 v2.28.3/go.mod h1:+aXOY+vzZ5mu2iI2HpTZUPmM//oQfsNFX6gU9kNcA44=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
@@ -1275,6 +1275,10 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.1.0 h1:s7DLGDK45Dyfg7++yxI0khrfwq9661w9EN78eP/UZVs=
github.com/zeebo/xxh3 v1.1.0/go.mod h1:IisAie1LELR4xhVinxWS5+zf1lA4p0MW4T+w+W07F5s=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo=
go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E=
@@ -1397,8 +1401,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI=
golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY=
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1449,8 +1453,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1642,8 +1646,8 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s=
golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0=
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
golang.org/x/tools/godoc v0.1.0-deprecated h1:o+aZ1BOj6Hsx/GBdJO/s815sqftjSnrZZwyYTHODvtk=
golang.org/x/tools/godoc v0.1.0-deprecated/go.mod h1:qM63CriJ961IHWmnWa9CjZnBndniPt4a3CK0PVB9bIg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+2 -2
View File
@@ -1,4 +1,4 @@
FROM golang:alpine3.22 AS build
FROM golang:alpine3.23 AS build
ARG TARGETOS
ARG TARGETARCH
ARG VERSION
@@ -14,7 +14,7 @@ RUN --mount=type=bind,target=/build,rw \
GOOS="${TARGETOS:-linux}" GOARCH="${TARGETARCH:-amd64}" ; \
make -C opencloud/opencloud release-linux-docker-${TARGETARCH} ENABLE_VIPS=true DIST=/dist
FROM alpine:3.22
FROM alpine:3.23
ARG VERSION
ARG REVISION
ARG TARGETOS
+1 -1
View File
@@ -34,7 +34,7 @@ var (
// LatestTag is the latest released version plus the dev meta version.
// Will be overwritten by the release pipeline
// Needs a manual change for every tagged release
LatestTag = "6.1.0+dev"
LatestTag = "6.2.0+dev"
// Date indicates the build date.
// This has been removed, it looks like you can only replace static strings with recent go versions
@@ -627,13 +627,13 @@ type Bundle struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name"
Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=opencloud.messages.settings.v0.Bundle_Type" json:"type,omitempty" yaml:"type"` // @gotags: yaml:"type"
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty" yaml:"extension"` // @gotags: yaml:"extension"
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name"
Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty" yaml:"settings"` // @gotags: yaml:"settings"
Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name"
Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=opencloud.messages.settings.v0.Bundle_Type" json:"type,omitempty"` // @gotags: yaml:"type"
Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty"` // @gotags: yaml:"extension"
DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name"
Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty"` // @gotags: yaml:"settings"
Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
}
func (x *Bundle) Reset() {
@@ -722,10 +722,10 @@ type Setting struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name"
DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name"
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` // @gotags: yaml:"description"
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name"
DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name"
Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` // @gotags: yaml:"description"
// Types that are assignable to Value:
//
// *Setting_IntValue
@@ -736,7 +736,7 @@ type Setting struct {
// *Setting_PermissionValue
// *Setting_MultiChoiceCollectionValue
Value isSetting_Value `protobuf_oneof:"value"`
Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
}
func (x *Setting) Reset() {
@@ -867,31 +867,31 @@ type isSetting_Value interface {
}
type Setting_IntValue struct {
IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type Setting_StringValue struct {
StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type Setting_BoolValue struct {
BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
type Setting_SingleChoiceValue struct {
SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof" yaml:"single_choice_value"` // @gotags: yaml:"single_choice_value"
SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof"` // @gotags: yaml:"single_choice_value"
}
type Setting_MultiChoiceValue struct {
MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof" yaml:"multi_choice_value"` // @gotags: yaml:"multi_choice_value"
MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof"` // @gotags: yaml:"multi_choice_value"
}
type Setting_PermissionValue struct {
PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof" yaml:"permission_value"` // @gotags: yaml:"permission_value"
PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof"` // @gotags: yaml:"permission_value"
}
type Setting_MultiChoiceCollectionValue struct {
MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof" yaml:"multi_choice_collection_value"` // @gotags: yaml:"multi_choice_collection_value"
MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof"` // @gotags: yaml:"multi_choice_collection_value"
}
func (*Setting_IntValue) isSetting_Value() {}
@@ -913,11 +913,11 @@ type Int struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty" yaml:"min"` // @gotags: yaml:"min"
Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty" yaml:"max"` // @gotags: yaml:"max"
Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty" yaml:"step"` // @gotags: yaml:"step"
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder"
Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty"` // @gotags: yaml:"min"
Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty"` // @gotags: yaml:"max"
Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty"` // @gotags: yaml:"step"
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder"
}
func (x *Int) Reset() {
@@ -992,11 +992,11 @@ type String struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty" yaml:"required"` // @gotags: yaml:"required"
MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty" yaml:"min_length"` // @gotags: yaml:"min_length"
MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty" yaml:"max_length"` // @gotags: yaml:"max_length"
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder"
Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty"` // @gotags: yaml:"required"
MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` // @gotags: yaml:"min_length"
MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` // @gotags: yaml:"max_length"
Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder"
}
func (x *String) Reset() {
@@ -1071,8 +1071,8 @@ type Bool struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty" yaml:"label"` // @gotags: yaml:"label"
Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` // @gotags: yaml:"label"
}
func (x *Bool) Reset() {
@@ -1126,7 +1126,7 @@ type SingleChoiceList struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
}
func (x *SingleChoiceList) Reset() {
@@ -1173,7 +1173,7 @@ type MultiChoiceList struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
}
func (x *MultiChoiceList) Reset() {
@@ -1220,9 +1220,9 @@ type ListOption struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value"
Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default"
DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value"
Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value"
Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default"
DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value"
}
func (x *ListOption) Reset() {
@@ -1283,7 +1283,7 @@ type MultiChoiceCollection struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options"
Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options"
}
func (x *MultiChoiceCollection) Reset() {
@@ -1330,10 +1330,10 @@ type MultiChoiceCollectionOption struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value"
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key"
Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty" yaml:"attribute"` // @gotags: yaml:"attribute"
DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value"
Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value"
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key"
Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty"` // @gotags: yaml:"attribute"
DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value"
}
func (x *MultiChoiceCollectionOption) Reset() {
@@ -1474,15 +1474,15 @@ type isMultiChoiceCollectionOptionValue_Option interface {
}
type MultiChoiceCollectionOptionValue_IntValue struct {
IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type MultiChoiceCollectionOptionValue_StringValue struct {
StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type MultiChoiceCollectionOptionValue_BoolValue struct {
BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
func (*MultiChoiceCollectionOptionValue_IntValue) isMultiChoiceCollectionOptionValue_Option() {}
@@ -1496,8 +1496,8 @@ type Permission struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=opencloud.messages.settings.v0.Permission_Operation" json:"operation,omitempty" yaml:"operation"` // @gotags: yaml:"operation"
Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=opencloud.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty" yaml:"constraint"` // @gotags: yaml:"constraint"
Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=opencloud.messages.settings.v0.Permission_Operation" json:"operation,omitempty"` // @gotags: yaml:"operation"
Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=opencloud.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty"` // @gotags: yaml:"constraint"
}
func (x *Permission) Reset() {
@@ -1552,12 +1552,12 @@ type Value struct {
unknownFields protoimpl.UnknownFields
// id is the id of the Value. It is generated on saving it.
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id"
BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty" yaml:"bundle_id"` // @gotags: yaml:"bundle_id"
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id"
BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty"` // @gotags: yaml:"bundle_id"
// setting_id is the id of the setting from within its bundle.
SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty" yaml:"setting_id"` // @gotags: yaml:"setting_id"
AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty" yaml:"account_uuid"` // @gotags: yaml:"account_uuid"
Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource"
SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty"` // @gotags: yaml:"setting_id"
AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty"` // @gotags: yaml:"account_uuid"
Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource"
// Types that are assignable to Value:
//
// *Value_BoolValue
@@ -1682,23 +1682,23 @@ type isValue_Value interface {
}
type Value_BoolValue struct {
BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
type Value_IntValue struct {
IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type Value_StringValue struct {
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type Value_ListValue struct {
ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof" yaml:"list_value"` // @gotags: yaml:"list_value"
ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof"` // @gotags: yaml:"list_value"
}
type Value_CollectionValue struct {
CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof" yaml:"collection_value"` // @gotags: yaml:"collection_value"
CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof"` // @gotags: yaml:"collection_value"
}
func (*Value_BoolValue) isValue_Value() {}
@@ -1716,7 +1716,7 @@ type ListValue struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values"
Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values"
}
func (x *ListValue) Reset() {
@@ -1836,15 +1836,15 @@ type isListOptionValue_Option interface {
}
type ListOptionValue_StringValue struct {
StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type ListOptionValue_IntValue struct {
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type ListOptionValue_BoolValue struct {
BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
func (*ListOptionValue_StringValue) isListOptionValue_Option() {}
@@ -1858,7 +1858,7 @@ type CollectionValue struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values"
Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values"
}
func (x *CollectionValue) Reset() {
@@ -1906,7 +1906,7 @@ type CollectionOption struct {
unknownFields protoimpl.UnknownFields
// required
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key"
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key"
// Types that are assignable to Option:
//
// *CollectionOption_IntValue
@@ -1987,15 +1987,15 @@ type isCollectionOption_Option interface {
}
type CollectionOption_IntValue struct {
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value"
IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value"
}
type CollectionOption_StringValue struct {
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value"
StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value"
}
type CollectionOption_BoolValue struct {
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value"
BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value"
}
func (*CollectionOption_IntValue) isCollectionOption_Option() {}
+13 -24
View File
@@ -4,8 +4,8 @@ import (
"context"
"fmt"
"github.com/oklog/run"
"github.com/opencloud-eu/opencloud/pkg/log"
"github.com/opencloud-eu/opencloud/pkg/runner"
"github.com/opencloud-eu/reva/v2/pkg/events"
"github.com/opencloud-eu/reva/v2/pkg/events/stream"
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
@@ -62,7 +62,7 @@ func Server(cfg *config.Config) *cobra.Command {
return err
}
gr := run.Group{}
gr := runner.NewGroup()
ctx, cancel := context.WithCancel(cmd.Context())
mtrcs := metrics.New()
@@ -132,23 +132,7 @@ func Server(cfg *config.Config) *cobra.Command {
return err
}
gr.Add(func() error {
return svc.Run()
}, func(err error) {
if err == nil {
logger.Info().
Str("transport", "http").
Str("server", cfg.Service.Name).
Msg("Shutting down server")
} else {
logger.Error().Err(err).
Str("transport", "http").
Str("server", cfg.Service.Name).
Msg("Shutting down server")
}
cancel()
})
gr.Add(runner.NewGoMicroHttpServerRunner(cfg.Service.Name+".http", svc))
}
{
@@ -162,13 +146,18 @@ func Server(cfg *config.Config) *cobra.Command {
return err
}
gr.Add(debugServer.ListenAndServe, func(_ error) {
_ = debugServer.Shutdown(ctx)
cancel()
})
gr.Add(runner.NewGolangHttpServerRunner(cfg.Service.Name+".debug", debugServer))
}
return gr.Run()
grResults := gr.Run(ctx)
// return the first non-nil error found in the results
for _, grResult := range grResults {
if grResult.RunnerError != nil {
return grResult.RunnerError
}
}
return nil
},
}
}
@@ -1278,6 +1278,7 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
fileinfo.KeyEnableOwnerTermination: true, // only for collabora
fileinfo.KeyEnableInsertRemoteImage: true,
fileinfo.KeyEnableInsertRemoteFile: true,
fileinfo.KeyEnableRemoteLinkPicker: true,
fileinfo.KeySupportsExtendedLockLength: true,
fileinfo.KeySupportsGetLock: true,
fileinfo.KeySupportsLocks: true,
@@ -1802,6 +1802,7 @@ var _ = Describe("FileConnector", func() {
PostMessageOrigin: "https://cloud.opencloud.test",
EnableInsertRemoteImage: true,
EnableInsertRemoteFile: true,
EnableRemoteLinkPicker: true,
IsAnonymousUser: true,
}
@@ -1995,6 +1996,7 @@ var _ = Describe("FileConnector", func() {
PostMessageOrigin: "https://cloud.opencloud.test",
EnableInsertRemoteImage: true,
EnableInsertRemoteFile: true,
EnableRemoteLinkPicker: true,
IsAdminUser: true,
UserExtraInfo: &fileinfo.UserExtraInfo{
Mail: "shaft@example.com",
@@ -46,6 +46,8 @@ type Collabora struct {
EnableInsertRemoteImage bool `json:"EnableInsertRemoteImage,omitempty"`
// If set to true, this will enable the insertion of remote files chosen from the WOPI storage. A UI_InsertFile postMessage will be sent to the WOPI host to request the UI to select the file. This enables multimedia insertion and document comparison features.
EnableInsertRemoteFile bool `json:"EnableInsertRemoteFile,omitempty"`
// If set to true, this will enable picking a link to a remote file from the WOPI storage. A UI_PickLink postMessage will be sent to the WOPI host to request the UI to select the file. The host is expected to reply with an Action_InsertLink message carrying the file URL.
EnableRemoteLinkPicker bool `json:"EnableRemoteLinkPicker,omitempty"`
// If set to true, this will disable the insertion of image chosen from the local device. If EnableInsertRemoteImage is not set to true, then inserting images files is not possible.
DisableInsertLocalImage bool `json:"DisableInsertLocalImage,omitempty"`
// If set to true, hides the print option from the file menu bar in the UI.
@@ -124,6 +126,8 @@ func (cinfo *Collabora) SetProperties(props map[string]any) {
cinfo.EnableInsertRemoteImage = value.(bool)
case KeyEnableInsertRemoteFile:
cinfo.EnableInsertRemoteFile = value.(bool)
case KeyEnableRemoteLinkPicker:
cinfo.EnableRemoteLinkPicker = value.(bool)
case KeyDisableInsertLocalImage:
cinfo.DisableInsertLocalImage = value.(bool)
case KeyHidePrintOption:
@@ -104,6 +104,7 @@ const (
KeyEnableInsertRemoteImage = "EnableInsertRemoteImage"
KeyEnableInsertRemoteFile = "EnableInsertRemoteFile"
KeyEnableRemoteLinkPicker = "EnableRemoteLinkPicker"
KeyDisableInsertLocalImage = "DisableInsertLocalImage"
KeyHidePrintOption = "HidePrintOption"
KeyHideSaveOption = "HideSaveOption"
+1 -1
View File
@@ -63,7 +63,7 @@ func FrontendConfigFromStruct(cfg *config.Config, logger log.Logger) (map[string
"tags": true,
"archivers": archivers,
"app_providers": appProviders,
"favorites": true,
"favorites": false,
"full_text_search": cfg.FullTextSearch,
}
@@ -3,6 +3,7 @@ package svc
import (
"context"
"errors"
"fmt"
"net/http"
"net/url"
"slices"
@@ -91,6 +92,10 @@ type ListPermissionsQueryOptions struct {
// NewDriveItemPermissionsService creates a new DriveItemPermissionsService
func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Selectable[gateway.GatewayAPIClient], identityCache cache.IdentityCache, config *config.Config) (DriveItemPermissionsService, error) {
publicBaseURL, err := url.Parse(config.Spaces.WebDavBase)
if err != nil {
return DriveItemPermissionsService{}, fmt.Errorf("could not parse graph.spaces.webdav_base: %w", err)
}
return DriveItemPermissionsService{
BaseGraphService: BaseGraphService{
logger: &log.Logger{Logger: logger.With().Str("graph api", "DrivesDriveItemService").Logger()},
@@ -98,6 +103,7 @@ func NewDriveItemPermissionsService(logger log.Logger, gatewaySelector pool.Sele
identityCache: identityCache,
config: config,
availableRoles: unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(config.UnifiedRoles.AvailableRoles...)),
publicBaseURL: publicBaseURL,
},
}, nil
}
@@ -401,7 +407,7 @@ func (s DriveItemPermissionsService) ListPermissions(ctx context.Context, itemID
driveItems := make(driveItemsByResourceID, 1)
// we can use the statResponse to build the drive item before fetching the shares
item, err := cs3ResourceToDriveItem(s.logger, statResponse.GetInfo())
item, err := cs3ResourceToDriveItem(s.logger, s.publicBaseURL, statResponse.GetInfo())
if err != nil {
return collectionOfPermissions, err
}
+2 -1
View File
@@ -49,6 +49,7 @@ type BaseGraphService struct {
identityCache cache.IdentityCache
config *config.Config
availableRoles []*libregraph.UnifiedRoleDefinition
publicBaseURL *url.URL
}
func (g BaseGraphService) getDriveItem(ctx context.Context, ref *storageprovider.Reference) (*libregraph.DriveItem, error) {
@@ -65,7 +66,7 @@ func (g BaseGraphService) getDriveItem(ctx context.Context, ref *storageprovider
refStr, _ := storagespace.FormatReference(ref)
return nil, fmt.Errorf("could not stat %s: %s", refStr, res.GetStatus().GetMessage())
}
return cs3ResourceToDriveItem(g.logger, res.GetInfo())
return cs3ResourceToDriveItem(g.logger, g.publicBaseURL, res.GetInfo())
}
func (g BaseGraphService) CS3ReceivedSharesToDriveItems(ctx context.Context, receivedShares []*collaboration.ReceivedShare) ([]libregraph.DriveItem, error) {
+10 -6
View File
@@ -204,7 +204,7 @@ func (g Graph) GetRootDriveChildren(w http.ResponseWriter, r *http.Request) {
return
}
files, err := formatDriveItems(g.logger, lRes.GetInfos())
files, err := formatDriveItems(g.logger, g.publicBaseURL, lRes.GetInfos())
if err != nil {
g.logger.Error().Err(err).Msg("error encoding response as json")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
@@ -269,7 +269,7 @@ func (g Graph) GetDriveItem(w http.ResponseWriter, r *http.Request) {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, res.GetStatus().GetMessage())
return
}
driveItem, err := cs3ResourceToDriveItem(g.logger, res.GetInfo())
driveItem, err := cs3ResourceToDriveItem(g.logger, g.publicBaseURL, res.GetInfo())
if err != nil {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
@@ -337,7 +337,7 @@ func (g Graph) GetDriveItemChildren(w http.ResponseWriter, r *http.Request) {
return
}
files, err := formatDriveItems(g.logger, res.GetInfos())
files, err := formatDriveItems(g.logger, g.publicBaseURL, res.GetInfos())
if err != nil {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
@@ -385,10 +385,10 @@ func (g Graph) getRemoteItem(ctx context.Context, root *storageprovider.Resource
return item, nil
}
func formatDriveItems(logger *log.Logger, mds []*storageprovider.ResourceInfo) ([]*libregraph.DriveItem, error) {
func formatDriveItems(logger *log.Logger, publicBaseURL *url.URL, mds []*storageprovider.ResourceInfo) ([]*libregraph.DriveItem, error) {
responses := make([]*libregraph.DriveItem, 0, len(mds))
for i := range mds {
res, err := cs3ResourceToDriveItem(logger, mds[i])
res, err := cs3ResourceToDriveItem(logger, publicBaseURL, mds[i])
if err != nil {
return nil, err
}
@@ -402,7 +402,7 @@ func cs3TimestampToTime(t *types.Timestamp) time.Time {
return time.Unix(int64(t.GetSeconds()), int64(t.GetNanos()))
}
func cs3ResourceToDriveItem(logger *log.Logger, res *storageprovider.ResourceInfo) (*libregraph.DriveItem, error) {
func cs3ResourceToDriveItem(logger *log.Logger, publicBaseURL *url.URL, res *storageprovider.ResourceInfo) (*libregraph.DriveItem, error) {
size := new(int64)
*size = int64(res.GetSize()) // TODO lurking overflow: make size of libregraph drive item use uint64
@@ -411,6 +411,10 @@ func cs3ResourceToDriveItem(logger *log.Logger, res *storageprovider.ResourceInf
Size: size,
}
webURL := *publicBaseURL
webURL.Path = path.Join(webURL.Path, "f", storagespace.FormatResourceID(res.GetId()))
driveItem.WebUrl = libregraph.PtrString(webURL.String())
if name := path.Base(res.GetPath()); name != "" {
driveItem.Name = &name
}
@@ -0,0 +1,44 @@
package svc
import (
"net/url"
"testing"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/opencloud-eu/opencloud/pkg/log"
)
func TestCS3ResourceToDriveItemPopulatesWebUrl(t *testing.T) {
logger := log.NewLogger()
res := &provider.ResourceInfo{
Id: &provider.ResourceId{
StorageId: "storage-1",
SpaceId: "space-1",
OpaqueId: "item-1",
},
Type: provider.ResourceType_RESOURCE_TYPE_CONTAINER,
}
t.Run("public base URL without path", func(t *testing.T) {
base, err := url.Parse("https://example.com")
require.NoError(t, err)
item, err := cs3ResourceToDriveItem(&logger, base, res)
require.NoError(t, err)
require.NotNil(t, item.WebUrl)
assert.Equal(t, "https://example.com/f/storage-1$space-1%21item-1", *item.WebUrl)
})
t.Run("public base URL with path prefix", func(t *testing.T) {
base, err := url.Parse("https://example.com/cloud")
require.NoError(t, err)
item, err := cs3ResourceToDriveItem(&logger, base, res)
require.NoError(t, err)
require.NotNil(t, item.WebUrl)
assert.Equal(t, "https://example.com/cloud/f/storage-1$space-1%21item-1", *item.WebUrl)
})
}
+1 -1
View File
@@ -94,7 +94,7 @@ func (g Graph) FollowDriveItem(w http.ResponseWriter, r *http.Request) {
}
}
driveItem, err := cs3ResourceToDriveItem(g.logger, statRes.GetInfo())
driveItem, err := cs3ResourceToDriveItem(g.logger, g.publicBaseURL, statRes.GetInfo())
if err != nil {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
return
+7
View File
@@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"net/http"
"net/url"
"os"
"strconv"
"time"
@@ -154,12 +155,18 @@ func NewService(opts ...Option) (Graph, error) { //nolint:maintidx
cache.IdentityCacheWithGroupsTTL(time.Duration(options.Config.Spaces.GroupsCacheTTL)),
)
publicBaseURL, err := url.Parse(options.Config.Spaces.WebDavBase)
if err != nil {
return Graph{}, fmt.Errorf("could not parse graph.spaces.webdav_base: %w", err)
}
baseGraphService := BaseGraphService{
logger: &options.Logger,
identityCache: identityCache,
gatewaySelector: options.GatewaySelector,
config: options.Config,
availableRoles: unifiedrole.GetRoles(unifiedrole.RoleFilterIDs(options.Config.UnifiedRoles.AvailableRoles...)),
publicBaseURL: publicBaseURL,
}
drivesDriveItemService, err := NewDrivesDriveItemService(options.Logger, options.GatewaySelector)
+2 -3
View File
@@ -36,7 +36,6 @@ import (
"github.com/opencloud-eu/opencloud/services/graph/pkg/identity"
"github.com/opencloud-eu/opencloud/services/graph/pkg/odata"
"github.com/opencloud-eu/opencloud/services/graph/pkg/userstate"
ocsettingssvc "github.com/opencloud-eu/opencloud/services/settings/pkg/service/v0"
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
)
@@ -421,10 +420,10 @@ func (g Graph) PostUser(w http.ResponseWriter, r *http.Request) {
// to all new users for now, as create Account request does not have any role field
if _, err = g.roleService.AssignRoleToUser(r.Context(), &settingssvc.AssignRoleToUserRequest{
AccountUuid: *u.Id,
RoleId: ocsettingssvc.BundleUUIDRoleUser,
RoleId: defaults.BundleUUIDRoleUser,
}); err != nil {
// log as error, admin eventually needs to do something
logger.Error().Err(err).Str("id", *u.Id).Str("role", ocsettingssvc.BundleUUIDRoleUser).Msg("could not create user: role assignment failed")
logger.Error().Err(err).Str("id", *u.Id).Str("role", defaults.BundleUUIDRoleUser).Msg("could not create user: role assignment failed")
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, "role assignment failed")
return
}
@@ -119,7 +119,7 @@ func (_c *UserBackend_Authenticate_Call) RunAndReturn(run func(ctx context.Conte
}
// CreateUserFromClaims provides a mock function for the type UserBackend
func (_mock *UserBackend) CreateUserFromClaims(ctx context.Context, claims map[string]interface{}) (*userv1beta1.User, error) {
func (_mock *UserBackend) CreateUserFromClaims(ctx context.Context, claims map[string]any) (*userv1beta1.User, error) {
ret := _mock.Called(ctx, claims)
if len(ret) == 0 {
@@ -128,17 +128,17 @@ func (_mock *UserBackend) CreateUserFromClaims(ctx context.Context, claims map[s
var r0 *userv1beta1.User
var r1 error
if returnFunc, ok := ret.Get(0).(func(context.Context, map[string]interface{}) (*userv1beta1.User, error)); ok {
if returnFunc, ok := ret.Get(0).(func(context.Context, map[string]any) (*userv1beta1.User, error)); ok {
return returnFunc(ctx, claims)
}
if returnFunc, ok := ret.Get(0).(func(context.Context, map[string]interface{}) *userv1beta1.User); ok {
if returnFunc, ok := ret.Get(0).(func(context.Context, map[string]any) *userv1beta1.User); ok {
r0 = returnFunc(ctx, claims)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*userv1beta1.User)
}
}
if returnFunc, ok := ret.Get(1).(func(context.Context, map[string]interface{}) error); ok {
if returnFunc, ok := ret.Get(1).(func(context.Context, map[string]any) error); ok {
r1 = returnFunc(ctx, claims)
} else {
r1 = ret.Error(1)
@@ -153,20 +153,20 @@ type UserBackend_CreateUserFromClaims_Call struct {
// CreateUserFromClaims is a helper method to define mock.On call
// - ctx context.Context
// - claims map[string]interface{}
// - claims map[string]any
func (_e *UserBackend_Expecter) CreateUserFromClaims(ctx interface{}, claims interface{}) *UserBackend_CreateUserFromClaims_Call {
return &UserBackend_CreateUserFromClaims_Call{Call: _e.mock.On("CreateUserFromClaims", ctx, claims)}
}
func (_c *UserBackend_CreateUserFromClaims_Call) Run(run func(ctx context.Context, claims map[string]interface{})) *UserBackend_CreateUserFromClaims_Call {
func (_c *UserBackend_CreateUserFromClaims_Call) Run(run func(ctx context.Context, claims map[string]any)) *UserBackend_CreateUserFromClaims_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
arg0 = args[0].(context.Context)
}
var arg1 map[string]interface{}
var arg1 map[string]any
if args[1] != nil {
arg1 = args[1].(map[string]interface{})
arg1 = args[1].(map[string]any)
}
run(
arg0,
@@ -181,7 +181,7 @@ func (_c *UserBackend_CreateUserFromClaims_Call) Return(user *userv1beta1.User,
return _c
}
func (_c *UserBackend_CreateUserFromClaims_Call) RunAndReturn(run func(ctx context.Context, claims map[string]interface{}) (*userv1beta1.User, error)) *UserBackend_CreateUserFromClaims_Call {
func (_c *UserBackend_CreateUserFromClaims_Call) RunAndReturn(run func(ctx context.Context, claims map[string]any) (*userv1beta1.User, error)) *UserBackend_CreateUserFromClaims_Call {
_c.Call.Return(run)
return _c
}
@@ -267,7 +267,7 @@ func (_c *UserBackend_GetUserByClaims_Call) RunAndReturn(run func(ctx context.Co
}
// SyncGroupMemberships provides a mock function for the type UserBackend
func (_mock *UserBackend) SyncGroupMemberships(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) error {
func (_mock *UserBackend) SyncGroupMemberships(ctx context.Context, user *userv1beta1.User, claims map[string]any) error {
ret := _mock.Called(ctx, user, claims)
if len(ret) == 0 {
@@ -275,7 +275,7 @@ func (_mock *UserBackend) SyncGroupMemberships(ctx context.Context, user *userv1
}
var r0 error
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]interface{}) error); ok {
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]any) error); ok {
r0 = returnFunc(ctx, user, claims)
} else {
r0 = ret.Error(0)
@@ -291,12 +291,12 @@ type UserBackend_SyncGroupMemberships_Call struct {
// SyncGroupMemberships is a helper method to define mock.On call
// - ctx context.Context
// - user *userv1beta1.User
// - claims map[string]interface{}
// - claims map[string]any
func (_e *UserBackend_Expecter) SyncGroupMemberships(ctx interface{}, user interface{}, claims interface{}) *UserBackend_SyncGroupMemberships_Call {
return &UserBackend_SyncGroupMemberships_Call{Call: _e.mock.On("SyncGroupMemberships", ctx, user, claims)}
}
func (_c *UserBackend_SyncGroupMemberships_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{})) *UserBackend_SyncGroupMemberships_Call {
func (_c *UserBackend_SyncGroupMemberships_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any)) *UserBackend_SyncGroupMemberships_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
@@ -306,9 +306,9 @@ func (_c *UserBackend_SyncGroupMemberships_Call) Run(run func(ctx context.Contex
if args[1] != nil {
arg1 = args[1].(*userv1beta1.User)
}
var arg2 map[string]interface{}
var arg2 map[string]any
if args[2] != nil {
arg2 = args[2].(map[string]interface{})
arg2 = args[2].(map[string]any)
}
run(
arg0,
@@ -324,13 +324,13 @@ func (_c *UserBackend_SyncGroupMemberships_Call) Return(err error) *UserBackend_
return _c
}
func (_c *UserBackend_SyncGroupMemberships_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) error) *UserBackend_SyncGroupMemberships_Call {
func (_c *UserBackend_SyncGroupMemberships_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any) error) *UserBackend_SyncGroupMemberships_Call {
_c.Call.Return(run)
return _c
}
// UpdateUserIfNeeded provides a mock function for the type UserBackend
func (_mock *UserBackend) UpdateUserIfNeeded(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) error {
func (_mock *UserBackend) UpdateUserIfNeeded(ctx context.Context, user *userv1beta1.User, claims map[string]any) error {
ret := _mock.Called(ctx, user, claims)
if len(ret) == 0 {
@@ -338,7 +338,7 @@ func (_mock *UserBackend) UpdateUserIfNeeded(ctx context.Context, user *userv1be
}
var r0 error
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]interface{}) error); ok {
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]any) error); ok {
r0 = returnFunc(ctx, user, claims)
} else {
r0 = ret.Error(0)
@@ -354,12 +354,12 @@ type UserBackend_UpdateUserIfNeeded_Call struct {
// UpdateUserIfNeeded is a helper method to define mock.On call
// - ctx context.Context
// - user *userv1beta1.User
// - claims map[string]interface{}
// - claims map[string]any
func (_e *UserBackend_Expecter) UpdateUserIfNeeded(ctx interface{}, user interface{}, claims interface{}) *UserBackend_UpdateUserIfNeeded_Call {
return &UserBackend_UpdateUserIfNeeded_Call{Call: _e.mock.On("UpdateUserIfNeeded", ctx, user, claims)}
}
func (_c *UserBackend_UpdateUserIfNeeded_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{})) *UserBackend_UpdateUserIfNeeded_Call {
func (_c *UserBackend_UpdateUserIfNeeded_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any)) *UserBackend_UpdateUserIfNeeded_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
@@ -369,9 +369,9 @@ func (_c *UserBackend_UpdateUserIfNeeded_Call) Run(run func(ctx context.Context,
if args[1] != nil {
arg1 = args[1].(*userv1beta1.User)
}
var arg2 map[string]interface{}
var arg2 map[string]any
if args[2] != nil {
arg2 = args[2].(map[string]interface{})
arg2 = args[2].(map[string]any)
}
run(
arg0,
@@ -387,7 +387,7 @@ func (_c *UserBackend_UpdateUserIfNeeded_Call) Return(err error) *UserBackend_Up
return _c
}
func (_c *UserBackend_UpdateUserIfNeeded_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) error) *UserBackend_UpdateUserIfNeeded_Call {
func (_c *UserBackend_UpdateUserIfNeeded_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any) error) *UserBackend_UpdateUserIfNeeded_Call {
_c.Call.Return(run)
return _c
}
+3 -3
View File
@@ -6,7 +6,7 @@ import (
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/opencloud-eu/opencloud/pkg/middleware"
settingssvc "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/services/settings/v0"
settingsService "github.com/opencloud-eu/opencloud/services/settings/pkg/service/v0"
"github.com/opencloud-eu/opencloud/services/settings/pkg/store/defaults"
"github.com/opencloud-eu/reva/v2/pkg/utils"
"go-micro.dev/v4/metadata"
)
@@ -44,9 +44,9 @@ func (d defaultRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user
// default user role. At least until proper roles are provided. See
// https://github.com/owncloud/ocis/issues/1825 for more context.
if user.Id.Type == cs3.UserType_USER_TYPE_PRIMARY || user.Id.Type == cs3.UserType_USER_TYPE_GUEST {
roleId := settingsService.BundleUUIDRoleUser
roleId := defaults.BundleUUIDRoleUser
if user.Id.Type == cs3.UserType_USER_TYPE_GUEST {
roleId = settingsService.BundleUUIDRoleGuest
roleId = defaults.BundleUUIDRoleGuest
}
d.logger.Info().Str("userid", user.Id.OpaqueId).Msg("user has no role assigned, assigning default user role")
ctx = metadata.Set(ctx, middleware.AccountID, user.Id.OpaqueId)
@@ -107,7 +107,7 @@ func (_c *UserRoleAssigner_ApplyUserRole_Call) RunAndReturn(run func(ctx context
}
// UpdateUserRoleAssignment provides a mock function for the type UserRoleAssigner
func (_mock *UserRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) (*userv1beta1.User, error) {
func (_mock *UserRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, user *userv1beta1.User, claims map[string]any) (*userv1beta1.User, error) {
ret := _mock.Called(ctx, user, claims)
if len(ret) == 0 {
@@ -116,17 +116,17 @@ func (_mock *UserRoleAssigner) UpdateUserRoleAssignment(ctx context.Context, use
var r0 *userv1beta1.User
var r1 error
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]interface{}) (*userv1beta1.User, error)); ok {
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]any) (*userv1beta1.User, error)); ok {
return returnFunc(ctx, user, claims)
}
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]interface{}) *userv1beta1.User); ok {
if returnFunc, ok := ret.Get(0).(func(context.Context, *userv1beta1.User, map[string]any) *userv1beta1.User); ok {
r0 = returnFunc(ctx, user, claims)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*userv1beta1.User)
}
}
if returnFunc, ok := ret.Get(1).(func(context.Context, *userv1beta1.User, map[string]interface{}) error); ok {
if returnFunc, ok := ret.Get(1).(func(context.Context, *userv1beta1.User, map[string]any) error); ok {
r1 = returnFunc(ctx, user, claims)
} else {
r1 = ret.Error(1)
@@ -142,12 +142,12 @@ type UserRoleAssigner_UpdateUserRoleAssignment_Call struct {
// UpdateUserRoleAssignment is a helper method to define mock.On call
// - ctx context.Context
// - user *userv1beta1.User
// - claims map[string]interface{}
// - claims map[string]any
func (_e *UserRoleAssigner_Expecter) UpdateUserRoleAssignment(ctx interface{}, user interface{}, claims interface{}) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
return &UserRoleAssigner_UpdateUserRoleAssignment_Call{Call: _e.mock.On("UpdateUserRoleAssignment", ctx, user, claims)}
}
func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{})) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) Run(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any)) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
_c.Call.Run(func(args mock.Arguments) {
var arg0 context.Context
if args[0] != nil {
@@ -157,9 +157,9 @@ func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) Run(run func(ctx conte
if args[1] != nil {
arg1 = args[1].(*userv1beta1.User)
}
var arg2 map[string]interface{}
var arg2 map[string]any
if args[2] != nil {
arg2 = args[2].(map[string]interface{})
arg2 = args[2].(map[string]any)
}
run(
arg0,
@@ -175,7 +175,7 @@ func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) Return(user1 *userv1be
return _c
}
func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]interface{}) (*userv1beta1.User, error)) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
func (_c *UserRoleAssigner_UpdateUserRoleAssignment_Call) RunAndReturn(run func(ctx context.Context, user *userv1beta1.User, claims map[string]any) (*userv1beta1.User, error)) *UserRoleAssigner_UpdateUserRoleAssignment_Call {
_c.Call.Return(run)
return _c
}
+2 -2
View File
@@ -118,11 +118,11 @@ It can also be used to re-index all spaces:
opencloud search index --all-spaces
```
Please note that a reindex only picks up new files. Files that have already been indexed are not indexed again, even if the configuration or the whole extractor has been changed. To force a full reindex you need to use the `force-reindex` flag:
Please note that a reindex only picks up new or changed files. Files that have already been indexed are not scanned again, even if the configuration or the whole extractor has been changed. To force a full rescan (re-running the extractor on every file) you need to use the `force-rescan` flag:
```shell
opencloud search index --all-spaces --force-reindex
opencloud search index --all-spaces --force-rescan
```
## Metrics
@@ -81,35 +81,26 @@ var _ = Describe("SpaceDebouncer", func() {
}
}, log.NewLogger())
// Initial call to start the timers
// Reset the debounce timer every 50ms (shorter than the 100ms debounce
// duration) but stop before the 250ms timeout fires. Continuing past the
// timeout would race with the work function's cleanup of pending state:
// a Debounce call arriving right after the timeout fires would find
// pending empty and schedule a second workItem, breaking the assertion
// below that the work function is invoked exactly once.
debouncer.Debounce(spaceid, nil)
// Continuously reset the debounce timer using a ticker, at an interval
// shorter than the debounce time.
ticker := time.NewTicker(50 * time.Millisecond)
defer ticker.Stop()
done := make(chan bool)
go func() {
for {
select {
case <-done:
return
case <-ticker.C:
debouncer.Debounce(spaceid, nil)
}
for i := 0; i < 4 && callCount.Load() == 0; i++ {
time.Sleep(50 * time.Millisecond)
if callCount.Load() == 0 {
debouncer.Debounce(spaceid, nil)
}
}()
}
// The debounce timer (100ms) should be reset every 50ms and thus never fire.
// The timeout timer (250ms) should fire regardless.
// The debounce timer (100ms) was reset roughly every 50ms and should
// not have fired. The timeout timer (250ms) should fire regardless.
Eventually(func() int {
return int(callCount.Load())
}, "300ms").Should(Equal(1))
// Stop the ticker goroutine
close(done)
// And it should not fire again
Consistently(func() int {
return int(callCount.Load())
@@ -1,61 +1,13 @@
package svc
const (
// BundleUUIDRoleAdmin represents the admin role
BundleUUIDRoleAdmin = "71881883-1768-46bd-a24d-a356a2afdf7f"
// BundleUUIDRoleSpaceAdmin represents the space admin role
BundleUUIDRoleSpaceAdmin = "2aadd357-682c-406b-8874-293091995fdd"
// BundleUUIDRoleUser represents the user role.
BundleUUIDRoleUser = "d7beeea8-8ff4-406b-8fb6-ab2dd81e6b11"
// BundleUUIDRoleGuest represents the guest role.
BundleUUIDRoleGuest = "38071a68-456a-4553-846a-fa67bf5596cc"
// RoleManagementPermissionID is the hardcoded setting UUID for the role management permission
RoleManagementPermissionID string = "a53e601e-571f-4f86-8fec-d4576ef49c62"
// RoleManagementPermissionName is the hardcoded setting name for the role management permission
RoleManagementPermissionName string = "role-management"
// SettingsManagementPermissionID is the hardcoded setting UUID for the settings management permission
SettingsManagementPermissionID string = "3d58f441-4a05-42f8-9411-ef5874528ae1"
// SettingsManagementPermissionName is the hardcoded setting name for the settings management permission
SettingsManagementPermissionName string = "settings-management"
// SetSpaceQuotaPermissionID is the hardcoded setting UUID for the set space quota permission
SetSpaceQuotaPermissionID string = "4e6f9709-f9e7-44f1-95d4-b762d27b7896"
// SetSpaceQuotaPermissionName is the hardcoded setting name for the set space quota permission
SetSpaceQuotaPermissionName string = "set-space-quota"
// ListAllSpacesPermissionID is the hardcoded setting UUID for the list all spaces permission
ListAllSpacesPermissionID string = "016f6ddd-9501-4a0a-8ebe-64a20ee8ec82"
// ListAllSpacesPermissionName is the hardcoded setting name for the list all spaces permission
ListAllSpacesPermissionName string = "list-all-spaces"
// CreateSpacePermissionID is the hardcoded setting UUID for the create space permission
CreateSpacePermissionID string = "79e13b30-3e22-11eb-bc51-0b9f0bad9a58"
// CreateSpacePermissionName is the hardcoded setting name for the create space permission
CreateSpacePermissionName string = "create-space"
// SettingUUIDProfileLanguage is the hardcoded setting UUID for the user profile language
SettingUUIDProfileLanguage = "aa8cfbe5-95d4-4f7e-a032-c3c01f5f062f"
// AccountManagementPermissionID is the hardcoded setting UUID for the account management permission
AccountManagementPermissionID string = "8e587774-d929-4215-910b-a317b1e80f73"
// AccountManagementPermissionName is the hardcoded setting name for the account management permission
AccountManagementPermissionName string = "account-management"
// GroupManagementPermissionID is the hardcoded setting UUID for the group management permission
GroupManagementPermissionID string = "522adfbe-5908-45b4-b135-41979de73245"
// GroupManagementPermissionName is the hardcoded setting name for the group management permission
GroupManagementPermissionName string = "group-management"
// SelfManagementPermissionID is the hardcoded setting UUID for the self management permission
SelfManagementPermissionID string = "e03070e9-4362-4cc6-a872-1c7cb2eb2b8e"
// SelfManagementPermissionName is the hardcoded setting name for the self management permission
SelfManagementPermissionName string = "self-management"
// ChangeLogoPermissionID is the hardcoded setting UUID for the change-logo permission
ChangeLogoPermissionID string = "ed83fc10-1f54-4a9e-b5a7-fb517f5f3e01"
// ChangeLogoPermissionName is the hardcoded setting name for the change-logo permission
ChangeLogoPermissionName string = "change-logo"
)
@@ -14,6 +14,8 @@ const (
BundleUUIDRoleUser = "d7beeea8-8ff4-406b-8fb6-ab2dd81e6b11"
// BundleUUIDRoleUserLight represents the user light role.
BundleUUIDRoleUserLight = "38071a68-456a-4553-846a-fa67bf5596cc"
// BundleUUIDRoleGuest represents the guest role.
BundleUUIDRoleGuest = "38071a68-456a-4553-846a-fa67bf5596cc"
// BundleUUIDProfile represents the user profile.
BundleUUIDProfile = "2a506de7-99bd-4f0d-994e-c38e72c28fd9"
// BundleUUIDServiceAccount represents the service account role.
+1 -1
View File
@@ -204,7 +204,7 @@ type PosixDriver struct {
EnableFSRevisions bool `yaml:"enable_fs_revisions" env:"STORAGE_USERS_POSIX_ENABLE_FS_REVISIONS" desc:"Allow for generating revisions from changes done to the local storage. Note: This doubles the number of bytes stored on disk because a copy of the current revision is stored to be turned into a revision later." introductionVersion:"1.0.0"`
ScanFS bool `yaml:"scan_fs" env:"STORAGE_USERS_POSIX_SCAN_FS" desc:"Scan the filesystem at startup for changes and update the metadata accordingly." introductionVersion:"%%NEXT%%"`
ScanFS bool `yaml:"scan_fs" env:"STORAGE_USERS_POSIX_SCAN_FS" desc:"Scan the filesystem at startup for changes and update the metadata accordingly." introductionVersion:"6.2.0"`
WatchFS bool `yaml:"watch_fs" env:"STORAGE_USERS_POSIX_WATCH_FS" desc:"Enable the filesystem watcher to detect changes to the filesystem. This is used to detect changes to the filesystem and update the metadata accordingly." introductionVersion:"2.0.0"`
WatchType string `yaml:"watch_type" env:"STORAGE_USERS_POSIX_WATCH_TYPE" desc:"Type of the watcher to use for getting notified about changes to the filesystem. Currently available options are 'inotifywait' (default), 'cephfs', 'gpfswatchfolder' and 'gpfsfileauditlogging'." introductionVersion:"1.0.0"`
WatchPath string `yaml:"watch_path" env:"STORAGE_USERS_POSIX_WATCH_PATH" desc:"Path to the watch directory/file. Only applies to the 'gpfsfileauditlogging' and 'inotifywait' watcher, in which case it is the path of the file audit log file/base directory to watch." introductionVersion:"1.0.0"`
+1 -1
View File
@@ -1,6 +1,6 @@
SHELL := bash
NAME := web
WEB_ASSETS_VERSION = v6.2.0
WEB_ASSETS_VERSION = v7.0.0
WEB_ASSETS_BRANCH = main
ifneq (, $(shell command -v go 2> /dev/null)) # suppress `command not found warnings` for non go targets in CI
+5 -3
View File
@@ -45,6 +45,11 @@ var (
}
)
// register the REPORT method at init so it cannot race with concurrent route setup in other services.
func init() {
chi.RegisterMethod("REPORT")
}
// Service defines the extension handlers.
type Service interface {
ServeHTTP(w http.ResponseWriter, r *http.Request)
@@ -93,9 +98,6 @@ func NewService(opts ...Option) (Service, error) {
svc.thumbnailsClient = nil
}
// register method with chi before any routing is set up
chi.RegisterMethod("REPORT")
m.Route(options.Config.HTTP.Root, func(r chi.Router) {
if !svc.config.DisablePreviews {
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright (c) 2016 HashiCorp, Inc.
Copyright IBM Corp. 2016, 2025
Mozilla Public License, version 2.0
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) HashiCorp, Inc.
# Copyright IBM Corp. 2016, 2025
# SPDX-License-Identifier: MPL-2.0
version: v1
+1 -1
View File
@@ -1,4 +1,4 @@
# Copyright (c) HashiCorp, Inc.
# Copyright IBM Corp. 2016, 2025
# SPDX-License-Identifier: MPL-2.0
version: v1
+6 -4
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
@@ -669,7 +669,7 @@ func (c *Client) Start() (addr net.Addr, err error) {
// Setup a temporary certificate for client/server mtls, and send the public
// certificate to the plugin.
if c.config.AutoMTLS {
c.logger.Info("configuring client automatic mTLS")
c.logger.Debug("configuring client automatic mTLS")
certPEM, keyPEM, err := generateCert()
if err != nil {
c.logger.Error("failed to generate client certificate", "error", err)
@@ -753,9 +753,12 @@ func (c *Client) Start() (addr net.Addr, err error) {
// Create a context for when we kill
c.doneCtx, c.ctxCancel = context.WithCancel(context.Background())
// Add two to pipesWaitGroup: one for logStderr, one for the goroutine
// below that consumes Stdout. We mustn't continue to Add once we might Wait.
c.pipesWaitGroup.Add(2)
// Start goroutine that logs the stderr
c.clientWaitGroup.Add(1)
c.pipesWaitGroup.Add(1)
// logStderr calls c.pipesWaitGroup.Done()
go c.logStderr(runner.Name(), runner.Stderr())
@@ -791,7 +794,6 @@ func (c *Client) Start() (addr net.Addr, err error) {
// out of stdout
linesCh := make(chan string)
c.clientWaitGroup.Add(1)
c.pipesWaitGroup.Add(1)
go func() {
defer c.clientWaitGroup.Done()
defer c.pipesWaitGroup.Done()
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package cmdrunner
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package cmdrunner
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package cmdrunner
+1 -2
View File
@@ -1,8 +1,7 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
//go:build !windows
// +build !windows
package cmdrunner
+1 -2
View File
@@ -1,8 +1,7 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
//go:build windows
// +build windows
package cmdrunner
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package cmdrunner
+6 -2
View File
@@ -1,8 +1,7 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
//go:build !windows
// +build !windows
package cmdrunner
@@ -16,6 +15,11 @@ import (
func _pidAlive(pid int) bool {
proc, err := os.FindProcess(pid)
if err == nil {
// On Linux with Go 1.23+, FindProcess opens a pidfd which must be
// released or it leaks an FD on every call. Release errors are
// intentionally ignored; the handle is short-lived and there's
// nothing actionable to recover from a release failure.
defer func() { _ = proc.Release() }()
err = proc.Signal(syscall.Signal(0))
}
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package cmdrunner
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package grpcmux
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package grpcmux
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package grpcmux
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package grpcmux
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package grpcmux
+2 -2
View File
@@ -1,9 +1,9 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
syntax = "proto3";
package plugin;
option go_package = "./plugin";
option go_package = "github.com/hashicorp/go-plugin/internal/plugin";
message ConnInfo {
uint32 service_id = 1;
@@ -1,9 +1,9 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
syntax = "proto3";
package plugin;
option go_package = "./plugin";
option go_package = "github.com/hashicorp/go-plugin/internal/plugin";
message Empty {
}
+2 -2
View File
@@ -1,9 +1,9 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
syntax = "proto3";
package plugin;
option go_package = "./plugin";
option go_package = "github.com/hashicorp/go-plugin/internal/plugin";
import "google/protobuf/empty.proto";
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
// The plugin package exposes functions and helpers for communicating to
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package runner
+2 -2
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
@@ -307,7 +307,7 @@ func Serve(opts *ServeConfig) {
// If the client is configured using AutoMTLS, the certificate will be here,
// and we need to generate our own in response.
if tlsConfig == nil && clientCert != "" {
logger.Info("configuring server automatic mTLS")
logger.Debug("configuring server automatic mTLS")
clientCertPool := x509.NewCertPool()
if !clientCertPool.AppendCertsFromPEM([]byte(clientCert)) {
logger.Error("client cert provided but failed to parse", "cert", clientCert)
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+1 -1
View File
@@ -1,4 +1,4 @@
// Copyright (c) HashiCorp, Inc.
// Copyright IBM Corp. 2016, 2025
// SPDX-License-Identifier: MPL-2.0
package plugin
+5
View File
@@ -175,6 +175,11 @@ func (c *Client) appendObjectDo(ctx context.Context, bucketName, objectName stri
ChecksumSHA1: h.Get(ChecksumSHA1.Key()),
ChecksumSHA256: h.Get(ChecksumSHA256.Key()),
ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
ChecksumMD5: h.Get(ChecksumMD5.Key()),
ChecksumSHA512: h.Get(ChecksumSHA512.Key()),
ChecksumXXHash64: h.Get(ChecksumXXHash64.Key()),
ChecksumXXHash3: h.Get(ChecksumXXHash3.Key()),
ChecksumXXHash128: h.Get(ChecksumXXHash128.Key()),
ChecksumMode: h.Get(ChecksumFullObjectMode.Key()),
}, nil
}
+17 -5
View File
@@ -150,6 +150,11 @@ type UploadInfo struct {
ChecksumSHA1 string
ChecksumSHA256 string
ChecksumCRC64NVME string
ChecksumMD5 string
ChecksumSHA512 string
ChecksumXXHash64 string
ChecksumXXHash3 string
ChecksumXXHash128 string
ChecksumMode string
}
@@ -168,11 +173,12 @@ type ObjectInfo struct {
// each parts concatenated into one string.
ETag string `json:"etag"`
Key string `json:"name"` // Name of the object
LastModified time.Time `json:"lastModified"` // Date and time the object was last modified.
Size int64 `json:"size"` // Size in bytes of the object.
ContentType string `json:"contentType"` // A standard MIME type describing the format of the object data.
Expires time.Time `json:"expires"` // The date and time at which the object is no longer able to be cached.
Key string `json:"name"` // Name of the object
LastModified time.Time `json:"lastModified"` // Date and time the object was last modified.
Size int64 `json:"size"` // Size in bytes of the object.
ContentType string `json:"contentType"` // A standard MIME type describing the format of the object data.
ContentEncoding string `json:"contentEncoding"` // A standard MIME type describing encoding of the object data.
Expires time.Time `json:"expires"` // The date and time at which the object is no longer able to be cached.
// Collection of additional metadata on the object.
// eg: x-amz-meta-*, content-encoding etc.
@@ -226,6 +232,12 @@ type ObjectInfo struct {
ChecksumSHA1 string
ChecksumSHA256 string
ChecksumCRC64NVME string
ChecksumMD5 string
ChecksumSHA512 string
ChecksumXXHash64 string
ChecksumXXHash3 string
ChecksumXXHash128 string
ChecksumAlgorithm string
ChecksumMode string `xml:"ChecksumType"`
Internal *struct {
+96 -10
View File
@@ -23,6 +23,7 @@ import (
"net/http"
"net/url"
"strconv"
"strings"
"time"
"github.com/minio/minio-go/v7/pkg/encrypt"
@@ -88,10 +89,17 @@ type ObjectAttributesResponse struct {
StorageClass string
ObjectSize int
Checksum struct {
ChecksumCRC32 string `xml:",omitempty"`
ChecksumCRC32C string `xml:",omitempty"`
ChecksumSHA1 string `xml:",omitempty"`
ChecksumSHA256 string `xml:",omitempty"`
ChecksumCRC32 string `xml:",omitempty"`
ChecksumCRC32C string `xml:",omitempty"`
ChecksumCRC64NVME string `xml:",omitempty"`
ChecksumSHA1 string `xml:",omitempty"`
ChecksumSHA256 string `xml:",omitempty"`
ChecksumMD5 string `xml:",omitempty"`
ChecksumSHA512 string `xml:",omitempty"`
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
ChecksumType string `xml:",omitempty"`
}
ObjectParts struct {
PartsCount int
@@ -105,12 +113,90 @@ type ObjectAttributesResponse struct {
// ObjectAttributePart is used by ObjectAttributesResponse to describe an object part
type ObjectAttributePart struct {
ChecksumCRC32 string `xml:",omitempty"`
ChecksumCRC32C string `xml:",omitempty"`
ChecksumSHA1 string `xml:",omitempty"`
ChecksumSHA256 string `xml:",omitempty"`
PartNumber int
Size int
ChecksumCRC32 string `xml:",omitempty"`
ChecksumCRC32C string `xml:",omitempty"`
ChecksumCRC64NVME string `xml:",omitempty"`
ChecksumSHA1 string `xml:",omitempty"`
ChecksumSHA256 string `xml:",omitempty"`
ChecksumMD5 string `xml:",omitempty"`
ChecksumSHA512 string `xml:",omitempty"`
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
PartNumber int
Size int
}
// ChecksumMap returns a map of checksums for the object.
func (o *ObjectAttributesResponse) ChecksumMap() map[string]string {
res := make(map[string]string)
setif := func(typ ChecksumType, value string) {
if value != "" {
res[typ.Key()] = value
}
}
setif(ChecksumCRC32C, o.Checksum.ChecksumCRC32C)
setif(ChecksumCRC32, o.Checksum.ChecksumCRC32)
setif(ChecksumCRC64NVME, o.Checksum.ChecksumCRC64NVME)
setif(ChecksumSHA1, o.Checksum.ChecksumSHA1)
setif(ChecksumSHA256, o.Checksum.ChecksumSHA256)
setif(ChecksumMD5, o.Checksum.ChecksumMD5)
setif(ChecksumSHA512, o.Checksum.ChecksumSHA512)
setif(ChecksumXXHash64, o.Checksum.ChecksumXXHash64)
setif(ChecksumXXHash3, o.Checksum.ChecksumXXHash3)
setif(ChecksumXXHash128, o.Checksum.ChecksumXXHash128)
return res
}
// ChecksumMode returns the checksum mode of the object.
// If unable to determine, returns ChecksumUnknownMode.
func (o *ObjectAttributesResponse) ChecksumMode() ChecksumMode {
t := o.ChecksumType()
if !t.IsSet() {
return ChecksumUnknownMode
}
switch o.Checksum.ChecksumType {
case amzChecksumModeComposite:
return ChecksumCompositeMode
case amzChecksumModeFullObject:
return ChecksumFullObjectMode
case "":
// Likely not supported by the server.
if o.Checksum.ChecksumCRC64NVME != "" || !strings.ContainsRune(o.ETag, '-') {
// Always full object.
return ChecksumFullObjectMode
}
if !t.CanMergeCRC() {
// Only composite possible.
return ChecksumCompositeMode
}
}
return ChecksumUnknownMode
}
// ChecksumType returns the checksum type of the object.
// If none is set, returns ChecksumNone.
func (o *ObjectAttributesResponse) ChecksumType() ChecksumType {
t := ChecksumNone
setif := func(typ ChecksumType, value string) {
if value != "" {
t = typ
}
}
setif(ChecksumCRC32C, o.Checksum.ChecksumCRC32C)
setif(ChecksumCRC32, o.Checksum.ChecksumCRC32)
setif(ChecksumCRC64NVME, o.Checksum.ChecksumCRC64NVME)
setif(ChecksumSHA1, o.Checksum.ChecksumSHA1)
setif(ChecksumSHA256, o.Checksum.ChecksumSHA256)
setif(ChecksumMD5, o.Checksum.ChecksumMD5)
setif(ChecksumSHA512, o.Checksum.ChecksumSHA512)
setif(ChecksumXXHash64, o.Checksum.ChecksumXXHash64)
setif(ChecksumXXHash3, o.Checksum.ChecksumXXHash3)
setif(ChecksumXXHash128, o.Checksum.ChecksumXXHash128)
if t.IsSet() && o.Checksum.ChecksumType == amzChecksumModeFullObject {
t |= ChecksumFullObject
}
return t
}
func (o *ObjectAttributes) parseResponse(resp *http.Response) (err error) {
+7 -1
View File
@@ -404,7 +404,7 @@ func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts
}
var (
keyMarker = ""
keyMarker = opts.StartAfter
versionIDMarker = ""
preName = ""
preKey = ""
@@ -432,12 +432,18 @@ func (c *Client) listObjectVersions(ctx context.Context, bucketName string, opts
UserMetadata: version.UserMetadata,
Internal: version.Internal,
NumVersions: numVersions,
ChecksumAlgorithm: version.ChecksumAlgorithm,
ChecksumMode: version.ChecksumType,
ChecksumCRC32: version.ChecksumCRC32,
ChecksumCRC32C: version.ChecksumCRC32C,
ChecksumSHA1: version.ChecksumSHA1,
ChecksumSHA256: version.ChecksumSHA256,
ChecksumCRC64NVME: version.ChecksumCRC64NVME,
ChecksumMD5: version.ChecksumMD5,
ChecksumSHA512: version.ChecksumSHA512,
ChecksumXXHash64: version.ChecksumXXHash64,
ChecksumXXHash3: version.ChecksumXXHash3,
ChecksumXXHash128: version.ChecksumXXHash128,
}
if !yield(info) {
return false
+15
View File
@@ -192,6 +192,11 @@ func (c *Client) putObjectMultipartNoStream(ctx context.Context, bucketName, obj
ChecksumSHA1: part.ChecksumSHA1,
ChecksumSHA256: part.ChecksumSHA256,
ChecksumCRC64NVME: part.ChecksumCRC64NVME,
ChecksumMD5: part.ChecksumMD5,
ChecksumSHA512: part.ChecksumSHA512,
ChecksumXXHash64: part.ChecksumXXHash64,
ChecksumXXHash3: part.ChecksumXXHash3,
ChecksumXXHash128: part.ChecksumXXHash128,
})
}
@@ -353,6 +358,11 @@ func (c *Client) uploadPart(ctx context.Context, p uploadPartParams) (ObjectPart
ChecksumSHA1: h.Get(ChecksumSHA1.Key()),
ChecksumSHA256: h.Get(ChecksumSHA256.Key()),
ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
ChecksumMD5: h.Get(ChecksumMD5.Key()),
ChecksumSHA512: h.Get(ChecksumSHA512.Key()),
ChecksumXXHash64: h.Get(ChecksumXXHash64.Key()),
ChecksumXXHash3: h.Get(ChecksumXXHash3.Key()),
ChecksumXXHash128: h.Get(ChecksumXXHash128.Key()),
}
objPart.Size = p.size
objPart.PartNumber = p.partNumber
@@ -458,6 +468,11 @@ func (c *Client) completeMultipartUpload(ctx context.Context, bucketName, object
ChecksumCRC32: completeMultipartUploadResult.ChecksumCRC32,
ChecksumCRC32C: completeMultipartUploadResult.ChecksumCRC32C,
ChecksumCRC64NVME: completeMultipartUploadResult.ChecksumCRC64NVME,
ChecksumMD5: completeMultipartUploadResult.ChecksumMD5,
ChecksumSHA512: completeMultipartUploadResult.ChecksumSHA512,
ChecksumXXHash64: completeMultipartUploadResult.ChecksumXXHash64,
ChecksumXXHash3: completeMultipartUploadResult.ChecksumXXHash3,
ChecksumXXHash128: completeMultipartUploadResult.ChecksumXXHash128,
ChecksumMode: completeMultipartUploadResult.ChecksumType,
}, nil
}
+20
View File
@@ -259,6 +259,11 @@ func (c *Client) putObjectMultipartStreamFromReadAt(ctx context.Context, bucketN
ChecksumSHA1: uploadRes.Part.ChecksumSHA1,
ChecksumSHA256: uploadRes.Part.ChecksumSHA256,
ChecksumCRC64NVME: uploadRes.Part.ChecksumCRC64NVME,
ChecksumMD5: uploadRes.Part.ChecksumMD5,
ChecksumSHA512: uploadRes.Part.ChecksumSHA512,
ChecksumXXHash64: uploadRes.Part.ChecksumXXHash64,
ChecksumXXHash3: uploadRes.Part.ChecksumXXHash3,
ChecksumXXHash128: uploadRes.Part.ChecksumXXHash128,
})
}
}
@@ -418,6 +423,11 @@ func (c *Client) putObjectMultipartStreamOptionalChecksum(ctx context.Context, b
ChecksumSHA1: part.ChecksumSHA1,
ChecksumSHA256: part.ChecksumSHA256,
ChecksumCRC64NVME: part.ChecksumCRC64NVME,
ChecksumMD5: part.ChecksumMD5,
ChecksumSHA512: part.ChecksumSHA512,
ChecksumXXHash64: part.ChecksumXXHash64,
ChecksumXXHash3: part.ChecksumXXHash3,
ChecksumXXHash128: part.ChecksumXXHash128,
})
}
@@ -617,6 +627,11 @@ func (c *Client) putObjectMultipartStreamParallel(ctx context.Context, bucketNam
ChecksumSHA1: part.ChecksumSHA1,
ChecksumSHA256: part.ChecksumSHA256,
ChecksumCRC64NVME: part.ChecksumCRC64NVME,
ChecksumMD5: part.ChecksumMD5,
ChecksumSHA512: part.ChecksumSHA512,
ChecksumXXHash64: part.ChecksumXXHash64,
ChecksumXXHash3: part.ChecksumXXHash3,
ChecksumXXHash128: part.ChecksumXXHash128,
})
}
@@ -796,6 +811,11 @@ func (c *Client) putObjectDo(ctx context.Context, bucketName, objectName string,
ChecksumSHA1: h.Get(ChecksumSHA1.Key()),
ChecksumSHA256: h.Get(ChecksumSHA256.Key()),
ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
ChecksumMD5: h.Get(ChecksumMD5.Key()),
ChecksumSHA512: h.Get(ChecksumSHA512.Key()),
ChecksumXXHash64: h.Get(ChecksumXXHash64.Key()),
ChecksumXXHash3: h.Get(ChecksumXXHash3.Key()),
ChecksumXXHash128: h.Get(ChecksumXXHash128.Key()),
ChecksumMode: h.Get(ChecksumFullObjectMode.Key()),
}, nil
}
+5
View File
@@ -502,6 +502,11 @@ func (c *Client) putObjectMultipartStreamNoLength(ctx context.Context, bucketNam
ChecksumSHA1: part.ChecksumSHA1,
ChecksumSHA256: part.ChecksumSHA256,
ChecksumCRC64NVME: part.ChecksumCRC64NVME,
ChecksumMD5: part.ChecksumMD5,
ChecksumSHA512: part.ChecksumSHA512,
ChecksumXXHash64: part.ChecksumXXHash64,
ChecksumXXHash3: part.ChecksumXXHash3,
ChecksumXXHash128: part.ChecksumXXHash128,
})
}
+41
View File
@@ -113,6 +113,12 @@ type Version struct {
ChecksumSHA1 string `xml:",omitempty"`
ChecksumSHA256 string `xml:",omitempty"`
ChecksumCRC64NVME string `xml:",omitempty"`
ChecksumMD5 string `xml:",omitempty"`
ChecksumSHA512 string `xml:",omitempty"`
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
ChecksumAlgorithm string `xml:",omitempty"`
ChecksumType string `xml:",omitempty"`
isDeleteMarker bool
@@ -297,6 +303,11 @@ type ObjectPart struct {
ChecksumSHA1 string
ChecksumSHA256 string
ChecksumCRC64NVME string
ChecksumMD5 string
ChecksumSHA512 string
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
}
// Checksum will return the checksum for the given type.
@@ -313,6 +324,16 @@ func (c ObjectPart) Checksum(t ChecksumType) string {
return c.ChecksumSHA256
case t.Is(ChecksumCRC64NVME):
return c.ChecksumCRC64NVME
case t.Is(ChecksumMD5):
return c.ChecksumMD5
case t.Is(ChecksumSHA512):
return c.ChecksumSHA512
case t.Is(ChecksumXXHash64):
return c.ChecksumXXHash64
case t.Is(ChecksumXXHash3):
return c.ChecksumXXHash3
case t.Is(ChecksumXXHash128):
return c.ChecksumXXHash128
}
return ""
}
@@ -382,6 +403,11 @@ type completeMultipartUploadResult struct {
ChecksumSHA1 string
ChecksumSHA256 string
ChecksumCRC64NVME string
ChecksumMD5 string
ChecksumSHA512 string
ChecksumXXHash64 string `xml:"ChecksumXXHASH64"`
ChecksumXXHash3 string `xml:"ChecksumXXHASH3"`
ChecksumXXHash128 string `xml:"ChecksumXXHASH128"`
ChecksumType string
}
@@ -398,6 +424,11 @@ type CompletePart struct {
ChecksumSHA1 string `xml:"ChecksumSHA1,omitempty"`
ChecksumSHA256 string `xml:"ChecksumSHA256,omitempty"`
ChecksumCRC64NVME string `xml:",omitempty"`
ChecksumMD5 string `xml:",omitempty"`
ChecksumSHA512 string `xml:",omitempty"`
ChecksumXXHash64 string `xml:"ChecksumXXHASH64,omitempty"`
ChecksumXXHash3 string `xml:"ChecksumXXHASH3,omitempty"`
ChecksumXXHash128 string `xml:"ChecksumXXHASH128,omitempty"`
}
// Checksum will return the checksum for the given type.
@@ -414,6 +445,16 @@ func (c CompletePart) Checksum(t ChecksumType) string {
return c.ChecksumSHA256
case t.Is(ChecksumCRC64NVME):
return c.ChecksumCRC64NVME
case t.Is(ChecksumMD5):
return c.ChecksumMD5
case t.Is(ChecksumSHA512):
return c.ChecksumSHA512
case t.Is(ChecksumXXHash64):
return c.ChecksumXXHash64
case t.Is(ChecksumXXHash3):
return c.ChecksumXXHash3
case t.Is(ChecksumXXHash128):
return c.ChecksumXXHash128
}
return ""
}
+17 -9
View File
@@ -52,6 +52,12 @@ type UpdateObjectEncryptionOptions struct {
VersionID string
}
// UpdateObjectEncryptionResult holds the result of an UpdateObjectEncryption call.
type UpdateObjectEncryptionResult struct {
// VersionID is the version ID of the object that was updated, if versioning is enabled.
VersionID string
}
// UpdateObjectEncryption changes the encryption configuration of an existing object in-place.
// The object must already be encrypted with SSE-S3 or SSE-KMS. SSE-C objects are not supported.
// This operation rotates the data encryption key envelope without re-reading/re-writing object data.
@@ -62,19 +68,19 @@ type UpdateObjectEncryptionOptions struct {
// - objectName: Name of the object
// - opts: Options including KMSKeyArn (required), optional BucketKeyEnabled, and optional VersionID
//
// Returns an error if the operation fails.
func (c *Client) UpdateObjectEncryption(ctx context.Context, bucketName, objectName string, opts UpdateObjectEncryptionOptions) error {
// Returns the version ID of the updated object (if versioning is enabled) and an error if the operation fails.
func (c *Client) UpdateObjectEncryption(ctx context.Context, bucketName, objectName string, opts UpdateObjectEncryptionOptions) (UpdateObjectEncryptionResult, error) {
// Input validation.
if err := s3utils.CheckValidBucketName(bucketName); err != nil {
return err
return UpdateObjectEncryptionResult{}, err
}
if err := s3utils.CheckValidObjectName(objectName); err != nil {
return err
return UpdateObjectEncryptionResult{}, err
}
if opts.KMSKeyArn == "" {
return errInvalidArgument("KMSKeyArn is required for UpdateObjectEncryption.")
return UpdateObjectEncryptionResult{}, errInvalidArgument("KMSKeyArn is required for UpdateObjectEncryption.")
}
// Get resources properly escaped and lined up before
@@ -96,7 +102,7 @@ func (c *Client) UpdateObjectEncryption(ctx context.Context, bucketName, objectN
bodyData, err := xml.Marshal(reqBody)
if err != nil {
return err
return UpdateObjectEncryptionResult{}, err
}
reqMetadata := requestMetadata{
@@ -113,10 +119,12 @@ func (c *Client) UpdateObjectEncryption(ctx context.Context, bucketName, objectN
resp, err := c.executeMethod(ctx, http.MethodPut, reqMetadata)
defer closeResponse(resp)
if err != nil {
return err
return UpdateObjectEncryptionResult{}, err
}
if resp.StatusCode != http.StatusOK {
return httpRespToErrorResponse(resp, bucketName, objectName)
return UpdateObjectEncryptionResult{}, httpRespToErrorResponse(resp, bucketName, objectName)
}
return nil
return UpdateObjectEncryptionResult{
VersionID: resp.Header.Get(amzVersionID),
}, nil
}
+13 -1
View File
@@ -198,6 +198,9 @@ func New(endpoint string, opts *Options) (*Client, error) {
// Amazon S3 endpoints are resolved into dual-stack endpoints by default
// for backwards compatibility.
clnt.s3DualstackEnabled = true
} else if s3utils.IsAmazonOutpostsEndpoint(*clnt.endpointURL) {
// S3 on Outposts uses signature v4 with service name s3-outposts.
clnt.overrideSignerType = credentials.SignatureV4
}
return clnt, nil
@@ -912,7 +915,11 @@ func (c *Client) newRequest(ctx context.Context, method string, metadata request
req = signer.PreSignV2(*req, accessKeyID, secretAccessKey, metadata.expires, isVirtualHost)
} else if signerType.IsV4() {
// Presign URL with signature v4.
req = signer.PreSignV4(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.expires)
if s3utils.IsAmazonOutpostsEndpoint(*c.endpointURL) {
req = signer.PreSignV4Outposts(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.expires)
} else {
req = signer.PreSignV4(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.expires)
}
}
return req, nil
}
@@ -971,6 +978,9 @@ func (c *Client) newRequest(ctx context.Context, method string, metadata request
if s3utils.IsAmazonExpressRegionalEndpoint(*c.endpointURL) {
req = signer.StreamingSignV4Express(req, accessKeyID,
secretAccessKey, sessionToken, location, metadata.contentLength, time.Now().UTC(), c.sha256Hasher())
} else if s3utils.IsAmazonOutpostsEndpoint(*c.endpointURL) {
req = signer.StreamingSignV4Outposts(req, accessKeyID,
secretAccessKey, sessionToken, location, metadata.contentLength, time.Now().UTC(), c.sha256Hasher())
} else {
req = signer.StreamingSignV4(req, accessKeyID,
secretAccessKey, sessionToken, location, metadata.contentLength, time.Now().UTC(), c.sha256Hasher())
@@ -991,6 +1001,8 @@ func (c *Client) newRequest(ctx context.Context, method string, metadata request
if s3utils.IsAmazonExpressRegionalEndpoint(*c.endpointURL) {
req = signer.SignV4TrailerExpress(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.trailer)
} else if s3utils.IsAmazonOutpostsEndpoint(*c.endpointURL) {
req = signer.SignV4TrailerOutposts(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.trailer)
} else {
// Add signature version '4' authorization header.
req = signer.SignV4Trailer(*req, accessKeyID, secretAccessKey, sessionToken, location, metadata.trailer)
+6 -1
View File
@@ -209,6 +209,11 @@ func (c *Client) getBucketLocationRequest(ctx context.Context, bucketName string
}
req.Header.Set("X-Amz-Content-Sha256", contentSha256)
req = signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, "us-east-1")
if s3utils.IsAmazonOutpostsEndpoint(*c.endpointURL) {
region := getDefaultLocation(*c.endpointURL, c.region)
req = signer.SignV4Outposts(*req, accessKeyID, secretAccessKey, sessionToken, region)
} else {
req = signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, "us-east-1")
}
return req, nil
}
+67 -4
View File
@@ -18,8 +18,10 @@
package minio
import (
"crypto/md5"
"crypto/sha1"
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"encoding/binary"
"errors"
@@ -30,8 +32,10 @@ import (
"sort"
"strings"
"github.com/cespare/xxhash/v2"
"github.com/klauspost/crc32"
"github.com/minio/crc64nvme"
"github.com/zeebo/xxh3"
)
// ChecksumMode contains information about the checksum mode on the object
@@ -49,6 +53,9 @@ const (
// checksumModeMask is a mask for valid checksum mode types.
checksumModeMask = checksumLastMode - 1
// ChecksumUnknownMode indicates no or unknown checksum mode.
ChecksumUnknownMode ChecksumMode = 0
)
// Is returns if c is all of t.
@@ -64,9 +71,9 @@ func (c ChecksumMode) Key() string {
func (c ChecksumMode) String() string {
switch c & checksumModeMask {
case ChecksumFullObjectMode:
return "FULL_OBJECT"
return amzChecksumModeFullObject
case ChecksumCompositeMode:
return "COMPOSITE"
return amzChecksumModeComposite
}
return ""
}
@@ -86,6 +93,16 @@ const (
ChecksumCRC32C
// ChecksumCRC64NVME indicates CRC64 with 0xad93d23594c93659 polynomial.
ChecksumCRC64NVME
// ChecksumMD5 indicates an MD5 checksum.
ChecksumMD5
// ChecksumSHA512 indicates a SHA-512 checksum.
ChecksumSHA512
// ChecksumXXHash64 indicates an XXHash64 checksum.
ChecksumXXHash64
// ChecksumXXHash3 indicates an XXH3-64 checksum.
ChecksumXXHash3
// ChecksumXXHash128 indicates an XXH3-128 checksum.
ChecksumXXHash128
// Keep after all valid checksums
checksumLast
@@ -112,7 +129,15 @@ const (
amzChecksumSHA1 = "x-amz-checksum-sha1"
amzChecksumSHA256 = "x-amz-checksum-sha256"
amzChecksumCRC64NVME = "x-amz-checksum-crc64nvme"
amzChecksumMD5 = "x-amz-checksum-md5"
amzChecksumSHA512 = "x-amz-checksum-sha512"
amzChecksumXXHash64 = "x-amz-checksum-xxhash64"
amzChecksumXXHash3 = "x-amz-checksum-xxhash3"
amzChecksumXXHash128 = "x-amz-checksum-xxhash128"
amzChecksumMode = "x-amz-checksum-type"
amzChecksumModeComposite = "COMPOSITE"
amzChecksumModeFullObject = "FULL_OBJECT"
)
// Base returns the base type, without modifiers.
@@ -139,6 +164,16 @@ func (c ChecksumType) Key() string {
return amzChecksumSHA256
case ChecksumCRC64NVME:
return amzChecksumCRC64NVME
case ChecksumMD5:
return amzChecksumMD5
case ChecksumSHA512:
return amzChecksumSHA512
case ChecksumXXHash64:
return amzChecksumXXHash64
case ChecksumXXHash3:
return amzChecksumXXHash3
case ChecksumXXHash128:
return amzChecksumXXHash128
}
return ""
}
@@ -146,7 +181,8 @@ func (c ChecksumType) Key() string {
// CanComposite will return if the checksum type can be used for composite multipart upload on AWS.
func (c ChecksumType) CanComposite() bool {
switch c & checksumMask {
case ChecksumSHA256, ChecksumSHA1, ChecksumCRC32, ChecksumCRC32C:
case ChecksumSHA256, ChecksumSHA1, ChecksumCRC32, ChecksumCRC32C,
ChecksumMD5, ChecksumSHA512, ChecksumXXHash64, ChecksumXXHash3, ChecksumXXHash128:
return true
}
return false
@@ -186,6 +222,14 @@ func (c ChecksumType) RawByteLen() int {
return sha256.Size
case ChecksumCRC64NVME:
return crc64nvme.Size
case ChecksumXXHash64, ChecksumXXHash3:
return 8
case ChecksumMD5:
return md5.Size
case ChecksumSHA512:
return sha512.Size
case ChecksumXXHash128:
return 16
}
return 0
}
@@ -206,6 +250,16 @@ func (c ChecksumType) Hasher() hash.Hash {
return sha256.New()
case ChecksumCRC64NVME:
return crc64nvme.New()
case ChecksumMD5:
return md5.New()
case ChecksumSHA512:
return sha512.New()
case ChecksumXXHash64:
return xxhash.New()
case ChecksumXXHash3:
return xxh3.New()
case ChecksumXXHash128:
return xxh3.New128()
}
return nil
}
@@ -233,7 +287,6 @@ func (c ChecksumType) EncodeToString(b []byte) string {
}
// String returns the type as a string.
// CRC32, CRC32C, SHA1, and SHA256 for valid values.
// Empty string for unset and "<invalid>" if not valid.
func (c ChecksumType) String() string {
switch c & checksumMask {
@@ -249,6 +302,16 @@ func (c ChecksumType) String() string {
return ""
case ChecksumCRC64NVME:
return "CRC64NVME"
case ChecksumMD5:
return "MD5"
case ChecksumSHA512:
return "SHA512"
case ChecksumXXHash64:
return "XXHASH64"
case ChecksumXXHash3:
return "XXHASH3"
case ChecksumXXHash128:
return "XXHASH128"
}
return "<invalid>"
}
+4 -4
View File
@@ -94,15 +94,15 @@ var awsS3EndpointMap = map[string]awsS3Endpoint{
},
"us-iso-east-1": {
"s3.us-iso-east-1.c2s.ic.gov",
"s3.dualstack.us-iso-east-1.c2s.ic.gov",
"", // dualstack endpoint doesn't exist
},
"us-isob-east-1": {
"s3.us-isob-east-1.sc2s.sgov.gov",
"s3.dualstack.us-isob-east-1.sc2s.sgov.gov",
"", // dualstack endpoint doesn't exist
},
"us-iso-west-1": {
"s3.us-iso-west-1.c2s.ic.gov",
"s3.dualstack.us-iso-west-1.c2s.ic.gov",
"", // dualstack endpoint doesn't exist
},
"us-west-2": {
"s3.us-west-2.amazonaws.com",
@@ -269,7 +269,7 @@ func getS3Endpoint(bucketLocation string, useDualstack bool) (endpoint string) {
}
return "s3.us-east-1.amazonaws.com"
}
if useDualstack {
if useDualstack && s3Endpoint.dualstackEndpoint != "" {
return s3Endpoint.dualstackEndpoint
}
return s3Endpoint.endpoint
+160 -4
View File
@@ -73,8 +73,25 @@ const (
enableKMS = "ENABLE_KMS"
appVersion = "0.1.0"
skipCERTValidation = "SKIP_CERT_VALIDATION"
// TODO: remove when server supports the 2026 checksum types.
ignore2026Checksums = true
)
func ignore2026ChecksumError(cs minio.ChecksumType, err error) bool {
if !ignore2026Checksums {
return false
}
switch cs.Base() {
case minio.ChecksumMD5, minio.ChecksumSHA512,
minio.ChecksumXXHash64, minio.ChecksumXXHash3, minio.ChecksumXXHash128:
default:
return false
}
var er minio.ErrorResponse
return errors.As(err, &er) && er.Code == "InvalidArgument"
}
func createHTTPTransport() (transport *http.Transport) {
var err error
transport, err = minio.DefaultTransport(mustParseBool(os.Getenv(enableHTTPS)))
@@ -2096,6 +2113,11 @@ func testPutObjectWithChecksums() {
tests := []struct {
cs minio.ChecksumType
}{
{cs: minio.ChecksumMD5},
{cs: minio.ChecksumSHA512},
{cs: minio.ChecksumXXHash64},
{cs: minio.ChecksumXXHash3},
{cs: minio.ChecksumXXHash128},
{cs: minio.ChecksumCRC32C},
{cs: minio.ChecksumCRC32},
{cs: minio.ChecksumSHA1},
@@ -2160,6 +2182,10 @@ func testPutObjectWithChecksums() {
UserMetadata: meta,
})
if err != nil {
if ignore2026ChecksumError(test.cs, err) {
logIgnored(testName, function, args, startTime, "server does not support "+test.cs.String())
continue
}
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
@@ -2168,6 +2194,11 @@ func testPutObjectWithChecksums() {
cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
cmpChecksum(resp.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
cmpChecksum(resp.ChecksumMD5, meta["x-amz-checksum-md5"])
cmpChecksum(resp.ChecksumSHA512, meta["x-amz-checksum-sha512"])
cmpChecksum(resp.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
cmpChecksum(resp.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
cmpChecksum(resp.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
if resp.ChecksumMode != minio.ChecksumFullObjectMode.String() {
logError(testName, function, args, startTime, "", "Checksum mode is not full object", fmt.Errorf("got %s, want %s", resp.ChecksumMode, minio.ChecksumFullObjectMode.String()))
}
@@ -2191,6 +2222,11 @@ func testPutObjectWithChecksums() {
cmpChecksum(st.ChecksumCRC32, meta["x-amz-checksum-crc32"])
cmpChecksum(st.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
cmpChecksum(st.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
cmpChecksum(st.ChecksumMD5, meta["x-amz-checksum-md5"])
cmpChecksum(st.ChecksumSHA512, meta["x-amz-checksum-sha512"])
cmpChecksum(st.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
cmpChecksum(st.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
cmpChecksum(st.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
if st.ChecksumMode != minio.ChecksumFullObjectMode.String() {
logError(testName, function, args, startTime, "", "Checksum mode is not full object", fmt.Errorf("got %s, want %s", st.ChecksumMode, minio.ChecksumFullObjectMode.String()))
}
@@ -2238,6 +2274,11 @@ func testPutObjectWithChecksums() {
cmpChecksum(st.ChecksumCRC32, "")
cmpChecksum(st.ChecksumCRC32C, "")
cmpChecksum(st.ChecksumCRC64NVME, "")
cmpChecksum(st.ChecksumMD5, "")
cmpChecksum(st.ChecksumSHA512, "")
cmpChecksum(st.ChecksumXXHash64, "")
cmpChecksum(st.ChecksumXXHash3, "")
cmpChecksum(st.ChecksumXXHash128, "")
delete(args, "range")
delete(args, "metadata")
@@ -2283,6 +2324,11 @@ func testPutObjectWithTrailingChecksums() {
tests := []struct {
cs minio.ChecksumType
}{
{cs: minio.ChecksumMD5},
{cs: minio.ChecksumSHA512},
{cs: minio.ChecksumXXHash64},
{cs: minio.ChecksumXXHash3},
{cs: minio.ChecksumXXHash128},
{cs: minio.ChecksumCRC64NVME},
{cs: minio.ChecksumCRC32C},
{cs: minio.ChecksumCRC32},
@@ -2329,6 +2375,10 @@ func testPutObjectWithTrailingChecksums() {
Checksum: test.cs,
})
if err != nil {
if ignore2026ChecksumError(test.cs, err) {
logIgnored(testName, function, args, startTime, "server does not support "+test.cs.String())
continue
}
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
@@ -2341,6 +2391,11 @@ func testPutObjectWithTrailingChecksums() {
cmpChecksum(resp.ChecksumCRC32, meta["x-amz-checksum-crc32"])
cmpChecksum(resp.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
cmpChecksum(resp.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
cmpChecksum(resp.ChecksumMD5, meta["x-amz-checksum-md5"])
cmpChecksum(resp.ChecksumSHA512, meta["x-amz-checksum-sha512"])
cmpChecksum(resp.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
cmpChecksum(resp.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
cmpChecksum(resp.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
// Read the data back
gopts := minio.GetObjectOptions{Checksum: true}
@@ -2361,7 +2416,12 @@ func testPutObjectWithTrailingChecksums() {
cmpChecksum(st.ChecksumSHA1, meta["x-amz-checksum-sha1"])
cmpChecksum(st.ChecksumCRC32, meta["x-amz-checksum-crc32"])
cmpChecksum(st.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
cmpChecksum(resp.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
cmpChecksum(st.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
cmpChecksum(st.ChecksumMD5, meta["x-amz-checksum-md5"])
cmpChecksum(st.ChecksumSHA512, meta["x-amz-checksum-sha512"])
cmpChecksum(st.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
cmpChecksum(st.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
cmpChecksum(st.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
if st.Size != int64(bufSize) {
logError(testName, function, args, startTime, "", "Number of bytes returned by PutObject does not match GetObject, expected "+string(bufSize)+" got "+string(st.Size), err)
@@ -2407,6 +2467,11 @@ func testPutObjectWithTrailingChecksums() {
cmpChecksum(st.ChecksumCRC32, "")
cmpChecksum(st.ChecksumCRC32C, "")
cmpChecksum(st.ChecksumCRC64NVME, "")
cmpChecksum(st.ChecksumMD5, "")
cmpChecksum(st.ChecksumSHA512, "")
cmpChecksum(st.ChecksumXXHash64, "")
cmpChecksum(st.ChecksumXXHash3, "")
cmpChecksum(st.ChecksumXXHash128, "")
function = "GetObjectAttributes(...)"
s, err := c.GetObjectAttributes(context.Background(), bucketName, objectName, minio.ObjectAttributesOptions{})
@@ -2418,6 +2483,16 @@ func testPutObjectWithTrailingChecksums() {
cmpChecksum(s.Checksum.ChecksumSHA1, meta["x-amz-checksum-sha1"])
cmpChecksum(s.Checksum.ChecksumCRC32, meta["x-amz-checksum-crc32"])
cmpChecksum(s.Checksum.ChecksumCRC32C, meta["x-amz-checksum-crc32c"])
cmpChecksum(s.Checksum.ChecksumCRC64NVME, meta["x-amz-checksum-crc64nvme"])
cmpChecksum(s.Checksum.ChecksumMD5, meta["x-amz-checksum-md5"])
cmpChecksum(s.Checksum.ChecksumSHA512, meta["x-amz-checksum-sha512"])
cmpChecksum(s.Checksum.ChecksumXXHash64, meta["x-amz-checksum-xxhash64"])
cmpChecksum(s.Checksum.ChecksumXXHash3, meta["x-amz-checksum-xxhash3"])
cmpChecksum(s.Checksum.ChecksumXXHash128, meta["x-amz-checksum-xxhash128"])
if s.Checksum.ChecksumType != "" && s.Checksum.ChecksumType != minio.ChecksumFullObjectMode.String() {
logError(testName, function, args, startTime, "", "ChecksumType mismatch in GetObjectAttributes", fmt.Errorf("want %s, got %s", minio.ChecksumFullObjectMode.String(), s.Checksum.ChecksumType))
return
}
delete(args, "range")
delete(args, "metadata")
@@ -2495,6 +2570,11 @@ func testPutMultipartObjectWithChecksums() {
tests := []struct {
cs minio.ChecksumType
}{
{cs: minio.ChecksumMD5},
{cs: minio.ChecksumSHA512},
{cs: minio.ChecksumXXHash64},
{cs: minio.ChecksumXXHash3},
{cs: minio.ChecksumXXHash128},
{cs: minio.ChecksumFullObjectCRC32},
{cs: minio.ChecksumFullObjectCRC32C},
{cs: minio.ChecksumCRC64NVME},
@@ -2552,6 +2632,10 @@ func testPutMultipartObjectWithChecksums() {
Checksum: cs,
})
if err != nil {
if ignore2026ChecksumError(test.cs, err) {
logIgnored(testName, function, args, startTime, "server does not support "+test.cs.String())
continue
}
logError(testName, function, args, startTime, "", "PutObject failed", err)
return
}
@@ -2567,6 +2651,16 @@ func testPutMultipartObjectWithChecksums() {
cmpChecksum(resp.ChecksumSHA256, wantChksm)
case minio.ChecksumCRC64NVME:
cmpChecksum(resp.ChecksumCRC64NVME, wantChksm)
case minio.ChecksumMD5:
cmpChecksum(resp.ChecksumMD5, wantChksm)
case minio.ChecksumSHA512:
cmpChecksum(resp.ChecksumSHA512, wantChksm)
case minio.ChecksumXXHash64:
cmpChecksum(resp.ChecksumXXHash64, wantChksm)
case minio.ChecksumXXHash3:
cmpChecksum(resp.ChecksumXXHash3, wantChksm)
case minio.ChecksumXXHash128:
cmpChecksum(resp.ChecksumXXHash128, wantChksm)
}
args["section"] = "HeadObject"
@@ -2586,6 +2680,16 @@ func testPutMultipartObjectWithChecksums() {
cmpChecksum(st.ChecksumSHA256, wantChksm)
case minio.ChecksumCRC64NVME:
cmpChecksum(st.ChecksumCRC64NVME, wantChksm)
case minio.ChecksumMD5:
cmpChecksum(st.ChecksumMD5, wantChksm)
case minio.ChecksumSHA512:
cmpChecksum(st.ChecksumSHA512, wantChksm)
case minio.ChecksumXXHash64:
cmpChecksum(st.ChecksumXXHash64, wantChksm)
case minio.ChecksumXXHash3:
cmpChecksum(st.ChecksumXXHash3, wantChksm)
case minio.ChecksumXXHash128:
cmpChecksum(st.ChecksumXXHash128, wantChksm)
}
// Use the CopyObject API to make a copy, in the case it was a composite checksum,
@@ -2622,6 +2726,16 @@ func testPutMultipartObjectWithChecksums() {
cmpChecksum(st.ChecksumSHA256, wantFullObjectChksm)
case minio.ChecksumCRC64NVME:
cmpChecksum(st.ChecksumCRC64NVME, wantFullObjectChksm)
case minio.ChecksumMD5:
cmpChecksum(st.ChecksumMD5, wantFullObjectChksm)
case minio.ChecksumSHA512:
cmpChecksum(st.ChecksumSHA512, wantFullObjectChksm)
case minio.ChecksumXXHash64:
cmpChecksum(st.ChecksumXXHash64, wantFullObjectChksm)
case minio.ChecksumXXHash3:
cmpChecksum(st.ChecksumXXHash3, wantFullObjectChksm)
case minio.ChecksumXXHash128:
cmpChecksum(st.ChecksumXXHash128, wantFullObjectChksm)
}
args["section"] = "GetObjectAttributes"
@@ -2644,6 +2758,35 @@ func testPutMultipartObjectWithChecksums() {
cmpChecksum(s.Checksum.ChecksumSHA1, wantChksm)
case minio.ChecksumSHA256:
cmpChecksum(s.Checksum.ChecksumSHA256, wantChksm)
case minio.ChecksumCRC64NVME:
cmpChecksum(s.Checksum.ChecksumCRC64NVME, wantChksm)
case minio.ChecksumMD5:
cmpChecksum(s.Checksum.ChecksumMD5, wantChksm)
case minio.ChecksumSHA512:
cmpChecksum(s.Checksum.ChecksumSHA512, wantChksm)
case minio.ChecksumXXHash64:
cmpChecksum(s.Checksum.ChecksumXXHash64, wantChksm)
case minio.ChecksumXXHash3:
cmpChecksum(s.Checksum.ChecksumXXHash3, wantChksm)
case minio.ChecksumXXHash128:
cmpChecksum(s.Checksum.ChecksumXXHash128, wantChksm)
}
if s.Checksum.ChecksumType != "" {
var wantType string
if test.cs.FullObjectRequested() {
wantType = minio.ChecksumFullObjectMode.String()
} else {
wantType = minio.ChecksumCompositeMode.String()
}
cmpChecksum(s.Checksum.ChecksumType, wantType)
}
for _, part := range s.ObjectParts.Parts {
if test.cs == minio.ChecksumCRC64NVME && part.ChecksumCRC64NVME == "" {
logError(testName, function, args, startTime, "", "Part missing CRC64NVME checksum in GetObjectAttributes", fmt.Errorf("part %d", part.PartNumber))
return
}
}
// Read the data back
@@ -2684,6 +2827,16 @@ func testPutMultipartObjectWithChecksums() {
if st.ChecksumCRC64NVME != "" {
cmpChecksum(st.ChecksumCRC64NVME, wantChksm)
}
case minio.ChecksumMD5:
cmpChecksum(st.ChecksumMD5, wantChksm)
case minio.ChecksumSHA512:
cmpChecksum(st.ChecksumSHA512, wantChksm)
case minio.ChecksumXXHash64:
cmpChecksum(st.ChecksumXXHash64, wantChksm)
case minio.ChecksumXXHash3:
cmpChecksum(st.ChecksumXXHash3, wantChksm)
case minio.ChecksumXXHash128:
cmpChecksum(st.ChecksumXXHash128, wantChksm)
}
delete(args, "metadata")
@@ -3475,6 +3628,8 @@ func validateObjectAttributeRequest(OA *minio.ObjectAttributes, opts *minio.Obje
checksumFound = true
} else if v.ChecksumCRC32C != "" {
checksumFound = true
} else if v.ChecksumCRC64NVME != "" {
checksumFound = true
}
if !checksumFound {
partsMissingChecksum = true
@@ -3497,6 +3652,7 @@ func validateObjectAttributeRequest(OA *minio.ObjectAttributes, opts *minio.Obje
hasFullObjectChecksum := (OA.Checksum.ChecksumCRC32 != "" ||
OA.Checksum.ChecksumCRC32C != "" ||
OA.Checksum.ChecksumCRC64NVME != "" ||
OA.Checksum.ChecksumSHA1 != "" ||
OA.Checksum.ChecksumSHA256 != "")
@@ -14789,6 +14945,9 @@ func main() {
// execute tests
if isFullMode() {
testPutObjectWithChecksums()
testPutObjectWithTrailingChecksums()
testPutMultipartObjectWithChecksums()
testCopyObjectWithChecksums()
testReplaceObjectWithChecksums()
testCorsSetGetDelete()
@@ -14808,9 +14967,6 @@ func main() {
testComposeObjectErrorCasesV2()
testCompose10KSourcesV2()
testUserMetadataCopyingV2()
testPutObjectWithChecksums()
testPutObjectWithTrailingChecksums()
testPutMultipartObjectWithChecksums()
testPutObject0ByteV2()
testPutObjectMetadataNonUSASCIIV2()
testPutObjectNoLengthV2()
+21
View File
@@ -119,6 +119,10 @@ var elbAmazonCnRegex = regexp.MustCompile(`elb(.*?).amazonaws.com.cn$`)
// amazonS3HostPrivateLink - regular expression used to determine if an arg is s3 host in AWS PrivateLink interface endpoints style
var amazonS3HostPrivateLink = regexp.MustCompile(`^(?:bucket|accesspoint).vpce-.*?.s3.(.*?).vpce.amazonaws.com$`)
// amazonS3HostOutposts - regular expression used to determine if an arg is S3 on Outposts endpoint.
// Pattern: <something>.s3-outposts.<region>.amazonaws.com
var amazonS3HostOutposts = regexp.MustCompile(`^(.+)\.s3-outposts\.([a-z0-9-]+)\.amazonaws\.com$`)
// GetRegionFromURL - returns a region from url host.
func GetRegionFromURL(endpointURL url.URL) string {
if endpointURL == sentinelURL {
@@ -181,6 +185,11 @@ func GetRegionFromURL(endpointURL url.URL) string {
return parts[1]
}
parts = amazonS3HostOutposts.FindStringSubmatch(endpointURL.Hostname())
if len(parts) > 2 {
return parts[2]
}
parts = amazonS3HostDot.FindStringSubmatch(endpointURL.Hostname())
if len(parts) > 1 {
if strings.HasPrefix(parts[1], "xpress-") {
@@ -210,8 +219,20 @@ func IsAmazonExpressZonalEndpoint(endpointURL url.URL) bool {
return amazonS3HostExpress.MatchString(endpointURL.Hostname())
}
// IsAmazonOutpostsEndpoint - Match if the endpoint is S3 on Outposts endpoint.
func IsAmazonOutpostsEndpoint(endpointURL url.URL) bool {
if endpointURL == sentinelURL {
return false
}
return amazonS3HostOutposts.MatchString(endpointURL.Hostname())
}
// IsAmazonEndpoint - Match if it is exactly Amazon S3 endpoint.
// S3 on Outposts is not treated as Amazon S3 here so that the client keeps path-style and does not replace the host.
func IsAmazonEndpoint(endpointURL url.URL) bool {
if IsAmazonOutpostsEndpoint(endpointURL) {
return false
}
if endpointURL.Hostname() == "s3-external-1.amazonaws.com" || endpointURL.Hostname() == "s3.amazonaws.com" {
return true
}
@@ -90,32 +90,34 @@ func getStreamLength(dataLen, chunkSize int64, trailers http.Header) int64 {
return streamLen
}
// buildChunkStringToSign - returns the string to sign given chunk data
// and previous signature.
func buildChunkStringToSign(t time.Time, region, previousSig, chunkChecksum string) string {
// buildChunkStringToSignWithService - like buildChunkStringToSign but with configurable service type.
func buildChunkStringToSignWithService(t time.Time, region, previousSig, chunkChecksum, serviceType string) string {
if serviceType == "" {
serviceType = ServiceTypeS3
}
stringToSignParts := []string{
streamingPayloadHdr,
t.Format(iso8601DateFormat),
getScope(region, t, ServiceTypeS3),
getScope(region, t, serviceType),
previousSig,
emptySHA256,
chunkChecksum,
}
return strings.Join(stringToSignParts, "\n")
}
// buildTrailerChunkStringToSign - returns the string to sign given chunk data
// and previous signature.
func buildTrailerChunkStringToSign(t time.Time, region, previousSig, chunkChecksum string) string {
// buildTrailerChunkStringToSignWithService - like buildTrailerChunkStringToSign but with configurable service type.
func buildTrailerChunkStringToSignWithService(t time.Time, region, previousSig, chunkChecksum, serviceType string) string {
if serviceType == "" {
serviceType = ServiceTypeS3
}
stringToSignParts := []string{
streamingTrailerHdr,
t.Format(iso8601DateFormat),
getScope(region, t, ServiceTypeS3),
getScope(region, t, serviceType),
previousSig,
chunkChecksum,
}
return strings.Join(stringToSignParts, "\n")
}
@@ -150,36 +152,42 @@ func buildChunkHeader(chunkLen int64, signature string) []byte {
}
// buildChunkSignature - returns chunk signature for a given chunk and previous signature.
// serviceType defaults to ServiceTypeS3 when empty.
func buildChunkSignature(chunkCheckSum string, reqTime time.Time, region,
previousSignature, secretAccessKey string,
previousSignature, secretAccessKey, serviceType string,
) string {
chunkStringToSign := buildChunkStringToSign(reqTime, region,
previousSignature, chunkCheckSum)
signingKey := getSigningKey(secretAccessKey, region, reqTime, ServiceTypeS3)
if serviceType == "" {
serviceType = ServiceTypeS3
}
chunkStringToSign := buildChunkStringToSignWithService(reqTime, region,
previousSignature, chunkCheckSum, serviceType)
signingKey := getSigningKey(secretAccessKey, region, reqTime, serviceType)
return getSignature(signingKey, chunkStringToSign)
}
// buildChunkSignature - returns chunk signature for a given chunk and previous signature.
// buildTrailerChunkSignature - returns chunk signature for trailer chunk.
// serviceType defaults to ServiceTypeS3 when empty.
func buildTrailerChunkSignature(chunkChecksum string, reqTime time.Time, region,
previousSignature, secretAccessKey string,
previousSignature, secretAccessKey, serviceType string,
) string {
chunkStringToSign := buildTrailerChunkStringToSign(reqTime, region,
previousSignature, chunkChecksum)
signingKey := getSigningKey(secretAccessKey, region, reqTime, ServiceTypeS3)
if serviceType == "" {
serviceType = ServiceTypeS3
}
chunkStringToSign := buildTrailerChunkStringToSignWithService(reqTime, region,
previousSignature, chunkChecksum, serviceType)
signingKey := getSigningKey(secretAccessKey, region, reqTime, serviceType)
return getSignature(signingKey, chunkStringToSign)
}
// getSeedSignature - returns the seed signature for a given request.
func (s *StreamingReader) setSeedSignature(req *http.Request) {
// Get canonical request
serviceType := s.serviceType
if serviceType == "" {
serviceType = ServiceTypeS3
}
canonicalRequest := getCanonicalRequest(*req, ignoredStreamingHeaders, getHashedPayload(*req))
// Get string to sign from canonical request.
stringToSign := getStringToSignV4(s.reqTime, s.region, canonicalRequest, ServiceTypeS3)
signingKey := getSigningKey(s.secretAccessKey, s.region, s.reqTime, ServiceTypeS3)
// Calculate signature.
stringToSign := getStringToSignV4(s.reqTime, s.region, canonicalRequest, serviceType)
signingKey := getSigningKey(s.secretAccessKey, s.region, s.reqTime, serviceType)
s.seedSignature = getSignature(signingKey, stringToSign)
}
@@ -190,6 +198,7 @@ type StreamingReader struct {
secretAccessKey string
sessionToken string
region string
serviceType string // e.g. ServiceTypeS3, ServiceTypeS3Outposts; empty means S3
prevSignature string
seedSignature string
contentLen int64 // Content-Length from req header
@@ -214,8 +223,12 @@ func (s *StreamingReader) signChunk(chunkLen int, addCrLf bool) {
s.sh256.Write(s.chunkBuf[:chunkLen])
chunckChecksum := hex.EncodeToString(s.sh256.Sum(nil))
serviceType := s.serviceType
if serviceType == "" {
serviceType = ServiceTypeS3
}
signature := buildChunkSignature(chunckChecksum, s.reqTime,
s.region, s.prevSignature, s.secretAccessKey)
s.region, s.prevSignature, s.secretAccessKey, serviceType)
// For next chunk signature computation
s.prevSignature = signature
@@ -249,9 +262,12 @@ func (s *StreamingReader) addSignedTrailer(h http.Header) {
s.sh256.Reset()
s.sh256.Write(s.chunkBuf)
chunkChecksum := hex.EncodeToString(s.sh256.Sum(nil))
// Compute chunk signature
serviceType := s.serviceType
if serviceType == "" {
serviceType = ServiceTypeS3
}
signature := buildTrailerChunkSignature(chunkChecksum, s.reqTime,
s.region, s.prevSignature, s.secretAccessKey)
s.region, s.prevSignature, s.secretAccessKey, serviceType)
// For next chunk signature computation
s.prevSignature = signature
@@ -376,6 +392,40 @@ func StreamingSignV4(req *http.Request, accessKeyID, secretAccessKey, sessionTok
return req
}
// StreamingSignV4Outposts - provides chunked upload signatureV4 support for S3 on Outposts (service name s3-outposts).
func StreamingSignV4Outposts(req *http.Request, accessKeyID, secretAccessKey, sessionToken,
region string, dataLen int64, reqTime time.Time, sh256 md5simd.Hasher,
) *http.Request {
prepareStreamingRequest(req, sessionToken, dataLen, reqTime)
if req.Body == nil {
req.Body = io.NopCloser(bytes.NewReader([]byte("")))
}
stReader := &StreamingReader{
baseReadCloser: req.Body,
accessKeyID: accessKeyID,
secretAccessKey: secretAccessKey,
sessionToken: sessionToken,
region: region,
serviceType: ServiceTypeS3Outposts,
reqTime: reqTime,
chunkBuf: make([]byte, payloadChunkSize),
contentLen: dataLen,
chunkNum: 1,
totalChunks: int((dataLen+payloadChunkSize-1)/payloadChunkSize) + 1,
lastChunkSize: int(dataLen % payloadChunkSize),
sh256: sh256,
}
if len(req.Trailer) > 0 {
stReader.trailer = req.Trailer
req.Trailer = nil
}
stReader.setSeedSignature(req)
stReader.setStreamingAuthHeader(req, ServiceTypeS3Outposts)
stReader.prevSignature = stReader.seedSignature
req.Body = stReader
return req
}
// Read - this method performs chunk upload signature providing a
// io.Reader interface.
func (s *StreamingReader) Read(buf []byte) (int, error) {
+51 -3
View File
@@ -38,9 +38,10 @@ const (
// Different service types
const (
ServiceTypeS3 = "s3"
ServiceTypeSTS = "sts"
ServiceTypeS3Express = "s3express"
ServiceTypeS3 = "s3"
ServiceTypeSTS = "sts"
ServiceTypeS3Express = "s3express"
ServiceTypeS3Outposts = "s3-outposts"
)
// Excerpts from @lsegal -
@@ -256,6 +257,38 @@ func PreSignV4(req http.Request, accessKeyID, secretAccessKey, sessionToken, loc
return &req
}
// PreSignV4Outposts presign the request for S3 on Outposts (service name s3-outposts).
func PreSignV4Outposts(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string, expires int64) *http.Request {
// Presign is not needed for anonymous credentials.
if accessKeyID == "" || secretAccessKey == "" {
return &req
}
t := time.Now().UTC()
credential := GetCredential(accessKeyID, location, t, ServiceTypeS3Outposts)
signedHeaders := getSignedHeaders(req, v4IgnoredHeaders)
query := req.URL.Query()
query.Set("X-Amz-Algorithm", signV4Algorithm)
query.Set("X-Amz-Date", t.Format(iso8601DateFormat))
query.Set("X-Amz-Expires", strconv.FormatInt(expires, 10))
query.Set("X-Amz-SignedHeaders", signedHeaders)
query.Set("X-Amz-Credential", credential)
if sessionToken != "" {
if v := req.Header.Get("x-amz-s3session-token"); v != "" {
query.Set("X-Amz-S3session-Token", sessionToken)
} else {
query.Set("X-Amz-Security-Token", sessionToken)
}
}
req.URL.RawQuery = query.Encode()
canonicalRequest := getCanonicalRequest(req, v4IgnoredHeaders, getHashedPayload(req))
stringToSign := getStringToSignV4(t, location, canonicalRequest, ServiceTypeS3Outposts)
signingKey := getSigningKey(secretAccessKey, location, t, ServiceTypeS3Outposts)
signature := getSignature(signingKey, stringToSign)
req.URL.RawQuery += "&X-Amz-Signature=" + signature
return &req
}
// PostPresignSignatureV4 - presigned signature for PostPolicy
// requests.
func PostPresignSignatureV4(policyBase64 string, t time.Time, secretAccessKey, location string) string {
@@ -393,3 +426,18 @@ func SignV4TrailerExpress(req http.Request, accessKeyID, secretAccessKey, sessio
func SignV4Trailer(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string, trailer http.Header) *http.Request {
return signV4(req, accessKeyID, secretAccessKey, sessionToken, location, ServiceTypeS3, trailer)
}
// SignV4Outposts sign the request for S3 on Outposts (service name s3-outposts).
func SignV4Outposts(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string) *http.Request {
return signV4(req, accessKeyID, secretAccessKey, sessionToken, location, ServiceTypeS3Outposts, nil)
}
// SignV4WithServiceType signs a request with AWS Signature Version 4 using a custom service type.
func SignV4WithServiceType(req http.Request, accessKeyID, secretAccessKey, sessionToken, location, serviceType string) *http.Request {
return signV4(req, accessKeyID, secretAccessKey, sessionToken, location, serviceType, nil)
}
// SignV4TrailerOutposts sign the request with trailer for S3 on Outposts (service name s3-outposts).
func SignV4TrailerOutposts(req http.Request, accessKeyID, secretAccessKey, sessionToken, location string, trailer http.Header) *http.Request {
return signV4(req, accessKeyID, secretAccessKey, sessionToken, location, ServiceTypeS3Outposts, trailer)
}
+21
View File
@@ -18,6 +18,7 @@
package tags
import (
"encoding/json"
"encoding/xml"
"io"
"net/url"
@@ -293,6 +294,26 @@ func (tags Tags) ToMap() map[string]string {
return tags.TagSet.toMap()
}
// MarshalJSON encodes Tags as a flat JSON object {"key":"value",...}.
func (tags Tags) MarshalJSON() ([]byte, error) {
return json.Marshal(tags.ToMap())
}
// UnmarshalJSON decodes a flat JSON object {"key":"value",...} into Tags.
func (tags *Tags) UnmarshalJSON(data []byte) error {
var m map[string]string
if err := json.Unmarshal(data, &m); err != nil {
return err
}
if tags.TagSet == nil {
tags.TagSet = &tagSet{
tagMap: make(map[string]string),
}
}
tags.TagSet.tagMap = m
return nil
}
// MapToObjectTags converts an input map of key and value into
// *Tags data structure with validation.
func MapToObjectTags(tagMap map[string]string) (*Tags, error) {
+27
View File
@@ -179,6 +179,11 @@ func isValidEndpointURL(endpointURL url.URL) error {
return errInvalidArgument("Google Cloud Storage endpoint should be 'storage.googleapis.com'.")
}
}
if strings.Contains(host, "s3-outposts") {
if !s3utils.IsAmazonOutpostsEndpoint(endpointURL) {
return errInvalidArgument("S3 Outposts endpoint must match <prefix>.s3-outposts.<region>.amazonaws.com")
}
}
return nil
}
@@ -304,6 +309,21 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
Region: h.Get("x-amz-bucket-region"),
}
}
mtimeStr := h.Get("X-Minio-Source-Mtime")
if mtimeStr != "" {
mtime, err = time.Parse(time.RFC3339Nano, mtimeStr)
if err != nil {
return ObjectInfo{}, ErrorResponse{
Code: InternalError,
Message: fmt.Sprintf("X-Minio-Source-Mtime is not in supported format: %v", err),
BucketName: bucketName,
Key: objectName,
RequestID: h.Get("x-amz-request-id"),
HostID: h.Get("x-amz-id-2"),
Region: h.Get("x-amz-bucket-region"),
}
}
}
// Fetch content type if any present.
contentType := strings.TrimSpace(h.Get("Content-Type"))
@@ -381,6 +401,7 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
Size: size,
LastModified: mtime,
ContentType: contentType,
ContentEncoding: strings.TrimSpace(h.Get("Content-Encoding")),
Expires: expiry,
VersionID: h.Get(amzVersionID),
IsDeleteMarker: deleteMarker,
@@ -402,6 +423,12 @@ func ToObjectInfo(bucketName, objectName string, h http.Header) (ObjectInfo, err
ChecksumSHA1: h.Get(ChecksumSHA1.Key()),
ChecksumSHA256: h.Get(ChecksumSHA256.Key()),
ChecksumCRC64NVME: h.Get(ChecksumCRC64NVME.Key()),
ChecksumMD5: h.Get(ChecksumMD5.Key()),
ChecksumSHA512: h.Get(ChecksumSHA512.Key()),
ChecksumXXHash64: h.Get(ChecksumXXHash64.Key()),
ChecksumXXHash3: h.Get(ChecksumXXHash3.Key()),
ChecksumXXHash128: h.Get(ChecksumXXHash128.Key()),
ChecksumAlgorithm: h.Get(amzChecksumAlgo),
ChecksumMode: h.Get(ChecksumFullObjectMode.Key()),
}, nil
}
+14
View File
@@ -1,3 +1,17 @@
## 2.28.3
### Maintenance
Bump all dependencies
## 2.28.2
- Add ArtifactDir() to support Go 1.26 testing.TB interface [f3a36b6]
- Implement shell completion [94151c8]
- Add asan CLI option mirroring msan implementation [4d21dbb]
- Bump uri from 1.0.3 to 1.0.4 in /docs (#1630) [c102161]
- fix aspect ratio [9619647]
- update logos [5779304]
## 2.28.1
Update all dependencies. This auto-updated the required version of Go to 1.24, consistent with the fact that Go 1.23 has been out of support for almost six months.
+1 -1
View File
@@ -120,6 +120,6 @@ Sponsors commit to a [sponsorship](https://github.com/sponsors/onsi) for a year.
<p style="font-size:21px; color:black;">Browser testing via
<a href="https://www.testmu.ai/" target="_blank">
<img src="https://www.testmu.ai/blue-logo.png" style="vertical-align: middle;" width="250" height="45" />
<img src="https://assets.testmu.ai/resources/images/logos/white-logo.png" style="vertical-align: middle;" width="250" />
</a>
</p>
+164
View File
@@ -1,9 +1,13 @@
package command
import (
"bufio"
"fmt"
"io"
"maps"
"os"
"path/filepath"
"slices"
"strings"
"github.com/onsi/ginkgo/v2/formatter"
@@ -158,6 +162,166 @@ func (p Program) handleHelpRequestsAndExit(writer io.Writer, args []string) {
}
}
type completionOptions = struct {
Complete bool
Install bool
}
func (p *Program) BuildCompletionCommand() Command {
opts := completionOptions{}
flags, err := types.NewGinkgoFlagSet(
types.GinkgoFlags{
{Name: "complete", KeyPath: "Complete", Usage: "Generate completion for arguments after --"},
{Name: "install", KeyPath: "Install", Usage: "Install shell completion script into $XDG_DATA_HOME, ~/.local/share"},
},
&opts,
types.GinkgoFlagSections{},
)
if err != nil {
panic(err)
}
return Command{
Name: "completion",
Usage: "ginkgo completion <FLAGS> <SHELL> [-- <COMPLETE>]",
Flags: flags,
ShortDoc: "Generate shell completion",
Documentation: `To use install completion script for your shell (bash, fish, zsh).
Or load completion code by: {{bold}}source <(ginkgo completion <SHELL>){{/}}.`,
Command: func(args []string, completeArgs []string) {
p.handleCompletionAndExit(args, completeArgs, opts)
},
}
}
func (p Program) generateShellCompletionScript(shell string) (scriptPath string, script string) {
switch shell {
case "bash":
scriptPath = fmt.Sprintf("bash-completion/completions/%s", p.Name)
script = fmt.Sprintf(`__%s_complete_bash() {
mapfile -t COMPREPLY < <("${COMP_WORDS[0]}" completion --complete bash -- "${COMP_WORDS[@]:1:COMP_CWORD}")
}
complete -o bashdefault -o default -F __%[1]s_complete_bash %[1]s
`, p.Name)
case "fish":
scriptPath = fmt.Sprintf("fish/vendor_completions.d/%s.fish", p.Name)
script = fmt.Sprintf(`function __fish_%[1]s_complete
set -l args (commandline -opc) (commandline -ct)
set -e args[1]
%[1]s completion --complete fish -- $args
end
complete -c %[1]s -a "(__fish_%[1]s_complete)"
`, p.Name)
case "zsh":
scriptPath = fmt.Sprintf("zsh/site-functions/_%s", p.Name)
script = fmt.Sprintf(`#compdef %[1]s
_%[1]s() {
local -a completions
completions=(${(f)"$("${words[1]}" completion --complete zsh -- "${words[@]:1:$((CURRENT-1))}")"})
if (( ${#completions[@]} )); then
_describe 'completions' completions
else
_default
fi
}
compdef _%[1]s %[1]s
if [ "$funcstack[1]" = "_%[1]s" ]; then
_%[1]s
fi
`, p.Name)
case "":
AbortWithUsage("Shell is not specified")
default:
AbortWith("Shell %q is not supported yet. Choose: bash, fish, zsh", shell)
}
return scriptPath, script
}
func (p Program) handleCompletionAndExit(args, completeArgs []string, opts completionOptions) {
writer := p.OutWriter
if writer == nil {
writer = os.Stdout
}
buffer := bufio.NewWriter(writer)
defer buffer.Flush()
var shell string
if len(args) > 0 {
shell = args[0]
}
if !opts.Complete {
scriptPath, script := p.generateShellCompletionScript(shell)
if opts.Install {
dataHomeDir := os.Getenv("XDG_DATA_HOME")
if dataHomeDir == "" {
userHomeDir, err := os.UserHomeDir()
AbortIfError("Failed to find home", err)
dataHomeDir = filepath.Join(userHomeDir, ".local/share")
}
scriptPath = filepath.Join(dataHomeDir, scriptPath)
fmt.Fprintf(buffer, "Installing completion script: %v\n", scriptPath)
err := os.WriteFile(scriptPath, []byte(script), 0644)
AbortIfError("Failed to install completion script", err)
} else {
buffer.Write([]byte(script))
}
Abort(AbortDetails{})
}
var lastArg string
var result map[string]string
if len(completeArgs) > 0 {
lastArg = completeArgs[len(completeArgs)-1]
}
if delim := slices.Index(completeArgs, "--"); delim >= 0 && delim != len(completeArgs)-1 {
// No completion for pass-through arguments after "--"
} else if len(lastArg) > 0 && lastArg[0] == '-' {
// Complete flags
cmd := &p.DefaultCommand
for i := range p.Commands {
if p.Commands[i].Name == completeArgs[0] {
cmd = &p.Commands[i]
break
}
}
result = cmd.Flags.Completion(lastArg)
} else if len(completeArgs) <= 1 {
// Complete commands
result = make(map[string]string, len(p.Commands)+1)
for _, cmd := range append(p.Commands, p.DefaultCommand) {
if strings.HasPrefix(cmd.Name, lastArg) {
result[cmd.Name] = cmd.Usage
}
}
}
width := 0
for suggest := range result {
width = max(width, len(suggest))
}
for _, suggest := range slices.Sorted(maps.Keys(result)) {
usage := result[suggest]
switch {
case shell == "bash" && usage != "" && len(result) > 1:
fmt.Fprintf(buffer, "%*s (%s)\n", -width-2, suggest, usage)
case shell == "fish":
fmt.Fprintf(buffer, "%s\t%s\n", suggest, usage)
case shell == "zsh":
fmt.Fprintf(buffer, "%s:%s\n", suggest, usage)
default:
fmt.Fprintln(buffer, suggest)
}
}
Abort(AbortDetails{})
}
func (p Program) EmitUsage(writer io.Writer) {
fmt.Fprintln(writer, formatter.F(p.Heading))
fmt.Fprintln(writer, formatter.F("{{gray}}%s{{/}}", strings.Repeat("-", len(p.Heading))))
+1
View File
@@ -41,6 +41,7 @@ func main() {
{Name: "nodot", Deprecation: types.Deprecations.Nodot()},
},
}
program.Commands = append(program.Commands, program.BuildCompletionCommand())
program.RunAndExit(os.Args)
}
+4
View File
@@ -72,6 +72,7 @@ type GinkgoTInterface interface {
TempDir() string
Attr(key, value string)
Output() io.Writer
ArtifactDir() string
}
/*
@@ -196,3 +197,6 @@ func (g *GinkgoTBWrapper) Attr(key, value string) {
func (g *GinkgoTBWrapper) Output() io.Writer {
return g.GinkgoT.Output()
}
func (g *GinkgoTBWrapper) ArtifactDir() string {
return g.GinkgoT.ArtifactDir()
}
@@ -181,6 +181,15 @@ func (t *ginkgoTestingTProxy) TempDir() string {
return tmpDir
}
func (t *ginkgoTestingTProxy) ArtifactDir() string {
artifactDir, err := os.MkdirTemp("", "ginkgo")
if err != nil {
t.fail(fmt.Sprintf("Failed to create artifact directory: %v", err), 1)
return ""
}
return artifactDir
}
// FullGinkgoTInterface
func (t *ginkgoTestingTProxy) AddReportEntryVisibilityAlways(name string, args ...any) {
finalArgs := []any{internal.Offset(1), types.ReportEntryVisibilityAlways}
+3
View File
@@ -215,6 +215,7 @@ type GoFlagsConfig struct {
N bool
ModFile string
ModCacheRW bool
ASan bool
MSan bool
PkgDir string
Tags string
@@ -570,6 +571,8 @@ var GoBuildFlags = GinkgoFlags{
Usage: "leave newly-created directories in the module cache read-write instead of making them read-only."},
{KeyPath: "Go.ModFile", Name: "modfile", UsageArgument: "file", SectionKey: "go-build",
Usage: `in module aware mode, read (and possibly write) an alternate go.mod file instead of the one in the module root directory. A file named go.mod must still be present in order to determine the module root directory, but it is not accessed. When -modfile is specified, an alternate go.sum file is also used: its path is derived from the -modfile flag by trimming the ".mod" extension and appending ".sum".`},
{KeyPath: "Go.ASan", Name: "asan", SectionKey: "go-build",
Usage: "enable interoperation with address sanitizer."},
{KeyPath: "Go.MSan", Name: "msan", SectionKey: "go-build",
Usage: "enable interoperation with memory sanitizer. Supported only on linux/amd64, linux/arm64 and only with Clang/LLVM as the host C compiler. On linux/arm64, pie build mode will be used."},
{KeyPath: "Go.N", Name: "n", SectionKey: "go-build",

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