mirror of
https://github.com/replicatedhq/troubleshoot.git
synced 2026-08-27 00:37:20 +00:00
Core tokenization functionality with minimal file changes: ✅ Core Features: - Intelligent tokenization engine (tokenizer.go) - Context-aware secret classification (PASSWORD, APIKEY, DATABASE, etc.) - Cross-file correlation with deterministic HMAC-SHA256 tokens - Optional encrypted mapping for token→original value resolution ✅ Integration: - CLI flags: --tokenize, --redaction-map, --encrypt-redaction-map - Updated all redactor types: literal, single-line, multi-line, YAML - Support bundle integration with auto-upload compatibility - Backward compatibility: preserves ***HIDDEN*** when disabled ✅ Production Ready: - Only 11 essential files (vs 31 in original PR) - No excessive test files or documentation - Clean build, all functionality verified - Maintains existing redaction behavior by default Token format: ***TOKEN_<TYPE>_<HASH>*** (e.g., ***TOKEN_PASSWORD_A1B2C3***)
91 lines
2.0 KiB
Go
91 lines
2.0 KiB
Go
package redact
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/replicatedhq/troubleshoot/pkg/constants"
|
|
"k8s.io/klog/v2"
|
|
)
|
|
|
|
type literalRedactor struct {
|
|
match []byte
|
|
filePath string
|
|
redactName string
|
|
isDefault bool
|
|
}
|
|
|
|
func literalString(match []byte, path, name string) Redactor {
|
|
return literalRedactor{
|
|
match: match,
|
|
filePath: path,
|
|
redactName: name,
|
|
}
|
|
}
|
|
|
|
func (r literalRedactor) Redact(input io.Reader, path string) io.Reader {
|
|
out, writer := io.Pipe()
|
|
|
|
go func() {
|
|
var err error
|
|
defer func() {
|
|
if err == nil || err == io.EOF {
|
|
writer.Close()
|
|
} else {
|
|
if err == bufio.ErrTooLong {
|
|
s := fmt.Sprintf("Error redacting %q. A line in the file exceeded %d MB max length", path, constants.SCANNER_MAX_SIZE/1024/1024)
|
|
klog.V(2).Info(s)
|
|
} else {
|
|
klog.V(2).Info(fmt.Sprintf("Error redacting %q: %v", path, err))
|
|
}
|
|
writer.CloseWithError(err)
|
|
}
|
|
}()
|
|
|
|
buf := make([]byte, constants.BUF_INIT_SIZE)
|
|
scanner := bufio.NewScanner(input)
|
|
scanner.Buffer(buf, constants.SCANNER_MAX_SIZE)
|
|
|
|
lineNum := 0
|
|
for scanner.Scan() {
|
|
lineNum++
|
|
line := scanner.Bytes()
|
|
|
|
var clean []byte
|
|
tokenizer := GetGlobalTokenizer()
|
|
if tokenizer.IsEnabled() {
|
|
// For literal redaction, we tokenize the matched value
|
|
matchStr := string(r.match)
|
|
context := r.redactName
|
|
token := tokenizer.TokenizeValueWithPath(matchStr, context, r.filePath)
|
|
clean = bytes.ReplaceAll(line, r.match, []byte(token))
|
|
} else {
|
|
// Use original masking behavior
|
|
clean = bytes.ReplaceAll(line, r.match, maskTextBytes)
|
|
}
|
|
|
|
// Append newline since scanner strips it
|
|
err = writeBytes(writer, clean, NEW_LINE)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
if !bytes.Equal(clean, line) {
|
|
addRedaction(Redaction{
|
|
RedactorName: r.redactName,
|
|
CharactersRemoved: len(line) - len(clean),
|
|
Line: lineNum,
|
|
File: r.filePath,
|
|
IsDefaultRedactor: r.isDefault,
|
|
})
|
|
}
|
|
}
|
|
if scanErr := scanner.Err(); scanErr != nil {
|
|
err = scanErr
|
|
}
|
|
}()
|
|
return out
|
|
}
|