Documentation
¶
Overview ¶
Package client provides the OpenCTEM API client.
Index ¶
- Constants
- Variables
- func DefaultLegacyRetryQueueDir() string
- func IsAuthenticationError(err error) bool
- func IsAuthorizationError(err error) bool
- func IsClientError(err error) bool
- func IsCommandGone(err error) bool
- func IsNotFoundError(err error) bool
- func IsRateLimitError(err error) bool
- func IsRetryable(err error) bool
- func IsServerError(err error) bool
- func ParseProtocol(s string) (string, error)
- type ChunkUploadResponse
- type Client
- func (c *Client) APIKeyHint() string
- func (c *Client) AbandonReport(ctx context.Context, reportID string) error
- func (c *Client) AcknowledgeCommand(ctx context.Context, cmdID string) error
- func (c *Client) AsChunkUploader() chunk.Uploader
- func (c *Client) BaselineDiff(ctx context.Context, repository, baseBranch string, fingerprints []string) ([]string, error)
- func (c *Client) CheckFingerprints(ctx context.Context, fingerprints []string) (*retry.FingerprintCheckResult, error)
- func (c *Client) Close() error
- func (c *Client) CompleteCommand(ctx context.Context, cmdID string, result json.RawMessage) error
- func (c *Client) Deliver(ctx context.Context, d *outbox.Delivery) (any, error)
- func (c *Client) DisableRetryQueue(_ context.Context) errordeprecated
- func (c *Client) EnableOutbox(cfg OutboxConfig) error
- func (c *Client) EnableRetryQueue(_ context.Context, cfg *RetryQueueConfig) errordeprecated
- func (c *Client) EnrichFindings(ctx context.Context, findings []ctis.Finding) ([]ctis.Finding, error)
- func (c *Client) FailCommand(ctx context.Context, cmdID string, errorMsg string) error
- func (c *Client) FilterSuppressedFindings(findings []ctis.Finding, rules []SuppressionRule) []ctis.Finding
- func (c *Client) FlushOutbox(ctx context.Context) error
- func (c *Client) GetCommands(ctx context.Context) (*core.GetCommandsResponse, error)
- func (c *Client) GetCommandsLimit(ctx context.Context, limit int) (*core.GetCommandsResponse, error)
- func (c *Client) GetEPSSScores(ctx context.Context, cveIDs []string) ([]EPSSScore, error)
- func (c *Client) GetKEVEntries(ctx context.Context, cveIDs []string) ([]KEVEntry, error)
- func (c *Client) GetReportStatus(ctx context.Context, reportID string) (*protov2.Status, error)
- func (c *Client) GetRetryQueueStats(_ context.Context) (*retry.QueueStats, error)deprecated
- func (c *Client) GetRetryWorkerStats() (*retry.WorkerStats, error)deprecated
- func (c *Client) GetSuppressions(ctx context.Context) ([]SuppressionRule, error)
- func (c *Client) Hello(ctx context.Context) (*protov2.Hello, error)
- func (c *Client) Outbox() *outbox.Outbox
- func (c *Client) OutboxStats() (outbox.Stats, bool)
- func (c *Client) PollCommands(ctx context.Context, limit int) ([]Command, error)
- func (c *Client) ProcessRetryQueueNow(ctx context.Context) errordeprecated
- func (c *Client) ProtocolFeatures() []string
- func (c *Client) PushAssets(ctx context.Context, report *ctis.Report) (*core.PushResult, error)
- func (c *Client) PushExposures(ctx context.Context, events []ExposureEvent) (*PushExposuresResult, error)
- func (c *Client) PushFindings(ctx context.Context, report *ctis.Report) (*core.PushResult, error)
- func (c *Client) PushReport(ctx context.Context, report *ctis.Report) errordeprecated
- func (c *Client) PushResultsV2(ctx context.Context, report *ctis.Report, opts *V2PushOptions) (*protov2.Status, error)
- func (c *Client) ReleaseCommand(ctx context.Context, cmdID, reason string) error
- func (c *Client) ReportCommandProgress(ctx context.Context, cmdID string, progress int, message string) error
- func (c *Client) ReportCommandResult(ctx context.Context, cmdID string, result *core.CommandResult) error
- func (c *Client) ResultsProtocol(ctx context.Context) (string, error)
- func (c *Client) SendHeartbeat(ctx context.Context, status *core.SensorStatus) error
- func (c *Client) SendHeartbeatWithHints(ctx context.Context, status *core.SensorStatus) (*core.HeartbeatHints, error)
- func (c *Client) SetAPIKey(key string)
- func (c *Client) SetVerbose(v bool)
- func (c *Client) StartCommand(ctx context.Context, cmdID string) error
- func (c *Client) StartRetryWorker(_ context.Context) errordeprecated
- func (c *Client) StopRetryWorker(_ context.Context) errordeprecated
- func (c *Client) TestConnection(ctx context.Context) error
- func (c *Client) UploadChunk(ctx context.Context, data *chunk.ChunkData) error
- type Command
- type Config
- type EPSSScore
- type ExposureEvent
- type HTTPError
- type HeartbeatOutbox
- type HeartbeatRequest
- type IngestResponse
- type KEVEntry
- type Option
- func WithAPIKey(key string) Option
- func WithBaseURL(url string) Option
- func WithCompression(algorithm string, level int) Option
- func WithProtocol(p string) Option
- func WithRetry(maxRetries int, retryDelay time.Duration) Option
- func WithSensorID(id string) Option
- func WithTimeout(d time.Duration) Option
- func WithUserAgent(product string) Option
- func WithVerbose(v bool) Option
- func WithoutCompression() Option
- type OutboxConfig
- type PushExposuresResult
- type RefusedError
- type RetryQueueConfigdeprecated
- type SuppressionRule
- type V2Error
- type V2Progress
- type V2PushOptions
Constants ¶
const ( // ProtocolAuto uses v2 when the platform offers it and v1 otherwise // (the default). ProtocolAuto = "auto" // ProtocolV1 always uses the frozen v1 ingest routes. ProtocolV1 = "v1" // ProtocolV2 always uses v2 and fails against a platform without it. ProtocolV2 = "v2" )
Results protocol selection (Config.Protocol, SENSOR_PROTOCOL).
const DefaultCommandPollLimit = 10
DefaultCommandPollLimit is how many commands GetCommands asks for.
const DefaultOutboxSyncWait = 30 * time.Second
DefaultOutboxSyncWait is OutboxConfig.SyncWait's default.
Variables ¶
var ErrV2NoTool = errors.New("protocol v2 requires report.tool.name")
ErrV2NoTool: v2 requires the report's tool (RFC-026 §3.3 step 8).
var ErrV2Unsupported = errors.New("the platform does not offer protocol v2 results (set the protocol to auto or v1)")
ErrV2Unsupported: protocol v2 was required but the platform does not offer it.
Functions ¶
func DefaultLegacyRetryQueueDir ¶ added in v0.8.0
func DefaultLegacyRetryQueueDir() string
DefaultLegacyRetryQueueDir is where pre-outbox SDKs kept their retry queue.
func IsAuthenticationError ¶
IsAuthenticationError checks if the error is a 401 authentication error.
func IsAuthorizationError ¶
IsAuthorizationError checks if the error is a 403 authorization error.
func IsClientError ¶
IsClientError checks if the error is a 4xx client error.
func IsCommandGone ¶ added in v0.9.0
IsCommandGone reports whether err says the command can no longer be worked on by this sensor: another sensor claimed it, it was canceled or expired, it already finished, or it is not (or no longer) this sensor's. The poller drops such a command instead of retrying it.
func IsNotFoundError ¶
IsNotFoundError checks if the error is a 404 not found error.
func IsRateLimitError ¶
IsRateLimitError checks if the error is a 429 rate limit error.
func IsRetryable ¶
IsRetryable checks if the error should be retried.
func IsServerError ¶
IsServerError checks if the error is a 5xx server error.
func ParseProtocol ¶ added in v0.8.0
ParseProtocol validates a protocol setting ("" is auto).
Types ¶
type ChunkUploadResponse ¶
type ChunkUploadResponse struct {
ChunkID string `json:"chunk_id"`
ReportID string `json:"report_id"`
ChunkIndex int `json:"chunk_index"`
Status string `json:"status"`
AssetsCreated int `json:"assets_created"`
AssetsUpdated int `json:"assets_updated"`
FindingsCreated int `json:"findings_created"`
FindingsUpdated int `json:"findings_updated"`
FindingsSkipped int `json:"findings_skipped"`
}
ChunkUploadResponse is the response from chunk upload endpoint.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is the OpenCTEM API client. It implements the core.Pusher interface.
func NewWithOptions ¶
NewWithOptions creates a new client using functional options. Example:
client := client.NewWithOptions(
client.WithBaseURL("http://localhost:8080"),
client.WithAPIKey("xxx"),
client.WithSensorID("agent-1"),
client.WithTimeout(30 * time.Second),
)
func (*Client) APIKeyHint ¶ added in v0.8.0
APIKeyHint names the client's API key in log lines without revealing it (core.APIKeyHint: at most its first 8 characters).
func (*Client) AbandonReport ¶ added in v0.8.0
AbandonReport deletes an uncommitted segmented report.
func (*Client) AcknowledgeCommand ¶
AcknowledgeCommand acknowledges receipt of a command.
func (*Client) AsChunkUploader ¶
AsChunkUploader returns the client as a chunk.Uploader interface. This is useful for passing to chunk.Manager.
func (*Client) BaselineDiff ¶ added in v0.4.0
func (c *Client) BaselineDiff(ctx context.Context, repository, baseBranch string, fingerprints []string) ([]string, error)
BaselineDiff returns the subset of fingerprints that are NEW relative to a PR's base/target branch (not already open there). Used to focus a PR gate / inline comments on findings the PR introduces, not pre-existing tech debt. On error or no PR context the caller should treat all findings as new (fail-open for visibility). Returns the new fingerprints.
func (*Client) CheckFingerprints ¶
func (c *Client) CheckFingerprints(ctx context.Context, fingerprints []string) (*retry.FingerprintCheckResult, error)
CheckFingerprints checks which fingerprints already exist on the server. This is used by the retry mechanism to avoid re-uploading data that already exists. It also serves as a connectivity check before processing the retry queue. This method implements retry.FingerprintChecker interface.
func (*Client) Close ¶
Close stops the outbox's delivery and releases its directory. Items not delivered yet stay on disk for the next process.
func (*Client) CompleteCommand ¶
CompleteCommand marks a command as completed with optional result.
func (*Client) Deliver ¶ added in v0.8.0
Deliver implements outbox.Deliverer: one attempt at one item, classified for the outbox (RFC-026 §3.8 retry table).
func (*Client) DisableRetryQueue
deprecated
func (*Client) EnableOutbox ¶ added in v0.8.0
func (c *Client) EnableOutbox(cfg OutboxConfig) error
EnableOutbox opens the outbox and starts delivering from it in the background until Close. Reports left in an old retry-queue directory are imported first.
func (*Client) EnableRetryQueue
deprecated
func (c *Client) EnableRetryQueue(_ context.Context, cfg *RetryQueueConfig) error
EnableRetryQueue enables the durable outbox in cfg.Dir/outbox (default ~/.openctem/outbox) and imports the reports an older SDK queued in cfg.Dir.
Deprecated: use EnableOutbox.
func (*Client) EnrichFindings ¶
func (c *Client) EnrichFindings(ctx context.Context, findings []ctis.Finding) ([]ctis.Finding, error)
EnrichFindings adds EPSS and KEV data to findings with CVE IDs.
func (*Client) FailCommand ¶
FailCommand marks a command as failed with an error message.
func (*Client) FilterSuppressedFindings ¶
func (c *Client) FilterSuppressedFindings(findings []ctis.Finding, rules []SuppressionRule) []ctis.Finding
FilterSuppressedFindings removes findings that match suppression rules. This is used by the security gate to exclude false positives.
func (*Client) FlushOutbox ¶ added in v0.8.0
FlushOutbox delivers what can be delivered now and returns when nothing is left that could be sent right away (or ctx ends). A one-shot run calls it before exiting.
func (*Client) GetCommands ¶
GetCommands retrieves pending commands from the server (implements core.CommandClient).
func (*Client) GetCommandsLimit ¶ added in v0.10.0
func (c *Client) GetCommandsLimit(ctx context.Context, limit int) (*core.GetCommandsResponse, error)
GetCommandsLimit retrieves at most limit pending commands (implements core.LimitedCommandClient). The CommandPoller passes its free slots, so the platform keeps the rest for sensors that can run them now. limit < 1 is 1.
func (*Client) GetEPSSScores ¶
GetEPSSScores fetches EPSS scores for the given CVE IDs.
func (*Client) GetKEVEntries ¶
GetKEVEntries fetches CISA KEV entries for the given CVE IDs.
func (*Client) GetReportStatus ¶ added in v0.8.0
GetReportStatus reads a report's status resource.
func (*Client) GetRetryQueueStats
deprecated
func (*Client) GetRetryWorkerStats
deprecated
func (c *Client) GetRetryWorkerStats() (*retry.WorkerStats, error)
GetRetryWorkerStats returns the outbox's delivery counters in the old shape.
Deprecated: use OutboxStats.
func (*Client) GetSuppressions ¶
func (c *Client) GetSuppressions(ctx context.Context) ([]SuppressionRule, error)
GetSuppressions fetches the tenant's active suppression rules from the platform, for the security gate to leave out findings the platform has suppressed.
It calls the sensor route (legacyv1.PathSuppressions). An API that predates that route answers 404; the client then tries the user route (legacyv1.PathSuppressionsUser) once, which only accepts a user token.
A failure is returned, never swallowed: the caller decides whether a gate may run without suppressions, and should say so where the operator sees it.
func (*Client) Outbox ¶ added in v0.8.0
Outbox returns the client's outbox, or nil when it is not enabled.
func (*Client) OutboxStats ¶ added in v0.8.0
OutboxStats returns the outbox's state; ok is false without an outbox.
func (*Client) PollCommands ¶
PollCommands retrieves pending commands for this sensor.
func (*Client) ProcessRetryQueueNow
deprecated
func (*Client) ProtocolFeatures ¶ added in v0.9.0
ProtocolFeatures returns the features this client uses protocol v2 for, as last negotiated (nil: protocol v1 for everything, or not asked yet).
func (*Client) PushAssets ¶
PushAssets sends a report's assets (its findings are dropped). See PushFindings for the outbox behavior.
func (*Client) PushExposures ¶
func (c *Client) PushExposures(ctx context.Context, events []ExposureEvent) (*PushExposuresResult, error)
PushExposures sends exposure events to OpenCTEM.
func (*Client) PushFindings ¶
PushFindings sends a report's findings (and assets) to OpenCTEM, over protocol v2 when the platform offers it (Config.Protocol) and v1 otherwise.
With the outbox enabled (EnableOutbox) the report is first written to disk and this call waits up to OutboxConfig.SyncWait for its delivery: it returns the result when the platform accepted it, a *RefusedError when the platform refused it for good (dead letter), and Queued=true when the platform could not be reached yet; the outbox delivers it later, across restarts. Without the outbox the report is sent once (with the client's own retries) and an error means it was not delivered.
A context from core.WithCommandID binds the results to that command.
func (*Client) PushResultsV2 ¶ added in v0.8.0
func (c *Client) PushResultsV2(ctx context.Context, report *ctis.Report, opts *V2PushOptions) (*protov2.Status, error)
PushResultsV2 sends a report over protocol v2 and returns its status resource. It makes one pass: transient failures (network, 429, 5xx) are returned as errors for the caller to retry with the same report id and progress (the outbox does). It handles the protocol's own recoveries: a 413 re-splits into smaller segments, an expired report or a gone command restarts under a new report id (unbound), and a conflicting replay of a report the server already has is resolved by reading its status.
func (*Client) ReleaseCommand ¶ added in v0.10.0
ReleaseCommand hands a claimed command back to the platform, which returns it to pending (unpinned) so any sensor can run it at once (implements core.ReleasingCommandClient). On a platform without the release transition (protocol v1, or a v2 platform from before it) the command is failed with "released: <reason>" instead, so it does not wait for a timeout.
func (*Client) ReportCommandProgress ¶
func (c *Client) ReportCommandProgress(ctx context.Context, cmdID string, progress int, message string) error
ReportCommandProgress reports progress of command execution.
func (*Client) ReportCommandResult ¶
func (c *Client) ReportCommandResult(ctx context.Context, cmdID string, result *core.CommandResult) error
ReportCommandResult reports the result of command execution (implements core.CommandClient). With the outbox enabled the result is stored and delivered after every report of the same command was accepted (or refused, which turns a "completed" result into "failed"); it returns once the result was delivered, or after OutboxConfig.SyncWait (or at once while the platform is unreachable) with the result safe on disk.
Waiting for the delivery matters for dispatch (api RFC-030): the platform counts the command as held by this sensor until its complete arrives, so a poller that freed the slot and polled first was refused (no free capacity) or, before the platform knew the sensor's capacity, handed one command too many.
func (*Client) ResultsProtocol ¶ added in v0.8.0
ResultsProtocol returns the protocol the client uses for results now ("v1" or "v2"), asking the platform when the decision is stale (auto).
func (*Client) SendHeartbeat ¶
SendHeartbeat sends a heartbeat to OpenCTEM. It does not announce the heartbeat doorbell and ignores the response body: a caller that acts on the platform's hints uses SendHeartbeatWithHints instead.
func (*Client) SendHeartbeatWithHints ¶ added in v0.7.1
func (c *Client) SendHeartbeatWithHints(ctx context.Context, status *core.SensorStatus) (*core.HeartbeatHints, error)
SendHeartbeatWithHints sends a heartbeat that announces the doorbell (X-OpenCTEM-Sensor-Features: doorbell) and returns the hints the platform answered with. Against a server without the doorbell the hints have Present=false. Announcing the feature is a promise to act on it: a disabled sensor is then answered 200 with the pause action instead of 401. On protocol v2 the doorbell is always on.
func (*Client) SetAPIKey ¶ added in v0.5.0
SetAPIKey atomically replaces the API key used by subsequent requests. Safe to call concurrently with in-flight pushes (sensor key auto-renewal).
func (*Client) StartCommand ¶
StartCommand marks a command as started.
func (*Client) StartRetryWorker
deprecated
func (*Client) StopRetryWorker
deprecated
func (*Client) TestConnection ¶
TestConnection tests the API connection.
type Command ¶
type Command struct {
ID string `json:"id"`
TenantID string `json:"tenant_id,omitempty"`
SourceID string `json:"source_id,omitempty"`
Type string `json:"type"`
Priority string `json:"priority"`
Payload json.RawMessage `json:"payload,omitempty"`
Status string `json:"status"`
ErrorMessage string `json:"error_message,omitempty"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
AcknowledgedAt *time.Time `json:"acknowledged_at,omitempty"`
StartedAt *time.Time `json:"started_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
Result json.RawMessage `json:"result,omitempty"`
}
Command represents a command from the server.
type Config ¶
type Config struct {
BaseURL string `yaml:"base_url" json:"base_url"`
APIKey string `yaml:"api_key" json:"api_key"`
SensorID string `yaml:"sensor_id" json:"sensor_id"` // Registered sensor ID for audit trail; the pre-rename key agent_id is still read (config_compat.go)
Timeout time.Duration `yaml:"timeout" json:"timeout"`
MaxRetries int `yaml:"max_retries" json:"max_retries"`
RetryDelay time.Duration `yaml:"retry_delay" json:"retry_delay"`
Verbose bool `yaml:"verbose" json:"verbose"`
// UserAgent is this client's product token, "name/version" (for example
// "openctemio-sensor/0.3.1"), sent before the SDK's own token:
// "openctemio-sensor/0.3.1 openctem-sdk-go/0.7.4". Empty: the process-wide
// product set with useragent.SetProduct, if any.
UserAgent string `yaml:"user_agent" json:"user_agent"`
// Compression configuration
EnableCompression bool `yaml:"enable_compression" json:"enable_compression"` // Enable request compression (default: true)
CompressionAlgo string `yaml:"compression_algo" json:"compression_algo"` // "zstd" or "gzip" (default: "zstd")
CompressionLevel int `yaml:"compression_level" json:"compression_level"` // 1-9 (default: 3)
// Protocol selects the results protocol: "auto" (default: v2 when the
// platform offers it, else v1), "v1" or "v2".
Protocol string `yaml:"protocol" json:"protocol"`
// OutboxDir enables the durable outbox (see EnableOutbox) in that
// directory. New logs, and leaves the outbox off, when it cannot be
// opened; call EnableOutbox yourself to handle the error.
OutboxDir string `yaml:"outbox_dir" json:"outbox_dir"`
// OutboxMaxBytes and OutboxMaxAge override the outbox caps.
OutboxMaxBytes int64 `yaml:"outbox_max_bytes" json:"outbox_max_bytes"`
OutboxMaxAge time.Duration `yaml:"outbox_max_age" json:"outbox_max_age"`
// Deprecated: the retry queue is replaced by the outbox. EnableRetryQueue
// enables the outbox (in OutboxDir, else RetryQueueDir/outbox, else
// ~/.openctem/outbox) and imports the reports an older SDK left in
// RetryQueueDir. RetryInterval and RetryMaxAttempts are ignored: the
// outbox retries with back-off until RetryTTL (OutboxMaxAge) evicts.
EnableRetryQueue bool `yaml:"enable_retry_queue" json:"enable_retry_queue"`
RetryQueueDir string `yaml:"retry_queue_dir" json:"retry_queue_dir"`
RetryInterval time.Duration `yaml:"retry_interval" json:"retry_interval"`
RetryMaxAttempts int `yaml:"retry_max_attempts" json:"retry_max_attempts"`
RetryTTL time.Duration `yaml:"retry_ttl" json:"retry_ttl"`
}
Config holds client configuration.
func (*Config) UnmarshalJSON ¶ added in v0.7.0
UnmarshalJSON reads Config, accepting the pre-rename key "agent_id" for SensorID so configuration files written before the agent -> sensor rename keep working (see legacyv1.MergeSensorID).
type EPSSScore ¶
type EPSSScore struct {
CVEID string `json:"cve_id"`
Score float64 `json:"score"` // 0.0 to 1.0
Percentile float64 `json:"percentile"` // 0.0 to 100.0
Date time.Time `json:"date"`
}
EPSSScore represents an EPSS score for a CVE.
type ExposureEvent ¶
type ExposureEvent struct {
// Event type: new_asset, asset_removed, exposure_detected, exposure_resolved
Type string `json:"type"`
// Asset identifier
AssetID string `json:"asset_id,omitempty"`
AssetType string `json:"asset_type,omitempty"`
AssetName string `json:"asset_name,omitempty"`
// Exposure details
ExposureType string `json:"exposure_type,omitempty"` // port_open, service_exposed, etc.
Protocol string `json:"protocol,omitempty"`
Port int `json:"port,omitempty"`
Service string `json:"service,omitempty"`
// Detection info
DetectedAt time.Time `json:"detected_at"`
DetectedBy string `json:"detected_by,omitempty"` // scan source
Severity string `json:"severity,omitempty"`
Description string `json:"description,omitempty"`
// Resolution
ResolvedAt *time.Time `json:"resolved_at,omitempty"`
// Metadata
Tags []string `json:"tags,omitempty"`
Properties map[string]any `json:"properties,omitempty"`
}
ExposureEvent represents an attack surface change event.
type HTTPError ¶
type HTTPError struct {
StatusCode int `json:"status_code"`
Body string `json:"body"`
RequestID string `json:"request_id,omitempty"`
// RetryAfter is the server's Retry-After (429/503), 0 when absent.
RetryAfter time.Duration `json:"retry_after,omitempty"`
}
HTTPError represents an HTTP error response.
func IsHTTPError ¶
IsHTTPError checks if err is an HTTPError and returns it.
func (*HTTPError) HTTPStatusCode ¶ added in v0.8.0
HTTPStatusCode returns the response status. pkg/core uses it to tell a rejected API key (401/403) from other failures without importing this package.
type HeartbeatOutbox ¶ added in v0.8.0
type HeartbeatOutbox struct {
PendingCount int `json:"pending_count"`
PendingBytes int64 `json:"pending_bytes"`
OldestAgeSeconds int64 `json:"oldest_age_seconds"`
DeadLetterCount int `json:"dead_letter_count"`
EvictedCount int64 `json:"evicted_count"`
}
HeartbeatOutbox is the outbox state a heartbeat reports (additive to the v1 heartbeat; servers that do not know it ignore it).
type HeartbeatRequest ¶
type HeartbeatRequest struct {
Name string `json:"name,omitempty"`
Status core.SensorState `json:"status"`
Version string `json:"version,omitempty"`
Hostname string `json:"hostname,omitempty"`
// InstanceID is this sensor process's random id
// (core.ProcessInstanceID): a restart changes it once, a key running in
// two places makes two ids alternate, which the platform flags (api
// RFC-032 Phase 0). Platforms that do not know it ignore it.
InstanceID string `json:"instance_id,omitempty"`
Message string `json:"message,omitempty"`
Scanners []string `json:"scanners,omitempty"`
Collectors []string `json:"collectors,omitempty"`
Uptime int64 `json:"uptime_seconds,omitempty"`
TotalScans int64 `json:"total_scans,omitempty"`
Errors int64 `json:"errors,omitempty"`
// System Metrics
CPUPercent float64 `json:"cpu_percent,omitempty"`
MemoryPercent float64 `json:"memory_percent,omitempty"`
ActiveJobs int `json:"active_jobs,omitempty"`
Region string `json:"region,omitempty"`
// ActiveJobsReported sends active_jobs even when it is 0 (the sensor
// measured it). Without it a 0 is left out, as before.
ActiveJobsReported bool `json:"-"`
// Outbox is the durable outbox's state (absent without an outbox).
Outbox *HeartbeatOutbox `json:"outbox,omitempty"`
// The sensor-reported capabilities (core.CapabilityReport): absent when
// the sensor reports nothing, and an empty list when it reports none.
Tools []core.ToolInfo `json:"tools,omitzero"`
Capabilities []string `json:"capabilities,omitzero"`
MaxConcurrentJobs int `json:"max_concurrent_jobs,omitempty"`
OS string `json:"os,omitempty"`
Arch string `json:"arch,omitempty"`
// The sensor's work now (core.SensorStatus; api RFC-030): absent when
// not reported.
Resources *resource.HostResources `json:"resources,omitempty"`
Capacity *resource.Capacity `json:"capacity,omitempty"`
Queue *core.QueueStats `json:"queue,omitempty"`
RunningCommands []string `json:"running,omitzero"`
// SDK and Sensor name the SDK and the sensor binary. Every heartbeat
// sends both: what the status carries, else the SDK linked into this
// binary and a sensor block built from the status's version.
SDK *core.SDKInfo `json:"sdk,omitempty"`
Sensor *core.SensorBuild `json:"sensor,omitempty"`
}
HeartbeatRequest is the heartbeat payload.
func (HeartbeatRequest) MarshalJSON ¶ added in v0.10.0
func (r HeartbeatRequest) MarshalJSON() ([]byte, error)
MarshalJSON encodes the heartbeat. active_jobs is sent even when it is 0 if ActiveJobsReported is set: an idle sensor then reports "0 running", which the platform's dispatch can trust, instead of leaving the field out.
type IngestResponse ¶
type IngestResponse struct {
ScanID string `json:"scan_id"`
AssetsCreated int `json:"assets_created"`
AssetsUpdated int `json:"assets_updated"`
FindingsCreated int `json:"findings_created"`
FindingsUpdated int `json:"findings_updated"`
FindingsSkipped int `json:"findings_skipped"`
Errors []string `json:"errors,omitempty"`
}
IngestResponse is the response from ingest endpoints.
type KEVEntry ¶
type KEVEntry struct {
CVEID string `json:"cve_id"`
VendorProject string `json:"vendor_project"`
Product string `json:"product"`
VulnerabilityName string `json:"vulnerability_name"`
DateAdded time.Time `json:"date_added"`
ShortDescription string `json:"short_description"`
RequiredAction string `json:"required_action"`
DueDate time.Time `json:"due_date"`
KnownRansomwareCampaignUse string `json:"known_ransomware_campaign_use"`
}
KEVEntry represents a CISA Known Exploited Vulnerabilities entry.
type Option ¶
type Option func(*Client)
Option is a function that configures the client.
func WithCompression ¶
WithCompression enables request compression with the specified algorithm. Supported algorithms: "zstd" (recommended), "gzip"
func WithProtocol ¶ added in v0.8.0
WithProtocol sets the results protocol: ProtocolAuto (default), ProtocolV1 or ProtocolV2. An unknown value keeps auto.
func WithSensorID ¶ added in v0.7.0
WithSensorID sets the sensor ID for tracking which sensor is pushing data.
func WithUserAgent ¶ added in v0.8.0
WithUserAgent sets this client's product token, "name/version", sent before the SDK's own token in the User-Agent (see Config.UserAgent).
func WithoutCompression ¶
func WithoutCompression() Option
WithoutCompression disables request compression.
type OutboxConfig ¶ added in v0.8.0
type OutboxConfig struct {
// Dir is the outbox directory (required). The sensor's default is
// /var/lib/openctem/outbox.
Dir string
// KeyFile is the encryption key file (default <Dir>/outbox.key).
KeyFile string
// MaxBytes caps the bytes on disk (default 1 GiB, and never more than
// half of the space the outbox could use).
MaxBytes int64
// MaxAge evicts items older than this (default 7 days).
MaxAge time.Duration
// Concurrency is 1 (default) or 2.
Concurrency int
// SyncWait is how long PushFindings/PushAssets wait for the first
// delivery before answering "queued" (default 30s; negative: do not
// wait).
SyncWait time.Duration
// LegacyRetryQueueDir is a pre-outbox retry-queue directory whose
// reports are imported once (default ~/.openctem/retry-queue; "-" skips
// the import).
LegacyRetryQueueDir string
// Logf receives the outbox's log lines (default: stderr with a
// timestamp).
Logf func(format string, args ...any)
// OnEvict is told when the caps dropped results (turn it into an alert).
OnEvict func(evicted []outbox.Meta, reason string)
}
OutboxConfig enables the durable outbox (pkg/outbox) on a client. With it, every report and command result is written to disk before the first send and deleted only after the platform acknowledged it.
type PushExposuresResult ¶
type PushExposuresResult struct {
EventsCreated int `json:"events_created"`
EventsUpdated int `json:"events_updated"`
EventsSkipped int `json:"events_skipped"`
}
PushExposuresResult is the result of pushing exposure events.
type RefusedError ¶ added in v0.8.0
type RefusedError struct {
DeadLetter outbox.DeadLetter
}
RefusedError says the platform refused a report for good; it is in the outbox's dead-letter folder.
func (*RefusedError) Error ¶ added in v0.8.0
func (e *RefusedError) Error() string
type RetryQueueConfig
deprecated
type RetryQueueConfig struct {
Dir string
MaxSize int
Interval time.Duration
BatchSize int
MaxAttempts int
TTL time.Duration
Backoff *retry.BackoffConfig
AutoStart bool
}
RetryQueueConfig configures the retry queue.
Deprecated: use EnableOutbox with an OutboxConfig. Dir is where the old queue's files are imported from (the outbox lives in Dir/outbox); TTL becomes the outbox's MaxAge; the other fields are ignored.
func DefaultRetryQueueConfig
deprecated
func DefaultRetryQueueConfig() *RetryQueueConfig
DefaultRetryQueueConfig returns a configuration with default values.
Deprecated: use EnableOutbox.
type SuppressionRule ¶
type SuppressionRule struct {
RuleID string `json:"rule_id,omitempty"`
ToolName string `json:"tool_name,omitempty"`
PathPattern string `json:"path_pattern,omitempty"`
AssetID *string `json:"asset_id,omitempty"`
ExpiresAt *string `json:"expires_at,omitempty"`
}
SuppressionRule represents a platform-controlled suppression rule.
type V2Error ¶ added in v0.8.0
type V2Error struct {
Status int
Problem *protov2.Problem
RetryAfter time.Duration
// Body is the raw answer when it was not a problem document (truncated).
Body string
RequestID string
}
V2Error is a non-2xx answer of a v2 resource.
func (*V2Error) HTTPStatusCode ¶ added in v0.8.0
HTTPStatusCode lets core.AuthFailureStatus classify the error.
func (*V2Error) ProblemName ¶ added in v0.8.0
func (e *V2Error) ProblemName() protov2.ProblemType
ProblemName is the problem type's short name, or "".
type V2Progress ¶ added in v0.8.0
type V2Progress struct {
// ReportID in use (it changes only when the report had to be restarted:
// expired, or re-split after a 413).
ReportID string `json:"report_id"`
// Unbound: the command is gone; the report is sent unsolicited.
Unbound bool `json:"unbound,omitempty"`
// SegFindings and SegBytes cap the segments after a 413 (0: the
// server's limits). Each 413 halves the segment that was refused.
SegFindings int `json:"seg_findings,omitempty"`
SegBytes int `json:"seg_bytes,omitempty"`
// Split is true once the report was split after a 413: it is then sent
// as segments plus a commit even when one segment remains.
Split bool `json:"split,omitempty"`
// Segments is the planned segment count (0: not planned yet).
Segments int `json:"segments,omitempty"`
// Acked maps a segment number to the Content-Digest the server
// acknowledged for it.
Acked map[int]string `json:"acked,omitempty"`
// Restarts counts report-id restarts (bounded).
Restarts int `json:"restarts,omitempty"`
// contains filtered or unexported fields
}
V2Progress is the resumable state of one v2 report delivery. The outbox persists it, so a restart neither resends acknowledged segments nor loses the report id.
type V2PushOptions ¶ added in v0.8.0
type V2PushOptions struct {
// ReportID is the stable report id (lower-case UUID). Empty: a new
// UUIDv7. Retries MUST reuse it.
ReportID string
// CommandID binds the report to a command this sensor claimed ("" for
// unsolicited results).
CommandID string
// Progress resumes an earlier attempt (nil: start).
Progress *V2Progress
// OnProgress persists progress after every acknowledged segment and
// every restart. An error stops the push.
OnProgress func(V2Progress) error
// Logf receives restarts and fall-backs. Nil: silent.
Logf func(format string, args ...any)
// MaxFindingsPerSegment lowers the server's per-segment finding limit
// (0: the server's). For constrained links and conformance tests.
MaxFindingsPerSegment int
}
V2PushOptions configures PushResultsV2.