Documentation
¶
Overview ¶
Package core provides the core interfaces and base implementations for the OpenCTEM Scanner SDK. Tenants can implement these interfaces to create custom scanners, collectors, and sensors.
Stability: Stable (docs/STABILITY.md).
Package core provides the core interfaces and base implementations for the OpenCTEM Scanner SDK.
Index ¶
- Constants
- Variables
- func APIKeyHint(key string) string
- func ApplyScannerPriority(cmd *exec.Cmd)
- func AuthFailureAdvice(err error, keyHint string) string
- func AuthFailureStatus(err error) int
- func BlockTool(name string) string
- func CanonicalScannerName(name string) string
- func CapScanLimit(requested, own, ceiling int) int
- func CheckBinaryInstalled(ctx context.Context, binary string, versionArgs ...string) (bool, string, error)
- func CheckEnv() error
- func CommandIDFromContext(ctx context.Context) string
- func ConfigHealthOf(checks []ConfigCheck) string
- func ConfigureScannerProcess(cmd *exec.Cmd)
- func ContentEnviron(extra ...map[string]string) []string
- func CoverageGapsMetadata(r *ScanResult) map[string]any
- func DSSEPreAuthEncoding(payloadType string, payload []byte) []byte
- func DetectRuntime() string
- func GenerateSastFingerprint(file, ruleID string, startLine int) string
- func GenerateScaFingerprint(pkgName, pkgVersion, vulnID string) string
- func GenerateSecretFingerprint(file, ruleID string, startLine int, secretValue string) string
- func HostArch() string
- func HostKey(target string) stringdeprecated
- func HostOS() string
- func IsCodeScanner(scanner string) bool
- func KeyBoundHint(keyID string) string
- func ListPresetScanners() []string
- func LiveHostsReport(report *ctis.Report, targets []string)
- func MaskAPIKey(key string) string
- func MaskSecret(secret string) string
- func MaskSecretInText(text, secret string) string
- func NormalizeSeverity(sev string) string
- func NowRFC3339() string
- func PlanWaves(targets []string, network string, maxWaves int) [][]string
- func PlatformTLSPin() string
- func ProcessInstanceID() string
- func ReapScannerProcess(cmd *exec.Cmd)
- func RecordOutput(ctx context.Context, records, bytes int)
- func RecordProcessState(ctx context.Context, ps *os.ProcessState)
- func RefusedTargetsMetadata(refused []RefusedTarget) map[string]any
- func RequireLocalPolicyFromEnv(lookup func(string) (string, bool)) (required, set bool, err error)
- func RequireSignedJobsFromEnv(lookup func(string) (string, bool)) (required, set bool, err error)
- func RunWaves(ctx context.Context, targets []string, network string, maxWaves int, ...) error
- func ScannerEnviron(extra ...map[string]string) []string
- func ScannerEnvironFor(tool string, extra ...map[string]string) []string
- func ScannerProxySummary() string
- func SetDefaultLogger(logger Logger)
- func SetJobsKeySet(t *jobsig.KeySetTrust)
- func SetJobsPosture(signed string)
- func SetScannerEnvAllowlist(names []string)
- func SetScannerInheritEnv(inherit bool)
- func SetScannerPriority(p *ScannerPriority)
- func SetScannerProxyMode(m ScannerProxyMode)
- func SettingsDigest(raw []byte) (string, error)
- func SeverityFromCVSS(score float64) string
- func StripANSI(s string) string
- func TargetDone(ctx context.Context, target string)
- func TargetOutcomes(targets []string, report *ctis.Report) []outcome.Target
- func TemplateKeyID(pub ed25519.PublicKey) string
- func TrackProcess(ctx context.Context, pid int)
- func ValidateBaseScannerConfig(cfg *BaseScannerConfig) error
- func ValidateBaseSensorConfig(cfg *BaseSensorConfig) error
- func ValidateCommandPollerConfig(cfg *CommandPollerConfig) error
- func ValidateExtraArgs(args []string) error
- func ValidateScanOptions(opts *ScanOptions) error
- func ValidateTemplate(tpl *EmbeddedTemplate) error
- func VersionAfterLabel(output, label string) string
- func VersionOutput(ctx context.Context, binary string, versionArgs ...string) (bool, string, error)
- func WithCommandID(ctx context.Context, cmdID string) context.Context
- func WithProgress(ctx context.Context, p *Progress) context.Context
- type APIKeyHinter
- type ASN
- type Adapter
- type AdapterOptions
- type AssetResolver
- type AuthGate
- type AuthGateConfig
- type BaseCollector
- func (c *BaseCollector) Collect(ctx context.Context, opts *CollectOptions) (*CollectResult, error)
- func (c *BaseCollector) FetchJSON(ctx context.Context, path string, query map[string]string, result interface{}) error
- func (c *BaseCollector) Name() string
- func (c *BaseCollector) SetVerbose(v bool)
- func (c *BaseCollector) TestConnection(ctx context.Context) error
- func (c *BaseCollector) Type() string
- type BaseCollectorConfig
- type BaseParser
- func (p *BaseParser) CanParse(data []byte) bool
- func (p *BaseParser) CreateFinding(id, title string, severity ctis.Severity) ctis.Finding
- func (p *BaseParser) CreateReport(toolName, toolVersion string) *ctis.Report
- func (p *BaseParser) Name() string
- func (p *BaseParser) Parse(ctx context.Context, data []byte, opts *ParseOptions) (*ctis.Report, error)
- func (p *BaseParser) SupportedFormats() []string
- type BaseProcessor
- func (p *BaseProcessor) AddParser(parser Parser)
- func (p *BaseProcessor) Process(ctx context.Context, scanner Scanner, opts *ProcessOptions) (*ProcessResult, error)
- func (p *BaseProcessor) ProcessBatch(ctx context.Context, scanners []Scanner, opts *ProcessOptions) ([]*ProcessResult, error)
- func (p *BaseProcessor) SetVerbose(v bool)
- type BaseScanner
- func (s *BaseScanner) BuildArgs(target string, opts *ScanOptions) []string
- func (s *BaseScanner) Capabilities() []string
- func (s *BaseScanner) IsInstalled(ctx context.Context) (bool, string, error)
- func (s *BaseScanner) Name() string
- func (s *BaseScanner) Scan(ctx context.Context, target string, opts *ScanOptions) (*ScanResult, error)
- func (s *BaseScanner) SetVerbose(v bool)
- func (s *BaseScanner) Version() string
- type BaseScannerConfig
- type BaseSensor
- func (a *BaseSensor) AddCollector(collector Collector) error
- func (a *BaseSensor) AddParser(parser Parser)
- func (a *BaseSensor) AddScanner(scanner Scanner) error
- func (a *BaseSensor) AuthGate() *AuthGate
- func (a *BaseSensor) CommandToolGate() func(*Command) error
- func (a *BaseSensor) FirstHeartbeat(ctx context.Context) (time.Duration, error)
- func (a *BaseSensor) ManifestPolicy() *ManifestPolicy
- func (a *BaseSensor) Name() string
- func (a *BaseSensor) Posture() *SensorPosture
- func (a *BaseSensor) RemoveCollector(name string) error
- func (a *BaseSensor) RemoveScanner(name string) error
- func (a *BaseSensor) SetAssetResolver(r AssetResolver)
- func (a *BaseSensor) SetAuthGate(g *AuthGate)
- func (a *BaseSensor) SetCapabilityReporter(r CapabilityReporter)
- func (a *BaseSensor) SetConfigReporter(r ConfigReporter)
- func (a *BaseSensor) SetDoorbell(d *Doorbell)
- func (a *BaseSensor) SetLoadReporter(r LoadReporter)
- func (a *BaseSensor) SetLocalPolicy(lp *LocalPolicy)
- func (a *BaseSensor) SetNetworkReporter(r NetworkReporter)
- func (a *BaseSensor) SetPosture(p *SensorPosture)
- func (a *BaseSensor) SetVerbose(v bool)
- func (a *BaseSensor) Start(ctx context.Context) error
- func (a *BaseSensor) Status() *SensorStatus
- func (a *BaseSensor) Stop(ctx context.Context) error
- func (a *BaseSensor) Tools() *ToolRegistry
- type BaseSensorConfig
- type CVSSData
- type CVSSSource
- type CacheStats
- type CachedTemplateMetadata
- type CancelPusher
- type CapabilityReport
- type CapabilityReporter
- type CapabilityReporterFunc
- type CapabilityScanner
- type CollectCommandPayload
- type CollectOptions
- type CollectResult
- type Collector
- type Command
- type CommandAdmission
- type CommandCanceler
- type CommandClaimer
- type CommandClient
- type CommandExecutionResult
- type CommandExecutor
- type CommandLogSink
- type CommandPoller
- func (p *CommandPoller) ActiveJobs() int
- func (p *CommandPoller) CancelCommands(ids ...string)
- func (p *CommandPoller) HeldCommandIDs() []string
- func (p *CommandPoller) LocalKillSwitch() bool
- func (p *CommandPoller) MaxJobs() int
- func (p *CommandPoller) QueueStats() QueueStats
- func (p *CommandPoller) ReportStatus(status *SensorStatus)
- func (p *CommandPoller) RunClaimed(ctx context.Context, cmd *Command) error
- func (p *CommandPoller) SetAuthGate(g *AuthGate)
- func (p *CommandPoller) SetCommandGate(gate func(*Command) error)
- func (p *CommandPoller) SetCommandLogSink(sink CommandLogSink)
- func (p *CommandPoller) SetDoorbell(d *Doorbell)
- func (p *CommandPoller) SetJobGuard(g *JobGuard)
- func (p *CommandPoller) SetLocalPolicy(lp *LocalPolicy)
- func (p *CommandPoller) SetResourceManager(m *resource.Manager)
- func (p *CommandPoller) SetVerbose(v bool)
- func (p *CommandPoller) Start(ctx context.Context) error
- func (p *CommandPoller) Stop()
- func (p *CommandPoller) StopCommands(ids ...string)
- type CommandPollerConfig
- type CommandProgress
- type CommandResult
- type ConfigCheck
- type ConfigParam
- type ConfigReport
- type ConfigReportAck
- type ConfigReportPusher
- type ConfigReportSummary
- type ConfigReporter
- type ConfigReporterFunc
- type ConfigRuntime
- type ConfigSetting
- type Connector
- type ConnectorConfig
- type ContentInfo
- type ContentPin
- type ContentPolicy
- type ControlStats
- type DNSRecord
- type DefaultCommandExecutor
- func (e *DefaultCommandExecutor) AddCollector(collector Collector)
- func (e *DefaultCommandExecutor) AddScanner(scanner Scanner)
- func (e *DefaultCommandExecutor) Execute(ctx context.Context, cmd *Command) (*CommandExecutionResult, error)
- func (e *DefaultCommandExecutor) ScanTargetPolicy() *ScanTargetPolicy
- func (e *DefaultCommandExecutor) SetAssetResolver(r AssetResolver)
- func (e *DefaultCommandExecutor) SetLocalPolicy(lp *LocalPolicy)
- func (e *DefaultCommandExecutor) SetParserRegistry(r *ParserRegistry)
- func (e *DefaultCommandExecutor) SetScanTargetPolicy(p *ScanTargetPolicy)
- func (e *DefaultCommandExecutor) SetSensorID(id string)
- func (e *DefaultCommandExecutor) SetSourceCredentials(c SourceCredentials)
- func (e *DefaultCommandExecutor) SetTemplateVerifier(v *TemplateVerifier)
- func (e *DefaultCommandExecutor) SetToolRegistry(r *ToolRegistry)
- func (e *DefaultCommandExecutor) SetVerbose(v bool)
- type DefaultLogger
- func (l *DefaultLogger) Debug(format string, args ...interface{})
- func (l *DefaultLogger) Error(format string, args ...interface{})
- func (l *DefaultLogger) Info(format string, args ...interface{})
- func (l *DefaultLogger) SetLevel(level LogLevel)
- func (l *DefaultLogger) SetOutput(w io.Writer)
- func (l *DefaultLogger) Warn(format string, args ...interface{})
- type DiscoveredURL
- type Doorbell
- func (d *Doorbell) ConfigVersion() string
- func (d *Doorbell) Draining() bool
- func (d *Doorbell) Handle(h *HeartbeatHints)
- func (d *Doorbell) HeartbeatFailed()
- func (d *Doorbell) HintsActive() bool
- func (d *Doorbell) Paused() bool
- func (d *Doorbell) PendingJobs() int
- func (d *Doorbell) State() string
- func (d *Doorbell) Wake() <-chan struct{}
- type DoorbellConfig
- type DoorbellPusher
- type EmbeddedTemplate
- type Enricher
- type EnricherConfig
- type EnvelopeSignature
- type ExecConfig
- type ExecResult
- type FileSettingsStore
- type GetCommandsResponse
- type GitHubAlertInstance
- type GitHubAlertLocation
- type GitHubAlertMessage
- type GitHubAlertRule
- type GitHubAlertTool
- type GitHubCodeScanningAlert
- type GitHubCollector
- type GitHubCollectorConfig
- type HeartbeatAction
- type HeartbeatHints
- type JSONParser
- type JobGuard
- type JobsPosture
- type LimitedCommandClient
- type LiveHost
- type LoadReporter
- type LocalPolicy
- func (lp *LocalPolicy) AcceptsManagedPolicy() bool
- func (lp *LocalPolicy) AdmitCommand(ctx context.Context, cmd *Command) error
- func (lp *LocalPolicy) AdmitCommandTargets(ctx context.Context, cmd *Command) (*CommandAdmission, error)
- func (lp *LocalPolicy) AdmittedAddrs(ctx context.Context, host string) ([]netip.Addr, error)
- func (lp *LocalPolicy) AllowsCheck(commandType string) bool
- func (lp *LocalPolicy) AllowsCustomTemplates() bool
- func (lp *LocalPolicy) AllowsInteractsh() bool
- func (lp *LocalPolicy) AllowsTool(tool string) bool
- func (lp *LocalPolicy) CapRate(requested int) int
- func (lp *LocalPolicy) CapTimeout(requested time.Duration) time.Duration
- func (lp *LocalPolicy) CheckDial(ctx context.Context, network, address string) ([]net.IP, error)
- func (lp *LocalPolicy) CheckTarget(ctx context.Context, target string) error
- func (lp *LocalPolicy) CommandWarnings(cmd *Command) []string
- func (lp *LocalPolicy) Describe() string
- func (lp *LocalPolicy) DialContext(d *net.Dialer) func(ctx context.Context, network, address string) (net.Conn, error)
- func (lp *LocalPolicy) Digest() string
- func (lp *LocalPolicy) HTTPPolicy() (userAgent string, allowInsecureTLS bool)
- func (lp *LocalPolicy) KillSwitchEngaged() bool
- func (lp *LocalPolicy) NetworkScope() netctx.Scope
- func (lp *LocalPolicy) Path() string
- func (lp *LocalPolicy) Present() bool
- func (lp *LocalPolicy) Report() *LocalPolicyReport
- func (lp *LocalPolicy) Required() bool
- func (lp *LocalPolicy) Schema() string
- func (lp *LocalPolicy) Warnings() []string
- func (lp *LocalPolicy) WithRequired(required bool) *LocalPolicy
- type LocalPolicyError
- type LocalPolicyOptions
- type LocalPolicyReport
- type LocalPolicySummary
- type LogLevel
- type Logger
- type Manifest
- type ManifestAck
- type ManifestConcurrency
- type ManifestContent
- type ManifestIgnored
- type ManifestPlatform
- type ManifestPolicy
- type ManifestPusher
- type ManifestResources
- type ManifestStateReader
- type ManifestTemplate
- type ManifestTool
- type ManifestToolSettings
- type MultiTargetScanner
- type NetworkReporter
- type NopLogger
- type OAuthConfig
- type OpenPort
- type OrgHTTPPolicy
- type OutputHandler
- type Package
- type PackageDependency
- type PackageType
- type ParseOptions
- type Parser
- type ParserRegistry
- type PerTargetOptions
- type PlatformTLSPosture
- type PrintfLogger
- type ProcessOptions
- type ProcessResult
- type Processor
- type Progress
- func (p *Progress) DoneN(n int)
- func (p *Progress) RecordOutput(records int, bytes int)
- func (p *Progress) SetTargets(targets []string)
- func (p *Progress) SetTotal(total int)
- func (p *Progress) Snapshot() CommandProgress
- func (p *Progress) TargetDone(target string)
- func (p *Progress) TrackProcess(pid int)
- type Provider
- type ProviderConfig
- type PushResult
- type Pusher
- type QueueStats
- type ReconOptions
- type ReconResult
- type ReconScanner
- type ReconType
- type RefreshContentRequest
- type Refusal
- type RefusedTarget
- type ReleasingCommandClient
- type RetryAfterHinter
- type SARIFParser
- type SDKInfo
- type SandboxPosture
- type ScaResult
- type ScaScanOptions
- type ScaScanner
- type ScanCommandPayload
- type ScanOptions
- type ScanResult
- type ScanTargetPolicy
- type Scanner
- type ScannerPriority
- type ScannerProxyMode
- type ScannerType
- type ScopeLimitScanner
- type SecretFinding
- type SecretResult
- type SecretScanOptions
- type SecretScanner
- type Sensor
- type SensorBuild
- type SensorPosture
- type SensorSettings
- type SensorState
- type SensorStatus
- type SettingProperty
- type SettingScope
- type SettingSource
- type SettingsError
- type SettingsErrors
- type SettingsLayer
- type SettingsLayers
- type SettingsSchema
- type SettingsSchemaError
- type SettingsSchemaProvider
- type SettingsSignature
- type SettingsStore
- type SignedEnvelope
- type SourceCredentials
- type StatusReporter
- type Subdomain
- type TLSLeaf
- type TargetOutcome
- type TaskBudget
- type Technology
- type TemplateBinding
- type TemplateCache
- func (c *TemplateCache) Cleanup() error
- func (c *TemplateCache) Clear(tenantID string) error
- func (c *TemplateCache) Get(contentHash string) (string, bool)deprecated
- func (c *TemplateCache) GetFor(tenantID, templateType, contentHash string) (string, bool)
- func (c *TemplateCache) GetOrPut(tenantID string, template *EmbeddedTemplate) (string, error)
- func (c *TemplateCache) GetTemplateDir(tenantID, templateType string, templates []EmbeddedTemplate) (string, error)
- func (c *TemplateCache) Put(tenantID string, template *EmbeddedTemplate) (string, error)
- func (c *TemplateCache) Remove(contentHash string) error
- func (c *TemplateCache) Stats() *CacheStats
- type TemplateCacheConfig
- type TemplateManifest
- type TemplateVerifier
- type ToolContent
- type ToolContract
- type ToolContractProvider
- type ToolInfo
- type ToolKind
- type ToolProbe
- type ToolRegistry
- func (r *ToolRegistry) AddCapabilities(caps ...string)
- func (r *ToolRegistry) Allowed(name string) bool
- func (r *ToolRegistry) CapabilityReport(ctx context.Context) CapabilityReport
- func (r *ToolRegistry) CostHints() map[string]resource.ToolCostHint
- func (r *ToolRegistry) HasKind(k ToolKind) bool
- func (r *ToolRegistry) Installed(ctx context.Context) []ToolInfo
- func (r *ToolRegistry) Len() int
- func (r *ToolRegistry) Limit(names ...string)
- func (r *ToolRegistry) Names() []string
- func (r *ToolRegistry) Refresh()
- func (r *ToolRegistry) Register(spec ToolSpec) error
- func (r *ToolRegistry) RegisterCollector(c Collector, caps ...string) error
- func (r *ToolRegistry) RegisterScanner(s Scanner, extraCaps ...string) error
- func (r *ToolRegistry) SetBackgroundRefresh(on bool)
- func (r *ToolRegistry) SetMaxConcurrentJobs(n int)
- func (r *ToolRegistry) SetProbeTTL(d time.Duration)
- func (r *ToolRegistry) SetProbeTimeout(d time.Duration)
- func (r *ToolRegistry) SettingsSchema(name string) *SettingsSchema
- func (r *ToolRegistry) SettingsSchemas() map[string]*SettingsSchema
- func (r *ToolRegistry) Unregister(name string)
- type ToolSettings
- type ToolSettingsBlock
- type ToolSpec
- type ValidationError
- type ValidationErrors
- type Validator
- func (v *Validator) APIKey(field, value string) *Validator
- func (v *Validator) Custom(field string, check func() bool, message string) *Validator
- func (v *Validator) DirectoryExists(field, path string) *Validator
- func (v *Validator) Errors() ValidationErrors
- func (v *Validator) FileExists(field, path string) *Validator
- func (v *Validator) Max(field string, value, max int) *Validator
- func (v *Validator) MaxDuration(field string, value, max time.Duration) *Validator
- func (v *Validator) Min(field string, value, min int) *Validator
- func (v *Validator) MinDuration(field string, value, min time.Duration) *Validator
- func (v *Validator) OneOf(field, value string, allowed []string) *Validator
- func (v *Validator) Required(field, value string) *Validator
- func (v *Validator) SourceID(field, value string) *Validator
- func (v *Validator) URL(field, value string) *Validator
- func (v *Validator) Validate() error
- type Vulnerability
- type VulnerabilityMetadata
- type WebhookCollector
- type WebhookCollectorConfig
Constants ¶
const ( // DefaultAuthBackoffBase is the delay before the first re-check after a // rejected heartbeat. It doubles on every further rejection. DefaultAuthBackoffBase = 30 * time.Second // DefaultAuthBackoffMax caps the delay between re-checks. DefaultAuthBackoffMax = 10 * time.Minute )
Backoff after the platform rejects the sensor's API key. A rejected key does not start working by itself: the operator has to re-activate the sensor or give it a new key. Until then the sensor checks back rarely instead of sending a heartbeat and a poll every interval.
const ( MinTargetBudget = time.Second MaxTargetBudget = time.Hour MinTaskBudget = time.Minute // OverrunFactor is how far past its budget a task may run before the // sensor stops it: a slow but progressing task is not cut at its // estimate. OverrunFactor = 2 )
Budget bounds. A target budget outside [MinTargetBudget, MaxTargetBudget] and a task budget outside [MinTaskBudget, MaxScanTimeout] are clamped.
const ( // MinClaimBackoff is the wait after the first fruitless poll. MinClaimBackoff = time.Second // MaxClaimBackoff caps the wait between fruitless polls. MaxClaimBackoff = time.Minute // MaxPollRetryAfter caps a Retry-After the platform sends on a refused // poll (429/503), so a broken or hostile answer cannot stop the sensor. MaxPollRetryAfter = 5 * time.Minute )
Bounds of the command poller's claim backoff.
A poll that only hands commands back (their hosts are busy here, no slot is free, the type is not allowed) changes nothing, yet each hand-back returns the command to the queue, the platform rings the doorbell again and the same command comes straight back: a claim/release loop as fast as the round trip. After such a poll the poller waits before the next one, doubling the wait (with jitter) while the polls stay fruitless, and lets the platform give the command to another sensor meanwhile. A command that ends here (the busy host may be free now) or a poll that starts a command ends the backoff.
const ( ReleaseReasonDraining = "draining" ReleaseReasonShutdown = "shutdown" ReleaseReasonCanceled = "canceled" ReleaseReasonPoliteness = "politeness" )
Release reasons sent with ReleasingCommandClient.ReleaseCommand.
const ( MaxConfigChecks = 200 MaxConfigSettings = 300 MaxConfigParams = 16 MaxConfigKeys = 8 MaxConfigBlocks = 8 MaxConfigNames = 8 MaxConfigSummaryLen = 300 MaxConfigExcerptLen = 512 )
Limits of a config report.
const ( CheckPass = "pass" CheckWarn = "warn" CheckFail = "fail" CheckSkip = "skip" CheckError = "error" )
Check statuses.
const ( SeverityInfo = "info" SeverityWarning = "warning" SeverityCritical = "critical" )
Check severities.
const ( ConfigHealthOK = "ok" ConfigHealthAttention = "attention" ConfigHealthImpaired = "impaired" ConfigHealthBlocked = "blocked" )
Config health rollups.
const ( ConfigTriggerStart = "start" ConfigTriggerChange = "change" ConfigTriggerRequested = "requested" )
Report triggers.
const ( RuntimeDocker = "docker" RuntimeKubernetes = "kubernetes" RuntimeSystemd = "systemd" RuntimeBinary = "binary" RuntimeUnknown = "unknown" )
Runtime kinds.
const ( BlockAll = "role:*" BlockScan = "role:scan" BlockPrivateTargets = "target:private" BlockCustomTemplates = "feature:custom_templates" )
Blocks: what a failed check keeps the sensor from doing.
const ( ContentTrivyDB = "trivy-db" ContentTrivyJavaDB = "trivy-java-db" ContentNucleiTemplates = "nuclei-templates" ContentSemgrepRules = "semgrep-rules" )
Content names. A name is one kind of content a tool uses; a sensor may report others.
const ( // MetaCoverageGaps is the list of hosts not fully covered // ([]adapt.Gap: host, reason breaker_open | rate_floor | blocked, // detail), at most adapt.TargetRate.MaxGaps entries. MetaCoverageGaps = "coverage_gaps" // MetaCoverageGapsTotal is how many hosts were not fully covered. MetaCoverageGapsTotal = "coverage_gaps_total" // MetaTargetRate is the per-host rate summary (adapt.Summary without // its gap list). MetaTargetRate = "target_rate" )
Result metadata keys of a scan's coverage gaps (RFC-074 in openctemio/openctem api/docs/rfcs): the platform shows them on the run and keeps the step partial.
const ( MinDoorbellHeartbeatInterval = 5 * time.Second MaxDoorbellHeartbeatInterval = 5 * time.Minute // MaxDoorbellPendingJobs is the most pending_jobs the server reports. MaxDoorbellPendingJobs = 100 // DefaultDoorbellSafetyPoll is how often a doorbell-driven poller still // polls on its own, in case a heartbeat answer that would have rung the // doorbell was lost. DefaultDoorbellSafetyPoll = 5 * time.Minute )
Client-side bounds on the heartbeat delay the platform advises. The server already clamps its advice; these only protect the sensor (and the platform) from a broken or hostile answer.
const ( // JobsSignedRequired: every command must carry a signed job that // verifies. JobsSignedRequired = "required" // JobsSignedVerifiedWhenPresent: a signed job is verified; an unsigned // command runs (a legacy install with pinned keys). JobsSignedVerifiedWhenPresent = "verified_when_present" // JobsSignedOff: no job-signing key is pinned; jobs are not verified. JobsSignedOff = "off" )
Job signing postures (JobsPosture.Signed).
const ( // EnvLocalPolicy is the path of the local policy file. Unset, the // sensor reads DefaultLocalPolicyPath when it exists. EnvLocalPolicy = "SENSOR_LOCAL_POLICY" // DefaultLocalPolicyPath is where an install mounts the policy // read-only. DefaultLocalPolicyPath = "/etc/openctem/sensor-policy.yaml" // EnvAllowedRanges is a shorthand policy without a file: a // comma-separated targets.allow list (CIDRs, IPs, domains, *.domains; // *.x covers x and every name below it). EnvAllowedRanges = "SENSOR_ALLOWED_RANGES" // EnvAllowedPorts is a shorthand policy without a file: ports.allow // ("1-1024,3389"). EnvAllowedPorts = "SENSOR_ALLOWED_PORTS" // EnvKillSwitchFile names a file whose presence stops every job, with // or without a policy file. EnvKillSwitchFile = "SENSOR_KILL_SWITCH_FILE" // EnvRequireLocalPolicy (true/false) decides whether the sensor fails // closed without a local policy. Set, it wins; unset, the caller decides // (LocalPolicyOptions.Required: the sensor kit requires a policy for an // identity paired by an SDK that fails closed). EnvRequireLocalPolicy = "SENSOR_REQUIRE_LOCAL_POLICY" // LocalPolicyRuleNoPolicy is the rule of a job refused because the // sensor requires a local policy and has none. LocalPolicyRuleNoPolicy = "no_local_policy" // LocalPolicyAPIVersion is the apiVersion of schema v1. v1 is frozen: // it never gains a key, because a sensor refuses a file with a key it // does not know, so a new v1 key would stop every older sensor (owner // decision D13, api research/25 §3.3). New keys go into a new version. LocalPolicyAPIVersion = "openctem.io/sensor-policy/v1" // LocalPolicyAPIVersionV2 is the apiVersion of schema v2: every v1 key // plus managed (see policyFileV2). LocalPolicyAPIVersionV2 = "openctem.io/sensor-policy/v2" // LocalPolicyAPIVersionV3 is the apiVersion of schema v3: every v2 key // plus http (see policyFileV3). LocalPolicyAPIVersionV3 = "openctem.io/sensor-policy/v3" // MaxLocalPolicyBytes bounds the policy file. MaxLocalPolicyBytes = 1 << 20 // MaxLocalPolicyEntries bounds each list in the policy. MaxLocalPolicyEntries = 4096 // MaxScanTimeout caps a scan command's timeout_seconds whatever the // platform sends (api RFC-040 P0); a local policy can lower it. MaxScanTimeout = 24 * time.Hour )
Local policy settings and limits.
const ( // LocalPolicyStateEnforced: a policy is loaded and every job is // checked against it. LocalPolicyStateEnforced = "enforced" // LocalPolicyStateAbsent: no policy; the sensor works as before // (built-in deny list and the private-range switch only). LocalPolicyStateAbsent = "absent" )
Local policy states, as LocalPolicyReport.State reports them.
const ( LocalPolicySourceFile = "file" LocalPolicySourceEnv = "env" )
Local policy sources, as LocalPolicyReport.Source reports them.
const ( // ConcurrencyModelDynamic: the SDK sizes the slots from CPU, memory and // the tools' learned cost (a resource manager), at most the ceiling. ConcurrencyModelDynamic = "dynamic" // ConcurrencyModelFixed: the ceiling is the slot count. ConcurrencyModelFixed = "fixed" )
Concurrency models of a manifest.
const ( // TLSPinFingerprint: platform requests trust only a pinned TLS // identity: the CA certificate of SENSOR_CA_FINGERPRINT, or the trust // anchor key recorded at pairing (identity.json platform_tls_pin). TLSPinFingerprint = "fingerprint" // TLSPinCAFile: platform requests trust a private CA file // (SENSOR_CA_CERT_FILE) besides the system trust store. TLSPinCAFile = "ca_file" // TLSPinNone: platform requests trust the system trust store only. TLSPinNone = "none" )
Platform TLS pins, as PlatformTLSPosture.Pin reports them.
const ( RefusalLayerBuiltin = "builtin" RefusalLayerLocal = "local" RefusalLayerManaged = "managed" RefusalLayerScope = "scope" RefusalLayerPlatformToolGate = "platform_tool_gate" )
Refusal layers (the closed set the platform accepts).
const ( // RefusedTargetUnresolvable: a host name that does not resolve // (NXDOMAIN, a resolver failure). Its addresses cannot be checked. RefusedTargetUnresolvable = "unresolvable" // RefusedTargetWildcard: a pattern such as "*.example.com", not a host // a policy can check or a tool can reach. RefusedTargetWildcard = "wildcard_pattern" // RefusedTargetDenied: the target (or an address it resolves to) is // outside the local policy's targets or ports, or in the built-in deny // list. RefusedTargetDenied = "denied_by_policy" // RefusedTargetInvalid: the target cannot be read as a URL, host, // address, range or path, or it is unsafe to hand to a tool. RefusedTargetInvalid = "invalid_target" )
Refused-target reasons (the closed set the platform shows).
const ( // MetaRefusedTargets is the list of refused targets ([]RefusedTarget, // at most MaxRefusedTargetsReported entries). MetaRefusedTargets = "refused_targets" // MetaRefusedTargetsTotal is how many targets were refused (also those // the list leaves out). MetaRefusedTargetsTotal = "refused_targets_total" // MetaPartial is true when the command ran on some of its targets only. MetaPartial = "partial" )
Result metadata keys of a command with refused targets.
const ( // EnvScanRoots is a filepath.ListSeparator-separated list (':' on Unix) // of directories filesystem scan targets must live under. EnvScanRoots = "OPENCTEM_SDK_SCAN_ROOTS" // EnvSensorAllowPrivateTargets=1 permits RFC1918 / IPv6 ULA network // targets. It is the one switch for scan targets. EnvSensorAllowPrivateTargets = "SENSOR_ALLOW_PRIVATE_TARGETS" // EnvAllowPrivateTargets is EnvSensorAllowPrivateTargets. // // Deprecated: use EnvSensorAllowPrivateTargets. The separate // OPENCTEM_SDK_ALLOW_PRIVATE_TARGETS switch is gone. EnvAllowPrivateTargets = EnvSensorAllowPrivateTargets )
Environment variables read by DefaultScanTargetPolicy.
const ( MaxSettingsSchemaBytes = settings.MaxSchemaBytes MaxSettingsProperties = settings.MaxProperties MaxSettingsEnum = settings.MaxEnum MaxSettingsPatternLen = settings.MaxPatternLen MaxSettingsStringLen = settings.MaxStringLen MaxSettingsItems = settings.MaxItems )
Limits of a settings schema.
const ( SettingScopeSensor = settings.ScopeSensor SettingScopeScan = settings.ScopeScan SettingSourceDefault = settings.SourceDefault SettingSourceTenant = settings.SourceTenant SettingSourceSensor = settings.SourceSensor SettingSourceProfile = settings.SourceProfile SettingSourceScan = settings.SourceScan SettingSourceJob = settings.SourceJob SettingSourceLocal = settings.SourceLocal )
Setting scopes and sources.
const ( ToolOriginBuiltin = "builtin" ToolOriginAdapter = "adapter" )
Tool origins.
const ( // DefaultToolProbeTTL is how long a probe result is reused: probes run // a tool's version check, too slow for every heartbeat. A tool installed // while the sensor runs shows up within this time (or at Refresh). DefaultToolProbeTTL = 10 * time.Minute // DefaultToolProbeTimeout bounds one probe. DefaultToolProbeTimeout = 30 * time.Second )
Default probe settings.
const CapabilityHostDiscovery = "discover.hosts"
CapabilityHostDiscovery is the host discovery capability id.
const CommandTypeRefreshContent = "refresh_content"
CommandTypeRefreshContent is the command that asks a sensor to refresh its scanner content now (RefreshContentRequest is its payload). A sensor that reports managed content accepts it.
const ConfigReportSchema = 1
ConfigReportSchema is the config report document version this SDK writes.
const DefaultDrainGrace = 30 * time.Second
DefaultDrainGrace is how long a stopping poller lets running commands finish before it cancels them and releases them to the platform.
const ( // DefaultMaxScannerOutput bounds a scanner's captured stdout (its // results) unless ExecConfig.MaxOutputBytes or // BaseScannerConfig.MaxOutputBytes sets another bound. DefaultMaxScannerOutput int64 = 512 << 20 )
Bounds on what the SDK keeps of a scanner's output. A scanner pointed at a hostile target (a site answering every nuclei template with megabytes), or one that loops, must not be able to exhaust the sensor's memory: past the stdout bound the scan is stopped and fails, rather than being read without end or silently truncated into a "clean" result.
const DefaultPerHostConcurrency = 1
DefaultPerHostConcurrency is how many held commands may touch one host when the command does not say (limits.per_host_concurrency).
const DefaultWebhookMaxBodyBytes = 32 << 20
DefaultWebhookMaxBodyBytes bounds one webhook delivery when WebhookCollectorConfig.MaxBodyBytes is not set.
const EnvRequireSignedJobs = "SENSOR_REQUIRE_SIGNED_JOBS"
EnvRequireSignedJobs overrides whether the sensor requires signed jobs: true refuses every command without a valid signature; false runs unsigned commands (a signed one is still verified when a key is pinned). Unset: required when the identity pinned job-signing keys at pairing.
const EnvScannerProxy = "OPENCTEM_SDK_SCANNER_PROXY"
EnvScannerProxy is the SDK setting for the scanner proxy mode: inherit (default) or direct. The OpenCTEM sensor reads SENSOR_SCAN_PROXY instead (sensorkit), which wins over this one.
const ( // HeartbeatRetryDelay is the delay before the next heartbeat after one // that failed (not for a rejected key, which backs off): the heartbeat // is not retried with its stale report, the next one comes sooner. It // is jittered by ±20% so sensors cut off together do not come back in // step. HeartbeatRetryDelay = 10 * time.Second )
Heartbeat timing (api RFC-035 §5.1).
const KillSwitchCheckInterval = 2 * time.Second
KillSwitchCheckInterval is how often a poller with a local policy checks its kill switch file while commands run.
const LocalPolicyPausedMessage = "paused by local policy"
LocalPolicyPausedMessage is the heartbeat message while the sensor owner's kill switch is engaged.
const ManifestSchema = 1
ManifestSchema is the manifest document version this SDK writes.
const MaxConfigReportBytes = 64 << 10
MaxConfigReportBytes is the most a config report may weigh on the wire (the platform answers 413 above it).
const (
// MaxJobExclusions bounds the exclusions one job carries.
MaxJobExclusions = 4096
)
const MaxManifestDescriptorBytes = 128 << 10
MaxManifestDescriptorBytes bounds the tool descriptors one manifest carries in all. The platform caps a manifest document (256 KiB in OpenCTEM); descriptors past the budget are left out, largest first, and the platform keeps planning with those tools by their digest and contract fields.
const MaxProgressRanges = 256
MaxProgressRanges bounds the index ranges one command's progress lists; past it the ranges are left out and only the counts are sent.
const MaxRefusalDetail = 512
MaxRefusalDetail bounds a refusal's detail.
const MaxRefusedTargetsReported = 100
MaxRefusedTargetsReported bounds the refused targets one result lists.
const MaxScanLimit = 1_000_000
MaxScanLimit bounds any value of a scan's rate_limit, bulk_size or concurrency config key. Sensors cap the values far lower (their configured ceilings); this only rejects nonsense early.
const MaxScanTargets = 10000
MaxScanTargets bounds the targets one scan command may carry (the platform's per-run limit).
const MaxSettingsDocumentBytes = 4 << 20
MaxSettingsDocumentBytes bounds a stored settings document.
const MaxTemplateManifestBytes = 256 << 10
MaxTemplateManifestBytes bounds a manifest's payload.
const MaxTemplateNameLength = 128
MaxTemplateNameLength is the maximum allowed length for template names.
const MaxTemplateSize = 1024 * 1024
MaxTemplateSize is the maximum allowed size for a single template (1MB).
const MaxTemplatesPerCommand = 50
MaxTemplatesPerCommand is the maximum number of templates allowed per command.
const MaxToolDescriptorBytes = 64 << 10
MaxToolDescriptorBytes bounds a descriptor in the manifest.
const PropLiveBy = "live_by"
PropLiveBy is the property of a live address that names the probe that answered ("tcp:443", "icmp").
const RefusalRuleJobExclusions = "job_exclusions"
RefusalRuleJobExclusions is the rule of a target the job's own exclusions remove.
const RefusalRuleJobKeySet = "job_keyset"
RefusalRuleJobKeySet is the rule of a signed command refused because the sensor pins a job-signing root and holds no valid key set (none yet, expired, or refused).
const RefusalRuleJobSignature = "job_signature"
RefusalRuleJobSignature is the rule of a command refused for its job signature.
const RefusalRuleScopeLimits = "scope_limits"
RefusalRuleScopeLimits is the refusal of a job whose signed statement limits its targets to some ports or paths, for a scanner or a sandbox that cannot enforce the limits.
const RefusalRuleToolsAllowed = "tools.allowed"
RefusalRuleToolsAllowed is the rule of a command refused by the platform's own tool policy (ErrToolNotAllowed, api RFC-033 §6.12).
const RefusedTargetRuleGuard = "target_guard"
RefusedTargetRuleGuard is the rule of a target the scan-target guard (the built-in network and path checks of ScanTargetPolicy) refused, as opposed to a local policy rule. The platform counts these per task.
const ScannerBetterleaks = "betterleaks"
ScannerBetterleaks is the name of the secret scanner (betterleaks), as the sensor reports it in CTIS tool.name and as the platform dispatches it.
const SettingsDocumentKind = "openctem.sensor.settings/v1"
SettingsDocumentKind is the kind of a settings document.
const SettingsFileName = "tool-settings.json"
SettingsFileName is the file a FileSettingsStore keeps in its directory.
const TemplateManifestKind = "openctem.template-manifest/v1"
TemplateManifestKind is the kind of a template manifest (v1).
const TemplateManifestPayloadType = "application/vnd.openctem.template-manifest+json"
TemplateManifestPayloadType is the DSSE payload type of a template manifest.
Variables ¶
var CVSSPriority = []CVSSSource{ CVSSSourceNVD, CVSSSourceGHSA, CVSSSourceRedHat, CVSSSourceBitnami, }
CVSSPriority defines the priority order for CVSS sources. Higher priority sources are preferred.
var DangerousToolFlags = map[string]bool{}/* 190 elements not displayed */
DangerousToolFlags are scanner CLI flags that must never arrive through ScanOptions.ExtraArgs or ReconOptions.ExtraArgs. Extra args can come from a job payload, so each of these would let whoever controls the payload change what the tool talks to or executes (CWE-77): write files, route traffic through their proxy (SSRF/MITM), name targets that skipped target validation, load their own templates or rules (nuclei code: protocol = RCE), call back to their interaction server, run a headless browser, use their DNS resolvers, or bind to another interface or source address.
The sensor's platform-mode executor enforced this set until that mode was removed (sensor#107); it now lives here so every SDK scanner applies it.
var DefaultScannerPriority = ScannerPriority{Nice: 10, IOLevel: 7, OOMScoreAdj: 500}
DefaultScannerPriority is the priority sensorkit gives scanners: nice +10, lowest best-effort I/O, and an OOM score well above the sensor's.
var ErrConfigReportUnsupported = errors.New("the platform does not accept sensor config reports")
ErrConfigReportUnsupported is returned by ConfigReportPusher.PutConfigReport when the platform does not take config reports (no "config_report" on hello). The sensor then sends none.
var ErrInvalidRefreshContent = errors.New("invalid refresh_content payload")
ErrInvalidRefreshContent is returned for a malformed refresh_content payload.
var ErrManifestNotRegistered = errors.New("the platform has no manifest for this sensor")
ErrManifestNotRegistered: the platform has no manifest for this sensor.
var ErrManifestUnsupported = errors.New("the platform does not accept sensor manifests")
ErrManifestUnsupported is returned by ManifestPusher.PutManifest when the platform does not serve manifests (no "manifest" on hello). The sensor then keeps reporting only on its heartbeat, as before.
var ErrNoProbePorts = fmt.Errorf("the host discovery job names no probe ports (param ports)")
ErrNoProbePorts: a host discovery job that names no probe ports. The platform sends them with every such job; a tool never guesses them.
var ErrNoTemplateKeys = errors.New("custom templates are refused: no template-signing key is pinned on this sensor (SENSOR_TEMPLATE_SIGNING_KEYS)")
ErrNoTemplateKeys is returned when a command carries custom templates and the sensor has no template-signing key to check them with.
var ErrNotRun = errors.New("command not run")
ErrNotRun is the error of a claimed command RunClaimed did not run (it was released back to the platform).
var ErrRefusedByLocalPolicy = errors.New("refused by local policy")
ErrRefusedByLocalPolicy is the error every refusal by the local policy wraps (see LocalPolicyError).
var ErrScannerOutputTooLarge = errors.New("scanner output exceeded the size limit")
ErrScannerOutputTooLarge reports a scanner stopped because its output exceeded the bound on captured output.
var ErrSettingsVersionNotNewer = errors.New("settings document is not newer than the stored one")
ErrSettingsVersionNotNewer is returned by SettingsStore.Save for a document whose version is not above the stored one: settings only move forward, so a replayed or reordered older document is refused.
var ErrStoppedByPlatform = errors.New("stopped by the platform (the task stalled); delivering what it finished")
ErrStoppedByPlatform is the cause a held command's context is canceled with when the platform asks the sensor to stop it and deliver what it finished (stop_command_ids: the task stalled). Unlike a cancel, the run's settled targets are delivered and the command completes partial with the rest unfinished; the platform runs only those again.
var ErrTemplatesUnsigned = errors.New("custom templates are not signed by the platform")
ErrTemplatesUnsigned is returned for custom templates without a signed manifest.
var ErrToolNotAllowed = errors.New("tool-not-allowed")
ErrToolNotAllowed is the error of a command refused because its tool is outside the platform's policy (api RFC-033 §6.12). The command is reported failed with it, never run.
var LocalPolicySchemas = []string{"v1", "v2", "v3"}
LocalPolicySchemas are the local policy schema versions this SDK reads, as LocalPolicyReport.Schemas reports them: the platform generates a recommended policy only in a version the sensor lists, so a downloaded file never stops a sensor.
var PresetScanners = map[string]*BaseScannerConfig{ "semgrep": { Name: "semgrep", Binary: "semgrep", DefaultArgs: []string{"scan", "--sarif", "--config", "auto", "{target}"}, Timeout: 30 * time.Minute, OKExitCodes: []int{0, 1}, Capabilities: []string{"sast", "secret"}, }, "trivy-fs": { Name: "trivy", Binary: "trivy", DefaultArgs: []string{"fs", "--format", "sarif", "{target}"}, Timeout: 15 * time.Minute, OKExitCodes: []int{0}, Capabilities: []string{"sca", "vulnerability"}, }, "trivy-config": { Name: "trivy", Binary: "trivy", DefaultArgs: []string{"config", "--format", "sarif", "{target}"}, Timeout: 15 * time.Minute, OKExitCodes: []int{0}, Capabilities: []string{"iac", "misconfiguration"}, }, "betterleaks": { Name: "betterleaks", Binary: "betterleaks", DefaultArgs: []string{"dir", "{target}", "--report-format", "sarif", "--report-path", "-", "--exit-code", "0", "--no-banner"}, Timeout: 15 * time.Minute, OKExitCodes: []int{0, 1}, Capabilities: []string{"secret"}, }, "slither": { Name: "slither", Binary: "slither", DefaultArgs: []string{"{target}", "--sarif", "/dev/stdout"}, Timeout: 30 * time.Minute, OKExitCodes: []int{0, 1, 255}, Capabilities: []string{"web3", "smart-contract"}, }, "checkov": { Name: "checkov", Binary: "checkov", DefaultArgs: []string{"-d", "{target}", "-o", "sarif", "--output-file-path", "/dev/stdout"}, Timeout: 15 * time.Minute, OKExitCodes: []int{0, 1}, Capabilities: []string{"iac", "misconfiguration"}, }, "bandit": { Name: "bandit", Binary: "bandit", DefaultArgs: []string{"-r", "{target}", "-f", "sarif", "-o", "/dev/stdout"}, Timeout: 15 * time.Minute, OKExitCodes: []int{0, 1}, Capabilities: []string{"sast"}, }, "gosec": { Name: "gosec", Binary: "gosec", DefaultArgs: []string{"-fmt", "sarif", "-out", "/dev/stdout", "{target}/..."}, Timeout: 15 * time.Minute, OKExitCodes: []int{0, 1}, Capabilities: []string{"sast"}, }, "snyk": { Name: "snyk", Binary: "snyk", DefaultArgs: []string{"code", "test", "{target}", "--sarif"}, Timeout: 30 * time.Minute, OKExitCodes: []int{0, 1}, Capabilities: []string{"sast", "sca"}, }, "codeql": { Name: "codeql", Binary: "codeql", DefaultArgs: []string{"database", "analyze", "{target}", "--format=sarif-latest", "--output=/dev/stdout"}, Timeout: 60 * time.Minute, OKExitCodes: []int{0}, Capabilities: []string{"sast"}, }, }
PresetScanners contains configurations for popular security tools.
var RateLimitToolFlags = map[string]bool{ "-rl": true, "-rate-limit": true, "-rld": true, "-rate-limit-duration": true, "-per-host-rate-limit": true, "-rlm": true, "-rate-limit-minute": true, "-bs": true, "-bulk-size": true, "-concurrency": true, "-hbs": true, "-headless-bulk-size": true, "-headc": true, "-headless-concurrency": true, "-jsc": true, "-js-concurrency": true, "-payload-concurrency": true, "-prc": true, "-probe-concurrency": true, "-rate": true, "-rls": true, "-threads": true, "-parallelism": true, }
RateLimitToolFlags are scanner CLI flags that set how hard a tool hits its targets (requests per second, hosts or templates in parallel). They never arrive through extra args: a scan asks for lower limits with the typed ScanOptions.RateLimit / BulkSize / Concurrency, and the sensor caps those at the ceilings its operator configured. A free-form "-rate-limit 100000" (or "-per-host-rate-limit", which lifts nuclei's global limit) would get around the ceiling.
var ScanLimitKeys = []string{"rate_limit", "bulk_size", "concurrency"}
ScanLimitKeys are the scan-command config keys the executor reads into ScanOptions.RateLimit, BulkSize and Concurrency.
var ValidTemplateTypes = map[string]bool{ "nuclei": true, "semgrep": true, ScannerBetterleaks: true, }
ValidTemplateTypes defines allowed template types for security validation. A retired type ("gitleaks") is accepted through CanonicalScannerName.
Functions ¶
func APIKeyHint ¶ added in v0.8.0
APIKeyHint returns the non-secret prefix of an API key for log lines: at most 8 characters (e.g. "rda_" and 4 more) and never more than half of the key, followed by an ellipsis.
func ApplyScannerPriority ¶ added in v0.15.0
ApplyScannerPriority lowers a started scanner's priority as SetScannerPriority says: its process group's CPU and I/O priority, and the OOM score of its leader. Call right after Start (the SDK's exec helpers do); a scanner configured with ConfigureScannerProcess leads its own process group, so processes it already forked are covered too. Best effort: a refused change is ignored and the scanner runs as it is.
A scanner never keeps a negative OOM score inherited from a sensor that is protected from the OOM killer (sensorkit's SENSOR_PROTECT_FROM_OOM, or systemd's OOMScoreAdjust): with no priority set it is raised to 0, so the kernel still kills a scanner before the sensor. Raising a score needs no privilege.
func AuthFailureAdvice ¶ added in v0.8.0
AuthFailureAdvice explains a rejected request (AuthFailureStatus(err) != 0) in one actionable sentence: the HTTP status, the key's non-secret prefix (keyHint, see APIKeyHint) and what to do. A 401 saying "API key required" although the sensor sent its key means the key never reached the API: SENSOR_API_URL points at the web UI, or at a proxy that strips the Authorization header, rather than at the API.
func AuthFailureStatus ¶ added in v0.8.0
AuthFailureStatus returns the HTTP status (401 or 403) when err, or an error it wraps, says the platform rejected the sensor's credentials, and 0 otherwise.
func CanonicalScannerName ¶ added in v0.8.0
CanonicalScannerName returns the current name for a scanner or template type: a retired name maps to its replacement, anything else is returned unchanged.
func CapScanLimit ¶ added in v0.17.0
CapScanLimit returns the limit a scanner runs with: requested when set (above 0), else own (the scanner's setting), and never above ceiling when one is set (above 0); with a ceiling and nothing else set, the ceiling. Scanners use it so a scan can ask for any limit up to the sensor's ceiling and never past it.
func CheckBinaryInstalled ¶
func CheckBinaryInstalled(ctx context.Context, binary string, versionArgs ...string) (bool, string, error)
CheckBinaryInstalled checks if a binary is installed and returns its version line: the first non-empty line of VersionOutput. Scanners whose version command prints several lines (nuclei, the ProjectDiscovery tools) should call VersionOutput and parse the whole text instead.
func CheckEnv ¶ added in v0.7.0
func CheckEnv() error
CheckEnv reports a configuration error in the environment variables the default scan target policy reads: an allow-private switch set to anything but "1" (allow) or "0"/empty (refuse). Only "1" enables the switch, so "true" or "yes" would otherwise be silently ignored and every private target refused. It also reports an unrecognized OPENCTEM_SDK_SCANNER_PROXY (EnvScannerProxy). A sensor calls it at startup to refuse to start instead of failing jobs later.
func CommandIDFromContext ¶ added in v0.8.0
CommandIDFromContext returns the command id set by WithCommandID, or "".
func ConfigHealthOf ¶ added in v0.18.0
func ConfigHealthOf(checks []ConfigCheck) string
ConfigHealthOf is the rollup: blocked (a failure that blocks everything), impaired (any other failure or a check that could not run), attention (a warning of severity warning or critical), else ok.
func ConfigureScannerProcess ¶ added in v0.10.0
ConfigureScannerProcess makes a scanner command safe to cancel: it runs in its own process group, a canceled context kills the WHOLE group (a wrapper script's children too, not only the direct child), and on Linux the scanner is killed if the sensor dies. Call before Start; right after Start, call ApplyScannerPriority; after Wait, call ReapScannerProcess. The SDK's exec helpers do all three. No-op on systems without process groups.
func ContentEnviron ¶ added in v0.15.0
ContentEnviron is ScannerEnviron for a process that downloads scanner content (trivy's database, template or rule updates): its proxy variables follow the content proxy (httpsec.ContentProxy) instead of the scanner proxy mode.
- environment: the sensor's proxy variables, as they are;
- direct: none;
- a URL: HTTP_PROXY, HTTPS_PROXY and ALL_PROXY (both spellings) set to it, and NO_PROXY to the setting's bypass list.
func CoverageGapsMetadata ¶ added in v0.21.0
func CoverageGapsMetadata(r *ScanResult) map[string]any
CoverageGapsMetadata returns the result metadata for r's coverage gaps and rate summary (nil when there is neither).
func DSSEPreAuthEncoding ¶ added in v0.17.0
DSSEPreAuthEncoding is DSSE v1's PAE: "DSSEv1 <len(type)> <type> <len(body)> <body>", lengths in ASCII decimal.
func DetectRuntime ¶ added in v0.18.0
func DetectRuntime() string
DetectRuntime says how this process runs: kubernetes, docker (any container engine), systemd, else binary.
func GenerateSastFingerprint ¶
GenerateSastFingerprint creates a fingerprint for SAST/Secret findings. Deprecated: Use fingerprint.GenerateSAST from pkg/shared/fingerprint instead.
func GenerateScaFingerprint ¶
GenerateScaFingerprint creates a fingerprint for SCA vulnerabilities. Deprecated: Use fingerprint.GenerateSCA from pkg/shared/fingerprint instead.
func GenerateSecretFingerprint ¶
GenerateSecretFingerprint creates a fingerprint for secret findings.
secretValue may be the raw secret: it is masked with MaskSecret before it goes into the fingerprint, so the fingerprint never carries a hash of the secret itself. An unsalted hash of a short secret can be reversed by brute force; a hash of the masked value reveals no more than the masked value does (CTIS spec 5.2: the secret input is the masked value or a keyed hash). Callers of fingerprint.GenerateSecret directly must do the same.
func HostKey
deprecated
added in
v0.10.0
HostKey is the politeness key of a scan target: the host of a URL, a service or an address, "host/owner" of a repository, the path of a local directory (politeness.HostOf).
Deprecated: use github.com/openctemio/ctis/politeness, the one definition the platform uses too (HostOf, Keys).
func HostOS ¶ added in v0.10.0
func HostOS() string
HostOS and HostArch are the operating system and architecture the sensor reports (runtime.GOOS, runtime.GOARCH).
func IsCodeScanner ¶ added in v0.33.0
IsCodeScanner reports whether scanner takes a filesystem path target.
func KeyBoundHint ¶ added in v0.18.0
KeyBoundHint names a key-bound sensor's signing key in log lines by the start of its public thumbprint (nothing secret).
func ListPresetScanners ¶
func ListPresetScanners() []string
ListPresetScanners returns all available preset scanner names.
func LiveHostsReport ¶ added in v0.26.0
LiveHostsReport turns a port probe's report into a host discovery report in place: every ip_address with an answering port is kept as a live address, with the first answering port in properties.live_by ("tcp:<port>"); everything else (a host name, an address without an answering port) is dropped, because host discovery reports addresses only. targets, when not empty, also drops an address that is none of the job's targets nor inside one of its ranges: a tool never reports a host it was not given.
func MaskAPIKey ¶
MaskAPIKey masks an API key for logs. It shows as many characters as MaskSecret does: none below 12 characters, at most a quarter in total.
func MaskSecret ¶
MaskSecret masks a secret value for display and for use as a fingerprint input (CTIS spec 4.8 and 5.2). It never shows more than a quarter of the secret, at most 4 characters at either end, and nothing at all of a secret shorter than 12 characters:
MaskSecret("not-a-real-1") == "no****1"
MaskSecret("short-one") == "****"
MaskSecret("fake_tok_0123456789abcdefghijklmn") == "fake****klmn"
Characters are counted as runes, so a multi-byte character is never cut.
func MaskSecretInText ¶ added in v0.7.0
MaskSecretInText returns text with every occurrence of secret replaced by MaskSecret(secret). It is for context strings such as a scanner's matched line, which embed the raw secret.
It fails safe: when secret is empty or does not occur in text (the scanner trimmed or re-encoded it), the whole text is replaced by the mask marker, because no part of the text can be shown to be free of the secret.
func NormalizeSeverity ¶
NormalizeSeverity normalizes severity strings from different scanners. Deprecated: Use severity.FromString from pkg/shared/severity instead.
func NowRFC3339 ¶ added in v0.18.0
func NowRFC3339() string
NowRFC3339 is the report timestamp format.
func PlanWaves ¶ added in v0.33.0
PlanWaves cuts targets into at most maxWaves waves of whole hosts (politeness.Group in network): every target of one host is in one wave, so a wave that ends frees its hosts completely. Waves are balanced by target count (the largest host first, into the smallest wave), keep the targets' order inside each wave and are ordered by their first target. maxWaves < 1 is 1; fewer hosts than maxWaves give one wave per host. Nil for no targets.
func PlatformTLSPin ¶ added in v0.19.0
func PlatformTLSPin() string
PlatformTLSPin is the platform TLS pin of API clients created now: TLSPinFingerprint when a CA fingerprint or an anchor key is pinned (httpsec.SetAPIPinnedCA, httpsec.SetAPIPinnedSPKI), TLSPinCAFile when only a private CA pool is set (httpsec.SetAPIRootCAs), else TLSPinNone.
func ProcessInstanceID ¶ added in v0.12.0
func ProcessInstanceID() string
ProcessInstanceID returns the random id this process picked when it first asked: 32 hex characters, the same for the life of the process, different on every start. Heartbeats carry it as "instance_id" so the platform can tell a restart (the id changes once) from one key running in two places (two ids alternate), and flag a copied or shared key (api RFC-032 Phase 0). It identifies a process, not a host or a sensor, and carries no secret.
func ReapScannerProcess ¶ added in v0.10.0
ReapScannerProcess kills what is left of a finished scanner's process group (background children it did not wait for), so nothing outlives the command (api RFC-030 §5.4). Safe to call on any command that was started.
func RecordOutput ¶ added in v0.28.0
RecordOutput counts records of the job's tool output in its Progress (no-op outside a job).
func RecordProcessState ¶ added in v0.10.0
func RecordProcessState(ctx context.Context, ps *os.ProcessState)
RecordProcessState adds a finished process's CPU time and peak memory to the command running in ctx, for the per-tool cost history the sensor reports (capacity.per_tool). The SDK's exec helpers call it; an executor that starts processes itself should call it after Wait. No-op outside a command or with a nil state.
func RefusedTargetsMetadata ¶ added in v0.19.0
func RefusedTargetsMetadata(refused []RefusedTarget) map[string]any
RefusedTargetsMetadata returns the result metadata for refused (nil when none): the bounded list, the total and the partial flag.
func RequireLocalPolicyFromEnv ¶ added in v0.19.0
RequireLocalPolicyFromEnv reads EnvRequireLocalPolicy: set reports whether it is set (to anything but blanks), required its value. A value that is not a boolean is an error: the sensor must not guess its posture.
func RequireSignedJobsFromEnv ¶ added in v0.19.0
RequireSignedJobsFromEnv reads EnvRequireSignedJobs: set reports whether it is set; an unrecognized value is an error.
func RunWaves ¶ added in v0.33.0
func RunWaves(ctx context.Context, targets []string, network string, maxWaves int, fn func(ctx context.Context, wave []string) error, done func(target string), ) error
RunWaves runs fn once per wave of targets (PlanWaves), one wave after the other, and calls done for every target of a wave whose run returned nil, at once, so the wave's hosts are freed while later waves run. A nil done marks the target done in the job's Progress (TargetDone); a tool run out of process passes its tool context's TargetDone. fn should deliver the wave's results before it returns: a settled target is not run again. It stops at the first error, or when ctx ends, and returns it; the targets of the failed wave and of the waves not run are not marked done, so they stay unfinished (and are sent again) rather than settled without results.
func ScannerEnviron ¶ added in v0.7.0
ScannerEnviron returns the environment for a scanner child process: the allowlisted subset of the current environment followed by extra (which wins on conflict because later entries take precedence in exec).
func ScannerEnvironFor ¶ added in v0.19.0
ScannerEnvironFor is ScannerEnviron for one tool: a vendor namespace (TRIVY_*, SEMGREP_*, PDCP_*, the container runtime variables, ...) is passed only to the tool it belongs to. tool is the bundled tool's name; "" is a program the operator installed, which gets no vendor namespace. The variables in extra, and those the operator allows by name (OPENCTEM_SDK_SCANNER_ENV_ALLOW, SetScannerEnvAllowlist) or by inheriting the whole environment, are passed as ScannerEnviron passes them.
func ScannerProxySummary ¶ added in v0.15.0
func ScannerProxySummary() string
ScannerProxySummary describes what scanner processes get, for the start-up log, without credentials: "inherit (HTTPS_PROXY=http://proxy:3128)", "inherit (no proxy variables set)" or "direct".
func SetDefaultLogger ¶
func SetDefaultLogger(logger Logger)
SetDefaultLogger sets the global default logger.
func SetJobsKeySet ¶ added in v0.19.0
func SetJobsKeySet(t *jobsig.KeySetTrust)
SetJobsKeySet sets the key set trust whose root, version and expiry CurrentPosture reports; nil reports none.
func SetJobsPosture ¶ added in v0.19.0
func SetJobsPosture(signed string)
SetJobsPosture sets the JobsSigned* posture CurrentPosture reports; "" reports none.
func SetScannerEnvAllowlist ¶ added in v0.7.0
func SetScannerEnvAllowlist(names []string)
SetScannerEnvAllowlist adds variable names to the scanner environment allowlist, replacing any previous call's list (the env var list is replaced too). A name ending in '*' is treated as a prefix.
func SetScannerInheritEnv ¶ added in v0.7.0
func SetScannerInheritEnv(inherit bool)
SetScannerInheritEnv makes scanner processes inherit the full sensor environment when inherit is true (the pre-hardening behavior). Only for setups where a scanner needs variables that cannot be enumerated.
func SetScannerPriority ¶ added in v0.15.0
func SetScannerPriority(p *ScannerPriority)
SetScannerPriority sets the priority every scanner process the SDK starts gets from now on (ExecuteScanner, StreamScanner, BaseScanner). nil, the default, leaves scanners at the sensor's own priority. sensorkit sets DefaultScannerPriority unless SENSOR_SCANNER_PRIORITY=normal.
func SetScannerProxyMode ¶ added in v0.15.0
func SetScannerProxyMode(m ScannerProxyMode)
SetScannerProxyMode sets the scanner proxy mode of every scanner process started afterwards. An unknown mode is treated as inherit.
func SettingsDigest ¶ added in v0.16.0
SettingsDigest is the canonical digest of a values document.
func SeverityFromCVSS ¶
SeverityFromCVSS converts a CVSS score to severity level. Deprecated: Use severity.FromCVSS from pkg/shared/severity instead.
func TargetDone ¶ added in v0.26.0
TargetDone marks target finished in the job's Progress (no-op outside a job). A scanner that runs its targets itself calls it as each finishes.
func TargetOutcomes ¶ added in v0.28.0
TargetOutcomes returns one outcome per target the scanner ran over, in order, from a completed scan's report (nil: the run reported nothing on its targets). A target nothing marks is done: the scan ran over it. Values of the report are the tool's, read as hints and bounded by the targets.
func TemplateKeyID ¶ added in v0.17.0
TemplateKeyID names a template-signing public key: the first 16 hex characters of its SHA-256.
func TrackProcess ¶ added in v0.28.0
TrackProcess adds a tool process to the job's CPU time in its Progress (no-op outside a job).
func ValidateBaseScannerConfig ¶
func ValidateBaseScannerConfig(cfg *BaseScannerConfig) error
ValidateBaseScannerConfig validates a BaseScannerConfig.
func ValidateBaseSensorConfig ¶ added in v0.7.0
func ValidateBaseSensorConfig(cfg *BaseSensorConfig) error
ValidateBaseSensorConfig validates a BaseSensorConfig.
func ValidateCommandPollerConfig ¶
func ValidateCommandPollerConfig(cfg *CommandPollerConfig) error
ValidateCommandPollerConfig validates a CommandPollerConfig.
func ValidateExtraArgs ¶ added in v0.15.0
ValidateExtraArgs rejects extra CLI args that contain a DangerousToolFlags or RateLimitToolFlags entry, either bare ("-proxy") or in "flag=value" form ("-proxy=http://x"). Matching is case-insensitive, ignores surrounding whitespace and ignores how many dashes the flag has: Go's flag package (nuclei, httpx, katana, subfinder, dnsx, naabu) accepts "-proxy" and "--proxy" alike, so an entry listed as "-proxy" also blocks "--proxy" and "---proxy", and "--config" also blocks "-config".
func ValidateScanOptions ¶
func ValidateScanOptions(opts *ScanOptions) error
ValidateScanOptions validates ScanOptions.
func ValidateTemplate ¶
func ValidateTemplate(tpl *EmbeddedTemplate) error
ValidateTemplate validates an embedded template for security issues. It checks for path traversal, valid template types, and size limits.
func VersionAfterLabel ¶ added in v0.13.0
VersionAfterLabel returns the first word after `label` on the first line of output that contains it, or "" when no line does. For example VersionAfterLabel("[INF] Nuclei Engine Version: v3.11.1", "Engine Version:") returns "v3.11.1".
func VersionOutput ¶ added in v0.13.0
VersionOutput runs `binary versionArgs...` (default "--version") and returns its whole output with ANSI color sequences removed. It reads stdout, and stderr when stdout is empty: several scanners (nuclei and the other ProjectDiscovery tools) print their version banner only to stderr, in color. A binary that cannot be started or exits non-zero is reported as not installed.
func WithCommandID ¶ added in v0.8.0
WithCommandID returns a context that says the work done under it belongs to the platform command cmdID. The CommandPoller sets it around every command, so a Pusher can bind the results it pushes to that command (protocol v2's command-bound resource) and report the command only after them.
Types ¶
type APIKeyHinter ¶ added in v0.8.0
type APIKeyHinter interface {
APIKeyHint() string
}
APIKeyHinter is implemented by a Pusher that can name its API key in log lines without revealing it (*client.Client does).
type ASN ¶ added in v0.18.0
type ASN struct {
Number string `json:"number,omitempty"` // "AS13335"
Org string `json:"org,omitempty"` // Holder name
Country string `json:"country,omitempty"` // ISO 3166-1 alpha-2
}
ASN is an autonomous system.
type Adapter ¶
type Adapter interface {
// Name returns the adapter name (e.g., "sarif", "cyclonedx")
Name() string
// InputFormats returns supported input formats
InputFormats() []string
// OutputFormat returns the output format (usually "ctis")
OutputFormat() string
// CanConvert checks if the input can be converted
CanConvert(input []byte) bool
// Convert transforms input to CTIS Report
Convert(ctx context.Context, input []byte, opts *AdapterOptions) (*ctis.Report, error)
}
Adapter translates between different data formats and CTIS.
type AdapterOptions ¶
type AdapterOptions struct {
// Source information
SourceName string `yaml:"source_name" json:"source_name"`
SourceType string `yaml:"source_type" json:"source_type"`
// Target repository/asset info
Repository string `yaml:"repository" json:"repository"`
Branch string `yaml:"branch" json:"branch"`
CommitSHA string `yaml:"commit_sha" json:"commit_sha"`
// Filtering
MinSeverity string `yaml:"min_severity" json:"min_severity"`
// Debug
Verbose bool `yaml:"verbose" json:"verbose"`
}
AdapterOptions configures adapter behavior.
type AssetResolver ¶ added in v0.7.0
AssetResolver returns the asset a scan of target (already validated) should report its findings on, or an empty value to let the parser decide.
type AuthGate ¶ added in v0.8.0
type AuthGate struct {
// contains filtered or unexported fields
}
AuthGate tracks whether the platform accepts the sensor's heartbeats. The heartbeat loop reports every outcome to it (Observe). While the key is rejected the gate turns the heartbeat interval into a capped exponential backoff and tells the command poller to stop polling (Rejected); the first accepted heartbeat lifts it. It logs without verbose mode, but only once per backoff step or change of state, never once per request. Safe for concurrent use.
func NewAuthGate ¶ added in v0.8.0
func NewAuthGate(cfg *AuthGateConfig) *AuthGate
NewAuthGate creates an AuthGate. A nil config uses the defaults.
func (*AuthGate) MarkRejected ¶ added in v0.8.0
MarkRejected records an authentication failure seen outside the heartbeat (a command poll). It stops polling until the next accepted heartbeat but leaves the backoff to the heartbeat loop. It logs only on the change of state.
func (*AuthGate) Observe ¶ added in v0.8.0
Observe records the outcome of one heartbeat (or, for a poller without a heartbeat to share a gate with, one poll). keyHint names the key in the log line (see APIKeyHint). It returns the delay before the next heartbeat when the gate overrides the normal interval (a rejected key), or 0 when the caller keeps its own interval.
type AuthGateConfig ¶ added in v0.8.0
type AuthGateConfig struct {
// BackoffBase is the first re-check delay after a rejection.
BackoffBase time.Duration
// BackoffMax caps the re-check delay.
BackoffMax time.Duration
// Logger receives the state changes. Nil logs to stderr with timestamps.
Logger *log.Logger
}
AuthGateConfig configures an AuthGate. Zero values use the defaults.
type BaseCollector ¶
type BaseCollector struct {
// contains filtered or unexported fields
}
BaseCollector provides a base implementation for collectors. Embed this in your custom collector to get common functionality.
func NewBaseCollector ¶
func NewBaseCollector(cfg *BaseCollectorConfig) *BaseCollector
NewBaseCollector creates a new base collector.
func (*BaseCollector) Collect ¶
func (c *BaseCollector) Collect(ctx context.Context, opts *CollectOptions) (*CollectResult, error)
Collect is the base collect method - override in your implementation.
func (*BaseCollector) FetchJSON ¶
func (c *BaseCollector) FetchJSON(ctx context.Context, path string, query map[string]string, result interface{}) error
FetchJSON makes an HTTP GET request and decodes JSON response.
func (*BaseCollector) SetVerbose ¶
func (c *BaseCollector) SetVerbose(v bool)
SetVerbose sets verbose mode.
func (*BaseCollector) TestConnection ¶
func (c *BaseCollector) TestConnection(ctx context.Context) error
TestConnection tests the connection to the source.
type BaseCollectorConfig ¶
type BaseCollectorConfig struct {
Name string `yaml:"name" json:"name"`
SourceType string `yaml:"source_type" json:"source_type"`
BaseURL string `yaml:"base_url" json:"base_url"`
APIKey string `yaml:"api_key" json:"api_key"`
Headers map[string]string `yaml:"headers" json:"headers"`
Timeout time.Duration `yaml:"timeout" json:"timeout"`
Verbose bool `yaml:"verbose" json:"verbose"`
}
BaseCollectorConfig configures a BaseCollector.
type BaseParser ¶
type BaseParser struct {
// contains filtered or unexported fields
}
BaseParser provides a base implementation for custom parsers. Embed this in your custom parser for common functionality.
func NewBaseParser ¶
func NewBaseParser(name string, formats []string) *BaseParser
NewBaseParser creates a new base parser.
func (*BaseParser) CanParse ¶
func (p *BaseParser) CanParse(data []byte) bool
CanParse default implementation - override in your parser.
func (*BaseParser) CreateFinding ¶
CreateFinding is a helper to create a finding with common fields set.
func (*BaseParser) CreateReport ¶
func (p *BaseParser) CreateReport(toolName, toolVersion string) *ctis.Report
CreateReport is a helper to create a new report.
func (*BaseParser) Parse ¶
func (p *BaseParser) Parse(ctx context.Context, data []byte, opts *ParseOptions) (*ctis.Report, error)
Parse default implementation - override in your parser.
func (*BaseParser) SupportedFormats ¶
func (p *BaseParser) SupportedFormats() []string
SupportedFormats returns supported formats.
type BaseProcessor ¶
type BaseProcessor struct {
// contains filtered or unexported fields
}
BaseProcessor provides a default implementation of the Processor interface.
func NewBaseProcessor ¶
func NewBaseProcessor(pusher Pusher) *BaseProcessor
NewBaseProcessor creates a new processor.
func (*BaseProcessor) AddParser ¶
func (p *BaseProcessor) AddParser(parser Parser)
AddParser adds a custom parser.
func (*BaseProcessor) Process ¶
func (p *BaseProcessor) Process(ctx context.Context, scanner Scanner, opts *ProcessOptions) (*ProcessResult, error)
Process runs a complete scan workflow: scan -> parse -> push.
func (*BaseProcessor) ProcessBatch ¶
func (p *BaseProcessor) ProcessBatch(ctx context.Context, scanners []Scanner, opts *ProcessOptions) ([]*ProcessResult, error)
ProcessBatch runs multiple scanners in parallel.
func (*BaseProcessor) SetVerbose ¶
func (p *BaseProcessor) SetVerbose(v bool)
SetVerbose sets verbose mode.
type BaseScanner ¶
type BaseScanner struct {
// contains filtered or unexported fields
}
BaseScanner provides a base implementation for scanners. Embed this in your custom scanner to get common functionality.
func NewBaseScanner ¶
func NewBaseScanner(cfg *BaseScannerConfig) *BaseScanner
NewBaseScanner creates a new base scanner with the given config.
func NewPresetScanner ¶
func NewPresetScanner(name string) (*BaseScanner, error)
NewPresetScanner creates a scanner from a preset configuration.
func (*BaseScanner) BuildArgs ¶
func (s *BaseScanner) BuildArgs(target string, opts *ScanOptions) []string
BuildArgs builds command arguments. Override this in your scanner for custom argument handling.
func (*BaseScanner) Capabilities ¶
func (s *BaseScanner) Capabilities() []string
Capabilities returns what the scanner can detect.
func (*BaseScanner) IsInstalled ¶
IsInstalled checks if the scanner binary is available.
func (*BaseScanner) Scan ¶
func (s *BaseScanner) Scan(ctx context.Context, target string, opts *ScanOptions) (*ScanResult, error)
Scan executes the scanner with the given options. This is the base implementation - override BuildArgs in your scanner for customization.
func (*BaseScanner) SetVerbose ¶
func (s *BaseScanner) SetVerbose(v bool)
SetVerbose sets verbose mode.
func (*BaseScanner) Version ¶
func (s *BaseScanner) Version() string
Version returns the scanner version.
type BaseScannerConfig ¶
type BaseScannerConfig struct {
Name string `yaml:"name" json:"name"`
Version string `yaml:"version" json:"version"`
Binary string `yaml:"binary" json:"binary"`
DefaultArgs []string `yaml:"default_args" json:"default_args"`
Timeout time.Duration `yaml:"timeout" json:"timeout"`
OKExitCodes []int `yaml:"ok_exit_codes" json:"ok_exit_codes"`
Capabilities []string `yaml:"capabilities" json:"capabilities"`
WorkDir string `yaml:"work_dir" json:"work_dir"`
Env map[string]string `yaml:"env" json:"env"`
Verbose bool `yaml:"verbose" json:"verbose"`
// MaxOutputBytes bounds the captured stdout; 0 means
// DefaultMaxScannerOutput. A scanner that writes more is stopped and
// Scan returns ErrScannerOutputTooLarge.
MaxOutputBytes int64 `yaml:"max_output_bytes" json:"max_output_bytes"`
}
BaseScannerConfig configures a BaseScanner.
type BaseSensor ¶ added in v0.7.0
type BaseSensor struct {
// contains filtered or unexported fields
}
BaseSensor provides a base implementation for sensors. Embed this in your custom sensor to get common functionality.
func NewBaseSensor ¶ added in v0.7.0
func NewBaseSensor(cfg *BaseSensorConfig, pusher Pusher) *BaseSensor
NewBaseSensor creates a new base sensor.
func (*BaseSensor) AddCollector ¶ added in v0.7.0
func (a *BaseSensor) AddCollector(collector Collector) error
AddCollector adds a collector to the sensor.
func (*BaseSensor) AddParser ¶ added in v0.7.0
func (a *BaseSensor) AddParser(parser Parser)
AddParser adds a custom parser to the sensor.
func (*BaseSensor) AddScanner ¶ added in v0.7.0
func (a *BaseSensor) AddScanner(scanner Scanner) error
AddScanner adds a scanner to the sensor.
func (*BaseSensor) AuthGate ¶ added in v0.8.0
func (a *BaseSensor) AuthGate() *AuthGate
AuthGate returns the gate that tracks whether the platform accepts this sensor's heartbeats. Share it with a CommandPoller (SetAuthGate) so the poller stops polling while the key is rejected; a poller sharing the sensor's doorbell gets it automatically.
func (*BaseSensor) CommandToolGate ¶ added in v0.15.0
func (a *BaseSensor) CommandToolGate() func(*Command) error
CommandToolGate returns the check the command poller runs before it executes a command (CommandPoller.SetCommandGate): a command that names a tool (payload "scanner", else "preferred_tool", as the platform's tool gate reads it) outside the platform's policy is refused with ErrToolNotAllowed (owner decision O2). Commands that name no tool, and any command before the platform said a policy, pass.
func (*BaseSensor) FirstHeartbeat ¶ added in v0.8.0
FirstHeartbeat sends the sensor's first heartbeat now, before Start, and returns the delay before the next one and the heartbeat's error. It is the daemon's connection check: it goes through the doorbell and the AuthGate exactly like the heartbeat loop, so a rejected key is logged and backed off the same way (AuthFailureStatus(err) != 0; wait the returned delay before trying again). The next Start does not send another heartbeat at once: its first one follows the returned delay. Without this, a daemon that checked the connection with Pusher.TestConnection sent two heartbeats back to back.
func (*BaseSensor) ManifestPolicy ¶ added in v0.15.0
func (a *BaseSensor) ManifestPolicy() *ManifestPolicy
ManifestPolicy returns the platform's policy for this sensor (api RFC-033 §6.12), nil until the platform said it.
func (*BaseSensor) Name ¶ added in v0.7.0
func (a *BaseSensor) Name() string
Name returns the sensor name.
func (*BaseSensor) Posture ¶ added in v0.19.0
func (a *BaseSensor) Posture() *SensorPosture
Posture is what SetPosture set (nil: none).
func (*BaseSensor) RemoveCollector ¶ added in v0.7.0
func (a *BaseSensor) RemoveCollector(name string) error
RemoveCollector removes a collector from the sensor.
func (*BaseSensor) RemoveScanner ¶ added in v0.7.0
func (a *BaseSensor) RemoveScanner(name string) error
RemoveScanner removes a scanner from the sensor.
func (*BaseSensor) SetAssetResolver ¶ added in v0.8.0
func (a *BaseSensor) SetAssetResolver(r AssetResolver)
SetAssetResolver names the asset a scheduled scan's findings are filed on (for example the repository a directory belongs to). Without it a parser may emit findings without an asset, which protocol v2 rejects (RFC-026).
func (*BaseSensor) SetAuthGate ¶ added in v0.8.0
func (a *BaseSensor) SetAuthGate(g *AuthGate)
SetAuthGate replaces the sensor's AuthGate (nil is ignored). Call before Start.
func (*BaseSensor) SetCapabilityReporter ¶ added in v0.10.0
func (a *BaseSensor) SetCapabilityReporter(r CapabilityReporter)
SetCapabilityReporter makes every heartbeat carry r's report instead of the tool registry's (see Tools): the tools the sensor actually has, the capabilities it serves and its concurrency. The platform dispatches by it (an administrator can only narrow it). nil goes back to the registry. A reporter that returns an empty CapabilityReport reports nothing, and the platform keeps using its administrator's settings. Call before Start.
func (*BaseSensor) SetConfigReporter ¶ added in v0.18.0
func (a *BaseSensor) SetConfigReporter(r ConfigReporter)
SetConfigReporter makes the sensor deliver r's report to a platform that takes config reports, and put its digest on every heartbeat. Call before Start.
func (*BaseSensor) SetDoorbell ¶ added in v0.7.1
func (a *BaseSensor) SetDoorbell(d *Doorbell)
SetDoorbell makes the sensor act on the heartbeat doorbell: heartbeats announce the feature, their hints go to d, the advised interval replaces the configured one, and scheduled scans and collections are skipped while the platform has paused or drained the sensor. Share d with the CommandPoller (CommandPoller.SetDoorbell) so it polls when the doorbell rings. The pusher must implement DoorbellPusher (*client.Client does); otherwise heartbeats stay plain. Call before Start.
func (*BaseSensor) SetLoadReporter ¶ added in v0.10.0
func (a *BaseSensor) SetLoadReporter(r LoadReporter)
SetLoadReporter makes every heartbeat carry r's load: the commands the sensor runs now (active_jobs, sent even when 0), its dynamic slots when r is a StatusReporter with a resource manager (capacity), and otherwise, when the capability report does not already say it, its fixed concurrency (max_concurrent_jobs). Pass the sensor's *CommandPoller. Call before Start.
func (*BaseSensor) SetLocalPolicy ¶ added in v0.18.0
func (a *BaseSensor) SetLocalPolicy(lp *LocalPolicy)
SetLocalPolicy makes every heartbeat and manifest report lp (api RFC-040 §5.7): its state ("enforced" or "absent"), digest and summary, never its ranges. The platform receives it only when it lists the "local_policy" feature on hello. While lp's kill switch is engaged the heartbeat message is LocalPolicyPausedMessage. Enforcement is the command poller's and the executor's (CommandPoller.SetLocalPolicy); this only reports. Call before Start.
func (*BaseSensor) SetNetworkReporter ¶ added in v0.25.0
func (a *BaseSensor) SetNetworkReporter(r NetworkReporter)
SetNetworkReporter makes every manifest carry r's latest report, to a platform that lists the "network" feature. A changed report changes the manifest digest, so the next heartbeat registers the manifest again. nil reports none.
func (*BaseSensor) SetPosture ¶ added in v0.19.0
func (a *BaseSensor) SetPosture(p *SensorPosture)
SetPosture makes every manifest report p (SensorPosture: the platform TLS pin and the tool sandbox), to a platform that lists the "posture" feature. nil reports nothing. Call before Start.
func (*BaseSensor) SetVerbose ¶ added in v0.7.0
func (a *BaseSensor) SetVerbose(v bool)
SetVerbose sets verbose mode.
func (*BaseSensor) Start ¶ added in v0.7.0
func (a *BaseSensor) Start(ctx context.Context) error
Start starts the sensor.
func (*BaseSensor) Status ¶ added in v0.7.0
func (a *BaseSensor) Status() *SensorStatus
Status returns the current sensor status.
func (*BaseSensor) Stop ¶ added in v0.7.0
func (a *BaseSensor) Stop(ctx context.Context) error
Stop stops the sensor gracefully.
func (*BaseSensor) Tools ¶ added in v0.11.0
func (a *BaseSensor) Tools() *ToolRegistry
Tools returns the sensor's tool registry. Every heartbeat reports it (unless SetCapabilityReporter replaced it): the scanners and collectors added with AddScanner and AddCollector are in it already; register any other tool the sensor runs (an executor's scanners: DefaultCommandExecutor.SetToolRegistry), the capabilities it serves whatever the tools (AddCapabilities) and its cap (SetMaxConcurrentJobs). The platform needs no list of a sensor's tools: it learns them here.
type BaseSensorConfig ¶ added in v0.7.0
type BaseSensorConfig struct {
Name string `yaml:"name" json:"name"`
Version string `yaml:"version" json:"version"`
// ProductName, Commit and BuildTime describe the sensor binary on every
// heartbeat ("sensor"); all optional. ProductName defaults to the name
// given to useragent.SetProduct, then to the executable's name;
// BuildTime is RFC 3339.
ProductName string `yaml:"product_name" json:"product_name"`
Commit string `yaml:"commit" json:"commit"`
BuildTime string `yaml:"build_time" json:"build_time"`
Region string `yaml:"region" json:"region"` // Deployment region (e.g., "us-east-1", "ap-southeast-1")
ScanInterval time.Duration `yaml:"scan_interval" json:"scan_interval"`
CollectInterval time.Duration `yaml:"collect_interval" json:"collect_interval"`
HeartbeatInterval time.Duration `yaml:"heartbeat_interval" json:"heartbeat_interval"`
Targets []string `yaml:"targets" json:"targets"`
Verbose bool `yaml:"verbose" json:"verbose"`
}
BaseSensorConfig configures a BaseSensor.
type CVSSData ¶
type CVSSData struct {
Source CVSSSource `json:"source"`
Score float64 `json:"score"`
Vector string `json:"vector"`
}
CVSSData holds CVSS information from various sources.
func SelectBestCVSS ¶
func SelectBestCVSS(cvssMap map[CVSSSource]CVSSData) *CVSSData
SelectBestCVSS selects the best CVSS data from multiple sources. Uses priority order: NVD > GHSA > RedHat > Bitnami
type CVSSSource ¶
type CVSSSource string
CVSSSource represents the source of CVSS data.
const ( CVSSSourceNVD CVSSSource = "nvd" // National Vulnerability Database CVSSSourceGHSA CVSSSource = "ghsa" // GitHub Security Advisory CVSSSourceRedHat CVSSSource = "redhat" // Red Hat CVSSSourceBitnami CVSSSource = "bitnami" // Bitnami )
type CacheStats ¶
type CacheStats struct {
TemplateCount int `json:"template_count"`
TotalSize int64 `json:"total_size"`
TenantCount map[string]int `json:"tenant_count"`
TypeCount map[string]int `json:"type_count"`
OldestEntry time.Time `json:"oldest_entry"`
NewestEntry time.Time `json:"newest_entry"`
}
CacheStats contains cache statistics.
type CachedTemplateMetadata ¶
type CachedTemplateMetadata struct {
ID string `json:"id"`
Name string `json:"name"`
TemplateType string `json:"template_type"`
ContentHash string `json:"content_hash"`
TenantID string `json:"tenant_id"`
FilePath string `json:"file_path"`
Size int64 `json:"size"`
CachedAt time.Time `json:"cached_at"`
LastUsedAt time.Time `json:"last_used_at"`
}
CachedTemplateMetadata stores metadata about a cached template.
type CancelPusher ¶ added in v0.18.0
type CancelPusher interface {
SendHeartbeatForCancels(ctx context.Context, status *SensorStatus) ([]string, error)
}
CancelPusher sends a heartbeat that does not announce the doorbell and returns the commands the platform says this sensor must stop (cancel_command_ids). A sensor without a doorbell (sensorkit DisableDoorbell) still honors cancels through it: the platform answers cancel_command_ids to any heartbeat that lists what the sensor runs. *client.Client implements it.
type CapabilityReport ¶ added in v0.10.0
type CapabilityReport struct {
// Tools is the tool inventory. nil reports nothing (the platform keeps
// using its administrator's list); an empty, non-nil slice reports that
// no tool is available.
Tools []ToolInfo
// Capabilities are the capability names the sensor serves ("validate",
// a tool name, "sast"). nil reports nothing, as for Tools.
Capabilities []string
// MaxConcurrentJobs is the operator's ceiling on concurrent jobs
// (SENSOR_MAX_JOBS, SetMaxConcurrentJobs); 0 reports none. It is not
// what the sensor can run now: a sensor with a resource manager reports
// that as its dynamic slots (SensorStatus.Capacity.SlotsTotal), always
// at most this ceiling.
MaxConcurrentJobs int
}
CapabilityReport is what a sensor reports it can do.
func (CapabilityReport) Apply ¶ added in v0.10.0
func (r CapabilityReport) Apply(status *SensorStatus)
Apply copies the report onto a heartbeat status (copies of the slices, so the reporter may reuse its own).
type CapabilityReporter ¶ added in v0.10.0
type CapabilityReporter interface {
CapabilityReport(ctx context.Context) CapabilityReport
}
CapabilityReporter supplies the capability report a BaseSensor puts on every heartbeat. It is called once per heartbeat, so an implementation that probes tools should cache the result.
func StaticCapabilities ¶ added in v0.10.0
func StaticCapabilities(r CapabilityReport) CapabilityReporter
StaticCapabilities is a reporter that always reports r.
type CapabilityReporterFunc ¶ added in v0.10.0
type CapabilityReporterFunc func(ctx context.Context) CapabilityReport
CapabilityReporterFunc adapts a function to CapabilityReporter.
func (CapabilityReporterFunc) CapabilityReport ¶ added in v0.10.0
func (f CapabilityReporterFunc) CapabilityReport(ctx context.Context) CapabilityReport
CapabilityReport calls f.
type CapabilityScanner ¶ added in v0.19.0
CapabilityScanner is a scanner that runs capability jobs: it takes the job's capability, standard params and tier ceiling (ScanOptions) and applies the tool contract to them. A job that carries them for any other scanner fails: they would have no effect.
type CollectCommandPayload ¶
type CollectCommandPayload struct {
Collector string `json:"collector"`
SourceConfig map[string]interface{} `json:"source_config,omitempty"`
}
CollectCommandPayload is the payload for collect commands.
type CollectOptions ¶
type CollectOptions struct {
// Source configuration
SourceURL string `yaml:"source_url" json:"source_url"`
APIKey string `yaml:"api_key" json:"api_key"`
Headers map[string]string `yaml:"headers" json:"headers"`
Query map[string]string `yaml:"query" json:"query"`
// Filtering
Since int64 `yaml:"since" json:"since"` // Unix timestamp
Repository string `yaml:"repository" json:"repository"`
Branches []string `yaml:"branches" json:"branches"`
// Pagination
PageSize int `yaml:"page_size" json:"page_size"`
MaxPages int `yaml:"max_pages" json:"max_pages"`
}
CollectOptions configures data collection.
type CollectResult ¶
type CollectResult struct {
// Source info
SourceName string `json:"source_name"`
SourceType string `json:"source_type"`
// Collection timing
CollectedAt int64 `json:"collected_at"`
DurationMs int64 `json:"duration_ms"`
// Results
Reports []*ctis.Report `json:"reports"`
TotalItems int `json:"total_items"`
ErrorItems int `json:"error_items"`
// Cursor for pagination
NextCursor string `json:"next_cursor,omitempty"`
HasMore bool `json:"has_more"`
}
CollectResult holds collected data.
type Collector ¶
type Collector interface {
// Name returns the collector name
Name() string
// Type returns the source type (e.g., "github", "gitlab", "api")
Type() string
// Collect pulls data from the external source
Collect(ctx context.Context, opts *CollectOptions) (*CollectResult, error)
// TestConnection verifies the connection to the external source
TestConnection(ctx context.Context) error
}
Collector pulls security data from external sources (GitHub, GitLab, etc.). Implement this interface to create a custom collector.
type Command ¶
type Command struct {
ID string `json:"id"`
Type string `json:"type"`
Priority string `json:"priority"`
Payload json.RawMessage `json:"payload"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
// LeaseEpoch and LeaseExpiresAt are the command's lease as the poll
// saw it (protocol v2, api RFC-035 D6): the claim that follows starts
// a new epoch, which the client keeps and echoes on complete and fail.
// Zero from a platform without leases.
LeaseEpoch int `json:"lease_epoch,omitempty"`
LeaseExpiresAt time.Time `json:"lease_expires_at,omitzero"`
// SignedJob is the platform job signer's DSSE envelope for this
// delivery ("signed_job" of a claim answer; api RFC-040 §5.6). It binds
// Payload's exact bytes, so Payload must be kept as received.
SignedJob json.RawMessage `json:"signed_job,omitempty"`
// Claimed is true when the poll already claimed the command for this
// sensor (claim-N, api RFC-046 §11). The poller still acknowledges it
// (a replay) when it runs it, and releases it when it does not.
Claimed bool `json:"-"`
// contains filtered or unexported fields
}
Command represents a server command.
type CommandAdmission ¶ added in v0.19.0
type CommandAdmission struct {
// Total is how many targets the command named.
Total int
// Refused are the targets removed from the command (or, with an error,
// the targets that made it refused), in payload order.
Refused []RefusedTarget
}
CommandAdmission is what AdmitCommandTargets decided about a command's targets.
func (*CommandAdmission) Partial ¶ added in v0.19.0
func (a *CommandAdmission) Partial() bool
Partial reports whether the command runs on some of its targets only.
type CommandCanceler ¶ added in v0.18.0
type CommandCanceler interface {
CancelCommands(ids ...string)
}
CommandCanceler stops held commands by id. *CommandPoller implements it.
type CommandClaimer ¶ added in v0.19.0
CommandClaimer claims a command and returns it as the claim answered it: its payload, its signed job and the lease epoch of the claim. *client.Client implements it. With a JobGuard that verifies, the poller claims through it, so the signed job and the payload it checks are the claim's.
type CommandClient ¶
type CommandClient interface {
GetCommands(ctx context.Context) (*GetCommandsResponse, error)
AcknowledgeCommand(ctx context.Context, cmdID string) error
StartCommand(ctx context.Context, cmdID string) error
ReportCommandResult(ctx context.Context, cmdID string, result *CommandResult) error
ReportCommandProgress(ctx context.Context, cmdID string, progress int, message string) error
}
CommandClient interface for command-related API operations.
type CommandExecutionResult ¶
type CommandExecutionResult struct {
DurationMs int64
FindingsCount int
ExitCode int
Metadata map[string]interface{}
// TargetOutcomes is how each of a scan job's targets ended, in job
// order (target_outcomes.go); nil for other commands.
TargetOutcomes []outcome.Target
}
CommandExecutionResult is the result of command execution.
type CommandExecutor ¶
type CommandExecutor interface {
Execute(ctx context.Context, cmd *Command) (*CommandExecutionResult, error)
}
CommandExecutor executes commands.
type CommandLogSink ¶ added in v0.19.0
type CommandLogSink interface {
// CommandLog adds one line (level: info, warn or error) to the log of
// command commandID. It never blocks on the network.
CommandLog(ctx context.Context, commandID, level, msg string, fields map[string]any)
// FinishCommandLog sends what is left of the command's lines. Queued
// (direct false), the lines are delivered by the outbox ahead of the
// result reported after it. Direct, they are sent before it returns:
// for a command about to be handed back, after which the platform no
// longer takes this sensor's lines for it.
FinishCommandLog(ctx context.Context, commandID string, direct bool)
}
CommandLogSink takes the poller's lines about a command.
type CommandPoller ¶
type CommandPoller struct {
// contains filtered or unexported fields
}
CommandPoller polls the server for pending commands.
func NewCommandPoller ¶
func NewCommandPoller(client CommandClient, executor CommandExecutor, cfg *CommandPollerConfig) *CommandPoller
NewCommandPoller creates a new command poller.
func (*CommandPoller) ActiveJobs ¶ added in v0.10.0
func (p *CommandPoller) ActiveJobs() int
ActiveJobs is the number of commands this poller holds now (claimed and running). It implements LoadReporter.
func (*CommandPoller) CancelCommands ¶ added in v0.10.0
func (p *CommandPoller) CancelCommands(ids ...string)
CancelCommands cancels held commands (the platform's cancel_command_ids): a running one is stopped (its context is canceled), and each is released back to the platform instead of reported. Ids not held are ignored.
func (*CommandPoller) HeldCommandIDs ¶ added in v0.10.0
func (p *CommandPoller) HeldCommandIDs() []string
HeldCommandIDs are the commands this sensor holds (claimed, not finished), sorted: the lease list a heartbeat carries as "running".
func (*CommandPoller) LocalKillSwitch ¶ added in v0.18.0
func (p *CommandPoller) LocalKillSwitch() bool
LocalKillSwitch reports whether the local kill switch is engaged now.
func (*CommandPoller) MaxJobs ¶ added in v0.10.0
func (p *CommandPoller) MaxJobs() int
MaxJobs is the most commands this poller runs at once: the configured cap (CommandPollerConfig.MaxConcurrent, or the resource manager's). The live slot count is at most this. It implements LoadReporter. With a resource manager the heartbeat reports the live slots (ReportStatus) rather than this bound.
func (*CommandPoller) QueueStats ¶ added in v0.10.0
func (p *CommandPoller) QueueStats() QueueStats
QueueStats is the local queue now.
func (*CommandPoller) ReportStatus ¶ added in v0.10.0
func (p *CommandPoller) ReportStatus(status *SensorStatus)
ReportStatus fills a heartbeat with the poller's work: active jobs, the local queue, the held ids and, with a resource manager, resources and capacity. It implements StatusReporter.
func (*CommandPoller) RunClaimed ¶ added in v0.18.0
func (p *CommandPoller) RunClaimed(ctx context.Context, cmd *Command) error
RunClaimed runs one command this sensor already claimed, and returns when its result was reported (or queued in the outbox): the sensor that runs one job and exits (a Kubernetes Job). The command passes every check a polled command passes: the local kill switch, the command types this sensor serves, the expiry, its job signature (SetJobGuard; cmd must come from the claim answer, as client.ClaimCommand returns it), then (as for any command) the local policy admission, the start transition, the platform's tool gate, the executor and the result report. A command that is not run is released to the platform (an error wrapping ErrNotRun says why). Canceling ctx stops the command and releases it, as a drain does.
func (*CommandPoller) SetAuthGate ¶ added in v0.8.0
func (p *CommandPoller) SetAuthGate(g *AuthGate)
SetAuthGate shares the heartbeat's AuthGate (BaseSensor.AuthGate) with the poller: it does not poll while the platform rejects the key, and resumes with the first accepted heartbeat. A poller sharing the sensor's doorbell already gets it. Call before Start.
func (*CommandPoller) SetCommandGate ¶ added in v0.15.0
func (p *CommandPoller) SetCommandGate(gate func(*Command) error)
SetCommandGate sets a check every command passes before it runs: a non-nil error reports the command failed with it and never executes it. A BaseSensor's CommandToolGate refuses tools outside the platform's policy (api RFC-033 §6.12). nil removes the check. Safe at any time.
func (*CommandPoller) SetCommandLogSink ¶ added in v0.19.0
func (p *CommandPoller) SetCommandLogSink(sink CommandLogSink)
SetCommandLogSink makes the poller write its own lines about each command to sink (nil: none). Call before Start.
func (*CommandPoller) SetDoorbell ¶ added in v0.7.1
func (p *CommandPoller) SetDoorbell(d *Doorbell)
SetDoorbell makes the poller follow the heartbeat doorbell: it polls when the doorbell rings, and while the server sends hints it drops the fixed interval for a long safety poll (CommandPollerConfig.DoorbellSafetyPoll). While the platform has paused or drained the sensor it claims nothing. Share d with the heartbeat (BaseSensor.SetDoorbell). Call before Start.
func (*CommandPoller) SetJobGuard ¶ added in v0.19.0
func (p *CommandPoller) SetJobGuard(g *JobGuard)
SetJobGuard makes the poller check every command's signed job (api RFC-040 §5.6) right after it is claimed, before it is started and before the local policy, the command gate or any executor sees it. A command the guard refuses is reported failed with rule "job_signature" and never run. With a guard that verifies, commands are claimed through CommandClaimer when the client implements it, so the payload, the signed job and the lease epoch checked are those of the claim answer. Call before Start.
func (*CommandPoller) SetLocalPolicy ¶ added in v0.18.0
func (p *CommandPoller) SetLocalPolicy(lp *LocalPolicy)
SetLocalPolicy makes the poller enforce the sensor-local policy (api RFC-040 §5.7): every command passes LocalPolicy.AdmitCommandTargets after it is claimed and before any executor or tool sees it. A scan target it refuses is removed from the job and listed in the result (MetaRefusedTargets); a refused command is reported failed with "refused by local policy: <rule>: …", never run and never dropped silently. While the kill switch is engaged the poller claims nothing and stops the commands it runs (reported failed). It is checked before the gate of SetCommandGate, so no platform policy can widen it. Call before Start.
func (*CommandPoller) SetResourceManager ¶ added in v0.10.0
func (p *CommandPoller) SetResourceManager(m *resource.Manager)
SetResourceManager sizes the poller's slots from m: the jobs that fit the sensor's CPU and memory for its tools' learned cost, at most m's cap, narrowed after OOM kills, timeouts and throttling. Every finished command teaches m its cost. The heartbeat then reports resources and capacity. Call before Start.
func (*CommandPoller) SetVerbose ¶
func (p *CommandPoller) SetVerbose(v bool)
SetVerbose sets verbose mode.
func (*CommandPoller) Start ¶
func (p *CommandPoller) Start(ctx context.Context) error
Start starts the command poller.
func (*CommandPoller) StopCommands ¶ added in v0.28.0
func (p *CommandPoller) StopCommands(ids ...string)
StopCommands stops held commands the platform asks to stop and deliver (stop_command_ids): a running one's context is canceled with ErrStoppedByPlatform, and the run's settled targets are delivered and reported (partial, the rest unfinished) instead of released. Ids not held are ignored.
type CommandPollerConfig ¶
type CommandPollerConfig struct {
PollInterval time.Duration `yaml:"poll_interval" json:"poll_interval"`
MaxConcurrent int `yaml:"max_concurrent" json:"max_concurrent"`
AllowedTypes []string `yaml:"allowed_types" json:"allowed_types"`
Verbose bool `yaml:"verbose" json:"verbose"`
// DoorbellSafetyPoll is how often the poller still polls on its own
// while the heartbeat doorbell is active. Default 5m.
DoorbellSafetyPoll time.Duration `yaml:"doorbell_safety_poll" json:"doorbell_safety_poll"`
// DrainGrace is how long a stopping poller lets running commands finish
// before it cancels them and releases them to the platform. Default 30s.
DrainGrace time.Duration `yaml:"drain_grace" json:"drain_grace"`
}
CommandPollerConfig configures a CommandPoller.
func DefaultCommandPollerConfig ¶
func DefaultCommandPollerConfig() *CommandPollerConfig
DefaultCommandPollerConfig returns default config.
type CommandProgress ¶ added in v0.26.0
type CommandProgress struct {
Done int `json:"done"`
Total int `json:"total"`
Finished [][2]int `json:"finished,omitempty"`
Records int64 `json:"records,omitempty"`
OutputBytes int64 `json:"output_bytes,omitempty"`
CPUMs int64 `json:"cpu_ms,omitempty"`
// ReleasedKeys are the politeness keys the sensor freed because the
// targets that needed them settled (politeness.Holding): the platform
// stops counting them as held by the command, so other work on those
// hosts can start before it ends. Sorted, at most politeness.MaxKeys.
ReleasedKeys []string `json:"released_keys,omitempty"`
}
CommandProgress is one held command's progress. Finished lists the finished targets as inclusive [first, last] index ranges into the command's target list, sorted and merged; it is omitted when the job's targets are unknown or there are more than MaxProgressRanges ranges.
Records, OutputBytes and CPUMs are liveness counters, all monotonic for the job: the records the tool's output delivered and their bytes, and the CPU time of the job's tool processes. A batch tool that finishes targets rarely still shows it is working through them; the platform calls a task stalled only when none of done and these moves for its stall window.
type CommandResult ¶
type CommandResult struct {
Status string `json:"status"`
CompletedAt time.Time `json:"completed_at"`
DurationMs int64 `json:"duration_ms"`
ExitCode int `json:"exit_code"`
FindingsCount int `json:"findings_count"`
Error string `json:"error,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
// Refusal is set when a policy refused the command (RefusalOf): it was
// never run, or was stopped by the kill switch.
Refusal *Refusal `json:"refusal,omitempty"`
// TargetOutcomes is how each target of a completed scan command ended
// (ctis outcome.ResultKey): the platform settles the targets with an
// outcome and hands out only the unfinished ones again.
TargetOutcomes []outcome.Target `json:"target_outcomes,omitempty"`
}
CommandResult represents the result of command execution.
type ConfigCheck ¶ added in v0.18.0
type ConfigCheck struct {
ID string `json:"id"`
Status string `json:"status"`
Severity string `json:"severity"`
Code string `json:"code"`
Params map[string]ConfigParam `json:"params,omitempty"`
Keys []string `json:"keys,omitempty"`
Summary string `json:"summary,omitempty"`
Excerpt string `json:"excerpt,omitempty"`
Blocks []string `json:"blocks,omitempty"`
}
ConfigCheck is one check result.
type ConfigParam ¶ added in v0.18.0
type ConfigParam struct {
Int *int64 `json:"int,omitempty"`
Bool *bool `json:"bool,omitempty"`
Enum string `json:"enum,omitempty"`
Path string `json:"path,omitempty"`
Host string `json:"host,omitempty"`
Version string `json:"version,omitempty"`
Name string `json:"name,omitempty"`
Names []string `json:"names,omitempty"`
}
ConfigParam is a typed parameter: exactly one member is set.
func ParamBool ¶ added in v0.18.0
func ParamBool(b bool) ConfigParam
func ParamEnum ¶ added in v0.18.0
func ParamEnum(s string) ConfigParam
func ParamHost ¶ added in v0.18.0
func ParamHost(s string) ConfigParam
func ParamInt ¶ added in v0.18.0
func ParamInt(n int64) ConfigParam
ParamInt and the functions below build typed parameters.
func ParamName ¶ added in v0.18.0
func ParamName(s string) ConfigParam
func ParamNames ¶ added in v0.18.0
func ParamNames(s ...string) ConfigParam
func ParamPath ¶ added in v0.18.0
func ParamPath(s string) ConfigParam
func ParamVersion ¶ added in v0.18.0
func ParamVersion(s string) ConfigParam
type ConfigReport ¶ added in v0.18.0
type ConfigReport struct {
Schema int `json:"schema"`
ObservedAt string `json:"observed_at"`
Trigger string `json:"trigger"`
Runtime ConfigRuntime `json:"runtime"`
ConfigHealth string `json:"config_health"`
Checks []ConfigCheck `json:"checks"`
Settings []ConfigSetting `json:"settings"`
Truncated bool `json:"truncated"`
}
ConfigReport is the document (schema 1).
func (*ConfigReport) Counts ¶ added in v0.18.0
func (r *ConfigReport) Counts() (fail, warn int)
Counts returns the failed and warning checks.
func (*ConfigReport) Digest ¶ added in v0.18.0
func (r *ConfigReport) Digest() (string, error)
Digest is "sha256:" + the hex SHA-256 of the report's canonical JSON (object members sorted, no whitespace, no HTML escaping) with observed_at and trigger emptied: the same state rebuilt later has the same digest.
func (*ConfigReport) Finalize ¶ added in v0.18.0
func (r *ConfigReport) Finalize(secrets []string, maxBytes int)
Finalize makes r safe to send: it drops what does not fit the schema, scrubs every secret value and every URL's credentials from all text, bounds each field, recomputes the health rollup and, when the document is still larger than maxBytes (MaxConfigReportBytes when <= 0), drops the settings, then passing checks, then the least severe checks, marking it truncated. secrets are the values to scrub (the registry's secret settings, the API key in use).
func (*ConfigReport) Summary ¶ added in v0.18.0
func (r *ConfigReport) Summary(platformDigest string) *ConfigReportSummary
Summary is the heartbeat form of r under the platform's digest.
type ConfigReportAck ¶ added in v0.18.0
type ConfigReportAck struct {
Digest string
Changed bool
Ignored []ManifestIgnored
}
ConfigReportAck is the platform's answer to a config report.
type ConfigReportPusher ¶ added in v0.18.0
type ConfigReportPusher interface {
PutConfigReport(ctx context.Context, r *ConfigReport) (*ConfigReportAck, error)
}
ConfigReportPusher is implemented by a Pusher that can send a config report (client.Client on protocol v2).
type ConfigReportSummary ¶ added in v0.18.0
type ConfigReportSummary struct {
Digest string `json:"digest"`
Health string `json:"health"`
Fail int `json:"fail"`
Warn int `json:"warn"`
ObservedAt string `json:"observed_at"`
}
ConfigReportSummary is what every heartbeat says about the report: the digest the platform returned for it, the rollup and the counts.
type ConfigReporter ¶ added in v0.18.0
type ConfigReporter interface {
ConfigReport() *ConfigReport
}
ConfigReporter supplies the sensor's current config report, already finalized (ConfigReport.Finalize); nil when it has none yet. It is called on every heartbeat, so it should be cheap (build once, rebuild on change).
type ConfigReporterFunc ¶ added in v0.18.0
type ConfigReporterFunc func() *ConfigReport
ConfigReporterFunc adapts a function to ConfigReporter.
func (ConfigReporterFunc) ConfigReport ¶ added in v0.18.0
func (f ConfigReporterFunc) ConfigReport() *ConfigReport
ConfigReport calls f.
type ConfigRuntime ¶ added in v0.18.0
type ConfigRuntime struct {
Kind string `json:"kind"`
}
ConfigRuntime is how the sensor runs (docker, kubernetes, systemd, binary): the platform preselects the matching fix snippet.
type ConfigSetting ¶ added in v0.18.0
type ConfigSetting struct {
Name string `json:"name"`
Set bool `json:"set"`
Source string `json:"source"`
Secret bool `json:"secret"`
Valid bool `json:"valid"`
}
ConfigSetting is a declared setting's presence: set or not, where it came from, whether it is a secret and whether its value is valid. It has no value member: values never leave the host.
type Connector ¶
type Connector interface {
// Name returns the connector name (e.g., "github", "gitlab")
Name() string
// Type returns the connector type (e.g., "scm", "cloud", "ticketing")
Type() string
// Connect establishes connection to the external system
Connect(ctx context.Context) error
// Close closes the connection
Close() error
// IsConnected returns true if connected
IsConnected() bool
// TestConnection verifies the connection is working
TestConnection(ctx context.Context) error
// HTTPClient returns the configured HTTP client (with auth headers)
HTTPClient() *http.Client
// RateLimited returns true if rate limiting is enabled
RateLimited() bool
// WaitForRateLimit blocks until rate limit allows next request
WaitForRateLimit(ctx context.Context) error
}
Connector manages connection to an external system with authentication, rate limiting, and connection pooling.
type ConnectorConfig ¶
type ConnectorConfig struct {
// Authentication
APIKey string `yaml:"api_key" json:"api_key"`
Token string `yaml:"token" json:"token"`
Username string `yaml:"username" json:"username"`
Password string `yaml:"password" json:"password"`
OAuthConfig *OAuthConfig `yaml:"oauth" json:"oauth,omitempty"`
// Connection
BaseURL string `yaml:"base_url" json:"base_url"`
Timeout time.Duration `yaml:"timeout" json:"timeout"`
// Rate limiting
RateLimit int `yaml:"rate_limit" json:"rate_limit"` // requests per hour
BurstLimit int `yaml:"burst_limit" json:"burst_limit"` // burst size
// Retry
MaxRetries int `yaml:"max_retries" json:"max_retries"`
RetryDelay time.Duration `yaml:"retry_delay" json:"retry_delay"`
// Debug
Verbose bool `yaml:"verbose" json:"verbose"`
}
ConnectorConfig holds common configuration for connectors.
type ContentInfo ¶ added in v0.10.0
type ContentInfo struct {
// Name is the content's name (ContentTrivyDB, ContentNucleiTemplates, ...).
Name string `json:"name"`
// Version identifies the content: a release tag for templates, the
// build time for a database, a digest prefix for a rules bundle. Empty
// when the sensor has none.
Version string `json:"version,omitempty"`
// UpdatedAt is when the content was published (the database's build
// time, the templates' release date); the platform measures staleness
// from it. nil when unknown.
UpdatedAt *time.Time `json:"updated_at,omitempty"`
// FetchedAt is when this sensor installed it.
FetchedAt *time.Time `json:"fetched_at,omitempty"`
// CheckedAt is when the sensor last confirmed with its source that this
// is still the newest version (or the pinned one). Content that is old
// because its publisher has released nothing newer is not stale: see
// Stale.
CheckedAt *time.Time `json:"checked_at,omitempty"`
// Source is where it came from: a registry repository, a URL, "image"
// for content baked into the sensor image, or the tool's own fetch.
Source string `json:"source,omitempty"`
// Digest is the content's digest ("sha256:..."): the OCI manifest digest
// of a database, the archive digest of a template release.
Digest string `json:"digest,omitempty"`
// Managed is true when the sensor controls the content (it refreshes,
// verifies and swaps it, and scans use exactly this version); false
// when the tool fetches its content by itself.
Managed bool `json:"managed"`
// Error is the last refresh failure, if the last refresh failed (the
// sensor keeps scanning with the version above). Short, no secrets.
Error string `json:"error,omitempty"`
}
ContentInfo is one piece of scanner content a sensor has.
func (ContentInfo) Age ¶ added in v0.10.0
Age returns how old the content is at now (from UpdatedAt, else FetchedAt); ok is false when neither is known.
func (ContentInfo) Stale ¶ added in v0.10.0
Stale reports whether the content is stale at now under maxAge: older than maxAge (Age) AND not confirmed current (CheckedAt) within maxAge. A template set whose newest release is three weeks old is not stale while the sensor keeps confirming that nothing newer exists; a database whose refresh keeps failing is. maxAge <= 0 never makes content stale; content of unknown age is not stale.
type ContentPin ¶ added in v0.10.0
type ContentPin struct {
// MaxAgeHours: content older than this is stale. The sensor refreshes
// it on its next check and the platform reports the sensor degraded
// while it stays stale. 0: no limit.
MaxAgeHours int `json:"max_age_hours,omitempty"`
// Version pins the content: an OCI digest ("sha256:...") for a
// database, a release tag ("v10.4.9") for templates. Empty: the
// newest the source has.
Version string `json:"version,omitempty"`
// Rulesets (semgrep-rules only) are the registry rulesets the sensor
// fetches, verifies and pins ("p/default"). Empty: semgrep fetches its
// rules itself on every scan (--config auto).
Rulesets []string `json:"rulesets,omitempty"`
}
ContentPin is the policy for one kind of content.
func (ContentPin) MaxAge ¶ added in v0.10.0
func (p ContentPin) MaxAge() time.Duration
MaxAge returns MaxAgeHours as a duration (0 when unset).
type ContentPolicy ¶ added in v0.10.0
type ContentPolicy struct {
// RefreshIntervalHours is how often the sensor checks for new content;
// 0 leaves the sensor's own setting.
RefreshIntervalHours int `json:"refresh_interval_hours,omitempty"`
// Content is the per-content policy, keyed by content name.
Content map[string]ContentPin `json:"content,omitempty"`
}
ContentPolicy is a tenant's policy for scanner content, sent to sensors on refresh_content commands. Sources (registries, mirrors, local directories) are NOT part of it: they are the sensor host's configuration, so the platform cannot point a sensor at content from elsewhere.
type ControlStats ¶ added in v0.15.0
type ControlStats struct {
// IntervalSeconds is the heartbeat interval the sensor follows now: the
// platform's advice, else its own setting.
IntervalSeconds float64 `json:"interval_s"`
// GapSeconds is the time since the previous delivered heartbeat, when
// this one is sent (0 on the first).
GapSeconds float64 `json:"gap_s,omitempty"`
// LagMs is how late this heartbeat started against its schedule: the
// time the sensor waited for the CPU.
LagMs int64 `json:"lag_ms"`
// BuildMs is the time spent building this heartbeat's report (load
// snapshot, tool inventory, manifest).
BuildMs int64 `json:"build_ms"`
// RTTMs is the round trip of the previous delivered heartbeat.
RTTMs int64 `json:"rtt_ms,omitempty"`
// Failures is the heartbeats that failed since the previous delivered
// one.
Failures int `json:"failures,omitempty"`
}
ControlStats is how the sensor's control channel is doing, carried on every heartbeat as "control" (api RFC-035 §5.5). It tells a sensor that is busy but alive from one that is gone, and says where a late heartbeat lost its time: waiting for the CPU (lag), building the report (build) or on the way to the platform (rtt).
type DNSRecord ¶
type DNSRecord struct {
Host string `json:"host"` // Hostname
RecordType string `json:"record_type"` // A, AAAA, CNAME, MX, NS, TXT, SOA
Values []string `json:"values"` // Record values
TTL int `json:"ttl,omitempty"` // Time to live
Resolver string `json:"resolver,omitempty"` // Resolver used
StatusCode string `json:"status_code,omitempty"` // NOERROR, NXDOMAIN, etc.
}
DNSRecord represents a DNS record.
type DefaultCommandExecutor ¶
type DefaultCommandExecutor struct {
// contains filtered or unexported fields
}
DefaultCommandExecutor provides default command execution.
func NewDefaultCommandExecutor ¶
func NewDefaultCommandExecutor(pusher Pusher) *DefaultCommandExecutor
NewDefaultCommandExecutor creates a new default executor.
Scan targets are validated with DefaultScanTargetPolicy() (SSRF blocklist, filesystem confinement, flag-injection guard); override with SetScanTargetPolicy.
func (*DefaultCommandExecutor) AddCollector ¶
func (e *DefaultCommandExecutor) AddCollector(collector Collector)
AddCollector adds a collector.
func (*DefaultCommandExecutor) AddScanner ¶
func (e *DefaultCommandExecutor) AddScanner(scanner Scanner)
AddScanner adds a scanner.
func (*DefaultCommandExecutor) Execute ¶
func (e *DefaultCommandExecutor) Execute(ctx context.Context, cmd *Command) (*CommandExecutionResult, error)
Execute executes a command.
func (*DefaultCommandExecutor) ScanTargetPolicy ¶ added in v0.7.0
func (e *DefaultCommandExecutor) ScanTargetPolicy() *ScanTargetPolicy
ScanTargetPolicy returns the policy currently applied to scan targets.
func (*DefaultCommandExecutor) SetAssetResolver ¶ added in v0.7.0
func (e *DefaultCommandExecutor) SetAssetResolver(r AssetResolver)
SetAssetResolver sets how executeScan names the scanned asset. Without one, parsers that cannot tell the asset from the scanner output (a filesystem scan by betterleaks, for one) send findings without an asset, which the platform files under a placeholder. Set it before the poller starts.
func (*DefaultCommandExecutor) SetLocalPolicy ¶ added in v0.18.0
func (e *DefaultCommandExecutor) SetLocalPolicy(lp *LocalPolicy)
SetLocalPolicy makes the executor enforce the sensor-local policy (api RFC-040 §5.7) on every scan, behind the poller's admission check: targets through the scan target policy, allow_custom_templates, allow_interactsh, rate.max_rps and rate.max_job_seconds. Nothing in a command can loosen it. nil removes it (the MaxScanTimeout cap stays).
func (*DefaultCommandExecutor) SetParserRegistry ¶ added in v0.5.1
func (e *DefaultCommandExecutor) SetParserRegistry(r *ParserRegistry)
SetParserRegistry supplies the registry used to convert a scanner's raw output into a CTIS report. executeScan uses the parser registered under the scanner's name, else the first parser that recognizes the content (see ParserRegistry.ForScanner). Without a registry only SARIF output is understood. Output no parser recognizes fails the command instead of being reported as 0 findings — register a parser for every scanner that does not emit SARIF (betterleaks, semgrep, trivy, nuclei).
func (*DefaultCommandExecutor) SetScanTargetPolicy ¶ added in v0.7.0
func (e *DefaultCommandExecutor) SetScanTargetPolicy(p *ScanTargetPolicy)
SetScanTargetPolicy replaces the policy used to validate server-supplied scan targets (allowed filesystem roots, private-range opt-in). A nil policy restores DefaultScanTargetPolicy(). Safe to call concurrently with Execute.
func (*DefaultCommandExecutor) SetSensorID ¶ added in v0.17.0
func (e *DefaultCommandExecutor) SetSensorID(id string)
SetSensorID sets this sensor's own id (from its configuration, not from the platform): a signed template manifest for another sensor is then refused. Empty: manifests are bound to the command and the tenant's key only.
func (*DefaultCommandExecutor) SetSourceCredentials ¶ added in v0.30.0
func (e *DefaultCommandExecutor) SetSourceCredentials(c SourceCredentials)
SetSourceCredentials wires the credential fetch of code-scan jobs; without it a job whose source names a credential fails.
func (*DefaultCommandExecutor) SetTemplateVerifier ¶ added in v0.17.0
func (e *DefaultCommandExecutor) SetTemplateVerifier(v *TemplateVerifier)
SetTemplateVerifier sets the pinned keys custom templates must be signed with (see TemplateVerifier). Without one, a command that carries custom templates fails with ErrNoTemplateKeys: an unsigned template never reaches a scanner.
func (*DefaultCommandExecutor) SetToolRegistry ¶ added in v0.11.0
func (e *DefaultCommandExecutor) SetToolRegistry(r *ToolRegistry)
SetToolRegistry registers the executor's scanners and collectors, those added already and those added later, in r, so the sensor reports them to the platform. Pass the sensor's registry (BaseSensor.Tools). Call before the poller starts.
func (*DefaultCommandExecutor) SetVerbose ¶
func (e *DefaultCommandExecutor) SetVerbose(v bool)
SetVerbose sets verbose mode.
type DefaultLogger ¶
type DefaultLogger struct {
// contains filtered or unexported fields
}
DefaultLogger is the default logger implementation using standard library.
func NewDefaultLogger ¶
func NewDefaultLogger(prefix string, level LogLevel) *DefaultLogger
NewDefaultLogger creates a new default logger.
func (*DefaultLogger) Debug ¶
func (l *DefaultLogger) Debug(format string, args ...interface{})
Debug logs a debug message.
func (*DefaultLogger) Error ¶
func (l *DefaultLogger) Error(format string, args ...interface{})
Error logs an error message.
func (*DefaultLogger) Info ¶
func (l *DefaultLogger) Info(format string, args ...interface{})
Info logs an info message.
func (*DefaultLogger) SetLevel ¶
func (l *DefaultLogger) SetLevel(level LogLevel)
SetLevel sets the log level.
func (*DefaultLogger) SetOutput ¶
func (l *DefaultLogger) SetOutput(w io.Writer)
SetOutput sets the output writer.
func (*DefaultLogger) Warn ¶
func (l *DefaultLogger) Warn(format string, args ...interface{})
Warn logs a warning message.
type DiscoveredURL ¶
type DiscoveredURL struct {
URL string `json:"url"` // Full URL
Method string `json:"method,omitempty"` // HTTP method (GET, POST, etc.)
Source string `json:"source,omitempty"` // Discovery source (crawl, js, archive)
StatusCode int `json:"status_code,omitempty"`
Depth int `json:"depth,omitempty"` // Crawl depth
Parent string `json:"parent,omitempty"` // Parent URL
Type string `json:"type,omitempty"` // endpoint, form, api, static
Extension string `json:"extension,omitempty"` // File extension
}
DiscoveredURL represents a discovered URL/endpoint.
type Doorbell ¶ added in v0.7.1
type Doorbell struct {
// contains filtered or unexported fields
}
Doorbell holds what the platform said on the last heartbeat and turns it into sensor behavior: it wakes the command poller when work is waiting, pauses and resumes job intake, and triggers key renewal. One Doorbell is shared by the heartbeat loop (which calls Handle) and the poller (which reads Paused, HintsActive and Wake). Safe for concurrent use.
func NewDoorbell ¶ added in v0.7.1
func NewDoorbell(cfg *DoorbellConfig) *Doorbell
NewDoorbell creates a Doorbell. A nil config uses defaults.
func (*Doorbell) ConfigVersion ¶ added in v0.7.1
ConfigVersion returns the last config version the platform sent, or "".
func (*Doorbell) Draining ¶ added in v0.7.1
Draining reports whether the platform drained this sensor.
func (*Doorbell) Handle ¶ added in v0.7.1
func (d *Doorbell) Handle(h *HeartbeatHints)
Handle applies one heartbeat answer. A nil hints value (or one with Present=false) means the server does not speak the doorbell: the poller falls back to its fixed interval.
func (*Doorbell) HeartbeatFailed ¶ added in v0.7.1
func (d *Doorbell) HeartbeatFailed()
HeartbeatFailed records that a heartbeat got no answer. The doorbell can no longer ring, so the poller returns to its fixed interval until the next answered heartbeat. Pause and drain are kept.
func (*Doorbell) HintsActive ¶ added in v0.7.1
HintsActive reports whether the last heartbeat answer carried hints, i.e. the poller may rely on the doorbell instead of polling on a fixed interval.
func (*Doorbell) Paused ¶ added in v0.7.1
Paused reports whether the sensor must not claim or start new jobs (pause or drain).
func (*Doorbell) PendingJobs ¶ added in v0.7.1
PendingJobs returns pending_jobs from the last heartbeat answer.
type DoorbellConfig ¶ added in v0.7.1
type DoorbellConfig struct {
// OnRotateKey is called (in its own goroutine) when the platform sends
// rotate_key, e.g. platform.KeyRenewManager.RenewNow. Nil: rotate_key is
// logged and otherwise ignored.
OnRotateKey func()
// Logger receives the doorbell's state changes. Nil logs to stderr with
// timestamps.
Logger *log.Logger
// Verbose also logs every heartbeat's hints.
Verbose bool
}
DoorbellConfig configures a Doorbell.
type DoorbellPusher ¶ added in v0.7.1
type DoorbellPusher interface {
SendHeartbeatWithHints(ctx context.Context, status *SensorStatus) (*HeartbeatHints, error)
}
DoorbellPusher is a Pusher whose heartbeat announces the doorbell and returns the hints. *client.Client implements it.
type EmbeddedTemplate ¶
type EmbeddedTemplate struct {
ID string `json:"id"`
Name string `json:"name"`
TemplateType string `json:"template_type"` // nuclei, semgrep, betterleaks
Content string `json:"content"` // Base64-encoded template content (YAML/TOML)
ContentHash string `json:"content_hash"` // SHA256 hash of decoded content for verification
}
EmbeddedTemplate is a custom template embedded in scan command payload. Templates are sent from the platform and written to temp dir before scan.
type Enricher ¶
type Enricher interface {
// Name returns the enricher name (e.g., "epss", "kev", "nvd")
Name() string
// Enrich adds threat intel to a single finding
Enrich(ctx context.Context, finding *ctis.Finding) (*ctis.Finding, error)
// EnrichBatch adds threat intel to multiple findings
EnrichBatch(ctx context.Context, findings []ctis.Finding) ([]ctis.Finding, error)
}
Enricher adds threat intelligence data to findings.
type EnricherConfig ¶
type EnricherConfig struct {
// API endpoint (optional, for custom sources)
Endpoint string `yaml:"endpoint" json:"endpoint"`
// Cache duration
CacheTTL time.Duration `yaml:"cache_ttl" json:"cache_ttl"`
// Rate limiting
RateLimit int `yaml:"rate_limit" json:"rate_limit"`
// Debug
Verbose bool `yaml:"verbose" json:"verbose"`
}
EnricherConfig holds enricher configuration.
type EnvelopeSignature ¶ added in v0.17.0
EnvelopeSignature is one signature of a SignedEnvelope.
type ExecConfig ¶
type ExecConfig struct {
Binary string // Scanner binary path
Args []string // Command arguments
WorkDir string // Working directory
Env map[string]string // Extra environment variables (added to the allowlisted base, see ScannerEnviron)
Timeout time.Duration // Execution timeout
Verbose bool // Stream output to logs
// MaxOutputBytes bounds the captured stdout; 0 means
// DefaultMaxScannerOutput. A scanner that writes more is stopped and the
// call returns ErrScannerOutputTooLarge.
MaxOutputBytes int64
// WritePaths are paths the scanner may write besides its private task
// directory, when the task sandbox is on (pkg/sensorkit/executor): an output
// file's directory, a cache the scanner owns. Everything else is
// read-only to it.
WritePaths []string
// Limits override the sandbox's default resource limits (zero fields:
// the defaults).
Limits executor.Limits
}
ExecConfig configures scanner execution.
type ExecResult ¶
type ExecResult struct {
ExitCode int
Stdout []byte
Stderr []byte
DurationMs int64
Error error
// Sandbox is the protection the scanner ran under (pkg/sensorkit/executor).
Sandbox executor.Status
}
ExecResult holds the result of scanner execution.
func ExecuteScanner ¶
func ExecuteScanner(ctx context.Context, cfg *ExecConfig) (*ExecResult, error)
ExecuteScanner runs a scanner binary with real-time output streaming. Its stdout is bounded by cfg.MaxOutputBytes (see ErrScannerOutputTooLarge) and its stderr by a fixed bound past which it is cut.
func StreamScanner ¶
func StreamScanner(ctx context.Context, cfg *ExecConfig, handler OutputHandler) (*ExecResult, error)
StreamScanner runs a scanner with real-time output handling: handler gets every line of stdout and stderr, without its line ending, whatever its length. Output is bounded as for ExecuteScanner.
type FileSettingsStore ¶ added in v0.16.0
type FileSettingsStore struct {
// contains filtered or unexported fields
}
FileSettingsStore keeps the document as SettingsFileName in a directory: the directory 0700, the file 0600, written to a temporary file, synced and renamed into place.
func NewFileSettingsStore ¶ added in v0.16.0
func NewFileSettingsStore(dir string) *FileSettingsStore
NewFileSettingsStore returns a store in dir (created 0700 on the first Save).
func (*FileSettingsStore) Load ¶ added in v0.16.0
func (s *FileSettingsStore) Load() (*SensorSettings, error)
Load implements SettingsStore.
func (*FileSettingsStore) Path ¶ added in v0.16.0
func (s *FileSettingsStore) Path() string
Path is the document's file.
func (*FileSettingsStore) Save ¶ added in v0.16.0
func (s *FileSettingsStore) Save(d *SensorSettings) error
Save implements SettingsStore.
type GetCommandsResponse ¶
type GetCommandsResponse struct {
Commands []*Command `json:"commands"`
PollIntervalSeconds int `json:"poll_interval_seconds,omitempty"`
}
GetCommandsResponse is the response from GetCommands.
type GitHubAlertInstance ¶
type GitHubAlertInstance struct {
Ref string `json:"ref"`
State string `json:"state"`
Location GitHubAlertLocation `json:"location"`
Message GitHubAlertMessage `json:"message"`
}
GitHubAlertInstance represents an instance of the alert.
type GitHubAlertLocation ¶
type GitHubAlertLocation struct {
Path string `json:"path"`
StartLine int `json:"start_line"`
EndLine int `json:"end_line"`
StartColumn int `json:"start_column"`
EndColumn int `json:"end_column"`
}
GitHubAlertLocation represents the location of the alert.
type GitHubAlertMessage ¶
type GitHubAlertMessage struct {
Text string `json:"text"`
}
GitHubAlertMessage represents the alert message.
type GitHubAlertRule ¶
type GitHubAlertRule struct {
ID string `json:"id"`
Severity string `json:"severity"`
SecuritySeverityLevel string `json:"security_severity_level"`
Description string `json:"description"`
Tags []string `json:"tags"`
}
GitHubAlertRule represents the rule that triggered the alert.
type GitHubAlertTool ¶
GitHubAlertTool represents the tool that found the alert.
type GitHubCodeScanningAlert ¶
type GitHubCodeScanningAlert struct {
Number int `json:"number"`
State string `json:"state"`
HTMLURL string `json:"html_url"`
Rule GitHubAlertRule `json:"rule"`
Tool GitHubAlertTool `json:"tool"`
MostRecentInstance GitHubAlertInstance `json:"most_recent_instance"`
CreatedAt string `json:"created_at"`
}
GitHubCodeScanningAlert represents a GitHub code scanning alert.
type GitHubCollector ¶
type GitHubCollector struct {
*BaseCollector
// contains filtered or unexported fields
}
GitHubCollector pulls security alerts from GitHub Advanced Security.
func NewGitHubCollector ¶
func NewGitHubCollector(cfg *GitHubCollectorConfig) *GitHubCollector
NewGitHubCollector creates a new GitHub collector.
func (*GitHubCollector) Collect ¶
func (c *GitHubCollector) Collect(ctx context.Context, opts *CollectOptions) (*CollectResult, error)
Collect pulls security alerts from GitHub.
type GitHubCollectorConfig ¶
type GitHubCollectorConfig struct {
Token string `yaml:"token" json:"token"`
Owner string `yaml:"owner" json:"owner"`
Repo string `yaml:"repo" json:"repo"`
Verbose bool `yaml:"verbose" json:"verbose"`
}
GitHubCollectorConfig configures a GitHub collector.
type HeartbeatAction ¶ added in v0.7.1
type HeartbeatAction string
HeartbeatAction is a typed directive the platform may send on a heartbeat.
const ( // HeartbeatActionPause: stop claiming and starting new jobs; running jobs // finish and heartbeats continue. Lifted by the first heartbeat answer // without pause (or by resume). HeartbeatActionPause HeartbeatAction = "pause" // HeartbeatActionResume lifts a pause explicitly. HeartbeatActionResume HeartbeatAction = "resume" // HeartbeatActionDrain is pause that is not lifted for the rest of the // process lifetime: the sensor finishes its running jobs and takes no // more until it is restarted. HeartbeatActionDrain HeartbeatAction = "drain" // HeartbeatActionRotateKey: the presented API key is inside its renewal // window; renew it now. HeartbeatActionRotateKey HeartbeatAction = "rotate_key" // HeartbeatActionUpdate: a newer sensor build is available. Only logged: // the SDK never downloads or executes anything because of it. HeartbeatActionUpdate HeartbeatAction = "update" // HeartbeatActionCancel: stop the commands listed in cancel_command_ids // (the poller cancels and releases them). HeartbeatActionCancel HeartbeatAction = "cancel" )
The closed set of heartbeat actions. Any other value is ignored.
const HeartbeatActionSendConfigReport HeartbeatAction = "send_config_report"
HeartbeatActionSendConfigReport: the platform does not have the config report this sensor's heartbeat names; send it again.
const HeartbeatActionSendManifest HeartbeatAction = "send_manifest"
HeartbeatActionSendManifest: the platform does not have the manifest this sensor's heartbeat names (api RFC-033); register it again.
type HeartbeatHints ¶ added in v0.7.1
type HeartbeatHints struct {
// Present is true when the response carried at least one doorbell field.
// A server that knows the doorbell answers every heartbeat of a
// doorbell-aware sensor with at least next_heartbeat_seconds.
Present bool
// PendingJobs is the number of jobs this sensor could claim now (0..100).
PendingJobs int
// NextHeartbeat is the advised delay before the next heartbeat, already
// clamped to [MinDoorbellHeartbeatInterval, MaxDoorbellHeartbeatInterval].
// Zero when not advised.
NextHeartbeat time.Duration
// Actions are the actions the server sent, unfiltered. Doorbell.Handle
// acts only on the known ones.
Actions []HeartbeatAction
// ConfigVersion is the opaque version of what the platform governs about
// this sensor, or "" when absent or malformed.
ConfigVersion string
// CancelCommandIDs are commands the platform canceled that this sensor
// may hold (cancel_command_ids, api RFC-030 §5.4): the poller stops
// them and releases them.
CancelCommandIDs []string
// StopCommandIDs are held commands the platform asks the sensor to stop
// and complete with what they finished (stop_command_ids: the task
// stalled). See ErrStoppedByPlatform.
StopCommandIDs []string
}
HeartbeatHints is the doorbell part of a heartbeat response. A server without the doorbell sends none of these fields; Present is then false.
func ParseHeartbeatHints ¶ added in v0.7.1
func ParseHeartbeatHints(body []byte) *HeartbeatHints
ParseHeartbeatHints reads the doorbell hints from a heartbeat response body. Fields outside their documented range are dropped, never trusted. A body that is not a JSON object yields no hints (Present=false).
type JSONParser ¶
type JSONParser struct{}
JSONParser parses generic JSON output that follows CTIS schema.
func (*JSONParser) CanParse ¶
func (p *JSONParser) CanParse(data []byte) bool
CanParse checks if this parser can handle the data.
func (*JSONParser) Parse ¶
func (p *JSONParser) Parse(ctx context.Context, data []byte, opts *ParseOptions) (*ctis.Report, error)
Parse converts JSON to CTIS format.
func (*JSONParser) SupportedFormats ¶
func (p *JSONParser) SupportedFormats() []string
SupportedFormats returns supported formats.
type JobGuard ¶ added in v0.19.0
type JobGuard struct {
// contains filtered or unexported fields
}
JobGuard decides whether a claimed command may run as far as its job signature goes. Build it with NewJobGuard and give it to the poller (CommandPoller.SetJobGuard).
func NewJobGuard ¶ added in v0.19.0
NewJobGuard returns a guard for this sensor (tenantID, sensorID) that verifies with v (nil: no key pinned) and, when required, refuses commands without a valid signature. A guard that verifies needs both ids; a required guard needs a verifier.
func (*JobGuard) Check ¶ added in v0.19.0
Check verifies cmd's signed job. nil: the command may run. A refusal is a *LocalPolicyError (layer builtin, rule job_signature).
func (*JobGuard) SetConfigVersion ¶ added in v0.19.0
SetConfigVersion gives the guard the platform's current config_version (Doorbell.ConfigVersion). A new job-signing key set changes it, and the guard then fetches the key set again before it checks the next command, so a rotated or revoked signer key takes effect without a restart.
type JobsPosture ¶ added in v0.19.0
type JobsPosture struct {
// Signed is JobsSignedRequired, JobsSignedVerifiedWhenPresent or
// JobsSignedOff.
Signed string `json:"signed"`
// Root is the pinned job-signing root key id; "" when none is pinned.
Root string `json:"root,omitempty"`
// KeySetVersion and KeySetExpiresAt describe the accepted key set of
// the pinned root (absent without one): the sensor refuses every signed
// job once it expires, until the platform deploys a new one.
KeySetVersion uint64 `json:"keyset_version,omitempty"`
KeySetExpiresAt *time.Time `json:"keyset_expires_at,omitempty"`
}
JobsPosture is the sensor's signed-job checking (api RFC-040 §5.6).
type LimitedCommandClient ¶ added in v0.10.0
type LimitedCommandClient interface {
GetCommandsLimit(ctx context.Context, limit int) (*GetCommandsResponse, error)
}
LimitedCommandClient is a CommandClient that can poll for at most limit commands. The CommandPoller uses it, when the client implements it, to ask for no more commands than it has free slots (api RFC-030 §5.9), so the platform keeps the rest for sensors that can run them now. *client.Client implements it.
type LiveHost ¶
type LiveHost struct {
URL string `json:"url"` // Full URL (https://example.com)
Host string `json:"host"` // Hostname
IP string `json:"ip,omitempty"` // Resolved IP
Port int `json:"port,omitempty"` // Port number
Scheme string `json:"scheme"` // http or https
StatusCode int `json:"status_code"` // HTTP status code
ContentLength int64 `json:"content_length,omitempty"` // Response size
Title string `json:"title,omitempty"` // Page title
WebServer string `json:"web_server,omitempty"` // Server header
ContentType string `json:"content_type,omitempty"` // Content-Type header
Technologies []string `json:"technologies,omitempty"` // Detected technologies
CDN string `json:"cdn,omitempty"` // CDN provider
TLSVersion string `json:"tls_version,omitempty"` // TLS version
Redirect string `json:"redirect,omitempty"` // Final redirect URL
ResponseTime int64 `json:"response_time_ms"` // Response time in ms
// What the probe learned about the server (all optional; the values are
// chosen by the scanned server and bounded by ctis.ConvertReconToCTIS).
CDNType string `json:"cdn_type,omitempty"` // cdn, waf or cloud
TLS *TLSLeaf `json:"tls,omitempty"` // Leaf certificate of the TLS handshake
FaviconMMH3 string `json:"favicon_mmh3,omitempty"` // mmh3 favicon hash (signed 32-bit decimal)
JARM string `json:"jarm,omitempty"` // JARM TLS server fingerprint
ASN *ASN `json:"asn,omitempty"` // Autonomous system of the host's address
}
LiveHost represents an HTTP/HTTPS live host.
type LoadReporter ¶ added in v0.10.0
LoadReporter reports how busy a sensor is: the commands it runs now and how many it runs at once. A BaseSensor with a LoadReporter (BaseSensor.SetLoadReporter) puts both on every heartbeat. *CommandPoller implements it.
type LocalPolicy ¶ added in v0.18.0
type LocalPolicy struct {
// contains filtered or unexported fields
}
LocalPolicy is the loaded sensor-local policy. It is immutable once loaded; only the kill switch file is read live. A nil *LocalPolicy, like an absent one, restricts nothing but the built-in deny list.
func LoadLocalPolicy ¶ added in v0.18.0
func LoadLocalPolicy(opts LocalPolicyOptions) (*LocalPolicy, error)
LoadLocalPolicy loads the sensor-local policy: the file at opts.Path, else at SENSOR_LOCAL_POLICY, else at DefaultLocalPolicyPath when it exists; without a file, the SENSOR_ALLOWED_RANGES / SENSOR_ALLOWED_PORTS shorthands; without those, an absent policy (Present false) that still honors SENSOR_KILL_SWITCH_FILE. Any error means the sensor must not start.
func ParseLocalPolicy ¶ added in v0.18.0
func ParseLocalPolicy(data []byte, opts LocalPolicyOptions) (*LocalPolicy, error)
ParseLocalPolicy parses and validates a policy document (the content of the policy file). The private-range switch (SENSOR_ALLOW_PRIVATE_TARGETS) is read from opts.LookupEnv: a private target is allowed only when both the switch and targets.allow_private allow it.
func ReloadLocalPolicy ¶ added in v0.18.0
func ReloadLocalPolicy(prev *LocalPolicy, opts LocalPolicyOptions) (*LocalPolicy, error)
ReloadLocalPolicy re-reads the local policy (on SIGHUP; owner decision D10, api research/25 §4.2). A policy that loads replaces prev. One that does not load (a typo, a world-writable file, a missing file that was configured) does not leave the previous policy running: that may be the looser one the owner just tried to tighten. The result is prev with the kill switch engaged and a warning naming the error, so every job stops and the platform sees why, until a reload succeeds. The error is returned for the log.
func (*LocalPolicy) AcceptsManagedPolicy ¶ added in v0.18.0
func (lp *LocalPolicy) AcceptsManagedPolicy() bool
AcceptsManagedPolicy reports whether the sensor owner lets the platform narrow this policy with a managed document (v2 managed.accept; true without a policy or the key). A managed policy never widens the local one; this only decides whether it is read at all (owner decision D11).
func (*LocalPolicy) AdmitCommand ¶ added in v0.18.0
func (lp *LocalPolicy) AdmitCommand(ctx context.Context, cmd *Command) error
AdmitCommand decides whether cmd may run under the local policy, before any tool sees it: the kill switch, checks.allow (the command type), tools.allow, allow_custom_templates, allow_interactsh, and every target against targets.allow/deny, the private-range switch, the built-in deny list (host names are resolved; every address must pass) and ports.allow. A single violation refuses the whole job with a *LocalPolicyError naming the rule; nothing in the payload can widen the policy. Without a policy the kill switch applies, and a sensor that requires a policy refuses every job with a network target, custom templates or callbacks (rule no_local_policy); a legacy install admits the rest. AdmitCommandTargets is the same check that removes refused targets from a scan job instead of refusing all of it.
func (*LocalPolicy) AdmitCommandTargets ¶ added in v0.19.0
func (lp *LocalPolicy) AdmitCommandTargets(ctx context.Context, cmd *Command) (*CommandAdmission, error)
AdmitCommandTargets is AdmitCommand that refuses per target: in a scan job, a target the policy refuses or cannot check (it does not resolve, it is a wildcard pattern) is removed from cmd.Payload and listed with its reason, and the job runs on the rest. It refuses the whole command, with a *LocalPolicyError, when a job-wide rule refuses it (kill switch, checks.allow, tools.allow, templates, callbacks, the ports setting, an unreadable payload), when every target is refused, when the target the job runs on alone (payload "target") is refused, and for every other command type (a retest or a validation names its targets in items the sensor does not rewrite). The admission is returned with the error too, so the refusal can list every target.
It rewrites cmd.Payload only when it removed targets. A removed target is never handed to an executor or a tool.
func (*LocalPolicy) AdmittedAddrs ¶ added in v0.19.0
AdmittedAddrs checks a host name or address as CheckTarget does and returns the addresses it checked: a confined task's forwarder dials a target at these addresses only, never at what the name resolves to later. Without a policy the name is resolved and every address returned (the forwarder still refuses metadata and link-local ones).
func (*LocalPolicy) AllowsCheck ¶ added in v0.18.0
func (lp *LocalPolicy) AllowsCheck(commandType string) bool
AllowsCheck reports whether checks.allow lets a command type run. health_check touches no target and is always allowed.
func (*LocalPolicy) AllowsCustomTemplates ¶ added in v0.18.0
func (lp *LocalPolicy) AllowsCustomTemplates() bool
AllowsCustomTemplates reports whether jobs may carry platform-supplied custom templates (still only signed ones). Without a policy: true on a legacy install (owner decision Q4 (a)), false when a policy is required; a policy allows them only with allow_custom_templates.
func (*LocalPolicy) AllowsInteractsh ¶ added in v0.18.0
func (lp *LocalPolicy) AllowsInteractsh() bool
AllowsInteractsh reports whether a job may turn on out-of-band callbacks. Without a policy: true on a legacy install (Q4 (a)), false when a policy is required; a policy allows them only with allow_interactsh.
func (*LocalPolicy) AllowsTool ¶ added in v0.18.0
func (lp *LocalPolicy) AllowsTool(tool string) bool
AllowsTool reports whether tools.allow lets tool run (always without a policy or a tools section).
func (*LocalPolicy) CapRate ¶ added in v0.18.0
func (lp *LocalPolicy) CapRate(requested int) int
CapRate returns the requests-per-second a scan runs with under the policy's rate.max_rps: requested when set and lower, else the maximum. Without a maximum it returns requested.
func (*LocalPolicy) CapTimeout ¶ added in v0.18.0
func (lp *LocalPolicy) CapTimeout(requested time.Duration) time.Duration
CapTimeout returns how long a job may run: requested (0: no limit asked) capped at MaxScanTimeout and at the policy's rate.max_job_seconds.
func (*LocalPolicy) CheckDial ¶ added in v0.18.0
CheckDial is the egress hook (api RFC-034's in-sensor forwarder, and any in-process dial a tool makes): it checks a connection to address ("host:port") and returns the addresses the connection may use. Callers must connect to one of them, never resolve the name again (that is what defeats DNS rebinding). The built-in deny list applies even without a policy; with one, ports.allow and the target rules apply too. A sensor that requires a policy and has none refuses every dial.
func (*LocalPolicy) CheckTarget ¶ added in v0.18.0
func (lp *LocalPolicy) CheckTarget(ctx context.Context, target string) error
CheckTarget checks one job target (URL, host, host:port, IP, CIDR) against the policy. Host names are resolved and every address must pass, so a name that resolves to a denied address is refused. Filesystem targets are not network targets; the scan workspace confines them.
Without a policy, a sensor that requires one refuses every network target (rule no_local_policy); a legacy install still applies the built-in deny list (loopback, link-local and metadata, multicast, unspecified, CGNAT, reserved, and private ranges unless the private-range switch allows them), so a caller that checks a target directly (a retest, a tool task) never reaches those addresses.
func (*LocalPolicy) CommandWarnings ¶ added in v0.18.0
func (lp *LocalPolicy) CommandWarnings(cmd *Command) []string
CommandWarnings are what the sensor logs about cmd when no policy decides for it: a job that uses custom templates or out-of-band callbacks only because no local policy forbids them (owner decision Q4 (a)).
func (*LocalPolicy) Describe ¶ added in v0.18.0
func (lp *LocalPolicy) Describe() string
Describe is a one-line description of the policy for the startup log.
func (*LocalPolicy) DialContext ¶ added in v0.18.0
func (lp *LocalPolicy) DialContext(d *net.Dialer) func(ctx context.Context, network, address string) (net.Conn, error)
DialContext wraps d (nil: a zero net.Dialer) with CheckDial: it checks every connection against the policy and dials the checked addresses, in order, never the name. Use it for in-process scanners and the egress forwarder.
func (*LocalPolicy) Digest ¶ added in v0.18.0
func (lp *LocalPolicy) Digest() string
Digest is the policy's digest ("sha256:…" of the file bytes), "" when absent.
func (*LocalPolicy) HTTPPolicy ¶ added in v0.19.0
func (lp *LocalPolicy) HTTPPolicy() (userAgent string, allowInsecureTLS bool)
HTTPPolicy is what the policy decides about the tools' requests: a User-Agent that replaces every tool's ("" none), and whether a tool may skip TLS verification toward its targets. Without a policy: none, yes.
func (*LocalPolicy) KillSwitchEngaged ¶ added in v0.18.0
func (lp *LocalPolicy) KillSwitchEngaged() bool
KillSwitchEngaged reports whether the sensor owner stopped every job: the policy's kill_switch, or a kill switch file that exists. A file that cannot be checked (permission denied) counts as present.
func (*LocalPolicy) NetworkScope ¶ added in v0.25.0
func (lp *LocalPolicy) NetworkScope() netctx.Scope
NetworkScope is what the sensor's network report may name (netctx.Scope): the policy's targets.allow ranges (when the policy has an allow list), its targets.deny ranges and whether private targets are allowed. A sensor that requires a policy and has none may name no prefix at all. The report is never wider than what this sensor would scan.
func (*LocalPolicy) Path ¶ added in v0.18.0
func (lp *LocalPolicy) Path() string
Path is the policy file, "" without one.
func (*LocalPolicy) Present ¶ added in v0.18.0
func (lp *LocalPolicy) Present() bool
Present reports whether a policy is loaded (from a file or the shorthands). An absent policy restricts nothing but the kill switch.
func (*LocalPolicy) Report ¶ added in v0.18.0
func (lp *LocalPolicy) Report() *LocalPolicyReport
Report is the policy's state now (the kill switch is read live).
func (*LocalPolicy) Required ¶ added in v0.19.0
func (lp *LocalPolicy) Required() bool
Required reports whether the sensor requires a local policy: without one it refuses every job with network targets (rule no_local_policy), custom templates and out-of-band callbacks. False is a legacy install, which without a policy admits any target outside the built-in deny list.
func (*LocalPolicy) Schema ¶ added in v0.18.0
func (lp *LocalPolicy) Schema() string
Schema is the policy file's schema version ("v1", "v2"), "" without a file.
func (*LocalPolicy) Warnings ¶ added in v0.18.0
func (lp *LocalPolicy) Warnings() []string
Warnings are what an operator should know about the policy (absent, a switch that cannot take effect). The sensor logs them at start and reports them on the heartbeat.
func (*LocalPolicy) WithRequired ¶ added in v0.19.0
func (lp *LocalPolicy) WithRequired(required bool) *LocalPolicy
WithRequired returns a copy of lp (of the absent policy when lp is nil) that requires a local policy or not. The copy shares lp's lists, which are never modified after loading.
type LocalPolicyError ¶ added in v0.18.0
type LocalPolicyError struct {
// Layer is the policy layer that refused (RefusalLayer*); "" is the
// local policy.
Layer string
Rule string
Detail string
}
LocalPolicyError is a job refused by the local policy: Rule names the policy key that refused it (targets.allow, ports.allow, kill_switch, …) and Detail the offending item. Its text is what the platform shows: "refused by local policy: <rule>: <detail>".
func (*LocalPolicyError) Error ¶ added in v0.18.0
func (e *LocalPolicyError) Error() string
func (*LocalPolicyError) Unwrap ¶ added in v0.18.0
func (e *LocalPolicyError) Unwrap() error
Unwrap makes errors.Is(err, ErrRefusedByLocalPolicy) true.
type LocalPolicyOptions ¶ added in v0.18.0
type LocalPolicyOptions struct {
// Path is the policy file (a sensor's flag). "" reads EnvLocalPolicy,
// then DefaultPath when that file exists. A path given here or in the
// environment must exist.
Path string
// DefaultPath replaces DefaultLocalPolicyPath (tests).
DefaultPath string
// LookupEnv reads the environment (nil: os.LookupEnv).
LookupEnv func(string) (string, bool)
// LookupIP resolves host names for target checks (nil:
// net.DefaultResolver).
LookupIP func(ctx context.Context, host string) ([]net.IP, error)
// Required makes a sensor without a policy fail closed (see
// LocalPolicy.Required). EnvRequireLocalPolicy, when set, wins.
Required bool
}
LocalPolicyOptions say where LoadLocalPolicy finds the policy.
type LocalPolicyReport ¶ added in v0.18.0
type LocalPolicyReport struct {
// State is LocalPolicyStateEnforced or LocalPolicyStateAbsent.
State string `json:"state"`
// Required is true when the sensor requires a local policy (new
// installs): absent, it refuses every job with network targets. State
// absent with Required false is a legacy install that admits any
// target outside the built-in deny list. Always sent; an SDK that
// predates it sends none, which reads as false.
Required bool `json:"required"`
// Source is LocalPolicySourceFile or LocalPolicySourceEnv ("" when
// absent).
Source string `json:"source,omitempty"`
// Digest is the policy's sha256 digest ("" when absent).
Digest string `json:"digest,omitempty"`
// KillSwitch is true while the sensor owner has stopped every job.
KillSwitch bool `json:"kill_switch,omitempty"`
// Summary is set when a policy is enforced.
Summary *LocalPolicySummary `json:"summary,omitempty"`
// Warnings are the operator warnings (see LocalPolicy.Warnings).
Warnings []string `json:"warnings,omitempty"`
// Schema is the policy file's schema version ("v1", "v2"); "" without
// a file.
Schema string `json:"schema,omitempty"`
// Schemas are the schema versions this sensor reads
// (LocalPolicySchemas): the platform generates a recommended policy
// only in one of them.
Schemas []string `json:"schemas,omitempty"`
}
LocalPolicyReport is what the sensor tells the platform about its local policy: the state, the digest and a summary, never the ranges themselves. The platform shows it; enforcement stays on the sensor.
type LocalPolicySummary ¶ added in v0.18.0
type LocalPolicySummary struct {
// TargetsAllow is the number of targets.allow entries; -1 when the
// policy sets no allow list (any target outside the deny lists).
TargetsAllow int `json:"targets_allow"`
// TargetsDeny is the number of targets.deny entries.
TargetsDeny int `json:"targets_deny"`
// AllowPrivate: private ranges may be scanned (the policy and the
// private-range switch agree).
AllowPrivate bool `json:"allow_private"`
// Ports is ports.allow ("" = any port).
Ports string `json:"ports,omitempty"`
// Tools and Checks are tools.allow and checks.allow (absent = any).
Tools []string `json:"tools,omitempty"`
Checks []string `json:"checks,omitempty"`
// AllowCustomTemplates and AllowInteractsh are the policy's switches.
AllowCustomTemplates bool `json:"allow_custom_templates"`
AllowInteractsh bool `json:"allow_interactsh"`
// MaxRPS and MaxJobSeconds are rate.max_rps and rate.max_job_seconds
// (0 = not set).
MaxRPS int `json:"max_rps,omitempty"`
MaxJobSeconds int `json:"max_job_seconds,omitempty"`
// ManagedAccept is managed.accept (v2): false when the sensor owner
// refuses platform-managed policy documents.
ManagedAccept bool `json:"managed_accept"`
// HTTPUserAgent is http.user_agent (v3): the User-Agent forced on
// every tool ("" none). AllowInsecureTLS is http.allow_insecure_tls.
HTTPUserAgent string `json:"http_user_agent,omitempty"`
AllowInsecureTLS bool `json:"allow_insecure_tls"`
}
LocalPolicySummary is the shape of an enforced policy: counts for the target lists, the lists that routing needs (tools, check types), and the switches.
type Logger ¶
type Logger interface {
// Debug logs a debug message
Debug(format string, args ...interface{})
// Info logs an info message
Info(format string, args ...interface{})
// Warn logs a warning message
Warn(format string, args ...interface{})
// Error logs an error message
Error(format string, args ...interface{})
}
Logger is the interface for logging in the SDK. Implement this interface to use a custom logger (e.g., logrus, zap).
func GetDefaultLogger ¶
func GetDefaultLogger() Logger
GetDefaultLogger returns the global default logger.
func LoggerFromVerbose ¶
LoggerFromVerbose creates a logger based on verbose flag. If verbose is true, returns a PrintfLogger, otherwise returns NopLogger.
type Manifest ¶ added in v0.14.0
type Manifest struct {
Schema int `json:"schema"`
Sensor *SensorBuild `json:"sensor,omitempty"`
SDK *SDKInfo `json:"sdk,omitempty"`
Platform *ManifestPlatform `json:"platform,omitempty"`
Resources *ManifestResources `json:"resources,omitempty"`
Concurrency *ManifestConcurrency `json:"concurrency,omitempty"`
Capabilities []string `json:"capabilities,omitempty"`
Tools []ManifestTool `json:"tools"`
// LocalPolicy is the sensor-local policy's state, digest and summary
// (api RFC-040 §5.7), without the live kill switch (the heartbeat
// carries that). The API client sends it only to a platform that lists
// the "local_policy" feature.
LocalPolicy *LocalPolicyReport `json:"local_policy,omitempty"`
// Posture is the sensor's platform TLS pin and tool sandbox
// (SensorPosture; BaseSensor.SetPosture). The API client sends it only
// to a platform that lists the "posture" feature.
Posture *SensorPosture `json:"posture,omitempty"`
// Network is the sensor's network self-description (netctx.Report:
// declared and detected facts, fingerprint, internet mode;
// BaseSensor.SetNetworkReporter). The API client sends it only to a
// platform that lists the "network" feature.
Network *netctx.Report `json:"network,omitempty"`
}
Manifest is a sensor's self-description (api RFC-033 §6.2).
func BuildManifest ¶ added in v0.14.0
func BuildManifest(status *SensorStatus, res *resource.HostResources, model string) Manifest
BuildManifest builds the manifest of a heartbeat status that already carries the capability report (BaseSensor.withCapabilities): its tools, the capabilities no installed tool provides (sensor-wide), the operator's ceiling, the build and the platform. res, when known, gives the resources; model is ConcurrencyModelDynamic when a resource manager sizes the slots.
func (Manifest) Digest ¶ added in v0.14.0
Digest is "sha256:" + the hex SHA-256 of the manifest's canonical JSON (object members sorted, no whitespace, no HTML escaping), the form the platform digests. The sensor uses it to notice its own changes; the heartbeat echoes the digest the platform returned.
type ManifestAck ¶ added in v0.14.0
type ManifestAck struct {
// Digest is what the platform stored; heartbeats echo it.
Digest string
// Changed is false when the platform already had it.
Changed bool
// AcceptedTools and AcceptedCapabilities are what the platform kept.
AcceptedTools []string
AcceptedCapabilities []string
// Ignored lists what it dropped and why.
Ignored []ManifestIgnored
// Policy is what the platform lets the sensor run (api RFC-033 §6.12);
// nil from a platform that does not say. The BaseSensor refuses
// commands for tools outside it (CommandToolGate).
Policy *ManifestPolicy
// OmitInventory: heartbeats that echo Digest may leave the tool
// inventory out and carry only each tool's content freshness.
OmitInventory bool
}
ManifestAck is the platform's answer to a registered manifest.
type ManifestConcurrency ¶ added in v0.14.0
type ManifestConcurrency struct {
Ceiling int `json:"ceiling"`
Model string `json:"model,omitempty"`
}
ManifestConcurrency is the operator's ceiling (0: none) and the model.
type ManifestContent ¶ added in v0.14.0
type ManifestContent struct {
Name string `json:"name"`
Version string `json:"version,omitempty"`
Digest string `json:"digest,omitempty"`
Source string `json:"source,omitempty"`
Managed bool `json:"managed"`
}
ManifestContent is a tool's content version, without the timestamps (they change on every refresh and stay on the heartbeat).
type ManifestIgnored ¶ added in v0.14.0
type ManifestIgnored struct {
Path string `json:"path"`
Value string `json:"value,omitempty"`
Reason string `json:"reason"`
}
ManifestIgnored is one manifest item the platform dropped.
type ManifestPlatform ¶ added in v0.14.0
type ManifestPlatform struct {
OS string `json:"os,omitempty"`
Arch string `json:"arch,omitempty"`
}
ManifestPlatform is the operating system and architecture.
type ManifestPolicy ¶ added in v0.15.0
ManifestPolicy is the sensor's effective tools, capabilities and capacity as the platform computes them (the sensor's report narrowed by the administrator's settings).
type ManifestPusher ¶ added in v0.14.0
type ManifestPusher interface {
PutManifest(ctx context.Context, m *Manifest) (*ManifestAck, error)
}
ManifestPusher is implemented by a Pusher that can register a manifest (client.Client on protocol v2).
type ManifestResources ¶ added in v0.14.0
type ManifestResources struct {
CPUCores float64 `json:"cpu_cores,omitempty"`
MemTotalBytes int64 `json:"mem_total_bytes,omitempty"`
}
ManifestResources is what the sensor may use (container limits when it runs in one).
type ManifestStateReader ¶ added in v0.15.0
type ManifestStateReader interface {
GetManifestState(ctx context.Context) (*ManifestAck, error)
}
ManifestStateReader is implemented by a Pusher that can re-read the platform's view of the registered manifest (GET /manifest): the digest, the policy as it stands now and the heartbeat form. The BaseSensor calls it when the heartbeat's config_version changes. ErrManifestNotRegistered means the platform has no manifest for the sensor.
type ManifestTemplate ¶ added in v0.17.0
type ManifestTemplate struct {
ID string `json:"id"`
Name string `json:"name"`
TemplateType string `json:"template_type"`
SHA256 string `json:"sha256"` // hex, of the decoded content
}
ManifestTemplate is one template in a TemplateManifest.
type ManifestTool ¶ added in v0.14.0
type ManifestTool struct {
Name string `json:"name"`
Kind ToolKind `json:"kind,omitempty"`
Version string `json:"version,omitempty"`
Installed bool `json:"installed"`
Capabilities []string `json:"capabilities,omitempty"`
TargetTypes []string `json:"target_types,omitempty"`
Content []ManifestContent `json:"content,omitempty"`
// Settings identifies the tool's settings schema (api RFC-038): its
// version and digest only; the platform fetches a schema it does not
// have by digest. Absent for a tool without settings.
Settings *ManifestToolSettings `json:"settings,omitempty"`
// Contract names the tool's tool.yaml manifest by digest, with the
// fields the platform plans with (class, tier, network, consumes,
// produces). Absent for a tool not ported to the tool contract.
Contract *ToolContract `json:"contract,omitempty"`
}
ManifestTool is one registered tool.
type ManifestToolSettings ¶ added in v0.16.0
type ManifestToolSettings struct {
SchemaVersion int `json:"schema_version"`
Digest string `json:"digest"`
}
ManifestToolSettings is a tool's settings schema as the manifest names it.
type MultiTargetScanner ¶ added in v0.7.0
type MultiTargetScanner interface {
Scanner
ScanTargets(ctx context.Context, targets []string, opts *ScanOptions) (*ScanResult, error)
}
MultiTargetScanner is a Scanner that can scan a list of targets in one run (nuclei with -l). The command executor uses it when a scan command carries several targets.
type NetworkReporter ¶ added in v0.25.0
NetworkReporter supplies the sensor's network self-description (netctx.Watcher implements it). Report returns nil until the first detection, and never modifies a report it returned.
type OAuthConfig ¶
type OAuthConfig struct {
ClientID string `yaml:"client_id" json:"client_id"`
ClientSecret string `yaml:"client_secret" json:"client_secret"`
TokenURL string `yaml:"token_url" json:"token_url"`
Scopes []string `yaml:"scopes" json:"scopes"`
}
OAuthConfig holds OAuth configuration.
type OpenPort ¶
type OpenPort struct {
Host string `json:"host"` // IP or hostname
IP string `json:"ip,omitempty"` // IP address
Port int `json:"port"` // Port number
Protocol string `json:"protocol,omitempty"` // tcp, udp
Service string `json:"service,omitempty"` // Detected service name
Version string `json:"version,omitempty"` // Service version
Banner string `json:"banner,omitempty"` // Service banner
}
OpenPort represents an open port on a host.
type OrgHTTPPolicy ¶ added in v0.19.0
type OrgHTTPPolicy struct {
// UserAgent replaces the tools' User-Agent unless the local policy forces
// one ("" none).
UserAgent string `json:"user_agent,omitempty"`
// AllowInsecureTLS false refuses tools whose tool.yaml skips TLS
// verification; nil leaves it to the local policy.
AllowInsecureTLS *bool `json:"allow_insecure_tls,omitempty"`
// Headers are sent on every request of the job's tools: the
// identification a bug-bounty program requires of its researchers
// (api RFC-065), for example "X-Bug-Bounty: <handle>". They replace a
// tool.yaml header of the same name. Credentials and the headers the
// HTTP client and the forwarder own are refused.
Headers map[string]string `json:"headers,omitempty"`
}
OrgHTTPPolicy is what the organization decides about its tools' requests (api RFC-060 §4.1, the tenant layer). The platform sends it with each scan job. It can only narrow: the sensor-local policy decides first, and a tool that skips TLS verification is refused when either layer forbids it.
func (*OrgHTTPPolicy) Validate ¶ added in v0.19.0
func (p *OrgHTTPPolicy) Validate() error
Validate accepts a User-Agent of printable ASCII up to 256 bytes and at most 10 headers: token names, printable ASCII values up to 200 bytes, no credential or connection header.
type OutputHandler ¶
OutputHandler processes scanner output in real-time.
type Package ¶
type Package struct {
ID string `json:"id"` // Package URL or unique identifier
Name string `json:"name"` // Package name
Version string `json:"version"` // Installed version
Type string `json:"type"` // npm, maven, pip, etc.
Licenses []string `json:"licenses"` // License identifiers
PURL string `json:"purl"` // Package URL (purl spec)
}
Package represents a software package.
type PackageDependency ¶
type PackageDependency struct {
PackageID string `json:"package_id"` // Parent package
Dependencies []string `json:"dependencies"` // Child package IDs
}
PackageDependency represents a dependency relationship.
type PackageType ¶
type PackageType string
PackageType represents the package ecosystem.
const ( PackageTypeMaven PackageType = "maven" PackageTypeNPM PackageType = "npm" PackageTypePyPI PackageType = "pip" PackageTypeGo PackageType = "gomod" PackageTypeCargo PackageType = "cargo" PackageTypeNuGet PackageType = "nuget" PackageTypeGem PackageType = "gem" PackageTypeComposer PackageType = "composer" )
func DetectPackageType ¶
func DetectPackageType(filename string) PackageType
DetectPackageType detects the package type from a manifest file.
type ParseOptions ¶
type ParseOptions struct {
// Tool information
ToolName string `json:"tool_name"`
ToolType string `json:"tool_type"` // sast, sca, secret, iac, web3
// Asset information
AssetType ctis.AssetType `json:"asset_type"`
AssetValue string `json:"asset_value"`
AssetID string `json:"asset_id"`
// Git information (legacy - use BranchInfo for full context)
Branch string `json:"branch"`
CommitSHA string `json:"commit_sha"`
// Branch information for branch-aware finding lifecycle
// Provides full CI/CD context for auto-resolve and expiry features
BranchInfo *ctis.BranchInfo `json:"branch_info,omitempty"`
// BasePath is the root directory of the scanned codebase.
// Used to resolve relative file paths when reading snippets from source files.
BasePath string `json:"base_path,omitempty"`
// Defaults
DefaultConfidence int `json:"default_confidence"`
}
ParseOptions configures parsing.
type Parser ¶
type Parser interface {
// Name returns the parser name (e.g., "sarif", "json", "custom-trivy")
Name() string
// SupportedFormats returns the output formats this parser can handle
SupportedFormats() []string
// Parse converts raw output to CTIS report
Parse(ctx context.Context, data []byte, opts *ParseOptions) (*ctis.Report, error)
// CanParse checks if the parser can handle the given data
CanParse(data []byte) bool
}
Parser converts scanner output to CTIS format. Implement this interface to support custom output formats.
type ParserRegistry ¶
type ParserRegistry struct {
// contains filtered or unexported fields
}
ParserRegistry manages registered parsers.
func NewParserRegistry ¶
func NewParserRegistry() *ParserRegistry
NewParserRegistry creates a new parser registry with built-in parsers.
func (*ParserRegistry) FindParser ¶
func (r *ParserRegistry) FindParser(data []byte) Parser
FindParser finds a parser that can handle the given data. Parsers are probed in registration order, after the generic SARIF and JSON parsers that NewParserRegistry registers, so a tool-specific parser registered later wins only when the generic formats do not match.
func (*ParserRegistry) ForScanner ¶ added in v0.7.0
func (r *ParserRegistry) ForScanner(scannerName string, data []byte) (Parser, error)
ForScanner returns the parser for a scanner's raw output, or an error when no parser recognizes it.
Selection order: the parser registered under the scanner's own name (when it accepts the data), then content detection, then nothing. Output that no parser recognizes is an error, never "0 findings": a scanner whose results cannot be read must fail its command, or real findings vanish while the scan reports success. Callers decide what empty output means before calling.
func (*ParserRegistry) Get ¶
func (r *ParserRegistry) Get(name string) Parser
Get returns a parser by name.
func (*ParserRegistry) List ¶
func (r *ParserRegistry) List() []string
List returns all registered parser names.
func (*ParserRegistry) Register ¶
func (r *ParserRegistry) Register(parser Parser)
Register adds a parser to the registry. Registering a name again replaces that parser and keeps its original position.
type PerTargetOptions ¶ added in v0.26.0
type PerTargetOptions struct {
// Timeout is each target's budget; 0 runs a target until the job's
// context ends.
Timeout time.Duration
// Concurrency is how many targets run at once; < 1 is 1.
Concurrency int
}
PerTargetOptions configure RunPerTarget.
type PlatformTLSPosture ¶ added in v0.19.0
type PlatformTLSPosture struct {
// Pin is TLSPinFingerprint, TLSPinCAFile or TLSPinNone.
Pin string `json:"pin"`
}
PlatformTLSPosture is the platform TLS pin of the sensor's HTTPS requests (the gRPC transport always pins its own CA bundle, which it fetches over these requests).
type PrintfLogger ¶
type PrintfLogger struct {
// contains filtered or unexported fields
}
PrintfLogger is a simple logger that uses fmt.Printf. This is what the verbose mode was using before.
func NewPrintfLogger ¶
func NewPrintfLogger(prefix string) *PrintfLogger
NewPrintfLogger creates a new printf logger.
func (*PrintfLogger) Debug ¶
func (l *PrintfLogger) Debug(format string, args ...interface{})
func (*PrintfLogger) Error ¶
func (l *PrintfLogger) Error(format string, args ...interface{})
func (*PrintfLogger) Info ¶
func (l *PrintfLogger) Info(format string, args ...interface{})
func (*PrintfLogger) Warn ¶
func (l *PrintfLogger) Warn(format string, args ...interface{})
type ProcessOptions ¶
type ProcessOptions struct {
// Scan options
ScanOptions *ScanOptions `yaml:"scan" json:"scan"`
// Parse options
ParseOptions *ParseOptions `yaml:"parse" json:"parse"`
// Push options
Push bool `yaml:"push" json:"push"`
SaveLocal bool `yaml:"save_local" json:"save_local"`
OutputDir string `yaml:"output_dir" json:"output_dir"`
// Retry
MaxRetries int `yaml:"max_retries" json:"max_retries"`
RetryDelay int `yaml:"retry_delay_seconds" json:"retry_delay_seconds"`
}
ProcessOptions configures the processing workflow.
type ProcessResult ¶
type ProcessResult struct {
// Scanner info
ScannerName string `json:"scanner_name"`
// Scan result
ScanResult *ScanResult `json:"scan_result"`
// Parsed report
Report *ctis.Report `json:"report,omitempty"`
// Push result
PushResult *PushResult `json:"push_result,omitempty"`
// Local file if saved
LocalFile string `json:"local_file,omitempty"`
// Error
Error string `json:"error,omitempty"`
}
ProcessResult holds the result of a complete processing workflow.
type Processor ¶
type Processor interface {
// Process runs a complete scan workflow
Process(ctx context.Context, scanner Scanner, opts *ProcessOptions) (*ProcessResult, error)
// ProcessBatch runs multiple scanners in parallel
ProcessBatch(ctx context.Context, scanners []Scanner, opts *ProcessOptions) ([]*ProcessResult, error)
}
Processor orchestrates the complete workflow: scan -> parse -> push.
type Progress ¶ added in v0.26.0
type Progress struct {
// contains filtered or unexported fields
}
Progress records a job's finished targets. Safe for concurrent use; nil is usable (it records nothing).
func NewProgress ¶ added in v0.26.0
NewProgress returns a Progress over total targets (names unknown).
func ProgressFrom ¶ added in v0.26.0
ProgressFrom returns the job's Progress, or nil outside a job.
func (*Progress) DoneN ¶ added in v0.26.0
DoneN counts n finished targets a tool reports without names.
func (*Progress) RecordOutput ¶ added in v0.28.0
RecordOutput counts records the tool's output delivered, of n bytes in all (a liveness counter).
func (*Progress) SetTargets ¶ added in v0.26.0
SetTargets sets the job's target list once it is known: the total, and the indexes finished targets are reported by.
func (*Progress) SetTotal ¶ added in v0.26.0
SetTotal sets the number of targets without their names.
func (*Progress) Snapshot ¶ added in v0.26.0
func (p *Progress) Snapshot() CommandProgress
Snapshot is the progress now; Done never exceeds Total when Total is known.
func (*Progress) TargetDone ¶ added in v0.26.0
TargetDone marks target finished (whatever the outcome: found, nothing, failed, timed out). Marking the same target again counts once.
func (*Progress) TrackProcess ¶ added in v0.28.0
TrackProcess adds a tool process (and the processes it starts) to the job's CPU time (a liveness counter). Where the CPU time of a process cannot be read, it counts nothing.
type Provider ¶
type Provider interface {
// Name returns the provider name (e.g., "github", "aws")
Name() string
// Connector returns the underlying connector
Connector() Connector
// ListCollectors returns all available collectors
ListCollectors() []Collector
// GetCollector returns a specific collector by name
GetCollector(name string) (Collector, error)
// Initialize sets up the provider with configuration
Initialize(ctx context.Context, config *ProviderConfig) error
// TestConnection tests the provider connection
TestConnection(ctx context.Context) error
// Close closes the provider and all collectors
Close() error
}
Provider bundles a Connector with multiple Collectors for complete integration.
type ProviderConfig ¶
type ProviderConfig struct {
// Connector config
Connector ConnectorConfig `yaml:"connector" json:"connector"`
// Provider-specific settings
Settings map[string]any `yaml:"settings" json:"settings"`
// Which collectors to enable (empty = all)
EnabledCollectors []string `yaml:"enabled_collectors" json:"enabled_collectors"`
}
ProviderConfig holds provider configuration.
type PushResult ¶
type PushResult struct {
Success bool `json:"success"`
Message string `json:"message,omitempty"`
FindingsCreated int `json:"findings_created"`
FindingsUpdated int `json:"findings_updated"`
AssetsCreated int `json:"assets_created"`
AssetsUpdated int `json:"assets_updated"`
// Queued: the results are durably stored in the outbox and will be
// delivered when the platform is reachable; the counts above are not
// known yet.
Queued bool `json:"queued,omitempty"`
// ReportID is the protocol v2 report id the results travel under ("" on
// v1).
ReportID string `json:"report_id,omitempty"`
}
PushResult holds the result of a push operation.
type Pusher ¶
type Pusher interface {
// PushFindings sends findings to OpenCTEM
PushFindings(ctx context.Context, report *ctis.Report) (*PushResult, error)
// PushAssets sends assets to OpenCTEM
PushAssets(ctx context.Context, report *ctis.Report) (*PushResult, error)
// SendHeartbeat sends a heartbeat to OpenCTEM
SendHeartbeat(ctx context.Context, status *SensorStatus) error
// TestConnection tests the API connection
TestConnection(ctx context.Context) error
}
Pusher sends data to the OpenCTEM API.
type QueueStats ¶ added in v0.10.0
type QueueStats struct {
// Claimed is the commands this sensor holds (claimed and not finished).
Claimed int `json:"claimed"`
// Running is those it is executing.
Running int `json:"running"`
// QueuedLocal is those claimed and not started yet.
QueuedLocal int `json:"queued_local"`
// OldestAgeSeconds is how long the oldest held command has been held.
OldestAgeSeconds int64 `json:"oldest_age_seconds"`
}
QueueStats is the local queue a heartbeat carries as "queue".
type ReconOptions ¶
type ReconOptions struct {
// Target configuration
Target string `yaml:"target" json:"target"` // Domain, IP, or CIDR
InputFile string `yaml:"input_file" json:"input_file"` // File with multiple targets
OutputFile string `yaml:"output_file" json:"output_file"` // Output file path
ExtraArgs []string `yaml:"extra_args" json:"extra_args"` // Additional CLI args
// Performance
Threads int `yaml:"threads" json:"threads"` // Concurrency
RateLimit int `yaml:"rate_limit" json:"rate_limit"` // Rate limit (requests/second)
Timeout time.Duration `yaml:"timeout" json:"timeout"` // Scan timeout
// DNS configuration
Resolvers []string `yaml:"resolvers" json:"resolvers"` // Custom DNS resolvers
// Environment
Env map[string]string `yaml:"env" json:"env"` // Environment variables
// Output
Verbose bool `yaml:"verbose" json:"verbose"`
}
ReconOptions configures a reconnaissance scan.
type ReconResult ¶
type ReconResult struct {
// Scanner info
ScannerName string `json:"scanner_name"`
ScannerVersion string `json:"scanner_version"`
ReconType ReconType `json:"recon_type"`
// Target
Target string `json:"target"`
// Timing
StartedAt int64 `json:"started_at"`
FinishedAt int64 `json:"finished_at"`
DurationMs int64 `json:"duration_ms"`
// Results (populated based on ReconType)
Subdomains []Subdomain `json:"subdomains,omitempty"`
DNSRecords []DNSRecord `json:"dns_records,omitempty"`
OpenPorts []OpenPort `json:"open_ports,omitempty"`
LiveHosts []LiveHost `json:"live_hosts,omitempty"`
URLs []DiscoveredURL `json:"urls,omitempty"`
Technologies []Technology `json:"technologies,omitempty"`
// Raw output
RawOutput []byte `json:"raw_output,omitempty"`
ExitCode int `json:"exit_code"`
Error string `json:"error,omitempty"`
}
ReconResult holds the reconnaissance scan result.
type ReconScanner ¶
type ReconScanner interface {
// Name returns the scanner name (e.g., "subfinder", "naabu")
Name() string
// Version returns the scanner version
Version() string
// Type returns the recon type this scanner performs
Type() ReconType
// Scan performs reconnaissance on the target and returns results
Scan(ctx context.Context, target string, opts *ReconOptions) (*ReconResult, error)
// IsInstalled checks if the underlying tool is available
IsInstalled(ctx context.Context) (bool, string, error)
}
ReconScanner performs reconnaissance and asset discovery. Implement this interface to create a custom recon scanner.
type ReconType ¶
type ReconType string
ReconType represents the type of reconnaissance scan.
const ( ReconTypeSubdomain ReconType = "subdomain" // Subdomain enumeration ReconTypeDNS ReconType = "dns" // DNS resolution and records ReconTypePort ReconType = "port" // Port scanning ReconTypeHTTPProbe ReconType = "http_probe" // HTTP/HTTPS probing ReconTypeURLCrawl ReconType = "url_crawl" // URL and endpoint crawling ReconTypeTechDetect ReconType = "tech_detect" // Technology fingerprinting )
type RefreshContentRequest ¶ added in v0.10.0
type RefreshContentRequest struct {
// Content names the content to refresh; empty refreshes all managed
// content.
Content []string `json:"content,omitempty"`
// Force refreshes even content that is still fresh.
Force bool `json:"force,omitempty"`
// Policy, when present, replaces the policy the sensor applies (it
// keeps it for its scheduled refreshes).
Policy *ContentPolicy `json:"policy,omitempty"`
}
RefreshContentRequest is the payload of a refresh_content command.
func ParseRefreshContentRequest ¶ added in v0.10.0
func ParseRefreshContentRequest(payload json.RawMessage) (*RefreshContentRequest, error)
ParseRefreshContentRequest decodes and checks a refresh_content payload. An empty payload is a valid request (refresh all content that needs it).
type Refusal ¶ added in v0.18.0
type Refusal struct {
Layer string `json:"layer"`
Rule string `json:"rule"`
Detail string `json:"detail,omitempty"`
}
Refusal is why a policy refused a command: the layer (RefusalLayer*), the rule (a policy key: "tools.allow", "allow_interactsh", "kill_switch") and a short detail.
func RefusalOf ¶ added in v0.18.0
RefusalOf returns the structured refusal of err, or nil when err is not a policy refusal: a *LocalPolicyError (its layer, "local" when unset) or ErrToolNotAllowed (the platform's tool gate). The values are bounded: a rule outside the platform's pattern becomes "unknown", the detail loses control and bidi characters and is cut at MaxRefusalDetail bytes.
type RefusedTarget ¶ added in v0.19.0
type RefusedTarget struct {
Target string `json:"target"`
// Reason is one of RefusedTarget*.
Reason string `json:"reason"`
// Rule is the policy rule that refused it ("targets.deny",
// "ports.allow", "builtin"…), when a policy rule did.
Rule string `json:"rule,omitempty"`
// Detail is a short, bounded explanation.
Detail string `json:"detail,omitempty"`
}
RefusedTarget is one target a policy removed from a command.
type ReleasingCommandClient ¶ added in v0.10.0
type ReleasingCommandClient interface {
ReleaseCommand(ctx context.Context, cmdID, reason string) error
}
ReleasingCommandClient is a CommandClient that can hand a claimed command back to the platform, which returns it to pending (unpinned) so another sensor can run it at once. The CommandPoller uses it for work it will not run (draining, shutdown, canceled). *client.Client implements it.
type RetryAfterHinter ¶ added in v0.25.0
RetryAfterHinter is an error that carries the platform's advised wait before the next request (a Retry-After header, a retry_after_seconds field). The API clients' errors implement it.
type SARIFParser ¶
type SARIFParser struct{}
SARIFParser parses SARIF format output.
func (*SARIFParser) CanParse ¶
func (p *SARIFParser) CanParse(data []byte) bool
CanParse checks if this parser can handle the data: a single JSON object with a "runs" array, the one member every SARIF log must have. Substring checks are not enough: a JSON Lines stream (nuclei) whose response bodies mention "version" and "runs" passed them, and was then read as an empty SARIF log.
func (*SARIFParser) Parse ¶
func (p *SARIFParser) Parse(ctx context.Context, data []byte, opts *ParseOptions) (*ctis.Report, error)
Parse converts SARIF to CTIS with the one conversion entry point, github.com/openctemio/ctis/importer, under its input limits. Data that is not a SARIF log is an error: decoding arbitrary JSON into the SARIF structure succeeds with no runs, which used to turn a scanner's real results into "0 findings".
Every finding is filed on one asset:
- opts.AssetValue (opts.AssetType, default repository);
- else opts.BranchInfo.RepositoryURL (a repository);
- else the first repository the log names in versionControlProvenance;
- else the repository of the CI job.
With none of these, a log with results is an error matching ctis.ErrNoAssetForFindings, never a shared placeholder asset. opts.BranchInfo, when set, is the report's branch.
func (*SARIFParser) SupportedFormats ¶
func (p *SARIFParser) SupportedFormats() []string
SupportedFormats returns supported formats.
type SDKInfo ¶ added in v0.10.0
type SDKInfo struct {
// Name is "openctem-sdk-go".
Name string `json:"name"`
// Version is the SDK version linked into the binary, without a leading
// "v" (useragent.SDKVersion: from the build info, so a release tag sets
// it; "<sdk.Version>-devel" for a local checkout).
Version string `json:"version"`
}
SDKInfo names the SDK a sensor is built with: heartbeat "sdk".
func CurrentSDKInfo ¶ added in v0.10.0
func CurrentSDKInfo() SDKInfo
CurrentSDKInfo is the SDK this binary is built with.
type SandboxPosture ¶ added in v0.19.0
type SandboxPosture struct {
// Mode is the sandbox mode: off, auto or required (SENSOR_SANDBOX).
Mode string `json:"mode"`
// Sandboxed is true when tool runs go through the sandbox launcher.
Sandboxed bool `json:"sandboxed"`
// NetworkEnforced is true when each tool run's network is confined to
// its own forwarder (SENSOR_SANDBOX_NETWORK); false means the target
// checks are the only control on where a tool connects.
NetworkEnforced bool `json:"network_enforced"`
}
SandboxPosture is the tool sandbox's protection (executor.Status).
type ScaResult ¶
type ScaResult struct {
// Packages discovered
Packages []Package `json:"packages"`
// Dependency relationships
PackageDependencies []PackageDependency `json:"package_dependencies"`
// Vulnerabilities found
Vulnerabilities []Vulnerability `json:"vulnerabilities"`
// Timing
DurationMs int64 `json:"duration_ms"`
}
ScaResult holds SCA scan results.
type ScaScanOptions ¶
type ScaScanOptions struct {
// Target
TargetDir string `yaml:"target_dir" json:"target_dir"`
// Scan configuration
SkipDBUpdate bool `yaml:"skip_db_update" json:"skip_db_update"`
IgnoreUnfixed bool `yaml:"ignore_unfixed" json:"ignore_unfixed"`
IncludeDevDeps bool `yaml:"include_dev_deps" json:"include_dev_deps"`
// Output
GenerateSBOM bool `yaml:"generate_sbom" json:"generate_sbom"`
SBOMFormat string `yaml:"sbom_format" json:"sbom_format"` // cyclonedx, spdx
// Verbose
Verbose bool `yaml:"verbose" json:"verbose"`
}
ScaScanOptions configures an SCA scan.
type ScaScanner ¶
type ScaScanner interface {
// Name returns the scanner name (e.g., "trivy", "snyk")
Name() string
// Type returns the scanner type
Type() ScannerType
// Scan performs SCA scan and returns results
Scan(ctx context.Context, target string, opts *ScaScanOptions) (*ScaResult, error)
// IsInstalled checks if the scanner is available
IsInstalled(ctx context.Context) (bool, string, error)
}
ScaScanner performs Software Composition Analysis (dependency scanning). It generates SBOM and identifies vulnerabilities in dependencies.
type ScanCommandPayload ¶
type ScanCommandPayload struct {
Scanner string `json:"scanner"`
// Target is the single scan target. The platform omits it when a job has
// several targets for a list-capable scanner (nuclei) and sends only
// Targets; when both are set, Target is the job.
Target string `json:"target"`
// Targets is the full target list (additive).
Targets []string `json:"targets,omitempty"`
Config map[string]interface{} `json:"config,omitempty"`
TimeoutSeconds int `json:"timeout_seconds,omitempty"`
// Budget is the task's layered budget (per target, per task); nil
// from a platform that sends none (budget.go).
Budget *TaskBudget `json:"budget,omitempty"`
ReportProgress bool `json:"report_progress,omitempty"`
CustomTemplates []EmbeddedTemplate `json:"custom_templates,omitempty"`
// CustomTemplatesEnvelope is the platform's signed manifest of
// CustomTemplates (TemplateManifest in a DSSE envelope). Custom
// templates run only when it verifies (see TemplateVerifier.Verify).
CustomTemplatesEnvelope *SignedEnvelope `json:"custom_templates_envelope,omitempty"`
// Capability is the capability the job runs ("scan.ports@1"), sent to
// a tool that reported a contract. Params are its standard params as
// the workflow set them; the tool runtime maps them onto the tool's
// config keys. MaxTier is the grant's tier ceiling.
Capability string `json:"capability,omitempty"`
Params map[string]json.RawMessage `json:"params,omitempty"`
MaxTier string `json:"max_tier,omitempty"`
// WebScope is the hosts, paths and methods a web tool may request
// (webscope.Scope); an invalid one fails the job.
WebScope *webscope.Scope `json:"web_scope,omitempty"`
// HTTPPolicy is the organization's narrowing of its tools' requests
// (OrgHTTPPolicy); the local policy decides first.
HTTPPolicy *OrgHTTPPolicy `json:"http_policy,omitempty"`
// Source is the repository a code-scan job fetches before the scan
// (api RFC-091): the executor fetches exactly that commit read-only
// into the scan workspace (pkg/source), scans the checkout instead of
// Target, reports the findings on the repository Target names with the
// source's branch and commit as a full scan, and removes the checkout.
Source *ctissource.Repository `json:"source,omitempty"`
// Exclusions are the scope exclusions that touch the job's targets
// (addresses, CIDR prefixes, "first-last" ranges), covered by the job
// signature with the rest of the payload. The sensor cuts its range
// targets around them address by address before any check or tool
// (job_exclusions.go) and hands them to the tool (ScanOptions.ExcludeHosts).
Exclusions []string `json:"exclusions,omitempty"`
// SettingsLayers are the tenant's and the sensor's tool settings for
// the command's tool, set by administrators on the platform; checked
// against the tool's own schema like the config (resolveScanSettings).
SettingsLayers *SettingsLayers `json:"settings_layers,omitempty"`
// contains filtered or unexported fields
}
ScanCommandPayload is the payload for scan commands.
type ScanOptions ¶
type ScanOptions struct {
// Target configuration
TargetDir string `yaml:"target_dir" json:"target_dir"`
Include []string `yaml:"include" json:"include"`
Exclude []string `yaml:"exclude" json:"exclude"`
ConfigFile string `yaml:"config_file" json:"config_file"`
ExtraArgs []string `yaml:"extra_args" json:"extra_args"`
Env map[string]string `yaml:"env" json:"env"`
// Custom templates directory (written from embedded templates)
// Used by Nuclei (-t), Semgrep (--config), Betterleaks (--config)
CustomTemplateDir string `yaml:"custom_template_dir" json:"custom_template_dir"`
// AllowInteractsh lets this scan use out-of-band callbacks (nuclei's
// Interactsh), which are off by default. The command executor sets it
// only when the platform's scan command allows it
// (config "allow_interactsh": true, an approved intrusive run).
AllowInteractsh bool `yaml:"allow_interactsh" json:"allow_interactsh"`
// RateLimit (requests per second), BulkSize (hosts in parallel) and
// Concurrency (templates or workers in parallel) ask the scanner to run
// gentler than its own settings for this scan; 0 keeps them. They can
// only lower a scanner's limits: a scanner caps them at the ceilings
// its operator configured on the sensor. The command executor sets
// them from the command's config keys rate_limit, bulk_size and
// concurrency (see ScanLimitKeys).
RateLimit int `yaml:"rate_limit" json:"rate_limit"`
BulkSize int `yaml:"bulk_size" json:"bulk_size"`
Concurrency int `yaml:"concurrency" json:"concurrency"`
// Asset information for linking findings
RepoURL string `yaml:"repo_url" json:"repo_url"`
Branch string `yaml:"branch" json:"branch"`
CommitSHA string `yaml:"commit_sha" json:"commit_sha"`
// Output
Verbose bool `yaml:"verbose" json:"verbose"`
// Settings are the tool's effective settings for this scan (api
// RFC-038), resolved against the tool's SettingsSchema; nil: the tool's
// own defaults, as before. A tool maps each typed value to a specific
// flag; settings never become free-form arguments.
Settings *ToolSettings `yaml:"-" json:"-"`
// Capability, Params and MaxTier are a capability job's (see
// ScanCommandPayload); only a CapabilityScanner receives them.
Capability string `yaml:"-" json:"-"`
Params map[string]json.RawMessage `yaml:"-" json:"-"`
MaxTier string `yaml:"-" json:"-"`
// WebScope is the job's web scope (see ScanCommandPayload); only a
// CapabilityScanner receives it.
WebScope *webscope.Scope `yaml:"-" json:"-"`
// OrgHTTP is the job's organization HTTP policy (see ScanCommandPayload).
OrgHTTP *OrgHTTPPolicy `yaml:"-" json:"-"`
// Limits are the port, protocol and path limits of the job's targets,
// from its verified signed statement only (never the payload); only a
// ScopeLimitScanner receives them.
Limits []scopelimit.Limit `yaml:"-" json:"-"`
// ExcludeHosts are the job's exclusions (addresses, CIDR prefixes,
// "first-last" ranges) for a tool that can skip hosts itself (naabu
// -exclude-hosts). The sensor already cut the job's ranges around them.
ExcludeHosts []string `yaml:"-" json:"-"`
// TargetTimeout is the platform's per-target budget (TaskBudget.Target,
// clamped; 0 = none). A wrapper passes it as the tool's per-request or
// per-host timeout flag where the tool has one, and runs per-target
// tools through RunPerTarget, so one slow host costs one budget, not the
// whole task.
TargetTimeout time.Duration `yaml:"-" json:"-"`
}
ScanOptions configures a scan.
type ScanResult ¶
type ScanResult struct {
// Scanner info
ScannerName string `json:"scanner_name"`
ScannerVersion string `json:"scanner_version"`
// Timing
StartedAt int64 `json:"started_at"`
FinishedAt int64 `json:"finished_at"`
DurationMs int64 `json:"duration_ms"`
// Output
ExitCode int `json:"exit_code"`
RawOutput []byte `json:"raw_output,omitempty"`
Stderr string `json:"stderr,omitempty"`
// Error (if scan failed)
Error string `json:"error,omitempty"`
// CoverageGaps are hosts the scan could not fully cover (the host's
// breaker opened, it pushed back at the lowest rate, or it blocked the
// scan; adapt.Gap), at most adapt.TargetRate.MaxGaps; CoverageGapsTotal
// counts all. The scan still completes, as partial coverage: what it
// did not report on those hosts is not read as "no findings".
CoverageGaps []adapt.Gap `json:"coverage_gaps,omitempty"`
CoverageGapsTotal int `json:"coverage_gaps_total,omitempty"`
// TargetRate is the per-host rate outcome (nil: no controller ran).
TargetRate *adapt.Summary `json:"target_rate,omitempty"`
}
ScanResult holds the raw scan result before conversion.
func (*ScanResult) AddCoverageGaps ¶ added in v0.21.0
func (r *ScanResult) AddCoverageGaps(gaps []adapt.Gap, total int)
AddCoverageGaps adds gaps (total counting also those not listed) to r, once per host.
func (*ScanResult) HasCoverageGaps ¶ added in v0.21.0
func (r *ScanResult) HasCoverageGaps() bool
HasCoverageGaps reports whether the scan left hosts not fully covered.
func (*ScanResult) WithTargetRate ¶ added in v0.21.0
func (r *ScanResult) WithTargetRate(s *adapt.Summary)
WithTargetRate sets r's rate summary and adds its gaps to r's coverage gaps (nil s: no change).
type ScanTargetPolicy ¶ added in v0.7.0
type ScanTargetPolicy struct {
// AllowedRoots confines filesystem targets. When non-empty, a path target
// must resolve (after following symlinks) to one of these directories or
// a descendant. When empty, filesystem targets are allowed anywhere
// except the filesystem root, sensitive system directories (/etc, /proc,
// /root, ...) and credential directories in the user's home (~/.ssh,
// ~/.aws, ...). Configuring roots is strongly recommended.
AllowedRoots []string
// AllowPrivate permits network targets in RFC1918 (10/8, 172.16/12,
// 192.168/16) and IPv6 ULA (fc00::/7) space, for sensors that scan an
// internal network. Loopback, link-local (incl. 169.254.169.254 IMDS),
// CGNAT, multicast, unspecified and reserved ranges stay blocked
// regardless.
AllowPrivate bool
// AllowLoopback permits 127.0.0.0/8 and ::1. Test-only; mirrors
// httpsec.AllowLoopback.
AllowLoopback bool
// ByScanner checks each target by the scanner that receives it
// (ValidateFor): a code scanner's path is confined to AllowedRoots, and
// every other scanner is a network scanner whose targets must be hosts,
// host:port pairs, URLs or ranges, a name that does not resolve being
// refused. Off, a target is read by its shape whatever the scanner
// (Validate). A sensor whose tools are known by name sets it.
ByScanner bool
// Disabled turns validation off entirely. Only for callers that validate
// targets themselves before the executor sees the command.
Disabled bool
// LookupIP resolves a hostname; nil uses net.DefaultResolver. Exposed
// for tests.
LookupIP func(ctx context.Context, host string) ([]net.IP, error)
// Local is the sensor-local policy (api RFC-040 §5.7): when set, network
// targets must also pass its target, range and port rules, checked
// against the same resolved addresses. It can only narrow what this
// policy allows. nil: no local policy.
Local *LocalPolicy
}
ScanTargetPolicy decides whether a server-supplied scan target may be scanned. The zero value is NOT the secure default; use DefaultScanTargetPolicy and adjust.
func DefaultScanTargetPolicy ¶ added in v0.7.0
func DefaultScanTargetPolicy() *ScanTargetPolicy
DefaultScanTargetPolicy returns the policy DefaultCommandExecutor uses unless SetScanTargetPolicy is called:
- AllowedRoots from OPENCTEM_SDK_SCAN_ROOTS (unset = sensitive-path denylist only);
- AllowPrivate when SENSOR_ALLOW_PRIVATE_TARGETS=1, the one switch for scan targets (the SDK's own egress has its own switch, OPENCTEM_SDK_HTTPSEC_ALLOW_PRIVATE, which does not widen targets);
- AllowLoopback follows httpsec.AllowLoopback (test harnesses only).
func (*ScanTargetPolicy) Validate ¶ added in v0.7.0
Validate checks target and returns the value to hand to the scanner: for filesystem targets the cleaned, symlink-resolved absolute path (so the scanner reads exactly what was checked); otherwise the target unchanged.
func (*ScanTargetPolicy) ValidateFor ¶ added in v0.33.0
ValidateFor checks target for the scanner that will receive it when the policy is ByScanner (Validate otherwise), and returns the value to hand to the scanner (a confined, symlink-resolved path for a code scanner's directory; the target unchanged otherwise). See the package notes above for how each kind of scanner is checked.
func (*ScanTargetPolicy) ValidateNetworkTarget ¶ added in v0.33.0
func (p *ScanTargetPolicy) ValidateNetworkTarget(ctx context.Context, target string) error
ValidateNetworkTarget checks a target a network tool will connect to: a URL (http and https only), a host, an address, host:port ("203.0.113.7:80", "example.com:443", "[2001:db8::1]:443") or a range. The host must not be a blocked name, an address in a blocked range (loopback, link-local and cloud metadata, CGNAT, multicast, reserved; RFC1918 and ULA unless AllowPrivate), or a name that resolves to one. A name that does not resolve is refused (fail closed): it cannot be proven safe, and it could resolve to a blocked address when the tool connects. The local policy, when set, applies too.
type Scanner ¶
type Scanner interface {
// Name returns the scanner name (e.g., "semgrep", "trivy")
Name() string
// Version returns the scanner version
Version() string
// Capabilities returns what the scanner can detect
Capabilities() []string
// Scan performs a scan on the target and returns raw output
Scan(ctx context.Context, target string, opts *ScanOptions) (*ScanResult, error)
// IsInstalled checks if the underlying tool is available
IsInstalled(ctx context.Context) (bool, string, error)
}
Scanner is the main interface for security scanning tools. Implement this interface to create a custom scanner.
type ScannerPriority ¶ added in v0.15.0
type ScannerPriority struct {
// Nice is added to the sensor's own nice value for the scanner's process
// group (0-19; 10 is the "low" process priority of other scanning
// agents). Each nice step is about 10% less CPU under contention.
Nice int
// IOLevel is the best-effort I/O priority level of the process group,
// 0 (highest) to 7 (lowest); -1 leaves it. Only I/O schedulers that
// honor priorities (bfq, mq-deadline) apply it.
IOLevel int
// OOMScoreAdj is written to the scanner's oom_score_adj (0-1000): when
// memory runs out, the kernel kills a scanner before the sensor. Raising
// it needs no privilege; children forked after the write inherit it.
OOMScoreAdj int
}
ScannerPriority is how much a scanner process yields to the sensor that runs it (api RFC-035 §5.3). A scanner can saturate the CPU, the disk and the memory; the sensor must still heartbeat, poll and upload. Linux only; elsewhere it does nothing.
func CurrentScannerPriority ¶ added in v0.15.0
func CurrentScannerPriority() *ScannerPriority
CurrentScannerPriority returns the priority set with SetScannerPriority, nil when none is.
type ScannerProxyMode ¶ added in v0.15.0
type ScannerProxyMode string
ScannerProxyMode says whether scanner processes inherit the sensor's proxy variables.
const ( // ScannerProxyInherit passes the sensor's proxy variables to scanners. ScannerProxyInherit ScannerProxyMode = "inherit" // ScannerProxyDirect removes them. ScannerProxyDirect ScannerProxyMode = "direct" )
func ParseScannerProxyMode ¶ added in v0.15.0
func ParseScannerProxyMode(v string) (ScannerProxyMode, error)
ParseScannerProxyMode parses inherit or direct; "" is inherit.
func ScannerProxy ¶ added in v0.15.0
func ScannerProxy() ScannerProxyMode
ScannerProxy returns the scanner proxy mode.
type ScannerType ¶
type ScannerType string
ScannerType represents the type of security scanner.
const ( ScannerTypeSAST ScannerType = "sast" // Static Application Security Testing ScannerTypeDependency ScannerType = "dependency" // Software Composition Analysis ScannerTypeSecretDetection ScannerType = "secret_detection" // Secret/Credential Detection ScannerTypeIaC ScannerType = "iac" // Infrastructure as Code ScannerTypeContainer ScannerType = "container" // Container Image Scanning ScannerTypeWeb3 ScannerType = "web3" // Smart Contract Analysis )
type ScopeLimitScanner ¶ added in v0.19.0
ScopeLimitScanner is a scanner that runs a job whose targets carry scope limits (scopelimit): it hands them to a tool runtime that enforces them outside the tool (the task's egress forwarder). A job with limits for any other scanner is refused, never run unlimited.
type SecretFinding ¶
type SecretFinding struct {
// Identity
RuleID string `json:"rule_id"` // Detection rule ID
Fingerprint string `json:"fingerprint"` // For deduplication
// Classification
SecretType string `json:"secret_type"` // api_key, password, token, etc.
Service string `json:"service"` // AWS, GitHub, Stripe, etc.
// Location
File string `json:"file"`
StartLine int `json:"start_line"`
EndLine int `json:"end_line"`
StartColumn int `json:"start_column"`
EndColumn int `json:"end_column"`
// Content
Match string `json:"match"` // Full matched line
MaskedValue string `json:"masked_value"` // Redacted secret
// Metadata
Entropy float64 `json:"entropy,omitempty"` // Entropy score
Valid *bool `json:"valid,omitempty"` // If verified
Author string `json:"author,omitempty"` // Git author
Commit string `json:"commit,omitempty"` // Git commit
Date string `json:"date,omitempty"` // Commit date
}
SecretFinding represents a detected secret.
type SecretResult ¶
type SecretResult struct {
// Secrets found
Secrets []SecretFinding `json:"secrets"`
// Timing
DurationMs int64 `json:"duration_ms"`
}
SecretResult holds secret scan results.
type SecretScanOptions ¶
type SecretScanOptions struct {
// Target
TargetDir string `yaml:"target_dir" json:"target_dir"`
// Scan configuration
ConfigFile string `yaml:"config_file" json:"config_file"` // Custom rules file
Exclude []string `yaml:"exclude" json:"exclude"` // Paths to exclude
NoGit bool `yaml:"no_git" json:"no_git"` // Don't use git history
// Verification
Verify bool `yaml:"verify" json:"verify"` // Verify secrets are valid
// Verbose
Verbose bool `yaml:"verbose" json:"verbose"`
}
SecretScanOptions configures a secret scan.
type SecretScanner ¶
type SecretScanner interface {
// Name returns the scanner name (e.g., "betterleaks", "trufflehog")
Name() string
// Type returns the scanner type
Type() ScannerType
// Scan performs secret detection and returns results
Scan(ctx context.Context, target string, opts *SecretScanOptions) (*SecretResult, error)
// IsInstalled checks if the scanner is available
IsInstalled(ctx context.Context) (bool, string, error)
}
SecretScanner detects secrets and credentials in code.
type Sensor ¶ added in v0.7.0
type Sensor interface {
// Name returns the sensor name
Name() string
// Start starts the sensor
Start(ctx context.Context) error
// Stop gracefully stops the sensor
Stop(ctx context.Context) error
// Status returns the current sensor status
Status() *SensorStatus
// AddScanner adds a scanner to the sensor
AddScanner(scanner Scanner) error
// AddCollector adds a collector to the sensor
AddCollector(collector Collector) error
// RemoveScanner removes a scanner by name
RemoveScanner(name string) error
// RemoveCollector removes a collector by name
RemoveCollector(name string) error
}
Sensor is a long-running service that manages scanners and collectors. Implement this interface to create a custom sensor.
type SensorBuild ¶ added in v0.10.0
type SensorBuild struct {
// Name is the product name (BaseSensorConfig.ProductName, else the
// name given to useragent.SetProduct, else the executable's name).
Name string `json:"name"`
// Version is the sensor's version, without a leading "v"; "" when the
// sensor does not say.
Version string `json:"version,omitempty"`
// Commit is the source revision the binary was built from (optional).
Commit string `json:"commit,omitempty"`
// BuildTime is when the binary was built, RFC 3339 in UTC (optional).
BuildTime string `json:"build_time,omitempty"`
}
SensorBuild names the sensor binary: heartbeat "sensor".
func NewSensorBuild ¶ added in v0.10.0
func NewSensorBuild(productName, version, commit, buildTime string) SensorBuild
NewSensorBuild describes the sensor binary. Empty productName and version fall back to what was given to useragent.SetProduct, then (name only) to the executable's name. buildTime is kept only when it parses as RFC 3339 (it is normalized to UTC); commit and the names are trimmed and bounded.
type SensorPosture ¶ added in v0.19.0
type SensorPosture struct {
// PlatformTLS is how platform requests over HTTPS check the platform's
// certificate.
PlatformTLS *PlatformTLSPosture `json:"platform_tls,omitempty"`
// Sandbox is how tool runs are confined.
Sandbox *SandboxPosture `json:"sandbox,omitempty"`
// Jobs is how the sensor checks the platform's job signatures; nil
// when the runtime did not decide it (SetJobsPosture).
Jobs *JobsPosture `json:"jobs,omitempty"`
}
SensorPosture is the manifest member "posture".
func CurrentPosture ¶ added in v0.19.0
func CurrentPosture() *SensorPosture
CurrentPosture is the posture now: the platform TLS pin, the status of the tool sandbox installed with executor.SetCurrent and the signed-job checking set with SetJobsPosture.
type SensorSettings ¶ added in v0.16.0
type SensorSettings struct {
Kind string `json:"kind"`
SensorID string `json:"sensor_id"`
TenantID string `json:"tenant_id,omitempty"`
Version int64 `json:"version"`
IssuedAt time.Time `json:"issued_at"`
Tools map[string]ToolSettingsBlock `json:"tools"`
// Signature is the platform's signature over the document, when it
// signs (not verified by the store).
Signature *SettingsSignature `json:"signature,omitempty"`
}
SensorSettings is a settings document: per tool, the values the platform validated against the schema with SchemaDigest.
func (*SensorSettings) Check ¶ added in v0.16.0
func (d *SensorSettings) Check() error
Check verifies the document's shape: kind, a positive version, and a schema digest for every tool block. It does not validate the values (that needs the tools' schemas: ValidateAgainst).
func (*SensorSettings) ValidateAgainst ¶ added in v0.16.0
func (d *SensorSettings) ValidateAgainst(schemas map[string]*SettingsSchema) map[string]error
ValidateAgainst checks each tool block against the schema this sensor declares for the tool: the digests must match and the values must be valid. It returns the error of every rejected tool by name; tools not in the returned map are acceptable. A tool this sensor has no schema for is rejected.
type SensorState ¶ added in v0.7.0
type SensorState string
SensorState represents the state of a sensor.
const ( SensorStateRunning SensorState = "running" SensorStateStopped SensorState = "stopped" SensorStateStopping SensorState = "stopping" SensorStateError SensorState = "error" )
type SensorStatus ¶ added in v0.7.0
type SensorStatus struct {
Name string `json:"name"`
Status SensorState `json:"status"`
StartedAt int64 `json:"started_at,omitempty"`
Uptime int64 `json:"uptime_seconds,omitempty"`
Scanners []string `json:"scanners"`
Collectors []string `json:"collectors"`
LastScan int64 `json:"last_scan,omitempty"`
LastCollect int64 `json:"last_collect,omitempty"`
TotalScans int64 `json:"total_scans"`
TotalFindings int64 `json:"total_findings"`
Errors int64 `json:"errors"`
Message string `json:"message,omitempty"`
// System Metrics (collected from sensor)
CPUPercent float64 `json:"cpu_percent,omitempty"`
MemoryPercent float64 `json:"memory_percent,omitempty"`
ActiveJobs int `json:"active_jobs,omitempty"`
Region string `json:"region,omitempty"`
// ActiveJobsReported is true when ActiveJobs is a measured value (the
// sensor has a LoadReporter): the heartbeat then sends active_jobs even
// when it is 0, so the platform can tell "idle" from "not reported".
ActiveJobsReported bool `json:"-"`
// Version and Hostname identify the running sensor to the platform (shown
// on the Sensors page). Both are sent with every heartbeat.
Version string `json:"version,omitempty"`
Hostname string `json:"hostname,omitempty"`
// InstanceID identifies this sensor process (ProcessInstanceID when
// empty). The platform flags a key whose heartbeats come from two
// instances in turn: a copied or shared key (api RFC-032 Phase 0).
InstanceID string `json:"instance_id,omitempty"`
// What the sensor reports it can do (see CapabilityReport): its tool
// inventory, the capabilities it serves and how many jobs it runs at
// once. nil / 0 report nothing. BaseSensor fills them from its
// CapabilityReporter (SetCapabilityReporter).
Tools []ToolInfo `json:"tools,omitzero"`
Capabilities []string `json:"capabilities,omitzero"`
MaxConcurrentJobs int `json:"max_concurrent_jobs,omitempty"`
// OS and Arch are the sensor's platform (runtime.GOOS, runtime.GOARCH);
// BaseSensor sets them.
OS string `json:"os,omitempty"`
Arch string `json:"arch,omitempty"`
// What the sensor's work looks like now (api RFC-030); nil reports
// nothing. A CommandPoller fills them (StatusReporter): the resources
// it may use, its slots and per-tool costs, its local queue, and the
// ids of the commands it holds (the lease list: a platform with leases
// renews exactly these).
// SDK and Sensor name the SDK and the sensor binary (every heartbeat;
// BaseSensor fills them, and the API client fills what is missing).
SDK *SDKInfo `json:"sdk,omitempty"`
Sensor *SensorBuild `json:"sensor,omitempty"`
// ManifestDigest is the digest of the manifest the platform stored for
// this sensor (api RFC-033); BaseSensor sets it once its manifest is
// registered. "" sends none, and the platform derives the manifest
// from this heartbeat.
ManifestDigest string `json:"manifest_digest,omitempty"`
// Content is a slim heartbeat's content freshness (api RFC-033 §6.12):
// BaseSensor sets it, and leaves Tools, Capabilities and
// MaxConcurrentJobs out, once the platform acknowledged the manifest
// with omit_inventory.
Content []ToolContent `json:"content,omitzero"`
Resources *resource.HostResources `json:"resources,omitempty"`
Capacity *resource.Capacity `json:"capacity,omitempty"`
Queue *QueueStats `json:"queue,omitempty"`
RunningCommands []string `json:"running,omitzero"`
// Progress is each held command's finished targets (progress.go); the
// API client sends it only to a platform that lists the
// "command_progress" feature.
Progress map[string]CommandProgress `json:"progress,omitempty"`
// Control is the control channel's own stats (api RFC-035): BaseSensor
// sets it on every heartbeat.
Control *ControlStats `json:"control,omitempty"`
// LocalPolicy is the sensor-local policy's state, digest and summary
// (api RFC-040 §5.7; BaseSensor.SetLocalPolicy). nil reports nothing;
// the API client sends it only to a platform that lists the
// "local_policy" feature.
LocalPolicy *LocalPolicyReport `json:"local_policy,omitempty"`
// ConfigReport is the config report's digest (as the platform returned
// it), rollup and counts (BaseSensor.SetConfigReporter). nil reports
// nothing; the API client sends it only to a platform that lists the
// "config_report" feature.
ConfigReport *ConfigReportSummary `json:"config_report,omitempty"`
}
SensorStatus represents the sensor's current state.
type SettingProperty ¶ added in v0.16.0
SettingProperty is one key of a schema.
type SettingScope ¶ added in v0.16.0
SettingScope is the lowest level allowed to set a key.
type SettingSource ¶ added in v0.16.0
SettingSource is where an effective value came from.
type SettingsError ¶ added in v0.16.0
SettingsError is one invalid value.
type SettingsErrors ¶ added in v0.16.0
SettingsErrors is every problem of a values document.
type SettingsLayer ¶ added in v0.16.0
SettingsLayer is one level of values.
type SettingsLayers ¶ added in v0.29.0
type SettingsLayers struct {
Tenant map[string]any `json:"tenant,omitempty"`
Sensor map[string]any `json:"sensor,omitempty"`
}
SettingsLayers are the administrators' layers of a scan command's tool settings: the tenant's policy and the sensor's configuration, set on the platform and carried in the command payload (covered by the job signature). Each is checked against the tool's own schema here, like the scan's config.
type SettingsSchema ¶ added in v0.16.0
SettingsSchema is a tool's parsed settings schema.
func MustParseSettingsSchema ¶ added in v0.16.0
func MustParseSettingsSchema(raw string) *SettingsSchema
MustParseSettingsSchema is ParseSettingsSchema for a schema compiled into the binary; it panics on an invalid schema.
func ParseSettingsSchema ¶ added in v0.16.0
func ParseSettingsSchema(raw []byte) (*SettingsSchema, error)
ParseSettingsSchema parses and checks a schema (settings.ParseSchema).
type SettingsSchemaError ¶ added in v0.16.0
type SettingsSchemaError = settings.SchemaError
SettingsSchemaError is why a schema is invalid.
type SettingsSchemaProvider ¶ added in v0.17.0
type SettingsSchemaProvider interface {
SettingsSchema() *SettingsSchema
}
SettingsSchemaProvider is a Scanner that declares its settings schema (api RFC-038). The command executor resolves a scan command's config against it into ScanOptions.Settings, and the tool registry reports it in the manifest. A wrapper around a scanner should forward it.
type SettingsSignature ¶ added in v0.16.0
type SettingsSignature struct {
Alg string `json:"alg"`
KeyID string `json:"keyid"`
Sig string `json:"sig"`
}
SettingsSignature is a detached signature over a settings document.
type SettingsStore ¶ added in v0.16.0
type SettingsStore interface {
// Load returns the stored document, or nil when there is none.
Load() (*SensorSettings, error)
// Save stores a document atomically. It refuses a document that fails
// Check or whose version is not above the stored one
// (ErrSettingsVersionNotNewer).
Save(*SensorSettings) error
}
SettingsStore keeps the sensor's settings document.
type SignedEnvelope ¶ added in v0.17.0
type SignedEnvelope struct {
PayloadType string `json:"payloadType"`
Payload []byte `json:"payload"`
Signatures []EnvelopeSignature `json:"signatures"`
}
SignedEnvelope is a DSSE envelope: Payload holds the exact signed bytes (base64 in JSON), each signature covers DSSEPreAuthEncoding(PayloadType, Payload).
type SourceCredentials ¶ added in v0.30.0
type SourceCredentials interface {
SourceCredential(ctx context.Context, cmdID string) (*source.Credential, error)
}
SourceCredentials fetches the credential of a code-scan command's source (the platform client: client.SourceCredential).
type StatusReporter ¶ added in v0.10.0
type StatusReporter interface {
ReportStatus(status *SensorStatus)
}
StatusReporter fills a heartbeat with what it knows about the sensor's work: load, resources, capacity, local queue and the held command ids. A BaseSensor whose load reporter (SetLoadReporter) also implements it calls it on every heartbeat. *CommandPoller implements it.
type Subdomain ¶
type Subdomain struct {
Host string `json:"host"` // Full subdomain (e.g., api.example.com)
Domain string `json:"domain"` // Root domain (e.g., example.com)
Source string `json:"source,omitempty"` // Discovery source (crtsh, hackertarget, etc.)
IPs []string `json:"ips,omitempty"` // Resolved IP addresses
}
Subdomain represents a discovered subdomain.
type TLSLeaf ¶ added in v0.18.0
type TLSLeaf struct {
SubjectCN string `json:"subject_cn,omitempty"`
SANs []string `json:"sans,omitempty"`
IssuerCN string `json:"issuer_cn,omitempty"`
IssuerOrg string `json:"issuer_org,omitempty"`
SerialNumber string `json:"serial_number,omitempty"`
NotBefore time.Time `json:"not_before,omitempty"`
NotAfter time.Time `json:"not_after,omitempty"`
FingerprintSHA256 string `json:"fingerprint_sha256,omitempty"` // Identity of the certificate
SelfSigned bool `json:"self_signed,omitempty"`
Expired bool `json:"expired,omitempty"`
Wildcard bool `json:"wildcard,omitempty"`
Mismatched bool `json:"mismatched,omitempty"` // Names do not cover the probed host
}
TLSLeaf is the leaf certificate an HTTP probe saw in a TLS handshake.
type TargetOutcome ¶ added in v0.26.0
type TargetOutcome struct {
Target string
// Err is the function's error; context.DeadlineExceeded when the
// target exceeded its budget.
Err error
// TimedOut is set when the target exceeded its budget.
TimedOut bool
// Skipped is set when the job's context ended before the target
// started.
Skipped bool
}
TargetOutcome is how one target ended.
func RunPerTarget ¶ added in v0.26.0
func RunPerTarget(ctx context.Context, targets []string, opts PerTargetOptions, fn func(ctx context.Context, target string) error) []TargetOutcome
RunPerTarget calls fn for every target and returns one outcome per target, in the targets' order. It returns when every started target ended; targets not started when ctx ended are Skipped. Every target that ends (any outcome but Skipped) is marked done in the job's Progress.
type TaskBudget ¶ added in v0.26.0
type TaskBudget struct {
// TargetSeconds is the per-target budget: a tool wrapper passes it as
// the tool's per-request or per-host timeout (ScanOptions.TargetTimeout)
// and RunPerTarget enforces it per target.
TargetSeconds int `json:"target_seconds,omitempty"`
// TaskSeconds is the expected time of the whole task.
TaskSeconds int `json:"task_seconds,omitempty"`
// StallSeconds is how long the task may go without finishing a target
// before the platform considers it stalled (informational here: the
// platform enforces it from the heartbeat's progress).
StallSeconds int `json:"stall_seconds,omitempty"`
}
TaskBudget is a scan command's budgets (ScanCommandPayload.Budget).
func (*TaskBudget) Overrun ¶ added in v0.26.0
func (b *TaskBudget) Overrun() time.Duration
Overrun is how long the task may run before the sensor stops it: OverrunFactor times its budget, clamped to [MinTaskBudget, MaxScanTimeout]; 0 when no task budget was sent.
func (*TaskBudget) Target ¶ added in v0.26.0
func (b *TaskBudget) Target() time.Duration
Target is the per-target budget, clamped; 0 when none was sent.
type Technology ¶
type Technology struct {
Name string `json:"name"` // Technology name
Version string `json:"version,omitempty"` // Version if detected
Categories []string `json:"categories,omitempty"` // Category (framework, cms, etc.)
Confidence int `json:"confidence,omitempty"` // Detection confidence (0-100)
Website string `json:"website,omitempty"` // Technology website
}
Technology represents a detected technology.
type TemplateBinding ¶ added in v0.17.0
type TemplateBinding struct {
CommandID string
SensorID string // "" when the sensor does not know its id
}
TemplateBinding is what a manifest must be bound to: the command that carries the templates and, when the sensor knows it, its own id.
type TemplateCache ¶
type TemplateCache struct {
// contains filtered or unexported fields
}
TemplateCache provides persistent caching of custom templates. Templates are organized by: {cache_dir}/{tenant_id}/{template_type}/{template_name}
func NewTemplateCache ¶
func NewTemplateCache(cfg *TemplateCacheConfig) (*TemplateCache, error)
NewTemplateCache creates a new template cache.
func (*TemplateCache) Cleanup ¶
func (c *TemplateCache) Cleanup() error
Cleanup removes old and excess cached templates.
func (*TemplateCache) Clear ¶
func (c *TemplateCache) Clear(tenantID string) error
Clear removes all cached templates for a tenant.
func (*TemplateCache) Get
deprecated
func (c *TemplateCache) Get(contentHash string) (string, bool)
Get retrieves a template from cache by content hash, regardless of the tenant or template type it was cached for.
Deprecated: Get is not tenant-scoped; a hit may be another tenant's file. Use GetFor.
func (*TemplateCache) GetFor ¶ added in v0.7.0
func (c *TemplateCache) GetFor(tenantID, templateType, contentHash string) (string, bool)
GetFor retrieves a cached template for one tenant and template type. Entries cached for other tenants are never returned.
func (*TemplateCache) GetOrPut ¶
func (c *TemplateCache) GetOrPut(tenantID string, template *EmbeddedTemplate) (string, error)
GetOrPut returns cached template path or caches the template. The lookup is scoped to tenantID and the template's type.
func (*TemplateCache) GetTemplateDir ¶
func (c *TemplateCache) GetTemplateDir(tenantID, templateType string, templates []EmbeddedTemplate) (string, error)
GetTemplateDir returns the directory holding templates of templateType for tenantID, caching any that are missing. Every template must be of templateType (an empty TemplateType is treated as templateType), so all files land in the single returned directory: {cache_dir}/{tenant_id}/{template_type}. Returns empty string if templates slice is empty.
func (*TemplateCache) Put ¶
func (c *TemplateCache) Put(tenantID string, template *EmbeddedTemplate) (string, error)
Put stores a template in the cache. Returns the file path where the template was written.
tenantID must be a UUID and template.TemplateType one of ValidTemplateTypes; the file is written under {cache_dir}/{tenant_id}/{template_type}/ and the resolved path is checked to stay inside the cache directory.
func (*TemplateCache) Remove ¶
func (c *TemplateCache) Remove(contentHash string) error
Remove removes every cached copy of a template (all tenants) by content hash.
func (*TemplateCache) Stats ¶
func (c *TemplateCache) Stats() *CacheStats
Stats returns cache statistics.
type TemplateCacheConfig ¶
type TemplateCacheConfig struct {
// CacheDir is the base directory for cached templates.
// Default: ~/.openctem/templates
CacheDir string
// MaxCacheAge is the maximum age of cached templates before cleanup.
// Default: 7 days
MaxCacheAge time.Duration
// MaxCacheSize is the maximum total size of the cache in bytes.
// Default: 100MB
MaxCacheSize int64
// CleanupInterval is how often to run cleanup.
// Default: 1 hour
CleanupInterval time.Duration
// Verbose enables verbose logging.
Verbose bool
}
TemplateCacheConfig configures the template cache.
func DefaultTemplateCacheConfig ¶
func DefaultTemplateCacheConfig() *TemplateCacheConfig
DefaultTemplateCacheConfig returns default cache configuration.
type TemplateManifest ¶ added in v0.17.0
type TemplateManifest struct {
Kind string `json:"kind"`
TenantID string `json:"tenant_id"`
SensorID string `json:"sensor_id,omitempty"`
CommandID string `json:"command_id"`
IssuedAt time.Time `json:"issued_at"`
ExpiresAt time.Time `json:"expires_at"`
// Templates lists every template of the command, in the command's
// order.
Templates []ManifestTemplate `json:"templates"`
}
TemplateManifest is the signed description of a command's custom templates.
type TemplateVerifier ¶ added in v0.17.0
type TemplateVerifier struct {
// contains filtered or unexported fields
}
TemplateVerifier checks signed template manifests against pinned public keys.
func NewTemplateVerifier ¶ added in v0.17.0
func NewTemplateVerifier(keys ...ed25519.PublicKey) (*TemplateVerifier, error)
NewTemplateVerifier returns a verifier for keys; at least one is needed.
func ParseTemplateSigningKeys ¶ added in v0.17.0
func ParseTemplateSigningKeys(s string) (*TemplateVerifier, error)
ParseTemplateSigningKeys reads a comma- or space-separated list of base64 (standard or URL alphabet, padded or not) Ed25519 public keys, the form the platform shows them in and SENSOR_TEMPLATE_SIGNING_KEYS takes. Several keys let an operator pin the next key before a rotation.
func (*TemplateVerifier) KeyIDs ¶ added in v0.17.0
func (v *TemplateVerifier) KeyIDs() []string
KeyIDs returns the pinned keys' ids.
func (*TemplateVerifier) Verify ¶ added in v0.17.0
func (v *TemplateVerifier) Verify(env *SignedEnvelope, b TemplateBinding, templates []EmbeddedTemplate, contents [][]byte) (*TemplateManifest, error)
Verify checks env against the pinned keys and returns its manifest. The signature is checked over the exact payload bytes before they are parsed. The manifest must then be a v1 template manifest for b.CommandID (and b.SensorID when set), issued no later than now (plus a small clock allowance) and not expired, and list exactly templates — the same count, and at each position the same id, name, type and SHA-256 of the decoded content (contents, decoded by the caller, in the same order).
type ToolContent ¶ added in v0.15.0
type ToolContent struct {
Tool string `json:"tool"`
ContentInfo
}
ToolContent is one piece of a tool's content on a slim heartbeat's "content" (api RFC-033 §6.12): ContentInfo with the tool it belongs to.
type ToolContract ¶ added in v0.18.0
type ToolContract struct {
APIVersion string `json:"api_version"`
Digest string `json:"digest"`
Version string `json:"version"`
Class string `json:"class"`
Tier string `json:"tier"`
Network string `json:"network,omitempty"`
Consumes []string `json:"consumes,omitempty"`
Produces []string `json:"produces"`
// Implements are the capability references the tool implements
// ("scan.ports@1").
Implements []string `json:"implements,omitempty"`
// Batch: the tool takes a list of targets per task.
Batch bool `json:"batch,omitempty"`
// Origin is where the tool comes from: ToolOriginBuiltin (compiled
// into the signed sensor binary) or ToolOriginAdapter (installed by
// the operator in an adapter directory). The platform derives the
// tool's trust level from it; it never trusts a tool's own claim.
Origin string `json:"origin,omitempty"`
// Descriptor is the tool's full manifest in canonical JSON (its
// SHA-256 is Digest), so the platform can plan with every fact of the
// contract. It travels in the manifest only, which is registered when
// it changes; heartbeats carry the manifest digest. Absent when larger
// than MaxToolDescriptorBytes.
Descriptor json.RawMessage `json:"descriptor,omitempty"`
}
ToolContract names a tool's tool.yaml manifest (pkg/tool) in the sensor manifest: its canonical digest and the fields the platform plans with. The runtime enforces exactly this manifest. Build it with tool.Manifest.Contract.
type ToolContractProvider ¶ added in v0.18.0
type ToolContractProvider interface {
ToolContract() *ToolContract
}
ToolContractProvider is a scanner ported to the tool contract: the registry reports its contract with the tool.
type ToolInfo ¶ added in v0.10.0
type ToolInfo struct {
// Name is the tool's catalog name ("semgrep", "nuclei", "trivy").
Name string `json:"name"`
// Kind is what the tool does (scanner or collector); empty when the
// sensor does not say.
Kind ToolKind `json:"kind,omitempty"`
// Version is the installed version, when known.
Version string `json:"version,omitempty"`
// Installed is false for a tool the sensor is configured to run but
// cannot find (or cannot run). The platform does not dispatch jobs for
// it and shows it as not installed.
Installed bool `json:"installed"`
// Capabilities are what this tool serves besides its own name ("sast",
// "dast", "validate:nuclei"): the per-tool mapping behind the sensor's
// flat capability list, so the platform can show (and route by) which
// tool provides what. nil reports nothing.
Capabilities []string `json:"capabilities,omitzero"`
// Content is the data the tool scans with (vulnerability database,
// templates, rules) and how fresh it is; see ContentInfo. nil reports
// nothing (the platform shows no content for the tool).
Content []ContentInfo `json:"content,omitzero"`
// Settings names the tool's settings schema (ToolSpec.Settings) for the
// manifest. It is not part of the heartbeat.
Settings *ManifestToolSettings `json:"-"`
// Contract is the tool's tool-contract manifest (ToolSpec.Contract);
// it travels in the manifest only, not on the heartbeat.
Contract *ToolContract `json:"-"`
}
ToolInfo is one tool on a heartbeat's tool inventory.
type ToolProbe ¶ added in v0.11.0
ToolProbe reports whether a tool is usable here and its version. It has the signature of Scanner.IsInstalled. An error counts as not installed.
type ToolRegistry ¶ added in v0.11.0
type ToolRegistry struct {
// contains filtered or unexported fields
}
ToolRegistry is the inventory a sensor reports: the tools it registered, how to check each one, the capabilities it serves and its concurrency. It implements CapabilityReporter. Safe for concurrent use.
func NewToolRegistry ¶ added in v0.11.0
func NewToolRegistry() *ToolRegistry
NewToolRegistry returns an empty registry.
func (*ToolRegistry) AddCapabilities ¶ added in v0.11.0
func (r *ToolRegistry) AddCapabilities(caps ...string)
AddCapabilities adds capabilities the sensor serves whatever its tools ("validate" for a sensor that runs validation jobs).
func (*ToolRegistry) Allowed ¶ added in v0.11.0
func (r *ToolRegistry) Allowed(name string) bool
Allowed reports whether the limit (if any) lets name through.
func (*ToolRegistry) CapabilityReport ¶ added in v0.11.0
func (r *ToolRegistry) CapabilityReport(ctx context.Context) CapabilityReport
CapabilityReport implements CapabilityReporter: the allowed tools (probed, results reused for the probe TTL), the capabilities of the usable ones plus the sensor-wide ones, and the concurrency. The slices are the caller's.
func (*ToolRegistry) CostHints ¶ added in v0.11.0
func (r *ToolRegistry) CostHints() map[string]resource.ToolCostHint
CostHints returns the cost hints of the allowed tools that have one (for resource.ManagerConfig.CostHints).
func (*ToolRegistry) HasKind ¶ added in v0.11.0
func (r *ToolRegistry) HasKind(k ToolKind) bool
HasKind reports whether an allowed tool of kind k is registered.
func (*ToolRegistry) Installed ¶ added in v0.11.0
func (r *ToolRegistry) Installed(ctx context.Context) []ToolInfo
Installed returns the inventory: every allowed tool, probed (results are reused for the probe TTL).
func (*ToolRegistry) Len ¶ added in v0.11.0
func (r *ToolRegistry) Len() int
Len is the number of registered tools.
func (*ToolRegistry) Limit ¶ added in v0.11.0
func (r *ToolRegistry) Limit(names ...string)
Limit narrows the report to the named tools: an operator allowlist (for example the SENSOR_TOOLS of a sensor image). Registered tools outside it are neither reported nor served. No names lifts the limit.
func (*ToolRegistry) Names ¶ added in v0.11.0
func (r *ToolRegistry) Names() []string
Names returns the registered tools allowed by the limit, in registration order (for resource.ManagerConfig.Tools).
func (*ToolRegistry) Refresh ¶ added in v0.11.0
func (r *ToolRegistry) Refresh()
Refresh makes the next report probe every tool again.
func (*ToolRegistry) Register ¶ added in v0.11.0
func (r *ToolRegistry) Register(spec ToolSpec) error
Register adds a tool. A second registration of the same name (another mode of one tool, such as trivy fs and trivy image) adds its capabilities to the first; the first registration's probe and version stay.
func (*ToolRegistry) RegisterCollector ¶ added in v0.11.0
func (r *ToolRegistry) RegisterCollector(c Collector, caps ...string) error
RegisterCollector registers a collector (always usable: it runs in process) serving caps.
func (*ToolRegistry) RegisterScanner ¶ added in v0.11.0
func (r *ToolRegistry) RegisterScanner(s Scanner, extraCaps ...string) error
RegisterScanner registers a scanner: probed with its IsInstalled, serving the registry capabilities its Capabilities words map to (descriptive words the platform does not know are left out) plus extraCaps as given, with its settings schema when it declares one (SettingsSchemaProvider).
func (*ToolRegistry) SetBackgroundRefresh ¶ added in v0.15.0
func (r *ToolRegistry) SetBackgroundRefresh(on bool)
SetBackgroundRefresh moves the probes after a tool's first one off the report: a result older than the probe TTL is reported as it is and the tool is probed again in the background, so the next report has the new result. A probe runs the tool's version check, which on a sensor whose scanners saturate the CPU can take many seconds; in the report it delays the heartbeat by as much (api RFC-035 §5.1). The first probe of each tool (and the one after Refresh) stays in the report. sensorkit turns it on.
func (*ToolRegistry) SetMaxConcurrentJobs ¶ added in v0.11.0
func (r *ToolRegistry) SetMaxConcurrentJobs(n int)
SetMaxConcurrentJobs sets the operator ceiling the report carries (the most jobs the sensor may run at once, SENSOR_MAX_JOBS); 0 or less reports none. What the sensor can run now is its dynamic slot count, reported separately (SensorStatus.Capacity).
func (*ToolRegistry) SetProbeTTL ¶ added in v0.11.0
func (r *ToolRegistry) SetProbeTTL(d time.Duration)
SetProbeTTL sets how long a probe result is reused (default DefaultToolProbeTTL); 0 probes on every report.
func (*ToolRegistry) SetProbeTimeout ¶ added in v0.11.0
func (r *ToolRegistry) SetProbeTimeout(d time.Duration)
SetProbeTimeout bounds one probe (default DefaultToolProbeTimeout).
func (*ToolRegistry) SettingsSchema ¶ added in v0.16.0
func (r *ToolRegistry) SettingsSchema(name string) *SettingsSchema
SettingsSchema returns a registered tool's settings schema, or nil (no such tool, or a tool without settings).
func (*ToolRegistry) SettingsSchemas ¶ added in v0.16.0
func (r *ToolRegistry) SettingsSchemas() map[string]*SettingsSchema
SettingsSchemas returns the settings schema of every allowed tool that has one, by tool name.
func (*ToolRegistry) Unregister ¶ added in v0.11.0
func (r *ToolRegistry) Unregister(name string)
Unregister removes a tool (no-op when absent).
type ToolSettings ¶ added in v0.16.0
ToolSettings are a tool's effective settings for one scan.
type ToolSettingsBlock ¶ added in v0.16.0
type ToolSettingsBlock struct {
SchemaDigest string `json:"schema_digest"`
Values map[string]any `json:"values"`
// SealedSecrets are the tool's secret values sealed to the sensor's
// key; kept sealed on disk.
SealedSecrets string `json:"sealed_secrets,omitempty"`
}
ToolSettingsBlock is one tool's part of a settings document.
type ToolSpec ¶ added in v0.11.0
type ToolSpec struct {
// Name is the tool's catalog name ("nuclei", "semgrep"): lowercase
// letters, digits, '.', '_' and '-', at most 64 characters (it is
// lowercased and trimmed). The platform keeps only names in its tool
// catalog.
Name string
// Kind defaults to ToolKindScanner.
Kind ToolKind
// Version is reported when the probe gives none (or there is no probe).
Version string
// Capabilities the tool serves when it is usable, besides its own name
// (the platform dispatches a scan with the tool's name as the required
// capability). Words the platform does not know are dropped there.
Capabilities []string
// Probe checks the tool; nil means it is always usable (an in-process
// tool).
Probe ToolProbe
// Cost is an optional estimate of one job's cost, the prior of the
// resource manager until it has learned the tool (see CostHints).
Cost *resource.ToolCostHint
// Settings is what an administrator may configure for the tool (api
// RFC-038); nil: nothing. The manifest names it by version and digest,
// and a scan receives the effective values as ScanOptions.Settings.
Settings *SettingsSchema
// Contract is the tool's tool-contract manifest, by digest and the
// fields the platform plans with (sdk-go docs/rfcs/sensor-sdk-v2.md);
// nil for a tool not ported to the contract.
Contract *ToolContract
}
ToolSpec registers one tool.
type ValidationError ¶
ValidationError represents a configuration validation error.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
type ValidationErrors ¶
type ValidationErrors []ValidationError
ValidationErrors is a collection of validation errors.
func (*ValidationErrors) Add ¶
func (e *ValidationErrors) Add(field, message string)
Add adds a validation error.
func (ValidationErrors) Error ¶
func (e ValidationErrors) Error() string
func (ValidationErrors) HasErrors ¶
func (e ValidationErrors) HasErrors() bool
HasErrors returns true if there are any errors.
type Validator ¶
type Validator struct {
// contains filtered or unexported fields
}
Validator provides validation methods for configurations.
func (*Validator) DirectoryExists ¶
DirectoryExists validates that a directory exists.
func (*Validator) Errors ¶
func (v *Validator) Errors() ValidationErrors
Errors returns all validation errors.
func (*Validator) FileExists ¶
FileExists validates that a file exists.
func (*Validator) MaxDuration ¶
MaxDuration validates that a duration is at most the maximum.
func (*Validator) MinDuration ¶
MinDuration validates that a duration is at least the minimum.
type Vulnerability ¶
type Vulnerability struct {
// Identity
ID string `json:"id"` // CVE ID or advisory ID
Fingerprint string `json:"fingerprint"` // For deduplication
// Package info
PkgID string `json:"pkg_id"` // Affected package ID
PkgName string `json:"pkg_name"` // Package name
PkgVersion string `json:"pkg_version"` // Installed version
// Vulnerability info
Name string `json:"name"` // Short title
Description string `json:"description"` // Full description
Severity string `json:"severity"` // critical, high, medium, low
FixedVersion string `json:"fixed_version"` // Version with fix
// Metadata
Metadata *VulnerabilityMetadata `json:"metadata,omitempty"`
}
Vulnerability represents a security vulnerability in a package.
type VulnerabilityMetadata ¶
type VulnerabilityMetadata struct {
CWEs []string `json:"cwes,omitempty"` // CWE identifiers
References []string `json:"references,omitempty"` // Advisory URLs
CVSSScore float64 `json:"cvss_score,omitempty"` // CVSS score
CVSSVector string `json:"cvss_vector,omitempty"` // CVSS vector string
Source string `json:"source,omitempty"` // NVD, GHSA, etc.
}
VulnerabilityMetadata contains additional vulnerability details.
type WebhookCollector ¶
type WebhookCollector struct {
*BaseCollector
// contains filtered or unexported fields
}
WebhookCollector receives data via HTTP webhooks.
func NewWebhookCollector ¶
func NewWebhookCollector(cfg *WebhookCollectorConfig) *WebhookCollector
NewWebhookCollector creates a new webhook collector.
func (*WebhookCollector) Collect ¶
func (c *WebhookCollector) Collect(ctx context.Context, opts *CollectOptions) (*CollectResult, error)
Collect waits for webhook data (blocking).
type WebhookCollectorConfig ¶
type WebhookCollectorConfig struct {
ListenAddr string `yaml:"listen_addr" json:"listen_addr"`
// Secret, when set, must accompany every delivery, as
// "Authorization: Bearer <secret>" or "X-Webhook-Secret: <secret>";
// other deliveries get 401. Without it the endpoint accepts anyone who
// can reach it.
Secret string `yaml:"secret" json:"secret"`
// MaxBodyBytes bounds one delivery (0: DefaultWebhookMaxBodyBytes);
// larger bodies get 413.
MaxBodyBytes int64 `yaml:"max_body_bytes" json:"max_body_bytes"`
Verbose bool `yaml:"verbose" json:"verbose"`
}
WebhookCollectorConfig configures a webhook collector.
Source Files
¶
- auth_gate.go
- base_collector.go
- base_scanner.go
- base_sensor.go
- budget.go
- build_info.go
- capabilities.go
- capability_job.go
- claim_backoff.go
- command_context.go
- command_events.go
- command_poller.go
- command_queue.go
- command_run_one.go
- config_report.go
- config_report_sync.go
- content.go
- control_stats.go
- coverage_gaps.go
- doorbell.go
- exec.go
- exec_output.go
- extra_args.go
- host_discovery.go
- instance.go
- interfaces.go
- job_exclusions.go
- job_signing.go
- local_policy.go
- local_policy_enforce.go
- local_policy_network.go
- logger.go
- manifest.go
- org_http_policy.go
- parser_registry.go
- per_target.go
- posture.go
- proc_group.go
- proc_group_linux.go
- proc_group_unix.go
- processor.go
- progress.go
- progress_cpu.go
- progress_cpu_linux.go
- refusal.go
- refused_targets.go
- scan_limits.go
- scan_settings.go
- scan_target.go
- scan_target_scanner.go
- scanner_env.go
- scanner_env_owner.go
- scanner_names.go
- scanner_priority.go
- scanner_priority_linux.go
- scanner_proxy.go
- settings.go
- settings_store.go
- source_job.go
- target_outcomes.go
- template_cache.go
- template_signing.go
- tool_registry.go
- usage_unix.go
- utils.go
- validation.go
- waves.go