Severity: major
A script that redirects secret get to a file sees success with a truncated or empty file; the stored secret is intact.
What happens: GetSecret and GetSecretWithVersion write the value with _, _ = cmd.OutOrStdout().Write(value.Bytes()), so a short write, a full disk, a closed stdout or a broken pipe is neither reported nor reflected in the exit status.
Reproduction, after secret init and echo v | secret add s:
SB_UNLOCK_PASSPHRASE=... secret get s > /dev/full; echo $? # 0, no error
SB_UNLOCK_PASSPHRASE=... secret get s >&-; echo $? # 0, no error
secret list has the same shape (_, _ = fmt.Fprintf(out, ...)), but get is the one whose output is the secret.
Correct behaviour: a write error is returned as the command's error, so the exit status is 1 and stderr says the value could not be written (a broken pipe is the usual exception: the reader went away, and reporting it is optional).
Definition of done
secret get s > /dev/full exits 1 with an error naming the write failure; get to a closed stdout exits 1.
A test runs get with stdout set to a writer that fails and requires a non-nil error; it fails before the fix.
Model: fable-5-1
Severity: major
A script that redirects `secret get` to a file sees success with a truncated or empty file; the stored secret is intact.
What happens: `GetSecret` and `GetSecretWithVersion` write the value with `_, _ = cmd.OutOrStdout().Write(value.Bytes())`, so a short write, a full disk, a closed stdout or a broken pipe is neither reported nor reflected in the exit status.
Reproduction, after `secret init` and `echo v | secret add s`:
```
SB_UNLOCK_PASSPHRASE=... secret get s > /dev/full; echo $? # 0, no error
SB_UNLOCK_PASSPHRASE=... secret get s >&-; echo $? # 0, no error
```
`secret list` has the same shape (`_, _ = fmt.Fprintf(out, ...)`), but `get` is the one whose output is the secret.
Where: https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/secrets.go#L446 (`GetSecret`) and https://git.eeqj.de/sneak/secret/src/commit/ef0ae90768c8b18a829033b3ebd4cf98fcaeb3d1/internal/cli/secrets.go#L481 (`GetSecretWithVersion`).
Correct behaviour: a write error is returned as the command's error, so the exit status is 1 and stderr says the value could not be written (a broken pipe is the usual exception: the reader went away, and reporting it is optional).
**Definition of done**
- `secret get s > /dev/full` exits 1 with an error naming the write failure; `get` to a closed stdout exits 1.
- A test runs `get` with stdout set to a writer that fails and requires a non-nil error; it fails before the fix.
Model: fable-5-1
sneak
was assigned by clawbot2026-10-13 00:38:38 +02:00
Reassigned to clawbot: sneak ruled that nothing is a release candidate while a known bug is open (sneak/project-management#32).
Plan: as the issue says: any failed write of the value is returned as the command's error, exit 1.
Model: opus-5-5
Reassigned to clawbot: sneak ruled that nothing is a release candidate while a known bug is open (https://git.eeqj.de/sneak/project-management/issues/32).
Plan: as the issue says: any failed write of the value is returned as the command's error, exit 1.
Model: opus-5-5
sneak
was unassigned by clawbot2026-10-14 19:42:58 +02:00
clawbot
self-assigned this 2026-10-14 19:42:58 +02:00
clawbot
added this to the 1.0.0 milestone 2026-10-14 19:42:59 +02:00
Reading taken on the closed-stdout item of the Definition of done: it cannot be met when the shell closes stdout before secret starts. The Go runtime opens /dev/null for a closed standard descriptor before any of secret runs, so the value goes there and secret get exits 0. Telling that apart from a deliberate redirect to /dev/null would need a check of how the descriptor was opened, which I did not build.
What the PR does: any failed write of the value is the command's error and it exits 1. That covers a full disk and a stdout that fails while secret runs, such as the closed file the new test uses.
Model: opus-5-5
Reading taken on the closed-stdout item of the Definition of done: it cannot be met when the shell closes stdout before `secret` starts. The Go runtime opens `/dev/null` for a closed standard descriptor before any of `secret` runs, so the value goes there and `secret get` exits 0. Telling that apart from a deliberate redirect to `/dev/null` would need a check of how the descriptor was opened, which I did not build.
What the PR does: any failed write of the value is the command's error and it exits 1. That covers a full disk and a stdout that fails while `secret` runs, such as the closed file the new test uses.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Severity: major
A script that redirects
secret getto a file sees success with a truncated or empty file; the stored secret is intact.What happens:
GetSecretandGetSecretWithVersionwrite the value with_, _ = cmd.OutOrStdout().Write(value.Bytes()), so a short write, a full disk, a closed stdout or a broken pipe is neither reported nor reflected in the exit status.Reproduction, after
secret initandecho v | secret add s:secret listhas the same shape (_, _ = fmt.Fprintf(out, ...)), butgetis the one whose output is the secret.Where:
GetSecret) andGetSecretWithVersion).Correct behaviour: a write error is returned as the command's error, so the exit status is 1 and stderr says the value could not be written (a broken pipe is the usual exception: the reader went away, and reporting it is optional).
Definition of done
secret get s > /dev/fullexits 1 with an error naming the write failure;getto a closed stdout exits 1.getwith stdout set to a writer that fails and requires a non-nil error; it fails before the fix.Model: fable-5-1
Reassigned to clawbot: sneak ruled that nothing is a release candidate while a known bug is open (sneak/project-management#32).
Plan: as the issue says: any failed write of the value is returned as the command's error, exit 1.
Model: opus-5-5
Reading taken on the closed-stdout item of the Definition of done: it cannot be met when the shell closes stdout before
secretstarts. The Go runtime opens/dev/nullfor a closed standard descriptor before any ofsecretruns, so the value goes there andsecret getexits 0. Telling that apart from a deliberate redirect to/dev/nullwould need a check of how the descriptor was opened, which I did not build.What the PR does: any failed write of the value is the command's error and it exits 1. That covers a full disk and a stdout that fails while
secretruns, such as the closed file the new test uses.Model: opus-5-5