xbow

package module
v0.0.0-...-9de3175 Latest Latest
Warning

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

Go to latest
Published: Feb 12, 2026 License: MIT Imports: 21 Imported by: 0

README

xbow

⚠️ Unofficial & Alpha: This is not an official XBOW library. It is a personal/community project and is currently in alpha. The API may change without notice.

An idiomatic Go client library and CLI for the XBOW API, following google/go-github patterns.

Installation

CLI
go install github.com/rsclarke/xbow/cmd/xbow@latest
Library
go get github.com/rsclarke/xbow

Requires Go 1.23+ (uses iter.Seq2 for pagination).

CLI Usage

The xbow CLI provides command-line access to the XBOW API.

Authentication

Set your API key via environment variable or flag:

# Organization key (for most operations)
export XBOW_ORG_KEY="your-org-key"

# Or pass directly
xbow --org-key "your-org-key" assessment list --asset-id abc123
Assets
# Create an asset
xbow asset create --org-id <org-id> --name "My App" --sku standard-sku

# Get an asset
xbow asset get <asset-id>

# List all assets for an organization
xbow asset list --org-id <org-id>

# Update simple fields (GET-then-PUT; unspecified fields are preserved)
xbow asset update <asset-id> --name "New Name" --start-url "https://example.com" --max-rps 10

# Update with repeatable structured flags
# NOTE: Repeatable flags (--header, --credential, --dns-rule, --http-rule)
# perform a full replacement of that field. If you specify any values for a
# flag, they replace ALL existing values — omitted entries are removed.
# To keep existing entries, re-specify them alongside any new ones.
xbow asset update <asset-id> \
  --header "X-Custom: value" \
  --credential "name=admin,type=basic,username=u,password=p" \
  --dns-rule "action=allow-attack,type=hostname,filter=example.com,include-subdomains=true" \
  --http-rule "action=deny,type=url,filter=https://evil.com"

# Full replacement from a JSON file (or - for stdin)
xbow asset update <asset-id> --from-file asset.json
Assessments
# Create an assessment
xbow assessment create --asset-id <asset-id> --attack-credits 100 --objective "Find vulnerabilities"

# Get an assessment
xbow assessment get <assessment-id>

# List all assessments for an asset
xbow assessment list --asset-id <asset-id>

# Control assessment execution
xbow assessment pause <assessment-id>
xbow assessment resume <assessment-id>
xbow assessment cancel <assessment-id>
Findings
# Get a finding
xbow finding get <finding-id>

# List all findings for an asset
xbow finding list --asset-id <asset-id>

# Verify that a finding has been fixed (triggers a targeted assessment)
xbow finding verify-fix <finding-id>
Reports
# Download a report as PDF
xbow report get <report-id> --output-file report.pdf

# Or pipe to stdout
xbow report get <report-id> > report.pdf

# Get the markdown summary
xbow report summary <report-id>

# Save the summary to a file
xbow report summary <report-id> --output-file summary.md

# List all reports for an asset
xbow report list --asset-id <asset-id>
Organizations

Organization management requires an integration key (--integration-key or XBOW_INTEGRATION_KEY). The get subcommand also accepts an organization key.

# Get an organization
xbow organization get <org-id>

# List organizations for an integration
xbow organization list --integration-id <integration-id>

# Create an organization with members
xbow organization create \
  --integration-id <integration-id> \
  --name "My Org" \
  --external-id "ext-123" \
  --member "[email protected],name=Alice" \
  --member "[email protected],name=Bob"

# Update an organization
xbow organization update <org-id> --name "New Name" --external-id "ext-456"

# Create an API key for an organization
xbow organization create-key <org-id> --name "CI Key" --expires-in-days 90

# Revoke an API key
xbow organization revoke-key <key-id>
Webhooks
# List webhooks for an organization
xbow webhook list --org-id <org-id>

# Get a webhook
xbow webhook get <webhook-id>

# Create a webhook
xbow webhook create --org-id <org-id> --target-url "https://example.com/hook" \
  --event "assessment.changed" --event "finding.changed"

# Update a webhook
xbow webhook update <webhook-id> --target-url "https://example.com/new-hook"

# Delete a webhook
xbow webhook delete <webhook-id>

# Ping a webhook (send a test event)
xbow webhook ping <webhook-id>

# List deliveries for a webhook (table shows summary; use --output json for full payloads)
xbow webhook deliveries <webhook-id>
Meta
# Get the OpenAPI specification
xbow meta openapi

# Save the OpenAPI specification to a file
xbow meta openapi --output-file openapi.json

# Get webhook signing keys
xbow meta signing-keys
Output Formats
# Table output (default)
xbow assessment get <id>

# JSON output
xbow assessment get <id> --output json
Global Flags
Flag Environment Variable Description
--org-key XBOW_ORG_KEY Organization API key
--integration-key XBOW_INTEGRATION_KEY Integration API key
--output, -o - Output format: table (default), json
--version - Print CLI and API version

Library Usage

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/rsclarke/xbow"
)

func main() {
    // Most endpoints use an organization key
    client, err := xbow.NewClient(xbow.WithOrganizationKey("your-org-key"))
    if err != nil {
        log.Fatal(err)
    }

    ctx := context.Background()

    // Get an assessment
    assessment, err := client.Assessments.Get(ctx, "assessment-id")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Assessment: %s (%s)\n", assessment.Name, assessment.State)

    // List all findings for the assessment's asset
    for finding, err := range client.Findings.AllByAsset(ctx, assessment.AssetID, nil) {
        if err != nil {
            log.Fatal(err)
        }
        fmt.Printf("- %s: %s (%s)\n", finding.Name, finding.Severity, finding.State)
    }
}
Webhook Verification

Verify incoming webhook requests using Ed25519 signatures. Fetch the signing keys from the API, then create a verifier:

keys, err := client.Meta.GetWebhookSigningKeys(ctx)
if err != nil {
    log.Fatal(err)
}

verifier, err := xbow.NewWebhookVerifier(keys)
if err != nil {
    log.Fatal(err)
}

Use it as HTTP middleware, which returns 401 Unauthorized for invalid signatures:

http.Handle("/webhook", verifier.Middleware(myHandler))

Or verify requests manually:

if err := verifier.Verify(r); err != nil {
    // handle invalid signature
}

Options can be passed to NewWebhookVerifier to adjust clock skew tolerance (default 5 minutes) and maximum body size (default 5 MB):

verifier, err := xbow.NewWebhookVerifier(keys,
    xbow.WithMaxClockSkew(10*time.Minute),
    xbow.WithMaxBodyBytes(10*1024*1024), // 10 MB
)

Authentication

The XBOW API uses two types of API keys:

  • Organization key - Used for most endpoints (assessments, assets, findings, etc.)
  • Integration key - Required for organization management endpoints
// Most users - organization key only
client, _ := xbow.NewClient(xbow.WithOrganizationKey("your-org-key"))

// Integration key only (for organization management)
client, _ := xbow.NewClient(xbow.WithIntegrationKey("your-integration-key"))

// Both keys for full access
client, _ := xbow.NewClient(
    xbow.WithOrganizationKey("your-org-key"),
    xbow.WithIntegrationKey("your-integration-key"),
)

Configuration

// Custom base URL
client, _ := xbow.NewClient(
    xbow.WithOrganizationKey("your-org-key"),
    xbow.WithBaseURL("https://custom.xbow.com"),
)

// Custom HTTP client
client, _ := xbow.NewClient(
    xbow.WithOrganizationKey("your-org-key"),
    xbow.WithHTTPClient(myHTTPClient),
)

Rate Limiting

The API may return 429 Too Many Requests responses. You can configure a rate limiter to automatically throttle requests:

import "golang.org/x/time/rate"

// 10 requests per second with burst of 10
limiter := rate.NewLimiter(rate.Every(time.Second), 10)

client, _ := xbow.NewClient(
    xbow.WithOrganizationKey("your-org-key"),
    xbow.WithRateLimiter(limiter),
)

The RateLimiter interface requires only a Wait(context.Context) error method, so you can provide any custom implementation.

Retry Policy

Enable automatic retries with exponential backoff for transient failures (429, 5xx):

client, _ := xbow.NewClient(
    xbow.WithOrganizationKey("your-org-key"),
    xbow.WithRetryPolicy(&xbow.RetryPolicy{
        MaxAttempts:    4,
        InitialBackoff: time.Second,
    }),
)

By default, only idempotent methods (GET, HEAD, PUT, DELETE) are retried. To also retry POST requests:

xbow.WithRetryPolicy(&xbow.RetryPolicy{
    RetryPOST: true,
})

The retry policy uses exponential backoff with jitter (enabled by default). All defaults:

Field Default
MaxAttempts 3
InitialBackoff 500ms
MaxBackoff 30s
Jitter true
RetryableStatusCodes 429, 500, 502, 503, 504
RetryPOST false

When combined with a rate limiter, the rate limiter runs once per user-initiated request while the retry transport handles individual attempts:

HTTP Client → RateLimiter → RetryTransport → Base Transport

Pagination

List methods return a single page. Use All* methods for automatic pagination:

// Single page
page, err := client.Assessments.ListByAsset(ctx, assetID, &xbow.ListOptions{Limit: 10})

// All pages (iterator)
for assessment, err := range client.Assessments.AllByAsset(ctx, assetID, nil) {
    // ...
}

Error Handling

Errors from the API are returned as *xbow.Error with structured error codes:

assessment, err := client.Assessments.Get(ctx, "invalid-id")
if err != nil {
    var apiErr *xbow.Error
    if errors.As(err, &apiErr) {
        fmt.Printf("API error: %s - %s\n", apiErr.Code, apiErr.Message)
    }
}

License

MIT

Documentation

Overview

Package xbow provides an idiomatic Go client for the XBOW API.

This package wraps the generated doordash oapi-codegen client with a more ergonomic, google/go-github-style API.

Example usage:

// Most endpoints use an organization key
client, err := xbow.NewClient(xbow.WithOrganizationKey("your-org-key"))

// Organization management endpoints require an integration key
client, err := xbow.NewClient(xbow.WithIntegrationKey("your-integration-key"))

// Use both keys for full access
client, err := xbow.NewClient(
    xbow.WithOrganizationKey("your-org-key"),
    xbow.WithIntegrationKey("your-integration-key"),
)

// Get an assessment
assessment, err := client.Assessments.Get(ctx, "assessment-id")

// List all assessments for an asset with automatic pagination
for assessment, err := range client.Assessments.AllByAsset(ctx, assetID, nil) {
    if err != nil {
        return err
    }
    fmt.Println(assessment.Name)
}

Index

Constants

View Source
const (
	DefaultBaseURL = "https://console.xbow.com"
	APIVersion     = "2026-02-01"
)

API configuration constants.

View Source
const (
	ErrCodeValidation     = "FST_ERR_VALIDATION"
	ErrCodeNotFound       = "ERR_NOT_FOUND"
	ErrCodeQuotaExhausted = "ERR_QUOTA_EXHAUSTED"
)

Error codes returned by the API.

View Source
const (
	// HeaderSignatureTimestamp is the header containing the Unix timestamp.
	HeaderSignatureTimestamp = "X-Signature-Timestamp"
	// HeaderSignatureEd25519 is the header containing the hex-encoded Ed25519 signature.
	HeaderSignatureEd25519 = "X-Signature-Ed25519"
)

Variables

View Source
var (
	ErrNotFound       = errors.New("resource not found")
	ErrBadRequest     = errors.New("bad request")
	ErrUnauthorized   = errors.New("unauthorized")
	ErrForbidden      = errors.New("forbidden")
	ErrRateLimited    = errors.New("rate limited")
	ErrInternalServer = errors.New("internal server error")

	// Client-side configuration errors.
	ErrMissingOrgKey         = errors.New("xbow: organization key is required")
	ErrMissingIntegrationKey = errors.New("xbow: integration key is required")
	ErrMissingAnyKey         = errors.New("xbow: organization key or integration key is required")
)

Sentinel errors for use with errors.Is.

Functions

func Collect

func Collect[T any](seq iter.Seq2[T, error]) ([]T, error)

Collect gathers all items from an iterator into a slice.

func IsNotFound

func IsNotFound(err error) bool

IsNotFound returns true if the error is a 404 Not Found error.

func IsRateLimited

func IsRateLimited(err error) bool

IsRateLimited returns true if the error is a 429 Rate Limited error.

Types

type ApprovedTimeWindows

type ApprovedTimeWindows struct {
	Tz      string            `json:"tz"`
	Entries []TimeWindowEntry `json:"entries"`
}

ApprovedTimeWindows represents time windows when assessments can run.

type Assessment

type Assessment struct {
	ID             string            `json:"id"`
	Name           string            `json:"name"`
	AssetID        string            `json:"assetId"`
	OrganizationID string            `json:"organizationId"`
	State          AssessmentState   `json:"state"`
	Progress       float64           `json:"progress"`
	AttackCredits  int64             `json:"attackCredits"`
	RecentEvents   []AssessmentEvent `json:"recentEvents"`
	CreatedAt      time.Time         `json:"createdAt"`
	UpdatedAt      time.Time         `json:"updatedAt"`
}

Assessment represents a security assessment.

type AssessmentEvent

type AssessmentEvent struct {
	Name      string    `json:"name"`
	Timestamp time.Time `json:"timestamp"`
	Reason    string    `json:"reason,omitempty"`
}

AssessmentEvent represents an event in an assessment's history.

type AssessmentListItem

type AssessmentListItem struct {
	ID        string          `json:"id"`
	Name      string          `json:"name"`
	State     AssessmentState `json:"state"`
	Progress  float64         `json:"progress"`
	CreatedAt time.Time       `json:"createdAt"`
	UpdatedAt time.Time       `json:"updatedAt"`
}

AssessmentListItem represents an assessment in list responses (fewer fields).

type AssessmentState

type AssessmentState string

AssessmentState represents the current state of an assessment.

const (
	AssessmentStateWaitingForCapacity   AssessmentState = "waiting-for-capacity"
	AssessmentStateRunning              AssessmentState = "running"
	AssessmentStateSucceeded            AssessmentState = "succeeded"
	AssessmentStateReportReady          AssessmentState = "report-ready"
	AssessmentStateFailed               AssessmentState = "failed"
	AssessmentStateCancelling           AssessmentState = "cancelling"
	AssessmentStateCancelled            AssessmentState = "cancelled"
	AssessmentStatePaused               AssessmentState = "paused"
	AssessmentStateWaitingForTimeWindow AssessmentState = "waiting-for-time-window"
)

Possible values for AssessmentState.

type AssessmentsService

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

AssessmentsService handles assessment-related API calls.

func (*AssessmentsService) AllByAsset

func (s *AssessmentsService) AllByAsset(ctx context.Context, assetID string, opts *ListOptions) iter.Seq2[AssessmentListItem, error]

AllByAsset returns an iterator over all assessments for an asset. Use this for automatic pagination:

for assessment, err := range client.Assessments.AllByAsset(ctx, assetID, nil) {
    if err != nil {
        return err
    }
    fmt.Println(assessment.Name)
}

func (*AssessmentsService) Cancel

func (s *AssessmentsService) Cancel(ctx context.Context, id string) (*Assessment, error)

Cancel cancels a running assessment.

func (*AssessmentsService) Create

Create requests a new assessment for an asset.

func (*AssessmentsService) Get

Get retrieves an assessment by ID.

func (*AssessmentsService) ListByAsset

func (s *AssessmentsService) ListByAsset(ctx context.Context, assetID string, opts *ListOptions) (*Page[AssessmentListItem], error)

ListByAsset returns a page of assessments for an asset.

func (*AssessmentsService) Pause

func (s *AssessmentsService) Pause(ctx context.Context, id string) (*Assessment, error)

Pause pauses a running assessment.

func (*AssessmentsService) Resume

func (s *AssessmentsService) Resume(ctx context.Context, id string) (*Assessment, error)

Resume resumes a paused assessment.

type Asset

type Asset struct {
	ID                   string               `json:"id"`
	Name                 string               `json:"name"`
	OrganizationID       string               `json:"organizationId"`
	Lifecycle            AssetLifecycle       `json:"lifecycle"`
	Sku                  string               `json:"sku"`
	StartURL             *string              `json:"startUrl"`
	MaxRequestsPerSecond *int                 `json:"maxRequestsPerSecond"`
	ApprovedTimeWindows  *ApprovedTimeWindows `json:"approvedTimeWindows"`
	Credentials          []Credential         `json:"credentials"`
	DNSBoundaryRules     []DNSBoundaryRule    `json:"dnsBoundaryRules"`
	Headers              map[string][]string  `json:"headers"`
	HTTPBoundaryRules    []HTTPBoundaryRule   `json:"httpBoundaryRules"`
	Checks               *AssetChecks         `json:"checks"`
	ArchiveAt            *time.Time           `json:"archiveAt"`
	CreatedAt            time.Time            `json:"createdAt"`
	UpdatedAt            time.Time            `json:"updatedAt"`
}

Asset represents a web application to be assessed.

type AssetCheck

type AssetCheck struct {
	State   AssetCheckState  `json:"state"`
	Message string           `json:"message"`
	Error   *AssetCheckError `json:"error,omitempty"`
}

AssetCheck represents a single validation check.

type AssetCheckError

type AssetCheckError struct {
	Type        string `json:"type"`
	Code        string `json:"code,omitempty"`
	Status      int    `json:"status,omitempty"`
	WafProvider string `json:"wafProvider,omitempty"`
}

AssetCheckError represents error details for a failed asset check.

type AssetCheckState

type AssetCheckState string

AssetCheckState represents the state of an asset check.

const (
	AssetCheckStateUnchecked AssetCheckState = "unchecked"
	AssetCheckStateChecking  AssetCheckState = "checking"
	AssetCheckStateValid     AssetCheckState = "valid"
	AssetCheckStateInvalid   AssetCheckState = "invalid"
)

Possible values for AssetCheckState.

type AssetChecks

type AssetChecks struct {
	AssetReachable   AssetCheck `json:"assetReachable"`
	Credentials      AssetCheck `json:"credentials"`
	DNSBoundaryRules AssetCheck `json:"dnsBoundaryRules"`
	UpdatedAt        *time.Time `json:"updatedAt"`
}

AssetChecks represents validation checks for an asset.

type AssetLifecycle

type AssetLifecycle string

AssetLifecycle represents the lifecycle state of an asset.

const (
	AssetLifecycleActive   AssetLifecycle = "active"
	AssetLifecycleArchived AssetLifecycle = "archived"
)

Possible values for AssetLifecycle.

type AssetListItem

type AssetListItem struct {
	ID        string         `json:"id"`
	Name      string         `json:"name"`
	Lifecycle AssetLifecycle `json:"lifecycle"`
	CreatedAt time.Time      `json:"createdAt"`
	UpdatedAt time.Time      `json:"updatedAt"`
}

AssetListItem represents an asset in list responses (fewer fields).

type AssetsService

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

AssetsService handles asset-related API calls.

func (*AssetsService) AllByOrganization

func (s *AssetsService) AllByOrganization(ctx context.Context, organizationID string, opts *ListOptions) iter.Seq2[AssetListItem, error]

AllByOrganization returns an iterator over all assets for an organization.

func (*AssetsService) Create

func (s *AssetsService) Create(ctx context.Context, organizationID string, req *CreateAssetRequest) (*Asset, error)

Create creates a new asset in an organization.

func (*AssetsService) Get

func (s *AssetsService) Get(ctx context.Context, id string) (*Asset, error)

Get retrieves an asset by ID.

func (*AssetsService) ListByOrganization

func (s *AssetsService) ListByOrganization(ctx context.Context, organizationID string, opts *ListOptions) (*Page[AssetListItem], error)

ListByOrganization returns a page of assets for an organization.

func (*AssetsService) Update

func (s *AssetsService) Update(ctx context.Context, id string, req *UpdateAssetRequest) (*Asset, error)

Update updates an asset.

type Client

type Client struct {

	// Services
	Assessments   *AssessmentsService
	Assets        *AssetsService
	Findings      *FindingsService
	Meta          *MetaService
	Organizations *OrganizationsService
	Reports       *ReportsService
	Webhooks      *WebhooksService
	// contains filtered or unexported fields
}

Client manages communication with the XBOW API.

func NewClient

func NewClient(opts ...ClientOption) (*Client, error)

NewClient creates a new XBOW API client.

func (*Client) Raw

func (c *Client) Raw() *api.Client

Raw returns the underlying generated client for advanced use cases.

type ClientOption

type ClientOption func(*clientConfig)

ClientOption is a functional option for configuring the Client.

func WithAPIClientOption

func WithAPIClientOption(opt runtime.APIClientOption) ClientOption

WithAPIClientOption adds a runtime.APIClientOption to the underlying client.

func WithBaseURL

func WithBaseURL(baseURL string) ClientOption

WithBaseURL sets a custom base URL.

func WithHTTPClient

func WithHTTPClient(httpClient *http.Client) ClientOption

WithHTTPClient sets a custom HTTP client.

func WithIntegrationKey

func WithIntegrationKey(key string) ClientOption

WithIntegrationKey sets the integration API key for authenticating with organization management endpoints.

func WithOrganizationKey

func WithOrganizationKey(key string) ClientOption

WithOrganizationKey sets the organization API key for authenticating with most endpoints.

func WithRateLimiter

func WithRateLimiter(limiter RateLimiter) ClientOption

WithRateLimiter sets a rate limiter that will be called before each API request. The limiter's Wait method is called before every HTTP request, allowing you to implement strategies like token bucket or leaky bucket rate limiting.

Compatible with golang.org/x/time/rate.Limiter:

limiter := rate.NewLimiter(rate.Every(time.Second), 10) // 10 req/sec with burst of 10
client, err := xbow.NewClient(
    xbow.WithOrganizationKey("key"),
    xbow.WithRateLimiter(limiter),
)

func WithRetryPolicy

func WithRetryPolicy(p *RetryPolicy) ClientOption

WithRetryPolicy enables automatic retries with exponential backoff for transient failures. By default, only idempotent HTTP methods (GET, HEAD, PUT, DELETE) are retried. Set RetryPOST to true to also retry POST requests.

Retries are performed with exponential backoff and optional jitter (enabled by default) to avoid thundering herd problems.

client, err := xbow.NewClient(
    xbow.WithOrganizationKey("key"),
    xbow.WithRetryPolicy(&xbow.RetryPolicy{
        MaxAttempts:    4,
        InitialBackoff: time.Second,
    }),
)

type CreateAssessmentRequest

type CreateAssessmentRequest struct {
	AttackCredits int64
	Objective     *string
}

CreateAssessmentRequest specifies the parameters for creating an assessment.

type CreateAssetRequest

type CreateAssetRequest struct {
	Name string
	Sku  string
}

CreateAssetRequest specifies the parameters for creating an asset.

type CreateKeyRequest

type CreateKeyRequest struct {
	Name          string
	ExpiresInDays *int
}

CreateKeyRequest specifies the parameters for creating an organization API key.

type CreateOrganizationRequest

type CreateOrganizationRequest struct {
	Name       string               // Required - name of the organization
	ExternalID *string              // Required (use nil to set null, or pointer to string for a value)
	Members    []OrganizationMember // Required - at least one member
}

CreateOrganizationRequest specifies the parameters for creating an organization. All fields are required per the API specification.

type CreateWebhookRequest

type CreateWebhookRequest struct {
	APIVersion WebhookAPIVersion  `json:"apiVersion"`
	TargetURL  string             `json:"targetUrl"`
	Events     []WebhookEventType `json:"events"`
}

CreateWebhookRequest contains the parameters for creating a webhook subscription.

type Credential

type Credential struct {
	ID               string  `json:"id"`
	Name             string  `json:"name"`
	Type             string  `json:"type"`
	Username         string  `json:"username"`
	Password         string  `json:"password"`
	EmailAddress     *string `json:"emailAddress,omitempty"`
	AuthenticatorURI *string `json:"authenticatorUri,omitempty"`
}

Credential represents authentication credentials for an asset.

type DNSBoundaryRule

type DNSBoundaryRule struct {
	ID                string                `json:"id"`
	Action            DNSBoundaryRuleAction `json:"action"`
	Type              string                `json:"type"`
	Filter            string                `json:"filter"`
	IncludeSubdomains *bool                 `json:"includeSubdomains,omitempty"`
}

DNSBoundaryRule represents a DNS boundary rule for an asset.

type DNSBoundaryRuleAction

type DNSBoundaryRuleAction string

DNSBoundaryRuleAction represents the action for a DNS boundary rule. DNS rules do not support allow-auth (only HTTP rules do).

const (
	DNSBoundaryRuleActionAllowAttack DNSBoundaryRuleAction = "allow-attack"
	DNSBoundaryRuleActionAllowVisit  DNSBoundaryRuleAction = "allow-visit"
	DNSBoundaryRuleActionDeny        DNSBoundaryRuleAction = "deny"
)

Possible values for DNSBoundaryRuleAction.

type Error

type Error struct {
	StatusCode int    `json:"-"`
	Code       string `json:"code"`
	ErrorType  string `json:"error"`
	Message    string `json:"message"`
	Wrapped    error  `json:"-"`
}

Error represents an API error response.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Is

func (e *Error) Is(target error) bool

Is implements errors.Is for API errors.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the wrapped error.

type Finding

type Finding struct {
	ID          string          `json:"id"`
	Name        string          `json:"name"`
	Severity    FindingSeverity `json:"severity"`
	State       FindingState    `json:"state"`
	Summary     string          `json:"summary"`
	Impact      string          `json:"impact"`
	Mitigations string          `json:"mitigations"`
	Recipe      string          `json:"recipe"`
	Evidence    string          `json:"evidence"`
	CreatedAt   time.Time       `json:"createdAt"`
	UpdatedAt   time.Time       `json:"updatedAt"`
}

Finding represents a security finding with full details.

type FindingListItem

type FindingListItem struct {
	ID        string          `json:"id"`
	Name      string          `json:"name"`
	Severity  FindingSeverity `json:"severity"`
	State     FindingState    `json:"state"`
	CreatedAt time.Time       `json:"createdAt"`
	UpdatedAt time.Time       `json:"updatedAt"`
}

FindingListItem represents a finding in list responses (fewer fields).

type FindingSeverity

type FindingSeverity string

FindingSeverity represents the severity level of a finding.

const (
	FindingSeverityCritical      FindingSeverity = "critical"
	FindingSeverityHigh          FindingSeverity = "high"
	FindingSeverityMedium        FindingSeverity = "medium"
	FindingSeverityLow           FindingSeverity = "low"
	FindingSeverityInformational FindingSeverity = "informational"
)

Possible values for FindingSeverity.

type FindingState

type FindingState string

FindingState represents the current state of a finding.

const (
	FindingStateOpen       FindingState = "open"
	FindingStateChallenged FindingState = "challenged"
	FindingStateConfirmed  FindingState = "confirmed"
	FindingStateInvalid    FindingState = "invalid"
	FindingStateFixed      FindingState = "fixed"
)

Possible values for FindingState.

type FindingsService

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

FindingsService handles finding-related API calls.

func (*FindingsService) AllByAsset

func (s *FindingsService) AllByAsset(ctx context.Context, assetID string, opts *ListOptions) iter.Seq2[FindingListItem, error]

AllByAsset returns an iterator over all findings for an asset. Use this for automatic pagination:

for finding, err := range client.Findings.AllByAsset(ctx, assetID, nil) {
    if err != nil {
        return err
    }
    fmt.Println(finding.Name)
}

func (*FindingsService) Get

func (s *FindingsService) Get(ctx context.Context, id string) (*Finding, error)

Get retrieves a finding by ID.

func (*FindingsService) ListByAsset

func (s *FindingsService) ListByAsset(ctx context.Context, assetID string, opts *ListOptions) (*Page[FindingListItem], error)

ListByAsset returns a page of findings for an asset.

func (*FindingsService) VerifyFix

func (s *FindingsService) VerifyFix(ctx context.Context, id string) (*Assessment, error)

VerifyFix requests verification that a finding has been fixed. This triggers a targeted assessment to verify the vulnerability has been mitigated. Returns the assessment created for the verification.

type HTTPBoundaryRule

type HTTPBoundaryRule struct {
	ID                string                 `json:"id"`
	Action            HTTPBoundaryRuleAction `json:"action"`
	Type              string                 `json:"type"`
	Filter            string                 `json:"filter"`
	IncludeSubdomains *bool                  `json:"includeSubdomains,omitempty"`
}

HTTPBoundaryRule represents an HTTP boundary rule for an asset.

type HTTPBoundaryRuleAction

type HTTPBoundaryRuleAction string

HTTPBoundaryRuleAction represents the action for an HTTP boundary rule.

const (
	HTTPBoundaryRuleActionAllowAttack HTTPBoundaryRuleAction = "allow-attack"
	HTTPBoundaryRuleActionAllowAuth   HTTPBoundaryRuleAction = "allow-auth"
	HTTPBoundaryRuleActionAllowVisit  HTTPBoundaryRuleAction = "allow-visit"
	HTTPBoundaryRuleActionDeny        HTTPBoundaryRuleAction = "deny"
)

Possible values for HTTPBoundaryRuleAction.

type ListOptions

type ListOptions struct {
	Limit int
	After string
}

ListOptions specifies pagination options for list operations.

type MetaService

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

MetaService handles meta-related API calls.

func (*MetaService) GetOpenAPISpec

func (s *MetaService) GetOpenAPISpec(ctx context.Context) ([]byte, error)

GetOpenAPISpec retrieves the OpenAPI specification for the current API version. The response is returned as raw JSON bytes since the schema is dynamic.

func (*MetaService) GetWebhookSigningKeys

func (s *MetaService) GetWebhookSigningKeys(ctx context.Context) ([]WebhookSigningKey, error)

GetWebhookSigningKeys retrieves the public keys used to sign webhook requests. Use these keys to verify webhook signatures. The array supports key rotation - during rotation, multiple keys may be active.

type Organization

type Organization struct {
	ID         string            `json:"id"`
	Name       string            `json:"name"`
	ExternalID *string           `json:"externalId"`
	State      OrganizationState `json:"state"`
	CreatedAt  time.Time         `json:"createdAt"`
	UpdatedAt  time.Time         `json:"updatedAt"`
}

Organization represents an organization in the XBOW platform.

type OrganizationAPIKey

type OrganizationAPIKey struct {
	ID        string     `json:"id"`
	Name      string     `json:"name"`
	Key       string     `json:"key"`
	ExpiresAt *time.Time `json:"expiresAt"`
	CreatedAt time.Time  `json:"createdAt"`
	UpdatedAt time.Time  `json:"updatedAt"`
}

OrganizationAPIKey represents an API key for an organization.

type OrganizationListItem

type OrganizationListItem struct {
	ID         string            `json:"id"`
	Name       string            `json:"name"`
	ExternalID *string           `json:"externalId"`
	State      OrganizationState `json:"state"`
	CreatedAt  time.Time         `json:"createdAt"`
	UpdatedAt  time.Time         `json:"updatedAt"`
}

OrganizationListItem represents an organization in list responses.

type OrganizationMember

type OrganizationMember struct {
	Email string `json:"email"`
	Name  string `json:"name"`
}

OrganizationMember represents a member of an organization.

type OrganizationState

type OrganizationState string

OrganizationState represents the state of an organization.

const (
	OrganizationStateActive   OrganizationState = "active"
	OrganizationStateDisabled OrganizationState = "disabled"
)

Possible values for OrganizationState.

type OrganizationsService

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

OrganizationsService handles organization-related API calls.

func (*OrganizationsService) AllByIntegration

func (s *OrganizationsService) AllByIntegration(ctx context.Context, integrationID string, opts *ListOptions) iter.Seq2[OrganizationListItem, error]

AllByIntegration returns an iterator over all organizations for an integration.

func (*OrganizationsService) Create

func (s *OrganizationsService) Create(ctx context.Context, integrationID string, req *CreateOrganizationRequest) (*Organization, error)

Create creates a new organization in an integration. This endpoint requires an integration key.

func (*OrganizationsService) CreateKey

func (s *OrganizationsService) CreateKey(ctx context.Context, organizationID string, req *CreateKeyRequest) (*OrganizationAPIKey, error)

CreateKey creates a new API key for an organization. This endpoint requires an integration key.

func (*OrganizationsService) Get

Get retrieves an organization by ID. This endpoint accepts either an organization key or an integration key.

func (*OrganizationsService) ListByIntegration

func (s *OrganizationsService) ListByIntegration(ctx context.Context, integrationID string, opts *ListOptions) (*Page[OrganizationListItem], error)

ListByIntegration returns a page of organizations for an integration. This endpoint requires an integration key.

func (*OrganizationsService) RevokeKey

func (s *OrganizationsService) RevokeKey(ctx context.Context, keyID string) error

RevokeKey revokes an organization API key. This endpoint requires an integration key.

func (*OrganizationsService) Update

Update updates an organization. This endpoint requires an integration key.

type Page

type Page[T any] struct {
	Items    []T
	PageInfo PageInfo
}

Page represents a paginated response.

type PageInfo

type PageInfo struct {
	NextCursor *string
	HasMore    bool
}

PageInfo contains pagination metadata.

type RateLimiter

type RateLimiter interface {
	// Wait blocks until the rate limiter allows a request to proceed.
	// Returns an error if the context is cancelled or the limiter fails.
	Wait(ctx context.Context) error
}

RateLimiter defines the interface for rate limiting API requests. Implementations should block until the request is allowed to proceed, or return an error (e.g., context cancellation).

type ReportListItem

type ReportListItem struct {
	ID        string    `json:"id"`
	Version   int64     `json:"version"`
	CreatedAt time.Time `json:"createdAt"`
}

ReportListItem represents a report in list responses.

type ReportSummary

type ReportSummary struct {
	Markdown string `json:"markdown"`
}

ReportSummary represents the summary of a report.

type ReportsService

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

ReportsService handles report-related API calls.

func (*ReportsService) AllByAsset

func (s *ReportsService) AllByAsset(ctx context.Context, assetID string, opts *ListOptions) iter.Seq2[ReportListItem, error]

AllByAsset returns an iterator over all reports for an asset. Use this for automatic pagination:

for report, err := range client.Reports.AllByAsset(ctx, assetID, nil) {
    if err != nil {
        return err
    }
    fmt.Println(report.ID)
}

func (*ReportsService) Get

func (s *ReportsService) Get(ctx context.Context, id string) (io.ReadCloser, error)

Get returns the report PDF as a streaming reader. The caller is responsible for closing the returned ReadCloser.

Example:

rc, err := client.Reports.Get(ctx, "report-id")
if err != nil {
    return err
}
defer rc.Close()

// Write to file
f, _ := os.Create("report.pdf")
defer f.Close()
io.Copy(f, rc)

func (*ReportsService) GetSummary

func (s *ReportsService) GetSummary(ctx context.Context, id string) (*ReportSummary, error)

GetSummary retrieves the markdown summary of a report by ID.

func (*ReportsService) ListByAsset

func (s *ReportsService) ListByAsset(ctx context.Context, assetID string, opts *ListOptions) (*Page[ReportListItem], error)

ListByAsset returns a page of reports for an asset.

type RetryPolicy

type RetryPolicy struct {
	MaxAttempts          int
	InitialBackoff       time.Duration
	MaxBackoff           time.Duration
	Jitter               bool
	RetryableStatusCodes []int
	RetryPOST            bool
}

RetryPolicy configures automatic retry behavior for transient failures.

type TimeWindowEntry

type TimeWindowEntry struct {
	StartWeekday int    `json:"startWeekday"`
	StartTime    string `json:"startTime"`
	EndWeekday   int    `json:"endWeekday"`
	EndTime      string `json:"endTime"`
}

TimeWindowEntry represents a single time window entry.

type UpdateAssetRequest

type UpdateAssetRequest struct {
	Name                 string               `json:"name"`
	StartURL             string               `json:"startUrl"`
	MaxRequestsPerSecond int                  `json:"maxRequestsPerSecond"`
	Sku                  *string              `json:"sku,omitempty"`
	ApprovedTimeWindows  *ApprovedTimeWindows `json:"approvedTimeWindows,omitempty"`
	Credentials          []Credential         `json:"credentials"`
	DNSBoundaryRules     []DNSBoundaryRule    `json:"dnsBoundaryRules"`
	Headers              map[string][]string  `json:"headers"`
	HTTPBoundaryRules    []HTTPBoundaryRule   `json:"httpBoundaryRules"`
}

UpdateAssetRequest specifies the parameters for updating an asset.

type UpdateOrganizationRequest

type UpdateOrganizationRequest struct {
	Name       string  // Required
	ExternalID *string // Required (use nil to set null, or pointer to string for a value)
}

UpdateOrganizationRequest specifies the parameters for updating an organization. Both Name and ExternalID are required. Set ExternalID to nil to clear it.

type UpdateWebhookRequest

type UpdateWebhookRequest struct {
	APIVersion *WebhookAPIVersion `json:"apiVersion,omitempty"`
	TargetURL  *string            `json:"targetUrl,omitempty"`
	Events     []WebhookEventType `json:"events,omitempty"`
}

UpdateWebhookRequest contains the parameters for updating a webhook subscription. All fields are optional; only provided fields will be updated.

type Webhook

type Webhook struct {
	ID         string             `json:"id"`
	APIVersion WebhookAPIVersion  `json:"apiVersion"`
	TargetURL  string             `json:"targetUrl"`
	Events     []WebhookEventType `json:"events"`
	CreatedAt  time.Time          `json:"createdAt"`
	UpdatedAt  time.Time          `json:"updatedAt"`
}

Webhook represents a webhook subscription.

type WebhookAPIVersion

type WebhookAPIVersion string

WebhookAPIVersion represents the API version for webhook payloads.

const (
	WebhookAPIVersionN20251101 WebhookAPIVersion = "2025-11-01"
	WebhookAPIVersionN20260201 WebhookAPIVersion = "2026-02-01"
	WebhookAPIVersionNext      WebhookAPIVersion = "next"
	WebhookAPIVersionUnstable  WebhookAPIVersion = "unstable"
)

Possible values for WebhookAPIVersion.

type WebhookDelivery

type WebhookDelivery struct {
	Payload  any                     `json:"payload"`
	Request  WebhookDeliveryRequest  `json:"request"`
	Response WebhookDeliveryResponse `json:"response"`
	SentAt   time.Time               `json:"sentAt"`
	Success  bool                    `json:"success"`
}

WebhookDelivery represents a webhook delivery attempt.

type WebhookDeliveryRequest

type WebhookDeliveryRequest struct {
	Body    string            `json:"body"`
	Headers map[string]string `json:"headers"`
}

WebhookDeliveryRequest represents the request made during a webhook delivery.

type WebhookDeliveryResponse

type WebhookDeliveryResponse struct {
	Body    string            `json:"body"`
	Headers map[string]string `json:"headers"`
	Status  int               `json:"status"`
}

WebhookDeliveryResponse represents the response received during a webhook delivery.

type WebhookEventType

type WebhookEventType string

WebhookEventType represents the type of webhook event.

const (
	WebhookEventTypePing              WebhookEventType = "ping"
	WebhookEventTypeTargetChanged     WebhookEventType = "target.changed"
	WebhookEventTypeAssetChanged      WebhookEventType = "asset.changed"
	WebhookEventTypeAssessmentChanged WebhookEventType = "assessment.changed"
	WebhookEventTypeFindingChanged    WebhookEventType = "finding.changed"
	WebhookEventTypeChallengeChanged  WebhookEventType = "challenge.changed"
	WebhookEventTypeAll               WebhookEventType = "*"
)

Possible values for WebhookEventType.

type WebhookListItem

type WebhookListItem struct {
	ID         string             `json:"id"`
	APIVersion WebhookAPIVersion  `json:"apiVersion"`
	TargetURL  string             `json:"targetUrl"`
	Events     []WebhookEventType `json:"events"`
	CreatedAt  time.Time          `json:"createdAt"`
	UpdatedAt  time.Time          `json:"updatedAt"`
}

WebhookListItem represents a webhook in list responses.

type WebhookSigningKey

type WebhookSigningKey struct {
	// PublicKey is a Base64-encoded Ed25519 public key in SPKI format.
	PublicKey string `json:"publicKey"`
}

WebhookSigningKey represents a public key used to verify webhook signatures.

type WebhookVerifier

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

WebhookVerifier verifies webhook signatures from XBOW.

func NewWebhookVerifier

func NewWebhookVerifier(keys []WebhookSigningKey, opts ...WebhookVerifierOption) (*WebhookVerifier, error)

NewWebhookVerifier creates a new WebhookVerifier from the signing keys returned by MetaService.GetWebhookSigningKeys.

Example:

keys, err := client.Meta.GetWebhookSigningKeys(ctx)
if err != nil {
    log.Fatal(err)
}
verifier, err := xbow.NewWebhookVerifier(keys)
if err != nil {
    log.Fatal(err)
}
http.Handle("/webhook", verifier.Middleware(myHandler))

func (*WebhookVerifier) Middleware

func (v *WebhookVerifier) Middleware(next http.Handler) http.Handler

Middleware returns an http.Handler that verifies webhook signatures. Requests with valid signatures are passed to the next handler. Invalid requests receive a 401 Unauthorized response.

func (*WebhookVerifier) Verify

func (v *WebhookVerifier) Verify(r *http.Request) error

Verify checks the signature and timestamp of a webhook request. Returns nil if valid, or an error describing the failure.

type WebhookVerifierOption

type WebhookVerifierOption func(*WebhookVerifier)

WebhookVerifierOption configures the WebhookVerifier.

func WithMaxBodyBytes

func WithMaxBodyBytes(n int64) WebhookVerifierOption

WithMaxBodyBytes sets the maximum allowed request body size in bytes. Default is 5 MB. Requests with bodies exceeding this limit will be rejected.

func WithMaxClockSkew

func WithMaxClockSkew(d time.Duration) WebhookVerifierOption

WithMaxClockSkew sets the maximum allowed clock skew for timestamp validation. Default is 5 minutes.

type WebhooksService

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

WebhooksService handles webhook-related API calls.

func (*WebhooksService) AllByOrganization

func (s *WebhooksService) AllByOrganization(ctx context.Context, organizationID string, opts *ListOptions) iter.Seq2[WebhookListItem, error]

AllByOrganization returns an iterator over all webhook subscriptions for an organization. Use this for automatic pagination:

for webhook, err := range client.Webhooks.AllByOrganization(ctx, orgID, nil) {
    if err != nil {
        return err
    }
    fmt.Println(webhook.TargetURL)
}

func (*WebhooksService) AllDeliveries

func (s *WebhooksService) AllDeliveries(ctx context.Context, webhookID string, opts *ListOptions) iter.Seq2[WebhookDelivery, error]

AllDeliveries returns an iterator over all deliveries for a webhook subscription. Use this for automatic pagination:

for delivery, err := range client.Webhooks.AllDeliveries(ctx, webhookID, nil) {
    if err != nil {
        return err
    }
    fmt.Printf("Delivery at %s: success=%v\n", delivery.SentAt, delivery.Success)
}

func (*WebhooksService) Create

func (s *WebhooksService) Create(ctx context.Context, organizationID string, req *CreateWebhookRequest) (*Webhook, error)

Create creates a new webhook subscription for an organization.

func (*WebhooksService) Delete

func (s *WebhooksService) Delete(ctx context.Context, id string) error

Delete deletes a webhook subscription.

func (*WebhooksService) Get

func (s *WebhooksService) Get(ctx context.Context, id string) (*Webhook, error)

Get retrieves a webhook subscription by ID.

func (*WebhooksService) ListByOrganization

func (s *WebhooksService) ListByOrganization(ctx context.Context, organizationID string, opts *ListOptions) (*Page[WebhookListItem], error)

ListByOrganization returns a page of webhook subscriptions for an organization.

func (*WebhooksService) ListDeliveries

func (s *WebhooksService) ListDeliveries(ctx context.Context, webhookID string, opts *ListOptions) (*Page[WebhookDelivery], error)

ListDeliveries returns a page of delivery history for a webhook subscription.

func (*WebhooksService) Ping

func (s *WebhooksService) Ping(ctx context.Context, id string) error

Ping sends a ping event to a webhook subscription to test connectivity.

func (*WebhooksService) Update

Update updates an existing webhook subscription.

Directories

Path Synopsis
cmd
xbow command
Package main is the entry point for the xbow CLI.
Package main is the entry point for the xbow CLI.
xbow/cmd
Package cmd implements the xbow CLI commands.
Package cmd implements the xbow CLI commands.
internal
api
Package api provides the generated low-level client for the XBOW API.
Package api provides the generated low-level client for the XBOW API.

Jump to

Keyboard shortcuts

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