Compare commits

..

64 Commits

Author SHA1 Message Date
Alexander Neumann
7d0aa7f2e3 Add version for 0.18.1 2025-09-21 20:04:58 +02:00
Alexander Neumann
18f18b7f99 Generate CHANGELOG.md for 0.18.1 2025-09-21 20:03:56 +02:00
Alexander Neumann
426b71e3e5 Prepare changelog for 0.18.1 2025-09-21 20:03:56 +02:00
Michael Eischer
b7bb697cf7 Merge pull request #5513 from restic/more-polish-changelogs
doc: Nitpicks on changelogs
2025-09-17 20:38:19 +02:00
Michael Eischer
b12a638322 Merge pull request #5509 from restic/polish-changelogs
slightly polish changelogs
2025-09-17 20:37:46 +02:00
Leo R. Lundgren
4e0135e628 doc: Nitpicks on changelogs 2025-09-17 18:26:21 +02:00
Michael Eischer
9ef8e13102 slightly polish changelogs 2025-09-15 19:52:24 +02:00
Michael Eischer
4940e330c0 Merge pull request #5508 from restic/patch-release-cherrypicks
Patch release cherrypicks
2025-09-15 19:51:51 +02:00
Michael Eischer
3a63430b07 extend changelog 2025-09-15 19:34:25 +02:00
Michael Eischer
a5e814bd8d check: fix error reporting on download retry 2025-09-15 19:34:25 +02:00
Michael Eischer
398862c5c8 docs: sync compatibility section with website
This is no change in policy, just a more precise description of the
status quo.
2025-09-15 19:33:39 +02:00
Michael Eischer
b47c67fd90 update dependencies 2025-09-15 19:33:20 +02:00
Michael Eischer
6d7e37edce Merge pull request #5491 from MichaelEischer/patch-release-cherrypicks
Patch release cherrypicks
2025-09-06 22:32:40 +02:00
dependabot[bot]
4998fd68a7 build(deps): bump docker/login-action from 3.4.0 to 3.5.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](74a5d14239...184bdaa072)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 22:07:22 +02:00
greatroar
06cc6017b8 internal/restic: Fix panic in ParseDuration
Fixes #5485. Includes test case by @MichaelEischer.
2025-09-06 22:03:12 +02:00
gregoster
37851827c5 EOPNOTSUPP can be returned if the filesystem does not support xattrs (#5344)
---------

Co-authored-by: Greg Oster <oster@netbsd.org>
2025-09-06 22:03:12 +02:00
Michael Eischer
b75f80ae5f backup: fix test on windows 2025-09-06 22:02:50 +02:00
Michael Eischer
31f87b6188 add changelog 2025-09-06 22:02:50 +02:00
Michael Eischer
b67b88a0c0 backup: test that parent directory errors can be correctly filtered 2025-09-06 22:02:50 +02:00
Michael Eischer
d57b01d6eb backup: test that missing parent directory is correctly handled 2025-09-06 22:02:50 +02:00
Michael Eischer
fc81df3f54 backup: do not fail backup is some parent folder is inaccessible
Handle errors for parent directories of backup directories in the same
way as all other file access errors during a backup.
2025-09-06 22:02:50 +02:00
Michael Eischer
73995b818a backup: do not crash if nodeFromFileInfo fails
this could crash in two cases:
- if a directory is deleted between restic stating it and trying to list
  its directory content.
- when restic tries to list the parent directory of a backup target, but
  the parent directory has been deleted.

return an error in this case instead.
2025-09-06 22:02:50 +02:00
Michael Eischer
49abea6952 add changelog 2025-09-06 21:59:54 +02:00
Dominik Schulz
f18b8ad425 Mark HTTP Error 507 as permanent
This change classifies HTTP error 507 (Insufficient Storage) as a
permanent error that should not be retried. I keep running into
this once in a while and there is literally no point in retrying when
the server is full.

Fixes #5429

Signed-off-by: Dominik Schulz <dominik.schulz@gauner.org>
2025-09-06 21:59:54 +02:00
dependabot[bot]
0a6296bfde build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/storage/azblob
Bumps [github.com/Azure/azure-sdk-for-go/sdk/storage/azblob](https://github.com/Azure/azure-sdk-for-go) from 1.6.1 to 1.6.2.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/go-mgmt-sdk-release-guideline.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.6.1...sdk/storage/azblob/v1.6.2)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/storage/azblob
  dependency-version: 1.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:59:54 +02:00
dependabot[bot]
2403d1f139 build(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:59:54 +02:00
dependabot[bot]
86a453200a build(deps): bump google.golang.org/api from 0.228.0 to 0.248.0
Bumps [google.golang.org/api](https://github.com/googleapis/google-api-go-client) from 0.228.0 to 0.248.0.
- [Release notes](https://github.com/googleapis/google-api-go-client/releases)
- [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md)
- [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.228.0...v0.248.0)

---
updated-dependencies:
- dependency-name: google.golang.org/api
  dependency-version: 0.248.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:59:54 +02:00
dependabot[bot]
518fbbcdc2 build(deps): bump golang.org/x/crypto from 0.39.0 to 0.41.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.39.0 to 0.41.0.
- [Commits](https://github.com/golang/crypto/compare/v0.39.0...v0.41.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.41.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:59:54 +02:00
y0n3d4
c62f523e6d Update 020_installation.rst removing command options
Removed command options: their use is a user choice
2025-09-06 21:59:11 +02:00
Michele Testa
91e9f65991 Update 020_installation.rst adding instruction for Gentoo Linux 2025-09-06 21:59:11 +02:00
rhhub
d839850ed4 docs: clarify ** must me between path separators 2025-09-06 21:59:11 +02:00
A Crutcher
ac051c3dcd doc: Correct Wasabi link 2025-09-06 21:59:11 +02:00
Michael Terry
20f472a67f backend/local: ignore chmod "not supported" errors 2025-09-06 21:59:11 +02:00
dependabot[bot]
7b986795de build(deps): bump golang.org/x/time from 0.11.0 to 0.12.0
Bumps [golang.org/x/time](https://github.com/golang/time) from 0.11.0 to 0.12.0.
- [Commits](https://github.com/golang/time/compare/v0.11.0...v0.12.0)

---
updated-dependencies:
- dependency-name: golang.org/x/time
  dependency-version: 0.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:59:11 +02:00
dependabot[bot]
4f03e03b2c build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azidentity
Bumps [github.com/Azure/azure-sdk-for-go/sdk/azidentity](https://github.com/Azure/azure-sdk-for-go) from 1.10.0 to 1.10.1.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/go-mgmt-sdk-release-guideline.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.10.0...sdk/azidentity/v1.10.1)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/azidentity
  dependency-version: 1.10.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:59:11 +02:00
Michael Eischer
242b607bf6 walker: fix error handling if tree cannot be loaded
A tree that cannot be loaded is a fatal error when walking the tree.
Thus, return the error and exit the tree walk.
2025-09-06 21:59:11 +02:00
Michael Eischer
22bbbf42f5 Fix release note typos 2025-09-06 21:59:11 +02:00
dependabot[bot]
3c8fc9d9bc build(deps): bump github.com/peterbourgon/unixtransport
Bumps [github.com/peterbourgon/unixtransport](https://github.com/peterbourgon/unixtransport) from 0.0.4 to 0.0.6.
- [Release notes](https://github.com/peterbourgon/unixtransport/releases)
- [Commits](https://github.com/peterbourgon/unixtransport/compare/v0.0.4...v0.0.6)

---
updated-dependencies:
- dependency-name: github.com/peterbourgon/unixtransport
  dependency-version: 0.0.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:59:11 +02:00
dependabot[bot]
5070e62b18 build(deps): bump golang.org/x/crypto from 0.38.0 to 0.39.0
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.38.0 to 0.39.0.
- [Commits](https://github.com/golang/crypto/compare/v0.38.0...v0.39.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.39.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:59:11 +02:00
Patrick Wolf
d64bad1a90 Update 047_tuning_backup_parameters.rst - local backend (#5355)
users would find it helpful to know how to adjust the "local" backend and they might not get the idea that the local backend is just called local... which in turn leads them to think restic is slow as they can't adjust away  from 2 threads for restore and backup.
2025-09-06 21:54:41 +02:00
Michael Eischer
6bdca9a7d5 add changelog for --stdin-filename with/directory 2025-09-06 21:54:41 +02:00
Michael Eischer
91d582a667 backup: test subdirectories in stdin filenames work 2025-09-06 21:54:41 +02:00
Michael Eischer
ef1e137e7a fs/reader: return proper error on invalid filename 2025-09-06 21:54:41 +02:00
Michael Eischer
81ac49f59d fs/reader: test file not exist case 2025-09-06 21:54:41 +02:00
Michael Eischer
ba2b0b2cc7 fs/reader: use test helpers 2025-09-06 21:54:41 +02:00
Michael Eischer
37a4235e4d fs/reader: deduplicate test code 2025-09-06 21:54:41 +02:00
Michael Eischer
04898e41d1 fs/reader: fix open+stat handling 2025-09-06 21:54:41 +02:00
Michael Eischer
07e4a78e46 fs/reader: use modification time for file and directories
This ensures that a fixed input generates a fully deterministic output
file structure.
2025-09-06 21:54:41 +02:00
Michael Eischer
236f81758e fs: rewrite Reader to build fs tree up front
This adds proper support for filenames that include directories. For
example, `/foo/bar` would result in an error when trying to open `/foo`.

The directory tree is now build upfront. This ensures let's the
directory tree construction be handled only once. All accessors then
only have to look up the constructed directory entries.
2025-09-06 21:54:41 +02:00
Ilya Grigoriev
16850c61fa docs: when describing profiling, briefly explain .pprof files 2025-09-06 21:52:57 +02:00
Ilya Grigoriev
67a572fa0d docs: document profiling options a bit better
Previously, the docs were a bit mysterious about what "enables profiling
support" means or how one could take advantage of it.
2025-09-06 21:52:57 +02:00
Ilya Grigoriev
4686a12a2d bugfix: have --{cpu,mem,...}-profile work even if Restic exits with error code (#5373)
* bugfix: write pprof file for `--{cpu,mem,...}-profile` even on error code

Before this, if `restic backup --cpu-profile dir/ backup-dir/` couldn't
read some of the input files (e.g. they weren't readable by the user
restic was running under), the `cpu.pprof` file it outputs would be
empty.

https://github.com/spf13/cobra/issues/1893

* drop changelog as it's not relevant for end users

---------

Co-authored-by: Michael Eischer <michael.eischer@fau.de>
2025-09-06 21:52:57 +02:00
dependabot[bot]
4dbed5f905 build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/storage/azblob
Bumps [github.com/Azure/azure-sdk-for-go/sdk/storage/azblob](https://github.com/Azure/azure-sdk-for-go) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.6.0...sdk/azcore/v1.6.1)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/storage/azblob
  dependency-version: 1.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:52:57 +02:00
dependabot[bot]
d708c5ea73 build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azidentity
Bumps [github.com/Azure/azure-sdk-for-go/sdk/azidentity](https://github.com/Azure/azure-sdk-for-go) from 1.8.2 to 1.10.0.
- [Release notes](https://github.com/Azure/azure-sdk-for-go/releases)
- [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/go-mgmt-sdk-release-guideline.md)
- [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/azidentity/v1.8.2...sdk/azcore/v1.10.0)

---
updated-dependencies:
- dependency-name: github.com/Azure/azure-sdk-for-go/sdk/azidentity
  dependency-version: 1.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:52:57 +02:00
Mark Lopez
ee0cb7d1aa docs: updated installation docs for Windows 2025-09-06 21:52:57 +02:00
dependabot[bot]
590dc82719 build(deps): bump golang.org/x/sys from 0.31.0 to 0.33.0
Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.31.0 to 0.33.0.
- [Commits](https://github.com/golang/sys/compare/v0.31.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/sys
  dependency-version: 0.33.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-06 21:52:57 +02:00
Samuel Chambers
72d70d94f9 updated doc/faq.rst_commitsSquashed 2025-09-06 21:52:57 +02:00
Markus Hansmair
aaa48e765a doc: typo & minor rewording in 'Removing files from snapshots' 2025-09-06 21:50:54 +02:00
Michael Eischer
f61cf4a1e5 docs: fix typos in developer information (#5329) 2025-09-06 21:50:54 +02:00
Michael Eischer
a22b9d5735 update direct dependencies (#5340) 2025-09-06 21:50:54 +02:00
dependabot[bot]
e9ae67c968 build(deps): bump docker/login-action from 3.3.0 to 3.4.0 (#5333)
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](9780b0c442...74a5d14239)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-06 21:50:54 +02:00
Mohammad Javad Naderi
1fe6fbc4b8 doc: fix typos 2025-09-06 21:50:54 +02:00
Gilbert Gilb's
3d4fb876f4 docs: fix unit for S3 restore timeout
"d" is not a valid unit.
2025-09-06 21:50:54 +02:00
Michael Eischer
5d182ed1ab forget: fix ignored RESTIC_HOST environment variable 2025-09-06 21:50:54 +02:00
44 changed files with 890 additions and 494 deletions

View File

@@ -26,10 +26,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Log in to the Container registry
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}

View File

@@ -57,7 +57,7 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v5
@@ -220,7 +220,7 @@ jobs:
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Go ${{ env.latest_go }}
uses: actions/setup-go@v5
@@ -242,7 +242,7 @@ jobs:
checks: write
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Set up Go ${{ env.latest_go }}
uses: actions/setup-go@v5
@@ -287,7 +287,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: Docker meta
id: meta

View File

@@ -1,5 +1,6 @@
# Table of Contents
* [Changelog for 0.18.1](#changelog-for-restic-0181-2025-09-21)
* [Changelog for 0.18.0](#changelog-for-restic-0180-2025-03-27)
* [Changelog for 0.17.3](#changelog-for-restic-0173-2024-11-08)
* [Changelog for 0.17.2](#changelog-for-restic-0172-2024-10-27)
@@ -39,6 +40,106 @@
* [Changelog for 0.6.0](#changelog-for-restic-060-2017-05-29)
# Changelog for restic 0.18.1 (2025-09-21)
The following sections list the changes in restic 0.18.1 relevant to
restic users. The changes are ordered by importance.
## Summary
* Fix #5324: Correctly handle `backup --stdin-filename` with directory paths
* Fix #5325: Accept `RESTIC_HOST` environment variable in `forget` command
* Fix #5342: Ignore "chmod not supported" errors when writing files
* Fix #5344: Ignore `EOPNOTSUPP` errors for extended attributes
* Fix #5421: Fix rare crash if directory is removed during backup
* Fix #5429: Stop retrying uploads when rest-server runs out of space
* Fix #5467: Improve handling of download retries in `check` command
## Details
* Bugfix #5324: Correctly handle `backup --stdin-filename` with directory paths
In restic 0.18.0, the `backup` command failed if a filename that includes at
least a directory was passed to `--stdin-filename`. For example,
`--stdin-filename /foo/bar` resulted in the following error:
```
Fatal: unable to save snapshot: open /foo: no such file or directory
```
This has now been fixed.
https://github.com/restic/restic/issues/5324
https://github.com/restic/restic/pull/5356
* Bugfix #5325: Accept `RESTIC_HOST` environment variable in `forget` command
The `forget` command did not use the host name from the `RESTIC_HOST`
environment variable when filtering snapshots. This has now been fixed.
https://github.com/restic/restic/issues/5325
https://github.com/restic/restic/pull/5327
* Bugfix #5342: Ignore "chmod not supported" errors when writing files
Restic 0.18.0 introduced a bug that caused `chmod xxx: operation not supported`
errors to appear when writing to a local file repository that did not support
chmod (like CIFS or WebDAV mounted via FUSE). Restic now ignores those errors.
https://github.com/restic/restic/issues/5342
* Bugfix #5344: Ignore `EOPNOTSUPP` errors for extended attributes
Restic 0.18.0 added extended attribute support for NetBSD 10+, but not all
NetBSD filesystems support extended attributes. Other BSD systems can likewise
return `EOPNOTSUPP`, so restic now ignores these errors.
https://github.com/restic/restic/issues/5344
* Bugfix #5421: Fix rare crash if directory is removed during backup
In restic 0.18.0, the `backup` command could crash if a directory was removed
between reading its metadata and listing its directory content. This has now
been fixed.
https://github.com/restic/restic/pull/5421
* Bugfix #5429: Stop retrying uploads when rest-server runs out of space
When rest-server returns a `507 Insufficient Storage` error, it indicates that
no more storage capacity is available. Restic now correctly stops retrying
uploads in this case.
https://github.com/restic/restic/issues/5429
https://github.com/restic/restic/pull/5452
* Bugfix #5467: Improve handling of download retries in `check` command
In very rare cases, the `check` command could unnecessarily report repository
damage if the backend returned incomplete, corrupted data on the first download
try which is afterwards resolved by a download retry.
This could result in an error output like the following:
```
Load(<data/34567890ab>, 33918928, 0) returned error, retrying after 871.35598ms: readFull: unexpected EOF
Load(<data/34567890ab>, 33918928, 0) operation successful after 1 retries
check successful on second attempt, original error pack 34567890ab[...] contains 6 errors: [blob 12345678[...]: decrypting blob <data/12345678> from 34567890 failed: ciphertext verification failed ...]
[...]
Fatal: repository contains errors
```
This fix only applies to a very specific case where the log shows `operation
successful after 1 retries` followed by a `check successful on second attempt,
original error` that only reports `ciphertext verification failed` errors in the
pack file. If any other errors are reported in the pack file, then the
repository still has to be considered as damaged.
Now, only the check result of the last download retry is reported as intended.
https://github.com/restic/restic/issues/5467
https://github.com/restic/restic/pull/5495
# Changelog for restic 0.18.0 (2025-03-27)
The following sections list the changes in restic 0.18.0 relevant to
restic users. The changes are ordered by importance.
@@ -54,7 +155,7 @@ restic users. The changes are ordered by importance.
* Fix #5249: Fix creation of oversized index by `repair index --read-all-packs`
* Fix #5259: Fix rare crash in command output
* Chg #4938: Update dependencies and require Go 1.23 or newer
* Chg #5162: Promote feature flags
* Chg #5162: Graduate feature flags
* Enh #1378: Add JSON support to `check` command
* Enh #2511: Support generating shell completions to stdout
* Enh #3697: Allow excluding online-only cloud files (e.g. OneDrive)
@@ -76,7 +177,7 @@ restic users. The changes are ordered by importance.
* Enh #5173: Add experimental S3 cold storage support
* Enh #5174: Add xattr support for NetBSD 10+
* Enh #5251: Improve retry handling for flaky `rclone` backends
* Enh #52897: Make `recover` automatically rebuild index when needed
* Enh #5287: Make `recover` automatically rebuild index when needed
## Details
@@ -208,7 +309,7 @@ restic users. The changes are ordered by importance.
https://github.com/restic/restic/pull/4938
* Change #5162: Promote feature flags
* Change #5162: Graduate feature flags
The `deprecate-legacy-index`, `deprecate-s3-legacy-layout`,
`explicit-s3-anonymous-auth` and `safe-forget-keep-tags` features are now stable
@@ -408,13 +509,13 @@ restic users. The changes are ordered by importance.
https://github.com/restic/restic/pull/5251
* Enhancement #52897: Make `recover` automatically rebuild index when needed
* Enhancement #5287: Make `recover` automatically rebuild index when needed
When trying to recover data from an interrupted snapshot, it was previously
necessary to manually run `repair index` before runnning `recover`. This now
happens automatically so that only `recover` is necessary.
https://github.com/restic/restic/issues/52897
https://github.com/restic/restic/issues/5287
https://github.com/restic/restic/pull/5296

View File

@@ -1 +1 @@
0.18.0
0.18.1

View File

@@ -4,5 +4,5 @@ When trying to recover data from an interrupted snapshot, it was previously
necessary to manually run `repair index` before runnning `recover`. This now
happens automatically so that only `recover` is necessary.
https://github.com/restic/restic/issues/52897
https://github.com/restic/restic/issues/5287
https://github.com/restic/restic/pull/5296

View File

@@ -1,4 +1,4 @@
Change: Promote feature flags
Change: Graduate feature flags
The `deprecate-legacy-index`, `deprecate-s3-legacy-layout`,
`explicit-s3-anonymous-auth` and `safe-forget-keep-tags` features are

View File

@@ -0,0 +1,14 @@
Bugfix: Correctly handle `backup --stdin-filename` with directory paths
In restic 0.18.0, the `backup` command failed if a filename that includes
at least a directory was passed to `--stdin-filename`. For example,
`--stdin-filename /foo/bar` resulted in the following error:
```
Fatal: unable to save snapshot: open /foo: no such file or directory
```
This has now been fixed.
https://github.com/restic/restic/issues/5324
https://github.com/restic/restic/pull/5356

View File

@@ -0,0 +1,7 @@
Bugfix: Accept `RESTIC_HOST` environment variable in `forget` command
The `forget` command did not use the host name from the `RESTIC_HOST`
environment variable when filtering snapshots. This has now been fixed.
https://github.com/restic/restic/issues/5325
https://github.com/restic/restic/pull/5327

View File

@@ -0,0 +1,7 @@
Bugfix: Ignore "chmod not supported" errors when writing files
Restic 0.18.0 introduced a bug that caused `chmod xxx: operation not supported`
errors to appear when writing to a local file repository that did not support
chmod (like CIFS or WebDAV mounted via FUSE). Restic now ignores those errors.
https://github.com/restic/restic/issues/5342

View File

@@ -0,0 +1,7 @@
Bugfix: Ignore `EOPNOTSUPP` errors for extended attributes
Restic 0.18.0 added extended attribute support for NetBSD 10+, but not all
NetBSD filesystems support extended attributes. Other BSD systems can
likewise return `EOPNOTSUPP`, so restic now ignores these errors.
https://github.com/restic/restic/issues/5344

View File

@@ -0,0 +1,8 @@
Bugfix: Stop retrying uploads when rest-server runs out of space
When rest-server returns a `507 Insufficient Storage` error, it indicates
that no more storage capacity is available. Restic now correctly stops
retrying uploads in this case.
https://github.com/restic/restic/issues/5429
https://github.com/restic/restic/pull/5452

View File

@@ -0,0 +1,27 @@
Bugfix: Improve handling of download retries in `check` command
In very rare cases, the `check` command could unnecessarily report repository
damage if the backend returned incomplete, corrupted data on the first download
try which is afterwards resolved by a download retry.
This could result in an error output like the following:
```
Load(<data/34567890ab>, 33918928, 0) returned error, retrying after 871.35598ms: readFull: unexpected EOF
Load(<data/34567890ab>, 33918928, 0) operation successful after 1 retries
check successful on second attempt, original error pack 34567890ab[...] contains 6 errors: [blob 12345678[...]: decrypting blob <data/12345678> from 34567890 failed: ciphertext verification failed ...]
[...]
Fatal: repository contains errors
```
This fix only applies to a very specific case where the log shows
`operation successful after 1 retries` followed by a
`check successful on second attempt, original error` that only reports
`ciphertext verification failed` errors in the pack file. If any other errors
are reported in the pack file, then the repository still has to be considered
as damaged.
Now, only the check result of the last download retry is reported as intended.
https://github.com/restic/restic/issues/5467
https://github.com/restic/restic/pull/5495

View File

@@ -0,0 +1,7 @@
Bugfix: Fix rare crash if directory is removed during backup
In restic 0.18.0, the `backup` command could crash if a directory was removed
between reading its metadata and listing its directory content. This has now
been fixed.
https://github.com/restic/restic/pull/5421

View File

@@ -591,11 +591,12 @@ func runBackup(ctx context.Context, opts BackupOptions, gopts GlobalOptions, ter
return err
}
}
targetFS = &fs.Reader{
ModTime: timeStamp,
Name: filename,
Mode: 0644,
ReadCloser: source,
targetFS, err = fs.NewReader(filename, source, fs.ReaderOptions{
ModTime: timeStamp,
Mode: 0644,
})
if err != nil {
return fmt.Errorf("failed to backup from stdin: %w", err)
}
targets = []string{filename}
}

View File

@@ -632,12 +632,15 @@ func TestStdinFromCommand(t *testing.T) {
testSetupBackupData(t, env)
opts := BackupOptions{
StdinCommand: true,
StdinFilename: "stdin",
StdinCommand: true,
// test that subdirectories are handled correctly
StdinFilename: "stdin/subdir/file",
}
testRunBackup(t, filepath.Dir(env.testdata), []string{"python", "-c", "import sys; print('something'); sys.exit(0)"}, opts, env.gopts)
testListSnapshots(t, env.gopts, 1)
snapshots := testListSnapshots(t, env.gopts, 1)
files := testRunLs(t, env.gopts, snapshots[0].String())
rtest.Assert(t, includes(files, "/stdin/subdir/file"), "file %q missing from snapshot, got %v", "stdin/subdir/file", files)
testRunCheck(t, env.gopts)
}

View File

@@ -137,13 +137,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}

View File

@@ -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)
}

View File

@@ -46,7 +46,7 @@ import (
// to a missing backend storage location or config file
var ErrNoRepository = errors.New("repository does not exist")
var version = "0.18.0"
var version = "0.18.1"
// TimeFormat is the format used for all timestamps printed by restic.
const TimeFormat = "2006-01-02 15:04:05"

View File

@@ -30,14 +30,12 @@ func registerProfiling(cmd *cobra.Command) {
return profiler.Start(profiler.opts)
}
origPostRun := cmd.PersistentPostRunE
cmd.PersistentPostRunE = func(cmd *cobra.Command, args []string) error {
// Once https://github.com/spf13/cobra/issues/1893 is fixed,
// this could use PersistentPostRunE instead of OnFinalize,
// reverting https://github.com/restic/restic/pull/5373.
cobra.OnFinalize(func() {
profiler.Stop()
if origPostRun != nil {
return origPostRun(cmd, args)
}
return nil
}
})
profiler.opts.AddFlags(cmd.PersistentFlags())
}

View File

@@ -74,6 +74,16 @@ avoid any conflicts:
$ dnf copr remove copart/restic
Gentoo Linux
============
On `Gentoo Linux <https://www.gentoo.org/>`__, you can install the ``restic``
package from the official repos using ``emerge``:
.. code-block:: console
# emerge restic
macOS
=====
@@ -175,15 +185,19 @@ restic can be installed from the official repo of Solus via the ``eopkg`` packag
Windows
=======
restic can be installed using `Scoop <https://scoop.sh/>`__:
restic can be installed using either `Scoop <https://scoop.sh/>`__ or `WinGet <https://learn.microsoft.com/en-us/windows/package-manager/>`__.
Regardless of the method, the ``restic.exe`` binary will be added to your ``PATH`` automatically, making the ``restic`` command accessible in Powershell or CMD.
.. code-block:: console
scoop install restic
Using this installation method, ``restic.exe`` will automatically be available
in the ``PATH``. It can be called from cmd.exe or PowerShell by typing ``restic``.
.. code-block:: console
winget install --exact --id restic.restic --scope Machine
By default, WinGet will install restic into the ``User`` scope, which is typically in your user's ``%LOCALAPPDATA%`` directory. This behavior may be undesirable for system-wide backups, so specifying ``--scope Machine`` is recommended so that restic is installed into ``%ProgramFiles%``. This requires elevation.
.. _official_binaries:
@@ -253,13 +267,6 @@ the `restic beta download site
and ready to run, and a new version is built every time a push is made to the
master branch.
Windows
=======
On Windows, put the `restic.exe` binary into `%SystemRoot%\\System32` to use restic
in scripts without the need for absolute paths to the binary. This requires
administrator rights.
Docker Container
****************

View File

@@ -349,7 +349,7 @@ Wasabi
S3 storage from `Wasabi <https://wasabi.com>`__ can be used as follows.
- Determine the correct Wasabi service URL for your bucket `here <https://wasabi-support.zendesk.com/hc/en-us/articles/360015106031-What-are-the-service-URLs-for-Wasabi-s-different-regions->`__.
- Determine the correct Wasabi service URL for your bucket `here <https://docs.wasabi.com/v1/docs/what-are-the-service-urls-for-wasabi-s-different-storage-regions>`__.
- Set environment variables with the necessary account credentials
.. code-block:: console
@@ -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.

View File

@@ -346,9 +346,10 @@ A trailing ``/`` is ignored, a leading ``/`` anchors the pattern at the root dir
This means, ``/bin`` matches ``/bin/bash`` but does not match ``/usr/bin/restic``.
Regular wildcards cannot be used to match over the directory separator ``/``,
e.g. ``b*ash`` matches ``/bin/bash`` but does not match ``/bin/ash``. For this,
the special wildcard ``**`` can be used to match arbitrary sub-directories: The
pattern ``foo/**/bar`` matches:
e.g. ``b*ash`` matches ``/bin/bash`` but does not match ``/bin/ash``. To match
across an arbitrary number of subdirectories, use the special ``**`` wildcard.
The ``**`` must be positioned between path separators. The pattern
``foo/**/bar`` matches:
* ``/dir1/foo/dir2/bar/file``
* ``/foo/bar/file``

View File

@@ -297,7 +297,7 @@ Note that it is not possible to change the chunker parameters of an existing rep
Removing files from snapshots
=============================
Snapshots sometimes turn out to include more files that intended. Instead of
Snapshots sometimes turn out to include more files than intended. Instead of
removing the snapshots entirely and running the corresponding backup commands
again (which is not always practical after the fact) it is possible to remove
the unwanted files from affected snapshots by rewriting them using the
@@ -338,8 +338,8 @@ the only fields added are ``TotalFilesProcessed`` and ``TotalBytesProcessed``.
By default, the ``rewrite`` command will keep the original snapshots and create
new ones for every snapshot which was modified during rewriting. The new
snapshots are marked with the tag ``rewrite`` to differentiate them from the
original, rewritten snapshots.
snapshots are marked with the tag ``rewrite`` to distinguish them from the
original, untouched snapshots.
Alternatively, you can use the ``--forget`` option to immediately remove the
original snapshots. In this case, no tag is added to the new snapshots. Please

View File

@@ -34,11 +34,12 @@ Backend Connections
Restic uses a global limit for the number of concurrent connections to a backend.
This limit can be configured using ``-o <backend-name>.connections=5``, for example for
the REST backend the parameter would be ``-o rest.connections=5``. By default restic uses
``5`` connections for each backend, except for the local backend which uses a limit of ``2``.
The defaults should work well in most cases. For high-latency backends it can be beneficial
to increase the number of connections. Please be aware that this increases the resource
consumption of restic and that a too high connection count *will degrade performance*.
the REST backend the parameter would be ``-o rest.connections=5`` or for the local backend
``-o local.connections=2``. By default restic uses ``5`` connections for each backend,
except for the local backend which uses a limit of ``2``. The defaults should work well in
most cases. For high-latency backends it can be beneficial to increase the number of
connections. Please be aware that this increases the resource consumption of restic and
that a too high connection count *will degrade performance*.
CPU Usage

View File

@@ -71,8 +71,17 @@ The program can be built with debug support like this:
$ go run build.go -tags debug
This will make the ``restic debug <subcommand>`` available which can be used to
inspect internal data structures. In addition, this enables profiling support
which can help with investigation performance and memory usage issues.
inspect internal data structures.
In addition, this enables profiling flags such as ``--cpu-profile`` and
``--mem-profile`` which can help with investigation performance and memory usage
issues. See ``restic help`` for more details and a few additional
``--...-profile`` flags.
Running Restic with profiling enabled generates a ``.pprof`` file such as
``cpu.pprof``. To view a profile in a web browser, first make sure that the
``dot`` command from `Graphviz <https://graphviz.org/>`__ is in the PATH. Then,
run ``go tool pprof -http : cpu.pprof``.
************
@@ -121,14 +130,17 @@ Backward compatibility for backups is important so that our users are
always able to restore saved data. Therefore restic follows `Semantic
Versioning <https://semver.org>`__ to clearly define which versions are
compatible. The repository and data structures contained therein are
considered the "Public API" in the sense of Semantic Versioning. This
goes for all released versions of restic, this may not be the case for
the master branch.
considered the "Public API" in the sense of Semantic Versioning.
We guarantee backward compatibility of all repositories within one major
version; as long as we do not increment the major version, data can be
read and restored. We strive to be fully backward compatible to all
prior versions.
Once version 1.0.0 is released, we guarantee backward compatibility of
all repositories within one major version; as long as we do not
increment the major version, data can be read and restored. We strive
to be fully backward compatible to all prior versions.
During initial development (versions prior to 1.0.0), maintainers and
developers will do their utmost to keep backwards compatibility and
stability, although there might be breaking changes without increasing
the major version.
**********************
Building documentation

View File

@@ -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``.

View File

@@ -110,9 +110,8 @@ How can I specify encryption passwords automatically?
When you run ``restic backup``, you need to enter the passphrase on
the console. This is not very convenient for automated backups, so you
can also provide the password through the ``--password-file`` option, or one of
the environment variables ``RESTIC_PASSWORD`` or ``RESTIC_PASSWORD_FILE``.
A discussion is in progress over implementing unattended backups happens in
:issue:`533`.
the environment variables: ``RESTIC_PASSWORD``, ``RESTIC_PASSWORD_FILE``,
or ``RESTIC_PASSWORD_COMMAND``.
.. important:: Be careful how you set the environment; using the env
command, a `system()` call or using inline shell
@@ -124,10 +123,33 @@ A discussion is in progress over implementing unattended backups happens in
`accessible only to that user`_. Please make sure that
the permissions on the files where the password is
eventually stored are safe (e.g. `0600` and owned by
root).
root). Note also that ``RESTIC_PASSWORD_COMMAND`` is
safe because it does not export the password itself to
the environment.
.. _accessible only to that user: https://security.stackexchange.com/questions/14000/environment-variable-accessibility-in-linux/14009#14009
On platforms with an available keychain, keyring or similar secret store, a
user can add and then dynamically retrieve passwords, cloud credentials,
repository paths, or any other data deemed sensitive. Here's an example of
part of a shell script using the `built-in`_ ``security`` command on macOS
to retrieve credentials from the system's Keychain before running various
``restic`` commands:
.. _built-in: https://ss64.com/mac/security.html
::
export GOOGLE_PROJECT_ID=$(security find-generic-password -a resticGCS -s restic_project_ID -w)
export GOOGLE_APPLICATION_CREDENTIALS=$(security find-generic-password -a resticGCS -s restic_key -w)
export RESTIC_REPOSITORY=$(security find-generic-password -a resticGCS -s restic_repo_path -w)
export RESTIC_PASSWORD_COMMAND='security find-generic-password -a resticGCS -s restic_pwd -w'
How to prioritize restic's IO and CPU time
------------------------------------------
@@ -253,7 +275,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:**

107
go.mod
View File

@@ -7,10 +7,10 @@ go 1.23.0
godebug winsymlink=0
require (
cloud.google.com/go/storage v1.51.0
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0
cloud.google.com/go/storage v1.56.1
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2
github.com/Backblaze/blazer v0.7.2
github.com/Microsoft/go-winio v0.6.2
github.com/anacrolix/fuse v0.3.1
@@ -21,42 +21,42 @@ 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/ncw/swift/v2 v2.0.3
github.com/peterbourgon/unixtransport v0.0.4
github.com/minio/minio-go/v7 v7.0.95
github.com/ncw/swift/v2 v2.0.4
github.com/peterbourgon/unixtransport v0.0.6
github.com/pkg/errors v0.9.1
github.com/pkg/profile v1.7.0
github.com/pkg/sftp v1.13.8
github.com/pkg/xattr v0.4.10
github.com/pkg/sftp v1.13.9
github.com/pkg/xattr v0.4.12
github.com/restic/chunker v0.4.0
github.com/spf13/cobra v1.9.1
github.com/spf13/pflag v1.0.6
github.com/spf13/cobra v1.10.1
github.com/spf13/pflag v1.0.10
go.uber.org/automaxprocs v1.6.0
golang.org/x/crypto v0.36.0
golang.org/x/net v0.37.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
golang.org/x/crypto v0.41.0
golang.org/x/net v0.43.0
golang.org/x/oauth2 v0.30.0
golang.org/x/sync v0.16.0
golang.org/x/sys v0.35.0
golang.org/x/term v0.34.0
golang.org/x/text v0.28.0
golang.org/x/time v0.12.0
google.golang.org/api v0.248.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/compute/metadata v0.6.0 // indirect
cloud.google.com/go/iam v1.4.1 // indirect
cloud.google.com/go/monitoring v1.24.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 // indirect
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
cel.dev/expr v0.24.0 // indirect
cloud.google.com/go v0.121.6 // indirect
cloud.google.com/go/auth v0.16.5 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.8.0 // indirect
cloud.google.com/go/iam v1.5.2 // indirect
cloud.google.com/go/monitoring v1.24.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
@@ -64,38 +64,43 @@ require (
github.com/felixge/fgprof v0.9.3 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/googleapis/gax-go/v2 v2.15.0 // 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.11 // 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
github.com/minio/crc64nvme v1.0.2 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/philhofer/fwd v1.2.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
github.com/tinylib/msgp v1.3.0 // indirect
github.com/zeebo/errs v1.4.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect
go.opentelemetry.io/otel v1.34.0 // indirect
go.opentelemetry.io/otel/metric v1.34.0 // indirect
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.34.0 // indirect
go.opentelemetry.io/otel/trace v1.34.0 // indirect
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
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
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/sdk v1.36.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
google.golang.org/grpc v1.74.2 // indirect
google.golang.org/protobuf v1.36.7 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

249
go.sum
View File

@@ -1,51 +1,51 @@
cel.dev/expr v0.19.2 h1:V354PbqIXr9IQdwy4SYA4xa0HXaWq1BUPAGzugBY5V4=
cel.dev/expr v0.19.2/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
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/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=
cloud.google.com/go/iam v1.4.1/go.mod h1:2vUEJpUG3Q9p2UdsyksaKpDzlwOrnMzS30isdReIcLM=
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
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.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
cloud.google.com/go/logging v1.13.0 h1:7j0HgAp0B94o1YRDqiqm26w4q1rDMH7XNRU34lJXHYc=
cloud.google.com/go/logging v1.13.0/go.mod h1:36CoKh6KA/M0PbhPKMq6/qety2DCAErbhXT62TuXALA=
cloud.google.com/go/longrunning v0.6.5 h1:sD+t8DO8j4HKW4QfouCklg7ZC1qC4uzVZt8iz3uTW+Q=
cloud.google.com/go/longrunning v0.6.5/go.mod h1:Et04XK+0TTLKa5IPYryKf5DkpwImy6TluQ1QTLwlKmY=
cloud.google.com/go/monitoring v1.24.0 h1:csSKiCJ+WVRgNkRzzz3BPoGjFhjPY23ZTcaenToJxMM=
cloud.google.com/go/monitoring v1.24.0/go.mod h1:Bd1PRK5bmQBQNnuGwHBfUamAV1ys9049oEPHnn4pcsc=
cloud.google.com/go/storage v1.51.0 h1:ZVZ11zCiD7b3k+cH5lQs/qcNaoSz3U9I0jgwVzqDlCw=
cloud.google.com/go/storage v1.51.0/go.mod h1:YEJfu/Ki3i5oHC/7jyTgsGZwdQ8P9hqMqvpi5kRKGgc=
cloud.google.com/go/trace v1.11.3 h1:c+I4YFjxRQjvAhRmSsmjpASUKq88chOX854ied0K/pE=
cloud.google.com/go/trace v1.11.3/go.mod h1:pt7zCYiDSQjC9Y2oqCsh9jF4GStB/hmjrYLsxRR27q8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 h1:DSDNVxqkoXJiko6x8a90zidoYqnYYa6c1MTzDKzKkTo=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM=
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
cloud.google.com/go/storage v1.56.1 h1:n6gy+yLnHn0hTwBFzNn8zJ1kqWfR91wzdM8hjRF4wP0=
cloud.google.com/go/storage v1.56.1/go.mod h1:C9xuCZgFl3buo2HZU/1FncgvvOgTAs/rnh4gF4lMg0s=
cloud.google.com/go/trace v1.11.6 h1:2O2zjPzqPYAHrn3OKl029qlqG6W8ZdYaOWRyr8NgMT4=
cloud.google.com/go/trace v1.11.6/go.mod h1:GA855OeDEBiBMzcckLPE2kDunIpC72N+Pq8WFieFjnI=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0 h1:ci6Yd6nysBRLEodoziB6ah1+YOzZbZk+NYneoA6q+6E=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.0/go.mod h1:QyVsSSN64v5TGltphKLQ2sQxe4OBQg0J1eKRcVBnfgE=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0 h1:MhRfI58HblXzCtWEZCO0feHs8LweePB3s90r7WaR1KU=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.11.0/go.mod h1:okZ+ZURbArNdlJ+ptXoyHNuOETzOl1Oww19rm8I2WLA=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 h1:UXT0o77lXQrikd1kgwIPQOUect7EoR/+sbP4wQKdzxM=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0/go.mod h1:cTvi54pg19DoT07ekoeMgE/taAwNtCShVeZqA+Iv2xI=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1 h1:/Zt+cDPnpC3OVDm/JKLOs7M2DKmLRIIp3XIx9pHHiig=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.8.1/go.mod h1:Ng3urmn6dYe8gnbCMoHHVl5APYz2txho3koEkV2o2HA=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2 h1:FwladfywkNirM+FZYLBR2kBz5C8Tg0fw5w5Y7meRXWI=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.2/go.mod h1:vv5Ad0RrIoT1lJFdWBZwt4mB1+j+V8DUroixmKDTCdk=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 h1:H5xDQaE3XowWfhZRUpnfC+rGZMEVoSiji+b+/HFAPU4=
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 h1:oygO0locgZJe7PpYPXT5A29ZkwJaPqcva7BVeemZOZs=
github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/Backblaze/blazer v0.7.2 h1:UWNHMLB+Nf+UmbO2qkVvgriODLEMz4kIyr2Hm+DVXQM=
github.com/Backblaze/blazer v0.7.2/go.mod h1:T4y3EYa9IQ5J0PKc/C/J8/CEnSd3qa/lgNw938wZg10=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 h1:3c8yed4lgqTt+oTQ+JNMDo+F4xprBf+O/il4ZC0nRLw=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0 h1:fYE9p3esPxA/C0rQ0AHhP0drtPXDRhaWiwg1DPqO7IU=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.51.0/go.mod h1:BnBReJLvVYx2CS/UHOgVz2BXKXD9wsQPxZug20nZhd0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0 h1:OqVGm6Ei3x5+yZmSJG1Mh2NwHvpVmZ08CB5qJhT9Nuk=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.51.0/go.mod h1:SZiPHWGOOk3bl8tkevxkoiwPgsIl6CwrWcbwjfHZpdM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0 h1:6/0iUd0xrnX7qt+mLNRwg5c0PGv8wpE8K90ryANQwMI=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.51.0/go.mod h1:otE2jQekW/PqXk1Awf5lmfokJx4uwuqcj1ab5SpGeW0=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0 h1:4LP6hvB4I5ouTbGgWtixJhgED6xdf67twf9PoY96Tbg=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.53.0/go.mod h1:jUZ5LYlw40WMd07qxcQJD5M40aUxrfwqQX1g7zxYnrQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ=
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo=
github.com/Julusian/godocdown v0.0.0-20170816220326-6d19f8ff2df8/go.mod h1:INZr5t32rG59/5xeltqoCJoNY7e5x/3xoY9WSWVWg74=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
@@ -65,16 +65,15 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q6pvyM49i9XZAv9dDrkDA7gjk=
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/dvyukov/go-fuzz v0.0.0-20220726122315-1d375ef9f9f6/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
@@ -96,17 +95,19 @@ github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw
github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -124,20 +125,20 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q=
github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA=
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
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.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
github.com/klauspost/cpuid/v2 v2.2.11/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=
@@ -151,19 +152,21 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
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/crc64nvme v1.0.2 h1:6uO1UxGAD+kwqWWp7mBFsi5gAse66C4NXO8cmcVculg=
github.com/minio/crc64nvme v1.0.2/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/ncw/swift/v2 v2.0.3 h1:8R9dmgFIWs+RiVlisCEfiQiik1hjuR0JnOkLxaP9ihg=
github.com/ncw/swift/v2 v2.0.3/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
github.com/minio/minio-go/v7 v7.0.95 h1:ywOUPg+PebTMTzn9VDsoFJy32ZuARN9zhB+K3IYEvYU=
github.com/minio/minio-go/v7 v7.0.95/go.mod h1:wOOX3uxS334vImCNRVyIDdXX9OsXDm89ToynKgqUKlo=
github.com/ncw/swift/v2 v2.0.4 h1:hHWVFxn5/YaTWAASmn4qyq2p6OyP/Hm3vMLzkjEqR7w=
github.com/ncw/swift/v2 v2.0.4/go.mod h1:cbAO76/ZwcFrFlHdXPjaqWZ9R7Hdar7HpjRXBfbjigk=
github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/peterbourgon/ff/v3 v3.3.1/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
github.com/peterbourgon/unixtransport v0.0.4 h1:UTF0FxXCAglvoZz9jaGPYjEg52DjBLDYGMJvJni6Tfw=
github.com/peterbourgon/unixtransport v0.0.4/go.mod h1:o8aUkOCa8W/BIXpi15uKvbSabjtBh0JhSOJGSfoOhAU=
github.com/peterbourgon/unixtransport v0.0.6 h1:sWIViDoRIg2MeyRbWTUDdvvY5XbKaaSr9ionmzNGXWY=
github.com/peterbourgon/unixtransport v0.0.6/go.mod h1:o8aUkOCa8W/BIXpi15uKvbSabjtBh0JhSOJGSfoOhAU=
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -171,18 +174,17 @@ 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/xattr v0.4.10 h1:Qe0mtiNFHQZ296vRgUjRCoPHPqH7VdTOrZx3g0T+pGA=
github.com/pkg/xattr v0.4.10/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
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.12 h1:rRTkSyFNTRElv6pkA3zpjHpQ90p/OdHQC1GmGh1aTjM=
github.com/pkg/xattr v0.4.12/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E=
github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/restic/chunker v0.4.0 h1:YUPYCUn70MYP7VO4yllypp2SjmsRhRJaad3xKu1QFRw=
github.com/restic/chunker v0.4.0/go.mod h1:z0cH2BejpW636LXw0R/BGyv+Ey8+m9QGiOanDHItzyw=
github.com/robertkrimen/godocdown v0.0.0-20130622164427-0bfa04905481/go.mod h1:C9WhFzY47SzYBIvzFqSvHIR6ROgDo4TtdTuRaOMjF/s=
@@ -195,10 +197,13 @@ github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -210,30 +215,34 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww=
github.com/tinylib/msgp v1.3.0/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 h1:JRxssobiPg23otYU5SbWtQC//snGVIM3Tx6QRzlQBao=
go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY=
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0/go.mod h1:BLbf7zbNIONBLPwvFnwNHGj4zge8uTCM/UPIVW1Mq2I=
go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ=
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A=
go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU=
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0 h1:rixTyDGXFxRy1xzhKrotaHy3/KXdPhlWARrCgK+eqUY=
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.36.0/go.mod h1:dowW6UsM9MKbJq5JTz2AMVp3/5iW5I/TStsk8S+CfHw=
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -243,8 +252,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/exp v0.0.0-20220428152302-39d4317da171 h1:TfdoLivD44QwvssI9Sv1xwa5DcL5XQr4au4sZ2F2NV4=
golang.org/x/exp v0.0.0-20220428152302-39d4317da171/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
@@ -266,10 +275,10 @@ 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/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -278,8 +287,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -299,8 +308,8 @@ golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -311,8 +320,8 @@ golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -324,10 +333,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
@@ -339,18 +348,18 @@ 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/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=
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c=
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/api v0.248.0 h1:hUotakSkcwGdYUqzCRc5yGYsg4wXxpkKlW5ryVqvC1Y=
google.golang.org/api v0.248.0/go.mod h1:yAFUAF56Li7IuIQbTFoLwXTCI6XCFKueOlS7S9e4F9k=
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
google.golang.org/protobuf v1.36.7/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=

View File

@@ -264,6 +264,11 @@ func (arch *Archiver) trackItem(item string, previous, current *restic.Node, s I
// nodeFromFileInfo returns the restic node from an os.FileInfo.
func (arch *Archiver) nodeFromFileInfo(snPath, filename string, meta ToNoder, ignoreXattrListError bool) (*restic.Node, error) {
node, err := meta.ToNode(ignoreXattrListError)
// node does not exist. This prevents all further processing for this file.
// If an error and a node are returned, then preserve as much data as possible (see below).
if err != nil && node == nil {
return nil, err
}
if !arch.WithAtime {
node.AccessTime = node.ModTime
}
@@ -718,8 +723,14 @@ func (arch *Archiver) saveTree(ctx context.Context, snPath string, atree *tree,
arch.trackItem(snItem, oldNode, n, is, time.Since(start))
})
if err != nil {
err = arch.error(join(snPath, name), err)
if err == nil {
// ignore error
continue
}
return futureNode{}, 0, err
}
nodes = append(nodes, fn)
}

View File

@@ -174,12 +174,11 @@ func TestArchiverSaveFileReaderFS(t *testing.T) {
ts := time.Now()
filename := "xx"
readerFs := &fs.Reader{
ModTime: ts,
Mode: 0123,
Name: filename,
ReadCloser: io.NopCloser(strings.NewReader(test.Data)),
}
readerFs, err := fs.NewReader(filename, io.NopCloser(strings.NewReader(test.Data)), fs.ReaderOptions{
ModTime: ts,
Mode: 0123,
})
rtest.OK(t, err)
node, stats := saveFile(t, repo, filename, readerFs)
@@ -288,13 +287,11 @@ func TestArchiverSaveReaderFS(t *testing.T) {
ts := time.Now()
filename := "xx"
readerFs := &fs.Reader{
ModTime: ts,
Mode: 0123,
Name: filename,
ReadCloser: io.NopCloser(strings.NewReader(test.Data)),
}
readerFs, err := fs.NewReader(filename, io.NopCloser(strings.NewReader(test.Data)), fs.ReaderOptions{
ModTime: ts,
Mode: 0123,
})
rtest.OK(t, err)
arch := New(repo, readerFs, Options{})
arch.Error = func(item string, err error) error {
t.Errorf("archiver error for %v: %v", item, err)
@@ -1849,8 +1846,8 @@ func TestArchiverParent(t *testing.T) {
func TestArchiverErrorReporting(t *testing.T) {
ignoreErrorForBasename := func(basename string) ErrorFunc {
return func(item string, err error) error {
if filepath.Base(item) == "targetfile" {
t.Logf("ignoring error for targetfile: %v", err)
if filepath.Base(item) == basename {
t.Logf("ignoring error for %v: %v", basename, err)
return nil
}
@@ -1873,12 +1870,13 @@ func TestArchiverErrorReporting(t *testing.T) {
}
var tests = []struct {
name string
src TestDir
want TestDir
prepare func(t testing.TB)
errFn ErrorFunc
mustError bool
name string
targets []string
src TestDir
want TestDir
prepare func(t testing.TB)
errFn ErrorFunc
errStr []string
}{
{
name: "no-error",
@@ -1891,8 +1889,8 @@ func TestArchiverErrorReporting(t *testing.T) {
src: TestDir{
"targetfile": TestFile{Content: "foobar"},
},
prepare: chmodUnreadable("targetfile"),
mustError: true,
prepare: chmodUnreadable("targetfile"),
errStr: []string{"open targetfile: permission denied"},
},
{
name: "file-unreadable-ignore-error",
@@ -1913,8 +1911,8 @@ func TestArchiverErrorReporting(t *testing.T) {
"targetfile": TestFile{Content: "foobar"},
},
},
prepare: chmodUnreadable("subdir/targetfile"),
mustError: true,
prepare: chmodUnreadable("subdir/targetfile"),
errStr: []string{"open subdir/targetfile: permission denied"},
},
{
name: "file-subdir-unreadable-ignore-error",
@@ -1932,6 +1930,20 @@ func TestArchiverErrorReporting(t *testing.T) {
prepare: chmodUnreadable("subdir/targetfile"),
errFn: ignoreErrorForBasename("targetfile"),
},
{
name: "parent-dir-missing",
targets: []string{"subdir/missing"},
src: TestDir{},
errStr: []string{"stat subdir: no such file or directory", "CreateFile subdir: The system cannot find the file specified"},
},
{
name: "parent-dir-missing-filtered",
targets: []string{"targetfile", "subdir/missing"},
src: TestDir{
"targetfile": TestFile{Content: "foobar"},
},
errFn: ignoreErrorForBasename("subdir"),
},
}
for _, test := range tests {
@@ -1951,14 +1963,21 @@ func TestArchiverErrorReporting(t *testing.T) {
arch := New(repo, fs.Track{FS: fs.Local{}}, Options{})
arch.Error = test.errFn
_, snapshotID, _, err := arch.Snapshot(ctx, []string{"."}, SnapshotOptions{Time: time.Now()})
if test.mustError {
if err != nil {
t.Logf("found expected error (%v), skipping further checks", err)
return
target := test.targets
if len(target) == 0 {
target = []string{"."}
}
_, snapshotID, _, err := arch.Snapshot(ctx, target, SnapshotOptions{Time: time.Now()})
if test.errStr != nil {
// check if any of the expected errors are contained in the error message
for _, errStr := range test.errStr {
if strings.Contains(err.Error(), errStr) {
t.Logf("found expected error (%v)", err)
return
}
}
t.Fatalf("expected error not returned by archiver")
t.Fatalf("expected error (%v) not returned by archiver, got (%v)", test.errStr, err)
return
}

View File

@@ -43,5 +43,12 @@ func isMacENOTTY(err error) bool {
// set file to readonly
func setFileReadonly(f string, mode os.FileMode) error {
return os.Chmod(f, mode&^0222)
err := os.Chmod(f, mode&^0222)
// ignore the error if the FS does not support setting this mode (e.g. CIFS with gvfs on Linux)
if err != nil && errors.Is(err, errors.ErrUnsupported) {
return nil
}
return err
}

View File

@@ -182,7 +182,7 @@ func (b *Backend) IsPermanentError(err error) bool {
var rerr *restError
if errors.As(err, &rerr) {
if rerr.StatusCode == http.StatusRequestedRangeNotSatisfiable || rerr.StatusCode == http.StatusUnauthorized || rerr.StatusCode == http.StatusForbidden {
if rerr.StatusCode == http.StatusRequestedRangeNotSatisfiable || rerr.StatusCode == http.StatusUnauthorized || rerr.StatusCode == http.StatusForbidden || rerr.StatusCode == http.StatusInsufficientStorage {
return true
}
}

View File

@@ -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)"`

View File

@@ -293,7 +293,7 @@ type errorBackend struct {
func (b errorBackend) Load(ctx context.Context, h backend.Handle, length int, offset int64, consumer func(rd io.Reader) error) error {
return b.Backend.Load(ctx, h, length, offset, func(rd io.Reader) error {
if b.ProduceErrors {
return consumer(errorReadCloser{rd})
return consumer(errorReadCloser{Reader: rd})
}
return consumer(rd)
})
@@ -301,12 +301,21 @@ func (b errorBackend) Load(ctx context.Context, h backend.Handle, length int, of
type errorReadCloser struct {
io.Reader
shortenBy int
maxErrorOffset int // if 0, the error can be injected at any offset
}
func (erd errorReadCloser) Read(p []byte) (int, error) {
n, err := erd.Reader.Read(p)
if n > 0 {
induceError(p[:n])
maxOffset := n
if erd.maxErrorOffset > 0 {
maxOffset = min(erd.maxErrorOffset, maxOffset)
}
induceError(p[:maxOffset])
}
if n > erd.shortenBy {
n -= erd.shortenBy
}
return n, err
}
@@ -320,17 +329,26 @@ func induceError(data []byte) {
// errorOnceBackend randomly modifies data when reading a file for the first time.
type errorOnceBackend struct {
backend.Backend
m sync.Map
m sync.Map
shortenBy int
maxErrorOffset int
}
func (b *errorOnceBackend) Load(ctx context.Context, h backend.Handle, length int, offset int64, consumer func(rd io.Reader) error) error {
_, isRetry := b.m.LoadOrStore(h, struct{}{})
return b.Backend.Load(ctx, h, length, offset, func(rd io.Reader) error {
err := b.Backend.Load(ctx, h, length, offset, func(rd io.Reader) error {
if !isRetry && h.Type != restic.ConfigFile {
return consumer(errorReadCloser{rd})
return consumer(errorReadCloser{Reader: rd, shortenBy: b.shortenBy, maxErrorOffset: b.maxErrorOffset})
}
return consumer(rd)
})
if err == nil {
return nil
}
// retry if the consumer returned an error
return b.Backend.Load(ctx, h, length, offset, func(rd io.Reader) error {
return consumer(rd)
})
}
func TestCheckerModifiedData(t *testing.T) {
@@ -368,6 +386,15 @@ func TestCheckerModifiedData(t *testing.T) {
}
},
},
{
// ignore if a backend returns incomplete garbled data on the first try
"corruptPartialOnceBackend",
&errorOnceBackend{Backend: be, shortenBy: 10, maxErrorOffset: 100},
func() {},
func(t *testing.T, err error) {
test.Assert(t, err == nil, "unexpected error found, got %v", err)
},
},
} {
t.Run(test.name, func(t *testing.T) {
checkRepo := repository.TestOpenBackend(t, test.be)

View File

@@ -19,97 +19,135 @@ import (
// be opened once, all subsequent open calls return syscall.EIO. For Lstat(),
// the provided FileInfo is returned.
type Reader struct {
Name string
io.ReadCloser
items map[string]readerItem
}
// for FileInfo
type ReaderOptions struct {
Mode os.FileMode
ModTime time.Time
Size int64
AllowEmptyFile bool
}
open sync.Once
type readerItem struct {
open *sync.Once
fi *ExtendedFileInfo
rc io.ReadCloser
allowEmptyFile bool
children []string
}
// statically ensure that Local implements FS.
var _ FS = &Reader{}
func NewReader(name string, r io.ReadCloser, opts ReaderOptions) (*Reader, error) {
items := make(map[string]readerItem)
name = readerCleanPath(name)
if name == "/" {
return nil, fmt.Errorf("invalid filename specified")
}
isFile := true
for {
if isFile {
fi := &ExtendedFileInfo{
Name: path.Base(name),
Mode: opts.Mode,
ModTime: opts.ModTime,
Size: opts.Size,
}
items[name] = readerItem{
open: &sync.Once{},
fi: fi,
rc: r,
allowEmptyFile: opts.AllowEmptyFile,
}
isFile = false
} else {
fi := &ExtendedFileInfo{
Name: path.Base(name),
Mode: os.ModeDir | 0755,
ModTime: opts.ModTime,
Size: 0,
}
items[name] = readerItem{
fi: fi,
// keep the children set during the previous iteration
children: items[name].children,
}
}
parent := path.Dir(name)
if parent == name {
break
}
// add the current file to the children of the parent directory
item := items[parent]
item.children = append(item.children, path.Base(name))
items[parent] = item
name = parent
}
return &Reader{
items: items,
}, nil
}
func readerCleanPath(name string) string {
return path.Clean("/" + name)
}
// VolumeName returns leading volume name, for the Reader file system it's
// always the empty string.
func (fs *Reader) VolumeName(_ string) string {
return ""
}
func (fs *Reader) fi() *ExtendedFileInfo {
return &ExtendedFileInfo{
Name: fs.Name,
Mode: fs.Mode,
ModTime: fs.ModTime,
Size: fs.Size,
}
}
func (fs *Reader) OpenFile(name string, flag int, _ bool) (f File, err error) {
if flag & ^(O_RDONLY|O_NOFOLLOW) != 0 {
return nil, pathError("open", name,
fmt.Errorf("invalid combination of flags 0x%x", flag))
}
switch name {
case fs.Name:
fs.open.Do(func() {
f = newReaderFile(fs.ReadCloser, fs.fi(), fs.AllowEmptyFile)
name = readerCleanPath(name)
item, ok := fs.items[name]
if !ok {
return nil, pathError("open", name, syscall.ENOENT)
}
// Check if the path matches our target file
if item.rc != nil {
item.open.Do(func() {
f = newReaderFile(item.rc, item.fi, item.allowEmptyFile)
})
if f == nil {
return nil, pathError("open", name, syscall.EIO)
}
return f, nil
case "/", ".":
f = fakeDir{
entries: []string{fs.fi().Name},
}
return f, nil
}
return nil, pathError("open", name, syscall.ENOENT)
f = fakeDir{
fakeFile: fakeFile{
fi: item.fi,
},
entries: slices.Clone(item.children),
}
return f, nil
}
// Lstat returns the FileInfo structure describing the named file.
// If the file is a symbolic link, the returned FileInfo
// describes the symbolic link. Lstat makes no attempt to follow the link.
// If there is an error, it will be of type *os.PathError.
func (fs *Reader) Lstat(name string) (*ExtendedFileInfo, error) {
getDirInfo := func(name string) *ExtendedFileInfo {
return &ExtendedFileInfo{
Name: fs.Base(name),
Size: 0,
Mode: os.ModeDir | 0755,
ModTime: time.Now(),
}
name = readerCleanPath(name)
item, ok := fs.items[name]
if !ok {
return nil, pathError("lstat", name, os.ErrNotExist)
}
switch name {
case fs.Name:
return fs.fi(), nil
case "/", ".":
return getDirInfo(name), nil
}
dir := fs.Dir(fs.Name)
for {
if dir == "/" || dir == "." {
break
}
if name == dir {
return getDirInfo(name), nil
}
dir = fs.Dir(dir)
}
return nil, pathError("lstat", name, os.ErrNotExist)
return item.fi, nil
}
// Join joins any number of path elements into a single path, adding a
@@ -137,7 +175,7 @@ func (fs *Reader) IsAbs(_ string) bool {
//
// For the Reader, all paths are absolute.
func (fs *Reader) Abs(p string) (string, error) {
return path.Clean(p), nil
return readerCleanPath(p), nil
}
// Clean returns the cleaned path. For details, see filepath.Clean.

View File

@@ -17,19 +17,11 @@ import (
func verifyFileContentOpenFile(t testing.TB, fs FS, filename string, want []byte) {
f, err := fs.OpenFile(filename, O_RDONLY, false)
if err != nil {
t.Fatal(err)
}
test.OK(t, err)
buf, err := io.ReadAll(f)
if err != nil {
t.Fatal(err)
}
err = f.Close()
if err != nil {
t.Fatal(err)
}
test.OK(t, err)
test.OK(t, f.Close())
if !cmp.Equal(want, buf) {
t.Error(cmp.Diff(want, buf))
@@ -38,19 +30,11 @@ func verifyFileContentOpenFile(t testing.TB, fs FS, filename string, want []byte
func verifyDirectoryContents(t testing.TB, fs FS, dir string, want []string) {
f, err := fs.OpenFile(dir, O_RDONLY, false)
if err != nil {
t.Fatal(err)
}
test.OK(t, err)
entries, err := f.Readdirnames(-1)
if err != nil {
t.Fatal(err)
}
err = f.Close()
if err != nil {
t.Fatal(err)
}
test.OK(t, err)
test.OK(t, f.Close())
sort.Strings(want)
sort.Strings(entries)
@@ -69,7 +53,7 @@ func checkFileInfo(t testing.TB, fi *ExtendedFileInfo, filename string, modtime
t.Errorf("Mode has wrong value, want 0%o, got 0%o", mode, fi.Mode)
}
if !modtime.Equal(time.Time{}) && !fi.ModTime.Equal(modtime) {
if !fi.ModTime.Equal(modtime) {
t.Errorf("ModTime has wrong value, want %v, got %v", modtime, fi.ModTime)
}
@@ -82,40 +66,48 @@ func checkFileInfo(t testing.TB, fi *ExtendedFileInfo, filename string, modtime
}
}
func TestFSReader(t *testing.T) {
data := test.Random(55, 1<<18+588)
now := time.Now()
filename := "foobar"
type fsTest []struct {
name string
f func(t *testing.T, fs FS)
}
var tests = []struct {
name string
f func(t *testing.T, fs FS)
}{
func createReadDirTest(fpath, filename string) fsTest {
return fsTest{
{
name: "Readdirnames-slash",
name: "Readdirnames-slash-" + fpath,
f: func(t *testing.T, fs FS) {
verifyDirectoryContents(t, fs, "/", []string{filename})
verifyDirectoryContents(t, fs, "/"+fpath, []string{filename})
},
},
{
name: "Readdirnames-current",
name: "Readdirnames-current-" + fpath,
f: func(t *testing.T, fs FS) {
verifyDirectoryContents(t, fs, ".", []string{filename})
verifyDirectoryContents(t, fs, path.Clean(fpath), []string{filename})
},
},
}
}
func createFileTest(filename string, now time.Time, data []byte) fsTest {
return fsTest{
{
name: "file/OpenFile",
f: func(t *testing.T, fs FS) {
verifyFileContentOpenFile(t, fs, filename, data)
},
},
{
name: "file/Open-error-not-exist",
f: func(t *testing.T, fs FS) {
_, err := fs.OpenFile(filename+"/other", O_RDONLY, false)
test.Assert(t, errors.Is(err, os.ErrNotExist), "unexpected error, got %v, expected %v", err, os.ErrNotExist)
},
},
{
name: "file/Lstat",
f: func(t *testing.T, fs FS) {
fi, err := fs.Lstat(filename)
if err != nil {
t.Fatal(err)
}
test.OK(t, err)
checkFileInfo(t, fi, filename, now, 0644, false)
},
@@ -123,91 +115,113 @@ func TestFSReader(t *testing.T) {
{
name: "file/Stat",
f: func(t *testing.T, fs FS) {
f, err := fs.OpenFile(filename, O_RDONLY, true)
if err != nil {
t.Fatal(err)
}
fi, err := f.Stat()
if err != nil {
t.Fatal(err)
}
err = f.Close()
if err != nil {
t.Fatal(err)
}
fi := fsOpenAndStat(t, fs, filename, true)
checkFileInfo(t, fi, filename, now, 0644, false)
},
},
{
name: "dir/Lstat-slash",
f: func(t *testing.T, fs FS) {
fi, err := fs.Lstat("/")
if err != nil {
t.Fatal(err)
}
}
}
checkFileInfo(t, fi, "/", time.Time{}, os.ModeDir|0755, true)
func createDirTest(fpath string, now time.Time) fsTest {
return fsTest{
{
name: "dir/Lstat-slash-" + fpath,
f: func(t *testing.T, fs FS) {
fi, err := fs.Lstat("/" + fpath)
test.OK(t, err)
checkFileInfo(t, fi, "/"+fpath, now, os.ModeDir|0755, true)
},
},
{
name: "dir/Lstat-current",
name: "dir/Lstat-current-" + fpath,
f: func(t *testing.T, fs FS) {
fi, err := fs.Lstat(".")
if err != nil {
t.Fatal(err)
}
fi, err := fs.Lstat("./" + fpath)
test.OK(t, err)
checkFileInfo(t, fi, ".", time.Time{}, os.ModeDir|0755, true)
checkFileInfo(t, fi, "/"+fpath, now, os.ModeDir|0755, true)
},
},
{
name: "dir/Lstat-error-not-exist",
name: "dir/Lstat-error-not-exist-" + fpath,
f: func(t *testing.T, fs FS) {
_, err := fs.Lstat("other")
if !errors.Is(err, os.ErrNotExist) {
t.Fatal(err)
}
_, err := fs.Lstat(fpath + "/other")
test.Assert(t, errors.Is(err, os.ErrNotExist), "unexpected error, got %v, expected %v", err, os.ErrNotExist)
},
},
{
name: "dir/Open-slash",
name: "dir/Open-slash-" + fpath,
f: func(t *testing.T, fs FS) {
fi, err := fs.Lstat("/")
if err != nil {
t.Fatal(err)
}
checkFileInfo(t, fi, "/", time.Time{}, os.ModeDir|0755, true)
fi := fsOpenAndStat(t, fs, "/"+fpath, false)
checkFileInfo(t, fi, "/"+fpath, now, os.ModeDir|0755, true)
},
},
{
name: "dir/Open-current",
name: "dir/Open-current-" + fpath,
f: func(t *testing.T, fs FS) {
fi, err := fs.Lstat(".")
if err != nil {
t.Fatal(err)
}
checkFileInfo(t, fi, ".", time.Time{}, os.ModeDir|0755, true)
fi := fsOpenAndStat(t, fs, "./"+fpath, false)
checkFileInfo(t, fi, "/"+fpath, now, os.ModeDir|0755, true)
},
},
}
}
for _, test := range tests {
fs := &Reader{
Name: filename,
ReadCloser: io.NopCloser(bytes.NewReader(data)),
func fsOpenAndStat(t *testing.T, fs FS, fpath string, metadataOnly bool) *ExtendedFileInfo {
f, err := fs.OpenFile(fpath, O_RDONLY, metadataOnly)
test.OK(t, err)
fi, err := f.Stat()
test.OK(t, err)
test.OK(t, f.Close())
return fi
}
func TestFSReader(t *testing.T) {
data := test.Random(55, 1<<18+588)
now := time.Now()
filename := "foobar"
tests := createReadDirTest("", filename)
tests = append(tests, createFileTest(filename, now, data)...)
tests = append(tests, createDirTest("", now)...)
for _, tst := range tests {
fs, err := NewReader(filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{
Mode: 0644,
Size: int64(len(data)),
ModTime: now,
}
})
test.OK(t, err)
t.Run(test.name, func(t *testing.T) {
test.f(t, fs)
t.Run(tst.name, func(t *testing.T) {
tst.f(t, fs)
})
}
}
func TestFSReaderNested(t *testing.T) {
data := test.Random(55, 1<<18+588)
now := time.Now()
filename := "foo/sub/bar"
tests := createReadDirTest("", "foo")
tests = append(tests, createReadDirTest("foo", "sub")...)
tests = append(tests, createReadDirTest("foo/sub", "bar")...)
tests = append(tests, createFileTest(filename, now, data)...)
tests = append(tests, createDirTest("", now)...)
tests = append(tests, createDirTest("foo", now)...)
tests = append(tests, createDirTest("foo/sub", now)...)
for _, tst := range tests {
fs, err := NewReader(filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{
Mode: 0644,
Size: int64(len(data)),
ModTime: now,
})
test.OK(t, err)
t.Run(tst.name, func(t *testing.T) {
tst.f(t, fs)
})
}
}
@@ -230,29 +244,24 @@ func TestFSReaderDir(t *testing.T) {
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
fs := &Reader{
Name: test.filename,
ReadCloser: io.NopCloser(bytes.NewReader(data)),
for _, tst := range tests {
t.Run(tst.name, func(t *testing.T) {
fs, err := NewReader(tst.filename, io.NopCloser(bytes.NewReader(data)), ReaderOptions{
Mode: 0644,
Size: int64(len(data)),
ModTime: now,
}
dir := path.Dir(fs.Name)
})
test.OK(t, err)
dir := path.Dir(tst.filename)
for {
if dir == "/" || dir == "." {
break
}
fi, err := fs.Lstat(dir)
if err != nil {
t.Fatal(err)
}
test.OK(t, err)
checkFileInfo(t, fi, dir, time.Time{}, os.ModeDir|0755, true)
checkFileInfo(t, fi, dir, now, os.ModeDir|0755, true)
dir = path.Dir(dir)
}
@@ -285,40 +294,30 @@ func TestFSReaderMinFileSize(t *testing.T) {
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
fs := &Reader{
Name: "testfile",
ReadCloser: io.NopCloser(strings.NewReader(test.data)),
for _, tst := range tests {
t.Run(tst.name, func(t *testing.T) {
fs, err := NewReader("testfile", io.NopCloser(strings.NewReader(tst.data)), ReaderOptions{
Mode: 0644,
ModTime: time.Now(),
AllowEmptyFile: test.allowEmpty,
}
AllowEmptyFile: tst.allowEmpty,
})
test.OK(t, err)
f, err := fs.OpenFile("testfile", O_RDONLY, false)
if err != nil {
t.Fatal(err)
}
test.OK(t, err)
buf, err := io.ReadAll(f)
if test.readMustErr {
if tst.readMustErr {
if err == nil {
t.Fatal("expected error not found, got nil")
}
} else {
if err != nil {
t.Fatal(err)
}
test.OK(t, err)
}
if string(buf) != test.data {
t.Fatalf("wrong data returned, want %q, got %q", test.data, string(buf))
}
err = f.Close()
if err != nil {
t.Fatal(err)
if string(buf) != tst.data {
t.Fatalf("wrong data returned, want %q, got %q", tst.data, string(buf))
}
test.OK(t, f.Close())
})
}
}

View File

@@ -53,9 +53,8 @@ func handleXattrErr(err error) error {
case *xattr.Error:
// On Linux, xattr calls on files in an SMB/CIFS mount can return
// ENOATTR instead of ENOTSUP.
switch e.Err {
case syscall.ENOTSUP, xattr.ENOATTR:
// ENOATTR instead of ENOTSUP. BSD can return EOPNOTSUPP.
if e.Err == syscall.ENOTSUP || e.Err == syscall.EOPNOTSUPP || e.Err == xattr.ENOATTR {
return nil
}
return errors.WithStack(e)

View File

@@ -88,10 +88,14 @@ func checkPackInner(ctx context.Context, r *Repository, id restic.ID, blobs []re
// calculate hash on-the-fly while reading the pack and capture pack header
var hash restic.ID
var hdrBuf []byte
// must use a separate slice from `errs` here as we're only interested in the last retry
var blobErrors []error
h := backend.Handle{Type: backend.PackFile, Name: id.String()}
err := r.be.Load(ctx, h, int(size), 0, func(rd io.Reader) error {
hrd := hashing.NewReader(rd, sha256.New())
bufRd.Reset(hrd)
// reset blob errors for each retry
blobErrors = nil
it := newPackBlobIterator(id, newBufReader(bufRd), 0, blobs, r.Key(), dec)
for {
@@ -108,7 +112,7 @@ func checkPackInner(ctx context.Context, r *Repository, id restic.ID, blobs []re
debug.Log(" check blob %v: %v", val.Handle.ID, val.Handle)
if val.Err != nil {
debug.Log(" error verifying blob %v: %v", val.Handle.ID, val.Err)
errs = append(errs, errors.Errorf("blob %v: %v", val.Handle.ID, val.Err))
blobErrors = append(blobErrors, errors.Errorf("blob %v: %v", val.Handle.ID, val.Err))
}
}
@@ -134,6 +138,7 @@ func checkPackInner(ctx context.Context, r *Repository, id restic.ID, blobs []re
hash = restic.IDFromHash(hrd.Sum(nil))
return nil
})
errs = append(errs, blobErrors...)
if err != nil {
var e *partialReadError
isPartialReadError := errors.As(err, &e)

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"strconv"
"strings"
"unicode"
"github.com/restic/restic/internal/errors"
)
@@ -52,7 +51,7 @@ func nextNumber(input string) (num int, rest string, err error) {
}
for i, s := range input {
if !unicode.IsNumber(s) {
if s < '0' || s > '9' {
rest = input[i:]
break
}

View File

@@ -37,6 +37,9 @@ func TestNextNumber(t *testing.T) {
{
input: "5d ", num: 5, rest: "d ",
},
{
input: "5", num: 5, rest: "",
},
}
for _, test := range tests {
@@ -78,6 +81,7 @@ func TestParseDuration(t *testing.T) {
{input: "2w", err: true},
{input: "1y4m3w1d", err: true},
{input: "s", err: true},
{input: "\xdf\x80", err: true}, // NKO DIGIT ZERO; we want ASCII digits
}
for _, test := range tests {

View File

@@ -908,13 +908,12 @@ func TestRestorerSparseFiles(t *testing.T) {
var zeros [1<<20 + 13]byte
target := &fs.Reader{
Mode: 0600,
Name: "/zeros",
ReadCloser: io.NopCloser(bytes.NewReader(zeros[:])),
}
target, err := fs.NewReader("/zeros", io.NopCloser(bytes.NewReader(zeros[:])), fs.ReaderOptions{
Mode: 0600,
})
rtest.OK(t, err)
sc := archiver.NewScanner(target)
err := sc.Scan(context.TODO(), []string{"/zeros"})
err = sc.Scan(context.TODO(), []string{"/zeros"})
rtest.OK(t, err)
arch := archiver.New(repo, target, archiver.Options{})

View File

@@ -91,6 +91,8 @@ func walk(ctx context.Context, repo restic.BlobLoader, prefix string, parentTree
if err == ErrSkipNode {
continue
}
return err
}
err = walk(ctx, repo, p, *node.Subtree, subtree, visitor)

View File

@@ -8,6 +8,7 @@ import (
"github.com/pkg/errors"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
// TestTree is used to construct a list of trees for testing the walker.
@@ -93,12 +94,12 @@ func (t TreeMap) Connections() uint {
// checkFunc returns a function suitable for walking the tree to check
// something, and a function which will check the final result.
type checkFunc func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB))
type checkFunc func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error))
// checkItemOrder ensures that the order of the 'path' arguments is the one passed in as 'want'.
func checkItemOrder(want []string) checkFunc {
pos := 0
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB)) {
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error)) {
walker = func(treeID restic.ID, path string, node *restic.Node, err error) error {
if err != nil {
t.Errorf("error walking %v: %v", path, err)
@@ -121,7 +122,8 @@ func checkItemOrder(want []string) checkFunc {
return walker(restic.ID{}, "leave: "+path, nil, nil)
}
final = func(t testing.TB) {
final = func(t testing.TB, err error) {
rtest.OK(t, err)
if pos != len(want) {
t.Errorf("not enough items returned, want %d, got %d", len(want), pos)
}
@@ -134,7 +136,7 @@ func checkItemOrder(want []string) checkFunc {
// checkParentTreeOrder ensures that the order of the 'parentID' arguments is the one passed in as 'want'.
func checkParentTreeOrder(want []string) checkFunc {
pos := 0
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB)) {
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error)) {
walker = func(treeID restic.ID, path string, node *restic.Node, err error) error {
if err != nil {
t.Errorf("error walking %v: %v", path, err)
@@ -153,7 +155,8 @@ func checkParentTreeOrder(want []string) checkFunc {
return nil
}
final = func(t testing.TB) {
final = func(t testing.TB, err error) {
rtest.OK(t, err)
if pos != len(want) {
t.Errorf("not enough items returned, want %d, got %d", len(want), pos)
}
@@ -168,7 +171,7 @@ func checkParentTreeOrder(want []string) checkFunc {
func checkSkipFor(skipFor map[string]struct{}, wantPaths []string) checkFunc {
var pos int
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB)) {
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error)) {
walker = func(treeID restic.ID, path string, node *restic.Node, err error) error {
if err != nil {
t.Errorf("error walking %v: %v", path, err)
@@ -196,7 +199,8 @@ func checkSkipFor(skipFor map[string]struct{}, wantPaths []string) checkFunc {
return walker(restic.ID{}, "leave: "+path, nil, nil)
}
final = func(t testing.TB) {
final = func(t testing.TB, err error) {
rtest.OK(t, err)
if pos != len(wantPaths) {
t.Errorf("wrong number of paths returned, want %d, got %d", len(wantPaths), pos)
}
@@ -206,6 +210,32 @@ func checkSkipFor(skipFor map[string]struct{}, wantPaths []string) checkFunc {
}
}
func checkErrorReturned(errForPath string) checkFunc {
expectedErr := fmt.Errorf("error for %v", errForPath)
return func(t testing.TB) (walker WalkFunc, leaveDir func(path string) error, final func(testing.TB, error)) {
walker = func(treeID restic.ID, path string, node *restic.Node, err error) error {
if path == errForPath {
return expectedErr
}
return nil
}
leaveDir = func(path string) error {
return walker(restic.ID{}, "leave: "+path, nil, nil)
}
final = func(t testing.TB, err error) {
if err == nil {
t.Errorf("expected error for %v, got nil", errForPath)
}
rtest.Assert(t, err == expectedErr, "expected error for %v, got %v", errForPath, err)
}
return walker, leaveDir, final
}
}
func TestWalker(t *testing.T) {
var tests = []struct {
tree TestTree
@@ -427,6 +457,21 @@ func TestWalker(t *testing.T) {
}),
},
},
{
tree: TestTree{
"subdir1": TestTree{
"file": TestFile{},
},
"subdir2": TestTree{},
},
checks: []checkFunc{
checkErrorReturned("/subdir1"),
checkErrorReturned("/subdir2"),
checkErrorReturned("/subdir1/file"),
checkErrorReturned("leave: /subdir1"),
checkErrorReturned("leave: /subdir2"),
},
},
}
for _, test := range tests {
@@ -442,10 +487,7 @@ func TestWalker(t *testing.T) {
ProcessNode: fn,
LeaveDir: leaveDir,
})
if err != nil {
t.Error(err)
}
last(t)
last(t, err)
})
}
})