Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package fscrypt for openSUSE:Factory checked 
in at 2026-08-25 15:54:27
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/fscrypt (Old)
 and      /work/SRC/openSUSE:Factory/.fscrypt.new.1258 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "fscrypt"

Tue Aug 25 15:54:27 2026 rev:7 rq:1373568 version:0.3.7

Changes:
--------
--- /work/SRC/openSUSE:Factory/fscrypt/fscrypt.changes  2025-11-08 
16:36:30.113161497 +0100
+++ /work/SRC/openSUSE:Factory/.fscrypt.new.1258/fscrypt.changes        
2026-08-25 15:54:29.471289896 +0200
@@ -1,0 +2,21 @@
+Sat Aug 22 19:53:30 UTC 2026 - Marcus Rueckert <[email protected]>
+
+- update to 0.3.7:
+  - Upgraded various dependencies, including golang.org/x/crypto to
+    resolve the usual CVEs in it (but as usual, not actually
+    affecting fscrypt's use of it).
+  - When selecting password hashing parameters, fscrypt now takes
+    cgroup limitations into consideration.
+  - fscrypt encrypt no longer follows trailing symlinks when
+    writing the recovery instructions.
+  - fscrypt unlock no longer enters an infinite loop when an
+    incorrect key file is specified using --key=FILE, --quiet isn't
+    specified, and standard input is a terminal.
+  - fscrypt unlock no longer enters an infinite loop when an
+    incorrect password is specified, --quiet isn't specified, and
+    standard input isn't a terminal.
+  - The error message when multiple protectors are available now
+    mentions --unlock-with in addition to --protector.
+  - Documented the udev dependency for /dev/disk/by-uuid/ links.
+
+-------------------------------------------------------------------

Old:
----
  fscrypt-0.3.6.tar.gz

New:
----
  _service
  fscrypt-0.3.7.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ fscrypt.spec ++++++
--- /var/tmp/diff_new_pack.Sfb3QA/_old  2026-08-25 15:54:31.005344707 +0200
+++ /var/tmp/diff_new_pack.Sfb3QA/_new  2026-08-25 15:54:31.013344993 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package fscrypt
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,7 +17,7 @@
 
 
 Name:           fscrypt
-Version:        0.3.6
+Version:        0.3.7
 Release:        0
 Summary:        Go tool for managing Linux filesystem encryption
 License:        Apache-2.0

++++++ _service ++++++
<services>
  <service name="download_files" mode="manual"/>
  <service name="go_modules" mode="manual">
   <param name="compression">xz</param>
  </service>
</services>


++++++ fscrypt-0.3.6.tar.gz -> fscrypt-0.3.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/.github/workflows/ci.yml 
new/fscrypt-0.3.7/.github/workflows/ci.yml
--- old/fscrypt-0.3.6/.github/workflows/ci.yml  2025-11-04 23:08:18.000000000 
+0100
+++ new/fscrypt-0.3.7/.github/workflows/ci.yml  2026-08-22 17:57:07.000000000 
+0200
@@ -106,6 +106,26 @@
   #           make test
   #           make test-teardown
 
+  test-cgroup-integration:
+    name: Test cgroup integration
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v4
+    - uses: actions/setup-go@v2
+      with:
+        go-version: '1.25'
+    - name: Build test binary
+      run: go test -c -o cgroup.test ./cgroup/
+    - name: Run cgroup integration test
+      run: |
+        docker run --rm \
+          --cpus=0.5 --memory=128m \
+          -e CGROUP_EXPECTED_CPU_QUOTA=0.5 \
+          -e CGROUP_EXPECTED_MEMORY_LIMIT=134217728 \
+          -v "$PWD/cgroup.test":/cgroup.test:ro \
+          debian:bookworm-slim \
+          /cgroup.test -test.run TestIntegrationCgroupLimits -test.v
+
   run-cli-tests:
     name: Run command-line interface tests
     runs-on: ubuntu-latest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/Makefile new/fscrypt-0.3.7/Makefile
--- old/fscrypt-0.3.6/Makefile  2025-11-04 23:08:18.000000000 +0100
+++ new/fscrypt-0.3.7/Makefile  2026-08-22 17:57:07.000000000 +0200
@@ -16,7 +16,7 @@
 # the License.
 
 # Update this on each new release, along with the NEWS.md file.
-VERSION := v0.3.6
+VERSION := v0.3.7
 
 NAME := fscrypt
 PAM_NAME := pam_$(NAME)
@@ -115,6 +115,11 @@
 clean:
        rm -f $(BIN)/$(NAME) $(PAM_MODULE) $(TOOLS) coverage.out 
$(COVERAGE_FILES) $(PAM_CONFIG)
 
+###### Cgroup testdata ######
+.PHONY: gen-cgroup-testdata
+gen-cgroup-testdata:
+       bin/gen-cgroup-testdata
+
 ###### Go tests ######
 .PHONY: test test-setup test-teardown
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/NEWS.md new/fscrypt-0.3.7/NEWS.md
--- old/fscrypt-0.3.6/NEWS.md   2025-11-04 23:08:18.000000000 +0100
+++ new/fscrypt-0.3.7/NEWS.md   2026-08-22 17:57:07.000000000 +0200
@@ -1,5 +1,28 @@
 # `fscrypt` release notes
 
+## Version 0.3.7
+
+* Upgraded various dependencies, including `golang.org/x/crypto` to resolve the
+  usual CVEs in it (but as usual, not actually affecting `fscrypt`'s use of 
it).
+
+* When selecting password hashing parameters, `fscrypt` now takes cgroup
+  limitations into consideration.
+
+* `fscrypt encrypt` no longer follows trailing symlinks when writing the
+  recovery instructions.
+
+* `fscrypt unlock` no longer enters an infinite loop when an incorrect key file
+  is specified using `--key=FILE`, `--quiet` isn't specified, and standard 
input
+  is a terminal.
+
+* `fscrypt unlock` no longer enters an infinite loop when an incorrect password
+  is specified, `--quiet` isn't specified, and standard input isn't a terminal.
+
+* The error message when multiple protectors are available now mentions
+  `--unlock-with` in addition to `--protector`.
+
+* Documented the udev dependency for `/dev/disk/by-uuid/` links.
+
 ## Version 0.3.6
 
 * Upgraded various dependencies, including `golang.org/x/crypto` where the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/README.md new/fscrypt-0.3.7/README.md
--- old/fscrypt-0.3.6/README.md 2025-11-04 23:08:18.000000000 +0100
+++ new/fscrypt-0.3.7/README.md 2026-08-22 17:57:07.000000000 +0200
@@ -29,6 +29,7 @@
 - [Features](#features)
 - [Building and installing](#building-and-installing)
 - [Runtime dependencies](#runtime-dependencies)
+  - [udev dependency for cross-filesystem 
links](#udev-dependency-for-cross-filesystem-links)
 - [Configuration file](#configuration-file)
 - [Setting up `fscrypt` on a filesystem](#setting-up-fscrypt-on-a-filesystem)
 - [Setting up for login protectors](#setting-up-for-login-protectors)
@@ -313,6 +314,32 @@
 prerequisites may be needed too.  See [Configuration
 file](#configuration-file).
 
+### udev dependency for cross-filesystem links
+
+Cross-filesystem metadata links (for example `.fscrypt/protectors/*.link` files
+that point at a protector stored on another filesystem) prefer to identify the
+target filesystem by UUID via `/dev/disk/by-uuid`.  Those symlinks are created 
by
+the standard udev rule `60-persistent-storage.rules` (from systemd/udev, eudev,
+or classic udev).
+
+This is a **runtime / link-creation** dependency, not a build-time dependency:
+
+* **Link creation time:** when `fscrypt` writes a cross-filesystem link, it 
looks
+  up the target filesystem UUID under `/dev/disk/by-uuid`.  If that directory 
is
+  missing or does not contain a usable UUID symlink for the device, `fscrypt`
+  falls back to storing the mountpoint path only.
+* **Runtime (following a link):** when resolving an existing link that 
contains a
+  `UUID=` entry, `fscrypt` again uses `/dev/disk/by-uuid` (with a path 
fallback if
+  the UUID cannot be resolved).
+
+Most Linux distributions ship `60-persistent-storage.rules` by default.  If you
+run a minimal or custom udev setup without that rule, ensure equivalent rules
+still create `/dev/disk/by-uuid/*` symlinks before relying on UUID-based
+cross-filesystem links.  Example upstream sources:
+
+* [systemd 
`60-persistent-storage.rules`](https://github.com/systemd/systemd/blob/main/rules.d/60-persistent-storage.rules.in)
+* [eudev 
`60-persistent-storage.rules`](https://github.com/eudev-project/eudev/blob/master/rules/60-persistent-storage.rules)
+
 ## Configuration file
 
 Running `sudo fscrypt setup` will create the configuration file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/actions/config.go 
new/fscrypt-0.3.7/actions/config.go
--- old/fscrypt-0.3.6/actions/config.go 2025-11-04 23:08:18.000000000 +0100
+++ new/fscrypt-0.3.7/actions/config.go 2026-08-22 17:57:07.000000000 +0200
@@ -24,6 +24,7 @@
        "bytes"
        "fmt"
        "log"
+       "math"
        "os"
        "runtime"
        "time"
@@ -31,6 +32,7 @@
        "golang.org/x/sys/unix"
        "google.golang.org/protobuf/proto"
 
+       "github.com/google/fscrypt/cgroup"
        "github.com/google/fscrypt/crypto"
        "github.com/google/fscrypt/filesystem"
        "github.com/google/fscrypt/metadata"
@@ -186,8 +188,9 @@
 func getHashingCosts(target time.Duration) (*metadata.HashingCosts, error) {
        log.Printf("Finding hashing costs that take %v\n", target)
 
-       // Start out with the minimal possible costs that use all the CPUs.
-       parallelism := int64(runtime.NumCPU())
+       // Start out with the minimal possible costs that use all the available
+       // CPUs, respecting cgroup limits when present.
+       parallelism := int64(effectiveCPUCount())
        // golang.org/x/crypto/argon2 only supports parallelism up to 255.
        // For compatibility, don't use more than that amount.
        if parallelism > metadata.MaxParallelism {
@@ -248,9 +251,25 @@
        }
 }
 
+// effectiveCPUCount returns the number of CPUs available to this process,
+// taking cgroup limits into account. Falls back to runtime.NumCPU() when
+// cgroup information is unavailable.
+func effectiveCPUCount() int {
+       cg, err := cgroup.New()
+       if err != nil {
+               return runtime.NumCPU()
+       }
+       quota, err := cg.CPUQuota()
+       if err != nil || quota <= 0 {
+               return runtime.NumCPU()
+       }
+       cpus := int(math.Ceil(quota))
+       return min(cpus, runtime.NumCPU())
+}
+
 // memoryBytesLimit returns the maximum amount of memory we will use for
 // passphrase hashing. This will never be more than a reasonable maximum (for
-// compatibility) or an 8th the available system RAM.
+// compatibility) or an 8th the available RAM (considering cgroup limits).
 func memoryBytesLimit() int64 {
        // The sysinfo syscall only fails if given a bad address
        var info unix.Sysinfo_t
@@ -258,6 +277,11 @@
        util.NeverError(err)
 
        totalRAMBytes := int64(info.Totalram)
+       if cg, err := cgroup.New(); err == nil {
+               if cgroupMem, err := cg.MemoryLimit(); err == nil && cgroupMem 
> 0 {
+                       totalRAMBytes = util.MinInt64(totalRAMBytes, cgroupMem)
+               }
+       }
        return util.MinInt64(totalRAMBytes/8, maxMemoryBytes)
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/actions/recovery.go 
new/fscrypt-0.3.7/actions/recovery.go
--- old/fscrypt-0.3.6/actions/recovery.go       2025-11-04 23:08:18.000000000 
+0100
+++ new/fscrypt-0.3.7/actions/recovery.go       2026-08-22 17:57:07.000000000 
+0200
@@ -23,6 +23,7 @@
        "os"
        "strconv"
 
+       "golang.org/x/sys/unix"
        "google.golang.org/protobuf/proto"
 
        "github.com/google/fscrypt/crypto"
@@ -91,7 +92,7 @@
 // passphrase in a different location if they actually need it.
 func WriteRecoveryInstructions(recoveryPassphrase *crypto.Key, 
recoveryProtector *Protector,
        policy *Policy, path string) error {
-       file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0600)
+       file, err := os.OpenFile(path, 
os.O_WRONLY|os.O_CREATE|os.O_EXCL|unix.O_NOFOLLOW, 0600)
        if err != nil {
                return err
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/bin/gen-cgroup-testdata 
new/fscrypt-0.3.7/bin/gen-cgroup-testdata
--- old/fscrypt-0.3.6/bin/gen-cgroup-testdata   1970-01-01 01:00:00.000000000 
+0100
+++ new/fscrypt-0.3.7/bin/gen-cgroup-testdata   2026-08-22 17:57:07.000000000 
+0200
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+#
+# gen-cgroup-testdata - Generate cgroup testdata by running
+# bin/snapshot-cgroup inside Docker containers with known resource limits.
+#
+# Usage: gen-cgroup-testdata
+#
+# Prerequisites: Docker on a host running cgroup v2.
+#
+# Each testdata directory contains:
+#   expected.json  - {"cpu_quota": <float>, "memory_limit": <int>}
+#   proc/          - snapshot of /proc/self/cgroup
+#   sys/           - snapshot of cgroup control files
+
+set -euo pipefail
+
+cd "$(dirname "$0")/.."
+
+testdata="cgroup/testdata"
+snapshot_script="bin/snapshot-cgroup"
+
+generate() {
+    local name="$1" cpu_quota="$2" memory_limit="$3"
+    shift 3
+    local outdir="$testdata/$name"
+
+    echo "Generating $name..."
+    rm -rf "$outdir"
+    mkdir -p "$outdir"
+
+    docker run --rm \
+        --user "$(id -u):$(id -g)" \
+        "$@" \
+        -v "$PWD/$snapshot_script:/snapshot:ro" \
+        -v "$PWD/$outdir:/out" \
+        debian:bookworm-slim \
+        /snapshot /out
+
+    cat > "$outdir/expected.json" <<EOF
+{"cpu_quota": $cpu_quota, "memory_limit": $memory_limit}
+EOF
+}
+
+generate "v2-two-cores-256m"   2.0  268435456  --cpus=2   --memory=256m
+generate "v2-quarter-core-64m" 0.25 67108864   --cpus=0.25 --memory=64m
+generate "v2-no-limit"         null null
+
+echo "v2 testdata generated successfully."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/bin/snapshot-cgroup 
new/fscrypt-0.3.7/bin/snapshot-cgroup
--- old/fscrypt-0.3.6/bin/snapshot-cgroup       1970-01-01 01:00:00.000000000 
+0100
+++ new/fscrypt-0.3.7/bin/snapshot-cgroup       2026-08-22 17:57:07.000000000 
+0200
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+#
+# snapshot-cgroup - Copy cgroup v2 files from the live system into a
+# directory tree suitable for use with TestIntegrationCgroupLimits.
+#
+# Usage: snapshot-cgroup <output-dir>
+#
+# The script reads /proc/self/cgroup to find the v2 group path and copies
+# exactly the files that the cgroup package needs:
+#
+#   proc/self/cgroup
+#   sys/fs/cgroup/<group>/cpu.max
+#   sys/fs/cgroup/<group>/memory.max
+
+set -euo pipefail
+
+if [[ $# -ne 1 ]]; then
+    echo "Usage: $0 <output-dir>" >&2
+    exit 1
+fi
+
+out="$1"
+mkdir -p "$out"
+
+copy_file() {
+    local src="$1" dst="$out/$2"
+    mkdir -p "$(dirname "$dst")"
+    cp "$src" "$dst"
+}
+
+copy_file /proc/self/cgroup proc/self/cgroup
+
+group=$(awk -F: '/^0::/ { print $3 }' /proc/self/cgroup)
+cgdir="/sys/fs/cgroup${group}"
+
+for f in cpu.max memory.max; do
+    if [[ -f "$cgdir/$f" ]]; then
+        copy_file "$cgdir/$f" "sys/fs/cgroup${group}/$f"
+    fi
+done
+
+echo "Snapshot written to $out"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/cgroup/cgroup.go 
new/fscrypt-0.3.7/cgroup/cgroup.go
--- old/fscrypt-0.3.6/cgroup/cgroup.go  1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/cgroup.go  2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1,175 @@
+/*
+ * cgroup.go - Read CPU and memory limits from Linux cgroups v2.
+ *
+ * Copyright 2026 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy 
of
+ * the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations 
under
+ * the License.
+ */
+
+// Package cgroup reads CPU and memory resource limits from Linux control
+// groups (cgroup v2).
+//
+// References:
+//   - cgroups(7):           
https://man7.org/linux/man-pages/man7/cgroups.7.html
+//   - cgroup v2 (cpu.max, memory.max): 
https://docs.kernel.org/admin-guide/cgroup-v2.html
+//   - /proc/self/cgroup:    
https://man7.org/linux/man-pages/man7/cgroups.7.html (see "/proc files")
+package cgroup
+
+import (
+       "bufio"
+       "errors"
+       "fmt"
+       "os"
+       "path/filepath"
+       "strconv"
+       "strings"
+)
+
+// Errors.
+var (
+       // ErrNoLimit indicates that no cgroup limit is set.
+       ErrNoLimit = errors.New("no cgroup limit set")
+
+       // ErrV1Detected indicates that cgroup v1 controllers were found. Only 
v2 is
+       // supported.
+       ErrV1Detected = errors.New("cgroup v1 detected; only v2 is supported")
+)
+
+// Cgroup provides access to cgroup v2 resource limits. Create one with
+// New or NewFromRoot.
+type Cgroup struct {
+       // cgroupDir is the resolved filesystem path to the cgroup directory
+       // (e.g. /sys/fs/cgroup/user.slice/...).
+       cgroupDir string
+}
+
+// New returns a Cgroup by reading /proc/self/cgroup on the live system.
+func New() (Cgroup, error) {
+       return NewFromRoot("/")
+}
+
+// NewFromRoot is like New but resolves all filesystem paths relative to
+// root instead of "/". This is useful for testing with a mock filesystem.
+func NewFromRoot(root string) (Cgroup, error) {
+       groupPath, err := parseProcCgroup(filepath.Join(root, 
"proc/self/cgroup"))
+       if err != nil {
+               return Cgroup{}, err
+       }
+       return Cgroup{
+               cgroupDir: filepath.Join(root, "sys/fs/cgroup", groupPath),
+       }, nil
+}
+
+// CPUQuota returns the CPU quota as a fractional number of CPUs (e.g. 0.5
+// means half a core). Returns ErrNoLimit if no CPU limit is configured.
+func (c Cgroup) CPUQuota() (float64, error) {
+       data, err := c.readFile("cpu.max")
+       if err != nil {
+               return 0, err
+       }
+       return parseCPUMax(data)
+}
+
+// MemoryLimit returns the cgroup memory limit in bytes. Returns ErrNoLimit
+// if no memory limit is configured.
+func (c Cgroup) MemoryLimit() (int64, error) {
+       data, err := c.readFile("memory.max")
+       if err != nil {
+               return 0, err
+       }
+       return parseMemoryMax(data)
+}
+
+func (c Cgroup) readFile(path string) (string, error) {
+       data, err := os.ReadFile(filepath.Join(c.cgroupDir, path))
+       if err != nil {
+               if os.IsNotExist(err) {
+                       return "", ErrNoLimit
+               }
+               return "", err
+       }
+       return strings.TrimSpace(string(data)), nil
+}
+
+// parseProcCgroup parses /proc/self/cgroup and returns the cgroup v2 group
+// path. The v2 entry is the line with hierarchy-ID "0" and an empty
+// controller list: "0::<path>".
+//
+// Returns an error if v1 controllers are detected or no v2 entry is found.
+//
+// https://man7.org/linux/man-pages/man7/cgroups.7.html
+func parseProcCgroup(path string) (string, error) {
+       f, err := os.Open(path)
+       if err != nil {
+               return "", err
+       }
+       defer f.Close()
+
+       var v2Path string
+
+       scanner := bufio.NewScanner(f)
+       for scanner.Scan() {
+               parts := strings.SplitN(scanner.Text(), ":", 3)
+               if len(parts) != 3 {
+                       continue
+               }
+               if parts[0] == "0" && parts[1] == "" {
+                       v2Path = parts[2]
+               } else if parts[1] != "" {
+                       return "", ErrV1Detected
+               }
+       }
+       if err := scanner.Err(); err != nil {
+               return "", err
+       }
+       if v2Path == "" {
+               return "", fmt.Errorf("no cgroup v2 entry found in %s", path)
+       }
+       return v2Path, nil
+}
+
+func parseCPUMax(content string) (float64, error) {
+       fields := strings.Fields(content)
+       if len(fields) == 0 || len(fields) > 2 {
+               return 0, fmt.Errorf("unexpected cpu.max format: %q", content)
+       }
+       if fields[0] == "max" {
+               return 0, ErrNoLimit
+       }
+       quota, err := strconv.ParseFloat(fields[0], 64)
+       if err != nil {
+               return 0, fmt.Errorf("parsing cpu.max quota: %w", err)
+       }
+       period := 100000.0
+       if len(fields) == 2 {
+               period, err = strconv.ParseFloat(fields[1], 64)
+               if err != nil {
+                       return 0, fmt.Errorf("parsing cpu.max period: %w", err)
+               }
+               if period == 0 {
+                       return 0, fmt.Errorf("cpu.max period is zero")
+               }
+       }
+       return quota / period, nil
+}
+
+func parseMemoryMax(content string) (int64, error) {
+       if content == "max" {
+               return 0, ErrNoLimit
+       }
+       v, err := strconv.ParseInt(content, 10, 64)
+       if err != nil {
+               return 0, fmt.Errorf("parsing memory.max: %w", err)
+       }
+       return v, nil
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/cgroup/cgroup_test.go 
new/fscrypt-0.3.7/cgroup/cgroup_test.go
--- old/fscrypt-0.3.6/cgroup/cgroup_test.go     1970-01-01 01:00:00.000000000 
+0100
+++ new/fscrypt-0.3.7/cgroup/cgroup_test.go     2026-08-22 17:57:07.000000000 
+0200
@@ -0,0 +1,164 @@
+/*
+ * cgroup_test.go - Tests for cgroup CPU and memory limit reading.
+ *
+ * Copyright 2026 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy 
of
+ * the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations 
under
+ * the License.
+ */
+
+package cgroup
+
+import (
+       "encoding/json"
+       "errors"
+       "math"
+       "os"
+       "path/filepath"
+       "strconv"
+       "testing"
+)
+
+func writeFile(t *testing.T, path, content string) {
+       t.Helper()
+       if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+               t.Fatal(err)
+       }
+       if err := os.WriteFile(path, []byte(content), 0644); err != nil {
+               t.Fatal(err)
+       }
+}
+
+func TestCgroupV1Unsupported(t *testing.T) {
+       content := `12:memory:/docker/abc123
+11:cpu,cpuacct:/docker/abc123
+`
+       root := t.TempDir()
+       writeFile(t, filepath.Join(root, "proc/self/cgroup"), content)
+       _, err := NewFromRoot(root)
+       if !errors.Is(err, ErrV1Detected) {
+               t.Fatalf("NewFromRoot() error = %v, want %v", err, 
ErrV1Detected)
+       }
+}
+
+// testdataExpected holds the expected values from a testdata/*/expected.json.
+// Null fields indicate that ErrNoLimit is expected.
+type testdataExpected struct {
+       CPUQuota    *float64 `json:"cpu_quota"`
+       MemoryLimit *int64   `json:"memory_limit"`
+}
+
+// TestWithRootFromTestdata runs NewFromRoot, CPUQuota, and MemoryLimit
+// against filesystem snapshots captured from real Docker containers by
+// bin/snapshot-cgroup. Each subdirectory of testdata/ is a separate test
+// case containing a proc/ and sys/ tree plus an expected.json.
+//
+// Regenerate with: bin/gen-cgroup-testdata
+func TestWithRootFromTestdata(t *testing.T) {
+       entries, err := os.ReadDir("testdata")
+       if err != nil {
+               t.Fatalf("no testdata directory: %v", err)
+       }
+
+       for _, entry := range entries {
+               if !entry.IsDir() {
+                       continue
+               }
+               name := entry.Name()
+               root := filepath.Join("testdata", name)
+
+               t.Run(name, func(t *testing.T) {
+                       data, err := os.ReadFile(filepath.Join(root, 
"expected.json"))
+                       if err != nil {
+                               t.Fatalf("reading expected.json: %v", err)
+                       }
+                       var want testdataExpected
+                       if err := json.Unmarshal(data, &want); err != nil {
+                               t.Fatalf("parsing expected.json: %v", err)
+                       }
+
+                       cg, err := NewFromRoot(root)
+                       if err != nil {
+                               t.Fatalf("NewFromRoot(%q): %v", root, err)
+                       }
+
+                       gotCPU, err := cg.CPUQuota()
+                       if want.CPUQuota == nil {
+                               if !errors.Is(err, ErrNoLimit) {
+                                       t.Errorf("CPUQuota() error = %v, want 
ErrNoLimit", err)
+                               }
+                       } else if err != nil {
+                               t.Fatalf("CPUQuota(): %v", err)
+                       } else if math.Abs(gotCPU-*want.CPUQuota) > 0.001 {
+                               t.Errorf("CPUQuota() = %v, want %v", gotCPU, 
*want.CPUQuota)
+                       }
+
+                       gotMem, err := cg.MemoryLimit()
+                       if want.MemoryLimit == nil {
+                               if !errors.Is(err, ErrNoLimit) {
+                                       t.Errorf("MemoryLimit() error = %v, 
want ErrNoLimit", err)
+                               }
+                       } else if err != nil {
+                               t.Fatalf("MemoryLimit(): %v", err)
+                       } else if gotMem != *want.MemoryLimit {
+                               t.Errorf("MemoryLimit() = %v, want %v", gotMem, 
*want.MemoryLimit)
+                       }
+               })
+       }
+}
+
+// TestIntegrationCgroupLimits calls the real New(), CPUQuota(), and
+// MemoryLimit() against the live kernel cgroup interface. It is intended to
+// run inside a Docker container started with --cpus and --memory flags.
+//
+// The test is skipped unless CGROUP_EXPECTED_CPU_QUOTA and
+// CGROUP_EXPECTED_MEMORY_LIMIT are set in the environment.
+func TestIntegrationCgroupLimits(t *testing.T) {
+       cpuStr := os.Getenv("CGROUP_EXPECTED_CPU_QUOTA")
+       memStr := os.Getenv("CGROUP_EXPECTED_MEMORY_LIMIT")
+       if cpuStr == "" && memStr == "" {
+               t.Skip("set CGROUP_EXPECTED_CPU_QUOTA and 
CGROUP_EXPECTED_MEMORY_LIMIT to run")
+       }
+
+       cg, err := New()
+       if err != nil {
+               t.Fatalf("New() error: %v", err)
+       }
+
+       if cpuStr != "" {
+               wantCPU, err := strconv.ParseFloat(cpuStr, 64)
+               if err != nil {
+                       t.Fatalf("bad CGROUP_EXPECTED_CPU_QUOTA %q: %v", 
cpuStr, err)
+               }
+               gotCPU, err := cg.CPUQuota()
+               if err != nil {
+                       t.Fatalf("CPUQuota() error: %v", err)
+               }
+               if math.Abs(gotCPU-wantCPU) > 0.001 {
+                       t.Errorf("CPUQuota() = %v, want %v", gotCPU, wantCPU)
+               }
+       }
+
+       if memStr != "" {
+               wantMem, err := strconv.ParseInt(memStr, 10, 64)
+               if err != nil {
+                       t.Fatalf("bad CGROUP_EXPECTED_MEMORY_LIMIT %q: %v", 
memStr, err)
+               }
+               gotMem, err := cg.MemoryLimit()
+               if err != nil {
+                       t.Fatalf("MemoryLimit() error: %v", err)
+               }
+               if gotMem != wantMem {
+                       t.Errorf("MemoryLimit() = %v, want %v", gotMem, wantMem)
+               }
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-no-limit/expected.json 
new/fscrypt-0.3.7/cgroup/testdata/v2-no-limit/expected.json
--- old/fscrypt-0.3.6/cgroup/testdata/v2-no-limit/expected.json 1970-01-01 
01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-no-limit/expected.json 2026-08-22 
17:57:07.000000000 +0200
@@ -0,0 +1 @@
+{"cpu_quota": null, "memory_limit": null}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-no-limit/proc/self/cgroup 
new/fscrypt-0.3.7/cgroup/testdata/v2-no-limit/proc/self/cgroup
--- old/fscrypt-0.3.6/cgroup/testdata/v2-no-limit/proc/self/cgroup      
1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-no-limit/proc/self/cgroup      
2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+0::/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-no-limit/sys/fs/cgroup/cpu.max 
new/fscrypt-0.3.7/cgroup/testdata/v2-no-limit/sys/fs/cgroup/cpu.max
--- old/fscrypt-0.3.6/cgroup/testdata/v2-no-limit/sys/fs/cgroup/cpu.max 
1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-no-limit/sys/fs/cgroup/cpu.max 
2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+max 100000
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-no-limit/sys/fs/cgroup/memory.max 
new/fscrypt-0.3.7/cgroup/testdata/v2-no-limit/sys/fs/cgroup/memory.max
--- old/fscrypt-0.3.6/cgroup/testdata/v2-no-limit/sys/fs/cgroup/memory.max      
1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-no-limit/sys/fs/cgroup/memory.max      
2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+max
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-quarter-core-64m/expected.json 
new/fscrypt-0.3.7/cgroup/testdata/v2-quarter-core-64m/expected.json
--- old/fscrypt-0.3.6/cgroup/testdata/v2-quarter-core-64m/expected.json 
1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-quarter-core-64m/expected.json 
2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+{"cpu_quota": 0.25, "memory_limit": 67108864}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-quarter-core-64m/proc/self/cgroup 
new/fscrypt-0.3.7/cgroup/testdata/v2-quarter-core-64m/proc/self/cgroup
--- old/fscrypt-0.3.6/cgroup/testdata/v2-quarter-core-64m/proc/self/cgroup      
1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-quarter-core-64m/proc/self/cgroup      
2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+0::/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-quarter-core-64m/sys/fs/cgroup/cpu.max 
new/fscrypt-0.3.7/cgroup/testdata/v2-quarter-core-64m/sys/fs/cgroup/cpu.max
--- old/fscrypt-0.3.6/cgroup/testdata/v2-quarter-core-64m/sys/fs/cgroup/cpu.max 
1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-quarter-core-64m/sys/fs/cgroup/cpu.max 
2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+25000 100000
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-quarter-core-64m/sys/fs/cgroup/memory.max 
new/fscrypt-0.3.7/cgroup/testdata/v2-quarter-core-64m/sys/fs/cgroup/memory.max
--- 
old/fscrypt-0.3.6/cgroup/testdata/v2-quarter-core-64m/sys/fs/cgroup/memory.max  
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/fscrypt-0.3.7/cgroup/testdata/v2-quarter-core-64m/sys/fs/cgroup/memory.max  
    2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+67108864
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-two-cores-256m/expected.json 
new/fscrypt-0.3.7/cgroup/testdata/v2-two-cores-256m/expected.json
--- old/fscrypt-0.3.6/cgroup/testdata/v2-two-cores-256m/expected.json   
1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-two-cores-256m/expected.json   
2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+{"cpu_quota": 2.0, "memory_limit": 268435456}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-two-cores-256m/proc/self/cgroup 
new/fscrypt-0.3.7/cgroup/testdata/v2-two-cores-256m/proc/self/cgroup
--- old/fscrypt-0.3.6/cgroup/testdata/v2-two-cores-256m/proc/self/cgroup        
1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-two-cores-256m/proc/self/cgroup        
2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+0::/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-two-cores-256m/sys/fs/cgroup/cpu.max 
new/fscrypt-0.3.7/cgroup/testdata/v2-two-cores-256m/sys/fs/cgroup/cpu.max
--- old/fscrypt-0.3.6/cgroup/testdata/v2-two-cores-256m/sys/fs/cgroup/cpu.max   
1970-01-01 01:00:00.000000000 +0100
+++ new/fscrypt-0.3.7/cgroup/testdata/v2-two-cores-256m/sys/fs/cgroup/cpu.max   
2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+200000 100000
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/fscrypt-0.3.6/cgroup/testdata/v2-two-cores-256m/sys/fs/cgroup/memory.max 
new/fscrypt-0.3.7/cgroup/testdata/v2-two-cores-256m/sys/fs/cgroup/memory.max
--- 
old/fscrypt-0.3.6/cgroup/testdata/v2-two-cores-256m/sys/fs/cgroup/memory.max    
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/fscrypt-0.3.7/cgroup/testdata/v2-two-cores-256m/sys/fs/cgroup/memory.max    
    2026-08-22 17:57:07.000000000 +0200
@@ -0,0 +1 @@
+268435456
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/cli-tests/t_encrypt_raw_key.out 
new/fscrypt-0.3.7/cli-tests/t_encrypt_raw_key.out
--- old/fscrypt-0.3.6/cli-tests/t_encrypt_raw_key.out   2025-11-04 
23:08:18.000000000 +0100
+++ new/fscrypt-0.3.7/cli-tests/t_encrypt_raw_key.out   2026-08-22 
17:57:07.000000000 +0200
@@ -72,3 +72,25 @@
 Protected with 1 protector:
 PROTECTOR         LINKED  DESCRIPTION
 desc11  No      raw key protector "prot"
+
+# Try to unlock with wrong key, both with and without --quiet
+"MNT/dir" is now locked.
+[ERROR] fscrypt unlock: incorrect key provided
+[ERROR] fscrypt unlock: incorrect key provided
+ext4 filesystem "MNT" has 1 protector and 1 policy.
+All users can create fscrypt metadata on this filesystem.
+
+PROTECTOR         LINKED  DESCRIPTION
+desc16  No      raw key protector "prot"
+
+POLICY                            UNLOCKED  PROTECTORS
+desc17  No        desc16
+"MNT/dir" is encrypted with fscrypt.
+
+Policy:   desc17
+Options:  padding:32 contents:AES_256_XTS filenames:AES_256_CTS 
policy_version:2
+Unlocked: No
+
+Protected with 1 protector:
+PROTECTOR         LINKED  DESCRIPTION
+desc16  No      raw key protector "prot"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/cli-tests/t_encrypt_raw_key.sh 
new/fscrypt-0.3.7/cli-tests/t_encrypt_raw_key.sh
--- old/fscrypt-0.3.6/cli-tests/t_encrypt_raw_key.sh    2025-11-04 
23:08:18.000000000 +0100
+++ new/fscrypt-0.3.7/cli-tests/t_encrypt_raw_key.sh    2026-08-22 
17:57:07.000000000 +0200
@@ -51,3 +51,12 @@
 fscrypt lock "$dir"
 fscrypt unlock --quiet "$dir" < "$raw_key_file"
 show_status true
+
+begin "Try to unlock with wrong key, both with and without --quiet"
+head -c 32 /dev/urandom > "$raw_key_file"
+fscrypt encrypt --quiet --name=prot --source=raw_key --key="$raw_key_file" 
"$dir"
+fscrypt lock "$dir"
+head -c 32 /dev/urandom > "$raw_key_file"
+_expect_failure "fscrypt unlock --quiet --key='$raw_key_file' '$dir'"
+_expect_failure "fscrypt unlock --key='$raw_key_file' '$dir'"
+show_status true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/cli-tests/t_unlock.out 
new/fscrypt-0.3.7/cli-tests/t_unlock.out
--- old/fscrypt-0.3.6/cli-tests/t_unlock.out    2025-11-04 23:08:18.000000000 
+0100
+++ new/fscrypt-0.3.7/cli-tests/t_unlock.out    2026-08-22 17:57:07.000000000 
+0200
@@ -62,6 +62,30 @@
 PROTECTOR         LINKED  DESCRIPTION
 desc2  No      custom protector "prot"
 
+# Try to unlock with no stdin
+[ERROR] fscrypt unlock: incorrect key provided
+"MNT/dir" is encrypted with fscrypt.
+
+Policy:   desc1
+Options:  padding:32 contents:AES_256_XTS filenames:AES_256_CTS 
policy_version:2
+Unlocked: No
+
+Protected with 1 protector:
+PROTECTOR         LINKED  DESCRIPTION
+desc2  No      custom protector "prot"
+
+# Try to unlock with only a newline
+[ERROR] fscrypt unlock: incorrect key provided
+"MNT/dir" is encrypted with fscrypt.
+
+Policy:   desc1
+Options:  padding:32 contents:AES_256_XTS filenames:AES_256_CTS 
policy_version:2
+Unlocked: No
+
+Protected with 1 protector:
+PROTECTOR         LINKED  DESCRIPTION
+desc2  No      custom protector "prot"
+
 # Unlock directory
 Enter custom passphrase for protector "prot": "MNT/dir" is now unlocked and 
ready for use.
 
@@ -90,7 +114,7 @@
                         the policy metadata for "MNT/dir".
                         This directory has either been encrypted with another
                         tool (such as e4crypt), or the file
-                        "MNT/.fscrypt/policies/desc20"
+                        "MNT/.fscrypt/policies/desc24"
                         has been deleted.
 
 # Try to unlock with missing protector metadata
@@ -103,14 +127,14 @@
 [ERROR] fscrypt unlock: inconsistent metadata between encrypted directory
                         "MNT/dir1" and its corresponding
                         metadata file
-                        "MNT/.fscrypt/policies/desc21".
+                        "MNT/.fscrypt/policies/desc25".
 
                         Directory has
-                        descriptor:desc21 padding:32
+                        descriptor:desc25 padding:32
                         contents:AES_256_XTS filenames:AES_256_CTS
                         policy_version:2
 
                         Metadata file has
-                        descriptor:desc23 padding:32
+                        descriptor:desc27 padding:32
                         contents:AES_256_XTS filenames:AES_256_CTS
                         policy_version:2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/cli-tests/t_unlock.sh 
new/fscrypt-0.3.7/cli-tests/t_unlock.sh
--- old/fscrypt-0.3.6/cli-tests/t_unlock.sh     2025-11-04 23:08:18.000000000 
+0100
+++ new/fscrypt-0.3.7/cli-tests/t_unlock.sh     2026-08-22 17:57:07.000000000 
+0200
@@ -38,6 +38,14 @@
 _expect_failure "echo bad | fscrypt unlock --quiet '$dir'"
 fscrypt status "$dir"
 
+_print_header "Try to unlock with no stdin"
+_expect_failure "fscrypt unlock --quiet '$dir' </dev/null"
+fscrypt status "$dir"
+
+_print_header "Try to unlock with only a newline"
+_expect_failure "echo | fscrypt unlock --quiet '$dir'"
+fscrypt status "$dir"
+
 _print_header "Unlock directory"
 echo hunter2 | fscrypt unlock "$dir"
 _print_header "=> Check dir status"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/cmd/fscrypt/errors.go 
new/fscrypt-0.3.7/cmd/fscrypt/errors.go
--- old/fscrypt-0.3.6/cmd/fscrypt/errors.go     2025-11-04 23:08:18.000000000 
+0100
+++ new/fscrypt-0.3.7/cmd/fscrypt/errors.go     2026-08-22 17:57:07.000000000 
+0200
@@ -272,7 +272,8 @@
                return fmt.Sprintf("If desired, use %s to automatically run 
destructive operations.",
                        shortDisplay(forceFlag))
        case ErrSpecifyProtector:
-               return fmt.Sprintf("Use %s to specify a protector.", 
shortDisplay(protectorFlag))
+               return fmt.Sprintf("Use %s or %s to specify a protector.",
+                       shortDisplay(protectorFlag), 
shortDisplay(unlockWithFlag))
        case ErrSpecifyKeyFile:
                return fmt.Sprintf("Use %s to specify a key file.", 
shortDisplay(keyFileFlag))
        case ErrDropCachesPerm:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/cmd/fscrypt/keys.go 
new/fscrypt-0.3.7/cmd/fscrypt/keys.go
--- old/fscrypt-0.3.6/cmd/fscrypt/keys.go       2025-11-04 23:08:18.000000000 
+0100
+++ new/fscrypt-0.3.7/cmd/fscrypt/keys.go       2026-08-22 17:57:07.000000000 
+0200
@@ -144,11 +144,17 @@
                        if !supportRetry {
                                panic("this KeyFunc does not support retrying")
                        }
-                       // Don't retry for non-interactive sessions
-                       if quietFlag.Value {
+                       // Don't retry in --quiet mode, for non-interactive
+                       // sessions, or when a key file was specified.
+                       if quietFlag.Value || !term.IsTerminal(stdinFd) ||
+                               (info.Source() == metadata.SourceType_raw_key 
&& keyFileFlag.Value != "") {
                                return nil, ErrWrongKey
                        }
-                       fmt.Println("Incorrect Passphrase")
+                       if info.Source() == metadata.SourceType_raw_key {
+                               fmt.Println("Incorrect Key")
+                       } else {
+                               fmt.Println("Incorrect Passphrase")
+                       }
                }
 
                switch info.Source() {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/go.mod new/fscrypt-0.3.7/go.mod
--- old/fscrypt-0.3.6/go.mod    2025-11-04 23:08:18.000000000 +0100
+++ new/fscrypt-0.3.7/go.mod    2026-08-22 17:57:07.000000000 +0200
@@ -1,17 +1,15 @@
 module github.com/google/fscrypt
 
-go 1.23.0
-
-toolchain go1.23.12
+go 1.25.0
 
 require (
        github.com/client9/misspell v0.3.4
        github.com/pkg/errors v0.9.1
        github.com/urfave/cli v1.22.17
        github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad
-       golang.org/x/crypto v0.41.0
-       golang.org/x/sys v0.35.0
-       golang.org/x/term v0.34.0
+       golang.org/x/crypto v0.52.0
+       golang.org/x/sys v0.45.0
+       golang.org/x/term v0.43.0
        golang.org/x/tools v0.36.0
        google.golang.org/protobuf v1.36.10
        honnef.co/go/tools v0.6.1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/fscrypt-0.3.6/go.sum new/fscrypt-0.3.7/go.sum
--- old/fscrypt-0.3.6/go.sum    2025-11-04 23:08:18.000000000 +0100
+++ new/fscrypt-0.3.7/go.sum    2026-08-22 17:57:07.000000000 +0200
@@ -28,18 +28,18 @@
 github.com/urfave/cli v1.22.17/go.mod 
h1:b0ht0aqgH/6pBYzzxURyrM4xXNgsoT/n2ZzwQiEhNVo=
 github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad 
h1:W0LEBv82YCGEtcmPA3uNZBI33/qF//HAAs3MawDjRa0=
 github.com/wadey/gocovmerge v0.0.0-20160331181800-b5bfa59ec0ad/go.mod 
h1:Hy8o65+MXnS6EwGElrSRjUzQDLXreJlzYLlWiHtt8hM=
-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/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
+golang.org/x/crypto v0.52.0/go.mod 
h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
 golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 
h1:1P7xPZEwZMoBoz0Yze5Nx2/4pxj6nw9ZqHWXqP0iRgQ=
 golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678/go.mod 
h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
 golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
 golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
 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.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
-golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-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/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
+golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
+golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
+golang.org/x/term v0.43.0/go.mod 
h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
 golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
 golang.org/x/tools v0.36.0/go.mod 
h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
 golang.org/x/tools/go/expect v0.1.1-deprecated 
h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=

++++++ vendor.tar.xz ++++++
++++ 11407 lines of diff (skipped)

Reply via email to