Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package gopass for openSUSE:Factory checked in at 2026-09-10 15:37:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/gopass (Old) and /work/SRC/openSUSE:Factory/.gopass.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "gopass" Thu Sep 10 15:37:07 2026 rev:12 rq:1376755 version:1.17.1 Changes: -------- --- /work/SRC/openSUSE:Factory/gopass/gopass.changes 2026-08-31 15:56:41.117944450 +0200 +++ /work/SRC/openSUSE:Factory/.gopass.new.1265/gopass.changes 2026-09-10 15:37:10.074399650 +0200 @@ -1,0 +2,12 @@ +Wed Sep 9 21:04:56 UTC 2026 - Marcus Rueckert <[email protected]> + +- Update to 1.17.1: + - Added + - api: Add new AuditList method (#3594) + - create: support passwordless / SSO login profiles (#3493) + - Fixed + - ctxutil: restore password callback hook for embedded age + prompts (#3590) + - store: Fix reencrypt when adding recipients (#3595) (#3473) + +------------------------------------------------------------------- Old: ---- gopass-1.17.0.tar.gz New: ---- gopass-1.17.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ gopass.spec ++++++ --- /var/tmp/diff_new_pack.GmU6fV/_old 2026-09-10 15:37:11.072441478 +0200 +++ /var/tmp/diff_new_pack.GmU6fV/_new 2026-09-10 15:37:11.074441562 +0200 @@ -18,9 +18,9 @@ %global make_args PREFIX=%{_prefix} GOPASS_REVISION=v%{version} Name: gopass -Version: 1.17.0 +Version: 1.17.1 Release: 0 -%global pkg_version 1.17.0 +%global pkg_version 1.17.1 Summary: The slightly more awesome standard unix password manager for teams License: MIT URL: https://www.gopass.pw/ ++++++ gopass-1.17.0.tar.gz -> gopass-1.17.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/.github/workflows/autorelease.yml new/gopass-1.17.1/.github/workflows/autorelease.yml --- old/gopass-1.17.0/.github/workflows/autorelease.yml 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/.github/workflows/autorelease.yml 2026-09-09 22:44:38.000000000 +0200 @@ -18,7 +18,7 @@ runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: egress-policy: audit diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/.github/workflows/build.yml new/gopass-1.17.1/.github/workflows/build.yml --- old/gopass-1.17.0/.github/workflows/build.yml 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/.github/workflows/build.yml 2026-09-09 22:44:38.000000000 +0200 @@ -24,7 +24,7 @@ name: Go ${{ matrix.go }} steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: egress-policy: block allowed-endpoints: > @@ -48,12 +48,14 @@ uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go }} + - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- + - name: Ubuntu Dependencies run: sudo apt-get install --yes git gnupg - run: git config --global user.name nobody @@ -79,7 +81,7 @@ runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: egress-policy: audit @@ -109,7 +111,7 @@ shell: msys2 {0} steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: egress-policy: audit @@ -140,7 +142,7 @@ runs-on: macos-latest steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: egress-policy: audit diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/.github/workflows/codeql-analysis.yml new/gopass-1.17.1/.github/workflows/codeql-analysis.yml --- old/gopass-1.17.0/.github/workflows/codeql-analysis.yml 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/.github/workflows/codeql-analysis.yml 2026-09-09 22:44:38.000000000 +0200 @@ -49,7 +49,7 @@ steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: disable-sudo: true egress-policy: block diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/.github/workflows/container.yml new/gopass-1.17.1/.github/workflows/container.yml --- old/gopass-1.17.0/.github/workflows/container.yml 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/.github/workflows/container.yml 2026-09-09 22:44:38.000000000 +0200 @@ -31,7 +31,7 @@ steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: egress-policy: audit diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/.github/workflows/golangci-lint.yml new/gopass-1.17.1/.github/workflows/golangci-lint.yml --- old/gopass-1.17.0/.github/workflows/golangci-lint.yml 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/.github/workflows/golangci-lint.yml 2026-09-09 22:44:38.000000000 +0200 @@ -22,7 +22,7 @@ runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: disable-sudo: true egress-policy: block diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/.github/workflows/grype.yml new/gopass-1.17.1/.github/workflows/grype.yml --- old/gopass-1.17.0/.github/workflows/grype.yml 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/.github/workflows/grype.yml 2026-09-09 22:44:38.000000000 +0200 @@ -20,7 +20,7 @@ runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: egress-policy: audit diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/.github/workflows/key-canary.yml new/gopass-1.17.1/.github/workflows/key-canary.yml --- old/gopass-1.17.0/.github/workflows/key-canary.yml 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/.github/workflows/key-canary.yml 2026-09-09 22:44:38.000000000 +0200 @@ -18,7 +18,7 @@ runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@b09bb98e06d4d774595224525879c09bc6e98c40 # v2.20.1 + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 with: disable-sudo: true egress-policy: block diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/.github/workflows/scorecard.yml new/gopass-1.17.1/.github/workflows/scorecard.yml --- old/gopass-1.17.0/.github/workflows/scorecard.yml 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/.github/workflows/scorecard.yml 2026-09-09 22:44:38.000000000 +0200 @@ -67,6 +67,6 @@ # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v3.29.5 + uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v3.29.5 with: sarif_file: results.sarif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/.goreleaser.yml new/gopass-1.17.1/.goreleaser.yml --- old/gopass-1.17.0/.goreleaser.yml 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/.goreleaser.yml 2026-09-09 22:44:38.000000000 +0200 @@ -165,6 +165,7 @@ env: - "ARTIFACT=${artifact}" - "SIGNATURE=${signature}" + - "GPG_FINGERPRINT={{ .Env.GPG_FINGERPRINT }}" args: - -ec - | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/CHANGELOG.md new/gopass-1.17.1/CHANGELOG.md --- old/gopass-1.17.0/CHANGELOG.md 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/CHANGELOG.md 2026-09-09 22:44:38.000000000 +0200 @@ -12,6 +12,18 @@ ## [Unreleased] +## [1.17.1] - 2026-09-09 + +### Added + +- api: Add new AuditList method (#3594) +- create: support passwordless / SSO login profiles (#3493) + +### Fixed + +- ctxutil: restore password callback hook for embedded age prompts (#3590) +- store: Fix reencrypt when adding recipients (#3595) (#3473) + ## [1.17.0] - 2026-08-30 ### Added @@ -1274,7 +1286,8 @@ * [ENHANCEMENT] Simplified recipient management * [ENHANCEMENT] Interactive questions for missing parameters -[Unreleased]: https://github.com/gopasspw/gopass/compare/v1.17.0...HEAD +[Unreleased]: https://github.com/gopasspw/gopass/compare/v1.17.1...HEAD +[1.17.1]: https://github.com/gopasspw/gopass/compare/v1.17.0...v1.17.1 [1.17.0]: https://github.com/gopasspw/gopass/compare/v1.16.1...v1.17.0 [1.16.1]: https://github.com/gopasspw/gopass/compare/v1.16.0...v1.16.1 [1.16.0]: https://github.com/gopasspw/gopass/compare/v1.15.18...v1.16.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/VERSION new/gopass-1.17.1/VERSION --- old/gopass-1.17.0/VERSION 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/VERSION 2026-09-09 22:44:38.000000000 +0200 @@ -1 +1 @@ -1.17.0 +1.17.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/docs/setup.md new/gopass-1.17.1/docs/setup.md --- old/gopass-1.17.0/docs/setup.md 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/docs/setup.md 2026-09-09 22:44:38.000000000 +0200 @@ -455,7 +455,7 @@ Because gopass is fully backwards compatible with pass, you can use some existing graphical user interfaces / frontends: * Android - [Password Store](https://github.com/agrahn/Android-Password-Store) -* iOS - [Pass for iOS](https://github.com/davidjb/pass-ios#readme) +* iOS - [Pass for iOS](https://github.com/mssun/passforios) * Windows / MacOS / Linux - [QtPass](https://qtpass.org/) There is also [Gopass UI](https://github.com/codecentric/gopass-ui) which was exclusively implemented for gopass and is available for MacOS, Linux and Windows. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/go.mod new/gopass-1.17.1/go.mod --- old/gopass-1.17.0/go.mod 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/go.mod 2026-09-09 22:44:38.000000000 +0200 @@ -3,7 +3,7 @@ go 1.25.0 require ( - filippo.io/age v1.3.1 + filippo.io/age v1.3.2 github.com/ProtonMail/go-crypto v1.4.1 github.com/blang/semver/v4 v4.0.0 github.com/caspr-io/yamlpath v0.0.0-20200722075116-502e8d113a9b @@ -17,7 +17,7 @@ github.com/google/go-github/v61 v61.0.0 github.com/gopasspw/clipboard v0.0.5-0.20260524141134-6b387ae5aa1a github.com/gopasspw/gitconfig v0.0.4 - github.com/gopasspw/gopass-hibp v1.16.1 + github.com/gopasspw/gopass-hibp v1.17.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/jsimonetti/pwscheme v0.0.0-20220922140336-67a4d090f150 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 @@ -51,13 +51,13 @@ require ( codeberg.org/tslocum/cbind v0.1.9 // indirect - filippo.io/edwards25519 v1.1.0 // indirect + filippo.io/edwards25519 v1.2.0 // indirect filippo.io/hpke v0.4.0 // indirect filippo.io/nistec v0.0.4 // indirect github.com/boombuler/barcode v1.1.0 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect - github.com/cloudflare/circl v1.6.3 // indirect + github.com/cloudflare/circl v1.6.5 // indirect github.com/creack/pty v1.1.24 // indirect github.com/danieljoos/wincred v1.2.3 // indirect github.com/ebitengine/purego v0.10.1 // indirect @@ -66,7 +66,7 @@ github.com/gdamore/tcell/v3 v3.4.0 // indirect github.com/gen2brain/shm v0.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.5.0 // indirect - github.com/gobwas/glob v0.2.3 // indirect + github.com/gobwas/glob v1.0.0 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/jezek/xgb v1.1.1 // indirect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/go.sum new/gopass-1.17.1/go.sum --- old/gopass-1.17.0/go.sum 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/go.sum 2026-09-09 22:44:38.000000000 +0200 @@ -1,11 +1,11 @@ -c2sp.org/CCTV/age v0.0.0-20251208015420-e9274a7bdbfd h1:ZLsPO6WdZ5zatV4UfVpr7oAwLGRZ+sebTUruuM4Ra3M= -c2sp.org/CCTV/age v0.0.0-20251208015420-e9274a7bdbfd/go.mod h1:SrHC2C7r5GkDk8R+NFVzYy/sdj0Ypg9htaPXQq5Cqeo= +c2sp.org/CCTV/age v0.0.0-20260829155415-4448f2097b2d h1:Blprhc2SbChNZtWcU+BLTM4YdoqYAS9V7cJgOwJKyAs= +c2sp.org/CCTV/age v0.0.0-20260829155415-4448f2097b2d/go.mod h1:SrHC2C7r5GkDk8R+NFVzYy/sdj0Ypg9htaPXQq5Cqeo= codeberg.org/tslocum/cbind v0.1.9 h1:Y/l7h7xnu24lKf/Z6y6SpaIzDw8aJjPZDg+uIGLp1Rw= codeberg.org/tslocum/cbind v0.1.9/go.mod h1:xoMczSDzG2VHsT3UmUcusliDhuMss8Q0GL+IhapG1nk= -filippo.io/age v1.3.1 h1:hbzdQOJkuaMEpRCLSN1/C5DX74RPcNCk6oqhKMXmZi0= -filippo.io/age v1.3.1/go.mod h1:EZorDTYUxt836i3zdori5IJX/v2Lj6kWFU0cfh6C0D4= -filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= -filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +filippo.io/age v1.3.2 h1:r6RSZLFSMm6rzKepZ7ZAYkKCu14f3/Me8c7uKYh7C8c= +filippo.io/age v1.3.2/go.mod h1:TH/Yr2sSRhCKbaH4XPxpUV0Us8Gv6txYUpiZQWz8Evk= +filippo.io/edwards25519 v1.2.0 h1:crnVqOiS4jqYleHd9vaKZ+HKtHfllngJIiOpNpoJsjo= +filippo.io/edwards25519 v1.2.0/go.mod h1:xzAOLCNug/yB62zG1bQ8uziwrIqIuxhctzJT18Q77mc= filippo.io/hpke v0.4.0 h1:p575VVQ6ted4pL+it6M00V/f2qTZITO0zgmdKCkd5+A= filippo.io/hpke v0.4.0/go.mod h1:EmAN849/P3qdeK+PCMkDpDm83vRHM5cDipBJ8xbQLVY= filippo.io/nistec v0.0.4 h1:F14ZHT5htWlMnQVPndX9ro9arf56cBhQxq4LnDI491s= @@ -29,8 +29,8 @@ github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= -github.com/cloudflare/circl v1.6.3 h1:9GPOhQGF9MCYUeXyMYlqTR6a5gTrgR/fBLXvUgtVcg8= -github.com/cloudflare/circl v1.6.3/go.mod h1:2eXP6Qfat4O/Yhh8BznvKnJ+uzEoTQ6jVKJRn81BiS4= +github.com/cloudflare/circl v1.6.5 h1:O64F26HEqNhznd/hrC5KZXVKYuKM2rx4deZDTc4ihQA= +github.com/cloudflare/circl v1.6.5/go.mod h1:h5LNyxAc5nTue9DS5jT+48en2PSDYt3zdGnz5OstK6c= github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ= @@ -56,8 +56,8 @@ github.com/gen2brain/shm v0.1.1/go.mod h1:UgIcVtvmOu+aCJpqJX7GOtiN7X2ct+TKLg4RTxwPIUA= github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= -github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gobwas/glob v1.0.0 h1:p+FKbLEIsK1yZ39/OINwFvqNb5oyPY4H8xcy6uYu8dg= +github.com/gobwas/glob v1.0.0/go.mod h1:oWCdo522i2P1n/hMXGNWs7yoV4wy/ciZuUIbvKj5rkc= github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gokyle/twofactor v1.0.1 h1:uRhvx0S4Hb82RPIDALnf7QxbmPL49LyyaCkJDpWx+Ek= @@ -78,8 +78,8 @@ github.com/gopasspw/clipboard v0.0.5-0.20260524141134-6b387ae5aa1a/go.mod h1:i0cShr7JEbOXZ/iKM5RyfBLbu1FPzouO8BTCJy0uHy8= github.com/gopasspw/gitconfig v0.0.4 h1:7JE0iTm92OdXCtkS33CnbqcAEqQXYWTUriYFf3sRTBk= github.com/gopasspw/gitconfig v0.0.4/go.mod h1:W5AHsZgCbBRsc8TnElO82GYflOz/l2dIndncymoCv+A= -github.com/gopasspw/gopass-hibp v1.16.1 h1:PD38NEYCiFlVxKJWp2IiJYgSSnaBQ3B7oGavV+F8qvs= -github.com/gopasspw/gopass-hibp v1.16.1/go.mod h1:5WZTNON2U+XNe4UoeHWlSrN/VLggmv32EDrGjvnhYjM= +github.com/gopasspw/gopass-hibp v1.17.0 h1:H7OFo4VrB0S7oC10QxBYiLLJLPM7QLOXIR3xn4N23q4= +github.com/gopasspw/gopass-hibp v1.17.0/go.mod h1:KXUcLJWdQvnvT89SV2QEDeqOOOEbj5T0I3f9VetXr/k= 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/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= @@ -145,8 +145,8 @@ github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= -github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g= +github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/gopass.1 new/gopass-1.17.1/gopass.1 --- old/gopass-1.17.0/gopass.1 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/gopass.1 2026-09-09 22:44:38.000000000 +0200 @@ -1,5 +1,5 @@ -.TH GOPASS "1" "August 2026" "gopass (github.com/gopasspw/gopass) 1.17.0" "User Commands" +.TH GOPASS "1" "September 2026" "gopass (github.com/gopasspw/gopass) 1.17.1" "User Commands" .SH NAME gopass - The standard Unix password manager .SH SYNOPSIS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/helpers/gitutils/gitutils.go new/gopass-1.17.1/helpers/gitutils/gitutils.go --- old/gopass-1.17.0/helpers/gitutils/gitutils.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/helpers/gitutils/gitutils.go 2026-09-09 22:44:38.000000000 +0200 @@ -3,6 +3,7 @@ import ( "bytes" "fmt" + "io" "os" "os/exec" "path/filepath" @@ -183,6 +184,37 @@ return nil } +// GitSyncMaster makes sure the repo at dir is on master and in sync with +// origin/master. It fetches the remote and hard resets the local master +// to origin/master. It refuses to run on a dirty worktree. +func GitSyncMaster(dir string) error { + if !IsGitClean(dir) { + return fmt.Errorf("git worktree at %s is dirty, refusing to sync", dir) + } + + steps := [][]string{ + {"checkout", "master"}, + {"fetch", "origin"}, + {"reset", "--hard", "origin/master"}, + } + for _, args := range steps { + cmd := exec.Command("git", args...) + cmd.Dir = dir + buf := &bytes.Buffer{} + cmd.Stdout = buf + cmd.Stderr = buf + if Verbose { + fmt.Printf("Running command: %s\n", cmd) + } + + if err := cmd.Run(); err != nil { + return fmt.Errorf("git %s failed: %s: %w", strings.Join(args, " "), strings.TrimSpace(buf.String()), err) + } + } + + return nil +} + func GitAdd(dir string, files ...string) error { args := []string{"add"} args = append(args, files...) @@ -201,26 +233,28 @@ func GitCommitAndPush(dir, tag string) error { cmd := exec.Command("git", "commit", "-a", "-s", "-m", "Update to "+tag) cmd.Dir = dir - cmd.Stderr = os.Stderr + buf := &bytes.Buffer{} + cmd.Stdout = buf + cmd.Stderr = buf if Verbose { - cmd.Stdout = os.Stdout fmt.Printf("Running command: %s\n", cmd) } if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to commit changes: %w", err) + return fmt.Errorf("failed to commit changes: %s: %w", strings.TrimSpace(buf.String()), err) } cmd = exec.Command("git", "push", "origin", "master") cmd.Dir = dir - cmd.Stderr = os.Stderr + buf = &bytes.Buffer{} + cmd.Stdout = buf + cmd.Stderr = buf if Verbose { - cmd.Stdout = os.Stdout fmt.Printf("Running command: %s\n", cmd) } if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to push changes: %w", err) + return fmt.Errorf("failed to push changes: %s: %w", strings.TrimSpace(buf.String()), err) } return nil @@ -238,7 +272,9 @@ } cmd.Dir = dir - fmt.Printf("Running command: %s\n", cmd) + if Verbose { + fmt.Printf("Running command: %s\n", cmd) + } if err := cmd.Run(); err != nil { return err } @@ -250,7 +286,6 @@ fmt.Printf("Running command: %s\n", cmd) } cmd.Dir = dir - fmt.Printf("Running command: %s\n", cmd) return cmd.Run() } @@ -264,36 +299,43 @@ } cmd := exec.Command("git", "push", remote, branch) - cmd.Stderr = os.Stderr + buf := &bytes.Buffer{} + cmd.Stdout = buf + cmd.Stderr = buf if Verbose { - cmd.Stdout = os.Stdout fmt.Printf("Running command: %s\n", cmd) } - return cmd.Run() + if err := cmd.Run(); err != nil { + return fmt.Errorf("failed to push %s to %s: %s: %w", branch, remote, strings.TrimSpace(buf.String()), err) + } + + return nil } func GitTagAndPush(dir string, tag string) error { cmd := exec.Command("git", "tag", "-m", "'Tag "+tag+"'", tag) cmd.Dir = dir - cmd.Stderr = os.Stderr + buf := &bytes.Buffer{} + cmd.Stdout = buf + cmd.Stderr = buf if Verbose { - cmd.Stdout = os.Stdout fmt.Printf("Running command: %s\n", cmd) } if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to commit changes: %w", err) + return fmt.Errorf("failed to tag: %s: %w", strings.TrimSpace(buf.String()), err) } cmd = exec.Command("git", "push", "origin", tag) cmd.Dir = dir - cmd.Stderr = os.Stderr + buf = &bytes.Buffer{} + cmd.Stdout = buf + cmd.Stderr = buf if Verbose { - cmd.Stdout = os.Stdout fmt.Printf("Running command: %s\n", cmd) } if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to push changes: %w", err) + return fmt.Errorf("failed to push tag: %s: %w", strings.TrimSpace(buf.String()), err) } return nil @@ -302,10 +344,10 @@ func GitHasTag(dir string, tag string) bool { cmd := exec.Command("git", "rev-parse", tag) cmd.Dir = dir - cmd.Stderr = os.Stderr + cmd.Stdout = io.Discard + cmd.Stderr = io.Discard if Verbose { - cmd.Stdout = os.Stdout fmt.Printf("Running command: %s\n", cmd) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/helpers/postrel/main.go new/gopass-1.17.1/helpers/postrel/main.go --- old/gopass-1.17.0/helpers/postrel/main.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/helpers/postrel/main.go 2026-09-09 22:44:38.000000000 +0200 @@ -10,6 +10,7 @@ import ( "bufio" + "bytes" "context" "crypto/sha256" "crypto/sha512" @@ -197,13 +198,36 @@ return err } +// runCmd runs the given command in dir. Output is captured and only +// printed on error, with noisy lines (e.g. "go: downloading ...") +// filtered out. func runCmd(dir string, args ...string) error { cmd := exec.Command(args[0], args[1:]...) cmd.Dir = dir - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + buf := &bytes.Buffer{} + cmd.Stdout = buf + cmd.Stderr = buf - return cmd.Run() + if err := cmd.Run(); err != nil { + return fmt.Errorf("%s failed: %s: %w", strings.Join(args, " "), filterNoise(buf.String()), err) + } + + return nil +} + +// filterNoise removes uninteresting lines from command output, e.g. +// the "go: downloading ..." lines emitted by the go tool. +func filterNoise(out string) string { + var sb strings.Builder + for _, line := range strings.Split(out, "\n") { + if strings.HasPrefix(line, "go: downloading ") { + continue + } + sb.WriteString(line) + sb.WriteString("\n") + } + + return strings.TrimSpace(sb.String()) } func versionFile() (semver.Version, error) { @@ -255,6 +279,13 @@ } func (u *inUpdater) update(ctx context.Context) { + type result struct { + name string + err error + } + + var results []result + for _, upd := range []string{ "git-credential-gopass", "gopass-hibp", @@ -266,13 +297,30 @@ fmt.Println() fmt.Printf("๐ Updating: %s ...\n", upd) fmt.Println() - if err := u.doUpdate(ctx, upd); err != nil { + err := u.doUpdate(ctx, upd) + if err != nil { fmt.Printf("โ Updating %s failed: %s\n", upd, err) + } else { + fmt.Printf("โ Integration %s is up to date.\n", upd) + } + results = append(results, result{name: upd, err: err}) + } + + // print a summary of all integrations + fmt.Println() + fmt.Println("------------------------------") + fmt.Println() + fmt.Println("๐ Integration update summary:") + fmt.Println() + for _, r := range results { + if r.err != nil { + fmt.Printf("โ %-28s FAILED: %s\n", r.name, r.err) continue } - fmt.Printf("โ Integration %s is up to date.\n", upd) + fmt.Printf("โ %-28s OK\n", r.name) } + fmt.Println() } func (u *inUpdater) doUpdate(ctx context.Context, dir string) error { @@ -295,18 +343,14 @@ if !gitutils.IsGitClean(path) { return fmt.Errorf("git not clean at %s", path) } - fmt.Printf("โ [%s] Git is clean.", dir) - - // git pull origin master - if err := gitutils.GitPom(path); err != nil { - return fmt.Errorf("failed to fetch changes at %s: %s", path, err) - } + fmt.Printf("โ [%s] Git is clean.\n", dir) - // make upgrade - if err := runCmd(path, "make", "upgrade"); err != nil { - return err + // make sure we're on master and in sync with the remote, + // this avoids non-fast-forward push failures + if err := gitutils.GitSyncMaster(path); err != nil { + return fmt.Errorf("failed to sync with remote at %s: %w", path, err) } - fmt.Printf("โ [%s] make upgrade.\n", dir) + fmt.Printf("โ [%s] synced with origin/master.\n", dir) // go get github.com/gopasspw/gopass@tag if err := runCmd(path, "go", "get", "github.com/gopasspw/gopass@"+tag); err != nil { @@ -320,15 +364,14 @@ } fmt.Printf("โ [%s] synced .golangci.yml.\n", dir) - // update go.mod - if err := runCmd(path, "go", "mod", "edit", "-go="+u.goVer); err != nil { - return err - } - fmt.Printf("โ [%s] updated Go version in go.mod to %s.\n", dir, u.goVer) + // go mod tidy, pin to the same Go version as in the gopass repo, to avoid "go: updates to go.mod needed" errors + if err := runCmd(path, "go", "mod", "tidy", "-v", "-x", "-go="+u.goVer); err != nil { + fmt.Printf(`โ It looks like 'go mod tidy' failed. +If it tries to update to a newer Go version, please investigate. +We should always consider which Go versions are available in the +stable releases of our main target platforms before updating it.`) - // go mod tidy - if err := runCmd(path, "go", "mod", "tidy"); err != nil { - return err + return fmt.Errorf("go mod tidy failed at %s: %w", path, err) } fmt.Printf("โ [%s] go mod tidy.\n", dir) @@ -338,6 +381,12 @@ } fmt.Printf("โ [%s] updated workflows.\n", dir) + // update depdendabot.yml + if err := fsutil.CopyFile(filepath.Join(cwd, ".github", "dependabot.yml"), filepath.Join(path, ".github", "dependabot.yml")); err != nil { + return err + } + fmt.Printf("โ [%s] synced dependabot.yml.\n", dir) + // update VERSION if err := os.WriteFile(filepath.Join(path, "VERSION"), []byte(u.v.String()+"\n"), 0o644); err != nil { return err @@ -389,7 +438,7 @@ return nil } - return u.updateWorkflow(ctx, path) + return u.updateWorkflowGoVersion(ctx, path) }) return nil @@ -397,7 +446,7 @@ var goVersionRE = regexp.MustCompile(`go-version:\s+\d+\.\d+`) -func (u *inUpdater) updateWorkflow(_ context.Context, path string) error { +func (u *inUpdater) updateWorkflowGoVersion(_ context.Context, path string) error { buf, err := os.ReadFile(path) if err != nil { return err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/internal/action/audit.go new/gopass-1.17.1/internal/action/audit.go --- old/gopass-1.17.0/internal/action/audit.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/internal/action/audit.go 2026-09-09 22:44:38.000000000 +0200 @@ -45,12 +45,24 @@ return nil } - var excludes string - st := s.Store.Storage(ctx, cmd.Args().First()) - if buf, err := st.Get(ctx, ".gopass-audit-ignore"); err == nil && buf != nil { - excludes = string(buf) + nList, err := audit.FilteredList(ctx, s.Store) + if err != nil { + return exit.Error(exit.List, err, "failed to list secrets: %s", err) + } + // if a filter was given, restrict the audit to the matching subtree + if filter := cmd.Args().First(); filter != "" { + allowed := make(map[string]struct{}, len(list)) + for _, name := range list { + allowed[name] = struct{}{} + } + filtered := make([]string, 0, len(nList)) + for _, name := range nList { + if _, ok := allowed[name]; ok { + filtered = append(filtered, name) + } + } + nList = filtered } - nList := audit.FilterExcludes(excludes, list) if len(nList) < len(list) { out.Warningf(ctx, "Excluding %d secrets based on .gopass-audit-ignore", len(list)-len(nList)) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/internal/audit/excludes.go new/gopass-1.17.1/internal/audit/excludes.go --- old/gopass-1.17.0/internal/audit/excludes.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/internal/audit/excludes.go 2026-09-09 22:44:38.000000000 +0200 @@ -1,9 +1,15 @@ package audit import ( + "context" + "fmt" "regexp" + "sort" "strings" + "github.com/gopasspw/gopass/internal/store" + "github.com/gopasspw/gopass/internal/store/root" + "github.com/gopasspw/gopass/internal/tree" "github.com/gopasspw/gopass/pkg/debug" ) @@ -21,6 +27,63 @@ return false } +// FilteredList returns a list of all secrets in the given store, filtered against the .gopass-audit-ignore file in each mount point. +func FilteredList(ctx context.Context, rs *root.Store) ([]string, error) { + t, err := rs.Tree(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get store tree: %w", err) + } + + list := t.List(tree.INF) + if len(list) < 1 { + return list, nil + } + + // Collect the exclude patterns for every mount point (including the root store). + // The longer a mount point the more specific it is, so we sort them by descending + // length to make sure the most specific mount point wins for every secret. + mps := rs.MountPoints() + sort.Sort(sort.Reverse(store.ByPathLen(mps))) + + excludes := make(map[string]string, len(mps)+1) + for _, mp := range mps { + excludes[mp] = loadExcludes(ctx, rs, mp) + } + // the root store is the fallback for secrets not in any mount + excludes[""] = loadExcludes(ctx, rs, "") + + // Group the secrets by their mount point, so that each excludes file + // only needs to be parsed once. + byMount := make(map[string][]string, len(mps)+1) + for _, name := range list { + mp := rs.MountPoint(name) + byMount[mp] = append(byMount[mp], name) + } + + out := make([]string, 0, len(list)) + for mp, secrets := range byMount { + out = append(out, FilterExcludes(excludes[mp], secrets)...) + } + sort.Strings(out) + + return out, nil +} + +// loadExcludes returns the content of the .gopass-audit-ignore file at the +// root of the given mount point, if any. +func loadExcludes(ctx context.Context, rs *root.Store, mp string) string { + st := rs.Storage(ctx, mp) + if st == nil { + return "" + } + buf, err := st.Get(ctx, ".gopass-audit-ignore") + if err != nil || buf == nil { + return "" + } + + return string(buf) +} + // FilterExcludes filters the given list of secrets against the given exclude patterns (RE2 syntax). func FilterExcludes(excludes string, in []string) []string { debug.Log("Filtering %d secrets against %d exclude patterns", len(in), strings.Count(excludes, "\n")) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/internal/backend/crypto/age/age.go new/gopass-1.17.1/internal/backend/crypto/age/age.go --- old/gopass-1.17.0/internal/backend/crypto/age/age.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/internal/backend/crypto/age/age.go 2026-09-09 22:44:38.000000000 +0200 @@ -82,6 +82,11 @@ a.pwCallback = func(_ string, _ bool) ([]byte, error) { return []byte(ap), nil } a.pwPurgeCallback = func(_ string) {} // no-op for static passwords } + if ctxutil.HasPasswordCallback(ctx) { + debug.Log("age: using password callback from context") + a.pwCallback = ctxutil.GetPasswordCallback(ctx) + a.pwPurgeCallback = ctxutil.GetPasswordPurgeCallback(ctx) + } a.tryStartAgent(ctx) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/internal/backend/crypto/age/askpass_test.go new/gopass-1.17.1/internal/backend/crypto/age/askpass_test.go --- old/gopass-1.17.0/internal/backend/crypto/age/askpass_test.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/internal/backend/crypto/age/askpass_test.go 2026-09-09 22:44:38.000000000 +0200 @@ -8,6 +8,7 @@ "github.com/gopasspw/gopass/internal/config" "github.com/gopasspw/gopass/internal/out" + "github.com/gopasspw/gopass/pkg/ctxutil" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/zalando/go-keyring" @@ -121,3 +122,50 @@ assert.False(t, found) assert.Empty(t, val) } + +func TestNew_UsesContextPasswordCallback(t *testing.T) { + keyring.MockInit() + + var called bool + var purged string + + ctx := config.NewContextInMemory() + ctx = ctxutil.WithPasswordCallback(ctx, func(prompt string, confirm bool) ([]byte, error) { + called = true + assert.Equal(t, "prompt", prompt) + assert.True(t, confirm) + + return []byte("from-callback"), nil + }) + ctx = ctxutil.WithPasswordPurgeCallback(ctx, func(prompt string) { + purged = prompt + }) + + a, err := New(ctx, false, "") + require.NoError(t, err) + + pw, err := a.effectivePwCallback(ctx, "ignored")("prompt", true) + require.NoError(t, err) + assert.Equal(t, []byte("from-callback"), pw) + assert.True(t, called) + + a.effectivePwPurgeCallback()("prompt") + assert.Equal(t, "prompt", purged) +} + +func TestNew_ContextPasswordCallbackOverridesAgePassphrase(t *testing.T) { + keyring.MockInit() + + ctx := config.NewContextInMemory() + ctx = ctxutil.WithAgePassphrase(ctx, "from-env") + ctx = ctxutil.WithPasswordCallback(ctx, func(string, bool) ([]byte, error) { + return []byte("from-callback"), nil + }) + + a, err := New(ctx, false, "") + require.NoError(t, err) + + pw, err := a.effectivePwCallback(ctx, "ignored")("prompt", false) + require.NoError(t, err) + assert.Equal(t, []byte("from-callback"), pw) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/internal/create/templates.go new/gopass-1.17.1/internal/create/templates.go --- old/gopass-1.17.0/internal/create/templates.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/internal/create/templates.go 2026-09-09 22:44:38.000000000 +0200 @@ -59,6 +59,37 @@ - name: "comment" type: "string" `, + `--- +priority: 2 +name: "SSO / passwordless login (e.g. Google)" +prefix: "websites" +name_from: + - "url" + - "username" +welcome: "๐งช Creating SSO / passwordless login" +attributes: + - name: "url" + type: "hostname" + prompt: "Website URL" + min: 1 + max: 255 + - name: "username" + type: "string" + prompt: "Account / email" + min: 1 + - name: "login-method" + type: "choice" + prompt: "Login via" + options: + - "google" + - "apple" + - "github" + - "microsoft" + - "sso" + - "magic-link" + - name: "comment" + type: "string" +`, } type storageSetter interface { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/internal/create/wizard.go new/gopass-1.17.1/internal/create/wizard.go --- old/gopass-1.17.0/internal/create/wizard.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/internal/create/wizard.go 2026-09-09 22:44:38.000000000 +0200 @@ -38,14 +38,16 @@ // Attribute is a credential attribute that is being asked for // when populating a template. type Attribute struct { - Name string `yaml:"name"` - Type string `yaml:"type"` - Prompt string `yaml:"prompt"` - Charset string `yaml:"charset"` - Min int `yaml:"min"` - Max int `yaml:"max"` - AlwaysPrompt bool `yaml:"always_prompt"` // always prompt for the crendentials - Strict bool `yaml:"strict"` // enforce character class rules (all detected classes must be present) + Name string `yaml:"name"` + Type string `yaml:"type"` + Prompt string `yaml:"prompt"` + Charset string `yaml:"charset"` + Min int `yaml:"min"` + Max int `yaml:"max"` + AlwaysPrompt bool `yaml:"always_prompt"` // always prompt for the crendentials + Strict bool `yaml:"strict"` // enforce character class rules (all detected classes must be present) + Options []string `yaml:"options"` // selectable values for the "choice" attribute type + Optional bool `yaml:"optional"` // allow skipping a "password" attribute (e.g. SSO / social login accounts) } // Template is an action template for the create wizard. @@ -234,6 +236,19 @@ nameParts = append(nameParts, sv) } _ = sec.Set(k, sv) + case "choice": + if len(v.Options) < 1 { + return fmt.Errorf("choice attribute %s has no options", v.Name) + } + act, sel := cui.GetSelection(ctx, fmtfn(2, strconv.Itoa(step), v.Prompt), v.Options) + if act == "aborted" { + return exit.Error(exit.Aborted, nil, "user aborted") + } + choice := v.Options[sel] + if wantForName[k] { + nameParts = append(nameParts, choice) + } + _ = sec.Set(k, choice) case "multiline": ed := editor.Path(ctx, cmd) @@ -271,6 +286,20 @@ _ = sec.Set(k, sv) case "password": var err error + // Optional passwords let a single template cover accounts that + // authenticate without a stored password (e.g. login via Google / + // SSO / social login). When the user declines, we skip prompting + // and leave the password empty instead of storing a blank one. + if v.Optional { + var hasPw bool + hasPw, err = termio.AskForBool(ctx, fmtfn(2, strconv.Itoa(step), "Does this account have a password? (No for SSO / social login)"), true) + if err != nil { + return err + } + if !hasPw { + continue + } + } if !v.AlwaysPrompt { genPw, err = termio.AskForBool(ctx, fmtfn(2, strconv.Itoa(step), "Generate Password?"), true) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/internal/create/wizard_test.go new/gopass-1.17.1/internal/create/wizard_test.go --- old/gopass-1.17.0/internal/create/wizard_test.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/internal/create/wizard_test.go 2026-09-09 22:44:38.000000000 +0200 @@ -8,6 +8,7 @@ "github.com/gopasspw/gopass/internal/store/mockstore/inmem" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "go.yaml.in/yaml/v3" ) type fakeSetter struct{} @@ -91,3 +92,66 @@ assert.Equal(t, "password", w.Templates[0].Attributes[2].Type, "wrong type") assert.True(t, w.Templates[0].Attributes[2].AlwaysPrompt, "wrong always_prompt") } + +func TestDefaultTemplates(t *testing.T) { + t.Parallel() + + ctx := config.NewContextInMemory() + w := &Wizard{} + + tpls, err := w.parseTemplatesFallback(ctx) + require.NoError(t, err) + require.Len(t, tpls, len(defaultTemplates)) + + // find the SSO / passwordless template and validate it models a + // passwordless account: no password attribute, plus a login-method choice. + var sso *Template + for i := range tpls { + if tpls[i].Prefix == "websites" && len(tpls[i].Attributes) > 0 { + for _, a := range tpls[i].Attributes { + if a.Name == "login-method" { + sso = &tpls[i] + + break + } + } + } + if sso != nil { + break + } + } + require.NotNil(t, sso, "no SSO / passwordless template found") + + for _, a := range sso.Attributes { + assert.NotEqual(t, "password", a.Type, "SSO template must not contain a password attribute") + } + + var lm *Attribute + for i := range sso.Attributes { + if sso.Attributes[i].Name == "login-method" { + lm = &sso.Attributes[i] + + break + } + } + require.NotNil(t, lm) + assert.Equal(t, "choice", lm.Type, "login-method must be a choice") + assert.Contains(t, lm.Options, "google", "login-method must offer google") + assert.NotEmpty(t, lm.Options, "choice must have options") +} + +func TestOptionalPasswordParses(t *testing.T) { + t.Parallel() + + tpl := Template{} + require.NoError(t, yaml.Unmarshal([]byte(`--- +name: "optional pw" +prefix: "opt" +attributes: + - name: "password" + type: "password" + optional: true +`), &tpl)) + require.Len(t, tpl.Attributes, 1) + assert.True(t, tpl.Attributes[0].Optional, "optional flag must round-trip") +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/internal/store/leaf/reencrypt.go new/gopass-1.17.1/internal/store/leaf/reencrypt.go --- old/gopass-1.17.0/internal/store/leaf/reencrypt.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/internal/store/leaf/reencrypt.go 2026-09-09 22:44:38.000000000 +0200 @@ -86,6 +86,7 @@ } e = strings.TrimPrefix(e, s.alias) + e = strings.TrimPrefix(e, "/") jobs <- e } // We close the channel, so the workers will terminate diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/pkg/ctxutil/ctxutil.go new/gopass-1.17.1/pkg/ctxutil/ctxutil.go --- old/gopass-1.17.0/pkg/ctxutil/ctxutil.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/pkg/ctxutil/ctxutil.go 2026-09-09 22:44:38.000000000 +0200 @@ -4,6 +4,7 @@ import ( "context" + "errors" "time" "github.com/urfave/cli/v3" @@ -14,6 +15,8 @@ const ( // ctxKeyExecConfig holds the consolidated ExecConfig struct. ctxKeyExecConfig contextKey = iota + ctxKeyPasswordCallback + ctxKeyPasswordPurgeCallback ) // ExecConfig holds all boolean/string/struct configuration flags that are @@ -101,6 +104,18 @@ // ProgressCallback is a callback for updating progress. type ProgressCallback func() +// PasswordCallback is a password prompt callback used by the age crypto +// backend. The arguments are typically the filename and whether confirmation is +// required. +type PasswordCallback func(string, bool) ([]byte, error) + +// PasswordPurgeCallback invalidates a password previously cached by +// PasswordCallback. +type PasswordPurgeCallback func(string) + +// ErrNoCallback is returned by GetPasswordCallback when no callback was set. +var ErrNoCallback = errors.New("no callback") + // WithTerminal returns a context with an explicit value for whether or not we are // in a terminal. func WithTerminal(ctx context.Context, isTerm bool) context.Context { @@ -418,6 +433,55 @@ return GetExecConfig(ctx).Email } +// WithPasswordCallback returns a context with the password callback set. +func WithPasswordCallback(ctx context.Context, cb PasswordCallback) context.Context { + return context.WithValue(ctx, ctxKeyPasswordCallback, cb) +} + +// HasPasswordCallback returns true if a password callback was set in the +// context. +func HasPasswordCallback(ctx context.Context) bool { + _, ok := ctx.Value(ctxKeyPasswordCallback).(PasswordCallback) + + return ok +} + +// GetPasswordCallback returns the password callback or a default callback that +// fails with ErrNoCallback. +func GetPasswordCallback(ctx context.Context) PasswordCallback { + if pwcb, ok := ctx.Value(ctxKeyPasswordCallback).(PasswordCallback); ok && pwcb != nil { + return pwcb + } + + return func(string, bool) ([]byte, error) { + return nil, ErrNoCallback + } +} + +// WithPasswordPurgeCallback returns a context with the password purge callback +// set. +func WithPasswordPurgeCallback(ctx context.Context, cb PasswordPurgeCallback) context.Context { + return context.WithValue(ctx, ctxKeyPasswordPurgeCallback, cb) +} + +// HasPasswordPurgeCallback returns true if a password purge callback was set in +// the context. +func HasPasswordPurgeCallback(ctx context.Context) bool { + _, ok := ctx.Value(ctxKeyPasswordPurgeCallback).(PasswordPurgeCallback) + + return ok +} + +// GetPasswordPurgeCallback returns the password purge callback or a default +// no-op callback. +func GetPasswordPurgeCallback(ctx context.Context) PasswordPurgeCallback { + if ppcb, ok := ctx.Value(ctxKeyPasswordPurgeCallback).(PasswordPurgeCallback); ok && ppcb != nil { + return ppcb + } + + return func(string) {} +} + // WithAgePassphrase returns a context with the age passphrase set. // This is used by the age crypto backend to encrypt/decrypt the identity file // without interactive prompts (e.g. set from the GOPASS_AGE_PASSWORD env variable). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/pkg/ctxutil/ctxutil_test.go new/gopass-1.17.1/pkg/ctxutil/ctxutil_test.go --- old/gopass-1.17.0/pkg/ctxutil/ctxutil_test.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/pkg/ctxutil/ctxutil_test.go 2026-09-09 22:44:38.000000000 +0200 @@ -208,3 +208,46 @@ assert.True(t, HasSetupRemote(WithSetupRemote(ctx, "https://example.com/repo.git"))) assert.False(t, HasSetupRemote(WithSetupRemote(ctx, ""))) } + +func TestPasswordCallback(t *testing.T) { + t.Parallel() + + ctx := config.NewContextInMemory() + + _, err := GetPasswordCallback(ctx)("prompt", false) + require.ErrorIs(t, err, ErrNoCallback) + assert.False(t, HasPasswordCallback(ctx)) + + ctx = WithPasswordCallback(ctx, func(prompt string, confirm bool) ([]byte, error) { + assert.Equal(t, "prompt", prompt) + assert.True(t, confirm) + + return []byte("secret"), nil + }) + + pw, err := GetPasswordCallback(ctx)("prompt", true) + require.NoError(t, err) + assert.Equal(t, []byte("secret"), pw) + assert.True(t, HasPasswordCallback(ctx)) +} + +func TestPasswordPurgeCallback(t *testing.T) { + t.Parallel() + + ctx := config.NewContextInMemory() + + assert.False(t, HasPasswordPurgeCallback(ctx)) + assert.NotPanics(t, func() { + GetPasswordPurgeCallback(ctx)("prompt") + }) + + var purged bool + ctx = WithPasswordPurgeCallback(ctx, func(prompt string) { + assert.Equal(t, "prompt", prompt) + purged = true + }) + + GetPasswordPurgeCallback(ctx)("prompt") + assert.True(t, purged) + assert.True(t, HasPasswordPurgeCallback(ctx)) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/pkg/gopass/api/api.go new/gopass-1.17.1/pkg/gopass/api/api.go --- old/gopass-1.17.0/pkg/gopass/api/api.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/pkg/gopass/api/api.go 2026-09-09 22:44:38.000000000 +0200 @@ -16,6 +16,7 @@ // load crypto backends. _ "github.com/gopasspw/gopass/internal/backend/crypto" // load storage backends. + "github.com/gopasspw/gopass/internal/audit" _ "github.com/gopasspw/gopass/internal/backend/storage" "github.com/gopasspw/gopass/internal/config" "github.com/gopasspw/gopass/internal/queue" @@ -68,6 +69,14 @@ return g.rs.List(ctx, tree.INF) //nolint:wrapcheck } +// AuditList returns a list of all secret names, filtered against the optional +// .gopass-audit-ignore file at the root of each mount point. Secrets matching +// any of the exclude patterns (RE2 syntax) in the file of their mount point +// are omitted from the result. +func (g *Gopass) AuditList(ctx context.Context) ([]string, error) { + return audit.FilteredList(ctx, g.rs) +} + // Get returns a single, encrypted secret. It must be unwrapped before use. // Use "latest" to get the latest revision. // The revision parameter is not yet implemented. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/pkg/gopass/api/api_test.go new/gopass-1.17.1/pkg/gopass/api/api_test.go --- old/gopass-1.17.0/pkg/gopass/api/api_test.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/pkg/gopass/api/api_test.go 2026-09-09 22:44:38.000000000 +0200 @@ -6,6 +6,7 @@ "github.com/gopasspw/gopass/internal/config" "github.com/gopasspw/gopass/pkg/ctxutil" + "github.com/gopasspw/gopass/pkg/gopass" "github.com/gopasspw/gopass/pkg/gopass/api" "github.com/gopasspw/gopass/pkg/gopass/secrets" "github.com/stretchr/testify/assert" @@ -63,7 +64,10 @@ ctx = ctxutil.WithAlwaysYes(ctx, true) ctx = ctxutil.WithInteractive(ctx, false) - gp, err := api.New(ctx) + var gp gopass.Store + var err error + + gp, err = api.New(ctx) require.ErrorIs(t, err, api.ErrNotInitialized) assert.Nil(t, gp) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/pkg/gopass/apimock/mock.go new/gopass-1.17.1/pkg/gopass/apimock/mock.go --- old/gopass-1.17.0/pkg/gopass/apimock/mock.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/pkg/gopass/apimock/mock.go 2026-09-09 22:44:38.000000000 +0200 @@ -53,6 +53,12 @@ return a.store.List(ctx, "") //nolint:wrapcheck } +// AuditList returns a list of all secrets in the mock store. +// Filtering is not implemented in the mock store, so this is equivalent to List. +func (a *MockAPI) AuditList(ctx context.Context) ([]string, error) { + return a.store.List(ctx, "") //nolint:wrapcheck +} + // Get returns a secret from the mock store. func (a *MockAPI) Get(ctx context.Context, name, _ string) (gopass.Secret, error) { return a.store.Get(ctx, name) //nolint:wrapcheck diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/pkg/gopass/apimock/mock_test.go new/gopass-1.17.1/pkg/gopass/apimock/mock_test.go --- old/gopass-1.17.0/pkg/gopass/apimock/mock_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/gopass-1.17.1/pkg/gopass/apimock/mock_test.go 2026-09-09 22:44:38.000000000 +0200 @@ -0,0 +1,8 @@ +package apimock_test + +import ( + "github.com/gopasspw/gopass/pkg/gopass" + "github.com/gopasspw/gopass/pkg/gopass/apimock" +) + +var _ gopass.Store = apimock.New() //nolint:staticcheck diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/pkg/gopass/doc.go new/gopass-1.17.1/pkg/gopass/doc.go --- old/gopass-1.17.0/pkg/gopass/doc.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/pkg/gopass/doc.go 2026-09-09 22:44:38.000000000 +0200 @@ -10,6 +10,12 @@ // old symbol is removed. See docs/adr/A-12-pkg-api-stability.md for the full // policy. // +// Embedders that need to answer age identity passphrase prompts without using +// the gopass CLI can install a callback on the context with +// [github.com/gopasspw/gopass/pkg/ctxutil.WithPasswordCallback]. For +// non-interactive use cases with a fixed passphrase, use +// [github.com/gopasspw/gopass/pkg/ctxutil.WithAgePassphrase]. +// // Known consumers of this API: // - https://github.com/gopasspw/gopass-hibp // - https://github.com/gopasspw/gopass-jsonapi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/pkg/gopass/store.go new/gopass-1.17.1/pkg/gopass/store.go --- old/gopass-1.17.0/pkg/gopass/store.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/pkg/gopass/store.go 2026-09-09 22:44:38.000000000 +0200 @@ -46,6 +46,8 @@ // List lists all secrets in the store. List(context.Context) ([]string, error) + // AuditList lists all secrets in the store, filtered against the optional .gopass-audit-ignore file at the root of each mount point. + AuditList(ctx context.Context) ([]string, error) // Get returns a decrypted secret from the store. // The revision parameter defaults to "latest". Get(ctx context.Context, name, revision string) (Secret, error) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/gopass-1.17.0/version.go new/gopass-1.17.1/version.go --- old/gopass-1.17.0/version.go 2026-08-30 15:55:58.000000000 +0200 +++ new/gopass-1.17.1/version.go 2026-09-09 22:44:38.000000000 +0200 @@ -15,10 +15,10 @@ return semver.Version{ Major: 1, Minor: 17, - Patch: 0, + Patch: 1, Pre: []semver.PRVersion{ {VersionStr: "git"}, }, - Build: []string{"db760006"}, + Build: []string{"b9769532"}, } } ++++++ vendor.tar.xz ++++++ ++++ 7381 lines of diff (skipped)
