mirror of
https://github.com/skoelle/kctl-tui.git
synced 2026-09-17 20:10:24 +00:00
Phase 2 hardening: binary secret handling, tool checks, input validation, verbose flag, diff scroll
This commit is contained in:
+28
-5
@@ -5,10 +5,27 @@ import "sort"
|
||||
// SecretDiffEntry represents the comparison of one key between two secret
|
||||
// sources (e.g. AWS Secrets Manager vs. a Kubernetes Secret).
|
||||
type SecretDiffEntry struct {
|
||||
Key string
|
||||
Left string // e.g. the AWS Secrets Manager value
|
||||
Right string // e.g. the decoded Kubernetes secret value
|
||||
Match bool
|
||||
Key string
|
||||
Left string // e.g. the AWS Secrets Manager value
|
||||
Right string // e.g. the decoded Kubernetes secret value
|
||||
Match bool
|
||||
LeftBin bool // true if Left contains non-printable (binary) data
|
||||
RightBin bool // true if Right contains non-printable (binary) data
|
||||
}
|
||||
|
||||
// IsBinary reports whether s contains non-printable bytes (i.e. is likely
|
||||
// binary data rather than human-readable text). Control characters below
|
||||
// space (0x20) are excluded, except for common whitespace (\t, \n, \r).
|
||||
func IsBinary(s string) bool {
|
||||
for _, r := range s {
|
||||
if r > 0x7f {
|
||||
return true
|
||||
}
|
||||
if r < 0x20 && r != '\t' && r != '\n' && r != '\r' {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// DiffSecretValues compares two key/value maps and returns a sorted list of
|
||||
@@ -35,7 +52,13 @@ func DiffSecretValues(left, right map[string]string) []SecretDiffEntry {
|
||||
for _, k := range keys {
|
||||
l := left[k]
|
||||
r := right[k]
|
||||
result = append(result, SecretDiffEntry{Key: k, Left: l, Right: r, Match: l == r})
|
||||
lb := IsBinary(l)
|
||||
rb := IsBinary(r)
|
||||
match := l == r
|
||||
if lb || rb {
|
||||
match = l == r
|
||||
}
|
||||
result = append(result, SecretDiffEntry{Key: k, Left: l, Right: r, Match: match, LeftBin: lb, RightBin: rb})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -57,3 +57,43 @@ func TestDiffSecretValues_EmptyMaps(t *testing.T) {
|
||||
t.Fatalf("expected no mismatch for empty maps")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsBinary_Plaintext(t *testing.T) {
|
||||
if IsBinary("hello world") {
|
||||
t.Fatal("expected plaintext to not be binary")
|
||||
}
|
||||
if IsBinary("line1\nline2\ttab") {
|
||||
t.Fatal("expected newline/tab to not be binary")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsBinary_BinaryData(t *testing.T) {
|
||||
if !IsBinary("hello\x00world") {
|
||||
t.Fatal("expected null byte to be binary")
|
||||
}
|
||||
if !IsBinary("key=\xff\xfe") {
|
||||
t.Fatal("expected non-ASCII bytes to be binary")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiffSecretValues_BinaryDetection(t *testing.T) {
|
||||
left := map[string]string{"ok": "text", "bin": "data\x00here"}
|
||||
right := map[string]string{"ok": "text", "bin": "data\x00here"}
|
||||
|
||||
entries := DiffSecretValues(left, right)
|
||||
for _, e := range entries {
|
||||
if e.Key == "bin" {
|
||||
if !e.LeftBin || !e.RightBin {
|
||||
t.Fatalf("expected binary flags set for key 'bin', got LeftBin=%v RightBin=%v", e.LeftBin, e.RightBin)
|
||||
}
|
||||
if !e.Match {
|
||||
t.Fatalf("expected binary values to match")
|
||||
}
|
||||
}
|
||||
if e.Key == "ok" {
|
||||
if e.LeftBin || e.RightBin {
|
||||
t.Fatalf("expected binary flags unset for key 'ok'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user