Documentation
¶
Overview ¶
Package secrets provides secret detection and scanning capabilities.
Package secrets provides secret detection capabilities.
Package secrets provides secret detection capabilities for Deputy.
This package integrates Google's Veles secret scanner from OSV-SCALIBR to detect leaked credentials in source code, container images, and other artifacts. It serves two primary purposes:
Security scanning: Detect secrets in scanned targets (containers, repositories, SBOMs) as part of vulnerability analysis.
Agent masking: Mask detected secrets in AI agent sessions to prevent accidental exposure of credentials in prompts and responses.
Supported Secret Types ¶
Currently supported detectors (via Veles):
- GCP API Keys
- GCP Service Account Keys (JSON)
- RubyGems API Keys
Additional pattern-based detection:
- AWS access keys and secret keys
- GitHub tokens (classic and fine-grained)
- Generic high-entropy strings
- Environment variable patterns (PASSWORD, SECRET, TOKEN, etc.)
Usage ¶
Basic secret detection:
engine, err := secrets.NewEngine()
if err != nil {
return err
}
findings, err := engine.ScanFile(ctx, "config.json", content)
for _, f := range findings {
fmt.Printf("Found %s at line %d\n", f.Type, f.Line)
}
Masking secrets for AI agents:
masker := secrets.NewMasker(engine) safe := masker.Mask(userInput) // safe now has secrets replaced with [REDACTED:SECRET_TYPE]
Policy Integration ¶
Secret findings can be exposed to CEL policies via the `secrets` variable:
policies:
- name: no-secrets-in-images
entrypoints: ["scan_report"]
rules:
- action: deny
when: secrets.exists(s, s.type == "gcp_service_account_key")
reason: "GCP service account key found in image"
References ¶
- Veles: https://github.com/google/osv-scalibr/tree/main/veles
- Deputy security patterns: internal/security/env.go
Package secrets provides secret detection capabilities.
Package secrets provides secret detection capabilities.
Package secrets provides secret detection capabilities.
Index ¶
- Constants
- Variables
- func FindingsToSARIF(findings []Finding, opts ...func(*SARIFReportOptions)) (string, error)
- func GenerateHook(w io.Writer, config HookConfig) error
- func HashFinding(f Finding) string
- func InstallHook(repoPath string, config HookConfig) error
- func IsSensitiveEnvName(name string) bool
- func ParseInlineAllowlist(lines []string, lineNum int) (bool, string)
- func SafeExtractArchive(ctx context.Context, archivePath string, maxSize int64) (*os.Root, string, error)
- func SecretsFindingActivation(finding PolicyFinding) map[string]any
- func SecretsHelperFunctions() []cel.EnvOption
- func SecretsReportActivation(report PolicyReport, findings []PolicyFinding) map[string]any
- func UninstallHook(repoPath string, hookType HookType) error
- func WithBaseURI(baseURI string) func(*SARIFReportOptions)
- func WithToolVersion(version string) func(*SARIFReportOptions)
- type Allowlist
- func (a *Allowlist) AddHash(value, reason string)
- func (a *Allowlist) AddPath(pattern, reason string)
- func (a *Allowlist) AddPattern(pattern, reason string)
- func (a *Allowlist) AddType(secretType, reason string)
- func (a *Allowlist) Filter(findings []Finding) []Finding
- func (a *Allowlist) Save(path string) error
- func (a *Allowlist) ShouldIgnoreFile(path string) bool
- func (a *Allowlist) ShouldIgnoreFinding(f Finding) bool
- type ArchiveFinding
- type ArchiveFormat
- type ArchiveScanConfig
- type ArchiveScanResult
- type ArchiveScanner
- func (s *ArchiveScanner) ScanArchive(ctx context.Context, archivePath string) (*ArchiveScanResult, error)
- func (s *ArchiveScanner) ScanArchiveReader(ctx context.Context, r io.Reader, format ArchiveFormat, name string) (*ArchiveScanResult, error)
- func (s *ArchiveScanner) ScanBinary(ctx context.Context, path string) ([]Finding, error)
- func (s *ArchiveScanner) ScanBinaryContent(ctx context.Context, content []byte, name string) ([]Finding, error)
- func (s *ArchiveScanner) ScanWithRoot(ctx context.Context, root *os.Root) ([]Finding, error)
- type AuditResult
- type AuditStatus
- type Baseline
- func (b *Baseline) AddFinding(f Finding, reason string)
- func (b *Baseline) AddFindings(findings []Finding, reason string)
- func (b *Baseline) Audit(rootDir string) ([]AuditResult, error)
- func (b *Baseline) Clean(rootDir string) (int, error)
- func (b *Baseline) Contains(f Finding) bool
- func (b *Baseline) Files() []string
- func (b *Baseline) Filter(findings []Finding) []Finding
- func (b *Baseline) Merge(other *Baseline)
- func (b *Baseline) Save(path string) error
- func (b *Baseline) TotalEntries() int
- type BaselineComment
- type BaselineEntry
- type BaselineFilters
- type BaselineScanner
- type BatchResult
- type BatchScanner
- type BatchScannerOption
- type BinarySection
- type CommitInfo
- type ContainerFinding
- type ContainerScanConfig
- type ContainerScanOptions
- type ContainerScanResult
- type ContainerScanStats
- type ContainerScanner
- func (c *ContainerScanner) ScanChainLayers(ctx context.Context, chainLayers []scalibrimage.ChainLayer, ...) ([]ContainerFinding, error)
- func (c *ContainerScanner) ScanImageConfig(ctx context.Context, config *ImageConfig) ([]ContainerFinding, error)
- func (c *ContainerScanner) ScanImageLayers(ctx context.Context, img v1.Image, baseImageLayers int) ([]ContainerFinding, error)
- func (c *ContainerScanner) ScanIndividualLayers(ctx context.Context, layers []scalibrimage.Layer, baseImageLayers int) ([]ContainerFinding, error)
- func (c *ContainerScanner) ScanLayerTarball(ctx context.Context, layerReader io.Reader, layerIndex int, layerDigest string, ...) ([]ContainerFinding, error)
- type ContainerSecretSource
- type DiffResult
- type Engine
- type EngineConfig
- type FilteringScanner
- type FilteringScannerOption
- type Finding
- type GitHistoryOptions
- type HistoricalFinding
- type HistoryFinding
- type HistoryScanConfig
- type HistoryScanResult
- type HistoryScanner
- type HistoryStats
- type HookConfig
- type HookStatus
- type HookType
- type ImageConfig
- type ImageHistoryEntry
- type InlineAllowlistScanner
- type Masker
- type MultiScanner
- type PatternDetector
- type PolicyFinding
- type PolicyReport
- type SARIFReport
- type SARIFReportOptions
- type Scanner
- type SecretType
- type VerificationConfig
- type VerificationEngine
- type VerificationResult
- type VerificationStatus
- type Verifier
- type VerifyOptions
Constants ¶
const BaselineVersion = "1.0"
BaselineVersion is the current baseline file format version.
const DefaultBaselinePath = ".deputy-secrets-baseline.json"
DefaultBaselinePath is the default path for the baseline file.
Variables ¶
var SecretsPolicyVariables = []cel.EnvOption{ cel.Variable("secret", cel.MapType(cel.StringType, cel.DynType)), cel.Variable("secrets", cel.ListType(cel.MapType(cel.StringType, cel.DynType))), cel.Variable("report", cel.MapType(cel.StringType, cel.DynType)), }
SecretsPolicyVariables contains the CEL variable definitions for secrets policies. These are the variables available in CEL expressions when evaluating secrets policies.
var SensitiveEnvPatterns = []string{
"PASSWORD", "PASSWD", "PWD",
"SECRET", "KEY", "TOKEN",
"API_KEY", "APIKEY",
"PRIVATE", "CREDENTIAL",
"AUTH", "ACCESS_KEY",
"AWS_SECRET", "GITHUB_TOKEN",
"DATABASE_URL", "CONNECTION_STRING",
}
SensitiveEnvPatterns returns patterns for detecting sensitive environment variable names. This is used for env var name detection (not value detection).
Functions ¶
func FindingsToSARIF ¶
func FindingsToSARIF(findings []Finding, opts ...func(*SARIFReportOptions)) (string, error)
FindingsToSARIF is a convenience function to convert findings to SARIF JSON.
func GenerateHook ¶
func GenerateHook(w io.Writer, config HookConfig) error
GenerateHook generates a git hook script.
func HashFinding ¶
HashFinding creates a content-based hash for a finding. This allows matching findings even if line numbers change slightly.
func InstallHook ¶
func InstallHook(repoPath string, config HookConfig) error
InstallHook installs a git hook in the specified repository.
func IsSensitiveEnvName ¶
IsSensitiveEnvName returns true if the environment variable name matches sensitive patterns.
func ParseInlineAllowlist ¶
ParseInlineAllowlist checks if a line contains an inline allowlist comment. Returns true if the line (or previous line) allows the secret.
func SafeExtractArchive ¶
func SafeExtractArchive(ctx context.Context, archivePath string, maxSize int64) (*os.Root, string, error)
SafeExtractArchive extracts an archive to a temporary directory with os.Root isolation. This provides safe file system access within the extracted directory. The returned Root must be closed when done.
func SecretsFindingActivation ¶
func SecretsFindingActivation(finding PolicyFinding) map[string]any
SecretsFindingActivation creates a CEL activation for a single finding evaluation.
func SecretsHelperFunctions ¶
SecretsHelperFunctions returns CEL helper functions for secrets policies.
func SecretsReportActivation ¶
func SecretsReportActivation(report PolicyReport, findings []PolicyFinding) map[string]any
SecretsReportActivation creates a CEL activation for full report evaluation.
func UninstallHook ¶
UninstallHook removes a git hook from the specified repository.
func WithBaseURI ¶
func WithBaseURI(baseURI string) func(*SARIFReportOptions)
WithBaseURI sets the base URI for relative paths.
func WithToolVersion ¶
func WithToolVersion(version string) func(*SARIFReportOptions)
WithToolVersion sets the tool version in SARIF options.
Types ¶
type Allowlist ¶
type Allowlist struct {
// Patterns are regex patterns to match against secret values.
Patterns []string `json:"patterns,omitempty"`
// Hashes are SHA256 hashes of exact values to ignore.
Hashes []string `json:"hashes,omitempty"`
// Paths are glob patterns for files to completely skip.
Paths []string `json:"paths,omitempty"`
// Types are secret types to completely ignore.
Types []string `json:"types,omitempty"`
// Reasons maps entries to their justification.
Reasons map[string]string `json:"reasons,omitempty"`
}
Allowlist manages a list of patterns/values to ignore. This is simpler than a full baseline and works well for known test values.
func LoadAllowlist ¶
LoadAllowlist loads an allowlist from a JSON file.
func (*Allowlist) AddPattern ¶
AddPattern adds a regex pattern to ignore.
func (*Allowlist) ShouldIgnoreFile ¶
ShouldIgnoreFile checks if a file path should be skipped.
func (*Allowlist) ShouldIgnoreFinding ¶
ShouldIgnoreFinding checks if a finding should be ignored.
type ArchiveFinding ¶
type ArchiveFinding struct {
Finding
// ArchivePath is the path to the archive file.
ArchivePath string `json:"archivePath"`
// EntryPath is the path within the archive.
EntryPath string `json:"entryPath"`
// Format is the archive format.
Format ArchiveFormat `json:"format"`
// Nested indicates if this was found in a nested archive.
Nested bool `json:"nested,omitempty"`
// NestingDepth is how many levels of archives deep this finding is.
NestingDepth int `json:"nestingDepth,omitempty"`
}
ArchiveFinding extends Finding with archive context.
type ArchiveFormat ¶
type ArchiveFormat string
ArchiveFormat represents supported archive formats.
const ( FormatUnknown ArchiveFormat = "" FormatZip ArchiveFormat = "zip" FormatTar ArchiveFormat = "tar" FormatTarGz ArchiveFormat = "tar.gz" FormatTarBz2 ArchiveFormat = "tar.bz2" FormatTarXz ArchiveFormat = "tar.xz" )
func DetectArchiveFormat ¶
func DetectArchiveFormat(path string) (ArchiveFormat, error)
DetectArchiveFormat detects the format of an archive file.
type ArchiveScanConfig ¶
type ArchiveScanConfig struct {
// MaxFileSize limits individual file scanning within archives.
MaxFileSize int64
// MaxTotalSize limits total bytes read from an archive.
MaxTotalSize int64
// MaxFiles limits the number of files scanned in an archive.
MaxFiles int
// MaxNestingDepth limits recursive archive scanning depth.
MaxNestingDepth int
// MaxCompressionRatio limits the decompression ratio to protect against zip bombs.
// A ratio of 100 means the uncompressed size can be at most 100x the compressed size.
// Set to 0 to disable this check (not recommended).
MaxCompressionRatio float64
// PathPatterns limits scanning to matching paths (nil = all text files).
PathPatterns []string
// ScanBinaryStrings enables string extraction from binary files.
ScanBinaryStrings bool
// BinaryMinStringLen is the minimum length for extracted binary strings.
BinaryMinStringLen int
}
ArchiveScanConfig configures archive scanning behavior.
func DefaultArchiveScanConfig ¶
func DefaultArchiveScanConfig() ArchiveScanConfig
DefaultArchiveScanConfig returns safe defaults for archive scanning.
func (ArchiveScanConfig) Validate ¶
func (c ArchiveScanConfig) Validate() error
Validate checks the configuration for errors.
type ArchiveScanResult ¶
type ArchiveScanResult struct {
// ArchivePath is the path to the scanned archive.
ArchivePath string `json:"archivePath"`
// Format is the detected archive format.
Format ArchiveFormat `json:"format"`
// EntriesScanned is the number of entries analyzed.
EntriesScanned int `json:"entriesScanned"`
// BytesScanned is the total bytes scanned.
BytesScanned int64 `json:"bytesScanned"`
// Findings contains all discovered secrets.
Findings []ArchiveFinding `json:"findings"`
// Errors contains any non-fatal errors encountered.
Errors []string `json:"errors,omitempty"`
// Truncated indicates if scanning was stopped early due to limits.
Truncated bool `json:"truncated,omitempty"`
// TruncationReason explains why scanning was truncated.
TruncationReason string `json:"truncationReason,omitempty"`
}
ArchiveScanResult contains results from scanning an archive.
type ArchiveScanner ¶
type ArchiveScanner struct {
// contains filtered or unexported fields
}
ArchiveScanner scans archives for secrets.
func NewArchiveScanner ¶
func NewArchiveScanner(config ArchiveScanConfig) (*ArchiveScanner, error)
NewArchiveScanner creates a new archive scanner.
func (*ArchiveScanner) ScanArchive ¶
func (s *ArchiveScanner) ScanArchive(ctx context.Context, archivePath string) (*ArchiveScanResult, error)
ScanArchive scans an archive file for secrets. The archive is extracted to a temporary directory with os.Root isolation for safe traversal, preventing path traversal attacks.
func (*ArchiveScanner) ScanArchiveReader ¶
func (s *ArchiveScanner) ScanArchiveReader(ctx context.Context, r io.Reader, format ArchiveFormat, name string) (*ArchiveScanResult, error)
ScanArchiveReader scans an archive from a reader. This is useful for scanning archives from non-file sources (network, memory).
func (*ArchiveScanner) ScanBinary ¶
ScanBinary scans a binary file for secrets in its readable sections.
func (*ArchiveScanner) ScanBinaryContent ¶
func (s *ArchiveScanner) ScanBinaryContent(ctx context.Context, content []byte, name string) ([]Finding, error)
ScanBinaryContent scans binary content for secrets.
func (*ArchiveScanner) ScanWithRoot ¶
ScanWithRoot scans files using an os.Root for safe filesystem access.
type AuditResult ¶
type AuditResult struct {
File string
Entry BaselineEntry
Status AuditStatus
}
AuditResult represents the result of auditing a single entry.
type AuditStatus ¶
type AuditStatus string
AuditStatus represents the result of auditing a baseline entry.
const ( AuditStatusValid AuditStatus = "valid" AuditStatusFileDeleted AuditStatus = "file_deleted" AuditStatusLineMoved AuditStatus = "line_moved" AuditStatusContentChanged AuditStatus = "content_changed" )
type Baseline ¶
type Baseline struct {
// Version of the baseline format.
Version string `json:"version"`
// GeneratedAt is when the baseline was last updated.
GeneratedAt time.Time `json:"generated_at"`
// Plugins lists which detectors were enabled when generating this baseline.
// Used for compatibility checking.
Plugins []string `json:"plugins,omitempty"`
// Filters lists active filter configurations.
Filters *BaselineFilters `json:"filters,omitempty"`
// Results maps file paths to their known findings.
Results map[string][]BaselineEntry `json:"results"`
// Custom is for user-defined metadata.
Custom map[string]any `json:"custom,omitempty"`
}
Baseline represents a collection of known/accepted secret findings. It enables tracking of false positives and intentional test secrets, allowing incremental scanning that only reports new secrets.
func GenerateBaseline ¶
func GenerateBaseline(ctx context.Context, scanner Scanner, dir string, reason string) (*Baseline, error)
GenerateBaseline scans a directory and creates a baseline from all findings. This is useful for onboarding existing projects with known secrets.
func LoadBaseline ¶
LoadBaseline loads a baseline from a JSON file.
func (*Baseline) AddFinding ¶
AddFinding adds a finding to the baseline.
func (*Baseline) AddFindings ¶
AddFindings adds multiple findings to the baseline.
func (*Baseline) Audit ¶
func (b *Baseline) Audit(rootDir string) ([]AuditResult, error)
Audit verifies that baseline entries still match the actual file contents. Returns entries that no longer match (stale entries).
func (*Baseline) Clean ¶
Clean removes stale entries from the baseline. Returns the number of entries removed.
func (*Baseline) Filter ¶
Filter removes findings that are in the baseline. Returns only new findings not present in the baseline.
func (*Baseline) Merge ¶
Merge combines another baseline into this one. Entries from other take precedence on conflicts.
func (*Baseline) TotalEntries ¶
TotalEntries returns the total number of baseline entries.
type BaselineComment ¶
type BaselineComment struct {
// Pattern to match the comment
Pattern string
// Reason extracted from the comment
Reason string
}
BaselineComment represents a special comment in source code that marks a line as an allowed secret (inline allowlisting). Format: deputy:allowlist:reason
type BaselineEntry ¶
type BaselineEntry struct {
// Type of secret detected.
Type string `json:"type"`
// Line number (1-indexed).
Line int `json:"line"`
// Column position (1-indexed).
Column int `json:"column,omitempty"`
// Hash is a content-based hash for matching (avoids storing actual secret).
Hash string `json:"hash"`
// Reason explains why this is in the baseline (false positive, test data, etc.).
Reason string `json:"reason,omitempty"`
// IsVerified indicates if the hash was verified against the file.
IsVerified bool `json:"is_verified,omitempty"`
// AddedAt is when this entry was added to the baseline.
AddedAt time.Time `json:"added_at,omitempty"`
}
BaselineEntry represents a single known secret finding.
type BaselineFilters ¶
type BaselineFilters struct {
// ExcludedPatterns are file glob patterns to skip.
ExcludedPatterns []string `json:"excluded_patterns,omitempty"`
// ExcludedTypes are secret types to skip.
ExcludedTypes []string `json:"excluded_types,omitempty"`
// MinConfidence is the minimum confidence threshold.
MinConfidence float64 `json:"min_confidence,omitempty"`
}
BaselineFilters captures filter settings used when creating the baseline.
type BaselineScanner ¶
type BaselineScanner struct {
// contains filtered or unexported fields
}
BaselineScanner wraps a Scanner to filter findings against a baseline.
func NewBaselineScanner ¶
func NewBaselineScanner(scanner Scanner, baseline *Baseline) *BaselineScanner
NewBaselineScanner creates a scanner that filters findings against a baseline.
type BatchResult ¶
type BatchResult struct {
// ID is the identifier for the scanned item (e.g., filename, path).
ID string `json:"id"`
// Findings are the secrets found in this item.
Findings []Finding `json:"findings"`
// Error is any error encountered during scanning (nil if successful).
Error error `json:"error,omitempty"`
}
BatchResult represents the result of scanning a single item in a batch.
type BatchScanner ¶
type BatchScanner struct {
// contains filtered or unexported fields
}
BatchScanner provides concurrent batch scanning capabilities.
func NewBatchScanner ¶
func NewBatchScanner(scanner Scanner, concurrency int) *BatchScanner
NewBatchScanner creates a scanner for concurrent batch operations. Concurrency controls max parallel scans (defaults to runtime.NumCPU if <= 0).
func (*BatchScanner) ScanBatch ¶
func (b *BatchScanner) ScanBatch(ctx context.Context, items map[string][]byte) []BatchResult
ScanBatch scans multiple content items concurrently and returns results. Items is a map of ID to content bytes.
func (*BatchScanner) ScanFiles ¶
func (b *BatchScanner) ScanFiles(ctx context.Context, files []string) <-chan BatchResult
ScanFiles scans multiple files concurrently. Returns a channel of results for streaming processing.
type BatchScannerOption ¶
type BatchScannerOption func(*BatchScanner)
BatchScannerOption configures a BatchScanner.
func WithConcurrency ¶
func WithConcurrency(n int) BatchScannerOption
WithConcurrency sets the concurrency level.
type BinarySection ¶
BinarySection represents a section of a binary file.
func ExtractBinarySections ¶
func ExtractBinarySections(content []byte) ([]BinarySection, error)
ExtractBinarySections extracts relevant sections from binary files. This safely extracts read-only data sections that may contain secrets.
type CommitInfo ¶
type CommitInfo struct {
Hash string `json:"hash"`
ShortHash string `json:"shortHash"`
Author string `json:"author"`
Email string `json:"email"`
Message string `json:"message"`
Date time.Time `json:"date"`
}
CommitInfo contains metadata about a git commit.
type ContainerFinding ¶
type ContainerFinding struct {
Finding
// LayerIndex is the layer number (0 = base layer).
LayerIndex int `json:"layerIndex"`
// LayerDigest is the layer's digest.
LayerDigest string `json:"layerDigest,omitempty"`
// LayerCommand is the Dockerfile command that created this layer.
LayerCommand string `json:"layerCommand,omitempty"`
// InBaseImage indicates if this layer is from the base image.
InBaseImage bool `json:"inBaseImage"`
// Source indicates where the secret was found.
Source ContainerSecretSource `json:"source"`
}
ContainerFinding extends Finding with container layer context.
type ContainerScanConfig ¶
type ContainerScanConfig struct {
// ScanLayers enables deep layer content scanning.
ScanLayers bool
// ScanEnvVars enables environment variable scanning.
ScanEnvVars bool
// ScanHistory enables build history scanning.
ScanHistory bool
// ScanLabels enables label scanning.
ScanLabels bool
// MaxLayerSize limits layer scanning to files under this size (bytes).
MaxLayerSize int64
// PathPatterns limits file scanning to matching paths.
PathPatterns []string
// BaseImageLayers is the number of layers from the base image.
BaseImageLayers int
}
ContainerScanConfig configures container secret scanning.
func DefaultContainerScanConfig ¶
func DefaultContainerScanConfig() ContainerScanConfig
DefaultContainerScanConfig returns sensible defaults for container scanning.
type ContainerScanOptions ¶
ContainerScanOptions configures container secret scanning.
type ContainerScanResult ¶
type ContainerScanResult struct {
// Image is the image reference that was scanned.
Image string `json:"image"`
// Digest is the image digest.
Digest string `json:"digest,omitempty"`
// LayersScanned is how many layers were analyzed.
LayersScanned int `json:"layersScanned"`
// Findings contains all discovered secrets.
Findings []ContainerFinding `json:"findings"`
// Stats provides aggregate statistics.
Stats ContainerScanStats `json:"stats"`
}
ContainerScanResult contains results from scanning a container image.
type ContainerScanStats ¶
type ContainerScanStats struct {
// TotalSecrets is the total secrets found.
TotalSecrets int `json:"totalSecrets"`
// BySource breaks down by source location.
BySource map[ContainerSecretSource]int `json:"bySource"`
// ByLayer breaks down by layer index.
ByLayer map[int]int `json:"byLayer"`
// InBaseImage counts secrets from base image layers.
InBaseImage int `json:"inBaseImage"`
// InAppLayers counts secrets from application layers.
InAppLayers int `json:"inAppLayers"`
}
ContainerScanStats provides aggregate statistics.
type ContainerScanner ¶
type ContainerScanner struct {
// contains filtered or unexported fields
}
ContainerScanner scans container images for secrets.
func NewContainerScanner ¶
func NewContainerScanner(config ContainerScanConfig) (*ContainerScanner, error)
NewContainerScanner creates a new container scanner.
func (*ContainerScanner) ScanChainLayers ¶
func (c *ContainerScanner) ScanChainLayers(ctx context.Context, chainLayers []scalibrimage.ChainLayer, baseImageLayers int) ([]ContainerFinding, error)
ScanChainLayers scans container image layers using OSV-SCALIBR's ChainLayer interface. This provides access to the merged filesystem at each layer, which is more efficient for scanning the final state of files across all layers. The baseImageLayers parameter indicates how many layers are from the base image.
func (*ContainerScanner) ScanImageConfig ¶
func (c *ContainerScanner) ScanImageConfig(ctx context.Context, config *ImageConfig) ([]ContainerFinding, error)
ScanImageConfig scans container image configuration for secrets. This includes environment variables, labels, entrypoint, and build history.
func (*ContainerScanner) ScanImageLayers ¶
func (c *ContainerScanner) ScanImageLayers(ctx context.Context, img v1.Image, baseImageLayers int) ([]ContainerFinding, error)
ScanImageLayers scans all layers of a container image for secrets using v1.Image. This performs deep content scanning of files within each layer's filesystem. The baseImageLayers parameter indicates how many layers are from the base image (for distinguishing base image secrets from application secrets).
func (*ContainerScanner) ScanIndividualLayers ¶
func (c *ContainerScanner) ScanIndividualLayers(ctx context.Context, layers []scalibrimage.Layer, baseImageLayers int) ([]ContainerFinding, error)
ScanIndividualLayers scans each layer independently using SCALIBR's Layer interface. This shows which layer introduced each secret, useful for identifying when secrets were added during the build process.
func (*ContainerScanner) ScanLayerTarball ¶
func (c *ContainerScanner) ScanLayerTarball(ctx context.Context, layerReader io.Reader, layerIndex int, layerDigest string, isBaseImage bool) ([]ContainerFinding, error)
ScanLayerTarball scans a single layer's tarball for secrets.
type ContainerSecretSource ¶
type ContainerSecretSource string
ContainerSecretSource identifies where in a container a secret was found.
const ( // SourceLayerFile means the secret was found in a file within a layer. SourceLayerFile ContainerSecretSource = "layer_file" // SourceEnvVar means the secret was found in an environment variable. SourceEnvVar ContainerSecretSource = "env_var" // SourceBuildArg means the secret was found in a build argument. SourceBuildArg ContainerSecretSource = "build_arg" // SourceLabel means the secret was found in an image label. SourceLabel ContainerSecretSource = "label" // SourceHistory means the secret was found in build history. SourceHistory ContainerSecretSource = "history" // SourceEntrypoint means the secret was found in entrypoint/cmd. SourceEntrypoint ContainerSecretSource = "entrypoint" )
type DiffResult ¶
type DiffResult struct {
// Added are secrets introduced in the target ref.
Added []Finding
// Removed are secrets present in base ref but not target ref.
Removed []Finding
}
DiffResult contains the result of a git diff scan.
func ScanGitDiff ¶
func ScanGitDiff(ctx context.Context, repoPath, baseRef, targetRef string) (*DiffResult, error)
ScanGitDiff scans changes between two git refs for secrets.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine provides secret detection capabilities.
func NewEngineWithConfig ¶
func NewEngineWithConfig(config EngineConfig) (*Engine, error)
NewEngineWithConfig creates a new secret detection engine with custom configuration.
type EngineConfig ¶
type EngineConfig struct {
// EnableEntropy enables entropy-based detection for unknown secret formats.
EnableEntropy bool
// EntropyThreshold is the minimum Shannon entropy to flag (0-8 for bytes).
// Default is 4.5, which catches most random strings while avoiding false positives.
EntropyThreshold float64
// EntropyMinLength is the minimum string length for entropy detection.
EntropyMinLength int
// DisabledPatterns allows disabling specific pattern detectors.
DisabledPatterns map[SecretType]bool
// CustomPatterns allows adding custom pattern detectors.
CustomPatterns []PatternDetector
}
EngineConfig configures the secret detection engine.
func DefaultEngineConfig ¶
func DefaultEngineConfig() EngineConfig
DefaultEngineConfig returns sensible defaults for secret detection.
func (EngineConfig) Validate ¶
func (c EngineConfig) Validate() error
Validate checks the configuration for errors.
type FilteringScanner ¶
type FilteringScanner struct {
// contains filtered or unexported fields
}
FilteringScanner wraps a scanner with filtering capabilities.
func NewFilteringScanner ¶
func NewFilteringScanner(scanner Scanner, opts ...FilteringScannerOption) *FilteringScanner
NewFilteringScanner wraps a scanner with filtering options.
type FilteringScannerOption ¶
type FilteringScannerOption func(*FilteringScanner)
FilteringScannerOption configures a FilteringScanner.
func WithAllowedTypes ¶
func WithAllowedTypes(types ...SecretType) FilteringScannerOption
WithAllowedTypes only reports findings of specified types.
func WithDeniedTypes ¶
func WithDeniedTypes(types ...SecretType) FilteringScannerOption
WithDeniedTypes excludes findings of specified types.
func WithMinConfidence ¶
func WithMinConfidence(conf float64) FilteringScannerOption
WithMinConfidence only reports findings above the threshold.
type Finding ¶
type Finding struct {
// Type identifies what kind of secret was found.
Type SecretType `json:"type"`
// Description provides human-readable context.
Description string `json:"description"`
// File is the source file where the secret was found (if applicable).
File string `json:"file,omitempty"`
// Line number where the secret was found (1-indexed, 0 if unknown).
Line int `json:"line,omitempty"`
// Column where the secret starts (1-indexed, 0 if unknown).
Column int `json:"column,omitempty"`
// Value is the actual secret value (for masking purposes).
// This should NOT be logged or exposed in reports.
Value string `json:"-"`
// Redacted is a safe representation for display.
Redacted string `json:"redacted"`
// Confidence indicates detection certainty (0.0-1.0).
Confidence float64 `json:"confidence"`
// Validated indicates if the secret was verified as active.
Validated bool `json:"validated,omitempty"`
}
Finding represents a detected secret.
func ScanContainerImage ¶
func ScanContainerImage(ctx context.Context, ref string, opts ContainerScanOptions) ([]Finding, []string, error)
ScanContainerImage scans a container image for secrets.
func VerifyFindings ¶
VerifyFindings attempts to validate detected secrets.
type GitHistoryOptions ¶
type GitHistoryOptions struct {
MaxCommits int
Since string
Until string
Branch string
IncludeRemoved bool
}
GitHistoryOptions configures git history scanning.
type HistoricalFinding ¶
type HistoricalFinding struct {
Finding
// IntroducedIn is the commit that first introduced this secret.
IntroducedIn *CommitInfo `json:"introducedIn,omitempty"`
// RemovedIn is the commit that removed this secret (nil if still present).
RemovedIn *CommitInfo `json:"removedIn,omitempty"`
// StillPresent indicates if the secret exists in the current HEAD.
StillPresent bool `json:"stillPresent"`
// CommitCount is how many commits contained this secret.
CommitCount int `json:"commitCount"`
// Authors is the list of commit authors who touched this secret.
Authors []string `json:"authors,omitempty"`
// Age is how long the secret has existed (from introduction to now or removal).
Age time.Duration `json:"age,omitempty"`
}
HistoricalFinding extends Finding with git history context.
func DetectLeakedSecretInContent ¶
func DetectLeakedSecretInContent(content []byte, historicalFindings []HistoricalFinding) []HistoricalFinding
DetectLeakedSecretInContent checks if content contains a leaked secret from repo history.
type HistoryFinding ¶
type HistoryFinding struct {
Finding
// CommitHash where the secret was introduced.
CommitHash string
// Author of the commit.
Author string
// AuthorEmail of the commit author.
AuthorEmail string
// CommitDate when the secret was introduced.
CommitDate string
// CommitMessage summary.
CommitMessage string
// RemovedIn is the commit where the secret was removed (empty if still present).
RemovedIn string
// StillPresent indicates if the secret exists in HEAD.
StillPresent bool
}
HistoryFinding extends Finding with git history context for proto conversion. This wraps HistoricalFinding with simpler field names.
func ScanGitHistory ¶
func ScanGitHistory(ctx context.Context, repoPath string, opts GitHistoryOptions) ([]HistoryFinding, error)
ScanGitHistory scans git history for secrets.
type HistoryScanConfig ¶
type HistoryScanConfig struct {
// MaxCommits limits how many commits to scan (0 = all).
MaxCommits int
// Since only scans commits after this time.
Since *time.Time
// Until only scans commits before this time.
Until *time.Time
// Branch specifies which branch to scan (default: HEAD).
Branch string
// IncludeRemoved includes secrets that were later removed.
IncludeRemoved bool
// PathFilter limits scanning to specific paths.
PathFilter []string
}
HistoryScanConfig configures historical secret scanning.
type HistoryScanResult ¶
type HistoryScanResult struct {
// Repository is the path to the scanned repository.
Repository string `json:"repository"`
// Branch is the branch that was scanned.
Branch string `json:"branch"`
// CommitsScanned is the total number of commits analyzed.
CommitsScanned int `json:"commitsScanned"`
// Findings contains all historical secret findings.
Findings []HistoricalFinding `json:"findings"`
// Stats provides aggregate statistics.
Stats HistoryStats `json:"stats"`
// ScannedAt is when the scan was performed.
ScannedAt time.Time `json:"scannedAt"`
}
HistoryScanResult contains the results of a historical secret scan.
type HistoryScanner ¶
type HistoryScanner struct {
// contains filtered or unexported fields
}
HistoryScanner scans git history for secrets.
func NewHistoryScanner ¶
func NewHistoryScanner(config HistoryScanConfig) (*HistoryScanner, error)
NewHistoryScanner creates a new git history scanner.
func (*HistoryScanner) ScanDiff ¶
func (h *HistoryScanner) ScanDiff(ctx context.Context, repoPath, baseRef, headRef string) ([]Finding, error)
ScanDiff scans the diff between two git refs for new secrets.
func (*HistoryScanner) ScanRepository ¶
func (h *HistoryScanner) ScanRepository(ctx context.Context, repoPath string) (*HistoryScanResult, error)
ScanRepository scans a git repository's history for secrets.
type HistoryStats ¶
type HistoryStats struct {
// TotalSecrets is the total unique secrets found across all commits.
TotalSecrets int `json:"totalSecrets"`
// ActiveSecrets is secrets still present in HEAD.
ActiveSecrets int `json:"activeSecrets"`
// RemovedSecrets is secrets that were later removed.
RemovedSecrets int `json:"removedSecrets"`
// ByType breaks down secrets by type.
ByType map[SecretType]int `json:"byType"`
// OldestSecret is the age of the oldest secret.
OldestSecret time.Duration `json:"oldestSecret,omitempty"`
// AuthorsWithSecrets lists authors who committed secrets.
AuthorsWithSecrets []string `json:"authorsWithSecrets,omitempty"`
}
HistoryStats provides aggregate statistics for historical findings.
type HookConfig ¶
type HookConfig struct {
// HookType is the type of hook to generate.
HookType HookType
// FailOnSecrets determines whether the hook should fail if secrets are found.
// If false, it will only warn.
FailOnSecrets bool
// VerifySecrets enables verification of detected secrets.
VerifySecrets bool
// Format is the output format for the hook (text, json, sarif).
Format string
// ExcludePatterns are file patterns to exclude from scanning.
ExcludePatterns []string
// IncludePatterns are file patterns to include (if empty, scans all).
IncludePatterns []string
// DeputyPath is the path to the deputy binary.
// If empty, assumes "deputy" is in PATH.
DeputyPath string
// AllowList is a path to an allowlist/baseline file.
AllowList string
// ScanStaged only scans staged files (for pre-commit).
ScanStaged bool
// Diff mode for pre-push (compare branches).
DiffMode bool
}
HookConfig configures hook generation.
func DefaultHookConfig ¶
func DefaultHookConfig(hookType HookType) HookConfig
DefaultHookConfig returns sensible defaults for hook generation.
type HookStatus ¶
type HookStatus struct {
Type HookType
Installed bool
IsDeputy bool // True if it's a deputy-generated hook
HasBackup bool // True if there's a backup of previous hook
}
HookStatus represents the status of a hook.
func GetHookStatus ¶
func GetHookStatus(repoPath string) ([]HookStatus, error)
GetHookStatus returns the status of hooks in the repository.
type HookType ¶
type HookType string
HookType represents the type of git hook.
func ListInstalledHooks ¶
ListInstalledHooks returns which deputy hooks are installed in the repository.
type ImageConfig ¶
type ImageConfig struct {
Env []string `json:"Env"`
Entrypoint []string `json:"Entrypoint"`
Cmd []string `json:"Cmd"`
Labels map[string]string `json:"Labels"`
History []ImageHistoryEntry `json:"History"`
}
ImageConfig represents container image configuration.
func ParseImageConfig ¶
func ParseImageConfig(data []byte) (*ImageConfig, error)
ParseImageConfig parses image configuration from JSON.
type ImageHistoryEntry ¶
type ImageHistoryEntry struct {
CreatedBy string `json:"created_by"`
EmptyLayer bool `json:"empty_layer"`
}
ImageHistoryEntry represents a single build history entry.
type InlineAllowlistScanner ¶
type InlineAllowlistScanner struct {
// contains filtered or unexported fields
}
InlineAllowlistScanner wraps a scanner to respect inline allowlist comments.
func NewInlineAllowlistScanner ¶
func NewInlineAllowlistScanner(scanner Scanner) *InlineAllowlistScanner
NewInlineAllowlistScanner creates a scanner that respects inline comments.
type Masker ¶
type Masker struct {
// contains filtered or unexported fields
}
Masker provides secret masking capabilities for text content. It is designed for use with AI agents to prevent accidental exposure of credentials in prompts and responses.
func (*Masker) AddSecret ¶
func (m *Masker) AddSecret(value string, secretType SecretType)
AddSecret manually registers a secret value for masking. This is useful when secrets are known from other sources (e.g., environment variables, configuration files).
func (*Masker) Mask ¶
Mask scans the input text for secrets and replaces them with redacted placeholders. Returns the masked text.
func (*Masker) MaskAndLearn ¶
MaskAndLearn scans input for secrets, caches them, and returns masked text. Unlike Mask, this also returns the findings for inspection.
func (*Masker) MaskKnown ¶
MaskKnown masks any previously detected secrets without re-scanning. This is useful for masking output that may contain secrets detected in earlier input.
func (*Masker) Stats ¶
func (m *Masker) Stats() map[SecretType]int
Stats returns the count of known secrets by type.
type MultiScanner ¶
type MultiScanner struct {
// contains filtered or unexported fields
}
MultiScanner composes multiple scanners, deduplicating results.
func NewMultiScanner ¶
func NewMultiScanner(scanners ...Scanner) *MultiScanner
NewMultiScanner creates a scanner that runs multiple scanners and combines results.
type PatternDetector ¶
type PatternDetector struct {
Type SecretType
Pattern *regexp.Regexp
Description string
Confidence float64
}
PatternDetector defines a regex-based secret detector (exported for extensibility).
type PolicyFinding ¶
type PolicyFinding struct {
// Type is the secret type (e.g., "github_token", "aws_access_key").
Type string `json:"type"`
// Description provides context about the finding.
Description string `json:"description"`
// File is the path where the secret was found.
File string `json:"file"`
// Line is the line number (1-indexed).
Line int `json:"line"`
// Column is the column number (1-indexed).
Column int `json:"column"`
// Confidence is the detection confidence (0.0-1.0).
Confidence float64 `json:"confidence"`
// Validated indicates if the secret was verified as active.
Validated bool `json:"validated"`
// Redacted is the safe redacted representation.
Redacted string `json:"redacted"`
// Source identifies where the secret was found (for container scans).
Source string `json:"source,omitempty"`
// InBaseImage indicates if found in base image layer (for containers).
InBaseImage bool `json:"inBaseImage,omitempty"`
// LayerIndex is the layer where the secret was found (for containers).
LayerIndex int `json:"layerIndex,omitempty"`
}
PolicyFinding represents a secret finding for CEL policy evaluation. This is a CEL-friendly representation of a Finding.
func ContainerFindingToPolicyFinding ¶
func ContainerFindingToPolicyFinding(f ContainerFinding) PolicyFinding
ContainerFindingToPolicyFinding converts a ContainerFinding to PolicyFinding.
func ContainerFindingsToPolicyFindings ¶
func ContainerFindingsToPolicyFindings(findings []ContainerFinding) []PolicyFinding
ContainerFindingsToPolicyFindings converts ContainerFindings to PolicyFindings.
func ToPolicyFinding ¶
func ToPolicyFinding(f Finding) PolicyFinding
ToPolicyFinding converts a Finding to a PolicyFinding for CEL evaluation.
func ToPolicyFindings ¶
func ToPolicyFindings(findings []Finding) []PolicyFinding
ToPolicyFindings converts a slice of Findings to PolicyFindings.
type PolicyReport ¶
type PolicyReport struct {
// Target is what was scanned (directory, image, archive).
Target string `json:"target"`
// FilesScanned is the number of files analyzed.
FilesScanned int `json:"filesScanned"`
// SecretsFound is the total number of secrets detected.
SecretsFound int `json:"secretsFound"`
// HighConfidenceCount is findings with >= 90% confidence.
HighConfidenceCount int `json:"highConfidenceCount"`
// ValidatedCount is the number of verified active secrets.
ValidatedCount int `json:"validatedCount"`
// Stats provides aggregate counts by secret type.
Stats map[string]int `json:"stats"`
}
PolicyReport represents the full secrets scan report for CEL evaluation.
func BuildPolicyReport ¶
func BuildPolicyReport(target string, filesScanned int, findings []Finding) PolicyReport
BuildPolicyReport creates a PolicyReport from findings for CEL evaluation.
type SARIFReport ¶
type SARIFReport struct {
// contains filtered or unexported fields
}
SARIFReport generates a SARIF report from secret findings.
func NewSARIFReport ¶
func NewSARIFReport(opts SARIFReportOptions) *SARIFReport
NewSARIFReport creates a new SARIF report generator.
func (*SARIFReport) Generate ¶
func (r *SARIFReport) Generate(findings []Finding) *sarif.Log
Generate creates a SARIF document from findings using the shared sarif package.
type SARIFReportOptions ¶
type SARIFReportOptions struct {
// ToolVersion is the version of the tool.
ToolVersion string
// BaseURI is the base URI for relative file paths.
BaseURI string
// Repo is the repository URL or path that was scanned.
Repo string
// Ref is the git reference (branch/tag) that was scanned.
Ref string
// Commit is the git commit hash.
Commit string
// Category is a unique identifier for this analysis run.
Category string
// WorkingDirectory is the base path for artifact URIs.
WorkingDirectory string
// StartTime is when the scan started.
StartTime time.Time
// EndTime is when the scan completed.
EndTime time.Time
}
SARIFReportOptions configures SARIF report generation for secrets.
func DefaultSARIFOptions ¶
func DefaultSARIFOptions() SARIFReportOptions
DefaultSARIFOptions returns sensible defaults for SARIF generation.
type Scanner ¶
type Scanner interface {
// Scan analyzes content and returns any detected secrets.
Scan(ctx context.Context, content []byte) ([]Finding, error)
// ScanFile analyzes file content with filename context.
ScanFile(ctx context.Context, filename string, content []byte) ([]Finding, error)
}
Scanner defines the interface for secret scanning. This allows for composable, pluggable scanner implementations.
type SecretType ¶
type SecretType string
SecretType identifies the kind of secret detected.
const ( // Veles-detected types TypeGCPAPIKey SecretType = "gcp_api_key" TypeGCPServiceAccountKey SecretType = "gcp_service_account_key" TypeRubyGemsAPIKey SecretType = "rubygems_api_key" // Pattern-detected types TypeAWSAccessKey SecretType = "aws_access_key" TypeAWSSecretKey SecretType = "aws_secret_key" TypeGitHubToken SecretType = "github_token" TypeGitHubFineGrain SecretType = "github_fine_grained_token" TypeGenericAPIKey SecretType = "generic_api_key" TypePrivateKey SecretType = "private_key" TypeJWT SecretType = "jwt" TypeSlackToken SecretType = "slack_token" TypeStripeKey SecretType = "stripe_key" TypeSendGridKey SecretType = "sendgrid_key" TypeNpmToken SecretType = "npm_token" TypePyPIToken SecretType = "pypi_token" TypeDiscordToken SecretType = "discord_token" TypeTelegramToken SecretType = "telegram_token" TypeHerokuAPIKey SecretType = "heroku_api_key" TypeMailgunKey SecretType = "mailgun_key" TypeTwilioKey SecretType = "twilio_key" TypeHighEntropy SecretType = "high_entropy_string" TypeSensitiveEnvVar SecretType = "sensitive_env_var" // Additional patterns TypeSlackWebhook SecretType = "slack_webhook" TypeTerraformToken SecretType = "terraform_token" TypeCloudflareAPIKey SecretType = "cloudflare_api_key" TypeDatadogAPIKey SecretType = "datadog_api_key" TypeLinearAPIKey SecretType = "linear_api_key" TypeOpenAIKey SecretType = "openai_api_key" TypeAnthropicKey SecretType = "anthropic_api_key" TypeAzureSASToken SecretType = "azure_sas_token" TypeGitLabToken SecretType = "gitlab_token" TypeBitbucketToken SecretType = "bitbucket_token" TypeDigitalOceanToken SecretType = "digitalocean_token" )
type VerificationConfig ¶
type VerificationConfig struct {
// Timeout for individual verification requests.
Timeout time.Duration
// MaxConcurrent limits parallel verification requests.
MaxConcurrent int
// SkipTLSVerify disables TLS certificate validation (for testing).
SkipTLSVerify bool
// RateLimit is max verifications per second (0 = unlimited).
RateLimit int
}
VerificationConfig configures the verification engine.
type VerificationEngine ¶
type VerificationEngine struct {
// contains filtered or unexported fields
}
VerificationEngine orchestrates secret verification across multiple providers.
func NewVerificationEngine ¶
func NewVerificationEngine(cfg *VerificationConfig) *VerificationEngine
NewVerificationEngine creates a verification engine with default providers.
func (*VerificationEngine) Verify ¶
func (e *VerificationEngine) Verify(ctx context.Context, finding Finding) VerificationResult
Verify attempts to validate a secret using registered verifiers.
func (*VerificationEngine) VerifyBatch ¶
func (e *VerificationEngine) VerifyBatch(ctx context.Context, findings []Finding) map[int]VerificationResult
VerifyBatch verifies multiple findings concurrently.
type VerificationResult ¶
type VerificationResult struct {
// Status is the verification outcome.
Status VerificationStatus `json:"status"`
// Message provides additional context about the verification.
Message string `json:"message,omitempty"`
// Service identifies the service the secret belongs to.
Service string `json:"service,omitempty"`
// Identity is the authenticated identity (e.g., username, service account).
Identity string `json:"identity,omitempty"`
// Scopes lists the permissions/scopes the secret has.
Scopes []string `json:"scopes,omitempty"`
// ExpiresAt is when the secret expires (if applicable).
ExpiresAt *time.Time `json:"expiresAt,omitempty"`
// VerifiedAt is when verification was performed.
VerifiedAt time.Time `json:"verifiedAt"`
// Error contains error details if verification failed.
Error string `json:"error,omitempty"`
}
VerificationResult contains details about a secret verification attempt.
type VerificationStatus ¶
type VerificationStatus string
VerificationStatus represents the result of validating a secret.
const ( // StatusUnknown means verification was not attempted or inconclusive. StatusUnknown VerificationStatus = "unknown" // StatusValid means the secret was confirmed active/working. StatusValid VerificationStatus = "valid" // StatusInvalid means the secret was confirmed invalid/revoked. StatusInvalid VerificationStatus = "invalid" // StatusExpired means the secret has expired. StatusExpired VerificationStatus = "expired" // StatusRateLimited means verification was blocked by rate limiting. StatusRateLimited VerificationStatus = "rate_limited" // StatusError means verification failed due to an error. StatusError VerificationStatus = "error" )
type Verifier ¶
type Verifier interface {
// CanVerify returns true if this verifier handles the given secret type.
CanVerify(secretType SecretType) bool
// Verify checks if a secret is valid/active.
Verify(ctx context.Context, secret string, secretType SecretType) VerificationResult
// Name returns the verifier name for logging.
Name() string
}
Verifier validates whether detected secrets are active.
type VerifyOptions ¶
VerifyOptions configures secret verification.