server

package
v0.5.2 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2026 License: MIT Imports: 77 Imported by: 0

Documentation

Overview

Package server implements the REST API server (built on Fiber): traffic ingestion endpoints, scan and findings APIs, the agent run API, project scoping via the X-Project-UUID header, and the bundled Swagger UI. Handlers are composed from focused sub-structs and delegate scanning to pkg/core and agent runs to pkg/agent. See docs/server-mode/.

Index

Constants

View Source
const (
	ArtifactKindLog      = "log"
	ArtifactKindJSON     = "json"
	ArtifactKindJSONL    = "jsonl"
	ArtifactKindMarkdown = "markdown"
	ArtifactKindYAML     = "yaml"
	ArtifactKindText     = "text"
)

Artifact kind tags returned by artifactKind. Clients use these to pick a rendering mode (terminal log, JSON tree, markdown, etc.).

View Source
const (
	RoleAdmin    = "admin"
	RoleOperator = "operator"
	RoleViewer   = "viewer"
)

Role constants for user access control.

View Source
const DefaultIngestProxyCADir = "~/.vigolium/ca"

DefaultIngestProxyCADir is the default directory for the ingest-proxy MITM CA (used when ServerConfig.IngestProxyCADir is empty). It is the single source of truth shared with the CLI's --export-ca path so a CA exported out-of-band matches the one the running proxy uses.

View Source
const IngestSourceHeader = "X-Vigolium-Source"

IngestSourceHeader lets a client declare which tool the traffic it is pushing came from, so a record ingested by the Caido plugin is distinguishable from one pushed by curl. Mirrors the X-Project-UUID convention: a header rather than a body field, because the seven ingest modes share three save helpers but seven request shapes.

Variables

View Source
var (
	ErrMissingAuthHeader       = errors.New("missing Authorization header")
	ErrInvalidAuthToken        = errors.New("invalid Bearer token")
	ErrMissingMode             = errors.New("'input_mode' field is required")
	ErrInvalidMode             = errors.New("unsupported input mode")
	ErrMissingContent          = errors.New("'content', 'content_base64', or 'http_request_base64' is required")
	ErrQueueFull               = errors.New("queue is full, try again later")
	ErrServerClosed            = errors.New("server is shutting down")
	ErrDatabaseRequired        = errors.New("database is required for this endpoint")
	ErrScanAlreadyRunning      = errors.New("a scan is already running")
	ErrNoRecordsToScan         = errors.New("no records found after scan cursor")
	ErrAgentNotFound           = errors.New("agent run not found")
	ErrMissingPrompt           = errors.New("prompt_template, prompt_file, or prompt is required")
	ErrMissingTarget           = errors.New("'target' field is required")
	ErrRecordNotFound          = errors.New("HTTP record not found")
	ErrFindingNotFound         = errors.New("finding not found")
	ErrOASTInteractionNotFound = errors.New("OAST interaction not found")
	ErrMissingURL              = errors.New("'url' field is required")
	ErrMissingRawRequest       = errors.New("'raw_request' field is required")
	ErrInvalidRawRequest       = errors.New("failed to parse raw HTTP request")
	ErrScanNotFound            = errors.New("scan not found")
	ErrMissingRecordUUIDs      = errors.New("'record_uuids' field is required")
	ErrNoValidRecords          = errors.New("no valid records found for the provided UUIDs")
	ErrExtensionNotFound       = errors.New("extension not found")
	ErrForbidden               = errors.New("insufficient permissions")
	ErrInvalidCredentials      = errors.New("invalid username or access code")
)

Functions

func AuthorHeaderMiddleware

func AuthorHeaderMiddleware(author string) fiber.Handler

AuthorHeaderMiddleware stamps the `X-Author:` response header, the companion to the `Server:` banner. The value comes from ServerConfig.Author (wired from pkg/cli.Author) rather than a literal here — pkg/server cannot import pkg/cli without an import cycle, and a second copy of the name would drift. registerRoutes skips this middleware entirely when the author is unset, so an empty header is never written.

func BearerAuth

func BearerAuth(validKeys []string, store *UserStore) fiber.Handler

BearerAuth returns fiber middleware that validates Bearer tokens and resolves user identity. Checks the UserStore first (file-based users), then falls back to legacy API keys (admin role). Skips authentication for public endpoints: /, /health, /ready, /swagger/*, /metrics.

func BootstrapUsersFile

func BootstrapUsersFile(path string, defaultJSON []byte) (bool, error)

BootstrapUsersFile creates the users file from the embedded default template if it does not already exist. Each user with an empty access_code gets a freshly generated one. Returns true if a new file was created.

func DebugRequestMiddleware

func DebugRequestMiddleware() fiber.Handler

DebugRequestMiddleware logs the raw request body, URL/query parameters, and headers for every incoming request when --debug is enabled.

Sensitive headers and BYOK body fields are scrubbed before the line is emitted — see redact.go for the precise lists. JSON-shaped bodies are parsed and re-serialized; non-JSON or malformed bodies are summarized rather than logged verbatim so a binary upload doesn't tank the log.

func DefaultBodyLimitMiddleware

func DefaultBodyLimitMiddleware() fiber.Handler

DefaultBodyLimitMiddleware rejects request bodies larger than defaultBodyLimit for routes that aren't in bodyLimitExemptPaths.

With StreamRequestBody enabled (see fiber.Config) the declared-Content-Length check rejects an oversized body before it is read into memory, so a normal JSON route no longer buffers up to the framework's 512 MB ceiling just to bounce it. A chunked or otherwise undeclared body has no length to check, and there the naive `len(c.Body()) > limit` is the problem rather than the fix: c.Body() drains the stream first and asks afterwards, and the only ceiling on that drain is the framework BodyLimit — so a sender who omits Content-Length gets to grow the server's heap by 512 MB per request on a route whose limit is 4 MB, and a handful of concurrent senders can exhaust memory on requests that were always going to be rejected.

So the undeclared case is read explicitly, through a reader capped one byte past the limit: at most limit+1 bytes are ever allocated, and crossing the threshold is detectable without having consumed what follows.

func ProjectUUIDMiddleware

func ProjectUUIDMiddleware(repo *database.Repository) fiber.Handler

ProjectUUIDMiddleware extracts the project UUID from the X-Project-UUID request header and stores it in Fiber locals. Falls back to DefaultProjectUUID when the header is empty.

When repo is non-nil and the supplied UUID does not exist in the database, the middleware lazily creates a stub project row so callers (including UIs after a scanner DB reset) can keep working with the UUID stored client-side. Auto-creation is skipped for public/utility endpoints and for the default project UUID, which is seeded separately.

func RoleGuard

func RoleGuard(allowed ...string) fiber.Handler

RoleGuard returns middleware that rejects requests from users whose role is not in the allowed set. Must be applied after BearerAuth. When no auth user is present (--no-auth mode), requests are allowed through.

func SecurityHeadersMiddleware

func SecurityHeadersMiddleware() fiber.Handler

SecurityHeadersMiddleware adds security headers to all responses.

Types

type AgentArtifact

type AgentArtifact struct {
	Name       string    `json:"name"`        // path relative to session_dir
	Size       int64     `json:"size"`        // bytes
	ModifiedAt time.Time `json:"modified_at"` // mtime
	Kind       string    `json:"kind"`        // "log", "json", "markdown", "yaml", "jsonl", "text", "binary"
}

AgentArtifact is one file under an agent session directory.

type AgentArtifactListResponse

type AgentArtifactListResponse struct {
	AgenticScanUUID string          `json:"agentic_scan_uuid"`
	SessionDir      string          `json:"session_dir"`
	Artifacts       []AgentArtifact `json:"artifacts"`
	Truncated       bool            `json:"truncated,omitempty"` // true when the walk hit the file cap
}

AgentArtifactListResponse lists files under an agent session directory.

type AgentAuditDriverRequest

type AgentAuditDriverRequest struct {
	Source        string   `json:"source,omitempty"`         // local path, git URL, gs:// archive, or local archive (required)
	Target        string   `json:"target,omitempty"`         // optional target URL — stored on the run row for cross-referencing scans
	Intensity     string   `json:"intensity,omitempty"`      // quick | balanced (default) | deep — bundles mode + timeout + commit_depth
	Mode          string   `json:"mode,omitempty"`           // explicit audit mode: lite, balanced, scan, deep, mock, revisit, reinvest, confirm, merge, diff, status (overrides intensity)
	Modes         []string `json:"modes,omitempty"`          // mode chain run back-to-back via audit's native --modes (e.g. ["deep","refresh","confirm"]); overrides mode/intensity, stops on first non-complete
	Platform      string   `json:"platform,omitempty"`       // claude | codex (default: from settings, then claude)
	Agent         string   `json:"agent,omitempty"`          // alias for platform — accepted for parity with the CLI flag
	Timeout       string   `json:"timeout,omitempty"`        // Go duration string; overrides intensity preset (quick=1h, balanced=6h, deep=12h)
	Diff          string   `json:"diff,omitempty"`           // focus on changed code: PR URL, git ref range, or HEAD~N
	LastCommits   int      `json:"last_commits,omitempty"`   // focus on last N commits (shorthand for diff HEAD~N)
	CommitDepth   int      `json:"commit_depth,omitempty"`   // git clone --depth when source is a git URL; overrides intensity preset (quick/balanced=1, deep=0)
	Files         []string `json:"files,omitempty"`          // specific files to focus on
	Stream        bool     `json:"stream,omitempty"`         // enable SSE streaming of agent output
	UploadResults bool     `json:"upload_results,omitempty"` // upload session bundle to cloud storage on completion
	ProjectUUID   string   `json:"project_uuid,omitempty"`   // project UUID for data scoping
	ScanUUID      string   `json:"scan_uuid,omitempty"`      // optional scan UUID

	// AgentBYOK fields (api_key, oauth_token, oauth_cred_file, oauth_cred_json)
	// are accepted at the top level of the request body via JSON field
	// promotion. See AgentBYOK doc for resolution semantics.
	AgentBYOK
}

AgentAuditDriverRequest is the request body for POST /api/agent/run/audit. Mirrors the autopilot request shape for the fields audit actually consumes (source, intensity/mode, platform, timeout, diff context, scoping, streaming).

func (AgentAuditDriverRequest) EffectivePlatform

func (r AgentAuditDriverRequest) EffectivePlatform() string

EffectivePlatform resolves the platform field, accepting the legacy `agent` alias used by the CLI flag (`--agent claude|codex`).

type AgentAuditRequest

type AgentAuditRequest struct {
	Source        string   `json:"source,omitempty"`         // local path, git URL, gs:// archive, or local archive (required)
	Target        string   `json:"target,omitempty"`         // optional target URL — stored on the run row for cross-referencing scans
	Intensity     string   `json:"intensity,omitempty"`      // quick | balanced (default) | deep — bundles mode + timeout + commit_depth
	Mode          string   `json:"mode,omitempty"`           // explicit audit mode (overrides intensity). With driver=auto or driver=both, restricted to: lite, balanced, deep, revisit, confirm, merge. With driver=piolium adds: diff, longshot, status, smoke. With driver=audit adds: reinvest, diff, status, mock.
	Modes         []string `json:"modes,omitempty"`          // mode chain run back-to-back (e.g. ["deep","refresh","confirm"]); overrides mode/intensity. audit runs it natively; piolium chains via sequential runs collapsed into one row; with driver=auto/both, modes a driver can't run are skipped on that driver's leg.
	Timeout       string   `json:"timeout,omitempty"`        // Go duration string; overrides intensity preset (quick=1h, balanced=6h, deep=12h)
	Diff          string   `json:"diff,omitempty"`           // focus on changed code: PR URL, git ref range, or HEAD~N
	LastCommits   int      `json:"last_commits,omitempty"`   // focus on last N commits (shorthand for diff HEAD~N)
	CommitDepth   int      `json:"commit_depth,omitempty"`   // git clone --depth when source is a git URL; overrides intensity preset (quick/balanced=1, deep=0)
	Files         []string `json:"files,omitempty"`          // specific files to focus on
	Stream        bool     `json:"stream,omitempty"`         // enable SSE streaming of agent output. With driver=auto/both, events are tagged with a "driver" field
	UploadResults bool     `json:"upload_results,omitempty"` // upload session bundle to cloud storage on completion
	ProjectUUID   string   `json:"project_uuid,omitempty"`   // project UUID for data scoping
	ScanUUID      string   `json:"scan_uuid,omitempty"`      // optional scan UUID

	// Driver picks which audit harnesses participate. One of:
	//   "auto"    — audit first; piolium runs only as a fallback if
	//               audit fails (a clean audit run finishes the audit
	//               and piolium is never started). Default when empty.
	//   "both"    — sequential audit-then-piolium under one parent
	//               AgenticScan, run unconditionally
	//   "audit"  — audit only (equivalent to /api/agent/run/audit)
	//   "piolium" — piolium only
	// "auto" and "both" run under one parent AgenticScan with per-driver
	// child rows, post-pass findings dedup, and multiplexed SSE.
	// Defaults to "auto" when empty.
	Driver string `json:"driver,omitempty"`

	// NoDedup skips the post-pass project-wide findings dedup that runs
	// after the audit completes. Only meaningful for driver=auto/both,
	// since single-driver runs already INSERT-time-dedup by finding_hash.
	NoDedup bool `json:"no_dedup,omitempty"`

	// KeepRaw maps to vigolium-audit's `--keep-raw`: opt out of the
	// deep/confirm auto-prune so raw scanner output, draft findings, and
	// intermediate workspaces stay under <source>/vigolium-results/ (and
	// the synced session copy) for manual review. Audit-only — ignored on
	// the piolium leg of driver=auto/both/piolium runs.
	KeepRaw bool `json:"keep_raw,omitempty"`

	// Agent picks the audit platform when audit participates. Accepts
	// claude (default) or codex. Ignored when driver=piolium.
	Agent string `json:"agent,omitempty"`

	// Pi provider/model overrides, forwarded as `pi --provider X --model Y`.
	// Empty values fall back to whatever the user has configured in
	// ~/.pi/agent/settings.json. Ignored when driver=audit.
	PiProvider string `json:"pi_provider,omitempty"`
	PiModel    string `json:"pi_model,omitempty"`

	// Piolium passthrough flags (`--plm-*`). Empty/zero values are dropped
	// so piolium's own defaults still apply. Ignored when driver=audit.
	PlmScanLimit       int    `json:"plm_scan_limit,omitempty"`       // cap commit-history scan to N commits
	PlmScanSince       string `json:"plm_scan_since,omitempty"`       // git --since window (e.g. "60 days ago")
	PlmPhaseRetries    int    `json:"plm_phase_retries,omitempty"`    // per-phase retry count
	PlmCommandRetries  int    `json:"plm_command_retries,omitempty"`  // per-command retry count
	PlmLongshotLimit   int    `json:"plm_longshot_limit,omitempty"`   // max files in longshot mode
	PlmLongshotTimeout int    `json:"plm_longshot_timeout,omitempty"` // per-file kill timer in ms (longshot)
	PlmLongshotLangs   string `json:"plm_longshot_langs,omitempty"`   // comma-separated language allowlist

	// AgentBYOK fields (api_key, oauth_token, oauth_cred_file, oauth_cred_json)
	// are accepted at the top level of the request body via JSON field
	// promotion. The audit dispatcher applies these to whichever driver(s)
	// actually run: audit receives them as --api-key / --oauth-token /
	// --oauth-cred-file flags; piolium receives them as env vars on the pi
	// subprocess (and, for codex cred files, a temporarily-staged auth.json
	// under the configured pi-agent-dir, restored on completion). See
	// AgentBYOK doc for full semantics.
	AgentBYOK

	// AuditDriverAuth, when set, OVERRIDES the top-level AgentBYOK for the
	// audit driver only. Used with driver=auto/both to give each driver
	// its own identity (e.g. one tenant's claude OAuth for the audit side,
	// another tenant's codex cred file for piolium). When unset, audit
	// inherits the top-level AgentBYOK. Ignored when driver=piolium.
	AuditDriverAuth *AgentBYOK `json:"audit_auth,omitempty"`

	// PioliumAuth, when set, OVERRIDES the top-level AgentBYOK for the
	// piolium driver only. Symmetric to AuditDriverAuth. Ignored when
	// driver=audit.
	PioliumAuth *AgentBYOK `json:"piolium_auth,omitempty"`
}

AgentAuditRequest is the request body for POST /api/agent/run/audit.

Mirrors the `vigolium agent audit` CLI: dispatches audit and/or piolium against a source tree (local path, git URL, gs:// archive, or local archive) under one AgenticScan. When driver=auto (default), audit runs first and piolium only runs as a fallback if audit fails — a clean audit run finishes the audit and piolium is never started. When driver=both, both drivers run sequentially (audit first, then piolium) unconditionally. Multi-driver runs use per-driver child AgenticScan rows. Same /agent/status, /agent/sessions/:id/logs, and /agent/sessions/:id/artifacts shape as the single-driver endpoints.

Optional fields default to the same values as their CLI counterparts; in particular, the `pi_*` and `plm_*` knobs only fire when explicitly set.

type AgentAutopilotRequest

type AgentAutopilotRequest struct {
	Prompt      string   `json:"prompt,omitempty"`       // natural language scan prompt (parsed into target/source/focus when explicit fields are empty)
	Intensity   string   `json:"intensity,omitempty"`    // scan intensity preset: quick, balanced (default), deep
	Target      string   `json:"target,omitempty"`       // target URL (derived from input if not set)
	Input       string   `json:"input,omitempty"`        // raw input (curl, raw HTTP, Burp XML, URL) — target extracted automatically
	Agent       string   `json:"agent,omitempty"`        // agent backend name
	SourcePath  string   `json:"source,omitempty"`       // path to application source code
	Files       []string `json:"files,omitempty"`        // specific files to include
	Focus       string   `json:"focus,omitempty"`        // focus area hint
	Instruction string   `json:"instruction,omitempty"`  // custom instruction appended to the prompt
	Timeout     string   `json:"timeout,omitempty"`      // Go duration string, default "6h"
	MaxCommands int      `json:"max_commands,omitempty"` // max CLI commands, default 100
	DryRun      bool     `json:"dry_run,omitempty"`      // render prompt without executing
	Stream      bool     `json:"stream,omitempty"`       // enable SSE streaming
	ScanUUID    string   `json:"scan_uuid,omitempty"`    // optional scan UUID
	ProjectUUID string   `json:"project_uuid,omitempty"` // project UUID for data scoping
	// Deprecated: use NoAudit + AuditDriverMode instead. Kept for backward
	// compatibility with older API clients; "off" maps to NoAudit=true and
	// any other value (e.g. "deep") maps to AuditDriverMode. Slated for removal.
	Audit           string                      `json:"audit,omitempty"`             // legacy values: "lite", "balanced", "deep", "off"
	NoAudit         bool                        `json:"no_audit,omitempty"`          // disable automatic vigolium-audit (enabled by default when source is set)
	AuditDriverMode string                      `json:"audit_mode,omitempty"`        // audit mode: "lite" (default), "balanced", "deep"
	Diff            string                      `json:"diff,omitempty"`              // focus on changed code: PR URL, git ref range, or HEAD~N
	LastCommits     int                         `json:"last_commits,omitempty"`      // focus on last N commits (shorthand for diff HEAD~N)
	Browser         bool                        `json:"browser,omitempty"`           // explicitly enable browser tooling
	Credentials     string                      `json:"credentials,omitempty"`       // compact credential hint for preflight auth setup
	CredentialSets  []agent.IntentCredentialSet `json:"credential_sets,omitempty"`   // structured roles/accounts for preflight auth setup
	AuthRequired    bool                        `json:"auth_required,omitempty"`     // authenticate before scan
	RequiresBrowser bool                        `json:"requires_browser,omitempty"`  // browser is required for login/auth setup
	BrowserStartURL string                      `json:"browser_start_url,omitempty"` // explicit login/start URL for browser-based flows
	FocusRoutes     []string                    `json:"focus_routes,omitempty"`      // protected/browser focus routes

	// Piolium audit mode (Pi runtime). Empty triggers server-side auto-pick:
	// when pi+piolium are installed, the server runs piolium instead of
	// audit. Set explicitly to force piolium; pair with audit:"off" to
	// keep both off, or with an audit mode to keep audit (auto-pick is
	// suppressed once either flag is set).
	Piolium string `json:"piolium,omitempty"`

	// Triage, when true, runs an AI triage pass over the findings after the
	// scan completes — classifying each as confirmed or false positive and
	// writing the verdict back to finding status. Pure classification (no
	// native rescan).
	Triage bool `json:"triage,omitempty"`

	// NoPreflightDiscovery disables the pre-flight discovery + OpenAPI/Swagger
	// ingestion pass that seeds http_records before the operator agent
	// starts. Default false (pre-flight on). Set true to skip — useful when
	// the caller has already seeded the project via --input or a prior scan.
	NoPreflightDiscovery bool `json:"no_preflight_discovery,omitempty"`

	// NoPostHaltVerify disables the post-halt coverage verification loop —
	// the agent's halt_scan is accepted as final regardless of whether a
	// follow-up discovery probe would surface new routes. Default false
	// (verification on). Cap the cost via PostHaltGapThreshold rather than
	// disabling entirely when possible.
	NoPostHaltVerify bool `json:"no_post_halt_verify,omitempty"`

	// PostHaltGapThreshold sets the minimum number of new routes the
	// post-halt probe must turn up before the agent is re-entered. 0 falls
	// back to the autopilot's built-in default (5).
	PostHaltGapThreshold int `json:"post_halt_gap_threshold,omitempty"`

	// Upload results to cloud storage after scan completion
	UploadResults bool `json:"upload_results,omitempty"`

	// AgentBYOK fields (api_key, oauth_token, oauth_cred_file, oauth_cred_json)
	// are accepted at the top level of the request body. The in-process
	// olium engine for this run is built with these overlaid onto the
	// server-wide agent.olium.* defaults; the background audit (when
	// enabled via AuditDriverMode/Piolium) inherits the same overrides.
	AgentBYOK
}

AgentAutopilotRequest is the request body for POST /api/agent/run/autopilot.

func (AgentAutopilotRequest) ResolvedAuditDriverMode

func (r AgentAutopilotRequest) ResolvedAuditDriverMode() string

ResolvedAuditDriverMode returns the effective audit mode, handling backward compatibility with the legacy Audit field.

func (AgentAutopilotRequest) ResolvedNoAudit

func (r AgentAutopilotRequest) ResolvedNoAudit() bool

ResolvedNoAudit returns true when audit should be disabled, handling backward compatibility with the legacy Audit field.

type AgentBYOK

type AgentBYOK struct {
	APIKey        string `json:"api_key,omitempty"`
	OAuthToken    string `json:"oauth_token,omitempty"`
	OAuthCredFile string `json:"oauth_cred_file,omitempty"`
	OAuthCredJSON string `json:"oauth_cred_json,omitempty"`
}

AgentBYOK is the shared shape of "bring your own key" credentials sent on agent endpoints. Embedded in every request type that runs an agent (audit/audit subprocess drivers, autopilot/swarm/query in-process olium) so callers get a uniform field surface regardless of which endpoint they target.

Field semantics (mutually exclusive — at most one of APIKey / OAuthToken / OAuthCredFile / OAuthCredJSON may be non-empty):

  • APIKey — Anthropic or OpenAI API key. Routed to the right env / x-api-key header by the receiving driver.
  • OAuthToken — Claude Code OAuth token (`sk-ant-oat01-…` from `claude setup-token`). Claude-only.
  • OAuthCredFile — server-side path to a Codex auth.json. DEPRECATED: server-supplied paths let any operator point the audit at any readable file. New integrations should send the contents inline via OAuthCredJSON.
  • OAuthCredJSON — raw contents of a Codex auth.json. Staged by the server to a per-request 0600 temp file, used for one run, then deleted.

Values are treated as literals — unlike the CLI flags, REST does NOT honor $ENV / @path indirection. Doing so would let a network caller probe the server's environment or filesystem.

func (AgentBYOK) IsZero

func (b AgentBYOK) IsZero() bool

IsZero reports whether no BYOK fields are set. Used to short-circuit the resolver / staging path when the request doesn't carry any creds.

type AgentSessionDetail

type AgentSessionDetail struct {
	AgentSessionSummary
	InputRaw       string                `json:"input_raw,omitempty"`
	ModuleNames    []string              `json:"module_names,omitempty"`
	SessionID      string                `json:"session_id,omitempty"`
	PromptSent     string                `json:"prompt_sent,omitempty"`
	AgentRawOutput string                `json:"agent_raw_output,omitempty"`
	AttackPlan     string                `json:"attack_plan,omitempty"`
	TriageResult   string                `json:"triage_result,omitempty"`
	ResultJSON     string                `json:"result_json,omitempty"`
	ChildRuns      []*AgentSessionDetail `json:"child_runs,omitempty"`
}

AgentSessionDetail is the full representation of an agent run including debug fields.

type AgentSessionSummary

type AgentSessionSummary struct {
	UUID                  string     `json:"uuid"`
	Mode                  string     `json:"mode"`
	Status                string     `json:"status"`
	AgentName             string     `json:"agent_name,omitempty"`
	TemplateID            string     `json:"template_id,omitempty"`
	TargetURL             string     `json:"target_url,omitempty"`
	SourcePath            string     `json:"source_path,omitempty"`
	SessionDir            string     `json:"session_dir,omitempty"`
	VulnType              string     `json:"vuln_type,omitempty"`
	InputType             string     `json:"input_type,omitempty"`
	ParentAgenticScanUUID string     `json:"parent_agentic_scan_uuid,omitempty"`
	CurrentPhase          string     `json:"current_phase,omitempty"`
	PhasesRun             []string   `json:"phases_run,omitempty"`
	FindingCount          int        `json:"finding_count,omitempty"`
	RecordCount           int        `json:"record_count,omitempty"`
	SavedCount            int        `json:"saved_count,omitempty"`
	ErrorMessage          string     `json:"error_message,omitempty"`
	DurationMs            int64      `json:"duration_ms,omitempty"`
	StartedAt             *time.Time `json:"started_at,omitempty"`
	CompletedAt           *time.Time `json:"completed_at,omitempty"`
	CreatedAt             time.Time  `json:"created_at"`
	StorageURL            string     `json:"storage_url,omitempty"`
}

AgentSessionSummary is a lightweight representation of an agent run for list responses.

type AgentSwarmRequest

type AgentSwarmRequest struct {
	// Natural language prompt (parsed into structured fields when explicit fields are empty)
	Prompt string `json:"prompt,omitempty"`

	// Scan intensity preset: quick, balanced (default), deep
	Intensity string `json:"intensity,omitempty"`

	// Inputs
	Input              string   `json:"input,omitempty"`                // single input (URL, curl, raw HTTP, Burp XML, record UUID)
	Inputs             []string `json:"inputs,omitempty"`               // multiple inputs (for auth flows)
	HTTPRequestBase64  string   `json:"http_request_base64,omitempty"`  // base64-encoded raw HTTP request (ingested into DB, UUID used as input)
	HTTPResponseBase64 string   `json:"http_response_base64,omitempty"` // base64-encoded raw HTTP response (attached to the request above)
	URL                string   `json:"url,omitempty"`                  // optional URL hint for parsing the base64 request

	// Source analysis
	SourcePath         string   `json:"source,omitempty"`               // path to source code for route discovery (triggers source analysis phase)
	Files              []string `json:"files,omitempty"`                // specific source files to include (relative to source)
	SourceAnalysisOnly bool     `json:"source_analysis_only,omitempty"` // run only source analysis phase and exit

	// Scanning parameters
	VulnType      string   `json:"vuln_type,omitempty"`      // vulnerability type focus
	Focus         string   `json:"focus,omitempty"`          // broad focus area hint (e.g. "API injection", "auth bypass")
	Instruction   string   `json:"instruction,omitempty"`    // custom instruction appended to agent prompts
	ModuleNames   []string `json:"module_names,omitempty"`   // explicit module IDs
	OnlyPhase     string   `json:"only_phase,omitempty"`     // isolate a single phase
	SkipPhases    []string `json:"skip_phases,omitempty"`    // skip specific phases
	StartFrom     string   `json:"start_from,omitempty"`     // resume from a specific phase
	MaxIterations int      `json:"max_iterations,omitempty"` // max triage-rescan rounds (default 3)
	Discover      bool     `json:"discover,omitempty"`       // run discovery+spidering before master agent planning
	CodeAudit     bool     `json:"code_audit,omitempty"`     // enable AI security code audit phase
	Triage        bool     `json:"triage,omitempty"`         // enable AI triage and rescan phases (disabled by default)
	Profile       string   `json:"profile,omitempty"`        // scanning profile name (e.g. "light", "thorough")

	// Agent selection
	Agent string `json:"agent,omitempty"` // agent backend name

	// Auth/browser intent
	Browser         bool                        `json:"browser,omitempty"`           // explicitly enable browser tooling
	Auth            bool                        `json:"auth,omitempty"`              // explicitly run browser auth phase
	Credentials     string                      `json:"credentials,omitempty"`       // compact credential hint
	CredentialSets  []agent.IntentCredentialSet `json:"credential_sets,omitempty"`   // structured roles/accounts
	AuthRequired    bool                        `json:"auth_required,omitempty"`     // authenticate before scan
	RequiresBrowser bool                        `json:"requires_browser,omitempty"`  // browser is required for login/auth setup
	BrowserStartURL string                      `json:"browser_start_url,omitempty"` // explicit login/start URL
	FocusRoutes     []string                    `json:"focus_routes,omitempty"`      // protected/browser focus routes

	// Concurrency tuning
	BatchConcurrency int    `json:"batch_concurrency,omitempty"`  // max parallel master agent batches (0 = auto)
	MaxMasterRetries int    `json:"max_master_retries,omitempty"` // max master agent retries on parse failure (0 = default 3)
	SAMaxConcurrency int    `json:"sa_max_concurrency,omitempty"` // max parallel source analysis sub-agents (0 = default 3)
	MaxPlanRecords   int    `json:"max_plan_records,omitempty"`   // max records sent to plan agent (0 = use intensity preset, which picks 10/25/50 for quick/balanced/deep)
	MasterBatchSize  int    `json:"master_batch_size,omitempty"`  // max records per master agent batch (0 = default 5)
	ProbeConcurrency int    `json:"probe_concurrency,omitempty"`  // max parallel probe requests (0 = default 10)
	ProbeTimeout     string `json:"probe_timeout,omitempty"`      // per-request probe timeout as Go duration e.g. "10s" (0 = default 10s)
	MaxProbeBodySize int    `json:"max_probe_body,omitempty"`     // max response body size in bytes during probing (0 = default 2MB)

	// Output control
	DryRun     bool   `json:"dry_run,omitempty"`     // render prompts without executing
	ShowPrompt bool   `json:"show_prompt,omitempty"` // include rendered prompts in output
	Stream     bool   `json:"stream,omitempty"`      // enable SSE streaming
	Timeout    string `json:"timeout,omitempty"`     // Go duration string

	// Project/scan scoping
	ProjectUUID string `json:"project_uuid,omitempty"` // optional project UUID
	ScanUUID    string `json:"scan_uuid,omitempty"`    // optional scan UUID

	// Background vigolium-audit
	Audit string `json:"audit,omitempty"` // run background vigolium-audit: "lite" (3-phase), "balanced" (6-phase), "deep" (10-phase), "off" to disable

	// Background piolium audit (Pi runtime). Empty triggers server-side
	// auto-pick when audit is also empty: piolium runs when pi+piolium
	// are installed, otherwise nothing. Set explicitly to force piolium.
	Piolium string `json:"piolium,omitempty"`

	// Diff context
	Diff        string `json:"diff,omitempty"`         // focus on changed code: PR URL, git ref range, or HEAD~N
	LastCommits int    `json:"last_commits,omitempty"` // focus on last N commits (shorthand for diff HEAD~N)

	// Upload results to cloud storage after scan completion
	UploadResults bool `json:"upload_results,omitempty"`

	// AgentBYOK fields (api_key, oauth_token, oauth_cred_file, oauth_cred_json)
	// are accepted at the top level. Master / triage / source-analysis
	// agents all run against the in-process olium engine; when set, the
	// engine for this run is built with these overlaid onto the server-wide
	// agent.olium.* defaults.
	AgentBYOK
}

AgentSwarmRequest is the request body for POST /api/agent/run/swarm.

func (AgentSwarmRequest) EffectiveInputs

func (r AgentSwarmRequest) EffectiveInputs() []string

EffectiveInputs returns all inputs as a slice, merging Input and Inputs.

func (AgentSwarmRequest) ResolvedAuditDriverMode

func (r AgentSwarmRequest) ResolvedAuditDriverMode() string

ResolvedAuditDriverMode returns the effective audit mode. Returns empty string when audit is disabled.

func (AgentSwarmRequest) ResolvedNoAudit

func (r AgentSwarmRequest) ResolvedNoAudit() bool

ResolvedNoAudit returns true when audit should be disabled. Swarm uses opt-in audit: empty string means disabled.

func (*AgentSwarmRequest) UnmarshalJSON

func (r *AgentSwarmRequest) UnmarshalJSON(data []byte) error

UnmarshalJSON implements custom unmarshaling for AgentSwarmRequest to support the legacy "source_path" JSON key as a backward-compatible alias for "source".

type AgenticScanRequest

type AgenticScanRequest struct {
	Agent          string   `json:"agent,omitempty"`
	PromptTemplate string   `json:"prompt_template,omitempty"`
	PromptFile     string   `json:"prompt_file,omitempty"`
	Prompt         string   `json:"prompt,omitempty"`
	SourcePath     string   `json:"source,omitempty"` // path to source code
	Files          []string `json:"files,omitempty"`
	Append         string   `json:"append,omitempty"`
	Instruction    string   `json:"instruction,omitempty"` // custom instruction appended to the prompt
	Source         string   `json:"source_label,omitempty"`
	ScanUUID       string   `json:"scan_uuid,omitempty"`
	ProjectUUID    string   `json:"project_uuid,omitempty"` // project UUID for storage scoping (falls back to X-Project-UUID header)
	Stream         bool     `json:"stream,omitempty"`
	UploadResults  bool     `json:"upload_results,omitempty"` // upload session bundle to cloud storage on completion

	// AgentBYOK fields (api_key, oauth_token, oauth_cred_file, oauth_cred_json)
	// are accepted at the top level. When set, the in-process olium engine
	// for this request is built from a per-request OliumConfig overlay rather
	// than the server-wide agent.olium.* defaults.
	AgentBYOK
}

AgenticScanRequest is the request body for POST /api/agent/run/query.

type AgenticScanResponse

type AgenticScanResponse struct {
	AgenticScanUUID string `json:"agentic_scan_uuid"`
	Status          string `json:"status"`
	Message         string `json:"message,omitempty"`
}

AgenticScanResponse is the response for POST /api/agent/run/*.

type AgenticScanStatusResponse

type AgenticScanStatusResponse struct {
	AgenticScanUUID string        `json:"agentic_scan_uuid"`
	ProjectUUID     string        `json:"project_uuid,omitempty"` // owning project; scopes status/list/cancel to X-Project-UUID
	Mode            string        `json:"mode"`                   // "query", "autopilot", "pipeline"
	Status          string        `json:"status"`                 // "running", "completed", "failed"
	AgentName       string        `json:"agent_name,omitempty"`
	TemplateID      string        `json:"template_id,omitempty"`
	FindingCount    int           `json:"finding_count,omitempty"`
	RecordCount     int           `json:"record_count,omitempty"`
	SavedCount      int           `json:"saved_count,omitempty"`
	Error           string        `json:"error,omitempty"`
	CompletedAt     *time.Time    `json:"completed_at,omitempty"`
	Result          *agent.Result `json:"result,omitempty"`
	StorageURL      string        `json:"storage_url,omitempty"`

	// Phase progress fields
	CurrentPhase string   `json:"current_phase,omitempty"`
	PhasesRun    []string `json:"phases_run,omitempty"`

	// Swarm/pipeline result
	SwarmResult *agent.SwarmResult `json:"swarm_result,omitempty"`
}

AgenticScanStatusResponse is the response for GET /api/agent/status/:id and GET /api/agent/status/list.

type AppInfoResponse

type AppInfoResponse struct {
	Name        string `json:"name"`
	Version     string `json:"version"`
	Author      string `json:"author"`
	Docs        string `json:"docs"`
	LicenseSPDX string `json:"license_spdx"`
	Source      string `json:"source"`
	BuildTime   string `json:"build_time,omitempty"`
	Commit      string `json:"commit,omitempty"`
}

AppInfoResponse is the response for GET /api/info.

type ChatChoice

type ChatChoice struct {
	Index        int         `json:"index"`
	Message      ChatMessage `json:"message"`
	FinishReason string      `json:"finish_reason"`
}

ChatChoice represents a single completion choice.

type ChatCompletionRequest

type ChatCompletionRequest struct {
	Model    string        `json:"model"`
	Messages []ChatMessage `json:"messages"`

	// AgentBYOK fields (api_key, oauth_token, oauth_cred_file,
	// oauth_cred_json) are accepted at the top level. In no-auth server
	// mode, an `Authorization: Bearer <key>` header is also promoted into
	// AgentBYOK.APIKey for OpenAI-SDK compatibility.
	AgentBYOK
}

ChatCompletionRequest is an OpenAI-compatible chat completion request.

type ChatCompletionResponse

type ChatCompletionResponse struct {
	ID      string       `json:"id"`
	Object  string       `json:"object"`
	Created int64        `json:"created"`
	Model   string       `json:"model"`
	Choices []ChatChoice `json:"choices"`
	Usage   *ChatUsage   `json:"usage,omitempty"`
}

ChatCompletionResponse is an OpenAI-compatible chat completion response.

type ChatMessage

type ChatMessage struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

ChatMessage represents a single message in a chat completion request/response.

type ChatUsage

type ChatUsage struct {
	PromptTokens     int `json:"prompt_tokens"`
	CompletionTokens int `json:"completion_tokens"`
	TotalTokens      int `json:"total_tokens"`
}

ChatUsage reports token usage for a chat completion.

type ConfigEntryResponse

type ConfigEntryResponse struct {
	Key       string `json:"key"`
	Value     string `json:"value"`
	Sensitive bool   `json:"sensitive,omitempty"`
}

ConfigEntryResponse is a single config entry in API responses.

type ConfigListResponse

type ConfigListResponse struct {
	Entries []ConfigEntryResponse `json:"entries"`
	Total   int                   `json:"total"`
}

ConfigListResponse is the response for GET /api/config.

type ConfigUpdateRequest

type ConfigUpdateRequest map[string]string

ConfigUpdateRequest is the request body for POST /api/config. Keys are dot-notation paths, values are string representations.

type ConfigUpdateResponse

type ConfigUpdateResponse struct {
	Message string                `json:"message"`
	Updated []ConfigEntryResponse `json:"updated"`
	Errors  []string              `json:"errors,omitempty"`
}

ConfigUpdateResponse is the response for POST /api/config.

type ErrorResponse

type ErrorResponse struct {
	Error   string `json:"error"`
	Code    int    `json:"code,omitempty"`
	Details string `json:"details,omitempty"`
}

ErrorResponse is returned for error conditions.

type ExtensionAPIFunction

type ExtensionAPIFunction struct {
	Category    string `json:"category"`
	Namespace   string `json:"namespace"`
	Name        string `json:"name"`
	FullName    string `json:"full_name"`
	Signature   string `json:"signature"`
	Returns     string `json:"returns"`
	Description string `json:"description"`
	Example     string `json:"example,omitempty"`
}

ExtensionAPIFunction is a single JS utility function entry.

type ExtensionDetail

type ExtensionDetail struct {
	ExtensionInfo
	RawContent string `json:"raw_content"`
}

ExtensionDetail is the full extension response including raw file content, returned by GET /api/extensions/:name.

type ExtensionEditRequest

type ExtensionEditRequest struct {
	Content string `json:"content"`
}

ExtensionEditRequest is the request body for PUT /api/extensions/:name.

type ExtensionInfo

type ExtensionInfo struct {
	ID                   string   `json:"id"`
	Name                 string   `json:"name"`
	Language             string   `json:"language"` // "js" or "yaml"
	Type                 string   `json:"type"`     // "active", "passive", "pre_hook", "post_hook"
	Severity             string   `json:"severity,omitempty"`
	Confidence           string   `json:"confidence,omitempty"` // tentative, firm, certain
	ScanTypes            []string `json:"scan_types,omitempty"`
	Tags                 []string `json:"tags,omitempty"`
	Scope                string   `json:"scope,omitempty"`
	Description          string   `json:"description,omitempty"`
	ConfirmationCriteria string   `json:"confirmation_criteria,omitempty"`
	File                 string   `json:"file"`
	FileName             string   `json:"file_name"`
}

ExtensionInfo is the metadata summary of a loaded extension, returned in list responses.

type FileUser

type FileUser struct {
	Name       string `json:"name"`
	Email      string `json:"email"`
	AccessCode string `json:"access_code"`
	Role       string `json:"role"`
}

FileUser represents a single entry in the users JSON file.

func LoadUsersFile

func LoadUsersFile(path string) ([]FileUser, error)

LoadUsersFile reads and parses a users JSON file from the given path. Returns nil, nil if the file does not exist or is empty (graceful fallback to legacy auth).

type FindingStats

type FindingStats struct {
	Total      int64            `json:"total"`
	BySeverity map[string]int64 `json:"by_severity"`
}

FindingStats holds finding counts.

type HTTPRecordStats

type HTTPRecordStats struct {
	Total int64 `json:"total"`
}

HTTPRecordStats holds HTTP record counts.

type Handlers

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

Handlers holds the HTTP handlers and their dependencies.

func NewHandlers

func NewHandlers(q queue.Queue, db *database.DB, repo *database.Repository, rw *database.RecordWriter, cfg ServerConfig, settings *config.Settings, httpRequester *http.Requester, svc *services.Services) *Handlers

NewHandlers creates a new Handlers instance. Starts a background goroutine to clean up old agent run records from the database.

func (*Handlers) Close

func (h *Handlers) Close()

func (*Handlers) HandleAgentAudit

func (h *Handlers) HandleAgentAudit(c fiber.Ctx) error

HandleAgentAudit handles POST /api/agent/run/audit — launches one or both audit drivers (audit and piolium) against a source tree.

`driver` selects which harnesses participate; "both" (default) runs them sequentially under one parent AgenticScan with per-driver child rows, multiplexed SSE events tagged by driver, and a post-pass project-wide findings dedup. With "both", `mode` is restricted to the shared set — driver-specific modes require an explicit single-driver value.

func (*Handlers) HandleAgentAutopilot

func (h *Handlers) HandleAgentAutopilot(c fiber.Ctx) error

HandleAgentAutopilot handles POST /api/agent/run/autopilot — launches an autonomous AI scanning session.

func (*Handlers) HandleAgentCancel

func (h *Handlers) HandleAgentCancel(c fiber.Ctx) error

HandleAgentCancel handles POST /api/agent/scans/:uuid/cancel — aborts an in-flight agent run (autopilot/swarm/query/audit). It cancels the run's context, which unwinds the run and lets its finalization record the terminal "cancelled" status. Returns 404 when no run with that UUID is currently running in this process (already finished, never started, or unknown).

func (*Handlers) HandleAgentQuery

func (h *Handlers) HandleAgentQuery(c fiber.Ctx) error

HandleAgentQuery handles POST /api/agent/run/query — triggers a single-shot AI agent run. When "stream":true, the response is an SSE stream; otherwise it returns 202 async.

func (*Handlers) HandleAgentSessionArtifact

func (h *Handlers) HandleAgentSessionArtifact(c fiber.Ctx) error

HandleAgentSessionArtifact serves a single file from an agent session directory. The file path is captured by the wildcard route segment and is resolved within the session_dir; any attempt to escape via "..", absolute paths, or symlinks pointing outside the session_dir is rejected with 400.

When the file exists and is small enough, its bytes are streamed back with a content-type derived from the extension. Use ?max_bytes=N to override the default 10 MiB cap (hard cap: 100 MiB).

func (*Handlers) HandleAgentSessionArtifacts

func (h *Handlers) HandleAgentSessionArtifacts(c fiber.Ctx) error

HandleAgentSessionArtifacts lists files inside an agent session directory. The walk is recursive but capped at maxArtifactListEntries; the response flags `truncated: true` when the cap is hit. Names are returned as paths relative to the session_dir so they can be passed back to HandleAgentSessionArtifact unchanged.

func (*Handlers) HandleAgentSessionDetail

func (h *Handlers) HandleAgentSessionDetail(c fiber.Ctx) error

HandleAgentSessionDetail returns full details for a single agent session.

func (*Handlers) HandleAgentSessionList

func (h *Handlers) HandleAgentSessionList(c fiber.Ctx) error

HandleAgentSessionList returns a paginated list of agent sessions from the database.

func (*Handlers) HandleAgentSessionLogs

func (h *Handlers) HandleAgentSessionLogs(c fiber.Ctx) error

HandleAgentSessionLogs serves the raw run.log console stream for an agent session. With Accept: text/event-stream it tails the file as SSE until the run reaches a terminal status; otherwise it returns the full file as text/plain. ANSI colors are preserved by default so clients that render a terminal (xterm.js, etc.) see what the CLI user would see; pass ?strip=1 to get plain text with escape sequences removed.

func (*Handlers) HandleAgentSwarm

func (h *Handlers) HandleAgentSwarm(c fiber.Ctx) error

HandleAgentSwarm handles POST /api/agent/run/swarm — launches an AI-guided targeted swarm.

func (*Handlers) HandleAgenticScanList

func (h *Handlers) HandleAgenticScanList(c fiber.Ctx) error

HandleAgenticScanList handles GET /api/agent/status/list — returns all agent run statuses. Returns from database for historical runs, merged with in-memory status for active runs.

func (*Handlers) HandleAgenticScanStatus

func (h *Handlers) HandleAgenticScanStatus(c fiber.Ctx) error

HandleAgenticScanStatus handles GET /api/agent/status/:id — returns status of a specific agent run.

func (*Handlers) HandleAppInfo

func (h *Handlers) HandleAppInfo(c fiber.Ctx) error

HandleAppInfo handles GET /api/info — returns basic app info.

func (*Handlers) HandleBurpSiteMapSnapshot

func (h *Handlers) HandleBurpSiteMapSnapshot(c fiber.Ctx) error

func (*Handlers) HandleChatCompletions

func (h *Handlers) HandleChatCompletions(c fiber.Ctx) error

HandleChatCompletions handles POST /api/agent/chat/completions — OpenAI-compatible chat endpoint.

BYOK is accepted via two channels for OpenAI-client compatibility:

  1. Standard body fields (api_key / oauth_token / oauth_cred_file / oauth_cred_json) like every other /agent/run/* endpoint.
  2. An `Authorization: Bearer <key>` header — what every OpenAI SDK sends. The header is honored only when the body fields are empty so a request can't smuggle two keys; the bearer value is mapped into AgentBYOK.APIKey and routed through the same overlay path.

The server-level BearerAuth middleware also consumes the Authorization header (validating user tokens) but only when --no-auth is off. In no-auth mode the header passes through to this handler untouched; in auth mode the user token IS the bearer, so BYOK via header is not available — fall back to body fields.

func (*Handlers) HandleCreateDBRecord

func (h *Handlers) HandleCreateDBRecord(c fiber.Ctx) error

HandleCreateDBRecord inserts a new record into a table. POST /api/db/tables/:table/records

func (*Handlers) HandleCreateProject

func (h *Handlers) HandleCreateProject(c fiber.Ctx) error

HandleCreateProject handles POST /api/projects

func (*Handlers) HandleDeleteDBRecord

func (h *Handlers) HandleDeleteDBRecord(c fiber.Ctx) error

HandleDeleteDBRecord deletes a record by primary key. DELETE /api/db/tables/:table/records/:id

func (*Handlers) HandleDeleteOASTInteraction

func (h *Handlers) HandleDeleteOASTInteraction(c fiber.Ctx) error

HandleDeleteOASTInteraction handles DELETE /api/oast-interactions/:id

func (*Handlers) HandleDeleteProject

func (h *Handlers) HandleDeleteProject(c fiber.Ctx) error

HandleDeleteProject handles DELETE /api/projects/:uuid

func (*Handlers) HandleDeleteRecord

func (h *Handlers) HandleDeleteRecord(c fiber.Ctx) error

HandleDeleteRecord handles DELETE /api/http-records/:uuid — deletes a single HTTP record by UUID.

func (*Handlers) HandleDeleteScan

func (h *Handlers) HandleDeleteScan(c fiber.Ctx) error

HandleDeleteScan handles DELETE /api/scans/:uuid — deletes a scan record.

func (*Handlers) HandleDiagnostics

func (h *Handlers) HandleDiagnostics(c fiber.Ctx) error

HandleDiagnostics handles GET /api/diagnostics — returns a system readiness report.

func (*Handlers) HandleEditExtension

func (h *Handlers) HandleEditExtension(c fiber.Ctx) error

HandleEditExtension handles PUT /api/extensions/:name

func (*Handlers) HandleGetConfig

func (h *Handlers) HandleGetConfig(c fiber.Ctx) error

HandleGetConfig handles GET /api/config — returns flattened config entries. Query params:

  • filter: substring match on key (optional)
  • show_sensitive: "true" to show unredacted sensitive values (optional)

func (*Handlers) HandleGetDBRecord

func (h *Handlers) HandleGetDBRecord(c fiber.Ctx) error

HandleGetDBRecord returns a single record by primary key. GET /api/db/tables/:table/records/:id

func (*Handlers) HandleGetExtension

func (h *Handlers) HandleGetExtension(c fiber.Ctx) error

HandleGetExtension handles GET /api/extensions/:name Returns full extension metadata plus raw file content.

func (*Handlers) HandleGetOASTInteraction

func (h *Handlers) HandleGetOASTInteraction(c fiber.Ctx) error

HandleGetOASTInteraction handles GET /api/oast-interactions/:id

func (*Handlers) HandleGetProject

func (h *Handlers) HandleGetProject(c fiber.Ctx) error

HandleGetProject handles GET /api/projects/:uuid

func (*Handlers) HandleGetProjectStats

func (h *Handlers) HandleGetProjectStats(c fiber.Ctx) error

HandleGetProjectStats handles GET /api/projects/:uuid/stats — returns just the aggregated stats for a project, without the project metadata. Useful when the UI needs to refresh stats independently of the project record.

func (*Handlers) HandleGetRecord

func (h *Handlers) HandleGetRecord(c fiber.Ctx) error

HandleGetRecord handles GET /api/http-records/:uuid — returns a single HTTP record with full blob fields.

func (*Handlers) HandleGetScan

func (h *Handlers) HandleGetScan(c fiber.Ctx) error

HandleGetScan handles GET /api/scans/:uuid — returns a single scan by UUID.

func (*Handlers) HandleGetScanLogs

func (h *Handlers) HandleGetScanLogs(c fiber.Ctx) error

HandleGetScanLogs handles GET /api/scans/:uuid/logs — returns scan logs.

Response format is chosen by the content source in the same priority order as the `vigolium log <uuid>` CLI command:

  1. If {sessions_dir}/{scanUUID}/runtime.log exists, serve its contents as text/plain. Matches what the operator sees when tailing the CLI log. ANSI colors are preserved by default; pass ?strip=1 to remove them.

  2. Otherwise, fall back to the scan_logs database table and return the structured JSON envelope ({"logs": [...], "total": N}) that older clients depend on. This fallback is the legacy path used by scans that predate runtime.log persistence.

func (*Handlers) HandleGetScope

func (h *Handlers) HandleGetScope(c fiber.Ctx) error

HandleGetScope handles GET /api/scope — returns the current scope config.

func (*Handlers) HandleHealth

func (h *Handlers) HandleHealth(c fiber.Ctx) error

HandleHealth handles GET /health — a liveness probe. It reports that the process/event loop is alive and intentionally does NOT touch the database, so it never fails just because the DB is momentarily slow.

func (*Handlers) HandleImport

func (h *Handlers) HandleImport(c fiber.Ctx) error

HandleImport handles POST /api/import — imports scan data into the database from one of three input shapes, dispatched on Content-Type:

  • multipart/form-data with file=*.jsonl|*.ndjson: bulk JSONL import.
  • multipart/form-data with file=*.tar.gz|*.tgz|*.zip: archive containing audit output or JSONL files.
  • application/json with {"url": "gs://..."}: backend fetches the archive or JSONL from cloud storage, then imports it.

All shapes accept an optional `agentic_scan_uuid` to attach imported findings to an existing scan instead of creating a new one. For multipart requests it's a form field; for JSON it's a body field.

func (*Handlers) HandleIngestHTTP

func (h *Handlers) HandleIngestHTTP(c fiber.Ctx) error

HandleIngestHTTP handles POST /api/ingest-http

func (*Handlers) HandleListDBRecords

func (h *Handlers) HandleListDBRecords(c fiber.Ctx) error

HandleListDBRecords returns paginated, filtered records from any table. GET /api/db/tables/:table/records

func (*Handlers) HandleListDBTableColumns

func (h *Handlers) HandleListDBTableColumns(c fiber.Ctx) error

HandleListDBTableColumns returns column metadata for a specific table. GET /api/db/tables/:table/columns

func (*Handlers) HandleListDBTables

func (h *Handlers) HandleListDBTables(c fiber.Ctx) error

HandleListDBTables returns all database tables with row counts. GET /api/db/tables

func (*Handlers) HandleListExtensionAPI

func (h *Handlers) HandleListExtensionAPI(c fiber.Ctx) error

HandleListExtensionAPI handles GET /api/extensions/docs Optional query params: ?search=<text>

func (*Handlers) HandleListExtensions

func (h *Handlers) HandleListExtensions(c fiber.Ctx) error

HandleListExtensions handles GET /api/extensions Optional query params: ?type=active|passive|pre_hook|post_hook, ?search=<text>

func (*Handlers) HandleListModules

func (h *Handlers) HandleListModules(c fiber.Ctx) error

HandleListModules handles GET /api/modules?search=xss&tag=spring

func (*Handlers) HandleListOASTInteractions

func (h *Handlers) HandleListOASTInteractions(c fiber.Ctx) error

HandleListOASTInteractions handles GET /api/oast-interactions

func (*Handlers) HandleListProjects

func (h *Handlers) HandleListProjects(c fiber.Ctx) error

HandleListProjects handles GET /api/projects

func (*Handlers) HandleListRecords

func (h *Handlers) HandleListRecords(c fiber.Ctx) error

HandleListRecords handles GET /api/http-records

func (*Handlers) HandleListScans

func (h *Handlers) HandleListScans(c fiber.Ctx) error

HandleListScans handles GET /api/scans — returns paginated scan history.

func (*Handlers) HandleLogin

func (h *Handlers) HandleLogin(c fiber.Ctx) error

HandleLogin handles POST /api/auth/login. Validates username + access_code and returns user info with a Bearer token.

func (*Handlers) HandleMetrics

func (h *Handlers) HandleMetrics(c fiber.Ctx) error

HandleMetrics handles GET /metrics — serves Prometheus metrics.

func (*Handlers) HandlePauseScan

func (h *Handlers) HandlePauseScan(c fiber.Ctx) error

HandlePauseScan handles POST /api/scans/:uuid/pause — pauses a running scan.

func (*Handlers) HandleReady

func (h *Handlers) HandleReady(c fiber.Ctx) error

HandleReady handles GET /ready — a readiness probe distinct from liveness. It reports 200 only when the server can actually serve work: the database responds to a lightweight ping within a short timeout and the record writer is still accepting writes. Otherwise it returns 503 so an orchestrator routes traffic elsewhere without killing the (live) process.

func (*Handlers) HandleResumeScan

func (h *Handlers) HandleResumeScan(c fiber.Ctx) error

HandleResumeScan handles POST /api/scans/:uuid/resume — resumes a paused scan.

func (*Handlers) HandleRunScan

func (h *Handlers) HandleRunScan(c fiber.Ctx) error

HandleRunScan handles POST /api/scans/run — triggers an async target-based scan. This route only accepts target URLs. Use POST /api/scan-all-records to scan DB records.

func (*Handlers) HandleScanAllRecords

func (h *Handlers) HandleScanAllRecords(c fiber.Ctx) error

HandleScanAllRecords handles POST /api/scan-all-records — scans existing HTTP records from the database with optional filtering by hostname, method, path, status code, etc.

func (*Handlers) HandleScanRecords

func (h *Handlers) HandleScanRecords(c fiber.Ctx) error

HandleScanRecords handles POST /api/scan-records — starts a scan on specific HTTP records by UUID.

func (*Handlers) HandleScanRequest

func (h *Handlers) HandleScanRequest(c fiber.Ctx) error

HandleScanRequest handles POST /api/scan-request — scans a raw HTTP request asynchronously.

func (*Handlers) HandleScanStatus

func (h *Handlers) HandleScanStatus(c fiber.Ctx) error

HandleScanStatus handles GET /api/scan/status — returns current scan state. Accepts optional ?project= query param to check a specific project.

func (*Handlers) HandleScanURL

func (h *Handlers) HandleScanURL(c fiber.Ctx) error

HandleScanURL handles POST /api/scan-url — scans a single URL asynchronously.

func (*Handlers) HandleServerInfo

func (h *Handlers) HandleServerInfo(c fiber.Ctx) error

HandleServerInfo handles GET /server-info.

func (*Handlers) HandleStats

func (h *Handlers) HandleStats(c fiber.Ctx) error

HandleStats handles GET /api/stats — returns aggregated scan statistics.

func (*Handlers) HandleStopScan

func (h *Handlers) HandleStopScan(c fiber.Ctx) error

HandleStopScan handles POST /api/scans/:uuid/stop — stops a specific running scan.

func (*Handlers) HandleStorageDownloadResults

func (h *Handlers) HandleStorageDownloadResults(c fiber.Ctx) error

HandleStorageDownloadResults handles GET /api/storage/results/:scan_uuid. Downloads the result bundle for a native scan or agentic scan.

func (*Handlers) HandleStorageDownloadSource

func (h *Handlers) HandleStorageDownloadSource(c fiber.Ctx) error

HandleStorageDownloadSource handles GET /api/storage/source/:key. Downloads a source file from <bucket>/<project-uuid>/ugc/:key.

func (*Handlers) HandleStoragePresign

func (h *Handlers) HandleStoragePresign(c fiber.Ctx) error

HandleStoragePresign handles POST /api/storage/presign. Generates presigned URLs for direct upload/download.

func (*Handlers) HandleStorageUploadSource

func (h *Handlers) HandleStorageUploadSource(c fiber.Ctx) error

HandleStorageUploadSource handles POST /api/storage/upload-source. Accepts multipart file upload and stores it in <bucket>/<project-uuid>/ugc/<filename>.

func (*Handlers) HandleSwaggerSpec

func (h *Handlers) HandleSwaggerSpec(c fiber.Ctx) error

HandleSwaggerSpec serves the OpenAPI specification JSON.

func (*Handlers) HandleUpdateAgenticScan

func (h *Handlers) HandleUpdateAgenticScan(c fiber.Ctx) error

HandleUpdateAgenticScan handles POST /api/agent/scans/:uuid/update — partially updates an existing agentic scan record. Fields omitted from the body are left unchanged. Immutable fields (id, uuid, project_uuid, created_at) are ignored if present in the request body.

func (*Handlers) HandleUpdateConfig

func (h *Handlers) HandleUpdateConfig(c fiber.Ctx) error

HandleUpdateConfig handles POST /api/config — updates multiple config values. Accepts JSON body: {"dot.key1": "value1", "dot.key2": "value2"}

func (*Handlers) HandleUpdateDBRecord

func (h *Handlers) HandleUpdateDBRecord(c fiber.Ctx) error

HandleUpdateDBRecord updates fields on an existing record. PUT /api/db/tables/:table/records/:id

func (*Handlers) HandleUpdateProject

func (h *Handlers) HandleUpdateProject(c fiber.Ctx) error

HandleUpdateProject handles PUT /api/projects/:uuid

func (*Handlers) HandleUpdateScan

func (h *Handlers) HandleUpdateScan(c fiber.Ctx) error

HandleUpdateScan handles POST /api/scans/:uuid/update — partially updates an existing native scan record. Fields omitted from the body are left unchanged. Immutable fields (uuid, project_uuid, created_at) are ignored if present in the request body — the UUID is taken from the path, and project ownership is validated against X-Project-UUID before the write.

func (*Handlers) HandleUpdateScope

func (h *Handlers) HandleUpdateScope(c fiber.Ctx) error

HandleUpdateScope handles POST /api/scope — updates the scope config.

func (*Handlers) HandleUserInfo

func (h *Handlers) HandleUserInfo(c fiber.Ctx) error

HandleUserInfo handles GET /api/user/info. Returns the authenticated user's identity and role.

func (*Handlers) IsScanRunning

func (h *Handlers) IsScanRunning() bool

IsScanRunning reports whether any scan is currently running (across all projects). Implements metrics.ScanStateProvider.

type HealthResponse

type HealthResponse struct {
	Status    string `json:"status"`
	Timestamp string `json:"timestamp"`
}

HealthResponse is the response for GET /health.

type ImportRequest

type ImportRequest struct {
	URL             string `json:"url"`
	AgenticScanUUID string `json:"agentic_scan_uuid,omitempty"`
}

ImportRequest is the JSON body for POST /api/import when pointing the server at a cloud-stored archive instead of uploading bytes. URL must be gs:// (or gcs:// alias). AgenticScanUUID, when set, attaches findings to an existing scan row in the same project instead of creating a new one.

type ImportResponse

type ImportResponse struct {
	AgenticScanUUID string         `json:"agentic_scan_uuid,omitempty"`
	CreatedNew      bool           `json:"created_new"`
	RecordsImported int            `json:"records_imported"`
	FindingsTotal   int            `json:"findings_total"`
	FindingsSaved   int            `json:"findings_saved"`
	FindingsSkipped int            `json:"findings_skipped"`
	ParseErrors     int            `json:"parse_errors,omitempty"`
	Severity        map[string]int `json:"severity,omitempty"`
	SessionDir      string         `json:"session_dir,omitempty"`
	StorageURL      string         `json:"storage_url,omitempty"`
}

ImportResponse is the success response for POST /api/import.

type IngestHTTPRequest

type IngestHTTPRequest struct {
	InputMode          string `json:"input_mode"`
	URL                string `json:"url,omitempty"`
	Content            string `json:"content,omitempty"`
	ContentBase64      string `json:"content_base64,omitempty"`
	HTTPRequestBase64  string `json:"http_request_base64,omitempty"`
	HTTPResponseBase64 string `json:"http_response_base64,omitempty"`
}

IngestHTTPRequest is the request body for POST /api/ingest-http.

type IngestHTTPResponse

type IngestHTTPResponse struct {
	ProjectUUID string   `json:"project_uuid,omitempty"`
	Imported    int      `json:"imported"`
	Skipped     int      `json:"skipped,omitempty"`
	Errors      []string `json:"errors,omitempty"`
	Message     string   `json:"message"`
}

IngestHTTPResponse is the response for POST /api/ingest-http.

type LoginRequest

type LoginRequest struct {
	Username   string `json:"username"`
	AccessCode string `json:"access_code"`
}

LoginRequest is the request body for POST /api/auth/login.

type LoginResponse

type LoginResponse struct {
	Token string    `json:"token"`
	User  LoginUser `json:"user"`
}

LoginResponse is the response for POST /api/auth/login.

type LoginUser

type LoginUser struct {
	UUID  string `json:"uuid"`
	Name  string `json:"name"`
	Email string `json:"email"`
	Role  string `json:"role"`
}

LoginUser is the user info returned in a login response.

type ModuleCount

type ModuleCount struct {
	Total   int `json:"total"`
	Enabled int `json:"enabled"`
}

ModuleCount holds total and enabled counts for a module type.

type ModuleInfo

type ModuleInfo struct {
	ID                   string   `json:"id"`
	Name                 string   `json:"name"`
	Description          string   `json:"description"`
	ShortDescription     string   `json:"short_description"`
	ConfirmationCriteria string   `json:"confirmation_criteria"`
	Severity             string   `json:"severity"`
	Confidence           string   `json:"confidence"`
	ScanScope            []string `json:"scan_scope"`
	Tags                 []string `json:"tags"`
	Type                 string   `json:"type"` // "active" or "passive"
}

ModuleInfo is the response type for module listing.

type ModuleStats

type ModuleStats struct {
	Active  ModuleCount `json:"active"`
	Passive ModuleCount `json:"passive"`
}

ModuleStats holds module counts.

type PaginatedResponse

type PaginatedResponse struct {
	ProjectUUID string      `json:"project_uuid,omitempty"`
	Data        interface{} `json:"data"`
	Total       int64       `json:"total"`
	Limit       int         `json:"limit"`
	Offset      int         `json:"offset"`
	HasMore     bool        `json:"has_more"`
}

PaginatedResponse wraps paginated results.

type ProjectFindingStats

type ProjectFindingStats struct {
	Total    int64 `json:"total"`
	Critical int64 `json:"critical"`
	High     int64 `json:"high"`
	Medium   int64 `json:"medium"`
	Low      int64 `json:"low"`
	Info     int64 `json:"info"`
}

ProjectFindingStats holds finding counts with severity breakdown.

type ProjectHTTPRecordStats

type ProjectHTTPRecordStats struct {
	Total     int64 `json:"total"`
	Success   int64 `json:"success"`    // 2xx
	Redirect  int64 `json:"redirect"`   // 3xx
	ClientErr int64 `json:"client_err"` // 4xx
	ServerErr int64 `json:"server_err"` // 5xx
}

ProjectHTTPRecordStats holds HTTP record counts with status breakdown.

type ProjectRequest

type ProjectRequest struct {
	UUID        string `json:"uuid,omitempty"`
	Name        string `json:"name"`
	Description string `json:"description"`
	OwnerUUID   string `json:"owner_uuid"`
}

ProjectRequest is the request body for POST/PUT /api/projects.

UUID is optional on POST. When the cloud console eagerly provisions a scanner row for a Convex-managed project, it sends the Convex-side UUID so both systems agree on the same key. When omitted, the scanner mints a fresh UUID — preserving the standalone-CLI behavior.

type ProjectStats

type ProjectStats struct {
	HTTPRecords      ProjectHTTPRecordStats `json:"http_records"`
	Findings         ProjectFindingStats    `json:"findings"`
	Scans            int64                  `json:"scans"`
	AgenticScans     int64                  `json:"agentic_scans"`
	OASTInteractions int64                  `json:"oast_interactions"`
}

ProjectStats holds aggregated statistics for a project.

type ProjectWithStats

type ProjectWithStats struct {
	*database.Project
	Stats ProjectStats `json:"stats"`
}

ProjectWithStats wraps a Project with its aggregated stats.

type ResolvedUser

type ResolvedUser struct {
	UUID  string
	Name  string
	Email string
	Role  string
}

ResolvedUser is the identity attached to a request after auth resolution.

type RunScanRequest

type RunScanRequest struct {
	// Target URLs to scan (like -t). At least one target or url is required.
	Targets []string `json:"targets,omitempty"`
	// URLs is an alias for Targets.
	URLs []string `json:"urls,omitempty"`

	// DryRun validates params and creates scan record but does not launch the runner
	DryRun bool `json:"dry_run"`

	// Strategy preset: lite, balanced, deep
	Strategy string `json:"strategy,omitempty"`
	// Single phase isolation (like --only)
	Only string `json:"only,omitempty"`
	// Skip specific phases (like --skip)
	Skip []string `json:"skip,omitempty"`

	// Module IDs with fuzzy match (like -m)
	Modules []string `json:"modules,omitempty"`
	// Filter modules by tag (like --module-tag)
	ModuleTags []string `json:"module_tags,omitempty"`

	// Performance tuning
	Concurrency int    `json:"concurrency,omitempty"`
	Timeout     string `json:"timeout,omitempty"` // Go duration e.g. "30s"
	MaxPerHost  int    `json:"max_per_host,omitempty"`
	RateLimit   int    `json:"rate_limit,omitempty"`

	// Max scan duration (like --scanning-max-duration)
	ScanningMaxDuration string `json:"scanning_max_duration,omitempty"`

	// Scope origin mode: all, relaxed, balanced, strict
	ScopeOrigin string `json:"scope_origin,omitempty"`

	// Heuristics check level: none, basic, advanced
	HeuristicsCheck string `json:"heuristics_check,omitempty"`

	// Custom HTTP headers
	Headers map[string]string `json:"headers,omitempty"`

	// Scanning profile name or path
	ScanningProfile string `json:"scanning_profile,omitempty"`

	// Intensity preset: quick, balanced, deep (resolves to scanning_profile + strategy)
	Intensity string `json:"intensity,omitempty"`

	// Upload results to cloud storage after scan completion
	UploadResults bool `json:"upload_results,omitempty"`

	// OutputFormats selects extra result formats to materialize on disk during
	// the scan. Currently supports "jsonl" and "html". When set, files are
	// written to <sessions_dir>/<scan_uuid>/output.<ext> and — if
	// upload_results is also true — bundled into the uploaded tar.gz alongside
	// runtime.log.
	OutputFormats []string `json:"output_formats,omitempty"`

	// Pin scan UUID (for cross-node sync). When set, the scan record is
	// fetched-or-created with this UUID; if a record already exists, its
	// project_uuid must match.
	ScanUUID string `json:"scan_uuid,omitempty"`
}

RunScanRequest is the request body for POST /api/scans/run. This route only accepts target URLs — use /api/scan-all-records to scan DB records.

type ScanAllRecordsRequest

type ScanAllRecordsRequest struct {
	// Record selection filters (all optional — omit all to scan everything)
	Hostname     string   `json:"hostname,omitempty"`       // hostname filter (supports * wildcards)
	Methods      []string `json:"methods,omitempty"`        // HTTP methods filter
	Path         string   `json:"path,omitempty"`           // path filter (supports * wildcards)
	StatusCodes  []int    `json:"status_codes,omitempty"`   // status code filter
	Source       string   `json:"source,omitempty"`         // record source filter
	Search       string   `json:"search,omitempty"`         // search across URL/path
	MinRiskScore int      `json:"min_risk_score,omitempty"` // minimum risk score
	// MinSurfaceScore filters on the deterministic attack-surface score (0-100)
	// written by the surface_scoring passive module, which owns the scale.
	MinSurfaceScore int    `json:"min_surface_score,omitempty"`
	Remark          string `json:"remark,omitempty"` // remark substring filter

	// Force full rescan (ignore cursor, scan all matching records)
	Force bool `json:"force"`

	// DryRun validates params, counts matching records, but does not launch the runner
	DryRun bool `json:"dry_run"`

	// Module IDs with fuzzy match (like -m)
	Modules []string `json:"modules,omitempty"`
	// Filter modules by tag (like --module-tag)
	ModuleTags []string `json:"module_tags,omitempty"`

	// Performance tuning
	Concurrency int    `json:"concurrency,omitempty"`
	Timeout     string `json:"timeout,omitempty"` // Go duration e.g. "30s"
	MaxPerHost  int    `json:"max_per_host,omitempty"`
	RateLimit   int    `json:"rate_limit,omitempty"`

	// Max scan duration (like --scanning-max-duration)
	ScanningMaxDuration string `json:"scanning_max_duration,omitempty"`

	// Heuristics check level: none, basic, advanced
	HeuristicsCheck string `json:"heuristics_check,omitempty"`

	// Custom HTTP headers
	Headers map[string]string `json:"headers,omitempty"`

	// Scanning profile name or path
	ScanningProfile string `json:"scanning_profile,omitempty"`

	// Intensity preset: quick, balanced, deep (resolves to scanning_profile + strategy)
	Intensity string `json:"intensity,omitempty"`
}

ScanAllRecordsRequest is the request body for POST /api/scan-all-records. Scans existing HTTP records from the database with optional filtering.

type ScanRecordsRequest

type ScanRecordsRequest struct {
	RecordUUIDs   []string `json:"record_uuids"`
	EnableModules []string `json:"enable_modules,omitempty"`
}

ScanRecordsRequest is the request body for POST /api/scan-records.

type ScanRequestRequest

type ScanRequestRequest struct {
	// HTTPRequestBase64 is the preferred field name for the base64-encoded raw HTTP request.
	// RawRequest is accepted as an alias for backward compatibility.
	HTTPRequestBase64 string `json:"http_request_base64,omitempty"`
	RawRequest        string `json:"raw_request,omitempty"`
	// HTTPResponseBase64 is the preferred field name for the base64-encoded raw HTTP response
	// (optional, for Burp-style request+response pairs). RawResponse is accepted as an alias.
	HTTPResponseBase64 string `json:"http_response_base64,omitempty"`
	RawResponse        string `json:"raw_response,omitempty"`
	TargetURL          string `json:"target_url"` // scheme://host override
	Modules            string `json:"modules"`    // comma-separated module IDs
	NoPassive          bool   `json:"no_passive"`
}

ScanRequestRequest is the request body for POST /api/scan-request.

func (*ScanRequestRequest) ReqBase64

func (r *ScanRequestRequest) ReqBase64() string

ReqBase64 returns the base64-encoded raw request, preferring http_request_base64 over raw_request.

func (*ScanRequestRequest) RespBase64

func (r *ScanRequestRequest) RespBase64() string

RespBase64 returns the base64-encoded raw response, preferring http_response_base64 over raw_response.

type ScanResponse

type ScanResponse struct {
	ProjectUUID   string `json:"project_uuid,omitempty"`
	ScanUUID      string `json:"scan_uuid"`
	Status        string `json:"status"`
	Message       string `json:"message,omitempty"`
	RecordsToScan int64  `json:"records_to_scan,omitempty"`
	TargetsCount  int    `json:"targets_count,omitempty"`
	ScanMode      string `json:"scan_mode,omitempty"` // "target", "full", "incremental"
}

ScanResponse is the response for POST /api/scans/run.

type ScanStatusResponse

type ScanStatusResponse struct {
	ProjectUUID string `json:"project_uuid,omitempty"`
	ScanUUID    string `json:"scan_uuid,omitempty"`
	Running     bool   `json:"running"`
	Status      string `json:"status"`
	Message     string `json:"message,omitempty"`
}

ScanStatusResponse is the response for GET /api/scan/status.

type ScanURLRequest

type ScanURLRequest struct {
	URL       string            `json:"url"`
	Method    string            `json:"method"` // default GET
	Body      string            `json:"body"`
	Headers   map[string]string `json:"headers"`
	Modules   string            `json:"modules"` // comma-separated module IDs
	NoPassive bool              `json:"no_passive"`
}

ScanURLRequest is the request body for POST /api/scan-url.

type ScopeUpdateResponse

type ScopeUpdateResponse struct {
	Message string      `json:"message"`
	Scope   interface{} `json:"scope"`
}

ScopeUpdateResponse is the response for POST /api/scope.

type Server

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

Server is the HTTP API server.

func NewServer

func NewServer(cfg ServerConfig, q queue.Queue, db *database.DB, repo *database.Repository, settings *config.Settings, httpRequester *vhttp.Requester, svc *services.Services) *Server

NewServer creates a new HTTP API server.

svc is the shared *services.Services the caller built for httpRequester. It carries the dedup manager, host rate limiter, and scan Options used by the core executor — passing it through lets API-triggered scans reuse the same rate-limiter instance the ingestion path uses, rather than running unbounded. Safe to pass nil (handlers will fall back to the previous minimal-wiring behavior).

func (*Server) Config

func (s *Server) Config() ServerConfig

Config returns the server configuration.

func (*Server) OnConfigReload

func (s *Server) OnConfigReload(fn func(changed []string))

OnConfigReload registers fn to run after the config watcher hot-reloads one or more sections at runtime; fn receives the changed section names. No-op when the watcher failed to start. Register before Start(). Used by the CLI to print operator-facing reload feedback.

func (*Server) ProxyCACertPath

func (s *Server) ProxyCACertPath() string

ProxyCACertPath returns the on-disk path of the ingest-proxy MITM CA certificate, or "" when HTTPS interception is not enabled. Used by the CLI to surface the trust anchor at startup.

func (*Server) Queue

func (s *Server) Queue() queue.Queue

Queue returns the underlying queue.

func (*Server) Shutdown

func (s *Server) Shutdown(ctx context.Context) error

Shutdown gracefully shuts down the server.

func (*Server) Start

func (s *Server) Start() error

Start starts the API server (and proxy if configured). Blocks until the server is stopped.

type ServerConfig

type ServerConfig struct {
	ServiceAddr          string   // e.g. "0.0.0.0:9002"
	BurpBridgeURL        string   // optional loopback Burp listener merged into GET /api/http-records
	IngestProxyAddr      string   // e.g. "0.0.0.0:9003" (empty = disabled)
	IngestProxyMITM      bool     // Intercept HTTPS via a generated CA (records + scans TLS traffic)
	IngestProxyInsecure  bool     // Skip upstream TLS verification when intercepting HTTPS
	IngestProxyCADir     string   // Directory holding the MITM CA (empty = ~/.vigolium/ca)
	APIKeys              []string // Valid Bearer tokens
	NoAuth               bool     // If true, skip auth
	ScanOnReceive        bool
	DisableFetchResponse bool
	Concurrency          int // Worker concurrency for API-triggered scans
	ReadTimeout          time.Duration
	// WriteTimeout bounds how long the whole response may take to write. It must
	// be 0 (unlimited) for the SSE agent/audit streams this server hosts — a
	// finite cap severs a stream that outlives it. Non-streaming write protection
	// is provided by IdleTimeout and handler-level deadlines instead. 0 = default
	// (unlimited).
	WriteTimeout    time.Duration
	IdleTimeout     time.Duration
	ShutdownTimeout time.Duration
	// MaxUploadBytes is the framework-level request body ceiling (Fiber BodyLimit).
	// It must exceed the ordinary DefaultBodyLimitMiddleware cap so the large-upload
	// routes (/api/import, /api/storage/upload-source) aren't rejected by the
	// framework before the route exemption runs. 0 = default (512 MiB).
	MaxUploadBytes     int
	CORSAllowedOrigins string
	UserStore          *UserStore    // File-based user store (nil = legacy auth only)
	ScanQueueCapacity  int           // 0 = reject with 409 when busy (default), >0 = per-project queue depth
	NoAgent            bool          // If true, disable all agent endpoints and warm sessions
	ViewOnly           bool          // If true, only serve GET/viewer routes (no scanning, ingestion, or agent)
	DemoOnly           bool          // If true, expose only the demo allowlist (subset of GET endpoints)
	License            string        // Optional license tag surfaced in /server-info (configured in server.license)
	EnableMetrics      bool          // Enable Prometheus /metrics endpoint
	NoSwagger          bool          // If true, disable Swagger UI and spec endpoint
	Debug              bool          // Log raw request body, query params, and headers
	AgentHeavyMax      int           // Max concurrent heavy agent runs (autopilot/swarm); 0 = default 5
	AgentLightMax      int           // Max concurrent light agent runs (query/chat); 0 = default 10
	AgentQueueTimeout  time.Duration // Max wait time when all agent slots busy; 0 = default 30s
	// AgentHeavyPerProject caps how many concurrent heavy agent runs a
	// single project can hold at once. 0 = default 2; negative = disable
	// the per-project cap (only the global AgentHeavyMax applies). Used
	// to prevent one tenant from draining the cluster's heavy slot pool.
	AgentHeavyPerProject int
	Version              string // Injected version string for /server-info
	Author               string
	Commit               string
	BuildTime            string
	// MirrorFSPath, when set, mirrors every ingested HTTP record and finding to
	// a flat filesystem tree under this directory (in addition to the database),
	// so an external agent can read live traffic as files. See --mirror-fs.
	MirrorFSPath string
	// ConfigPath is the effective config file the server loaded settings from
	// (honors the --config flag). The config watcher watches this file for
	// hot-reload. Empty falls back to config.ConfigFilePath() (the default
	// ~/.vigolium/vigolium-configs.yaml).
	ConfigPath string
}

ServerConfig holds configuration for the API server.

func DefaultServerConfig

func DefaultServerConfig() ServerConfig

type ServerInfoResponse

type ServerInfoResponse struct {
	Name          string `json:"name"`
	Version       string `json:"version"`
	Author        string `json:"author"`
	Docs          string `json:"docs"`
	BuildTime     string `json:"build_time,omitempty"`
	Commit        string `json:"commit,omitempty"`
	Uptime        string `json:"uptime"`
	ServiceAddr   string `json:"service_addr"`
	ProxyAddr     string `json:"proxy_addr,omitempty"`
	QueueDepth    int64  `json:"queue_depth"`
	TotalRecords  int64  `json:"total_records"`
	TotalFindings int64  `json:"total_findings"`
	License       string `json:"license,omitempty"`
	LicenseSPDX   string `json:"license_spdx"`
	Source        string `json:"source"`
	DemoOnly      bool   `json:"demo_only,omitempty"`
	ViewOnly      bool   `json:"view_only,omitempty"`
}

ServerInfoResponse is the response for GET /server-info.

type StatsResponse

type StatsResponse struct {
	ProjectUUID string          `json:"project_uuid,omitempty"`
	HTTPRecords HTTPRecordStats `json:"http_records"`
	Modules     ModuleStats     `json:"modules"`
	Findings    FindingStats    `json:"findings"`
}

StatsResponse is the response for GET /api/stats.

type StoragePresignRequest

type StoragePresignRequest struct {
	Key           string `json:"key"`
	Method        string `json:"method,omitempty"` // GET (default) or PUT
	ExpirySeconds int    `json:"expiry_seconds,omitempty"`
}

StoragePresignRequest is the request body for POST /api/storage/presign.

type StoragePresignResponse

type StoragePresignResponse struct {
	URL    string `json:"url"`
	Key    string `json:"key"`
	Method string `json:"method"`
	Expiry int    `json:"expiry_seconds"`
}

StoragePresignResponse is the response for POST /api/storage/presign.

type StorageUploadResponse

type StorageUploadResponse struct {
	StorageURL string `json:"storage_url"`
	Key        string `json:"key"`
	Filename   string `json:"filename"`
	Size       int64  `json:"size"`
	Message    string `json:"message"`
}

StorageUploadResponse is the response for POST /api/storage/upload-source.

type UpdateFindingStatusRequest

type UpdateFindingStatusRequest struct {
	Status string `json:"status"`
}

UpdateFindingStatusRequest is the JSON body for PATCH /api/findings/:id/status.

type UserStore

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

UserStore maps access codes to resolved users for O(1) lookup.

func NewUserStore

func NewUserStore(entries []FileUser) *UserStore

NewUserStore builds a store from a slice of FileUser entries. Each user gets a deterministic UUID v5 derived from their email (or name if no email).

func (*UserStore) Lookup

func (s *UserStore) Lookup(accessCode string) *ResolvedUser

Lookup returns the resolved user for an access code, or nil if not found.

func (*UserStore) LookupByNameAndCode

func (s *UserStore) LookupByNameAndCode(name, accessCode string) *ResolvedUser

LookupByNameAndCode returns the resolved user matching both name and access code, or nil.

Directories

Path Synopsis
Package mitm provides a self-signed certificate authority used by the ingest proxy to intercept TLS connections.
Package mitm provides a self-signed certificate authority used by the ingest proxy to intercept TLS connections.

Jump to

Keyboard shortcuts

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