canon

package
v0.50.0 Latest Latest
Warning

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

Go to latest
Published: Nov 14, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package canon 提供「策略/配置面规范形指纹」原语:规范形(canonical) → schema 版本化哈希(48bit)→ 按 facet diff。任何「规则改过之后能 回答会话按哪版策略放行、两台机器授权面是否同版、按 facet 吊销受影响 面」的策略/配置治理,都复用同一条管线:配置面 → 排序/去重/缺省折算 → 版本哈希 → facet diff。stdlib-only(pkg 零第三方依赖红线)。

三条归一纪律(同语义必须同版本)

「同语义必须同版本」由三条纪律钉死,前两条本包直接给原语,第三条 是宿主职责、必须在喂进 Facet 前完成:

  • **排序**:集合语义字段(能力词、权限清单)声明顺序不是语义, 改一下排列不该换版本——用 SortDedup 排序后喂入;
  • **去重**:同一词写两遍与写一遍是同一个能力集(去重后才是集合 语义)——同上,SortDedup 一并完成;
  • **缺省折算**:{}(缺省)与显式写缺省值必须同版。缺省表是宿主 的业务语义,本包不内置:宿主用**单源折算函数**(如 admission 的 Effective)把「有效值」折算出来再喂入,禁止折算逻辑散落两处。 注意结构体显式零值与 map 缺键在 JSON 规范形里是两种形态 ("allow":false 与缺键),折算必须在喂入前完成,不能指望哈希层 兜底。

canonical 稳定性(键序无关、字段序钉死)

规范形 = schema 串 + facet 名 → 值的 JSON 形态,整体一次 JSON 化:

  • **map 键序无关**:encoding/json 对 map 键按字典序输出,键插入 顺序不进哈希;
  • **facet 声明序无关**:facet 按 Name 字典序进规范形——清单排列 不是语义;
  • **结构体字段序钉死**:结构体按字段声明序输出——字段序是规范形 的一部分。因此「改 canonical 结构」(增删字段、换字段序、改类型) 都会换哈希,**必须同时升格 Schema 串**(如 policyver/v1 → policyver/v2):版本串里的 schema 是读方识别旧形态的判据, 升格纪律是契约条文,本包按 schema 不一致的 diff 直接拒绝兜底。

48bit 的取舍

版本哈希取 sha256 前 48bit(12 个 hex 字符)。**只用于对比,不用于 防篡改**:指纹回答「这两个面是否同版」,48bit 碰撞概率在「同语义 必须同版本」的输入域下可忽略,但绝不是密码学承诺——任何把版本串当 完整性证明的用法都是错的(防篡改请用完整 sha256 或签名)。

facet diff

Diff 按 facet 名逐片比较各自规范形指纹,产出 Added/Changed/Removed 清单(同版 facet 不报)。按 facet 吊销受影响面(会话按旧版放行的 记录、mandate 重检)直接消费这份清单;FacetDigest 可独立持久化 单个 facet 的指纹(会话行记 policy_version + 命中 facet 集)。

用法

surface := canon.Surface{
    Schema: "policyver/v1", // 宿主自己的 schema 命名空间
    Facets: []canon.Facet{
        {Name: "role:admin", Value: canon.SortDedup(conf.AdminWords)},
        {Name: "admission", Value: admission.Effective(conf.Admission)},
    },
}
ver, err := canon.Fingerprint(surface) // "policyver/v1:3f9a1c2b4d5e"
changes, err := canon.Diff(oldSurface, surface)
for _, ch := range changes { // 按 facet 吊销受影响面
    revokeFacet(ch.Name, ch.Kind)
}

Index

Constants

View Source
const DefaultSchema = "canon/v1"

DefaultSchema 缺省 schema 版本串(宿主可经 Surface.Schema 覆盖为 自己的命名空间,如 "policyver/v1")。

Variables

View Source
var (
	ErrBadSurface     = errors.New("canon: surface 非法")
	ErrUnencodable    = errors.New("canon: facet 值不可 JSON 化")
	ErrSchemaMismatch = errors.New("canon: 新旧快照 schema 不一致,不可 diff")
)

哨兵错误:errors.Is 可判定(非法入参归 ErrBadSurface / ErrUnencodable / ErrSchemaMismatch,文案带上下文)。

Functions

func FacetDigest

func FacetDigest(f Facet) (string, error)

FacetDigest 单个 facet 值的规范形指纹(48bit 十六进制):按 facet 吊销/ 比对时可独立持久化的切片指纹,与会话行记的 policy_version 配套。 名字不进切片指纹——切片指纹只对「值」负责,名字是装配层的键。

func SortDedup

func SortDedup(words []string) []string

SortDedup 排序 + 去重(三条归一纪律的前两条):集合语义字段的唯一 入口原语——声明顺序不是语义、同一词写两遍与写一遍是同一集合。返回 副本不改写入参;空入参返回 nil。

Types

type Change

type Change struct {
	Kind ChangeKind
	Name string
	From string // 旧指纹(Removed/Changed 时非空)
	To   string // 新指纹(Added/Changed 时非空)
}

Change 一个 facet 的变更记录。

func Diff

func Diff(old, cur Surface) ([]Change, error)

Diff 按 facet 名逐片比较两个快照,返回变更清单。确定性顺序:Added 在前、Changed 居中、Removed 在后,各段按 Name 字典序——「新面多了 什么、什么变了、什么没了」。同版 facet 不报。新旧 schema 不一致按 ErrSchemaMismatch 拒绝:跨 schema 的 diff 是无意义比对,升格纪律 在此兜底。

type ChangeKind

type ChangeKind int

ChangeKind facet 变更形态。

const (
	FacetAdded   ChangeKind = iota // 新面新增的 facet
	FacetChanged                   // 两面同名但指纹不同
	FacetRemoved                   // 旧面有、新面没有
)

func (ChangeKind) String

func (k ChangeKind) String() string

String "added"/"changed"/"removed"。

type Facet

type Facet struct {
	Name  string
	Value any
}

Facet 策略面的一个可独立比对/吊销的切片。Name 在快照内唯一; Value 是宿主**已完成三条归一纪律**(排序/去重/缺省折算,见包文档) 的结构,须可 JSON 化(map 键序无关、结构体字段序钉死)。

type Surface

type Surface struct {
	Schema string
	Facets []Facet
}

Surface 一次策略面快照。Schema 空 = DefaultSchema;改 canonical 结构必须升格 Schema 串(契约见包文档「canonical 稳定性」)。

type Version

type Version struct {
	Schema string
	Digest string
}

Version 版本指纹:schema 前缀 + 48bit 十六进制摘要。

func Fingerprint

func Fingerprint(s Surface) (Version, error)

Fingerprint 计算快照的版本指纹:规范形 JSON → sha256 → 48bit 十六进制。 同语义(三条归一纪律后)必同版、可复现。

func (Version) String

func (v Version) String() string

String 形如 "policyver/v1:3f9a1c2b4d5e"。

Jump to

Keyboard shortcuts

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