Redesign write command: make it interactive to not leak secret into bash history - #303
Merged
jadrol merged 1 commit intoAug 12, 2026
Conversation
jadrol
requested review from
GabiBia and
lgd-michallasisz
and
a lite review from Copilot
August 11, 2026 09:39
jadrol
force-pushed
the
feature/INFRA-1251/write-command-without-leaking-secret
branch
from
August 11, 2026 09:44
bec6fbc to
6669afe
Compare
There was a problem hiding this comment.
Pull request overview
This PR redesigns the treasury write CLI to avoid leaking secrets via command-line arguments (shell history / process list) by reading secrets interactively (TTY) or via stdin (CI/scripts), and updates docs/tests accordingly.
Changes:
- Make
writeaccept only the key argument and read the secret from TTY (hidden) or stdin; add shared secret-input helper + unit tests. - Update Bats + README usage examples to reflect the interactive/stdin-based workflow and new output format.
- Improve SSM backend initialization by loading ambient AWS SDK config when a caller did not provide a usable
aws.Config.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
cmd/write.go |
Switches write to interactive/stdin secret input and updates help text + output formatting. |
cmd/secret_input.go |
Adds logic for securely reading secrets from TTY (hidden) or stdin (piped) with newline trimming + validation. |
cmd/secret_input_test.go |
Adds unit coverage for stdin trimming/validation behavior and edge cases. |
test/bats/tests.bats |
Updates integration tests to pass secrets via stdin pipe and adds negative/edge test cases. |
README.md |
Documents interactive write behavior and safe scripting patterns. |
backend/backend.go |
Adjusts SSM backend to load default AWS SDK config when not provided by caller. |
backend/backend_test.go |
Adds test coverage for caller-provided AWS config scenario. |
go.mod / go.sum |
Adds golang.org/x/term dependency for hidden TTY input. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| } | ||
|
|
||
| func readSecretFromTerminal(cmd *cobra.Command, file *os.File) (string, error) { | ||
| out := cmd.OutOrStdout() |
Comment on lines
+32
to
+34
| The secret value is never given as a command line argument, so it does not end | ||
| up in the shell history nor in the process list. When run in a terminal treasury | ||
| asks for the secret and hides what is typed, otherwise the secret is read from |
Comment on lines
+42
to
+46
| awsConfig := options.AWSConfig | ||
| if !isConfigured(awsConfig) { | ||
| var err error | ||
| awsConfig, err = config.LoadDefaultConfig(context.Background(), config.WithRegion(options.Region)) | ||
| if err != nil { |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 9 changed files in this pull request and generated no new comments.
Suppressed comments (3)
cmd/secret_input.go:42
- The interactive prompt is written to stdout via cmd.OutOrStdout(). If the user redirects stdout (e.g.
treasury write key > out.txt), they won’t see the prompt and it will pollute machine-readable output. Interactive prompts should go to stderr while the success message stays on stdout.
out := cmd.OutOrStdout()
_, _ = fmt.Fprint(out, secretPrompt)
//nolint:gosec // G115: a file descriptor always fits in an int
secret, err := term.ReadPassword(int(file.Fd()))
README.md:134
- This documentation claims
printf '%s\n' "${SECRET}"can be used when the secret must end with a newline, but stdin input always has a single trailing EOL stripped (see trimEOL/readSecret tests). As written, thisprintfexample would still lose the final newline.
The single trailing newline that `echo` adds is stripped, so there is no need for `echo -n` (which is not portable between shells anyway). Any other whitespace is treated as a part of the secret. If the secret has to end with a newline, use `printf '%s\n' "${SECRET}"` or write it from a file with `--file`.
backend/backend.go:46
- When options.Region is empty, calling config.LoadDefaultConfig(..., config.WithRegion(options.Region)) risks overriding an ambient region from env/shared config with an empty value, which can later cause "missing region" errors at runtime. Only apply config.WithRegion when Region is explicitly set.
awsConfig := options.AWSConfig
if !isConfigured(awsConfig) {
var err error
awsConfig, err = config.LoadDefaultConfig(context.Background(), config.WithRegion(options.Region))
if err != nil {
lgd-michallasisz
approved these changes
Aug 11, 2026
jadrol
deleted the
feature/INFRA-1251/write-command-without-leaking-secret
branch
August 12, 2026 06:19
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requestor/Issue: @jadrol
Risk (low/med/high): low
Tested (yes/no): yes, locally
Description/Why:
Old syntax for write command made us leak secret into bash history which with connection to internal security tooling made us leak secrets.
Rewrote write command to be interactive, secret is not being printed at any time, no leak to history.
There is still posibility to pass secret via pipe, see bats for examples.