Help us shape the future of Go! Take the 2026 Go Developer Survey

logredact

package
v0.17.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package logredact 日志/审计载荷凭据脱敏:连接串/URL/头中的凭据在落日志前模式化打码。 与 fence(Markdown/HTML 注入卫生)正交——本包打码凭据。

规则表是**公开且可组合**的:Rules() 给出内置表副本,RedactWith / NewRedactor 接受调用方自己的扩展规则。下游各家的凭据形态不一样(厂商前缀族、裸 hex、 任意 scheme 的 URL…),把表关在包内就等于逼下游**重写一整份脱敏器**, 或在后面串第二道——两道顺序敏感、掩码风格还不一致。

Index

Constants

View Source
const DefaultHintKeep = 4

DefaultHintKeep 保定位线索掩码默认保留位数(首尾各)。

View Source
const HintMinLenRatio = 4

HintMinLenRatio 被掩值长度不足 keep*该倍数 时**全量打码**。

阈值的作用是「留了也别等于没留」:9 字符的 secret 留首尾 4 个 = 8 个字符, 换个字符就复原了——那不是定位线索,是泄露。保留的字符数必须远小于被藏起的 字符数,掩码才真的不可逆。

Variables

This section is empty.

Functions

func MaskHint added in v0.6.0

func MaskHint(s string) string

MaskHint 保留首尾各 DefaultHintKeep 字符的不可逆掩码。

输出形如 "sk-a****mnop":长度**固定**(与原值长度无关), 保留位**封顶**(与原值长度无关),中间恒为固定长度的星号。

长度不足时返回全量打码 "****"(理由见 HintMinLenRatio)。 空串返回空串。

func MaskHintWith added in v0.6.0

func MaskHintWith(s string, keep int) string

MaskHintWith 保留首尾各 keep 字符的不可逆掩码。

keep<=0 取 DefaultHintKeep。被掩值长度不足 keep*HintMinLenRatio 时全量打码。 空串返回空串。

func NewPayloadRedactor added in v0.17.0

func NewPayloadRedactor(fields []string, extra []Rule) func(string) string

NewPayloadRedactor 返回可复用的「载荷裁剪 + 形状脱敏」函数(字段集与规则表 在构造时**快照**一次)。

与 NewRedactor 同构:高频路径(日志热路径、每条 tool_call 都过一遍)用它, 别每次调用现编正则。返回的函数是并发安全的(只读快照,不改共享状态)。

func NewRedactor added in v0.6.0

func NewRedactor(extra []Rule) func(string) string

NewRedactor 返回一个可复用的脱敏函数(内置规则 + 扩展规则)。

规则表在构造时**快照**一次:调用方之后改自己的切片,不影响已构造的脱敏器。 返回的函数是并发安全的(只读规则表,不改共享状态)。

高频路径(日志热路径、每条 tool_call 都过一遍)用这个,别每次重建规则表。

func Redact

func Redact(s string) string

Redact 返回打码后的文本(无命中原样返回)。

等价于 RedactWith(s, nil):只跑内置规则。

func RedactPayloadValue added in v0.17.0

func RedactPayloadValue(v any, fields ...string) any

RedactPayloadValue 结构化形态:递归把 fields 指定的字段裁剪成「只记长度」的标记, 其余字符串按 RedactValue 的口径做形状脱敏。

与 RedactPayloads 语义一致(同一份判定表),差别只在形态:它吃已解码的值、 吐已解码的值,可用于「按字段名裁剪后再落库」的结构化载荷管道。

裁剪只作用于**字符串形态**的字段值;非字符串形态(对象/数组/数字)的值 原样保留,只递归下探——被裁掉的是「载荷」,不是「字段所在的那个对象」。

func RedactPayloads added in v0.17.0

func RedactPayloads(s string, fields ...string) string

RedactPayloads 把 fields 指定的载荷字段裁剪成「只记长度」的标记,再做形状脱敏。

**顺序由本函数保证**:载荷裁剪先于形状规则(见 payloadMarkerFormat 的说明)。 这正是 issue 里说的「「先裁剪再脱敏」应当由函数内部保证,而不是由调用点的 书写顺序保证」——顺序写反不报错,只是报出来的大小是错的。

fields 是**字段名白名单**(如 "content" / "content_base64" / "body"): 只裁剪这些字段的值,其余原样。刻意不给默认表——「哪些字段算载荷」是 调用方的口径,库里替它猜就等于替它决定什么会落盘。

裁剪只作用于**字符串形态**的字段值(载荷就是字符串:一段 base64、一份内容)。 对象/数组形态的值本函数不动它(那是结构化入口 RedactPayloadValue 的射程)。

高频路径(日志热路径、每条 tool_call 都过一遍)用 NewPayloadRedactor, 别每次重建正则。

func RedactPayloadsWith added in v0.17.0

func RedactPayloadsWith(s string, fields []string, extra []Rule) string

RedactPayloadsWith = RedactPayloads + 扩展规则。

扩展规则仍然排在**最后**(与 RedactWith 的口径一致:先内建、后扩展); 载荷裁剪仍在最前。三段的顺序是:载荷裁剪 → 内建规则 → 扩展规则。

func RedactSecrets

func RedactSecrets(s string, secrets ...string) string

RedactSecrets 抹除调用方已知的确切秘密(clone URL 内嵌 token、动态签发的临时 凭据等):与模式化 Redact 互补——Redact 靠规则打码未知形态的凭据,本函数抹除 已知值。与 Masker 相反,高敏感秘密不做令牌、不回填(Masker 只收低敏感拓扑标识)。 长秘密优先替换(防短串是长串前缀时留下尾段泄漏),空串忽略。

func RedactValue

func RedactValue(v any) any

RedactValue 递归脱敏任意 JSON 形态值:map/slice 逐字段下探,字符串过 Redact,其余原样。 事件载荷入库前的统一出口——tool_call 参数与 tool_result 文本常含连接串、webhook key、Bearer 头。

func RedactWith added in v0.6.0

func RedactWith(s string, extra []Rule) string

RedactWith 用内置规则 + 扩展规则脱敏。

**应用顺序:先内置、后扩展**(每组内部按声明顺序)。

为什么是这个顺序:内置规则的打码**保留结构**("$1://$2:****@" —— scheme 与 用户名留着,只有凭据体被替换),它对同一段文本的定位比扩展规则精确。 先跑内置,扩展规则面对的就是「已经打过码」的文本,既不会把内置已处理的凭据 再脱一次(幂等),也不会让扩展的粗规则先吃掉内置能精确定位的那部分。

扩展规则里 Re 为 nil 的会被跳过(不 panic)——扩展表是调用方给的, 一条写错的规则不该让整条脱敏链路崩掉。

Types

type MaskStyle added in v0.6.0

type MaskStyle int

MaskStyle 命中后的替换方式。

const (
	// MaskStyleLiteral 按 Repl 字面替换(支持 $1 引用)。内置规则用它**保留结构**:
	// scheme、用户名、键名留着,只有凭据体变成 ****——处置后的文本仍能看出
	// 「是哪一条凭据」。这是默认档。
	MaskStyleLiteral MaskStyle = iota
	// MaskStyleHint 保定位线索的不可逆掩码:保留首尾各 Keep 个字符。
	// 用于「全量打码会让人认不出是哪一条凭据」的场景。
	//
	// 与 MaskStyleLiteral 是**不同档**,不是替代关系:前者给的是「认不出」,
	// 后者给的是「认得出但不还原」。
	MaskStyleHint
)

type Masker

type Masker struct {
	// contains filtered or unexported fields
}

Masker 低敏感掩码+令牌回填器(K8sGPT anonymize 形态,bianque spec 2026-09-14-aiops-uplift-design §3):把目标机拓扑标识(IPv4 + 调用方注册的精确串) 在进 LLM 前替换为 «Tn» 令牌,在最终展示面 Restore 回填原名——LLM 解释里引用的 「主机 «T1»」在报告中还原为真名,可读性与隐私兼得。

分级纪律:高敏感(密码/密钥/连接串/Bearer)不走本机制——那是 Redact 的领域, 删除后永不回填;Masker 只收低敏感拓扑标识,且回填只发生在展示面、不回灌二次 LLM 输入(防掩码词表被 prompt 注入探测绕过)。令牌用全角书名号+序号,难以仿造; Restore 对未知令牌原样保留(不猜、不误回填)。

func NewMasker

func NewMasker() *Masker

NewMasker 构造(零值不可用,一律经本构造)。

func (*Masker) AddSecret

func (m *Masker) AddSecret(v string) string

AddSecret 注册精确串(会话主机名、实例名等调用方已知标识),返回其令牌。空串忽略。

func (*Masker) Count

func (m *Masker) Count() int

Count 已签发令牌数(测试/观测用)。

func (*Masker) Mask

func (m *Masker) Mask(s string) string

Mask 掩码文本:先精确注册串,再 IPv4 模式(动态注册,同址恒同令牌)。

func (*Masker) Restore

func (m *Masker) Restore(s string) string

Restore 回填令牌为原文(展示面专用;未知令牌原样保留)。

type Rule added in v0.6.0

type Rule struct {
	// Name 规则名(诊断用:扩展规则出错时要能指出是哪一条)。
	Name string
	// Re 命中模式。nil 的规则会被跳过(不 panic)。
	Re *regexp.Regexp
	// Repl 字面替换串,支持 $1 引用。Style=MaskStyleHint 时被忽略。
	Repl string
	// Style 替换方式,默认 MaskStyleLiteral。
	Style MaskStyle
	// Keep Style=MaskStyleHint 时保留的首尾字符数(<=0 取 DefaultHintKeep)。
	Keep int
	// Group Style=MaskStyleHint 时,掩码作用在**第几个捕获组**(1 起);0 = 整段匹配。
	//
	// 默认 0(整段)有个陷阱:规则的匹配范围里若含上下文(如 "password=xxx"),
	// 整段掩码保留的尾部 4 个字符**就是凭据的一部分**——那不是定位线索,是泄露。
	// 所以凭据类规则应当用捕获组圈出凭据本体,再把 Group 指过去。
	Group int
}

Rule 一条脱敏规则。

命中后按 Style 替换:

MaskStyleLiteral —— 整段替换为 Repl(字面,支持 $1/$2 引用);
MaskStyleHint    —— 整段替换为保留首尾各 Keep 字符的不可逆掩码(Repl 被忽略)。

规则表按声明顺序应用;**同一条规则内的多个匹配**由 regexp 一次性替换。

func Rules added in v0.6.0

func Rules() []Rule

Rules 返回内置规则表的**副本**。

返回副本而不是共享切片:调用方要能自由改自己的表(追加规则、改顺序), 共享切片的话改到一半就污染了全进程的内置规则——而这份表是所有日志出口共用的。 规则里的 *regexp.Regexp 是不可变的,共享指针是安全的。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL