Repository: restic/restic
Pull request #5329 (2025-03-31 17:03:51)

docs: fix typos in developer information
<!--
Thank you very much for contributing code or documentation to restic! Please
fill out the following questions to make it easier for us to review your
changes.
-->

What does this PR change? What problem does it solve?
-----------------------------------------------------
Add `disable_grpc_modules` tag and fix several typos. The SLSA verification does not require a "tag", thus drop that remark.
<!--
Describe the changes and their purpose here, as detailed as needed.
-->

Was the change previously discussed in an issue or on the forum?
----------------------------------------------------------------
See https://forum.restic.net/t/restic-0-18-0-released/9578/9
<!--
Link issues and relevant forum posts here.

If this PR resolves an issue on GitHub, use "Closes #1234" so that the issue
is closed automatically when this PR is merged.
-->

Checklist
---------

<!--
You do not need to check all the boxes below all at once. Feel free to take
your time and add more commits. If you're done and ready for review, please
check the last box. Enable a checkbox by replacing [ ] with [x].

Please always follow these steps:
- Read the [contribution guidelines](https://github.com/restic/restic/blob/master/CONTRIBUTING.md#providing-patches).
- Enable [maintainer edits](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork).
- Run `gofmt` on the code in all commits.
- Format all commit messages in the same style as [the other commits in the repository](https://github.com/restic/restic/blob/master/CONTRIBUTING.md#git-commits).
-->

- ~~[ ] I have added tests for all code changes.~~
- [x] I have added documentation for relevant changes (in the manual).
- ~~[ ] There's a new file in `changelog/unreleased/` that describes the changes for our users (see [template](https://github.com/restic/restic/blob/master/changelog/TEMPLATE)).~~
- [x] I'm done! This pull request is ready for review.



Patch:
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 5e9713618..5156228ba 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -29,7 +29,7 @@ jobs:
         uses: actions/checkout@v4
 
       - name: Log in to the Container registry
-        uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
+        uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772
         with:
           registry: ${{ env.REGISTRY }}
           username: ${{ github.actor }}
diff --git a/changelog/unreleased/issue-4728 b/changelog/unreleased/issue-4728
new file mode 100644
index 000000000..e0149e675
--- /dev/null
+++ b/changelog/unreleased/issue-4728
@@ -0,0 +1,7 @@
+Enhancement: Added support for zstd compression levels `fastest` and `better`
+
+Restic now supports the zstd compression modes `fastest` and `better`. Set the
+environment variable `RESTIC_COMPRESSION` to `fastest` or `better` to use these
+compression levels. This can also be set with the `--compression` flag.
+
+https://github.com/restic/restic/issues/4728
diff --git a/changelog/unreleased/issue-5233 b/changelog/unreleased/issue-5233
new file mode 100644
index 000000000..14ff2b249
--- /dev/null
+++ b/changelog/unreleased/issue-5233
@@ -0,0 +1,8 @@
+Bugfix: forget command returns exit code 3 on partial removal of snapshots
+
+The `forget` command now returns exit code 3 when it fails to remove one or
+more snapshots. Previously, it returned exit code 0, which could lead to
+confusion if the command was used in a script.
+
+https://github.com/restic/restic/issues/5233
+https://github.com/restic/restic/pull/5322
diff --git a/changelog/unreleased/issue-5325 b/changelog/unreleased/issue-5325
new file mode 100644
index 000000000..883391a0a
--- /dev/null
+++ b/changelog/unreleased/issue-5325
@@ -0,0 +1,7 @@
+Bugfix: Correctly handle `RESTIC_HOST` in `forget` command
+
+The `forget` command did not use the host name from the `RESTIC_HOST`
+environment variable. This has been fixed.
+
+https://github.com/restic/restic/issues/5325
+https://github.com/restic/restic/pull/5327
diff --git a/cmd/restic/cmd_forget.go b/cmd/restic/cmd_forget.go
index 2bfacc4de..bef00ffa1 100644
--- a/cmd/restic/cmd_forget.go
+++ b/cmd/restic/cmd_forget.go
@@ -41,6 +41,7 @@ EXIT STATUS
 
 Exit status is 0 if the command was successful.
 Exit status is 1 if there was any error.
+Exit status is 3 if there was an error removing one or more snapshots.
 Exit status is 10 if the repository does not exist.
 Exit status is 11 if the repository is already locked.
 Exit status is 12 if the password is incorrect.
@@ -62,6 +63,7 @@ Exit status is 12 if the password is incorrect.
 type ForgetPolicyCount int
 
 var ErrNegativePolicyCount = errors.New("negative values not allowed, use 'unlimited' instead")
+var ErrFailedToRemoveOneOrMoreSnapshots = errors.New("failed to remove one or more snapshots")
 
 func (c *ForgetPolicyCount) Set(s string) error {
 	switch s {
@@ -137,13 +139,14 @@ func (opts *ForgetOptions) AddFlags(f *pflag.FlagSet) {
 	f.Var(&opts.KeepTags, "keep-tag", "keep snapshots with this `taglist` (can be specified multiple times)")
 	f.BoolVar(&opts.UnsafeAllowRemoveAll, "unsafe-allow-remove-all", false, "allow deleting all snapshots of a snapshot group")
 
-	initMultiSnapshotFilter(f, &opts.SnapshotFilter, false)
 	f.StringArrayVar(&opts.Hosts, "hostname", nil, "only consider snapshots with the given `hostname` (can be specified multiple times)")
 	err := f.MarkDeprecated("hostname", "use --host")
 	if err != nil {
 		// MarkDeprecated only returns an error when the flag is not found
 		panic(err)
 	}
+	// must be defined after `--hostname` to not override the default value from the environment
+	initMultiSnapshotFilter(f, &opts.SnapshotFilter, false)
 
 	f.BoolVarP(&opts.Compact, "compact", "c", false, "use compact output format")
 	opts.GroupBy = restic.SnapshotGroupByOptions{Host: true, Path: true}
@@ -304,12 +307,15 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
 		return ctx.Err()
 	}
 
+	// these are the snapshots that failed to be removed
+	failedSnIDs := restic.NewIDSet()
 	if len(removeSnIDs) > 0 {
 		if !opts.DryRun {
 			bar := printer.NewCounter("files deleted")
 			err := restic.ParallelRemove(ctx, repo, removeSnIDs, restic.WriteableSnapshotFile, func(id restic.ID, err error) error {
 				if err != nil {
 					printer.E("unable to remove %v/%v from the repository\n", restic.SnapshotFile, id)
+					failedSnIDs.Insert(id)
 				} else {
 					printer.VV("removed %v/%v\n", restic.SnapshotFile, id)
 				}
@@ -331,6 +337,10 @@ func runForget(ctx context.Context, opts ForgetOptions, pruneOptions PruneOption
 		}
 	}
 
+	if len(failedSnIDs) > 0 {
+		return ErrFailedToRemoveOneOrMoreSnapshots
+	}
+
 	if len(removeSnIDs) > 0 && opts.Prune {
 		if opts.DryRun {
 			printer.P("%d snapshots would be removed, running prune dry run\n", len(removeSnIDs))
diff --git a/cmd/restic/global.go b/cmd/restic/global.go
index 7dafa6f96..6e58a0d73 100644
--- a/cmd/restic/global.go
+++ b/cmd/restic/global.go
@@ -114,7 +114,7 @@ func (opts *GlobalOptions) AddFlags(f *pflag.FlagSet) {
 	f.BoolVar(&opts.InsecureNoPassword, "insecure-no-password", false, "use an empty password for the repository, must be passed to every restic command (insecure)")
 	f.BoolVar(&opts.InsecureTLS, "insecure-tls", false, "skip TLS certificate verification when connecting to the repository (insecure)")
 	f.BoolVar(&opts.CleanupCache, "cleanup-cache", false, "auto remove old cache directories")
-	f.Var(&opts.Compression, "compression", "compression mode (only available for repository format version 2), one of (auto|off|max) (default: $RESTIC_COMPRESSION)")
+	f.Var(&opts.Compression, "compression", "compression mode (only available for repository format version 2), one of (auto|off|fastest|better|max) (default: $RESTIC_COMPRESSION)")
 	f.BoolVar(&opts.NoExtraVerify, "no-extra-verify", false, "skip additional verification of data before upload (see documentation)")
 	f.IntVar(&opts.Limits.UploadKb, "limit-upload", 0, "limits uploads to a maximum `rate` in KiB/s. (default: unlimited)")
 	f.IntVar(&opts.Limits.DownloadKb, "limit-download", 0, "limits downloads to a maximum `rate` in KiB/s. (default: unlimited)")
diff --git a/cmd/restic/main.go b/cmd/restic/main.go
index b04b3b9ab..f4b17aa92 100644
--- a/cmd/restic/main.go
+++ b/cmd/restic/main.go
@@ -206,6 +206,8 @@ func main() {
 		exitCode = 0
 	case err == ErrInvalidSourceData:
 		exitCode = 3
+	case errors.Is(err, ErrFailedToRemoveOneOrMoreSnapshots):
+		exitCode = 3
 	case errors.Is(err, ErrNoRepository):
 		exitCode = 10
 	case restic.IsAlreadyLocked(err):
diff --git a/doc/030_preparing_a_new_repo.rst b/doc/030_preparing_a_new_repo.rst
index 34a0cd8bc..ac9657460 100644
--- a/doc/030_preparing_a_new_repo.rst
+++ b/doc/030_preparing_a_new_repo.rst
@@ -854,6 +854,6 @@ with an empty password, use the following command.
     restic init --insecure-no-password
 
 
-The ``init`` and ``copy`` command also support the option ``--from-insecure-no-password``
+The ``init`` and ``copy`` commands also support the option ``--from-insecure-no-password``
 which applies to the source repository. The ``key add`` and ``key passwd`` commands
-include the ``--new-insecure-no-password`` option to add or set and empty password.
+include the ``--new-insecure-no-password`` option to add or set an empty password.
diff --git a/doc/developer_information.rst b/doc/developer_information.rst
index a2d7adfe1..ce28317c6 100644
--- a/doc/developer_information.rst
+++ b/doc/developer_information.rst
@@ -18,7 +18,7 @@ depends on the following things:
 * The path to the Go workspace (``GOPATH=/home/build/go``)
 * Other environment variables (mostly ``$GOOS``, ``$GOARCH``, ``$CGO_ENABLED``)
 
-In addition, The compressed ZIP files for Windows depends on the modification
+In addition, the compressed ZIP files for Windows depends on the modification
 timestamp and filename of the binary contained in it. In order to reproduce the
 exact same ZIP file every time, we update the timestamp of the file ``VERSION``
 in the source code archive and set the timezone to Europe/Berlin.
@@ -52,10 +52,10 @@ In the following example, we'll use the file ``restic-0.14.0.tar.gz`` and Go
     $ go version
     go version go1.19 linux/amd64
 
-    $ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -tags selfupdate -o restic_linux_amd64 ./cmd/restic
+    $ GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -tags selfupdate,disable_grpc_modules -o restic_linux_amd64 ./cmd/restic
     $ bzip2 restic_linux_amd64
 
-    $ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -tags selfupdate -o restic_0.14.0_windows_amd64.exe ./cmd/restic
+    $ GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-s -w" -tags selfupdate,disable_grpc_modules -o restic_0.14.0_windows_amd64.exe ./cmd/restic
     $ touch --reference VERSION restic_0.14.0_windows_amd64.exe
     $ TZ=Europe/Berlin zip -q -X restic_0.14.0_windows_amd64.zip restic_0.14.0_windows_amd64.exe
 
@@ -66,7 +66,7 @@ The released binaries for restic are built using a Docker container. You can
 find it on `Docker Hub <https://hub.docker.com/r/restic/builder>`__ as
 ``restic/builder``, the ``Dockerfile`` and instructions on how to build the
 container can be found in the `GitHub repository
-<https://github.com/restic/builder>`__
+<https://github.com/restic/builder>`__.
 
 The container serves the following goals:
 * Have a very controlled environment which is independent from the local system
@@ -93,7 +93,7 @@ The following steps are necessary to build the binaries:
 
     mkdir output
 
-3. Mount the source code and the output directory in the container and run the default command, which starts ``helpers/build-release-binaries/main.go``:
+4. Mount the source code and the output directory in the container and run the default command, which starts ``helpers/build-release-binaries/main.go``:
 
 .. code::
 
@@ -103,7 +103,7 @@ The following steps are necessary to build the binaries:
         restic/builder \
         go run helpers/build-release-binaries/main.go --version 0.14.0
 
-4. If anything goes wrong, you can enable debug output like this:
+5. If anything goes wrong, you can enable debug output like this:
 
 .. code::
 
@@ -114,7 +114,7 @@ The following steps are necessary to build the binaries:
         go run helpers/build-release-binaries/main.go --version 0.14.0 --verbose
 
 Verifying SLSA Provenance for GHCR Docker Images
-*******************************************
+************************************************
 
 Our Docker images in the GitHub Container Registry (GHCR) are built with SLSA
 (Supply-chain Levels for Software Artifacts) provenance.
@@ -131,9 +131,8 @@ To verify this provenance:
         --source-uri github.com/restic/restic \
         <image-name>@<digest>
 
-   Replace `<tag>` with the Git tag of the release you're verifying, `<image-name>`
-   with the full name of the Docker image (including the registry), and `<digest>`
-   with the SHA256 digest of the image.
+   Replace `<image-name>` with the full name of the Docker image (including the registry),
+   and `<digest>` with the SHA256 digest of the image.
 
 3. If the verification is successful, you'll see output indicating that the provenance 
 is valid.
@@ -146,7 +145,7 @@ Verifying the Official Binaries
 
 To verify the official binaries, you can either build them yourself using the above
 instructions or use the ``helpers/verify-release-binaries.sh`` script from the restic
-repository. Run it as ``helpers/verify-release-binaries.sh restic_version go_version``.
+repository. Run it as ``helpers/verify-release-binaries.sh $restic_version $go_version``.
 The specified go compiler version must match the one used to build the official
 binaries. For example, for restic 0.16.2 the command would be
 ``helpers/verify-release-binaries.sh 0.16.2 1.21.3``.
diff --git a/doc/faq.rst b/doc/faq.rst
index 3b62f641d..0df4aa0ea 100644
--- a/doc/faq.rst
+++ b/doc/faq.rst
@@ -253,7 +253,7 @@ Archive** storage classes is available:
 .. code-block:: console
 
    $ restic backup -o s3.storage-class=GLACIER somedir/
-   $ RESTIC_FEATURES=s3-restore restic restore -o s3.enable-restore=1 -o s3.restore-days=7 -o s3.restore-timeout=1d latest
+   $ RESTIC_FEATURES=s3-restore restic restore -o s3.enable-restore=1 -o s3.restore-days=7 -o s3.restore-timeout=24h latest
 
 **Notes:**
 
diff --git a/go.mod b/go.mod
index 1e1ba52f2..da26ac878 100644
--- a/go.mod
+++ b/go.mod
@@ -21,33 +21,33 @@ require (
 	github.com/google/go-cmp v0.7.0
 	github.com/hashicorp/golang-lru/v2 v2.0.7
 	github.com/klauspost/compress v1.18.0
-	github.com/minio/minio-go/v7 v7.0.88
+	github.com/minio/minio-go/v7 v7.0.89
 	github.com/ncw/swift/v2 v2.0.3
 	github.com/peterbourgon/unixtransport v0.0.4
 	github.com/pkg/errors v0.9.1
 	github.com/pkg/profile v1.7.0
-	github.com/pkg/sftp v1.13.8
+	github.com/pkg/sftp v1.13.9
 	github.com/pkg/xattr v0.4.10
 	github.com/restic/chunker v0.4.0
 	github.com/spf13/cobra v1.9.1
 	github.com/spf13/pflag v1.0.6
 	go.uber.org/automaxprocs v1.6.0
 	golang.org/x/crypto v0.36.0
-	golang.org/x/net v0.37.0
+	golang.org/x/net v0.38.0
 	golang.org/x/oauth2 v0.28.0
 	golang.org/x/sync v0.12.0
 	golang.org/x/sys v0.31.0
 	golang.org/x/term v0.30.0
 	golang.org/x/text v0.23.0
 	golang.org/x/time v0.11.0
-	google.golang.org/api v0.227.0
+	google.golang.org/api v0.228.0
 )
 
 require (
 	cel.dev/expr v0.19.2 // indirect
 	cloud.google.com/go v0.118.3 // indirect
 	cloud.google.com/go/auth v0.15.0 // indirect
-	cloud.google.com/go/auth/oauth2adapt v0.2.7 // indirect
+	cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
 	cloud.google.com/go/compute/metadata v0.6.0 // indirect
 	cloud.google.com/go/iam v1.4.1 // indirect
 	cloud.google.com/go/monitoring v1.24.0 // indirect
@@ -74,7 +74,7 @@ require (
 	github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
 	github.com/googleapis/gax-go/v2 v2.14.1 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
-	github.com/klauspost/cpuid/v2 v2.2.9 // indirect
+	github.com/klauspost/cpuid/v2 v2.2.10 // indirect
 	github.com/kr/fs v0.1.0 // indirect
 	github.com/kylelemons/godebug v1.1.0 // indirect
 	github.com/minio/crc64nvme v1.0.1 // indirect
@@ -96,6 +96,6 @@ require (
 	google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
 	google.golang.org/grpc v1.71.0 // indirect
-	google.golang.org/protobuf v1.36.5 // indirect
+	google.golang.org/protobuf v1.36.6 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
index 54770e377..0dd0741b6 100644
--- a/go.sum
+++ b/go.sum
@@ -4,8 +4,8 @@ cloud.google.com/go v0.118.3 h1:jsypSnrE/w4mJysioGdMBg4MiW/hHx/sArFpaBWHdME=
 cloud.google.com/go v0.118.3/go.mod h1:Lhs3YLnBlwJ4KA6nuObNMZ/fCbOQBPuWKPoE0Wa/9Vc=
 cloud.google.com/go/auth v0.15.0 h1:Ly0u4aA5vG/fsSsxu98qCQBemXtAtJf+95z9HK+cxps=
 cloud.google.com/go/auth v0.15.0/go.mod h1:WJDGqZ1o9E9wKIL+IwStfyn/+s59zl4Bi+1KQNVXLZ8=
-cloud.google.com/go/auth/oauth2adapt v0.2.7 h1:/Lc7xODdqcEw8IrZ9SvwnlLX6j9FHQM74z6cBk9Rw6M=
-cloud.google.com/go/auth/oauth2adapt v0.2.7/go.mod h1:NTbTTzfvPl1Y3V1nPpOgl2w6d/FjO7NNUQaWSox6ZMc=
+cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
+cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
 cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
 cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
 cloud.google.com/go/iam v1.4.1 h1:cFC25Nv+u5BkTR/BT1tXdoF2daiVbZ1RLx2eqfQ9RMM=
@@ -136,8 +136,8 @@ github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeW
 github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
 github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
 github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
-github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
+github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
+github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
 github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
 github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -155,8 +155,8 @@ github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY
 github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
 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.88 h1:v8MoIJjwYxOkehp+eiLIuvXk87P2raUtoU5klrAAshs=
-github.com/minio/minio-go/v7 v7.0.88/go.mod h1:33+O8h0tO7pCeCWwBVa07RhVVfB/3vS4kEX7rwYKmIg=
+github.com/minio/minio-go/v7 v7.0.89 h1:hx4xV5wwTUfyv8LarhJAwNecnXpoTsj9v3f3q/ZkiJU=
+github.com/minio/minio-go/v7 v7.0.89/go.mod h1:2rFnGAp02p7Dddo1Fq4S2wYOfpF0MUTSeLTRC90I204=
 github.com/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=
 github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
 github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
@@ -171,8 +171,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
 github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
-github.com/pkg/sftp v1.13.8 h1:Xt7eJ/xqXv7s0VuzFw7JXhZj6Oc1zI6l4GK8KP9sFB0=
-github.com/pkg/sftp v1.13.8/go.mod h1:DmvEkvKE2lshEeuo2JMp06yqcx9HVnR7e3zqQl42F3U=
+github.com/pkg/sftp v1.13.9 h1:4NGkvGudBL7GteO3m6qnaQ4pC0Kvf0onSVc9gR3EWBw=
+github.com/pkg/sftp v1.13.9/go.mod h1:OBN7bVXdstkFFN/gdnHPUb5TE8eb8G1Rp9wCItqjkkA=
 github.com/pkg/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
 github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
 github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
@@ -266,8 +266,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
 golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
-golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
-golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
+golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
+golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
 golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
 golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -339,8 +339,8 @@ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxb
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/api v0.227.0 h1:QvIHF9IuyG6d6ReE+BNd11kIB8hZvjN8Z5xY5t21zYc=
-google.golang.org/api v0.227.0/go.mod h1:EIpaG6MbTgQarWF5xJvX0eOJPK9n/5D4Bynb9j2HXvQ=
+google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs=
+google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4=
 google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE=
 google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE=
 google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
@@ -349,8 +349,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
 google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
 google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
-google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
-google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/internal/backend/s3/config.go b/internal/backend/s3/config.go
index 77f27408e..365b16bf1 100644
--- a/internal/backend/s3/config.go
+++ b/internal/backend/s3/config.go
@@ -26,7 +26,7 @@ type Config struct {
 
 	EnableRestore  bool          `option:"enable-restore" help:"restore objects from GLACIER or DEEP_ARCHIVE storage classes (default: false, requires \"s3-restore\" feature flag)"`
 	RestoreDays    int           `option:"restore-days" help:"lifetime in days of restored object (default: 7)"`
-	RestoreTimeout time.Duration `option:"restore-timeout" help:"maximum time to wait for objects transition (default: 1d)"`
+	RestoreTimeout time.Duration `option:"restore-timeout" help:"maximum time to wait for objects transition (default: 24h)"`
 	RestoreTier    string        `option:"restore-tier" help:"Retrieval tier at which the restore will be processed. (Standard, Bulk or Expedited) (default: Standard)"`
 
 	Connections         uint   `option:"connections" help:"set a limit for the number of concurrent connections (default: 5)"`
diff --git a/internal/repository/repository.go b/internal/repository/repository.go
index 066ba5ed5..fb718e9f9 100644
--- a/internal/repository/repository.go
+++ b/internal/repository/repository.go
@@ -73,7 +73,9 @@ const (
 	CompressionAuto    CompressionMode = 0
 	CompressionOff     CompressionMode = 1
 	CompressionMax     CompressionMode = 2
-	CompressionInvalid CompressionMode = 3
+	CompressionFastest CompressionMode = 3
+	CompressionBetter  CompressionMode = 4
+	CompressionInvalid CompressionMode = 5
 )
 
 // Set implements the method needed for pflag command flag parsing.
@@ -85,9 +87,13 @@ func (c *CompressionMode) Set(s string) error {
 		*c = CompressionOff
 	case "max":
 		*c = CompressionMax
+	case "fastest":
+		*c = CompressionFastest
+	case "better":
+		*c = CompressionBetter
 	default:
 		*c = CompressionInvalid
-		return fmt.Errorf("invalid compression mode %q, must be one of (auto|off|max)", s)
+		return fmt.Errorf("invalid compression mode %q, must be one of (auto|off|fastest|better|max)", s)
 	}
 
 	return nil
@@ -101,6 +107,10 @@ func (c *CompressionMode) String() string {
 		return "off"
 	case CompressionMax:
 		return "max"
+	case CompressionFastest:
+		return "fastest"
+	case CompressionBetter:
+		return "better"
 	default:
 		return "invalid"
 	}
@@ -305,9 +315,17 @@ func (r *Repository) loadBlob(ctx context.Context, blobs []restic.PackedBlob, bu
 
 func (r *Repository) getZstdEncoder() *zstd.Encoder {
 	r.allocEnc.Do(func() {
-		level := zstd.SpeedDefault
-		if r.opts.Compression == CompressionMax {
+
+		var level zstd.EncoderLevel
+		switch r.opts.Compression {
+		case CompressionFastest:
+			level = zstd.SpeedFastest
+		case CompressionBetter:
+			level = zstd.SpeedBetterCompression
+		case CompressionMax:
 			level = zstd.SpeedBestCompression
+		default:
+			level = zstd.SpeedDefault
 		}
 
 		opts := []zstd.EOption{


Test patch:
diff --git a/cmd/restic/cmd_forget_test.go b/cmd/restic/cmd_forget_test.go
index ddeef028a..0d60f7445 100644
--- a/cmd/restic/cmd_forget_test.go
+++ b/cmd/restic/cmd_forget_test.go
@@ -5,6 +5,7 @@ import (
 
 	"github.com/restic/restic/internal/restic"
 	rtest "github.com/restic/restic/internal/test"
+	"github.com/spf13/pflag"
 )
 
 func TestForgetPolicyValues(t *testing.T) {
@@ -92,3 +93,10 @@ func TestForgetOptionValues(t *testing.T) {
 		}
 	}
 }
+
+func TestForgetHostnameDefaulting(t *testing.T) {
+	t.Setenv("RESTIC_HOST", "testhost")
+	opts := ForgetOptions{}
+	opts.AddFlags(pflag.NewFlagSet("test", pflag.ContinueOnError))
+	rtest.Equals(t, []string{"testhost"}, opts.Hosts)
+}