Files
syft/internal/redact/redact.go
T
MetalandAlex Goodman b0a8de7bf6 fix(redact): reset redaction store between command runs (#5386)
* fix(redact): reset redaction store between command runs

cli.Command() may be invoked more than once in the same process (e.g.
when syft is embedded as a library). The clio initializer calls
internal/redact.Set on every command execution, but the redact store is
process-global and Set panics when a store already exists, so the second
invocation dies with "replace existing redaction store (probably
unintentional)".

Add redact.Reset() to clear the previous run's store and call it in the
initializer before Set. The double-Set guard in Set is kept: an
unexpected second Set within a single run still panics.

Add TestAppClioSetupConfigInitializerCanRunMultipleTimes which runs the
initializer twice; it panics with the exact reported message on the old
code and passes with the fix.

Fixes #2285

Signed-off-by: JasonMetal <935216773@qq.com>

* fix(redact): release the redact store at the end of each run

Clear the global redact store in the post-run hook instead of resetting it
before every `Set`. The double-`Set` panic keeps its meaning: a store is only
present while a run is in flight, so a second run starting mid-run still
panics rather than splitting secrets across two stores and leaking the ones
in the dropped store. Sequential runs in the same process work since the
previous run releases its store on the way out.

A run only releases the store it set, so it never clears a store owned by
someone else.

Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>

---------

Signed-off-by: JasonMetal <935216773@qq.com>
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
Co-authored-by: Alex Goodman <wagoodman@users.noreply.github.com>
2026-10-07 20:28:15 +00:00

45 lines
1.5 KiB
Go

package redact
import "github.com/anchore/go-logger/adapter/redact"
var store redact.Store
func Set(s redact.Store) {
if store != nil {
// if someone is trying to set a redaction store and we already have one then something is wrong. The store
// that we're replacing might already have values in it, so we should never replace it.
panic("replace existing redaction store (probably unintentional)")
}
store = s
}
// Reset clears the global redaction store. It must only be called once a command
// run has fully finished (nothing left to Add or Apply), so that a later run can
// Set its own store. Calling it while a run is in flight would let a second Set
// split secrets across two stores and leak the ones in the dropped store.
func Reset() {
store = nil
}
func Get() redact.Store {
return store
}
func Add(vs ...string) {
if store == nil {
// if someone is trying to add values that should never be output and we don't have a store then something is wrong.
// we should never accidentally output values that should be redacted, thus we panic here.
panic("cannot add redactions without a store")
}
store.Add(vs...)
}
func Apply(value string) string {
if store == nil {
// if someone is trying to add values that should never be output and we don't have a store then something is wrong.
// we should never accidentally output values that should be redacted, thus we panic here.
panic("cannot apply redactions without a store")
}
return store.RedactString(value)
}