detect

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package detect は行単位の PII 検出エンジンを提供する。

Index

Constants

View Source
const (
	// DropReasonRequireContextMissing は RequireContext のパターンで、
	// 近傍にコンテキストキーワードが無く破棄されたことを表す。
	DropReasonRequireContextMissing = "require-context-missing"
	// DropReasonNegativeContext は同一行(source context 由来を含む)の
	// 負文脈で破棄されたことを表す。
	DropReasonNegativeContext = "negative-context"
	// DropReasonCrossLineNegativeContext は論理隣接行の負文脈
	// (hasCrossLineNegativeContext、ScanContent/ScanDiffHunk 経由)で
	// 破棄されたことを表す。
	DropReasonCrossLineNegativeContext = "cross-line-negative-context"
	// DropReasonValidateFailed は Rule.Validate または Pattern.Validate が
	// false を返して破棄されたことを表す(チェックサム等)。
	DropReasonValidateFailed = "validate-failed"
	// DropReasonValidateLineFailed は Pattern.ValidateLine が false を
	// 返して破棄されたことを表す。
	DropReasonValidateLineFailed = "validate-line-failed"
	// DropReasonAllowlisted は allowlist(stopword / 正規表現)に一致して
	// 破棄されたことを表す。
	DropReasonAllowlisted = "allowlisted"
	// DropReasonKindExcluded は Rule.Kind の下位種別が設定ファイルの
	// [rules] exclude_kinds に一致して破棄されたことを表す。
	DropReasonKindExcluded = "kind-excluded"
	// DropReasonBelowMinConfidence は最終信頼度が min_confidence 未満で
	// 破棄されたことを表す。cooccurrence_boost で一旦保持に回った候補が
	// 結局昇格しなかった場合の最終的な破棄もここに含む
	// (保持に回った時点そのものは記録しない)。
	DropReasonBelowMinConfidence = "below-min-confidence"
	// DropReasonOverlapLost は resolveOverlaps/resolveOverlapsPerLine の
	// 重複解決で他候補に敗れて破棄されたことを表す。
	DropReasonOverlapLost = "overlap-lost"
	// DropReasonPathDemotionBelowMin はテスト経路の信頼度降格
	// (path_profile.go)で Low に落ち、min_confidence 未満になって
	// 破棄されたことを表す。
	DropReasonPathDemotionBelowMin = "path-demotion-below-min"
	// DropReasonUUIDToken は候補が UUID トークンの内部に完全に含まれる
	// ため破棄されたことを表す。
	DropReasonUUIDToken = "uuid-token"
)

棄却理由の語彙(この文字列で固定。--explain-dropped の text/json 出力に そのまま現れる安定した識別子のため、値を変更しないこと)。

View Source
const AllowMarker = "pii-allow"

AllowMarker は後方互換のために残している旧除外マーカー。

View Source
const IgnoreMarker = "jp-pii-detector:ignore"

IgnoreMarker を含む行は検出対象から除外される(意図的なダミー値向け)。

Variables

This section is empty.

Functions

func IsCSVOrTSVPath

func IsCSVOrTSVPath(path string) bool

IsCSVOrTSVPath は path の拡張子が .csv/.tsv(大文字小文字を区別しない)かを 返す。internal/source/gitdiff.go が diff hunk 用の post-image ヘッダ行を `git show` で取得するかどうかの判定に使う(ヘッダ取得は CSV/TSV だけに 意味があり、それ以外の拡張子で無駄な git 呼び出しをしないため)。 sourceKindForPath と判定基準がずれないよう、拡張子リストを再定義せず sourceKindForPath に委譲する。

func IsObjectScopePath

func IsObjectScopePath(path string) bool

IsObjectScopePath は path がオブジェクトスコープ処理の対象(.json/.yaml/.yml) かを返す。internal/source/gitdiff.go が diff hunk 用の post-image 全文を `git show` で取得するかどうかの判定に使う(取得は対象拡張子だけに意味があり、 それ以外の拡張子で無駄な git 呼び出しをしないため)。csv_context.go の IsCSVOrTSVPath と対称で、拡張子リストを再定義せず objectScopeKindForPath に 委譲する。

Types

type DetectReason

type DetectReason struct {
	BaseConfidence  string   `json:"base_confidence,omitempty"`
	FinalConfidence string   `json:"final_confidence,omitempty"`
	ContextKeywords []string `json:"context_keywords,omitempty"`
	ContextPromoted bool     `json:"context_promoted,omitempty"`
	RequireContext  bool     `json:"require_context,omitempty"`
	ContextWindow   int      `json:"context_window,omitempty"`
	Validated       bool     `json:"validated,omitempty"`
	// CooccurrenceBoosted は、[rules] cooccurrence_boost 有効時に近傍の別カテゴリ
	// 高信頼 PII との共起で信頼度が 1 段昇格したことを示す(調査・チューニング用)。
	CooccurrenceBoosted bool `json:"cooccurrence_boosted,omitempty"`
	// PathDemoted はテスト経路(testdata/ 等)の信頼度降格が適用されたかを表す
	// (internal/detect/path_profile.go)。true の場合、Confidence は既に
	// 降格後の値(Low)になっている。
	PathDemoted bool `json:"path_demoted,omitempty"`
	// Kind はルール固有の下位種別(Rule.Kind が設定されている場合のみ設定される。
	// internal/rule/rule.go 参照)。現状は jp-phone-number の PhoneKind が返す
	// service/ip/mobile/fixed/international のいずれか。設定ファイルの
	// [rules] exclude_kinds(internal/config)でこの値ごとに検出を除外できる。
	Kind string `json:"kind,omitempty"`
	// External は組み込みルールではなく、[external_recognizer] で設定した外部コマンド
	// 由来の検出であることを示す(--explain 表示用。internal/detect/external.go の
	// MergeExternalFindings が設定する)。外部候補はチェックサム等の内部検証を
	// 一切行わないため、Validated は常に false のままになる。
	External bool `json:"external,omitempty"`
}

DetectReason は検出の根拠を表す。生の PII は含めない。

type Detector

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

Detector は設定を適用済みの検出エンジン。

func New

func New(cfg *config.Config) (*Detector, error)

New は設定に基づいて Detector を構築する。

func (*Detector) CollectDropped

func (d *Detector) CollectDropped(enabled bool)

CollectDropped は棄却候補の記録(DroppedCandidate)を有効/無効にする (既定 false)。無効時は記録のコストが各記録箇所の bool 分岐 1 個のみで、 性能・挙動・出力は従来と完全に不変(golden 等への影響ゼロ)。 --explain-dropped 用。並列フルスキャン開始前(Detector 構築直後)に 呼ぶことを想定する。

func (*Detector) DroppedTruncated

func (d *Detector) DroppedTruncated() bool

DroppedTruncated は直近の TakeDropped 以降、上限(maxDroppedCandidates)に 達して記録を打ち切ったことがあるかを返し、内部フラグをリセットする (TakeDropped と対で、1 回の走査ごとに呼ぶ想定)。

func (*Detector) MergeExternalFindings

func (d *Detector) MergeExternalFindings(file, content string, findings []Finding, candidates []external.Candidate) []Finding

MergeExternalFindings は file の外部レコグナイザ候補(internal/external.Run が 返した Candidate のうち、この file 分。File が一致しないものは無視する)を検証・ 変換し、findings(通常の検出。呼び出し側が d.ScanContent(file, content) で 得たもの)と統合して返す。candidates が空なら findings をそのまま返す (呼び出し側のホットパス最適化用。外部レコグナイザ未設定時はこの関数自体が 呼ばれないため、無効時のコストはゼロ)。

ScanContent が内部で行う cooccurrence_boost(近傍の高信頼 PII との共起昇格)と path_demotion(testdata/ 等の信頼度降格)は、この関数を呼ぶ時点で ScanContent が 既に完了しているため、外部候補には適用されない(意図的な v1 のスコープ外。 外部候補に適用するのは下記の allowlist・ignore マーカー・min_confidence・ 重複解決のみ)。

各候補は次の順で検証し、いずれかで落ちれば「この候補だけ」を破棄する (internal/external.Run 自体が返す「この走査回の候補をすべて破棄」判定とは別の、 候補単位の意味検証):

  1. rule_id が externalRuleIDSuffix を持たない候補は破棄する。internal/external は JSON の構造検証のみを行い、この意味検証はしないため、ここが唯一の強制点になる。
  2. rule_id が [rules] disabled に含まれる候補は破棄する。通常ルールと同じ無効化 手段を外部ルールにも適用できるようにするため。
  3. line・column・length が content の範囲内に収まらない候補は破棄する (子の自己申告位置を信用しない)。
  4. 値そのものは content から親側で切り出す(プロトコルは値を運ばない)。値が乗る 行に ignore マーカー(jp-pii-detector:ignore / 旧 pii-allow)があれば破棄する。
  5. allowlist(stopword・正規表現)に一致すれば破棄する。
  6. confidence は受信値をパースし、不正・空なら Low として扱う(破棄はしない)。 パース後の値が min_confidence 未満なら破棄する。

生存した候補は findings と合わせて resolveOverlapsPerLine で重複解決する (同一箇所に通常の検出と外部候補が重なった場合、既存の信頼度・範囲優先の決着規則 がそのまま適用される。外部候補だから優先/劣後するという特別扱いはしない)。

func (*Detector) Rules

func (d *Detector) Rules() []rule.Rule

Rules は有効なルール一覧を返す。

func (*Detector) ScanContent

func (d *Detector) ScanContent(file, content string) []Finding

ScanContent はファイル内容全体を行に分割して走査する。

func (*Detector) ScanDiffHunk

func (d *Detector) ScanDiffHunk(file string, lines []DiffLine) []Finding

ScanDiffHunk は差分 hunk(文脈行+追加行)を走査し、検出値が追加行に乗る finding だけを返す(行番号はウィンドウ内 1 始まり)。CSV/TSV の列コンテキスト・ JSON/YAML のオブジェクトスコープ親キー文脈のいずれも使わない後方互換の エントリポイントで、ScanDiffHunkOpts(file, lines, DiffScanOptions{}) に委譲する (既存呼び出し — internal/source/gitdiff.go の CSV/JSON/YAML 以外の経路、 internal/eval 等 — のシグネチャ・挙動を一切変えないため)。

func (*Detector) ScanDiffHunkOpts

func (d *Detector) ScanDiffHunkOpts(file string, lines []DiffLine, opts DiffScanOptions) []Finding

ScanDiffHunkOpts は ScanDiffHunk/ScanDiffHunkWithCSVHeader の一般化版 (issue #134)。opts がゼロ値なら ScanDiffHunk と完全に同じ挙動になる。

API 拡張の形について: ScanDiffHunkWithCSVHeader 追加時と同じく、既存 シグネチャ・既存呼び出し(本パッケージ外では internal/source・internal/eval)を 一切変更せず、新規の関数を追加する形を選んだ。ただし今回は CSV ヘッダに加えて JSON/YAML の post-image 全文・hunk 開始行という、渡せるオプションが今後も 増えうる性質を踏まえ、専用関数を増やす代わりに汎用の DiffScanOptions 構造体を 導入した。ScanDiffHunk・ScanDiffHunkWithCSVHeader 側はそれぞれ薄い委譲に とどめている。

設計意図(ScanDiffHunk と共通): 文脈行(未変更行)は正のコンテキスト (ラベル等)の補完にのみ使い、抑制(ignore マーカー・負コンテキスト)の 駆動には使わない。これにより、追加した値の隣の既存行に「円」等の負コンテキストや 古い jp-pii-detector:ignore があっても、追加行の新規 PII を取りこぼさない (セキュリティ検出器として偽陰性を避ける)。同一行の抑制(値そのものの行)は 通常どおり適用される。一方、追加行同士が隣接する場合(両方 Added)は、 フルスキャン(ScanContent)と同じく隣接行の負コンテキストを適用する。 そうしないと、同じ 2 行の追加が CI のフルスキャンでは抑制され pre-commit --staged では報告されるという非対称が生まれるため。CSV 列コンテキストの PositiveText/NegativeText も、この「文脈行は正の補完のみ・抑制は値の行のみ」 という原則に従う(csvHeader 自体は外部から渡された固定情報であり、hunk 内の 文脈行/追加行の区別とは独立に、行ごとの列の割り当てにのみ使う)。オブジェクト スコープの親キー文脈(PostImage 由来)も同じ原則に従う: postImage 自体は 外部から渡された固定情報で、hunk 内の文脈行/追加行の区別とは独立に働くが、 親キー由来の finding が実際に報告されるかどうかは通常どおり「値が追加行に 乗っているか」で決まる。

この「抑制は検出値が乗る行に対してのみ適用し、隣接行のマーカーを巻き添えに しない」という原則は diff 経路専用ではなく、ScanContent 側の隣接行走査 (scanAdjacentLines)にも同様に適用される。

func (*Detector) ScanDiffHunkWithCSVHeader

func (d *Detector) ScanDiffHunkWithCSVHeader(file string, lines []DiffLine, csvHeader string) []Finding

ScanDiffHunkWithCSVHeader は ScanDiffHunk に、走査対象が .csv/.tsv の場合の post-image ヘッダ行(1 行目のテキスト)を追加で渡せる版。hunk 自体は 変更箇所がファイル先頭付近でない限りヘッダ行を含まないため、呼び出し側 (internal/source/gitdiff.go)が `git show` で post-image のヘッダ行だけを 個別取得して渡す。csvHeader を空文字にすると ScanDiffHunk と完全に同じ 挙動になる(ヘッダ未取得・取得失敗・非 CSV ファイルはすべてこの経路)。 ScanDiffHunkOpts(file, lines, DiffScanOptions{CSVHeader: csvHeader}) に委譲する 後方互換のエントリポイント(既存呼び出しのシグネチャ・挙動を一切変えない)。

func (*Detector) ScanLine

func (d *Detector) ScanLine(file string, lineNo int, line string) []Finding

ScanLine は 1 行を走査する。lineNo は 1 始まり。

func (*Detector) SetScanMinConfidence added in v0.4.3

func (d *Detector) SetScanMinConfidence(minConf rule.Confidence)

SetScanMinConfidence は、報告用 min_confidence を変えずに ScanContent 等が 返す finding の下限だけを引き下げる。CLI の --fail-on が報告閾値より低い 場合の終了判定・baseline 登録に使う。走査開始前に 1 回だけ呼ぶこと。

func (*Detector) TakeDropped

func (d *Detector) TakeDropped() []DroppedCandidate

TakeDropped は記録済みの DroppedCandidate を返し、内部の蓄積をクリアする (drain 方式)。ScanContent/ScanLine/ScanDiffHunk を必要な回数呼び出した 後にまとめて回収する想定(フルスキャンで複数ファイルを走査する場合も、 全走査完了後に 1 度だけ呼べばよい)。CollectDropped(false)(既定)の ままなら常に nil を返す。

type DiffLine

type DiffLine struct {
	Text  string
	Added bool
}

DiffLine は差分 hunk の 1 行(新ファイル側)。Added が true なら追加行、 false なら文脈行(未変更行)。

type DiffScanOptions

type DiffScanOptions struct {
	// CSVHeader は .csv/.tsv の post-image ヘッダ行(1 行目のテキスト)。
	// ScanDiffHunkWithCSVHeader の csvHeader 引数と同じ意味・同じフォールバック
	// 規則(空文字列 = 列コンテキストなし)。
	CSVHeader string
	// PostImage は .json/.yaml/.yml の post-image 全文("\n" 区切り、hunk の
	// 断片ではなくファイル全体)。呼び出し側(internal/source/gitdiff.go)が
	// `git show` で取得する(サイズ上限・取得失敗・バイナリはすべて呼び出し側の
	// 責任で空文字列にフォールバックする)。空文字列は「取得できなかった/
	// 対象外」を表し、オブジェクトスコープの親キー文脈なしにフォールバックする
	// (object_scope.go の applyObjectScopeContextForDiff 参照)。
	PostImage string
	// HunkStartLine は hunk の新ファイル側開始行(unified diff の
	// `@@ -a,b +c,d @@` の c、1 始まり)。PostImage 中の対応行を lines[i]
	// (0 始まり)↔ PostImage の行 HunkStartLine+i-1(0 始まり)で対応付けるために
	// 使う。PostImage が空文字列の場合は参照されない。
	HunkStartLine int
}

DiffScanOptions は ScanDiffHunkOpts への追加オプション(すべて省略可能で、 ゼロ値なら ScanDiffHunk と完全に同じ挙動になる)。

type DroppedCandidate

type DroppedCandidate struct {
	RuleID string
	File   string
	Line   int // 1 始まり
	Column int // 1 始まり(ルーン単位)
	// Reason は棄却理由。下記 DropReasonXxx 定数のいずれか(固定語彙)。
	Reason string
	// PatternBase はこの候補が仮に採用されていた場合の信頼度。パターン
	// ループ内の棄却は Pattern.Base、below-min-confidence・overlap-lost・
	// path-demotion-below-min・cross-line-negative-context は棄却時点で
	// 解決済みの Finding.Confidence を使う。FN 分析での優先度付けに使う
	// 補助情報であり、検出可否・出力には一切影響しない。
	PatternBase rule.Confidence
}

DroppedCandidate は検出候補が確定に至らず棄却された記録(opt-in、FN 分析用。 issue #43 段階4)。生のマッチ値は絶対に保持しない(Finding.Match の json:"-" と同じ安全境界の思想。値はマスク済みですら持たない。位置と ルールで特定するには十分という判断)。

type Finding

type Finding struct {
	RuleID      string          `json:"rule_id"`
	Description string          `json:"description"`
	File        string          `json:"file"`
	Line        int             `json:"line"`   // 1 始まり
	Column      int             `json:"column"` // 1 始まり(ルーン単位)
	Match       string          `json:"-"`      // 元テキスト(生値。マスクは出力層で行う。直接 marshal では出さない)
	Confidence  rule.Confidence `json:"-"`
	// ConfidenceScore は検証・文脈距離・構造証拠を加算した内部スコア(0-100)。
	// JSON/SARIF 等の公開契約は既存の 3 値 Confidence を維持し、score は出力しない。
	ConfidenceScore int `json:"-"`
	// Reason は検出の根拠(調査・チューニング用。既定の出力には含めない)。
	Reason DetectReason `json:"reason,omitempty"`
	// Offset/EndOffset は走査対象テキスト全体の先頭からのルーン単位の半開区間
	// [Offset, EndOffset)。ComputeOffsets を呼んだときのみ設定され、その場合
	// HasOffset が true になる。行・列ベースの位置を文字オフセットへ変換したい
	// 利用側(例: Microsoft Presidio の RecognizerResult)向けの情報で、
	// 単一テキスト走査でのみ意味を持つ(ファイル/差分走査では付与されない)。
	HasOffset bool `json:"-"`
	Offset    int  `json:"-"`
	EndOffset int  `json:"-"`
	// contains filtered or unexported fields
}

Finding は 1 件の検出結果。

注意: この型は出力スキーマではない。機械可読な出力(json/sarif 等)は internal/report の jsonFinding を経由し、値は既定でマスクされる。Finding を 直接 json.Marshal する経路は存在しないが、誤って marshal しても生の PII を 漏らさないよう、生値を保持する Match は json:"-" でシリアライズ対象から外す。

func ComputeOffsets

func ComputeOffsets(content string, findings []Finding) []Finding

ComputeOffsets は ScanContent に渡したのと同一の content を使い、各 finding に テキスト全体の先頭からのルーン単位オフセット(半開区間 [Offset, EndOffset))を 付与して返す。行・列ベースの検出位置を文字オフセットベースへ変換したい利用側 (例: Microsoft Presidio の RecognizerResult は文字オフセットを要求する)向けの ヘルパー。

content は ScanContent と同じく "\n" 区切りで行に分割されるため、ここで求める 行頭のルーン位置は ScanContent が見た行と一致する。正規化は 1 ルーン = 1 ルーンの 1:1 変換なので、列はそのまま行頭からのルーン数として使える。

func (Finding) Format

func (f Finding) Format(s fmt.State, _ rune)

Format は fmt の全verbで生の Match と文脈詳細を出さない。テスト失敗時の `%+v` やログ出力を、json:"-" では防げないための安全境界。

Jump to

Keyboard shortcuts

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