handler

package
v0.1.5 Latest Latest
Warning

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

Go to latest
Published: Apr 9, 2026 License: GPL-3.0 Imports: 91 Imported by: 0

Documentation

Overview

Package handler provides HTTP handlers for the API server. This file implements admin audit log endpoints.

Package handler provides HTTP handlers for the API server. This file implements admin authentication endpoints.

Package handler provides HTTP handlers for the API server. This file implements admin target mapping management endpoints.

Package handler provides HTTP handlers for the API server. This file implements admin user management endpoints.

Index

Constants

View Source
const (
	// DefaultTenantCookieName is the default name of the cookie storing the current tenant ID.
	// This is NOT httpOnly because frontend needs to read it.
	DefaultTenantCookieName = "app_tenant"
)

Variables

This section is empty.

Functions

func AgentFromContext

func AgentFromContext(ctx context.Context) *agent.Agent

AgentFromContext retrieves the authenticated agent from context.

func ClearRefreshTokenCookie

func ClearRefreshTokenCookie(w http.ResponseWriter, cfg CookieConfig)

ClearRefreshTokenCookie removes the refresh token cookie.

func ClearTenantCookie

func ClearTenantCookie(w http.ResponseWriter, cfg CookieConfig)

ClearTenantCookie removes the tenant cookie.

func GetRefreshTokenFromCookie

func GetRefreshTokenFromCookie(r *http.Request, cfg CookieConfig) string

GetRefreshTokenFromCookie extracts the refresh token from the httpOnly cookie. Falls back to request body if cookie is not present (for backward compatibility).

func SetAccessTokenCookie

func SetAccessTokenCookie(w http.ResponseWriter, token string, expiresAt time.Time, cfg CookieConfig)

SetAccessTokenCookie sets the access token in an httpOnly cookie. This is used by endpoints that issue access tokens directly (e.g., accept invitation with refresh token).

func SetRefreshTokenCookie

func SetRefreshTokenCookie(w http.ResponseWriter, token string, expiresAt time.Time, cfg CookieConfig)

SetRefreshTokenCookie sets the refresh token in an httpOnly cookie. This is more secure than storing in localStorage as it prevents XSS attacks.

func SetTenantCookie

func SetTenantCookie(w http.ResponseWriter, tenantID, tenantSlug, role string, cfg CookieConfig)

SetTenantCookie sets the current tenant info as JSON in a cookie. This cookie is NOT httpOnly because frontend needs to read it. The JSON format matches what frontend TenantProvider expects: {id, slug, role}

func SourceFromContext

func SourceFromContext(ctx context.Context) *agent.Agent

SourceFromContext is an alias for AgentFromContext for backward compatibility. Deprecated: Use AgentFromContext instead.

func WorkerFromContext

func WorkerFromContext(ctx context.Context) *agent.Agent

WorkerFromContext is an alias for AgentFromContext for backward compatibility. Deprecated: Use AgentFromContext instead.

Types

type AITriageHandler

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

AITriageHandler handles AI triage HTTP requests. The handler can work with a nil triageService - in that case, it returns 503 Service Unavailable. This allows routes to be always registered while feature availability is controlled by: 1. Module middleware (checks is_active in database) 2. Service availability (checks if LLM provider is configured)

func NewAITriageHandler

func NewAITriageHandler(triageSvc *app.AITriageService, log *logger.Logger) *AITriageHandler

NewAITriageHandler creates a new AI triage handler. triageService can be nil - handler will return 503 for operations that require the service.

func (*AITriageHandler) GetConfig

func (h *AITriageHandler) GetConfig(w http.ResponseWriter, r *http.Request)

GetConfig handles GET /api/v1/ai-triage/config Returns the AI configuration info for the current tenant. If service is not available, returns a disabled config instead of error.

func (*AITriageHandler) GetTriageResult

func (h *AITriageHandler) GetTriageResult(w http.ResponseWriter, r *http.Request)

GetTriageResult handles GET /api/v1/findings/{id}/ai-triage Gets the latest triage result for a finding.

func (*AITriageHandler) GetTriageResultByID

func (h *AITriageHandler) GetTriageResultByID(w http.ResponseWriter, r *http.Request)

GetTriageResultByID handles GET /api/v1/findings/{id}/ai-triage/{triage_id} Gets a specific triage result by ID.

func (*AITriageHandler) ListTriageHistory

func (h *AITriageHandler) ListTriageHistory(w http.ResponseWriter, r *http.Request)

ListTriageHistory handles GET /api/v1/findings/{id}/ai-triage/history Gets the triage history for a finding.

func (*AITriageHandler) RequestBulkTriage

func (h *AITriageHandler) RequestBulkTriage(w http.ResponseWriter, r *http.Request)

RequestBulkTriage handles POST /api/v1/findings/ai-triage/bulk Triggers AI triage for multiple findings. Limits: max 100 findings, max 64KB payload size.

func (*AITriageHandler) RequestTriage

func (h *AITriageHandler) RequestTriage(w http.ResponseWriter, r *http.Request)

RequestTriage handles POST /api/v1/findings/{id}/ai-triage Triggers AI triage for a finding.

type APIKeyDataRequest

type APIKeyDataRequest struct {
	Key string `json:"key" validate:"required"`
}

APIKeyDataRequest represents API key credential data.

type APIKeyHandler

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

APIKeyHandler handles HTTP requests for API key management.

func NewAPIKeyHandler

func NewAPIKeyHandler(svc *app.APIKeyService, v *validator.Validator, log *logger.Logger) *APIKeyHandler

NewAPIKeyHandler creates a new APIKeyHandler.

func (*APIKeyHandler) Create

func (h *APIKeyHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/api-keys

func (*APIKeyHandler) Delete

func (h *APIKeyHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/api-keys/{id}

func (*APIKeyHandler) Get

Get handles GET /api/v1/api-keys/{id}

func (*APIKeyHandler) List

func (h *APIKeyHandler) List(w http.ResponseWriter, r *http.Request)

List handles GET /api/v1/api-keys

func (*APIKeyHandler) Revoke

func (h *APIKeyHandler) Revoke(w http.ResponseWriter, r *http.Request)

Revoke handles POST /api/v1/api-keys/{id}/revoke

type APIKeyResponse

type APIKeyResponse struct {
	ID          string     `json:"id"`
	TenantID    string     `json:"tenant_id"`
	UserID      string     `json:"user_id,omitempty"`
	Name        string     `json:"name"`
	Description string     `json:"description,omitempty"`
	KeyPrefix   string     `json:"key_prefix"`
	Scopes      []string   `json:"scopes"`
	RateLimit   int        `json:"rate_limit"`
	Status      string     `json:"status"`
	ExpiresAt   *time.Time `json:"expires_at,omitempty"`
	LastUsedAt  *time.Time `json:"last_used_at,omitempty"`
	LastUsedIP  string     `json:"last_used_ip,omitempty"`
	UseCount    int64      `json:"use_count"`
	CreatedBy   string     `json:"created_by,omitempty"`
	CreatedAt   time.Time  `json:"created_at"`
	UpdatedAt   time.Time  `json:"updated_at"`
	RevokedAt   *time.Time `json:"revoked_at,omitempty"`
	RevokedBy   string     `json:"revoked_by,omitempty"`
}

APIKeyResponse represents an API key in the response.

type APISettingsResponse

type APISettingsResponse struct {
	APIKeyEnabled bool     `json:"api_key_enabled"`
	WebhookURL    string   `json:"webhook_url,omitempty"`
	WebhookEvents []string `json:"webhook_events"`
}

APISettingsResponse represents API settings.

type AWSRoleDataRequest

type AWSRoleDataRequest struct {
	RoleARN    string `json:"role_arn" validate:"required"`
	ExternalID string `json:"external_id,omitempty"`
}

AWSRoleDataRequest represents AWS role credential data.

type AcceptInvitationWithRefreshRequest

type AcceptInvitationWithRefreshRequest struct {
	InvitationToken string `json:"invitation_token" validate:"required"`
}

AcceptInvitationWithRefreshRequest is the request body for accepting invitation with refresh token.

type AcceptInvitationWithRefreshResponse

type AcceptInvitationWithRefreshResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int64  `json:"expires_in"`
	TenantID     string `json:"tenant_id"`
	TenantSlug   string `json:"tenant_slug"`
	TenantName   string `json:"tenant_name"`
	Role         string `json:"role"`
}

AcceptInvitationWithRefreshResponse is the response body for accepting invitation with refresh token.

type ActivityItem

type ActivityItem struct {
	Type        string `json:"type"`
	Title       string `json:"title"`
	Description string `json:"description"`
	Timestamp   string `json:"timestamp"`
}

ActivityItem represents a recent activity item.

type AddAssetOwnerRequest added in v0.1.2

type AddAssetOwnerRequest struct {
	UserID        *string `json:"user_id"`
	GroupID       *string `json:"group_id"`
	OwnershipType string  `json:"ownership_type" validate:"required"`
}

AddAssetOwnerRequest represents the request to add an owner to an asset.

type AddAssetsRequest

type AddAssetsRequest struct {
	AssetIDs []string `json:"asset_ids" validate:"required,min=1,dive,uuid"`
}

AddAssetsRequest represents the request to add assets to a group.

type AddCampaignMemberRequest added in v0.1.3

type AddCampaignMemberRequest struct {
	UserID string `json:"user_id" validate:"required,uuid"`
	Role   string `json:"role" validate:"required,oneof=lead tester reviewer observer"`
}

AddCampaignMemberRequest is the API request for adding a team member. AddCampaignMemberRequest with validation tags.

type AddCommentRequest

type AddCommentRequest struct {
	Content string `json:"content" validate:"required,min=1,max=10000"`
}

AddCommentRequest represents the request to add a comment.

type AddGroupMemberRequest

type AddGroupMemberRequest struct {
	UserID string `json:"user_id" validate:"required,uuid"`
	Role   string `json:"role" validate:"required,oneof=owner lead member"`
}

AddGroupMemberRequest represents the request to add a member to a group.

type AddMemberRequest

type AddMemberRequest struct {
	UserID string `json:"user_id" validate:"required"`
	Role   string `json:"role" validate:"required,oneof=admin member viewer"`
}

AddMemberRequest represents the request to add a member.

type AddPermissionRequest

type AddPermissionRequest struct {
	PermissionID     string `json:"permission_id" validate:"required"`
	ModificationType string `json:"modification_type" validate:"omitempty,oneof=add remove"`
}

AddPermissionRequest represents the request to add a permission to a set.

type AdminAuditHandler

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

AdminAuditHandler handles admin audit log endpoints.

func NewAdminAuditHandler

func NewAdminAuditHandler(repo *postgres.AuditLogRepository, log *logger.Logger) *AdminAuditHandler

NewAdminAuditHandler creates a new AdminAuditHandler.

func (*AdminAuditHandler) Get

Get retrieves a single audit log. @Summary Get audit log @Description Returns a single audit log by ID. Requires Admin API Key. @Tags Admin Audit Logs @Accept json @Produce json @Param id path string true "Audit Log ID" @Success 200 {object} AdminAuditLogResponse @Failure 401 {object} apierror.Error "Unauthorized" @Failure 404 {object} apierror.Error "Not Found" @Failure 500 {object} apierror.Error "Internal Server Error" @Router /admin/audit-logs/{id} [get]

func (*AdminAuditHandler) GetStats

func (h *AdminAuditHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats returns audit log statistics. @Summary Get audit log statistics @Description Returns statistics about audit logs (total, failed actions). Requires Admin API Key. @Tags Admin Audit Logs @Accept json @Produce json @Success 200 {object} map[string]interface{} @Failure 401 {object} apierror.Error "Unauthorized" @Failure 500 {object} apierror.Error "Internal Server Error" @Router /admin/audit-logs/stats [get]

func (*AdminAuditHandler) List

List lists audit logs with filtering and pagination. @Summary List admin audit logs @Description Returns a paginated list of audit logs. Requires Admin API Key. @Tags Admin Audit Logs @Accept json @Produce json @Param page query int false "Page number" @Param per_page query int false "Items per page" @Param admin_email query string false "Filter by admin email" @Param action query string false "Filter by action" @Param resource_type query string false "Filter by resource type" @Param search query string false "Search term" @Param admin_id query string false "Filter by admin ID" @Param resource_id query string false "Filter by resource ID" @Param success query boolean false "Filter by success status" @Param from query string false "Start time (RFC3339)" @Param to query string false "End time (RFC3339)" @Success 200 {object} AdminAuditLogListResponse @Failure 401 {object} apierror.Error "Unauthorized" @Failure 500 {object} apierror.Error "Internal Server Error" @Router /admin/audit-logs [get]

type AdminAuditLogListResponse

type AdminAuditLogListResponse struct {
	Data       []AdminAuditLogResponse `json:"data"`
	Total      int64                   `json:"total"`
	Page       int                     `json:"page"`
	PerPage    int                     `json:"per_page"`
	TotalPages int                     `json:"total_pages"`
}

AdminAuditLogListResponse represents a paginated list of admin audit logs.

type AdminAuditLogResponse

type AdminAuditLogResponse struct {
	ID             string                 `json:"id"`
	AdminID        *string                `json:"admin_id,omitempty"`
	AdminEmail     string                 `json:"admin_email"`
	Action         string                 `json:"action"`
	ResourceType   string                 `json:"resource_type,omitempty"`
	ResourceID     *string                `json:"resource_id,omitempty"`
	ResourceName   string                 `json:"resource_name,omitempty"`
	RequestMethod  string                 `json:"request_method,omitempty"`
	RequestPath    string                 `json:"request_path,omitempty"`
	RequestBody    map[string]interface{} `json:"request_body,omitempty"`
	ResponseStatus int                    `json:"response_status,omitempty"`
	IPAddress      string                 `json:"ip_address,omitempty"`
	UserAgent      string                 `json:"user_agent,omitempty"`
	Success        bool                   `json:"success"`
	ErrorMessage   string                 `json:"error_message,omitempty"`
	CreatedAt      string                 `json:"created_at"`
}

AdminAuditLogResponse represents an admin audit log in API responses.

type AdminAuthHandler

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

AdminAuthHandler handles admin authentication endpoints.

func NewAdminAuthHandler

func NewAdminAuthHandler(log *logger.Logger) *AdminAuthHandler

NewAdminAuthHandler creates a new AdminAuthHandler.

func (*AdminAuthHandler) Validate

func (h *AdminAuthHandler) Validate(w http.ResponseWriter, r *http.Request)

Validate validates the admin API key and returns admin info. GET /api/v1/admin/auth/validate

The actual authentication is done by the AdminAuthMiddleware. This handler just returns the authenticated admin's information.

type AdminCreateResponse

type AdminCreateResponse struct {
	Admin  AdminResponse `json:"admin"`
	APIKey string        `json:"api_key"`
}

AdminCreateResponse includes the API key (only shown on creation).

type AdminListResponse

type AdminListResponse struct {
	Data       []AdminResponse `json:"data"`
	Total      int64           `json:"total"`
	Page       int             `json:"page"`
	PerPage    int             `json:"per_page"`
	TotalPages int             `json:"total_pages"`
}

AdminListResponse represents a paginated list of admins.

type AdminResponse

type AdminResponse struct {
	ID         string  `json:"id"`
	Email      string  `json:"email"`
	Name       string  `json:"name"`
	Role       string  `json:"role"`
	IsActive   bool    `json:"is_active"`
	LastUsedAt *string `json:"last_used_at,omitempty"`
	LastUsedIP string  `json:"last_used_ip,omitempty"`
	CreatedAt  string  `json:"created_at"`
	UpdatedAt  string  `json:"updated_at"`
}

AdminResponse represents an admin user in API responses.

type AdminRotateKeyResponse

type AdminRotateKeyResponse struct {
	APIKey string `json:"api_key"`
}

AdminRotateKeyResponse includes the new API key.

type AdminTargetMappingHandler

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

AdminTargetMappingHandler handles admin target mapping management endpoints.

func NewAdminTargetMappingHandler

func NewAdminTargetMappingHandler(repo *postgres.TargetMappingRepository, log *logger.Logger) *AdminTargetMappingHandler

NewAdminTargetMappingHandler creates a new AdminTargetMappingHandler.

func (*AdminTargetMappingHandler) Create

Create creates a new target mapping. POST /api/v1/admin/target-mappings

func (*AdminTargetMappingHandler) Delete

Delete deletes a target mapping. DELETE /api/v1/admin/target-mappings/{id}

func (*AdminTargetMappingHandler) Get

Get retrieves a single target mapping. GET /api/v1/admin/target-mappings/{id}

func (*AdminTargetMappingHandler) GetStats

GetStats returns aggregated statistics for target mappings. GET /api/v1/admin/target-mappings/stats

func (*AdminTargetMappingHandler) List

List lists all target mappings. GET /api/v1/admin/target-mappings

func (*AdminTargetMappingHandler) Update

Update updates a target mapping. PATCH /api/v1/admin/target-mappings/{id}

type AdminUserHandler

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

AdminUserHandler handles admin user management endpoints.

func NewAdminUserHandler

func NewAdminUserHandler(repo *postgres.AdminRepository, log *logger.Logger) *AdminUserHandler

NewAdminUserHandler creates a new AdminUserHandler.

func (*AdminUserHandler) Create

func (h *AdminUserHandler) Create(w http.ResponseWriter, r *http.Request)

Create creates a new admin user. POST /api/v1/admin/admins

func (*AdminUserHandler) Delete

func (h *AdminUserHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete deletes an admin user. DELETE /api/v1/admin/admins/{id}

func (*AdminUserHandler) Get

Get retrieves a single admin user. GET /api/v1/admin/admins/{id}

func (*AdminUserHandler) List

List lists all admin users. GET /api/v1/admin/admins

func (*AdminUserHandler) RotateKey

func (h *AdminUserHandler) RotateKey(w http.ResponseWriter, r *http.Request)

RotateKey rotates an admin's API key. POST /api/v1/admin/admins/{id}/rotate-key

func (*AdminUserHandler) Update

func (h *AdminUserHandler) Update(w http.ResponseWriter, r *http.Request)

Update updates an admin user. PATCH /api/v1/admin/admins/{id}

type AffectedVersionResponse

type AffectedVersionResponse struct {
	Ecosystem  string `json:"ecosystem"`
	Package    string `json:"package"`
	Introduced string `json:"introduced,omitempty"`
	Fixed      string `json:"fixed,omitempty"`
}

AffectedVersionResponse represents an affected version in API responses.

type AgentConfigTemplatesResponse added in v0.1.5

type AgentConfigTemplatesResponse struct {
	YAML   string `json:"yaml"`
	Env    string `json:"env"`
	Docker string `json:"docker"`
	CLI    string `json:"cli"`
}

AgentConfigTemplatesResponse holds the rendered agent config templates.

type AgentDisableRequest

type AgentDisableRequest struct {
	Reason string `json:"reason" validate:"max=500"`
}

AgentDisableRequest represents the request body for disabling an agent.

type AgentHandler

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

AgentHandler handles HTTP requests for agents.

func NewAgentHandler

func NewAgentHandler(service *app.AgentService, v *validator.Validator, log *logger.Logger) *AgentHandler

NewAgentHandler creates a new AgentHandler.

func (*AgentHandler) Activate

func (h *AgentHandler) Activate(w http.ResponseWriter, r *http.Request)

Activate handles POST /api/v1/agents/{id}/activate @Summary Activate agent @Description Activate an agent (admin action). Allows the agent to authenticate. @Tags Agents @Accept json @Produce json @Param id path string true "Agent ID" @Success 200 {object} AgentResponse @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /agents/{id}/activate [post]

func (*AgentHandler) Create

func (h *AgentHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/agents @Summary Create agent @Description Create a new agent and receive its API key @Tags Agents @Accept json @Produce json @Param body body CreateAgentRequest true "Agent data" @Success 201 {object} CreateAgentResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /agents [post]

func (*AgentHandler) Delete

func (h *AgentHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/agents/{id} @Summary Delete agent @Description Delete an agent and revoke its API key @Tags Agents @Accept json @Produce json @Param id path string true "Agent ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /agents/{id} [delete]

func (*AgentHandler) Disable

func (h *AgentHandler) Disable(w http.ResponseWriter, r *http.Request)

Disable handles POST /api/v1/agents/{id}/disable @Summary Disable agent @Description Disable an agent (admin action). Prevents the agent from authenticating. @Tags Agents @Accept json @Produce json @Param id path string true "Agent ID" @Param body body AgentDisableRequest false "Disable reason" @Success 200 {object} AgentResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /agents/{id}/disable [post]

func (*AgentHandler) Get

Get handles GET /api/v1/agents/{id} @Summary Get agent @Description Get a single agent by ID @Tags Agents @Accept json @Produce json @Param id path string true "Agent ID" @Success 200 {object} AgentResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /agents/{id} [get]

func (*AgentHandler) GetAvailableCapabilities

func (h *AgentHandler) GetAvailableCapabilities(w http.ResponseWriter, r *http.Request)

GetAvailableCapabilities returns all capabilities available to the current tenant. GET /api/v1/agents/available-capabilities @Summary Get available capabilities @Description Returns all unique capability names from all agents accessible to the tenant @Tags agents @Produce json @Success 200 {object} AvailableCapabilitiesResponse @Failure 401 {object} apierror.Error "Unauthorized" @Failure 500 {object} apierror.Error "Internal server error" @Router /api/v1/agents/available-capabilities [get]

func (*AgentHandler) GetConfigTemplates added in v0.1.5

func (h *AgentHandler) GetConfigTemplates(w http.ResponseWriter, r *http.Request)

GetConfigTemplates handles GET /api/v1/agents/{id}/config-templates Returns rendered configuration templates (YAML, env, Docker, CLI) for an agent. Templates are loaded from configs/agent-templates/*.tmpl on the API host and can be edited without rebuilding the frontend.

@Summary Get agent configuration templates @Description Returns rendered config templates for an agent in multiple formats @Tags Agents @Produce json @Param id path string true "Agent ID" @Param X-Agent-API-Key header string false "Optional API key to embed in templates (only available right after creation/regeneration). MUST be sent as header, not query parameter." @Success 200 {object} AgentConfigTemplatesResponse @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Failure 503 {object} apierror.Error "Template service not configured" @Security BearerAuth @Router /agents/{id}/config-templates [get]

func (*AgentHandler) GetStats added in v0.1.5

func (h *AgentHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats handles GET /api/v1/agents/stats @Summary Get tenant agent statistics @Description Returns aggregated stats for the tenant's agents (status, health, type, mode breakdowns) @Tags Agents @Produce json @Security BearerAuth @Success 200 {object} AgentStatsResponse @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /agents/stats [get]

func (*AgentHandler) List

func (h *AgentHandler) List(w http.ResponseWriter, r *http.Request)

List handles GET /api/v1/agents @Summary List agents @Description Get a paginated list of agents for the current tenant @Tags Agents @Accept json @Produce json @Param type query string false "Filter by type (runner, worker, collector, sensor)" @Param status query string false "Filter by admin-controlled status (active, disabled, revoked)" @Param health query string false "Filter by automatic health (unknown, online, offline, error)" @Param execution_mode query string false "Filter by execution mode (standalone, daemon)" @Param capabilities query string false "Filter by capabilities (comma-separated)" @Param tools query string false "Filter by tools (comma-separated)" @Param has_capacity query bool false "Filter by agents with available capacity" @Param search query string false "Search by name or description" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[AgentResponse] @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /agents [get]

func (*AgentHandler) RegenerateAPIKey

func (h *AgentHandler) RegenerateAPIKey(w http.ResponseWriter, r *http.Request)

RegenerateAPIKey handles POST /api/v1/agents/{id}/regenerate-key @Summary Regenerate API key @Description Regenerate the API key for an agent. The old key will be invalidated. @Tags Agents @Accept json @Produce json @Param id path string true "Agent ID" @Success 200 {object} AgentRegenerateAPIKeyResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /agents/{id}/regenerate-key [post]

func (*AgentHandler) Revoke

func (h *AgentHandler) Revoke(w http.ResponseWriter, r *http.Request)

Revoke handles POST /api/v1/agents/{id}/revoke @Summary Revoke agent @Description Permanently revoke an agent's access (admin action). Cannot be undone. @Tags Agents @Accept json @Produce json @Param id path string true "Agent ID" @Param body body AgentRevokeRequest false "Revoke reason" @Success 200 {object} AgentResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /agents/{id}/revoke [post]

func (*AgentHandler) SetPublicAPIURL added in v0.1.5

func (h *AgentHandler) SetPublicAPIURL(url string)

SetPublicAPIURL sets the public URL that agent configs will reference.

func (*AgentHandler) SetTemplateService added in v0.1.5

func (h *AgentHandler) SetTemplateService(svc *app.AgentConfigTemplateService)

SetTemplateService injects the agent config template service. Optional dependency — if nil, the config template endpoint returns 503.

func (*AgentHandler) Update

func (h *AgentHandler) Update(w http.ResponseWriter, r *http.Request)

Update handles PUT /api/v1/agents/{id} @Summary Update agent @Description Update an existing agent @Tags Agents @Accept json @Produce json @Param id path string true "Agent ID" @Param body body UpdateAgentRequest true "Update data" @Success 200 {object} AgentResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /agents/{id} [put]

type AgentRegenerateAPIKeyResponse

type AgentRegenerateAPIKeyResponse struct {
	APIKey string `json:"api_key"`
}

AgentRegenerateAPIKeyResponse represents the response for regenerating an API key.

type AgentResponse

type AgentResponse struct {
	ID            string         `json:"id"`
	TenantID      string         `json:"tenant_id"`
	Name          string         `json:"name"`
	Type          string         `json:"type"`
	Description   string         `json:"description,omitempty"`
	Capabilities  []string       `json:"capabilities"`
	Tools         []string       `json:"tools"`
	ExecutionMode string         `json:"execution_mode"`
	Status        string         `json:"status"` // Admin-controlled: active, disabled, revoked
	Health        string         `json:"health"` // Automatic: unknown, online, offline, error
	StatusMessage string         `json:"status_message,omitempty"`
	APIKeyPrefix  string         `json:"api_key_prefix,omitempty"`
	Labels        map[string]any `json:"labels,omitempty"`
	Version       string         `json:"version,omitempty"`
	Hostname      string         `json:"hostname,omitempty"`
	IPAddress     string         `json:"ip_address,omitempty"`
	// System metrics
	CPUPercent    float64 `json:"cpu_percent"`
	MemoryPercent float64 `json:"memory_percent"`
	Region        string  `json:"region,omitempty"`
	// Load balancing
	MaxConcurrentJobs int     `json:"max_concurrent_jobs"`
	CurrentJobs       int     `json:"current_jobs"`
	AvailableSlots    int     `json:"available_slots"`
	LoadFactor        float64 `json:"load_factor"` // 0.0 to 1.0
	// Statistics
	LastSeenAt    *string `json:"last_seen_at,omitempty"`
	TotalFindings int64   `json:"total_findings"`
	TotalScans    int64   `json:"total_scans"`
	ErrorCount    int64   `json:"error_count"`
	CreatedAt     string  `json:"created_at"`
	UpdatedAt     string  `json:"updated_at"`
}

AgentResponse represents the response for an agent.

type AgentRevokeRequest

type AgentRevokeRequest struct {
	Reason string `json:"reason" validate:"max=500"`
}

AgentRevokeRequest represents the request body for revoking an agent.

type AgentStatsResponse added in v0.1.5

type AgentStatsResponse struct {
	Total           int            `json:"total"`
	ByStatus        map[string]int `json:"by_status"`
	ByHealth        map[string]int `json:"by_health"`
	ByType          map[string]int `json:"by_type"`
	ByExecutionMode map[string]int `json:"by_execution_mode"`
	ActiveJobs      int            `json:"active_jobs"`
	OnlineActive    int            `json:"online_active"`
}

AgentStatsResponse mirrors agent.TenantAgentStats with snake_case JSON.

type ApprovalResponse added in v0.1.2

type ApprovalResponse struct {
	ID              string  `json:"id"`
	TenantID        string  `json:"tenant_id"`
	FindingID       string  `json:"finding_id"`
	RequestedStatus string  `json:"requested_status"`
	RequestedBy     string  `json:"requested_by"`
	Justification   string  `json:"justification"`
	ApprovedBy      *string `json:"approved_by,omitempty"`
	ApprovedAt      *string `json:"approved_at,omitempty"`
	RejectedBy      *string `json:"rejected_by,omitempty"`
	RejectedAt      *string `json:"rejected_at,omitempty"`
	RejectionReason string  `json:"rejection_reason,omitempty"`
	Status          string  `json:"status"`
	ExpiresAt       *string `json:"expires_at,omitempty"`
	CreatedAt       string  `json:"created_at"`
}

ApprovalResponse represents an approval in API responses.

type ApproveRuleRequest

type ApproveRuleRequest struct{}

ApproveRuleRequest represents a request to approve a rule.

type AssetBriefResponse added in v0.1.2

type AssetBriefResponse struct {
	ID     string `json:"id"`
	Name   string `json:"name"`
	Type   string `json:"type"`
	Status string `json:"status"`
}

AssetBriefResponse represents minimal asset info embedded in ownership responses.

type AssetBulkStatusRequest

type AssetBulkStatusRequest struct {
	AssetIDs []string `json:"asset_ids" validate:"required,min=1,max=100,dive,uuid"`
	Status   string   `json:"status" validate:"required,oneof=active inactive archived"`
}

AssetBulkStatusRequest represents a bulk asset status update request.

type AssetBulkStatusResponse

type AssetBulkStatusResponse struct {
	Updated int      `json:"updated"`
	Failed  int      `json:"failed"`
	Errors  []string `json:"errors,omitempty"`
}

AssetBulkStatusResponse represents a bulk asset status update response.

type AssetChangeResponse

type AssetChangeResponse struct {
	Type      string `json:"type" example:"added"`
	AssetName string `json:"asset_name" example:"new-api.example.com"`
	AssetType string `json:"asset_type" example:"service"`
	Timestamp string `json:"timestamp" example:"2024-01-15T10:30:00Z"`
}

AssetChangeResponse represents a recent asset change.

type AssetCompatibilityPreviewResponse

type AssetCompatibilityPreviewResponse struct {
	IsFullyCompatible    bool     `json:"is_fully_compatible"`
	CompatibilityPercent float64  `json:"compatibility_percent"`
	CompatibleCount      int      `json:"compatible_count"`
	IncompatibleCount    int      `json:"incompatible_count"`
	UnclassifiedCount    int      `json:"unclassified_count"`
	TotalCount           int      `json:"total_count"`
	CompatibleTypes      []string `json:"compatible_types,omitempty"`
	IncompatibleTypes    []string `json:"incompatible_types,omitempty"`
	Message              string   `json:"message"`
}

AssetCompatibilityPreviewResponse represents asset-scanner compatibility info.

type AssetGroupHandler

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

AssetGroupHandler handles asset group HTTP requests.

func NewAssetGroupHandler

func NewAssetGroupHandler(svc *app.AssetGroupService, v *validator.Validator, log *logger.Logger) *AssetGroupHandler

NewAssetGroupHandler creates a new asset group handler.

func (*AssetGroupHandler) AddAssets

func (h *AssetGroupHandler) AddAssets(w http.ResponseWriter, r *http.Request)

AddAssets handles POST /api/v1/asset-groups/{id}/assets @Summary Add assets to group @Description Add one or more assets to an asset group @Tags Asset Groups @Accept json @Produce json @Param id path string true "Asset Group ID" @Param body body AddAssetsRequest true "Asset IDs to add" @Success 200 {object} AssetGroupResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/{id}/assets [post]

func (*AssetGroupHandler) BulkDelete

func (h *AssetGroupHandler) BulkDelete(w http.ResponseWriter, r *http.Request)

BulkDelete handles POST /api/v1/asset-groups/bulk/delete @Summary Bulk delete asset groups @Description Delete multiple asset groups at once @Tags Asset Groups @Accept json @Produce json @Param body body BulkDeleteRequest true "Bulk delete data" @Success 200 {object} map[string]interface{} @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/bulk/delete [post]

func (*AssetGroupHandler) BulkUpdate

func (h *AssetGroupHandler) BulkUpdate(w http.ResponseWriter, r *http.Request)

BulkUpdate handles PATCH /api/v1/asset-groups/bulk @Summary Bulk update asset groups @Description Update multiple asset groups at once @Tags Asset Groups @Accept json @Produce json @Param body body BulkUpdateRequest true "Bulk update data" @Success 200 {object} map[string]interface{} @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/bulk [patch]

func (*AssetGroupHandler) Create

Create handles POST /api/v1/asset-groups @Summary Create asset group @Description Create a new asset group @Tags Asset Groups @Accept json @Produce json @Param body body CreateAssetGroupRequest true "Asset group data" @Success 201 {object} AssetGroupResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups [post]

func (*AssetGroupHandler) Delete

Delete handles DELETE /api/v1/asset-groups/{id} @Summary Delete asset group @Description Delete an asset group @Tags Asset Groups @Accept json @Produce json @Param id path string true "Asset Group ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/{id} [delete]

func (*AssetGroupHandler) Get

Get handles GET /api/v1/asset-groups/{id} @Summary Get asset group @Description Get a single asset group by ID @Tags Asset Groups @Accept json @Produce json @Param id path string true "Asset Group ID" @Success 200 {object} AssetGroupResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/{id} [get]

func (*AssetGroupHandler) GetAssets

func (h *AssetGroupHandler) GetAssets(w http.ResponseWriter, r *http.Request)

GetAssets handles GET /api/v1/asset-groups/{id}/assets @Summary Get assets in group @Description Get a paginated list of assets belonging to the group @Tags Asset Groups @Accept json @Produce json @Param id path string true "Asset Group ID" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[GroupAssetResponse] @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/{id}/assets [get]

func (*AssetGroupHandler) GetFindings

func (h *AssetGroupHandler) GetFindings(w http.ResponseWriter, r *http.Request)

GetFindings handles GET /api/v1/asset-groups/{id}/findings @Summary Get findings in group @Description Get a paginated list of findings from assets in the group @Tags Asset Groups @Accept json @Produce json @Param id path string true "Asset Group ID" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[GroupFindingResponse] @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/{id}/findings [get]

func (*AssetGroupHandler) GetStats

func (h *AssetGroupHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats handles GET /api/v1/asset-groups/stats @Summary Get asset group statistics @Description Get aggregated statistics for asset groups @Tags Asset Groups @Accept json @Produce json @Success 200 {object} AssetGroupStatsResponse @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/stats [get]

func (*AssetGroupHandler) List

List handles GET /api/v1/asset-groups @Summary List asset groups @Description Get a paginated list of asset groups for the current tenant @Tags Asset Groups @Accept json @Produce json @Param search query string false "Search by name" @Param environments query string false "Filter by environments (comma-separated)" @Param criticalities query string false "Filter by criticalities (comma-separated)" @Param business_unit query string false "Filter by business unit" @Param owner query string false "Filter by owner" @Param tags query string false "Filter by tags (comma-separated)" @Param has_findings query bool false "Filter groups with findings" @Param min_risk_score query int false "Minimum risk score" @Param max_risk_score query int false "Maximum risk score" @Param sort query string false "Sort field (name, created_at, risk_score)" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[AssetGroupResponse] @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups [get]

func (*AssetGroupHandler) RemoveAssets

func (h *AssetGroupHandler) RemoveAssets(w http.ResponseWriter, r *http.Request)

RemoveAssets handles POST /api/v1/asset-groups/{id}/assets/remove @Summary Remove assets from group @Description Remove one or more assets from an asset group @Tags Asset Groups @Accept json @Produce json @Param id path string true "Asset Group ID" @Param body body RemoveAssetsRequest true "Asset IDs to remove" @Success 200 {object} AssetGroupResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/{id}/assets/remove [post]

func (*AssetGroupHandler) Update

Update handles PATCH /api/v1/asset-groups/{id} @Summary Update asset group @Description Update an existing asset group @Tags Asset Groups @Accept json @Produce json @Param id path string true "Asset Group ID" @Param body body UpdateAssetGroupRequest true "Update data" @Success 200 {object} AssetGroupResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /asset-groups/{id} [patch]

type AssetGroupResponse

type AssetGroupResponse struct {
	ID              string    `json:"id"`
	Name            string    `json:"name"`
	Description     string    `json:"description,omitempty"`
	Environment     string    `json:"environment"`
	Criticality     string    `json:"criticality"`
	BusinessUnit    string    `json:"business_unit,omitempty"`
	Owner           string    `json:"owner,omitempty"`
	OwnerEmail      string    `json:"owner_email,omitempty"`
	Tags            []string  `json:"tags,omitempty"`
	AssetCount      int       `json:"asset_count"`
	DomainCount     int       `json:"domain_count"`
	WebsiteCount    int       `json:"website_count"`
	ServiceCount    int       `json:"service_count"`
	RepositoryCount int       `json:"repository_count"`
	CloudCount      int       `json:"cloud_count"`
	CredentialCount int       `json:"credential_count"`
	RiskScore       int       `json:"risk_score"`
	FindingCount    int       `json:"finding_count"`
	CreatedAt       time.Time `json:"created_at"`
	UpdatedAt       time.Time `json:"updated_at"`
}

AssetGroupResponse represents an asset group in API responses.

type AssetGroupStatsResponse

type AssetGroupStatsResponse struct {
	Total            int64            `json:"total"`
	ByEnvironment    map[string]int64 `json:"by_environment"`
	ByCriticality    map[string]int64 `json:"by_criticality"`
	TotalAssets      int64            `json:"total_assets"`
	TotalFindings    int64            `json:"total_findings"`
	AverageRiskScore float64          `json:"average_risk_score"`
}

AssetGroupStatsResponse represents stats response.

type AssetHandler

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

AssetHandler handles asset-related HTTP requests.

func NewAssetHandler

func NewAssetHandler(svc *app.AssetService, v *validator.Validator, log *logger.Logger) *AssetHandler

NewAssetHandler creates a new asset handler.

func (*AssetHandler) Activate

func (h *AssetHandler) Activate(w http.ResponseWriter, r *http.Request)

Activate handles POST /api/v1/assets/{id}/activate @Summary Activate asset @Description Activates an asset @Tags Assets @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Success 200 {object} AssetResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id}/activate [post]

func (*AssetHandler) Archive

func (h *AssetHandler) Archive(w http.ResponseWriter, r *http.Request)

Archive handles POST /api/v1/assets/{id}/archive @Summary Archive asset @Description Archives an asset @Tags Assets @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Success 200 {object} AssetResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id}/archive [post]

func (*AssetHandler) BulkSync

func (h *AssetHandler) BulkSync(w http.ResponseWriter, r *http.Request)

BulkSync handles POST /api/v1/assets/bulk-sync @Summary Bulk sync repositories @Description Syncs multiple repository assets from their SCM providers in a single request @Tags Assets @Accept json @Produce json @Security BearerAuth @Param request body BulkSyncRequest true "Asset IDs to sync" @Success 200 {object} BulkSyncResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/bulk-sync [post]

func (*AssetHandler) BulkUpdateStatus

func (h *AssetHandler) BulkUpdateStatus(w http.ResponseWriter, r *http.Request)

BulkUpdateStatus handles POST /api/v1/assets/bulk/status @Summary Bulk update asset status @Description Updates the status of multiple assets at once @Tags Assets @Accept json @Produce json @Security BearerAuth @Param request body AssetBulkStatusRequest true "Bulk update data" @Success 200 {object} AssetBulkStatusResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/bulk/status [post]

func (*AssetHandler) Create

func (h *AssetHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/assets @Summary Create asset @Description Creates a new asset for the current tenant @Tags Assets @Accept json @Produce json @Security BearerAuth @Param request body CreateAssetRequest true "Asset data" @Success 201 {object} AssetResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 409 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets [post]

func (*AssetHandler) CreateRepository

func (h *AssetHandler) CreateRepository(w http.ResponseWriter, r *http.Request)

CreateRepository handles POST /api/v1/assets/repository @Summary Create repository asset @Description Creates a new repository asset with its extension data @Tags Assets @Accept json @Produce json @Security BearerAuth @Param request body CreateRepositoryAssetRequest true "Repository asset data" @Success 201 {object} AssetWithRepositoryResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 409 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/repository [post]

func (*AssetHandler) Deactivate

func (h *AssetHandler) Deactivate(w http.ResponseWriter, r *http.Request)

Deactivate handles POST /api/v1/assets/{id}/deactivate @Summary Deactivate asset @Description Deactivates an asset @Tags Assets @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Success 200 {object} AssetResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id}/deactivate [post]

func (*AssetHandler) Delete

func (h *AssetHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/assets/{id} @Summary Delete asset @Description Deletes an asset by ID @Tags Assets @Security BearerAuth @Param id path string true "Asset ID" @Success 204 "No Content" @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id} [delete]

func (*AssetHandler) Get

Get handles GET /api/v1/assets/{id} @Summary Get asset @Description Retrieves an asset by ID @Tags Assets @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Success 200 {object} AssetResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id} [get]

func (*AssetHandler) GetRepository

func (h *AssetHandler) GetRepository(w http.ResponseWriter, r *http.Request)

GetRepository handles GET /api/v1/assets/{id}/repository @Summary Get repository extension @Description Retrieves the repository extension for an asset @Tags Assets @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Success 200 {object} RepositoryExtensionResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id}/repository [get]

func (*AssetHandler) GetStats

func (h *AssetHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats handles GET /api/v1/assets/stats @Summary Get asset statistics @Description Returns aggregated statistics for assets @Tags Assets @Produce json @Security BearerAuth @Param types query string false "Filter by types (comma-separated)" @Param tags query string false "Filter by tags (comma-separated, overlap)" @Success 200 {object} AssetStatsResponse @Failure 401 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/stats [get]

func (*AssetHandler) GetWithRepository

func (h *AssetHandler) GetWithRepository(w http.ResponseWriter, r *http.Request)

GetWithRepository handles GET /api/v1/assets/{id}/full @Summary Get asset with repository @Description Retrieves an asset with its repository extension (if applicable) @Tags Assets @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Success 200 {object} AssetWithRepositoryResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id}/full [get]

func (*AssetHandler) List

func (h *AssetHandler) List(w http.ResponseWriter, r *http.Request)

List handles GET /api/v1/assets @Summary List assets @Description Retrieves a paginated list of assets for the current tenant @Tags Assets @Accept json @Produce json @Security BearerAuth @Param name query string false "Filter by name (partial match)" @Param types query string false "Filter by types (comma-separated)" @Param criticalities query string false "Filter by criticalities (comma-separated)" @Param statuses query string false "Filter by statuses (comma-separated)" @Param scopes query string false "Filter by scopes (comma-separated)" @Param exposures query string false "Filter by exposures (comma-separated)" @Param tags query string false "Filter by tags (comma-separated)" @Param search query string false "Full-text search across name and description" @Param min_risk_score query int false "Minimum risk score (0-100)" @Param max_risk_score query int false "Maximum risk score (0-100)" @Param has_findings query bool false "Filter by whether asset has findings" @Param sort query string false "Sort field (e.g., -created_at, name, -risk_score)" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) maximum(100) @Success 200 {object} map[string]interface{} @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets [get]

func (*AssetHandler) ListTags added in v0.1.2

func (h *AssetHandler) ListTags(w http.ResponseWriter, r *http.Request)

ListTags returns distinct tags across all assets for the tenant. Supports prefix filtering for autocomplete via ?prefix= query parameter.

func (*AssetHandler) SetAccessControlRepo added in v0.1.2

func (h *AssetHandler) SetAccessControlRepo(repo accesscontrol.Repository)

SetAccessControlRepo sets the access control repository for owner resolution.

func (*AssetHandler) SetIntegrationService

func (h *AssetHandler) SetIntegrationService(svc *app.IntegrationService)

SetIntegrationService sets the integration service for sync operations.

func (*AssetHandler) Sync

func (h *AssetHandler) Sync(w http.ResponseWriter, r *http.Request)

Sync handles POST /api/v1/assets/{id}/sync @Summary Sync repository from SCM @Description Syncs repository metadata from the connected SCM provider @Tags Assets @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Success 200 {object} SyncResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id}/sync [post]

func (*AssetHandler) TriggerScan

func (h *AssetHandler) TriggerScan(w http.ResponseWriter, r *http.Request)

TriggerScan handles POST /api/v1/assets/{id}/scan @Summary Trigger security scan @Description Triggers a security scan for the repository asset @Tags Assets @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Success 202 {object} ScanResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id}/scan [post]

func (*AssetHandler) Update

func (h *AssetHandler) Update(w http.ResponseWriter, r *http.Request)

Update handles PUT /api/v1/assets/{id} @Summary Update asset @Description Updates an existing asset @Tags Assets @Accept json @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Param request body UpdateAssetRequest true "Asset data" @Success 200 {object} AssetResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id} [put]

func (*AssetHandler) UpdateRepository

func (h *AssetHandler) UpdateRepository(w http.ResponseWriter, r *http.Request)

UpdateRepository handles PUT /api/v1/assets/{id}/repository @Summary Update repository extension @Description Updates the repository extension for an asset @Tags Assets @Accept json @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Param request body UpdateRepositoryExtensionRequest true "Repository extension data" @Success 200 {object} RepositoryExtensionResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Failure 500 {object} map[string]string @Router /assets/{id}/repository [put]

type AssetOwnerHandler added in v0.1.2

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

AssetOwnerHandler handles asset ownership HTTP requests.

func NewAssetOwnerHandler added in v0.1.2

func NewAssetOwnerHandler(
	repo accesscontrol.Repository,
	assetRepo asset.Repository,
	log *logger.Logger,
) *AssetOwnerHandler

NewAssetOwnerHandler creates a new asset owner handler.

assetRepo is required for the per-request tenant check on AddOwner / UpdateOwner / RemoveOwner — without it a user with assets:write in tenant A could craft a request for an asset in tenant B because asset_owners is not directly tenant-scoped.

func (*AssetOwnerHandler) AddOwner added in v0.1.2

func (h *AssetOwnerHandler) AddOwner(w http.ResponseWriter, r *http.Request)

AddOwner handles POST /api/v1/assets/{id}/owners

func (*AssetOwnerHandler) ListOwners added in v0.1.2

func (h *AssetOwnerHandler) ListOwners(w http.ResponseWriter, r *http.Request)

ListOwners handles GET /api/v1/assets/{id}/owners

func (*AssetOwnerHandler) RemoveOwner added in v0.1.2

func (h *AssetOwnerHandler) RemoveOwner(w http.ResponseWriter, r *http.Request)

RemoveOwner handles DELETE /api/v1/assets/{id}/owners/{ownerID}

func (*AssetOwnerHandler) UpdateOwner added in v0.1.2

func (h *AssetOwnerHandler) UpdateOwner(w http.ResponseWriter, r *http.Request)

UpdateOwner handles PUT /api/v1/assets/{id}/owners/{ownerID}

type AssetOwnerResponse

type AssetOwnerResponse struct {
	ID             string    `json:"id"`
	UserID         *string   `json:"user_id,omitempty"`
	UserName       *string   `json:"user_name,omitempty"`
	UserEmail      *string   `json:"user_email,omitempty"`
	GroupID        *string   `json:"group_id,omitempty"`
	GroupName      *string   `json:"group_name,omitempty"`
	OwnershipType  string    `json:"ownership_type"`
	AssignedAt     time.Time `json:"assigned_at"`
	AssignedByName *string   `json:"assigned_by_name,omitempty"`
}

AssetOwnerResponse represents an asset owner in API responses.

type AssetRelationshipHandler

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

AssetRelationshipHandler handles asset relationship HTTP requests.

func NewAssetRelationshipHandler

func NewAssetRelationshipHandler(svc *app.AssetRelationshipService, v *validator.Validator, log *logger.Logger) *AssetRelationshipHandler

NewAssetRelationshipHandler creates a new AssetRelationshipHandler.

func (*AssetRelationshipHandler) BatchCreate added in v0.1.5

BatchCreate handles POST /api/v1/assets/{id}/relationships/batch

Bulk-creates relationships from one source asset to many targets. The source asset is taken from the URL path and validated ONCE for the whole batch (rather than once per item like the singleton path), which is why this endpoint exists. Per-item failures (invalid type, target not found, duplicate) do NOT abort the batch — every item gets a result entry with its own status, mirroring frontend Promise.allSettled semantics.

Always returns 200 with a results array, even if every item failed. The caller decides what to do based on per-item statuses.

func (*AssetRelationshipHandler) Create

Create handles POST /api/v1/assets/{id}/relationships

func (*AssetRelationshipHandler) Delete

Delete handles DELETE /api/v1/relationships/{relationshipId}

func (*AssetRelationshipHandler) Get

Get handles GET /api/v1/relationships/{relationshipId}

func (*AssetRelationshipHandler) ListByAsset

ListByAsset handles GET /api/v1/assets/{id}/relationships

func (*AssetRelationshipHandler) Update

Update handles PUT /api/v1/relationships/{relationshipId}

func (*AssetRelationshipHandler) UsageStats added in v0.1.5

UsageStats handles GET /api/v1/relationships/usage-stats

Returns the per-type usage count for every relationship type in the registry, joined with each type's display metadata. Used by tenant admins to see which types are actually being used and prune the registry based on real data instead of guesses. Types with count=0 are returned (so the response is "every type in the registry, with its count").

type AssetResponse

type AssetResponse struct {
	ID                    string                   `json:"id"`
	TenantID              string                   `json:"tenant_id,omitempty"`
	ParentID              string                   `json:"parent_id,omitempty"`
	OwnerRef              string                   `json:"owner_ref,omitempty"`
	Name                  string                   `json:"name"`
	Type                  string                   `json:"type"`
	Provider              string                   `json:"provider,omitempty"`
	ExternalID            string                   `json:"external_id,omitempty"`
	Criticality           string                   `json:"criticality"`
	Status                string                   `json:"status"`
	Scope                 string                   `json:"scope"`
	Exposure              string                   `json:"exposure"`
	RiskScore             int                      `json:"risk_score"`
	FindingCount          int                      `json:"finding_count"`
	FindingSeverityCounts *FindingSeverityResponse `json:"finding_severity_counts,omitempty"`
	Description           string                   `json:"description,omitempty"`
	Tags                  []string                 `json:"tags,omitempty"`
	Metadata              map[string]any           `json:"metadata,omitempty"`
	Properties            map[string]any           `json:"properties,omitempty"`
	PrimaryOwner          *OwnerBriefResponse      `json:"primary_owner,omitempty"`

	// Discovery
	DiscoverySource string     `json:"discovery_source,omitempty"`
	DiscoveryTool   string     `json:"discovery_tool,omitempty"`
	DiscoveredAt    *time.Time `json:"discovered_at,omitempty"`

	// CTEM
	ComplianceScope      []string `json:"compliance_scope,omitempty"`
	DataClassification   string   `json:"data_classification,omitempty"`
	PIIDataExposed       bool     `json:"pii_data_exposed"`
	PHIDataExposed       bool     `json:"phi_data_exposed"`
	IsInternetAccessible bool     `json:"is_internet_accessible"`

	// Sync
	SyncStatus   string     `json:"sync_status,omitempty"`
	LastSyncedAt *time.Time `json:"last_synced_at,omitempty"`

	// Timestamps
	FirstSeen time.Time `json:"first_seen"`
	LastSeen  time.Time `json:"last_seen"`
	CreatedAt time.Time `json:"created_at"`
	UpdatedAt time.Time `json:"updated_at"`
}

AssetResponse represents an asset in API responses.

type AssetServiceHandler

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

AssetServiceHandler handles asset service-related HTTP requests.

func NewAssetServiceHandler

func NewAssetServiceHandler(repo asset.AssetServiceRepository, assetRepo asset.Repository, v *validator.Validator, log *logger.Logger) *AssetServiceHandler

NewAssetServiceHandler creates a new asset service handler.

func (*AssetServiceHandler) Create

Create handles POST /api/v1/assets/{id}/services @Summary Create a service for an asset @Description Creates a new service entry for a specific asset (e.g., discovered port/protocol) @Tags Asset Services @Accept json @Produce json @Security BearerAuth @Param id path string true "Asset ID (UUID)" @Param body body CreateAssetServiceRequest true "Service details" @Success 201 {object} AssetServiceResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 409 {object} apierror.Error "Service already exists for this port" @Failure 500 {object} apierror.Error @Router /assets/{id}/services [post]

func (*AssetServiceHandler) Delete

Delete handles DELETE /api/v1/services/{id} @Summary Delete a service @Description Permanently removes a service entry @Tags Asset Services @Accept json @Produce json @Security BearerAuth @Param id path string true "Service ID (UUID)" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /services/{id} [delete]

func (*AssetServiceHandler) Get

Get handles GET /api/v1/services/{id} @Summary Get a service by ID @Description Retrieves a specific service by its unique identifier @Tags Asset Services @Accept json @Produce json @Security BearerAuth @Param id path string true "Service ID (UUID)" @Success 200 {object} AssetServiceResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /services/{id} [get]

func (*AssetServiceHandler) List

List handles GET /api/v1/services @Summary List all services @Description Retrieves a paginated list of all services for the tenant with optional filtering @Tags Asset Services @Accept json @Produce json @Security BearerAuth @Param service_type query string false "Filter by service type (e.g., http, ssh, database)" @Param state query string false "Filter by state (active, inactive, filtered)" @Param is_public query boolean false "Filter by public exposure" @Param port query int false "Filter by port number" @Param product query string false "Filter by product name" @Param limit query int false "Maximum results (max 1000)" default(50) @Param offset query int false "Pagination offset" default(0) @Param sort_by query string false "Sort field" @Param sort_order query string false "Sort order (asc, desc)" @Success 200 {object} object{data=[]AssetServiceResponse,total=int,limit=int,offset=int} @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /services [get]

func (*AssetServiceHandler) ListByAsset

func (h *AssetServiceHandler) ListByAsset(w http.ResponseWriter, r *http.Request)

ListByAsset handles GET /api/v1/assets/{id}/services @Summary List services for an asset @Description Retrieves all services discovered on a specific asset @Tags Asset Services @Accept json @Produce json @Security BearerAuth @Param id path string true "Asset ID (UUID)" @Success 200 {object} object{data=[]AssetServiceResponse,total=int} @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /assets/{id}/services [get]

func (*AssetServiceHandler) ListPublic

func (h *AssetServiceHandler) ListPublic(w http.ResponseWriter, r *http.Request)

ListPublic handles GET /api/v1/services/public @Summary List public services @Description Retrieves a paginated list of publicly exposed services @Tags Asset Services @Accept json @Produce json @Security BearerAuth @Param limit query int false "Maximum results (max 1000)" default(50) @Param offset query int false "Pagination offset" default(0) @Success 200 {object} object{data=[]AssetServiceResponse,total=int,limit=int,offset=int} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /services/public [get]

func (*AssetServiceHandler) Stats

Stats handles GET /api/v1/services/stats @Summary Get service statistics @Description Retrieves aggregate statistics about services including counts by type and top ports @Tags Asset Services @Accept json @Produce json @Security BearerAuth @Success 200 {object} AssetServiceStatsResponse @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /services/stats [get]

func (*AssetServiceHandler) Update

Update handles PUT /api/v1/services/{id} @Summary Update a service @Description Updates an existing service's properties @Tags Asset Services @Accept json @Produce json @Security BearerAuth @Param id path string true "Service ID (UUID)" @Param body body UpdateAssetServiceRequest true "Updated service details" @Success 200 {object} AssetServiceResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /services/{id} [put]

type AssetServiceResponse

type AssetServiceResponse struct {
	ID              string     `json:"id"`
	TenantID        string     `json:"tenant_id,omitempty"`
	AssetID         string     `json:"asset_id"`
	Name            string     `json:"name,omitempty"`
	Protocol        string     `json:"protocol"`
	Port            int        `json:"port"`
	ServiceType     string     `json:"service_type"`
	Product         string     `json:"product,omitempty"`
	Version         string     `json:"version,omitempty"`
	Banner          string     `json:"banner,omitempty"`
	CPE             string     `json:"cpe,omitempty"`
	Technologies    []string   `json:"technologies"`
	IsPublic        bool       `json:"is_public"`
	Exposure        string     `json:"exposure"`
	TLSEnabled      bool       `json:"tls_enabled"`
	TLSVersion      string     `json:"tls_version,omitempty"`
	DiscoverySource string     `json:"discovery_source,omitempty"`
	DiscoveredAt    *time.Time `json:"discovered_at,omitempty"`
	LastSeenAt      *time.Time `json:"last_seen_at,omitempty"`
	FindingCount    int        `json:"finding_count"`
	RiskScore       int        `json:"risk_score"`
	State           string     `json:"state"`
	StateChangedAt  *time.Time `json:"state_changed_at,omitempty"`
	CreatedAt       time.Time  `json:"created_at"`
	UpdatedAt       time.Time  `json:"updated_at"`
}

AssetServiceResponse represents an asset service in API responses.

type AssetServiceStatsResponse

type AssetServiceStatsResponse struct {
	TotalServices     int64               `json:"total_services"`
	PublicServices    int64               `json:"public_services"`
	ServiceTypeCounts map[string]int      `json:"service_type_counts"`
	TopPorts          []PortCountResponse `json:"top_ports"`
}

AssetServiceStatsResponse represents service statistics.

type AssetStateHistoryHandler

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

AssetStateHistoryHandler handles asset state history-related HTTP requests.

func NewAssetStateHistoryHandler

func NewAssetStateHistoryHandler(repo asset.StateHistoryRepository, assetRepo asset.Repository, v *validator.Validator, log *logger.Logger) *AssetStateHistoryHandler

NewAssetStateHistoryHandler creates a new asset state history handler.

func (*AssetStateHistoryHandler) ComplianceChanges

func (h *AssetStateHistoryHandler) ComplianceChanges(w http.ResponseWriter, r *http.Request)

ComplianceChanges handles GET /api/v1/state-history/compliance @Summary Get compliance-related changes @Description Retrieves state changes that may affect compliance status @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param since query string false "Start time (RFC3339, default: 7 days ago)" @Param limit query int false "Maximum results (max 1000)" default(100) @Success 200 {object} object{data=[]StateChangeResponse,total=int,since=string} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history/compliance [get]

func (*AssetStateHistoryHandler) ExposureChanges

func (h *AssetStateHistoryHandler) ExposureChanges(w http.ResponseWriter, r *http.Request)

ExposureChanges handles GET /api/v1/state-history/exposure-changes @Summary Get exposure changes @Description Retrieves assets that have changed exposure status (public/private/restricted) @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param since query string false "Start time (RFC3339, default: 7 days ago)" @Param limit query int false "Maximum results (max 1000)" default(100) @Success 200 {object} object{data=[]StateChangeResponse,total=int,since=string} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history/exposure-changes [get]

func (*AssetStateHistoryHandler) Get

Get handles GET /api/v1/state-history/{id} @Summary Get state change by ID @Description Retrieves a specific state change entry by its unique identifier @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param id path string true "State change ID (UUID)" @Success 200 {object} StateChangeResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history/{id} [get]

func (*AssetStateHistoryHandler) List

List handles GET /api/v1/state-history @Summary List all state history @Description Retrieves a paginated list of all state changes for the tenant with optional filtering @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param change_type query string false "Filter by change type" @Param source query string false "Filter by source" @Param from query string false "Start time (RFC3339)" @Param to query string false "End time (RFC3339)" @Param limit query int false "Maximum results (max 1000)" default(50) @Param offset query int false "Pagination offset" default(0) @Success 200 {object} object{data=[]StateChangeResponse,total=int,limit=int,offset=int} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history [get]

func (*AssetStateHistoryHandler) ListByAsset

ListByAsset handles GET /api/v1/assets/{id}/state-history @Summary List state history for an asset @Description Retrieves all state changes for a specific asset with optional filtering @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param id path string true "Asset ID (UUID)" @Param change_type query string false "Filter by change type" @Param source query string false "Filter by source" @Param from query string false "Start time (RFC3339)" @Param to query string false "End time (RFC3339)" @Param limit query int false "Maximum results (max 1000)" default(50) @Param offset query int false "Pagination offset" default(0) @Success 200 {object} object{data=[]StateChangeResponse,total=int,limit=int,offset=int} @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /assets/{id}/state-history [get]

func (*AssetStateHistoryHandler) NewlyExposed

func (h *AssetStateHistoryHandler) NewlyExposed(w http.ResponseWriter, r *http.Request)

NewlyExposed handles GET /api/v1/state-history/newly-exposed @Summary Get newly exposed assets @Description Retrieves assets that have recently become publicly exposed @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param since query string false "Start time (RFC3339, default: 7 days ago)" @Param limit query int false "Maximum results (max 1000)" default(100) @Success 200 {object} object{data=[]StateChangeResponse,total=int,since=string} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history/newly-exposed [get]

func (*AssetStateHistoryHandler) RecentAppearances

func (h *AssetStateHistoryHandler) RecentAppearances(w http.ResponseWriter, r *http.Request)

RecentAppearances handles GET /api/v1/state-history/appearances @Summary Get recent asset appearances @Description Retrieves recently discovered assets (new assets appearing in scans) @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param since query string false "Start time (RFC3339, default: 7 days ago)" @Param limit query int false "Maximum results (max 1000)" default(100) @Success 200 {object} object{data=[]StateChangeResponse,total=int,since=string} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history/appearances [get]

func (*AssetStateHistoryHandler) RecentDisappearances

func (h *AssetStateHistoryHandler) RecentDisappearances(w http.ResponseWriter, r *http.Request)

RecentDisappearances handles GET /api/v1/state-history/disappearances @Summary Get recent asset disappearances @Description Retrieves assets that have disappeared (no longer seen in scans) @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param since query string false "Start time (RFC3339, default: 7 days ago)" @Param limit query int false "Maximum results (max 1000)" default(100) @Success 200 {object} object{data=[]StateChangeResponse,total=int,since=string} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history/disappearances [get]

func (*AssetStateHistoryHandler) ShadowITCandidates

func (h *AssetStateHistoryHandler) ShadowITCandidates(w http.ResponseWriter, r *http.Request)

ShadowITCandidates handles GET /api/v1/state-history/shadow-it @Summary Get Shadow IT candidates @Description Retrieves assets identified as potential Shadow IT (unexpected or unauthorized resources) @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param since query string false "Start time (RFC3339, default: 7 days ago)" @Param limit query int false "Maximum results (max 1000)" default(100) @Success 200 {object} object{data=[]StateChangeResponse,total=int,since=string} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history/shadow-it [get]

func (*AssetStateHistoryHandler) Stats

Stats handles GET /api/v1/state-history/stats @Summary Get state history statistics @Description Retrieves aggregate statistics about state changes by type and source @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param since query string false "Start time (RFC3339, default: 30 days ago)" @Success 200 {object} StateHistoryStatsResponse @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history/stats [get]

func (*AssetStateHistoryHandler) Timeline

Timeline handles GET /api/v1/state-history/timeline @Summary Get activity timeline @Description Retrieves daily activity counts for visualization (appearances, disappearances, exposure changes) @Tags Asset State History @Accept json @Produce json @Security BearerAuth @Param from query string false "Start time (RFC3339, default: 30 days ago)" @Param to query string false "End time (RFC3339, default: now)" @Success 200 {object} object{data=[]DailyActivityResponse,from=string,to=string} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /state-history/timeline [get]

type AssetStats

type AssetStats struct {
	Total     int            `json:"total"`
	ByType    map[string]int `json:"by_type"`
	ByStatus  map[string]int `json:"by_status"`
	RiskScore float64        `json:"risk_score"`
}

AssetStats represents asset statistics.

type AssetStatsResponse

type AssetStatsResponse struct {
	Total         int            `json:"total"`
	ByType        map[string]int `json:"by_type"`
	ByStatus      map[string]int `json:"by_status"`
	ByCriticality map[string]int `json:"by_criticality"`
	ByScope       map[string]int `json:"by_scope"`
	ByExposure    map[string]int `json:"by_exposure"`
	WithFindings  int            `json:"with_findings"`
	RiskScoreAvg  float64        `json:"risk_score_avg"`
	FindingsTotal int            `json:"findings_total"`
	HighRiskCount int            `json:"high_risk_count"` // Assets with risk_score >= 70
}

AssetStatsResponse represents asset statistics in API responses.

type AssetTypeBreakdownResponse

type AssetTypeBreakdownResponse struct {
	Type    string `json:"type" example:"domain"`
	Total   int    `json:"total" example:"45"`
	Exposed int    `json:"exposed" example:"12"`
}

AssetTypeBreakdownResponse represents asset breakdown by type.

type AssetTypeHandler

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

AssetTypeHandler handles asset type-related HTTP requests. Asset types are read-only system configuration.

func NewAssetTypeHandler

func NewAssetTypeHandler(svc *app.AssetTypeService, v *validator.Validator, log *logger.Logger) *AssetTypeHandler

NewAssetTypeHandler creates a new asset type handler.

func (*AssetTypeHandler) GetAssetType

func (h *AssetTypeHandler) GetAssetType(w http.ResponseWriter, r *http.Request)

GetAssetType handles GET /api/v1/asset-types/{id} @Summary Get an asset type by ID @Description Retrieves a single system asset type by its unique identifier @Tags Asset Types @Accept json @Produce json @Security BearerAuth @Param id path string true "Asset Type ID (UUID)" @Success 200 {object} AssetTypeResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /asset-types/{id} [get]

func (*AssetTypeHandler) GetCategory

func (h *AssetTypeHandler) GetCategory(w http.ResponseWriter, r *http.Request)

GetCategory handles GET /api/v1/asset-types/categories/{categoryId} @Summary Get a category by ID @Description Retrieves a single asset type category by its unique identifier @Tags Asset Types @Accept json @Produce json @Security BearerAuth @Param categoryId path string true "Category ID (UUID)" @Success 200 {object} CategoryResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /asset-types/categories/{categoryId} [get]

func (*AssetTypeHandler) ListAssetTypes

func (h *AssetTypeHandler) ListAssetTypes(w http.ResponseWriter, r *http.Request)

ListAssetTypes handles GET /api/v1/asset-types @Summary List asset types @Description Retrieves a paginated list of system asset types. Asset types are read-only configuration. Use active_only=true to get all active types without pagination. @Tags Asset Types @Accept json @Produce json @Security BearerAuth @Param active_only query bool false "Return only active asset types (bypasses pagination)" @Param include_category query bool false "Include category details in response" @Param search query string false "Search by name or code" @Param category_id query string false "Filter by category ID" @Param code query string false "Filter by exact code" @Param is_system query bool false "Filter by system type" @Param is_scannable query bool false "Filter by scannable flag" @Param is_discoverable query bool false "Filter by discoverable flag" @Param sort query string false "Sort field (e.g., 'name', '-display_order')" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(50) @Success 200 {object} object{data=[]AssetTypeResponse,total=int,page=int,per_page=int,total_pages=int} @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /asset-types [get]

func (*AssetTypeHandler) ListCategories

func (h *AssetTypeHandler) ListCategories(w http.ResponseWriter, r *http.Request)

ListCategories handles GET /api/v1/asset-types/categories @Summary List asset type categories @Description Retrieves a paginated list of asset type categories. Use active_only=true to get all active categories without pagination. @Tags Asset Types @Accept json @Produce json @Security BearerAuth @Param active_only query bool false "Return only active categories (bypasses pagination)" @Param search query string false "Search by name or code" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} object{data=[]CategoryResponse,total=int,page=int,per_page=int,total_pages=int} @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /asset-types/categories [get]

type AssetTypeResponse

type AssetTypeResponse struct {
	ID                 string            `json:"id"`
	CategoryID         string            `json:"category_id,omitempty"`
	Category           *CategoryResponse `json:"category,omitempty"`
	Code               string            `json:"code"`
	Name               string            `json:"name"`
	Description        string            `json:"description,omitempty"`
	Icon               string            `json:"icon,omitempty"`
	Color              string            `json:"color,omitempty"`
	DisplayOrder       int               `json:"display_order"`
	PatternRegex       string            `json:"pattern_regex,omitempty"`
	PatternPlaceholder string            `json:"pattern_placeholder,omitempty"`
	PatternExample     string            `json:"pattern_example,omitempty"`
	SupportsWildcard   bool              `json:"supports_wildcard"`
	SupportsCIDR       bool              `json:"supports_cidr"`
	IsDiscoverable     bool              `json:"is_discoverable"`
	IsScannable        bool              `json:"is_scannable"`
	IsSystem           bool              `json:"is_system"`
	IsActive           bool              `json:"is_active"`
	CreatedAt          time.Time         `json:"created_at"`
	UpdatedAt          time.Time         `json:"updated_at"`
}

AssetTypeResponse represents an asset type in API responses.

type AssetWithRepositoryResponse

type AssetWithRepositoryResponse struct {
	AssetResponse
	Repository *RepositoryExtensionResponse `json:"repository,omitempty"`
}

AssetWithRepositoryResponse combines asset and repository extension.

type AssignAssetRequest

type AssignAssetRequest struct {
	AssetID       string `json:"asset_id" validate:"required,uuid"`
	OwnershipType string `json:"ownership_type" validate:"required,oneof=primary secondary stakeholder informed"`
}

AssignAssetRequest represents the request to assign an asset to a group.

type AssignFindingRequest

type AssignFindingRequest struct {
	UserID string `json:"user_id" validate:"required,uuid"`
}

AssignFindingRequest represents the request to assign a finding to a user.

type AssignPermissionSetRequest

type AssignPermissionSetRequest struct {
	PermissionSetID string `json:"permission_set_id" validate:"required,uuid"`
}

AssignPermissionSetRequest represents the request to assign a permission set.

type AssignRoleRequest

type AssignRoleRequest struct {
	RoleID string `json:"role_id" validate:"required,uuid"`
}

AssignRoleRequest represents the request to assign a role to a user.

type AssignToOwnersRequest added in v0.1.3

type AssignToOwnersRequest struct {
	Filter FindingFilterRequest `json:"filter"`
}

AssignToOwnersRequest is the request body for POST /api/v1/findings/actions/assign-to-owners

type AssignmentRuleHandler added in v0.1.2

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

AssignmentRuleHandler handles assignment rule HTTP requests.

func NewAssignmentRuleHandler added in v0.1.2

func NewAssignmentRuleHandler(svc *app.AssignmentRuleService, v *validator.Validator, log *logger.Logger) *AssignmentRuleHandler

NewAssignmentRuleHandler creates a new assignment rule handler.

func (*AssignmentRuleHandler) CreateRule added in v0.1.2

func (h *AssignmentRuleHandler) CreateRule(w http.ResponseWriter, r *http.Request)

CreateRule handles POST /api/v1/assignment-rules

func (*AssignmentRuleHandler) DeleteRule added in v0.1.2

func (h *AssignmentRuleHandler) DeleteRule(w http.ResponseWriter, r *http.Request)

DeleteRule handles DELETE /api/v1/assignment-rules/{id}

func (*AssignmentRuleHandler) GetRule added in v0.1.2

GetRule handles GET /api/v1/assignment-rules/{id}

func (*AssignmentRuleHandler) ListRules added in v0.1.2

ListRules handles GET /api/v1/assignment-rules

func (*AssignmentRuleHandler) TestRule added in v0.1.2

TestRule handles POST /api/v1/assignment-rules/{id}/test

func (*AssignmentRuleHandler) UpdateRule added in v0.1.2

func (h *AssignmentRuleHandler) UpdateRule(w http.ResponseWriter, r *http.Request)

UpdateRule handles PUT /api/v1/assignment-rules/{id}

type AssignmentRuleListResponse added in v0.1.2

type AssignmentRuleListResponse struct {
	Rules      []AssignmentRuleResponse `json:"rules"`
	TotalCount int64                    `json:"total_count"`
	Limit      int                      `json:"limit"`
	Offset     int                      `json:"offset"`
}

AssignmentRuleListResponse represents a paginated list of assignment rules.

type AssignmentRuleResponse added in v0.1.2

type AssignmentRuleResponse struct {
	ID            string                             `json:"id"`
	TenantID      string                             `json:"tenant_id"`
	Name          string                             `json:"name"`
	Description   string                             `json:"description,omitempty"`
	Priority      int                                `json:"priority"`
	IsActive      bool                               `json:"is_active"`
	Conditions    accesscontrol.AssignmentConditions `json:"conditions"`
	TargetGroupID string                             `json:"target_group_id"`
	Options       accesscontrol.AssignmentOptions    `json:"options"`
	CreatedAt     time.Time                          `json:"created_at"`
	UpdatedAt     time.Time                          `json:"updated_at"`
	CreatedBy     string                             `json:"created_by,omitempty"`
}

AssignmentRuleResponse represents an assignment rule in API responses.

type AttackSurfaceHandler

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

AttackSurfaceHandler handles attack surface related HTTP requests.

func NewAttackSurfaceHandler

func NewAttackSurfaceHandler(service *app.AttackSurfaceService, log *logger.Logger) *AttackSurfaceHandler

NewAttackSurfaceHandler creates a new AttackSurfaceHandler.

func (*AttackSurfaceHandler) GetStats

GetStats returns attack surface statistics for the current tenant. @Summary Get attack surface statistics @Description Returns attack surface statistics including total assets, exposed services, critical exposures, and risk score @Tags Attack Surface @Produce json @Security BearerAuth @Success 200 {object} AttackSurfaceStatsResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /attack-surface/stats [get]

type AttackSurfaceStatsResponse

type AttackSurfaceStatsResponse struct {
	// Summary statistics
	TotalAssets       int     `json:"total_assets" example:"303"`
	ExposedServices   int     `json:"exposed_services" example:"47"`
	CriticalExposures int     `json:"critical_exposures" example:"12"`
	RiskScore         float64 `json:"risk_score" example:"72.5"`

	// Trends (week-over-week changes)
	TotalAssetsChange       int `json:"total_assets_change" example:"12"`
	ExposedServicesChange   int `json:"exposed_services_change" example:"-3"`
	CriticalExposuresChange int `json:"critical_exposures_change" example:"2"`

	// Asset breakdown by type
	AssetBreakdown []AssetTypeBreakdownResponse `json:"asset_breakdown"`

	// Top exposed services
	ExposedServicesList []ExposedServiceResponse `json:"exposed_services_list"`

	// Recent changes
	RecentChanges []AssetChangeResponse `json:"recent_changes"`
}

AttackSurfaceStatsResponse represents the attack surface statistics response. @Description Attack surface statistics response

type AuditHandler

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

AuditHandler handles audit log-related HTTP requests.

func NewAuditHandler

func NewAuditHandler(svc *app.AuditService, v *validator.Validator, log *logger.Logger) *AuditHandler

NewAuditHandler creates a new audit handler.

func (*AuditHandler) Get

Get handles GET /api/v1/audit-logs/{id} @Summary Get audit log @Description Returns a single audit log by ID @Tags Audit Logs @Produce json @Security BearerAuth @Param id path string true "Audit Log ID" @Success 200 {object} AuditLogResponse @Failure 400 {object} map[string]string @Failure 403 {object} map[string]string @Failure 404 {object} map[string]string @Router /audit-logs/{id} [get]

func (*AuditHandler) GetResourceHistory

func (h *AuditHandler) GetResourceHistory(w http.ResponseWriter, r *http.Request)

GetResourceHistory handles GET /api/v1/audit-logs/resource/{type}/{id} @Summary Get resource history @Description Returns audit history for a specific resource @Tags Audit Logs @Produce json @Security BearerAuth @Param type path string true "Resource type" @Param id path string true "Resource ID" @Param page query int false "Page number" @Param per_page query int false "Items per page" default(20) @Success 200 {object} AuditLogListResponse @Failure 400 {object} map[string]string @Router /audit-logs/resource/{type}/{id} [get]

func (*AuditHandler) GetStats

func (h *AuditHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats handles GET /api/v1/audit-logs/stats @Summary Get audit stats @Description Returns audit log statistics for the last 7 days @Tags Audit Logs @Produce json @Security BearerAuth @Success 200 {object} AuditStatsResponse @Failure 400 {object} map[string]string @Router /audit-logs/stats [get]

func (*AuditHandler) GetUserActivity

func (h *AuditHandler) GetUserActivity(w http.ResponseWriter, r *http.Request)

GetUserActivity handles GET /api/v1/audit-logs/user/{id} @Summary Get user activity @Description Returns audit logs for a specific user @Tags Audit Logs @Produce json @Security BearerAuth @Param id path string true "User ID" @Param page query int false "Page number" @Param per_page query int false "Items per page" default(20) @Success 200 {object} AuditLogListResponse @Failure 400 {object} map[string]string @Router /audit-logs/user/{id} [get]

func (*AuditHandler) List

func (h *AuditHandler) List(w http.ResponseWriter, r *http.Request)

List handles GET /api/v1/audit-logs @Summary List audit logs @Description Returns paginated audit logs for the current tenant @Tags Audit Logs @Produce json @Security BearerAuth @Param page query int false "Page number" @Param per_page query int false "Items per page" default(20) @Param actor_id query string false "Filter by actor ID" @Param action query string false "Filter by action" @Param resource_type query string false "Filter by resource type" @Param resource_id query string false "Filter by resource ID" @Param result query string false "Filter by result" @Param severity query string false "Filter by severity" @Param since query string false "Filter since (RFC3339)" @Param until query string false "Filter until (RFC3339)" @Param search query string false "Search term" @Success 200 {object} AuditLogListResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /audit-logs [get]

type AuditLogListResponse

type AuditLogListResponse struct {
	Data       []AuditLogResponse `json:"data"`
	Total      int64              `json:"total"`
	Page       int                `json:"page"`
	PerPage    int                `json:"per_page"`
	TotalPages int                `json:"total_pages"`
}

AuditLogListResponse represents a paginated list of audit logs.

type AuditLogResponse

type AuditLogResponse struct {
	ID           string         `json:"id"`
	TenantID     string         `json:"tenant_id,omitempty"`
	ActorID      string         `json:"actor_id,omitempty"`
	ActorEmail   string         `json:"actor_email"`
	ActorIP      string         `json:"actor_ip,omitempty"`
	Action       string         `json:"action"`
	ResourceType string         `json:"resource_type"`
	ResourceID   string         `json:"resource_id"`
	ResourceName string         `json:"resource_name,omitempty"`
	Changes      *audit.Changes `json:"changes,omitempty"`
	Result       string         `json:"result"`
	Severity     string         `json:"severity"`
	Message      string         `json:"message"`
	Metadata     map[string]any `json:"metadata,omitempty"`
	RequestID    string         `json:"request_id,omitempty"`
	Timestamp    time.Time      `json:"timestamp"`
}

AuditLogResponse represents an audit log in API responses.

type AuditStatsResponse

type AuditStatsResponse struct {
	TotalLogs     int64              `json:"total_logs"`
	LogsByAction  map[string]int64   `json:"logs_by_action"`
	LogsByResult  map[string]int64   `json:"logs_by_result"`
	RecentActions []AuditLogResponse `json:"recent_actions"`
}

GetStats handles GET /api/v1/audit-logs/stats Returns audit log statistics.

type AuthHandler

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

AuthHandler handles authentication requests.

func NewAuthHandler

func NewAuthHandler(keycloakCfg *config.KeycloakConfig, log *logger.Logger) *AuthHandler

NewAuthHandler creates a new AuthHandler.

func (*AuthHandler) GenerateToken

func (h *AuthHandler) GenerateToken(w http.ResponseWriter, r *http.Request)

GenerateToken is deprecated - tokens are now issued by Keycloak. @Summary Generate token (deprecated) @Description Deprecated endpoint - returns redirect instruction to Keycloak OAuth flow @Tags Authentication @Produce json @Success 200 {object} map[string]string @Router /auth/keycloak/token [post]

func (*AuthHandler) Info

func (h *AuthHandler) Info(w http.ResponseWriter, r *http.Request)

Info returns Keycloak configuration info. @Summary Get Keycloak info @Description Returns Keycloak server configuration URLs and realm info @Tags Authentication @Produce json @Success 200 {object} KeycloakInfoResponse @Router /auth/keycloak/info [get]

type AuthInfoResponse

type AuthInfoResponse struct {
	Provider             string `json:"provider"`
	RegistrationEnabled  bool   `json:"registration_enabled"`
	EmailVerificationReq bool   `json:"email_verification_required"`
}

AuthInfoResponse is the response body for auth info.

type AuthorizeRequest

type AuthorizeRequest struct {
	RedirectURI   string `json:"redirect_uri"`
	FinalRedirect string `json:"final_redirect"`
}

AuthorizeRequest is the request for getting authorization URL.

type AuthorizeResponse

type AuthorizeResponse struct {
	AuthorizationURL string `json:"authorization_url"`
	State            string `json:"state"`
}

AuthorizeResponse is the response containing the authorization URL.

type AvailableCapabilitiesResponse

type AvailableCapabilitiesResponse struct {
	Capabilities []string `json:"capabilities"`
}

AvailableCapabilitiesResponse represents the response for available capabilities.

type AzureServicePrincipalDataRequest

type AzureServicePrincipalDataRequest struct {
	TenantID     string `json:"tenant_id" validate:"required"`
	ClientID     string `json:"client_id" validate:"required"`
	ClientSecret string `json:"client_secret" validate:"required"`
}

AzureServicePrincipalDataRequest represents Azure service principal credential data.

type BasicAuthDataRequest

type BasicAuthDataRequest struct {
	Username string `json:"username" validate:"required"`
	Password string `json:"password" validate:"required"`
}

BasicAuthDataRequest represents basic auth credential data.

type BatchCreateRelationshipItem added in v0.1.5

type BatchCreateRelationshipItem struct {
	Type            string   `json:"type" validate:"required"`
	TargetAssetID   string   `json:"target_asset_id" validate:"required,uuid"`
	Description     string   `json:"description" validate:"max=1000"`
	Confidence      string   `json:"confidence" validate:"omitempty"`
	DiscoveryMethod string   `json:"discovery_method" validate:"omitempty"`
	ImpactWeight    *int     `json:"impact_weight" validate:"omitempty,min=1,max=10"`
	Tags            []string `json:"tags" validate:"omitempty,max=20,dive,max=50"`
}

BatchCreateRelationshipItem is one entry in a batch create body. Note: NO `source_asset_id` here — the source comes from the URL path (`/assets/{id}/relationships/batch`) and is shared across the whole batch.

type BatchCreateRelationshipRequest added in v0.1.5

type BatchCreateRelationshipRequest struct {
	// Hard cap on items per batch — prevents abuse via giant payloads
	// and matches the validator's `dive` limit. The frontend's
	// "Select all visible" only ever offers up to PICKER_PAGE_SIZE
	// (50) items, so 100 is comfortable headroom.
	Items []BatchCreateRelationshipItem `json:"items" validate:"required,min=1,max=100,dive"`
}

BatchCreateRelationshipRequest is the body of POST /api/v1/assets/{id}/relationships/batch.

type BearerTokenDataRequest

type BearerTokenDataRequest struct {
	Token string `json:"token" validate:"required"`
}

BearerTokenDataRequest represents bearer token credential data.

type BootstrapHandler

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

BootstrapHandler handles the bootstrap endpoint that returns all initial data needed after login in a single API call.

func NewBootstrapHandler

func NewBootstrapHandler(
	permCacheSvc *app.PermissionCacheService,
	permVersionSvc *app.PermissionVersionService,
	moduleSvc *app.ModuleService,
	tenantSvc *app.TenantService,
	log *logger.Logger,
) *BootstrapHandler

NewBootstrapHandler creates a new bootstrap handler.

func (*BootstrapHandler) Bootstrap

func (h *BootstrapHandler) Bootstrap(w http.ResponseWriter, r *http.Request)

Bootstrap returns all initial data needed after login in a single API call.

@Summary Bootstrap initial data @Description Returns all initial data needed after login: permissions and modules. @Tags Bootstrap @Produce json @Security BearerAuth @Success 200 {object} BootstrapResponse @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /me/bootstrap [get]

func (*BootstrapHandler) GetTenantModules

func (h *BootstrapHandler) GetTenantModules(w http.ResponseWriter, r *http.Request)

GetTenantModules returns the modules available to the current tenant.

@Summary Get tenant modules @Description Returns the modules available to the current tenant based on their subscription. @Tags Modules @Produce json @Security BearerAuth @Success 200 {object} TenantModulesResponse @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /me/modules [get]

type BootstrapPermissions

type BootstrapPermissions struct {
	List    []string `json:"list"`
	Version int      `json:"version"`
}

BootstrapPermissions contains user permissions and version.

type BootstrapResponse

type BootstrapResponse struct {
	Permissions BootstrapPermissions    `json:"permissions"`
	Modules     *TenantModulesResponse  `json:"modules,omitempty"`
	RiskLevels  *tenant.RiskLevelConfig `json:"risk_levels,omitempty"`
}

BootstrapResponse combines all initial data needed after login.

type BranchHandler

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

BranchHandler handles branch-related HTTP requests.

func NewBranchHandler

func NewBranchHandler(svc *app.BranchService, v *validator.Validator, log *logger.Logger) *BranchHandler

NewBranchHandler creates a new branch handler.

func (*BranchHandler) Create

func (h *BranchHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/repositories/{repository_id}/branches @Summary Create branch @Description Creates a new branch for a repository @Tags Branches @Accept json @Produce json @Security BearerAuth @Param repository_id path string true "Repository ID" @Param request body CreateBranchRequest true "Branch data" @Success 201 {object} BranchResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 409 {object} map[string]string @Router /repositories/{repository_id}/branches [post]

func (*BranchHandler) Delete

func (h *BranchHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/repositories/{repository_id}/branches/{id} @Summary Delete branch @Description Deletes a branch @Tags Branches @Security BearerAuth @Param repository_id path string true "Repository ID" @Param id path string true "Branch ID" @Success 204 "No Content" @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /repositories/{repository_id}/branches/{id} [delete]

func (*BranchHandler) Get

Get handles GET /api/v1/repositories/{repository_id}/branches/{id} @Summary Get branch @Description Retrieves a branch by ID @Tags Branches @Produce json @Security BearerAuth @Param repository_id path string true "Repository ID" @Param id path string true "Branch ID" @Success 200 {object} BranchResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /repositories/{repository_id}/branches/{id} [get]

func (*BranchHandler) GetDefault

func (h *BranchHandler) GetDefault(w http.ResponseWriter, r *http.Request)

GetDefault handles GET /api/v1/repositories/{repository_id}/branches/default @Summary Get default branch @Description Gets the default branch for a repository @Tags Branches @Produce json @Security BearerAuth @Param repository_id path string true "Repository ID" @Success 200 {object} BranchResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /repositories/{repository_id}/branches/default [get]

func (*BranchHandler) List

func (h *BranchHandler) List(w http.ResponseWriter, r *http.Request)

List handles GET /api/v1/repositories/{repository_id}/branches @Summary List branches @Description Retrieves all branches for a repository @Tags Branches @Produce json @Security BearerAuth @Param repository_id path string true "Repository ID" @Param name query string false "Filter by name" @Param types query string false "Filter by types (comma-separated)" @Param is_default query bool false "Filter by default branch" @Param scan_status query string false "Filter by scan status" @Param sort query string false "Sort field" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} map[string]interface{} @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 404 {object} map[string]string @Router /repositories/{repository_id}/branches [get]

func (*BranchHandler) SetDefault

func (h *BranchHandler) SetDefault(w http.ResponseWriter, r *http.Request)

SetDefault handles PUT /api/v1/repositories/{repository_id}/branches/{id}/default @Summary Set default branch @Description Sets a branch as the default for a repository @Tags Branches @Produce json @Security BearerAuth @Param repository_id path string true "Repository ID" @Param id path string true "Branch ID" @Success 200 {object} BranchResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /repositories/{repository_id}/branches/{id}/default [put]

func (*BranchHandler) Update

func (h *BranchHandler) Update(w http.ResponseWriter, r *http.Request)

Update handles PUT /api/v1/repositories/{repository_id}/branches/{id} @Summary Update branch @Description Updates a branch @Tags Branches @Accept json @Produce json @Security BearerAuth @Param repository_id path string true "Repository ID" @Param id path string true "Branch ID" @Param request body UpdateBranchRequest true "Branch data" @Success 200 {object} BranchResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /repositories/{repository_id}/branches/{id} [put]

type BranchResponse

type BranchResponse struct {
	ID                     string     `json:"id"`
	RepositoryID           string     `json:"repository_id"`
	Name                   string     `json:"name"`
	Type                   string     `json:"type"`
	IsDefault              bool       `json:"is_default"`
	IsProtected            bool       `json:"is_protected"`
	LastCommitSHA          string     `json:"last_commit_sha,omitempty"`
	LastCommitMessage      string     `json:"last_commit_message,omitempty"`
	LastCommitAuthor       string     `json:"last_commit_author,omitempty"`
	LastCommitAuthorAvatar string     `json:"last_commit_author_avatar,omitempty"`
	LastCommitAt           *time.Time `json:"last_commit_at,omitempty"`
	ScanOnPush             bool       `json:"scan_on_push"`
	ScanOnPR               bool       `json:"scan_on_pr"`
	LastScanID             string     `json:"last_scan_id,omitempty"`
	LastScannedAt          *time.Time `json:"last_scanned_at,omitempty"`
	ScanStatus             string     `json:"scan_status"`
	QualityGateStatus      string     `json:"quality_gate_status"`
	FindingsTotal          int        `json:"findings_total"`
	FindingsCritical       int        `json:"findings_critical"`
	FindingsHigh           int        `json:"findings_high"`
	FindingsMedium         int        `json:"findings_medium"`
	FindingsLow            int        `json:"findings_low"`
	KeepWhenInactive       bool       `json:"keep_when_inactive"`
	RetentionDays          *int       `json:"retention_days,omitempty"`
	CreatedAt              time.Time  `json:"created_at"`
	UpdatedAt              time.Time  `json:"updated_at"`
}

BranchResponse represents a branch in API responses.

type BrandingSettingsResponse

type BrandingSettingsResponse struct {
	PrimaryColor string `json:"primary_color"`
	LogoDarkURL  string `json:"logo_dark_url,omitempty"`
	LogoData     string `json:"logo_data,omitempty"`
}

BrandingSettingsResponse represents branding settings.

type BulkActionRequest

type BulkActionRequest struct {
	ScanIDs []string `json:"scan_ids" validate:"required,min=1,max=100,dive,uuid"`
}

BulkActionRequest represents the request body for bulk scan operations.

type BulkActionResponse

type BulkActionResponse struct {
	Successful []string `json:"successful"`
	Failed     []struct {
		ID    string `json:"id"`
		Error string `json:"error"`
	} `json:"failed"`
	Message string `json:"message"`
}

BulkActionResponse represents the response for bulk scan operations.

type BulkAssignAssetsRequest added in v0.1.2

type BulkAssignAssetsRequest struct {
	AssetIDs      []string `json:"asset_ids" validate:"required,min=1,max=1000,dive,uuid"`
	OwnershipType string   `json:"ownership_type" validate:"required,oneof=primary secondary stakeholder informed"`
}

BulkAssignAssetsRequest represents the request to bulk assign assets to a group.

type BulkAssignAssetsResponse added in v0.1.2

type BulkAssignAssetsResponse struct {
	SuccessCount int      `json:"success_count"`
	FailedCount  int      `json:"failed_count"`
	FailedAssets []string `json:"failed_assets,omitempty"`
}

BulkAssignAssetsResponse represents the response for bulk asset assignment.

type BulkAssignRequest

type BulkAssignRequest struct {
	FindingIDs []string `json:"finding_ids" validate:"required,min=1,max=100,dive,uuid"`
	UserID     string   `json:"user_id" validate:"required,uuid"`
}

BulkAssignRequest represents a bulk assignment request.

type BulkAssignRoleMembersRequest

type BulkAssignRoleMembersRequest struct {
	UserIDs []string `json:"user_ids" validate:"required,min=1,max=100,dive,uuid"`
}

BulkAssignRoleMembersRequest represents the request to assign a role to multiple users.

type BulkAssignRoleMembersResponse

type BulkAssignRoleMembersResponse struct {
	SuccessCount int      `json:"success_count"`
	FailedCount  int      `json:"failed_count"`
	FailedUsers  []string `json:"failed_users,omitempty"`
}

BulkAssignRoleMembersResponse represents the response for bulk role assignment.

type BulkDeleteExclusionsRequest added in v0.1.2

type BulkDeleteExclusionsRequest struct {
	ExclusionIDs []string `json:"exclusion_ids" validate:"required,min=1,max=100,dive,uuid"`
}

BulkDeleteExclusionsRequest represents bulk delete exclusions request.

type BulkDeleteRequest

type BulkDeleteRequest struct {
	GroupIDs []string `json:"group_ids" validate:"required,min=1,dive,uuid"`
}

BulkDeleteRequest represents bulk delete request.

type BulkDeleteSchedulesRequest added in v0.1.2

type BulkDeleteSchedulesRequest struct {
	ScheduleIDs []string `json:"schedule_ids" validate:"required,min=1,max=100,dive,uuid"`
}

BulkDeleteSchedulesRequest represents bulk delete schedules request.

type BulkDeleteTargetsRequest added in v0.1.2

type BulkDeleteTargetsRequest struct {
	TargetIDs []string `json:"target_ids" validate:"required,min=1,max=100,dive,uuid"`
}

BulkDeleteTargetsRequest represents bulk delete targets request.

type BulkIngestRequest

type BulkIngestRequest struct {
	Exposures []CreateExposureRequest `json:"exposures" validate:"required,min=1,max=1000,dive"`
}

BulkIngestRequest represents the request to bulk ingest exposures.

type BulkSyncRequest

type BulkSyncRequest struct {
	AssetIDs []string `json:"asset_ids" validate:"required,min=1,max=100,dive,uuid"`
}

BulkSyncRequest represents the request to sync multiple assets.

type BulkSyncResponse

type BulkSyncResponse struct {
	TotalCount   int                  `json:"total_count"`
	SuccessCount int                  `json:"success_count"`
	FailedCount  int                  `json:"failed_count"`
	SyncedAt     time.Time            `json:"synced_at"`
	Results      []BulkSyncResultItem `json:"results"`
}

BulkSyncResponse represents the response from a bulk sync operation.

type BulkSyncResultItem

type BulkSyncResultItem struct {
	AssetID       string   `json:"asset_id"`
	Success       bool     `json:"success"`
	Message       string   `json:"message,omitempty"`
	UpdatedFields []string `json:"updated_fields,omitempty"`
	Error         string   `json:"error,omitempty"`
}

BulkSyncResultItem represents the sync result for a single asset.

type BulkToolIDsRequest

type BulkToolIDsRequest struct {
	ToolIDs []string `json:"tool_ids" validate:"required,min=1,dive,uuid"`
}

BulkToolIDsRequest represents request for bulk tool operations.

type BulkTriageJob

type BulkTriageJob struct {
	FindingID string `json:"finding_id"`
	JobID     string `json:"job_id,omitempty"`
	Status    string `json:"status"`
	Error     string `json:"error,omitempty"`
}

BulkTriageJob represents a single job in bulk triage response.

type BulkTriageRequest

type BulkTriageRequest struct {
	FindingIDs []string `json:"finding_ids"`
	Mode       string   `json:"mode"` // "quick" or "detailed" (optional)
}

BulkTriageRequest represents a request to triage multiple findings.

type BulkTriageResponse

type BulkTriageResponse struct {
	Jobs       []BulkTriageJob `json:"jobs"`
	TotalCount int             `json:"total_count"`
	Queued     int             `json:"queued"`
	Failed     int             `json:"failed"`
}

BulkTriageResponse represents the response from bulk triage.

type BulkUpdateRequest

type BulkUpdateRequest struct {
	GroupIDs []string `json:"group_ids" validate:"required,min=1,dive,uuid"`
	Update   struct {
		Environment *string `json:"environment" validate:"omitempty,asset_group_environment"`
		Criticality *string `json:"criticality" validate:"omitempty,asset_group_criticality"`
	} `json:"update"`
}

BulkUpdateRequest represents bulk update request.

type BulkUpdateResponse

type BulkUpdateResponse struct {
	Updated int      `json:"updated"`
	Failed  int      `json:"failed"`
	Errors  []string `json:"errors,omitempty"`
}

BulkUpdateResponse represents the response for bulk operations.

type BulkUpdateStatusRequest

type BulkUpdateStatusRequest struct {
	FindingIDs []string `json:"finding_ids" validate:"required,min=1,max=100,dive,uuid"`
	Status     string   `json:"status" validate:"required"`
	Resolution string   `json:"resolution" validate:"max=1000"`
}

BulkUpdateStatusRequest represents a bulk status update request.

type BundleResponse

type BundleResponse struct {
	ID               string            `json:"id"`
	TenantID         string            `json:"tenant_id"`
	ToolID           string            `json:"tool_id"`
	Version          string            `json:"version"`
	ContentHash      string            `json:"content_hash"`
	RuleCount        int               `json:"rule_count"`
	SourceCount      int               `json:"source_count"`
	SizeBytes        int64             `json:"size_bytes"`
	SourceIDs        []string          `json:"source_ids"`
	SourceHashes     map[string]string `json:"source_hashes,omitempty"`
	StoragePath      string            `json:"storage_path"`
	Status           string            `json:"status"`
	BuildError       string            `json:"build_error,omitempty"`
	BuildStartedAt   *string           `json:"build_started_at,omitempty"`
	BuildCompletedAt *string           `json:"build_completed_at,omitempty"`
	CreatedAt        string            `json:"created_at"`
	ExpiresAt        *string           `json:"expires_at,omitempty"`
}

BundleResponse represents the response for a rule bundle.

type CIHandler added in v0.1.2

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

CIHandler handles HTTP requests for CI/CD snippet generation.

func NewCIHandler added in v0.1.2

func NewCIHandler(service *scansvc.Service, log *logger.Logger) *CIHandler

NewCIHandler creates a new CIHandler.

func (*CIHandler) GenerateSnippet added in v0.1.2

func (h *CIHandler) GenerateSnippet(w http.ResponseWriter, r *http.Request)

GenerateSnippet handles GET /api/v1/scans/{id}/ci-snippet @Summary Generate CI/CD snippet @Description Generate a CI/CD pipeline snippet for a scan configuration @Tags Scans @Produce text/plain @Param id path string true "Scan ID" @Param platform query string true "CI/CD platform (github, gitlab, jenkins)" @Success 200 {string} string "YAML or pipeline snippet" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/ci-snippet [get]

type CISAKEVResponse

type CISAKEVResponse struct {
	DateAdded     time.Time `json:"date_added"`
	DueDate       time.Time `json:"due_date"`
	RansomwareUse string    `json:"ransomware_use,omitempty"`
	Notes         string    `json:"notes,omitempty"`
	IsPastDue     bool      `json:"is_past_due"`
}

CISAKEVResponse represents CISA KEV data in API responses.

type CTISIngestRequest

type CTISIngestRequest struct {
	Report ctis.Report `json:"report"`
}

CTISIngestRequest represents the request body for CTIS ingestion.

type CallbackRequest

type CallbackRequest struct {
	Code        string `json:"code"`
	State       string `json:"state"`
	RedirectURI string `json:"redirect_uri"`
}

CallbackRequest is the request body for OAuth callback.

type CallbackResponse

type CallbackResponse struct {
	AccessToken  string   `json:"access_token"`
	RefreshToken string   `json:"refresh_token"`
	TokenType    string   `json:"token_type"`
	ExpiresIn    int64    `json:"expires_in"`
	User         UserInfo `json:"user"`
}

CallbackResponse is the response body for OAuth callback.

type CampaignResponse added in v0.1.2

type CampaignResponse struct {
	ID                string           `json:"id"`
	Name              string           `json:"name"`
	Description       string           `json:"description"`
	CampaignType      string           `json:"campaign_type"`
	Status            string           `json:"status"`
	Priority          string           `json:"priority"`
	ScopeItems        []map[string]any `json:"scope_items"`
	RulesOfEngagement map[string]any   `json:"rules_of_engagement,omitempty"`
	Methodology       string           `json:"methodology,omitempty"`
	StartDate         *string          `json:"start_date,omitempty"`
	EndDate           *string          `json:"end_date,omitempty"`
	LeadUserID        *string          `json:"lead_user_id,omitempty"`
	TeamUserIDs       []string         `json:"team_user_ids"`
	TeamMembers       []TeamMemberInfo `json:"team_members,omitempty"`
	Objectives        []string         `json:"objectives"`
	ClientName        string           `json:"client_name,omitempty"`
	ClientContact     string           `json:"client_contact,omitempty"`
	AssetIDs          []string         `json:"asset_ids"`
	AssetGroupIDs     []string         `json:"asset_group_ids"`
	Tags              []string         `json:"tags"`
	FindingsCount     map[string]int64 `json:"findings_count,omitempty"`
	Progress          float64          `json:"progress"`
	CreatedAt         time.Time        `json:"created_at"`
	UpdatedAt         time.Time        `json:"updated_at"`
	CreatedBy         *string          `json:"created_by,omitempty"`
	CreatedByName     string           `json:"created_by_name,omitempty"`
	CurrentUserRole   *string          `json:"current_user_role,omitempty"`
	Warning           string           `json:"warning,omitempty"`
}

CampaignResponse is the API response for a campaign.

type CapabilityHandler

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

CapabilityHandler handles HTTP requests for capabilities.

func NewCapabilityHandler

func NewCapabilityHandler(service *app.CapabilityService, v *validator.Validator, log *logger.Logger) *CapabilityHandler

NewCapabilityHandler creates a new CapabilityHandler.

func (*CapabilityHandler) CreateCustomCapability

func (h *CapabilityHandler) CreateCustomCapability(w http.ResponseWriter, r *http.Request)

CreateCustomCapability creates a new tenant custom capability. POST /api/v1/custom-capabilities

func (*CapabilityHandler) DeleteCustomCapability

func (h *CapabilityHandler) DeleteCustomCapability(w http.ResponseWriter, r *http.Request)

DeleteCustomCapability deletes a tenant custom capability. DELETE /api/v1/custom-capabilities/:id?force=true

func (*CapabilityHandler) GetCapabilitiesUsageStatsBatch

func (h *CapabilityHandler) GetCapabilitiesUsageStatsBatch(w http.ResponseWriter, r *http.Request)

GetCapabilitiesUsageStatsBatch returns usage statistics for multiple capabilities. POST /api/v1/capabilities/usage-stats Security: Validates tenant access for custom capabilities in batch.

func (*CapabilityHandler) GetCapability

func (h *CapabilityHandler) GetCapability(w http.ResponseWriter, r *http.Request)

GetCapability returns a capability by ID. GET /api/v1/capabilities/:id

func (*CapabilityHandler) GetCapabilityUsageStats

func (h *CapabilityHandler) GetCapabilityUsageStats(w http.ResponseWriter, r *http.Request)

GetCapabilityUsageStats returns usage statistics for a capability. GET /api/v1/capabilities/:id/usage-stats Security: Validates tenant access for custom capabilities.

func (*CapabilityHandler) GetCategories

func (h *CapabilityHandler) GetCategories(w http.ResponseWriter, r *http.Request)

GetCategories returns all unique capability categories. GET /api/v1/capabilities/categories

func (*CapabilityHandler) ListAllCapabilities

func (h *CapabilityHandler) ListAllCapabilities(w http.ResponseWriter, r *http.Request)

ListAllCapabilities lists all capabilities for dropdowns (no pagination). GET /api/v1/capabilities/all

func (*CapabilityHandler) ListCapabilities

func (h *CapabilityHandler) ListCapabilities(w http.ResponseWriter, r *http.Request)

ListCapabilities lists all capabilities (platform + tenant custom). GET /api/v1/capabilities

func (*CapabilityHandler) ListCapabilitiesByCategory

func (h *CapabilityHandler) ListCapabilitiesByCategory(w http.ResponseWriter, r *http.Request)

ListCapabilitiesByCategory lists capabilities filtered by category. GET /api/v1/capabilities/by-category/:category

func (*CapabilityHandler) UpdateCustomCapability

func (h *CapabilityHandler) UpdateCustomCapability(w http.ResponseWriter, r *http.Request)

UpdateCustomCapability updates a tenant custom capability. PUT /api/v1/custom-capabilities/:id

type CapabilityResponse

type CapabilityResponse struct {
	ID          string  `json:"id"`
	TenantID    *string `json:"tenant_id,omitempty"`
	Name        string  `json:"name"`
	DisplayName string  `json:"display_name"`
	Description string  `json:"description,omitempty"`
	Icon        string  `json:"icon"`
	Color       string  `json:"color"`
	Category    string  `json:"category,omitempty"`
	IsBuiltin   bool    `json:"is_builtin"`
	SortOrder   int     `json:"sort_order"`
	CreatedBy   *string `json:"created_by,omitempty"`
	CreatedAt   string  `json:"created_at"`
	UpdatedAt   string  `json:"updated_at"`
}

CapabilityResponse represents the response for a capability.

type CapabilityUsageStatsResponse

type CapabilityUsageStatsResponse struct {
	ToolCount  int      `json:"tool_count"`
	AgentCount int      `json:"agent_count"`
	ToolNames  []string `json:"tool_names,omitempty"`
	AgentNames []string `json:"agent_names,omitempty"`
}

CapabilityUsageStatsResponse represents usage statistics for a capability.

type CategoryResponse

type CategoryResponse struct {
	ID           string    `json:"id"`
	Code         string    `json:"code"`
	Name         string    `json:"name"`
	Description  string    `json:"description,omitempty"`
	Icon         string    `json:"icon,omitempty"`
	DisplayOrder int       `json:"display_order"`
	IsActive     bool      `json:"is_active"`
	CreatedAt    time.Time `json:"created_at"`
	UpdatedAt    time.Time `json:"updated_at"`
}

CategoryResponse represents a category in API responses.

type ChangePasswordRequest

type ChangePasswordRequest struct {
	CurrentPassword string `json:"current_password" validate:"required"`
	NewPassword     string `json:"new_password" validate:"required,min=8,max=128"`
}

ChangePasswordRequest is the request body for changing password.

type ChangeStateRequest

type ChangeStateRequest struct {
	Reason string `json:"reason" validate:"max=500"`
}

ChangeStateRequest represents the request to change exposure state.

type CheckFingerprintsRequest

type CheckFingerprintsRequest struct {
	Fingerprints []string `json:"fingerprints"`
}

CheckFingerprintsRequest represents the request for checking fingerprint existence.

type CheckFingerprintsResponse

type CheckFingerprintsResponse struct {
	Existing []string `json:"existing"` // Fingerprints that already exist
	Missing  []string `json:"missing"`  // Fingerprints that don't exist
}

CheckFingerprintsResponse represents the response for fingerprint check.

type CheckResult

type CheckResult struct {
	Status   string `json:"status"`
	Duration string `json:"duration,omitempty"`
	Error    string `json:"error,omitempty"`
}

CheckResult represents a single health check result.

type CheckScopeRequest

type CheckScopeRequest struct {
	AssetType string `json:"asset_type" validate:"required"`
	Value     string `json:"value" validate:"required"`
}

CheckScopeRequest represents the request to check scope matching.

type ChunkIngestRequest

type ChunkIngestRequest struct {
	ReportID    string `json:"report_id"`             // Unique ID for the chunked report
	ChunkIndex  int    `json:"chunk_index"`           // 0-indexed chunk number
	TotalChunks int    `json:"total_chunks"`          // Total number of chunks
	Compression string `json:"compression,omitempty"` // Compression algorithm (zstd, gzip, none)
	Data        string `json:"data"`                  // Base64-encoded chunk data
	IsFinal     bool   `json:"is_final"`              // True for the last chunk
}

ChunkIngestRequest represents the request body for chunked ingestion. This is used by SDK when reports are too large for single upload.

type ChunkIngestResponse

type ChunkIngestResponse struct {
	ChunkID         string `json:"chunk_id"`
	ReportID        string `json:"report_id"`
	ChunkIndex      int    `json:"chunk_index"`
	Status          string `json:"status"`
	AssetsCreated   int    `json:"assets_created"`
	AssetsUpdated   int    `json:"assets_updated"`
	FindingsCreated int    `json:"findings_created"`
	FindingsUpdated int    `json:"findings_updated"`
	FindingsSkipped int    `json:"findings_skipped"`
}

ChunkIngestResponse represents the response from chunk ingestion.

type ClassifyFindingRequest

type ClassifyFindingRequest struct {
	CVEID      string   `json:"cve_id" validate:"max=20"`
	CVSSScore  *float64 `json:"cvss_score" validate:"omitempty,min=0,max=10"`
	CVSSVector string   `json:"cvss_vector" validate:"max=100"`
	CWEIDs     []string `json:"cwe_ids" validate:"max=20,dive,max=20"`
	OWASPIDs   []string `json:"owasp_ids" validate:"max=20,dive,max=50"`
}

ClassifyFindingRequest represents the request to classify a finding with CVE/CWE/CVSS.

type CloneScanProfileRequest

type CloneScanProfileRequest struct {
	NewName string `json:"new_name" validate:"required,min=1,max=100"`
}

CloneScanProfileRequest represents the request body for cloning a scan profile.

type CloneScanRequest

type CloneScanRequest struct {
	Name string `json:"name" validate:"required,min=1,max=200"`
}

CloneScanRequest represents the request body for cloning a scan.

type CloneTemplateRequest

type CloneTemplateRequest struct {
	Name string `json:"name" validate:"required,min=1,max=255"`
}

CloneTemplateRequest represents the request body for cloning a template.

type CommandHandler

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

CommandHandler handles command-related HTTP requests.

func NewCommandHandler

func NewCommandHandler(svc *app.CommandService, v *validator.Validator, log *logger.Logger) *CommandHandler

NewCommandHandler creates a new command handler.

func (*CommandHandler) Acknowledge

func (h *CommandHandler) Acknowledge(w http.ResponseWriter, r *http.Request)

Acknowledge handles POST /api/v1/agent/commands/{id}/acknowledge @Summary Acknowledge command @Description Agent acknowledges receipt of a command @Tags Agent @Accept json @Produce json @Param id path string true "Command ID" @Success 200 {object} CommandResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Security ApiKeyAuth @Router /agent/commands/{id}/acknowledge [post]

func (*CommandHandler) Cancel

func (h *CommandHandler) Cancel(w http.ResponseWriter, r *http.Request)

Cancel handles POST /api/v1/commands/{id}/cancel - admin endpoint @Summary Cancel command @Description Cancel a pending or running command @Tags Commands @Accept json @Produce json @Param id path string true "Command ID" @Success 200 {object} CommandResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /commands/{id}/cancel [post]

func (*CommandHandler) Complete

func (h *CommandHandler) Complete(w http.ResponseWriter, r *http.Request)

Complete handles POST /api/v1/agent/commands/{id}/complete @Summary Complete command @Description Agent reports successful command completion with optional result @Tags Agent @Accept json @Produce json @Param id path string true "Command ID" @Param body body UpdateCommandStatusRequest false "Completion result" @Success 200 {object} CommandResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Security ApiKeyAuth @Router /agent/commands/{id}/complete [post]

func (*CommandHandler) Create

func (h *CommandHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/commands @Summary Create command @Description Create a new command to be executed by an agent @Tags Commands @Accept json @Produce json @Param body body CreateCommandRequest true "Command data" @Success 201 {object} CommandResponse @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /commands [post]

func (*CommandHandler) Delete

func (h *CommandHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/commands/{id} @Summary Delete command @Description Delete a command @Tags Commands @Accept json @Produce json @Param id path string true "Command ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /commands/{id} [delete]

func (*CommandHandler) Fail

Fail handles POST /api/v1/agent/commands/{id}/fail @Summary Fail command @Description Agent reports command execution failure with error message @Tags Agent @Accept json @Produce json @Param id path string true "Command ID" @Param body body UpdateCommandStatusRequest false "Error details" @Success 200 {object} CommandResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Security ApiKeyAuth @Router /agent/commands/{id}/fail [post]

func (*CommandHandler) Get

Get handles GET /api/v1/commands/{id} @Summary Get command @Description Get a single command by ID @Tags Commands @Accept json @Produce json @Param id path string true "Command ID" @Success 200 {object} CommandResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /commands/{id} [get]

func (*CommandHandler) List

List handles GET /api/v1/commands @Summary List commands @Description Get a paginated list of commands @Tags Commands @Accept json @Produce json @Param agent_id query string false "Filter by agent ID" @Param type query string false "Filter by type (scan, collect, health_check, config_update, cancel)" @Param status query string false "Filter by status (pending, running, completed, failed, canceled)" @Param priority query string false "Filter by priority (low, normal, high, critical)" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[CommandResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /commands [get]

func (*CommandHandler) Poll

Poll handles GET /api/v1/agent/commands - agent polling endpoint @Summary Poll commands @Description Agent polls for pending commands to execute @Tags Agent @Accept json @Produce json @Param limit query int false "Max commands to return" default(10) @Success 200 {array} CommandResponse @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security ApiKeyAuth @Router /agent/commands [get]

func (*CommandHandler) SetPipelineService

func (h *CommandHandler) SetPipelineService(svc *pipelinesvc.Service)

SetPipelineService sets the pipeline service for triggering pipeline progression.

func (*CommandHandler) Start

func (h *CommandHandler) Start(w http.ResponseWriter, r *http.Request)

Start handles POST /api/v1/agent/commands/{id}/start @Summary Start command @Description Agent reports that command execution has started @Tags Agent @Accept json @Produce json @Param id path string true "Command ID" @Success 200 {object} CommandResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Security ApiKeyAuth @Router /agent/commands/{id}/start [post]

type CommandResponse

type CommandResponse struct {
	ID             string          `json:"id"`
	TenantID       string          `json:"tenant_id,omitempty"`
	AgentID        string          `json:"agent_id,omitempty"`
	Type           string          `json:"type"`
	Priority       string          `json:"priority"`
	Payload        json.RawMessage `json:"payload,omitempty"`
	Status         string          `json:"status"`
	ErrorMessage   string          `json:"error_message,omitempty"`
	CreatedAt      time.Time       `json:"created_at"`
	ExpiresAt      *time.Time      `json:"expires_at,omitempty"`
	AcknowledgedAt *time.Time      `json:"acknowledged_at,omitempty"`
	StartedAt      *time.Time      `json:"started_at,omitempty"`
	CompletedAt    *time.Time      `json:"completed_at,omitempty"`
	Result         json.RawMessage `json:"result,omitempty"`
}

CommandResponse represents a command in API responses.

type ComplianceAssessmentResponse added in v0.1.2

type ComplianceAssessmentResponse struct {
	ID            string     `json:"id"`
	TenantID      string     `json:"tenant_id"`
	FrameworkID   string     `json:"framework_id"`
	ControlID     string     `json:"control_id"`
	Status        string     `json:"status"`
	Priority      string     `json:"priority"`
	Owner         string     `json:"owner"`
	Notes         string     `json:"notes"`
	EvidenceCount int        `json:"evidence_count"`
	FindingCount  int        `json:"finding_count"`
	AssessedBy    *string    `json:"assessed_by,omitempty"`
	AssessedAt    *time.Time `json:"assessed_at,omitempty"`
	DueDate       *time.Time `json:"due_date,omitempty"`
	CreatedAt     time.Time  `json:"created_at"`
	UpdatedAt     time.Time  `json:"updated_at"`
}

ComplianceAssessmentResponse is the API response for a compliance assessment.

type ComplianceControlResponse added in v0.1.2

type ComplianceControlResponse struct {
	ID              string    `json:"id"`
	FrameworkID     string    `json:"framework_id"`
	ControlID       string    `json:"control_id"`
	Title           string    `json:"title"`
	Description     string    `json:"description"`
	Category        string    `json:"category"`
	ParentControlID *string   `json:"parent_control_id,omitempty"`
	SortOrder       int       `json:"sort_order"`
	CreatedAt       time.Time `json:"created_at"`
}

ComplianceControlResponse is the API response for a compliance control.

type ComplianceFrameworkResponse added in v0.1.2

type ComplianceFrameworkResponse struct {
	ID            string    `json:"id"`
	Name          string    `json:"name"`
	Slug          string    `json:"slug"`
	Version       string    `json:"version"`
	Description   string    `json:"description"`
	Category      string    `json:"category"`
	TotalControls int       `json:"total_controls"`
	IsSystem      bool      `json:"is_system"`
	IsActive      bool      `json:"is_active"`
	CreatedAt     time.Time `json:"created_at"`
	UpdatedAt     time.Time `json:"updated_at"`
}

ComplianceFrameworkResponse is the API response for a compliance framework.

type ComplianceHandler added in v0.1.2

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

ComplianceHandler handles compliance HTTP requests.

func NewComplianceHandler added in v0.1.2

func NewComplianceHandler(svc *app.ComplianceService, log *logger.Logger) *ComplianceHandler

NewComplianceHandler creates a new compliance handler.

func (*ComplianceHandler) GetComplianceStats added in v0.1.2

func (h *ComplianceHandler) GetComplianceStats(w http.ResponseWriter, r *http.Request)

GetComplianceStats returns overall compliance statistics.

func (*ComplianceHandler) GetControl added in v0.1.2

func (h *ComplianceHandler) GetControl(w http.ResponseWriter, r *http.Request)

GetControl returns a single compliance control.

func (*ComplianceHandler) GetFindingControls added in v0.1.2

func (h *ComplianceHandler) GetFindingControls(w http.ResponseWriter, r *http.Request)

GetFindingControls lists controls mapped to a finding.

func (*ComplianceHandler) GetFramework added in v0.1.2

func (h *ComplianceHandler) GetFramework(w http.ResponseWriter, r *http.Request)

GetFramework returns a single compliance framework.

func (*ComplianceHandler) GetFrameworkStats added in v0.1.2

func (h *ComplianceHandler) GetFrameworkStats(w http.ResponseWriter, r *http.Request)

GetFrameworkStats returns compliance statistics for a framework.

func (*ComplianceHandler) ListAssessments added in v0.1.2

func (h *ComplianceHandler) ListAssessments(w http.ResponseWriter, r *http.Request)

ListAssessments lists assessments for a framework.

func (*ComplianceHandler) ListControls added in v0.1.2

func (h *ComplianceHandler) ListControls(w http.ResponseWriter, r *http.Request)

ListControls lists controls for a framework with tenant verification.

func (*ComplianceHandler) ListFrameworks added in v0.1.2

func (h *ComplianceHandler) ListFrameworks(w http.ResponseWriter, r *http.Request)

ListFrameworks lists compliance frameworks with optional search filter.

func (*ComplianceHandler) MapFindingToControl added in v0.1.2

func (h *ComplianceHandler) MapFindingToControl(w http.ResponseWriter, r *http.Request)

MapFindingToControl maps a finding to a compliance control.

func (*ComplianceHandler) UnmapFindingFromControl added in v0.1.2

func (h *ComplianceHandler) UnmapFindingFromControl(w http.ResponseWriter, r *http.Request)

UnmapFindingFromControl removes a finding-to-control mapping.

func (*ComplianceHandler) UpdateAssessment added in v0.1.2

func (h *ComplianceHandler) UpdateAssessment(w http.ResponseWriter, r *http.Request)

UpdateAssessment creates or updates a control assessment.

type ComplianceMappingResponse added in v0.1.2

type ComplianceMappingResponse struct {
	ID        string    `json:"id"`
	FindingID string    `json:"finding_id"`
	ControlID string    `json:"control_id"`
	Impact    string    `json:"impact"`
	Notes     string    `json:"notes"`
	CreatedAt time.Time `json:"created_at"`
	CreatedBy *string   `json:"created_by,omitempty"`
}

ComplianceMappingResponse is the API response for a finding-to-control mapping.

type ComponentHandler

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

ComponentHandler handles component-related HTTP requests.

func NewComponentHandler

func NewComponentHandler(svc *app.ComponentService, v *validator.Validator, log *logger.Logger) *ComponentHandler

NewComponentHandler creates a new component handler.

func (*ComponentHandler) Create

func (h *ComponentHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/components @Summary Create component @Description Creates a new component @Tags Components @Accept json @Produce json @Security BearerAuth @Param request body CreateComponentRequest true "Component data" @Success 201 {object} ComponentResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 409 {object} map[string]string @Router /components [post]

func (*ComponentHandler) Delete

func (h *ComponentHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/components/{id} @Summary Delete component @Description Deletes a component @Tags Components @Security BearerAuth @Param id path string true "Component ID" @Success 204 "No Content" @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /components/{id} [delete]

func (*ComponentHandler) Get

Get handles GET /api/v1/components/{id} @Summary Get component @Description Retrieves a component by ID @Tags Components @Produce json @Security BearerAuth @Param id path string true "Component ID" @Success 200 {object} ComponentResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /components/{id} [get]

func (*ComponentHandler) GetEcosystemStats

func (h *ComponentHandler) GetEcosystemStats(w http.ResponseWriter, r *http.Request)

GetEcosystemStats handles GET /api/v1/components/ecosystems @Summary Get ecosystem statistics @Description Retrieves per-ecosystem statistics for the tenant @Tags Components @Produce json @Security BearerAuth @Success 200 {array} component.EcosystemStats @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /components/ecosystems [get]

func (*ComponentHandler) GetLicenseStats

func (h *ComponentHandler) GetLicenseStats(w http.ResponseWriter, r *http.Request)

GetLicenseStats handles GET /api/v1/components/licenses @Summary Get license statistics @Description Retrieves license distribution statistics for the tenant @Tags Components @Produce json @Security BearerAuth @Success 200 {array} component.LicenseStats @Failure 401 {object} map[string]string @Router /components/licenses [get]

func (*ComponentHandler) GetStats

func (h *ComponentHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats handles GET /api/v1/components/stats @Summary Get component statistics @Description Retrieves aggregated component statistics for the tenant @Tags Components @Produce json @Security BearerAuth @Success 200 {object} component.ComponentStats @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /components/stats [get]

func (*ComponentHandler) GetVulnerableComponents

func (h *ComponentHandler) GetVulnerableComponents(w http.ResponseWriter, r *http.Request)

GetVulnerableComponents handles GET /api/v1/components/vulnerable @Summary Get vulnerable components @Description Retrieves components with vulnerability details for the tenant @Tags Components @Produce json @Security BearerAuth @Param limit query int false "Limit results" default(10) @Success 200 {array} component.VulnerableComponent @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /components/vulnerable [get]

func (*ComponentHandler) List

List handles GET /api/v1/components @Summary List components @Description Retrieves a paginated list of components for the current tenant @Tags Components @Produce json @Security BearerAuth @Param asset_id query string false "Filter by asset ID" @Param name query string false "Filter by name" @Param ecosystems query string false "Filter by ecosystems (comma-separated)" @Param statuses query string false "Filter by statuses (comma-separated)" @Param dependency_types query string false "Filter by dependency types" @Param has_vulnerabilities query bool false "Filter by has vulnerabilities" @Param licenses query string false "Filter by licenses (comma-separated)" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} map[string]interface{} @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /components [get]

func (*ComponentHandler) ListByAsset

func (h *ComponentHandler) ListByAsset(w http.ResponseWriter, r *http.Request)

ListByAsset handles GET /api/v1/assets/{id}/components @Summary List asset components @Description Retrieves all components for an asset @Tags Components @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} map[string]interface{} @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /assets/{id}/components [get]

func (*ComponentHandler) Update

func (h *ComponentHandler) Update(w http.ResponseWriter, r *http.Request)

Update handles PUT /api/v1/components/{id} @Summary Update component @Description Updates a component @Tags Components @Accept json @Produce json @Security BearerAuth @Param id path string true "Component ID" @Param request body UpdateComponentRequest true "Component data" @Success 200 {object} ComponentResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /components/{id} [put]

type ComponentResponse

type ComponentResponse struct {
	ID                 string         `json:"id"`
	TenantID           string         `json:"tenant_id"`
	AssetID            string         `json:"asset_id"`
	Name               string         `json:"name"`
	Version            string         `json:"version"`
	Ecosystem          string         `json:"ecosystem"`
	PackageManager     string         `json:"package_manager,omitempty"`
	Namespace          string         `json:"namespace,omitempty"`
	ManifestFile       string         `json:"manifest_file,omitempty"`
	ManifestPath       string         `json:"manifest_path,omitempty"`
	DependencyType     string         `json:"dependency_type"`
	License            string         `json:"license,omitempty"`
	PURL               string         `json:"purl"`
	VulnerabilityCount int            `json:"vulnerability_count"`
	Status             string         `json:"status"`
	Metadata           map[string]any `json:"metadata,omitempty"`
	CreatedAt          time.Time      `json:"created_at"`
	UpdatedAt          time.Time      `json:"updated_at"`

	// Dependency hierarchy fields (industry-aligned: CycloneDX, Snyk, GitHub)
	Depth             int     `json:"depth"`                         // 1 = direct, 2+ = transitive depth
	ParentComponentID *string `json:"parent_component_id,omitempty"` // asset_components.id of parent dependency
	IsDirect          bool    `json:"is_direct"`                     // Convenience: depth == 1
}

ComponentResponse represents a component in API responses.

type CookieConfig

type CookieConfig struct {
	Secure                 bool
	Domain                 string
	SameSite               http.SameSite
	Path                   string
	AccessTokenCookieName  string // Configurable access token cookie name
	RefreshTokenCookieName string // Configurable refresh token cookie name
	TenantCookieName       string // Configurable tenant cookie name
}

CookieConfig holds cookie configuration for authentication.

func NewCookieConfig

func NewCookieConfig(cfg config.AuthConfig) CookieConfig

NewCookieConfig creates a CookieConfig from AuthConfig.

type CreateAPIKeyRequest

type CreateAPIKeyRequest struct {
	Name          string   `json:"name" validate:"required,min=1,max=255"`
	Description   string   `json:"description" validate:"max=1000"`
	Scopes        []string `json:"scopes" validate:"max=50"`
	RateLimit     int      `json:"rate_limit" validate:"min=0,max=100000"`
	ExpiresInDays int      `json:"expires_in_days" validate:"min=0,max=365"`
}

CreateAPIKeyRequest represents the request to create an API key.

type CreateAPIKeyResponse

type CreateAPIKeyResponse struct {
	APIKeyResponse
	Key string `json:"key"` // Plaintext key, shown only once
}

CreateAPIKeyResponse includes the plaintext key (only shown once).

type CreateAdminRequest

type CreateAdminRequest struct {
	Email string `json:"email"`
	Name  string `json:"name"`
	Role  string `json:"role"`
}

CreateAdminRequest represents the request to create an admin.

type CreateAgentRequest

type CreateAgentRequest struct {
	Name              string   `json:"name" validate:"required,min=1,max=255"`
	Type              string   `json:"type" validate:"required,oneof=runner worker collector sensor"`
	Description       string   `json:"description" validate:"max=1000"`
	Capabilities      []string `json:"capabilities" validate:"max=20,dive,max=50"`
	Tools             []string `json:"tools" validate:"max=20,dive,max=50"`
	ExecutionMode     string   `json:"execution_mode" validate:"omitempty,oneof=standalone daemon"`
	MaxConcurrentJobs int      `json:"max_concurrent_jobs" validate:"omitempty,min=1,max=100"`
}

CreateAgentRequest represents the request body for creating an agent.

type CreateAgentResponse

type CreateAgentResponse struct {
	Agent  *AgentResponse `json:"agent"`
	APIKey string         `json:"api_key"`
}

CreateAgentResponse includes the API key (only shown once).

type CreateAssetGroupRequest

type CreateAssetGroupRequest struct {
	Name         string   `json:"name" validate:"required,min=1,max=255"`
	Description  string   `json:"description" validate:"max=1000"`
	Environment  string   `json:"environment" validate:"required,asset_group_environment"`
	Criticality  string   `json:"criticality" validate:"required,asset_group_criticality"`
	BusinessUnit string   `json:"business_unit" validate:"max=255"`
	Owner        string   `json:"owner" validate:"max=255"`
	OwnerEmail   string   `json:"owner_email" validate:"omitempty,email,max=255"`
	Tags         []string `json:"tags" validate:"max=20,dive,max=50"`
	AssetIDs     []string `json:"existing_asset_ids" validate:"dive,uuid"`
}

CreateAssetGroupRequest represents the request to create an asset group.

type CreateAssetRequest

type CreateAssetRequest struct {
	Name        string   `json:"name" validate:"required,min=1,max=255"`
	Type        string   `json:"type" validate:"required,asset_type"`
	Criticality string   `json:"criticality" validate:"required,criticality"`
	Scope       string   `json:"scope" validate:"omitempty,scope"`
	Exposure    string   `json:"exposure" validate:"omitempty,exposure"`
	Description string   `json:"description" validate:"max=1000"`
	Tags        []string `json:"tags" validate:"max=20,dive,max=50"`
	OwnerRef    string   `json:"owner_ref" validate:"max=500"`
}

CreateAssetRequest represents the request to create an asset.

type CreateAssetServiceRequest

type CreateAssetServiceRequest struct {
	Name            string   `json:"name" validate:"omitempty,max=255"`
	Protocol        string   `json:"protocol" validate:"required,oneof=tcp udp"`
	Port            int      `json:"port" validate:"required,min=1,max=65535"`
	ServiceType     string   `json:"service_type" validate:"required"`
	Product         string   `json:"product" validate:"omitempty,max=255"`
	Version         string   `json:"version" validate:"omitempty,max=100"`
	Banner          string   `json:"banner" validate:"omitempty,max=4096"`
	CPE             string   `json:"cpe" validate:"omitempty,max=500"`
	Technologies    []string `json:"technologies" validate:"omitempty,max=50,dive,max=100"`
	IsPublic        bool     `json:"is_public"`
	Exposure        string   `json:"exposure" validate:"omitempty,oneof=public restricted private"`
	TLSEnabled      bool     `json:"tls_enabled"`
	TLSVersion      string   `json:"tls_version" validate:"omitempty,max=20"`
	DiscoverySource string   `json:"discovery_source" validate:"omitempty,max=100"`
}

CreateAssetServiceRequest represents the request to create an asset service.

type CreateAssignmentRuleRequest added in v0.1.2

type CreateAssignmentRuleRequest struct {
	Name          string                             `json:"name" validate:"required,min=2,max=200"`
	Description   string                             `json:"description" validate:"max=1000"`
	Priority      int                                `json:"priority"`
	Conditions    accesscontrol.AssignmentConditions `json:"conditions"`
	TargetGroupID string                             `json:"target_group_id" validate:"required,uuid"`
	Options       accesscontrol.AssignmentOptions    `json:"options"`
}

CreateAssignmentRuleRequest represents the request to create an assignment rule.

type CreateBranchRequest

type CreateBranchRequest struct {
	Name          string `json:"name" validate:"required,min=1,max=255"`
	BranchType    string `json:"type" validate:"required,branch_type"`
	IsDefault     bool   `json:"is_default"`
	IsProtected   bool   `json:"is_protected"`
	LastCommitSHA string `json:"last_commit_sha" validate:"max=40"`
}

CreateBranchRequest represents the request to create a branch.

type CreateCampaignRequest added in v0.1.2

type CreateCampaignRequest struct {
	Name              string           `json:"name" validate:"required,min=1,max=255"`
	Description       string           `json:"description" validate:"max=5000"`
	CampaignType      string           `json:"campaign_type" validate:"required,oneof=internal external red_team purple_team"`
	Priority          string           `json:"priority" validate:"required,oneof=low medium high critical"`
	Methodology       string           `json:"methodology" validate:"max=255"`
	ClientName        string           `json:"client_name" validate:"max=255"`
	ClientContact     string           `json:"client_contact" validate:"max=255"`
	StartDate         *string          `json:"start_date"`
	EndDate           *string          `json:"end_date"`
	Objectives        []string         `json:"objectives" validate:"max=50,dive,max=500"`
	ScopeItems        []map[string]any `json:"scope_items" validate:"max=100"`
	RulesOfEngagement map[string]any   `json:"rules_of_engagement"`
	LeadUserID        *string          `json:"lead_user_id,omitempty" validate:"omitempty,uuid"`
	TeamUserIDs       []string         `json:"team_user_ids" validate:"max=50,dive,uuid"`
	AssetIDs          []string         `json:"asset_ids" validate:"max=100,dive,uuid"`
	AssetGroupIDs     []string         `json:"asset_group_ids" validate:"max=20,dive,uuid"`
	Tags              []string         `json:"tags" validate:"max=50,dive,max=100"`
}

CreateCampaignRequest is the API request for creating a campaign.

type CreateCapabilityRequest

type CreateCapabilityRequest struct {
	Name        string `json:"name" validate:"required,min=2,max=50"`
	DisplayName string `json:"display_name" validate:"required,max=100"`
	Description string `json:"description" validate:"max=500"`
	Icon        string `json:"icon" validate:"max=50"`
	Color       string `json:"color" validate:"max=20"`
	Category    string `json:"category" validate:"max=50"`
}

CreateCapabilityRequest represents the request body for creating a capability.

type CreateCommandRequest

type CreateCommandRequest struct {
	AgentID   string          `json:"agent_id" validate:"omitempty,uuid"`
	Type      string          `json:"type" validate:"required,oneof=scan collect health_check config_update cancel"`
	Priority  string          `json:"priority" validate:"omitempty,oneof=low normal high critical"`
	Payload   json.RawMessage `json:"payload,omitempty"`
	ExpiresIn int             `json:"expires_in,omitempty"` // Seconds until expiration
}

CreateCommandRequest represents the request to create a command.

type CreateComponentRequest

type CreateComponentRequest struct {
	AssetID        string `json:"asset_id" validate:"required,uuid"`
	Name           string `json:"name" validate:"required,min=1,max=255"`
	Version        string `json:"version" validate:"required,max=100"`
	Ecosystem      string `json:"ecosystem" validate:"required"`
	PackageManager string `json:"package_manager" validate:"max=50"`
	Namespace      string `json:"namespace" validate:"max=255"`
	ManifestFile   string `json:"manifest_file" validate:"max=255"`
	ManifestPath   string `json:"manifest_path" validate:"max=500"`
	DependencyType string `json:"dependency_type" validate:"omitempty"`
	License        string `json:"license" validate:"max=100"`
}

CreateComponentRequest represents the request to create a component.

type CreateCredentialRequest

type CreateCredentialRequest struct {
	Name           string `json:"name" validate:"required,min=1,max=255"`
	CredentialType string `` /* 165-byte string literal not displayed */
	Description    string `json:"description" validate:"max=1000"`
	ExpiresAt      string `json:"expires_at,omitempty"`

	// Credential data (only one should be set based on credential_type)
	APIKey                *APIKeyDataRequest                `json:"api_key,omitempty"`
	BasicAuth             *BasicAuthDataRequest             `json:"basic_auth,omitempty"`
	BearerToken           *BearerTokenDataRequest           `json:"bearer_token,omitempty"`
	SSHKey                *SSHKeyDataRequest                `json:"ssh_key,omitempty"`
	AWSRole               *AWSRoleDataRequest               `json:"aws_role,omitempty"`
	GCPServiceAccount     *GCPServiceAccountDataRequest     `json:"gcp_service_account,omitempty"`
	AzureServicePrincipal *AzureServicePrincipalDataRequest `json:"azure_service_principal,omitempty"`
	GitHubApp             *GitHubAppDataRequest             `json:"github_app,omitempty"`
	GitLabToken           *GitLabTokenDataRequest           `json:"gitlab_token,omitempty"`
}

CreateCredentialRequest represents the request body for creating a credential.

type CreateEdgeRequest

type CreateEdgeRequest struct {
	SourceNodeKey string `json:"source_node_key" validate:"required,min=1,max=100"`
	TargetNodeKey string `json:"target_node_key" validate:"required,min=1,max=100"`
	SourceHandle  string `json:"source_handle" validate:"max=50"`
	Label         string `json:"label" validate:"max=100"`
}

CreateEdgeRequest represents an edge in the workflow request.

type CreateExposureRequest

type CreateExposureRequest struct {
	AssetID     string         `json:"asset_id" validate:"omitempty,uuid"`
	EventType   string         `json:"event_type" validate:"required"`
	Severity    string         `json:"severity" validate:"required"`
	Title       string         `json:"title" validate:"required,min=1,max=500"`
	Description string         `json:"description" validate:"max=2000"`
	Source      string         `json:"source" validate:"required,max=100"`
	Details     map[string]any `json:"details"`
}

CreateExposureRequest represents the request to create an exposure event.

type CreateFindingRequest

type CreateFindingRequest struct {
	AssetID         string `json:"asset_id" validate:"required,uuid"`
	BranchID        string `json:"branch_id" validate:"omitempty,uuid"`
	VulnerabilityID string `json:"vulnerability_id" validate:"omitempty,uuid"`
	ComponentID     string `json:"component_id" validate:"omitempty,uuid"`
	Source          string `json:"source" validate:"required"`
	ToolName        string `json:"tool_name" validate:"required,max=100"`
	ToolVersion     string `json:"tool_version" validate:"max=50"`
	RuleID          string `json:"rule_id" validate:"max=255"`
	FilePath        string `json:"file_path" validate:"max=500"`
	StartLine       int    `json:"start_line" validate:"min=0"`
	EndLine         int    `json:"end_line" validate:"min=0"`
	StartColumn     int    `json:"start_column" validate:"min=0"`
	EndColumn       int    `json:"end_column" validate:"min=0"`
	Snippet         string `json:"snippet" validate:"max=5000"`
	Message         string `json:"message" validate:"required,max=2000"`
	Severity        string `json:"severity" validate:"required"`
	ScanID          string `json:"scan_id" validate:"max=100"`
}

CreateFindingRequest represents the request to create a finding.

type CreateFirstTeamRequest

type CreateFirstTeamRequest struct {
	TeamName string `json:"team_name" validate:"required,min=2,max=100"`
	TeamSlug string `json:"team_slug" validate:"required,min=3,max=50"`
}

CreateFirstTeamRequest is the request body for creating first team.

type CreateFirstTeamResponse

type CreateFirstTeamResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	TokenType    string `json:"token_type"`
	ExpiresIn    int64  `json:"expires_in"`
	TenantID     string `json:"tenant_id"`
	TenantSlug   string `json:"tenant_slug"`
	TenantName   string `json:"tenant_name"`
	Role         string `json:"role"`
}

CreateFirstTeamResponse is the response body for creating first team.

type CreateGroupRequest

type CreateGroupRequest struct {
	Name               string                    `json:"name" validate:"required,min=2,max=100"`
	Slug               string                    `json:"slug" validate:"required,min=2,max=100,slug"`
	Description        string                    `json:"description" validate:"max=500"`
	GroupType          string                    `json:"group_type" validate:"required,oneof=security_team team department project external"`
	Settings           *group.GroupSettings      `json:"settings,omitempty"`
	NotificationConfig *group.NotificationConfig `json:"notification_config,omitempty"`
}

CreateGroupRequest represents the request to create a group.

type CreateIntegrationRequest

type CreateIntegrationRequest struct {
	Name            string `json:"name" validate:"required,min=1,max=255" example:"GitHub Production"`
	Description     string `json:"description" validate:"omitempty,max=1000" example:"Main GitHub integration"`
	Category        string `json:"category" validate:"required,oneof=scm security cloud ticketing notification" example:"scm"`
	Provider        string `json:"provider" validate:"required" example:"github"`
	AuthType        string `json:"auth_type" validate:"required,oneof=token oauth api_key basic app" example:"token"`
	BaseURL         string `json:"base_url" validate:"omitempty,url" example:"https://github.com"`
	Credentials     string `json:"credentials" validate:"omitempty,max=5000" example:"YOUR_TOKEN_HERE"`
	SCMOrganization string `json:"scm_organization" validate:"omitempty,max=255" example:"my-organization"`
}

CreateIntegrationRequest represents the request to create an integration. @Description Request body for creating a new integration

type CreateInvitationRequest

type CreateInvitationRequest struct {
	Email   string   `json:"email" validate:"required,email,max=254"`
	RoleIDs []string `json:"role_ids" validate:"required,min=1,max=10"` // RBAC roles to assign (required, max 10)
}

CreateInvitationRequest represents the request to create an invitation. Note: In simplified model, all invited users are "member". Permissions come from RBAC roles.

type CreateNotificationIntegrationRequest

type CreateNotificationIntegrationRequest struct {
	Name        string `json:"name" validate:"required,min=1,max=255"`
	Description string `json:"description" validate:"max=1000"`
	Provider    string `json:"provider" validate:"required,oneof=slack teams telegram webhook email"`
	AuthType    string `json:"auth_type" validate:"required,oneof=token api_key"`
	Credentials string `json:"credentials" validate:"required"` // Webhook URL or Bot Token

	// Notification-specific fields
	ChannelID          string   `json:"channel_id"`
	ChannelName        string   `json:"channel_name"`
	EnabledSeverities  []string `json:"enabled_severities"`  // Severity levels to notify on (critical, high, medium, low, info, none)
	EnabledEventTypes  []string `json:"enabled_event_types"` // Event types to receive notifications for
	MessageTemplate    string   `json:"message_template"`
	IncludeDetails     *bool    `json:"include_details"`
	MinIntervalMinutes *int     `json:"min_interval_minutes"`
}

CreateNotificationIntegrationRequest represents the request to create a notification integration.

type CreateOverrideRequest

type CreateOverrideRequest struct {
	ToolID           string  `json:"tool_id" validate:"omitempty,uuid"`
	RulePattern      string  `json:"rule_pattern" validate:"required,min=1,max=500"`
	IsPattern        bool    `json:"is_pattern"`
	Enabled          bool    `json:"enabled"`
	SeverityOverride string  `json:"severity_override" validate:"omitempty,oneof=critical high medium low info"`
	AssetGroupID     string  `json:"asset_group_id" validate:"omitempty,uuid"`
	ScanProfileID    string  `json:"scan_profile_id" validate:"omitempty,uuid"`
	Reason           string  `json:"reason" validate:"max=1000"`
	ExpiresAt        *string `json:"expires_at"`
}

CreateOverrideRequest represents the request body for creating a rule override.

type CreatePermissionSetRequest

type CreatePermissionSetRequest struct {
	Name        string   `json:"name" validate:"required,min=2,max=100"`
	Slug        string   `json:"slug" validate:"required,min=2,max=100,slug"`
	Description string   `json:"description" validate:"max=500"`
	SetType     string   `json:"set_type" validate:"required,oneof=custom extended cloned"`
	ParentSetID *string  `json:"parent_set_id,omitempty"`
	Permissions []string `json:"permissions,omitempty"`
}

CreatePermissionSetRequest represents the request to create a permission set.

type CreateProviderRequest added in v0.1.2

type CreateProviderRequest struct {
	Provider         string   `json:"provider" validate:"required,oneof=entra_id okta google_workspace"`
	DisplayName      string   `json:"display_name" validate:"required,min=1,max=255"`
	ClientID         string   `json:"client_id" validate:"required,max=255"`
	ClientSecret     string   `json:"client_secret" validate:"required,max=1000"`
	IssuerURL        string   `json:"issuer_url" validate:"omitempty,url,max=500"`
	TenantIdentifier string   `json:"tenant_identifier" validate:"max=255"`
	Scopes           []string `json:"scopes" validate:"max=20,dive,max=100"`
	AllowedDomains   []string `json:"allowed_domains" validate:"max=50,dive,max=255"`
	AutoProvision    bool     `json:"auto_provision"`
	DefaultRole      string   `json:"default_role" validate:"omitempty,oneof=member viewer"`
}

CreateProviderRequest is the request body for creating an identity provider.

type CreateRelationshipRequest

type CreateRelationshipRequest struct {
	Type            string   `json:"type" validate:"required"`
	SourceAssetID   string   `json:"source_asset_id" validate:"required,uuid"`
	TargetAssetID   string   `json:"target_asset_id" validate:"required,uuid"`
	Description     string   `json:"description" validate:"max=1000"`
	Confidence      string   `json:"confidence" validate:"omitempty"`
	DiscoveryMethod string   `json:"discovery_method" validate:"omitempty"`
	ImpactWeight    *int     `json:"impact_weight" validate:"omitempty,min=1,max=10"`
	Tags            []string `json:"tags" validate:"omitempty,max=20,dive,max=50"`
}

CreateRelationshipRequest represents the request to create a relationship.

type CreateRepositoryAssetRequest

type CreateRepositoryAssetRequest struct {
	// Basic info
	Name        string   `json:"name" validate:"required,min=1,max=255"`
	Description string   `json:"description" validate:"max=1000"`
	Criticality string   `json:"criticality" validate:"required,criticality"`
	Scope       string   `json:"scope" validate:"omitempty,scope"`
	Exposure    string   `json:"exposure" validate:"omitempty,exposure"`
	Tags        []string `json:"tags" validate:"max=20,dive,max=50"`
	// SCM connection info
	Provider        string `json:"provider" validate:"omitempty"`
	ExternalID      string `json:"external_id" validate:"omitempty,max=255"`
	RepoID          string `json:"repo_id" validate:"omitempty,max=255"`
	FullName        string `json:"full_name" validate:"required,max=500"`
	SCMOrganization string `json:"scm_organization" validate:"omitempty,max=255"`
	// URLs
	CloneURL string `json:"clone_url" validate:"omitempty,url"`
	WebURL   string `json:"web_url" validate:"omitempty,url"`
	SSHURL   string `json:"ssh_url" validate:"omitempty,max=500"`
	// Repository settings
	DefaultBranch string           `json:"default_branch" validate:"omitempty,max=100"`
	Visibility    string           `json:"visibility" validate:"omitempty"`
	Language      string           `json:"language" validate:"omitempty,max=50"`
	Languages     map[string]int64 `json:"languages" validate:"omitempty"`
	Topics        []string         `json:"topics" validate:"max=50,dive,max=100"`
	// Stats
	Stars      int `json:"stars" validate:"min=0"`
	Forks      int `json:"forks" validate:"min=0"`
	Watchers   int `json:"watchers" validate:"min=0"`
	OpenIssues int `json:"open_issues" validate:"min=0"`
	SizeKB     int `json:"size_kb" validate:"min=0"`
	// Scan settings
	ScanEnabled  bool   `json:"scan_enabled"`
	ScanSchedule string `json:"scan_schedule" validate:"omitempty,max=100"`
	// Timestamps from SCM (ISO 8601 format)
	RepoCreatedAt string `json:"repo_created_at" validate:"omitempty"`
	RepoUpdatedAt string `json:"repo_updated_at" validate:"omitempty"`
	RepoPushedAt  string `json:"repo_pushed_at" validate:"omitempty"`
}

CreateRepositoryAssetRequest represents the request to create a repository asset.

type CreateRoleRequest

type CreateRoleRequest struct {
	Slug              string   `json:"slug" validate:"required,min=2,max=50,slug"`
	Name              string   `json:"name" validate:"required,min=2,max=100"`
	Description       string   `json:"description" validate:"max=500"`
	HierarchyLevel    int      `json:"hierarchy_level" validate:"min=0,max=100"`
	HasFullDataAccess bool     `json:"has_full_data_access"`
	Permissions       []string `json:"permissions" validate:"max=200,dive,max=100"`
}

CreateRoleRequest represents the request to create a role.

type CreateSLAPolicyRequest

type CreateSLAPolicyRequest struct {
	AssetID             string         `json:"asset_id" validate:"omitempty,uuid"`
	Name                string         `json:"name" validate:"required,min=1,max=100"`
	Description         string         `json:"description" validate:"max=500"`
	IsDefault           bool           `json:"is_default"`
	CriticalDays        int            `json:"critical_days" validate:"required,min=1,max=365"`
	HighDays            int            `json:"high_days" validate:"required,min=1,max=365"`
	MediumDays          int            `json:"medium_days" validate:"required,min=1,max=365"`
	LowDays             int            `json:"low_days" validate:"required,min=1,max=365"`
	InfoDays            int            `json:"info_days" validate:"required,min=1,max=365"`
	WarningThresholdPct int            `json:"warning_threshold_pct" validate:"min=0,max=100"`
	EscalationEnabled   bool           `json:"escalation_enabled"`
	EscalationConfig    map[string]any `json:"escalation_config"`
}

CreateSLAPolicyRequest represents the request to create an SLA policy.

type CreateScanProfileRequest

type CreateScanProfileRequest struct {
	Name               string                       `json:"name" validate:"required,min=1,max=100"`
	Description        string                       `json:"description" validate:"max=500"`
	ToolsConfig        map[string]ToolConfigRequest `json:"tools_config"`
	Intensity          string                       `json:"intensity" validate:"omitempty,oneof=low medium high"`
	MaxConcurrentScans int                          `json:"max_concurrent_scans" validate:"omitempty,min=1,max=100"`
	TimeoutSeconds     int                          `json:"timeout_seconds" validate:"omitempty,min=60,max=86400"`
	Tags               []string                     `json:"tags" validate:"max=20,dive,max=50"`
	IsDefault          bool                         `json:"is_default"`
	QualityGate        *QualityGateRequest          `json:"quality_gate,omitempty"`
}

CreateScanProfileRequest represents the request body for creating a scan profile.

type CreateScanRequest

type CreateScanRequest struct {
	Name                string         `json:"name" validate:"required,min=1,max=200"`
	Description         string         `json:"description" validate:"max=1000"`
	AssetGroupID        string         `json:"asset_group_id" validate:"omitempty,uuid"`       // Single asset group (legacy)
	AssetGroupIDs       []string       `json:"asset_group_ids" validate:"omitempty,dive,uuid"` // Multiple asset groups (NEW)
	Targets             []string       `json:"targets" validate:"omitempty,max=1000"`          // Direct targets
	ScanType            string         `json:"scan_type" validate:"required,oneof=workflow single"`
	PipelineID          string         `json:"pipeline_id" validate:"omitempty,uuid"`
	ScannerName         string         `json:"scanner_name" validate:"max=100"`
	ScannerConfig       map[string]any `json:"scanner_config"`
	TargetsPerJob       int            `json:"targets_per_job"`
	ScheduleType        string         `json:"schedule_type" validate:"omitempty,oneof=manual daily weekly monthly crontab"`
	ScheduleCron        string         `json:"schedule_cron" validate:"max=100"`
	ScheduleDay         *int           `json:"schedule_day"`
	ScheduleTime        *string        `json:"schedule_time"`
	Timezone            string         `json:"timezone" validate:"max=50"`
	Tags                []string       `json:"tags" validate:"max=20,dive,max=50"`
	TenantRunner        bool           `json:"run_on_tenant_runner"`
	AgentPreference     string         `json:"agent_preference" validate:"omitempty,oneof=auto tenant platform"`
	ProfileID           string         `json:"profile_id" validate:"omitempty,uuid"`
	TimeoutSeconds      int            `json:"timeout_seconds" validate:"omitempty,min=30,max=86400"`
	MaxRetries          int            `json:"max_retries" validate:"omitempty,min=0,max=10"`
	RetryBackoffSeconds int            `json:"retry_backoff_seconds" validate:"omitempty,min=10,max=86400"`
}

CreateScanRequest represents the request body for creating a scan. Either asset_group_id OR asset_group_ids OR targets must be provided (can have all).

type CreateScanResponse

type CreateScanResponse struct {
	*ScanDetailResponse
	CompatibilityWarning *AssetCompatibilityPreviewResponse `json:"compatibility_warning,omitempty"`
}

CreateScanResponse wraps scan detail with optional compatibility warning. Used only for POST /scans to show warnings about asset-scanner compatibility.

type CreateScanScheduleRequest

type CreateScanScheduleRequest struct {
	Name                 string                 `json:"name" validate:"required,min=1,max=200"`
	Description          string                 `json:"description" validate:"max=1000"`
	ScanType             string                 `json:"scan_type" validate:"required"`
	TargetScope          string                 `json:"target_scope"`
	TargetIDs            []string               `json:"target_ids" validate:"max=100"`
	TargetTags           []string               `json:"target_tags" validate:"max=20,dive,max=50"`
	ScannerConfigs       map[string]interface{} `json:"scanner_configs"`
	ScheduleType         string                 `json:"schedule_type" validate:"required"`
	CronExpression       string                 `json:"cron_expression" validate:"max=100"`
	IntervalHours        int                    `json:"interval_hours" validate:"min=0,max=8760"`
	NotifyOnCompletion   bool                   `json:"notify_on_completion"`
	NotifyOnFindings     bool                   `json:"notify_on_findings"`
	NotificationChannels []string               `json:"notification_channels" validate:"max=10,dive,max=50"`
}

CreateScanScheduleRequest represents the request to create a scan schedule.

type CreateScannerTemplateRequest

type CreateScannerTemplateRequest struct {
	Name         string   `json:"name" validate:"required,min=1,max=255"`
	TemplateType string   `json:"template_type" validate:"required,oneof=nuclei semgrep gitleaks"`
	Description  string   `json:"description" validate:"max=1000"`
	Content      string   `json:"content" validate:"required"` // Base64 encoded
	Tags         []string `json:"tags" validate:"max=20,dive,max=50"`
}

CreateScannerTemplateRequest represents the request body for creating a template.

type CreateScopeExclusionRequest

type CreateScopeExclusionRequest struct {
	ExclusionType string     `json:"exclusion_type" validate:"required"`
	Pattern       string     `json:"pattern" validate:"required,max=500"`
	Reason        string     `json:"reason" validate:"required,max=1000"`
	ExpiresAt     *time.Time `json:"expires_at"`
}

CreateScopeExclusionRequest represents the request to create a scope exclusion.

type CreateScopeTargetRequest

type CreateScopeTargetRequest struct {
	TargetType  string   `json:"target_type" validate:"required"`
	Pattern     string   `json:"pattern" validate:"required,max=500"`
	Description string   `json:"description" validate:"max=1000"`
	Priority    int      `json:"priority" validate:"min=0,max=100"`
	Tags        []string `json:"tags" validate:"max=20,dive,max=50"`
}

CreateScopeTargetRequest represents the request to create a scope target.

type CreateSourceRequest

type CreateSourceRequest struct {
	ToolID              string          `json:"tool_id" validate:"omitempty,uuid"`
	Name                string          `json:"name" validate:"required,min=1,max=255"`
	Description         string          `json:"description" validate:"max=1000"`
	SourceType          string          `json:"source_type" validate:"required,oneof=git http local"`
	Config              json.RawMessage `json:"config" validate:"required"`
	CredentialsID       string          `json:"credentials_id" validate:"omitempty,uuid"`
	SyncEnabled         bool            `json:"sync_enabled"`
	SyncIntervalMinutes int             `json:"sync_interval_minutes" validate:"min=5,max=10080"`
	Priority            int             `json:"priority" validate:"min=0,max=1000"`
}

CreateSourceRequest represents the request body for creating a rule source.

type CreateStepRequest

type CreateStepRequest struct {
	StepKey           string                 `json:"step_key" validate:"required,min=1,max=100"`
	Name              string                 `json:"name" validate:"required,min=1,max=255"`
	Description       string                 `json:"description" validate:"max=1000"`
	Order             int                    `json:"order"`
	UIPosition        *UIPositionRequest     `json:"ui_position"`
	Tool              string                 `json:"tool" validate:"max=100"`
	Capabilities      []string               `json:"capabilities" validate:"omitempty,max=10,dive,max=50"`
	Config            map[string]interface{} `json:"config"`
	TimeoutSeconds    int                    `json:"timeout_seconds"`
	DependsOn         []string               `json:"depends_on" validate:"max=20,dive,max=50"`
	Condition         *StepConditionRequest  `json:"condition"`
	MaxRetries        int                    `json:"max_retries"`
	RetryDelaySeconds int                    `json:"retry_delay_seconds"`
}

CreateStepRequest represents a step in the create template request. Capabilities are optional - if not provided and tool is specified, they will be derived from the tool.

type CreateSuppressionRuleRequest

type CreateSuppressionRuleRequest struct {
	Name            string  `json:"name"`
	Description     string  `json:"description,omitempty"`
	SuppressionType string  `json:"suppression_type"`
	RuleID          string  `json:"rule_id,omitempty"`
	ToolName        string  `json:"tool_name,omitempty"`
	PathPattern     string  `json:"path_pattern,omitempty"`
	AssetID         *string `json:"asset_id,omitempty"`
	ExpiresAt       *string `json:"expires_at,omitempty"`
}

CreateSuppressionRuleRequest represents a request to create a suppression rule.

type CreateTargetMappingRequest

type CreateTargetMappingRequest struct {
	TargetType  string  `json:"target_type"`
	AssetType   string  `json:"asset_type"`
	Priority    *int    `json:"priority,omitempty"`
	IsPrimary   *bool   `json:"is_primary,omitempty"` // Convenience: sets priority to 10 if true
	IsActive    *bool   `json:"is_active,omitempty"`
	Description *string `json:"description,omitempty"`
}

CreateTargetMappingRequest represents the request to create a target mapping.

type CreateTargetResponseWithWarnings added in v0.1.2

type CreateTargetResponseWithWarnings struct {
	ScopeTargetResponse
	Warnings []string `json:"warnings,omitempty"`
}

CreateTargetResponseWithWarnings wraps a target response with overlap warnings.

type CreateTemplateRequest

type CreateTemplateRequest struct {
	Name        string                   `json:"name" validate:"required,min=1,max=255"`
	Description string                   `json:"description" validate:"max=1000"`
	Triggers    []TriggerRequest         `json:"triggers" validate:"max=10,dive"`
	Settings    *PipelineSettingsRequest `json:"settings"`
	Tags        []string                 `json:"tags" validate:"max=10,dive,max=50"`
	Steps       []CreateStepRequest      `json:"steps" validate:"max=50,dive"`
}

CreateTemplateRequest represents the request body for creating a pipeline template.

type CreateTemplateSourceRequest

type CreateTemplateSourceRequest struct {
	Name            string               `json:"name" validate:"required,min=1,max=255"`
	SourceType      string               `json:"source_type" validate:"required,oneof=git s3 http"`
	TemplateType    string               `json:"template_type" validate:"required,oneof=nuclei semgrep gitleaks"`
	Description     string               `json:"description" validate:"max=1000"`
	Enabled         bool                 `json:"enabled"`
	AutoSyncOnScan  bool                 `json:"auto_sync_on_scan"`
	CacheTTLMinutes int                  `json:"cache_ttl_minutes" validate:"min=0,max=10080"`
	GitConfig       *ts.GitSourceConfig  `json:"git_config,omitempty"`
	S3Config        *ts.S3SourceConfig   `json:"s3_config,omitempty"`
	HTTPConfig      *ts.HTTPSourceConfig `json:"http_config,omitempty"`
	CredentialID    string               `json:"credential_id" validate:"omitempty,uuid"`
}

CreateTemplateSourceRequest represents the request body for creating a template source.

type CreateTenantRequest

type CreateTenantRequest struct {
	Name        string `json:"name" validate:"required,min=2,max=100"`
	Slug        string `json:"slug" validate:"required,min=3,max=100,slug"`
	Description string `json:"description" validate:"max=500"`
}

CreateTenantRequest represents the request to create a tenant.

type CreateToolCategoryRequest

type CreateToolCategoryRequest struct {
	Name        string `json:"name" validate:"required,min=2,max=50"`
	DisplayName string `json:"display_name" validate:"required,max=100"`
	Description string `json:"description" validate:"max=500"`
	Icon        string `json:"icon" validate:"max=50"`
	Color       string `json:"color" validate:"max=20"`
}

CreateToolCategoryRequest represents the request body for creating a category.

type CreateToolRequest

type CreateToolRequest struct {
	Name             string         `json:"name" validate:"required,min=1,max=50"`
	DisplayName      string         `json:"display_name" validate:"max=100"`
	Description      string         `json:"description" validate:"max=1000"`
	CategoryID       string         `json:"category_id" validate:"omitempty,uuid"` // UUID reference to tool_categories table
	InstallMethod    string         `json:"install_method" validate:"required,oneof=go pip npm docker binary"`
	InstallCmd       string         `json:"install_cmd" validate:"max=500"`
	UpdateCmd        string         `json:"update_cmd" validate:"max=500"`
	VersionCmd       string         `json:"version_cmd" validate:"max=500"`
	VersionRegex     string         `json:"version_regex" validate:"max=200"`
	ConfigSchema     map[string]any `json:"config_schema"`
	DefaultConfig    map[string]any `json:"default_config"`
	Capabilities     []string       `json:"capabilities" validate:"max=20,dive,max=50"`
	SupportedTargets []string       `json:"supported_targets" validate:"max=10,dive,max=50"`
	OutputFormats    []string       `json:"output_formats" validate:"max=10,dive,max=20"`
	DocsURL          string         `json:"docs_url" validate:"omitempty,url,max=500"`
	GithubURL        string         `json:"github_url" validate:"omitempty,url,max=500"`
	LogoURL          string         `json:"logo_url" validate:"omitempty,url,max=500"`
	Tags             []string       `json:"tags" validate:"max=20,dive,max=50"`
}

CreateToolRequest represents the request body for creating a tool.

type CreateVulnerabilityRequest

type CreateVulnerabilityRequest struct {
	CVEID            string   `json:"cve_id" validate:"required"`
	Title            string   `json:"title" validate:"required,min=1,max=500"`
	Description      string   `json:"description" validate:"max=10000"`
	Severity         string   `json:"severity" validate:"required"`
	CVSSScore        *float64 `json:"cvss_score" validate:"omitempty,min=0,max=10"`
	CVSSVector       string   `json:"cvss_vector" validate:"max=100"`
	EPSSScore        *float64 `json:"epss_score" validate:"omitempty,min=0,max=1"`
	EPSSPercentile   *float64 `json:"epss_percentile" validate:"omitempty,min=0,max=1"`
	ExploitAvailable bool     `json:"exploit_available"`
	ExploitMaturity  string   `json:"exploit_maturity" validate:"omitempty"`
	FixedVersions    []string `json:"fixed_versions" validate:"max=50,dive,max=100"`
	Remediation      string   `json:"remediation" validate:"max=5000"`
}

CreateVulnerabilityRequest represents the request to create a vulnerability.

type CreateWebhookRequest

type CreateWebhookRequest struct {
	Name              string   `json:"name" validate:"required,min=1,max=255"`
	Description       string   `json:"description" validate:"max=1000"`
	URL               string   `json:"url" validate:"required,url,max=1000"`
	Secret            string   `json:"secret" validate:"max=500"`
	EventTypes        []string `json:"event_types" validate:"required,min=1,max=20"`
	SeverityThreshold string   `json:"severity_threshold" validate:"omitempty,oneof=critical high medium low info"`
	MaxRetries        int      `json:"max_retries" validate:"min=0,max=10"`
	RetryInterval     int      `json:"retry_interval_seconds" validate:"min=0,max=3600"`
}

CreateWebhookRequest represents the request to create a webhook.

type CreateWorkflowRequest

type CreateWorkflowRequest struct {
	Name        string              `json:"name" validate:"required,min=1,max=255"`
	Description string              `json:"description" validate:"max=1000"`
	Tags        []string            `json:"tags" validate:"max=10,dive,max=50"`
	Nodes       []NodeRequest       `json:"nodes" validate:"min=1,max=50,dive"`
	Edges       []CreateEdgeRequest `json:"edges" validate:"max=100,dive"`
}

CreateWorkflowRequest represents the request body for creating a workflow.

type CredentialContextReq

type CredentialContextReq struct {
	Username   string         `json:"username,omitempty" validate:"max=255"`
	Email      string         `json:"email,omitempty" validate:"omitempty,email,max=254"`
	Domain     string         `json:"domain,omitempty" validate:"max=255"`
	IPAddress  string         `json:"ip_address,omitempty" validate:"max=45"` // IPv6 max
	UserAgent  string         `json:"user_agent,omitempty" validate:"max=500"`
	LineNumber int            `json:"line_number,omitempty" validate:"min=0,max=10000000"`
	Extra      map[string]any `json:"extra,omitempty"`
}

CredentialContextReq represents context information in the request.

type CredentialImportHandler

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

CredentialImportHandler handles credential import HTTP requests.

func NewCredentialImportHandler

func NewCredentialImportHandler(
	svc *app.CredentialImportService,
	v *validator.Validator,
	log *logger.Logger,
) *CredentialImportHandler

NewCredentialImportHandler creates a new credential import handler.

func (*CredentialImportHandler) Accept

Accept handles POST /api/v1/credentials/{id}/accept @Summary Mark credential as accepted risk @Description Mark a credential leak as accepted risk @Tags Credentials @Accept json @Produce json @Param id path string true "Credential ID" @Param request body CredentialStateChangeRequest false "Acceptance notes" @Success 200 {object} app.CredentialItem @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/credentials/{id}/accept [post]

func (*CredentialImportHandler) GetByID

GetByID handles GET /api/v1/credentials/{id} @Summary Get credential leak by ID @Description Get a single credential leak by its ID @Tags Credentials @Produce json @Param id path string true "Credential ID" @Success 200 {object} app.CredentialItem @Failure 404 {object} apierror.Error @Failure 401 {object} apierror.Error @Router /api/v1/credentials/{id} [get]

func (*CredentialImportHandler) GetEnums

GetEnums handles GET /api/v1/credentials/enums @Summary Get available enum values @Description Get available credential types, source types, and other enums @Tags Credentials @Produce json @Success 200 {object} map[string]any @Router /api/v1/credentials/enums [get]

func (*CredentialImportHandler) GetExposuresForIdentity

func (h *CredentialImportHandler) GetExposuresForIdentity(w http.ResponseWriter, r *http.Request)

GetExposuresForIdentity handles GET /api/v1/credentials/identities/{identity}/exposures @Summary Get exposures for a specific identity (lazy load) @Description Get all credential exposures for a specific identity with pagination @Tags Credentials @Produce json @Param identity path string true "Identity (username or email)" @Param page query int false "Page number" default(1) @Param page_size query int false "Page size" default(20) @Success 200 {object} app.CredentialListResult @Failure 401 {object} apierror.Error @Router /api/v1/credentials/identities/{identity}/exposures [get]

func (*CredentialImportHandler) GetRelatedCredentials

func (h *CredentialImportHandler) GetRelatedCredentials(w http.ResponseWriter, r *http.Request)

GetRelatedCredentials handles GET /api/v1/credentials/{id}/related @Summary Get related credential leaks @Description Get all credentials related to the same identity @Tags Credentials @Produce json @Param id path string true "Credential ID" @Success 200 {array} app.CredentialItem @Failure 404 {object} apierror.Error @Failure 401 {object} apierror.Error @Router /api/v1/credentials/{id}/related [get]

func (*CredentialImportHandler) GetStats

GetStats handles GET /api/v1/credentials/stats @Summary Get credential leak statistics @Description Get statistics for credential leaks @Tags Credentials @Produce json @Success 200 {object} map[string]any @Failure 401 {object} apierror.Error @Router /api/v1/credentials/stats [get]

func (*CredentialImportHandler) GetTemplate

func (h *CredentialImportHandler) GetTemplate(w http.ResponseWriter, r *http.Request)

GetTemplate handles GET /api/v1/credentials/import/template @Summary Get CSV import template @Description Download CSV template for credential import @Tags Credentials @Produce text/csv @Success 200 {file} file "CSV template" @Router /api/v1/credentials/import/template [get]

func (*CredentialImportHandler) Import

Import handles POST /api/v1/credentials/import @Summary Import credential leaks @Description Import credential leaks with deduplication support @Tags Credentials @Accept json @Produce json @Param request body CredentialImportRequest true "Import request" @Success 201 {object} credential.ImportResult @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Router /api/v1/credentials/import [post]

func (*CredentialImportHandler) ImportCSV

ImportCSV handles POST /api/v1/credentials/import/csv @Summary Import credential leaks from CSV @Description Import credential leaks from CSV file @Tags Credentials @Accept multipart/form-data @Produce json @Param file formData file true "CSV file" @Param dedup_strategy query string false "Deduplication strategy" @Param reactivate_resolved query bool false "Reactivate resolved credentials" @Success 201 {object} credential.ImportResult @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Router /api/v1/credentials/import/csv [post]

func (*CredentialImportHandler) List

List handles GET /api/v1/credentials @Summary List credential leaks @Description List credential leaks with filtering and pagination @Tags Credentials @Produce json @Param page query int false "Page number" default(1) @Param page_size query int false "Page size" default(20) @Param severity query string false "Filter by severity (comma-separated)" @Param state query string false "Filter by state (comma-separated)" @Param source query string false "Filter by source (comma-separated)" @Param search query string false "Search in identifier" @Param sort query string false "Sort field (prefix - for desc)" @Success 200 {object} app.CredentialListResult @Failure 401 {object} apierror.Error @Router /api/v1/credentials [get]

func (*CredentialImportHandler) ListByIdentity

func (h *CredentialImportHandler) ListByIdentity(w http.ResponseWriter, r *http.Request)

ListByIdentity handles GET /api/v1/credentials/identities @Summary List credential leaks grouped by identity @Description List credential leaks grouped by identity (username/email) @Tags Credentials @Produce json @Param page query int false "Page number" default(1) @Param page_size query int false "Page size" default(20) @Param state query string false "Filter by state (comma-separated)" @Param search query string false "Search in identifier" @Success 200 {object} app.IdentityListResult @Failure 401 {object} apierror.Error @Router /api/v1/credentials/identities [get]

func (*CredentialImportHandler) MarkFalsePositive

func (h *CredentialImportHandler) MarkFalsePositive(w http.ResponseWriter, r *http.Request)

MarkFalsePositive handles POST /api/v1/credentials/{id}/false-positive @Summary Mark credential as false positive @Description Mark a credential leak as a false positive @Tags Credentials @Accept json @Produce json @Param id path string true "Credential ID" @Param request body CredentialStateChangeRequest false "Notes" @Success 200 {object} app.CredentialItem @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/credentials/{id}/false-positive [post]

func (*CredentialImportHandler) Reactivate

Reactivate handles POST /api/v1/credentials/{id}/reactivate @Summary Reactivate a resolved credential @Description Mark a resolved credential as active again @Tags Credentials @Produce json @Param id path string true "Credential ID" @Success 200 {object} app.CredentialItem @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/credentials/{id}/reactivate [post]

func (*CredentialImportHandler) Resolve

Resolve handles POST /api/v1/credentials/{id}/resolve @Summary Mark credential as resolved @Description Mark a credential leak as resolved @Tags Credentials @Accept json @Produce json @Param id path string true "Credential ID" @Param request body CredentialStateChangeRequest false "Resolution notes" @Success 200 {object} app.CredentialItem @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/credentials/{id}/resolve [post]

type CredentialImportItem

type CredentialImportItem struct {
	Identifier     string               `json:"identifier" validate:"required,max=500"`
	CredentialType string               `json:"credential_type" validate:"required"`
	SecretValue    string               `json:"secret_value,omitempty"` // The actual leaked secret (password, API key, etc.)
	Source         CredentialSourceReq  `json:"source" validate:"required"`
	Severity       string               `json:"severity,omitempty"`
	Classification string               `json:"classification,omitempty"`
	DedupKey       DedupKeyRequest      `json:"dedup_key"`
	Context        CredentialContextReq `json:"context"`
	IsVerified     bool                 `json:"is_verified"`
	IsRevoked      bool                 `json:"is_revoked"`
	Tags           []string             `json:"tags,omitempty"`
	Notes          string               `json:"notes,omitempty"`
}

CredentialImportItem represents a single credential in the import request.

type CredentialImportRequest

type CredentialImportRequest struct {
	Credentials []CredentialImportItem `json:"credentials" validate:"required,min=1,max=1000,dive"`
	Options     ImportOptionsRequest   `json:"options"`
	Metadata    ImportMetadataRequest  `json:"metadata"`
}

CredentialImportRequest represents the API request for importing credentials.

type CredentialResponse

type CredentialResponse struct {
	ID             string  `json:"id"`
	TenantID       string  `json:"tenant_id"`
	Name           string  `json:"name"`
	CredentialType string  `json:"credential_type"`
	Description    string  `json:"description,omitempty"`
	ExpiresAt      *string `json:"expires_at,omitempty"`
	LastUsedAt     *string `json:"last_used_at,omitempty"`
	LastRotatedAt  *string `json:"last_rotated_at,omitempty"`
	CreatedBy      *string `json:"created_by,omitempty"`
	CreatedAt      string  `json:"created_at"`
	UpdatedAt      string  `json:"updated_at"`
}

CredentialResponse represents the response for a credential.

type CredentialSourceReq

type CredentialSourceReq struct {
	Type         string  `json:"type" validate:"required,max=50"`
	Name         string  `json:"name,omitempty" validate:"max=255"`
	URL          string  `json:"url,omitempty" validate:"omitempty,url,max=2000"`
	DiscoveredAt *string `json:"discovered_at,omitempty"` // ISO8601 format
}

CredentialSourceReq represents source information in the request.

type CredentialStateChangeRequest

type CredentialStateChangeRequest struct {
	Notes string `json:"notes" validate:"max=500"`
}

CredentialStateChangeRequest represents the request to change credential state.

type CustomPatternResponse

type CustomPatternResponse struct {
	Name    string `json:"name"`
	Pattern string `json:"pattern"`
}

CustomPatternResponse represents a custom pattern in response.

type CustomTemplateResponse

type CustomTemplateResponse struct {
	Name    string `json:"name"`
	Path    string `json:"path,omitempty"`
	Content string `json:"content,omitempty"`
}

CustomTemplateResponse represents a custom template in response.

type DNSRecordResult

type DNSRecordResult struct {
	Host       string   `json:"host"`
	RecordType string   `json:"record_type"`
	Values     []string `json:"values"`
	TTL        int      `json:"ttl,omitempty"`
	Resolver   string   `json:"resolver,omitempty"`
	StatusCode string   `json:"status_code,omitempty"`
}

DNSRecordResult represents a DNS record.

type DailyActivityResponse

type DailyActivityResponse struct {
	Date           string `json:"date"`
	Appeared       int    `json:"appeared"`
	Disappeared    int    `json:"disappeared"`
	Recovered      int    `json:"recovered"`
	ExposureChange int    `json:"exposure_change"`
	OtherChanges   int    `json:"other_changes"`
	Total          int    `json:"total"`
}

DailyActivityResponse represents daily activity counts.

type DashboardHandler

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

DashboardHandler handles dashboard-related HTTP requests.

func NewDashboardHandler

func NewDashboardHandler(dashboardService *app.DashboardService, log *logger.Logger) *DashboardHandler

NewDashboardHandler creates a new DashboardHandler.

func (*DashboardHandler) GetGlobalStats

func (h *DashboardHandler) GetGlobalStats(w http.ResponseWriter, r *http.Request)

GetGlobalStats returns dashboard statistics filtered by user's accessible tenants. @Summary Get global dashboard stats @Description Returns dashboard statistics filtered by user's accessible tenants @Tags Dashboard @Produce json @Security BearerAuth @Success 200 {object} DashboardStatsResponse @Failure 401 {object} map[string]string @Failure 500 {object} map[string]string @Router /dashboard/stats/global [get]

func (*DashboardHandler) GetStats

func (h *DashboardHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats returns dashboard statistics for a tenant. @Summary Get tenant dashboard stats @Description Returns dashboard statistics for the current tenant @Tags Dashboard @Produce json @Security BearerAuth @Success 200 {object} DashboardStatsResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 500 {object} map[string]string @Router /dashboard/stats [get]

type DashboardStatsResponse

type DashboardStatsResponse struct {
	Assets         AssetStats          `json:"assets"`
	Findings       FindingStats        `json:"findings"`
	Repositories   RepositoryStats     `json:"repositories"`
	RecentActivity []ActivityItem      `json:"recent_activity"`
	FindingTrend   []FindingTrendPoint `json:"finding_trend"`
}

DashboardStatsResponse represents the dashboard statistics response.

type DataFlowLocationResponse

type DataFlowLocationResponse struct {
	// Physical location
	Path      string `json:"path,omitempty"`
	Line      int    `json:"line,omitempty"`
	EndLine   int    `json:"end_line,omitempty"`
	Column    int    `json:"column,omitempty"`
	EndColumn int    `json:"end_column,omitempty"`
	Snippet   string `json:"snippet,omitempty"` // Code at this location

	// Logical location (function/class context)
	FunctionName       string `json:"function_name,omitempty"`
	ClassName          string `json:"class_name,omitempty"`
	FullyQualifiedName string `json:"fully_qualified_name,omitempty"`
	ModuleName         string `json:"module_name,omitempty"`

	// Context
	Label        string `json:"label,omitempty"`         // Variable/expression name
	Message      string `json:"message,omitempty"`       // Description of what happens
	Index        int    `json:"index,omitempty"`         // Step order in the flow
	LocationType string `json:"location_type,omitempty"` // source, intermediate, sink, sanitizer
	NestingLevel int    `json:"nesting_level,omitempty"` // For display indentation
	Importance   string `json:"importance,omitempty"`    // essential, important, unimportant
}

DataFlowLocationResponse represents a single location in a data flow trace.

type DataFlowResponse

type DataFlowResponse struct {
	// Grouped view - locations by type (for quick visualization)
	Sources       []DataFlowLocationResponse `json:"sources,omitempty"`
	Intermediates []DataFlowLocationResponse `json:"intermediates,omitempty"`
	Sinks         []DataFlowLocationResponse `json:"sinks,omitempty"`
	Sanitizers    []DataFlowLocationResponse `json:"sanitizers,omitempty"`

	// Ordered view - full traces with all details (for detailed analysis)
	Traces []DataFlowTraceResponse `json:"traces,omitempty"`

	// Summary
	TotalSteps int `json:"total_steps,omitempty"` // Total number of steps across all traces
}

DataFlowResponse represents data flow traces for taint tracking/attack path. Provides both grouped (sources/intermediates/sinks) and ordered (traces) views.

type DataFlowStepResponse

type DataFlowStepResponse struct {
	Index        int                       `json:"index"`
	LocationType string                    `json:"location_type"` // source, intermediate, sink, sanitizer
	Location     *DataFlowLocationResponse `json:"location,omitempty"`
	Label        string                    `json:"label,omitempty"`
	Message      string                    `json:"message,omitempty"`
	Importance   string                    `json:"importance,omitempty"`
}

DataFlowStepResponse represents a single step in a data flow with full details.

type DataFlowTraceResponse

type DataFlowTraceResponse struct {
	Index      int                    `json:"index"`                // Flow index within finding
	Message    string                 `json:"message,omitempty"`    // Flow summary
	Importance string                 `json:"importance,omitempty"` // essential, important, unimportant
	Steps      []DataFlowStepResponse `json:"steps"`                // Ordered steps from source to sink
}

DataFlowTraceResponse represents a single data flow trace (attack path).

type DedupKeyRequest

type DedupKeyRequest struct {
	BreachName string `json:"breach_name,omitempty" validate:"max=255"`
	BreachDate string `json:"breach_date,omitempty" validate:"max=30"`
	Repository string `json:"repository,omitempty" validate:"max=500"`
	FilePath   string `json:"file_path,omitempty" validate:"max=1000"`
	CommitHash string `json:"commit_hash,omitempty" validate:"max=64"`
	Branch     string `json:"branch,omitempty" validate:"max=255"`
	SourceURL  string `json:"source_url,omitempty" validate:"omitempty,max=2000"`
	PasteID    string `json:"paste_id,omitempty" validate:"max=255"`
}

DedupKeyRequest represents deduplication key in the request.

type DeliveryResponse

type DeliveryResponse struct {
	ID           string         `json:"id"`
	WebhookID    string         `json:"webhook_id"`
	EventID      string         `json:"event_id,omitempty"`
	EventType    string         `json:"event_type"`
	Payload      map[string]any `json:"payload,omitempty"`
	Status       string         `json:"status"`
	ResponseCode *int           `json:"response_code,omitempty"`
	ResponseBody string         `json:"response_body,omitempty"`
	Attempt      int            `json:"attempt"`
	NextRetryAt  *time.Time     `json:"next_retry_at,omitempty"`
	ErrorMessage string         `json:"error_message,omitempty"`
	CreatedAt    time.Time      `json:"created_at"`
	DeliveredAt  *time.Time     `json:"delivered_at,omitempty"`
	DurationMs   *int           `json:"duration_ms,omitempty"`
}

DeliveryResponse represents a webhook delivery in the response.

type DiscoveredURLResult

type DiscoveredURLResult struct {
	URL        string `json:"url"`
	Method     string `json:"method,omitempty"`
	Source     string `json:"source,omitempty"`
	StatusCode int    `json:"status_code,omitempty"`
	Depth      int    `json:"depth,omitempty"`
	Parent     string `json:"parent,omitempty"`
	Type       string `json:"type,omitempty"`
	Extension  string `json:"extension,omitempty"`
}

DiscoveredURLResult represents a discovered URL/endpoint.

type DocsHandler

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

DocsHandler handles API documentation endpoints

func NewDocsHandler

func NewDocsHandler(specPath string) *DocsHandler

NewDocsHandler creates a new DocsHandler specPath is the path to the OpenAPI spec file (e.g., "api/openapi/openapi.yaml")

func (*DocsHandler) ServeDocsUI

func (h *DocsHandler) ServeDocsUI(w http.ResponseWriter, r *http.Request)

ServeDocsUI serves the Scalar API documentation UI

func (*DocsHandler) ServeOpenAPISpec

func (h *DocsHandler) ServeOpenAPISpec(w http.ResponseWriter, r *http.Request)

ServeOpenAPISpec serves the OpenAPI specification file

type EPSSScoreResponse

type EPSSScoreResponse struct {
	CVEID        string  `json:"cve_id"`
	Score        float64 `json:"score"`
	Percentile   float64 `json:"percentile"`
	ModelVersion string  `json:"model_version,omitempty"`
	ScoreDate    string  `json:"score_date"`
	RiskLevel    string  `json:"risk_level"`
}

EPSSScoreResponse is the response for an EPSS score.

type EdgeResponse

type EdgeResponse struct {
	ID            string `json:"id"`
	WorkflowID    string `json:"workflow_id"`
	SourceNodeKey string `json:"source_node_key"`
	TargetNodeKey string `json:"target_node_key"`
	SourceHandle  string `json:"source_handle,omitempty"`
	Label         string `json:"label,omitempty"`
	CreatedAt     string `json:"created_at"`
}

EdgeResponse represents an edge in the workflow response.

type EffectivePermissionsResponse

type EffectivePermissionsResponse struct {
	UserID      string   `json:"user_id"`
	TenantID    string   `json:"tenant_id"`
	Permissions []string `json:"permissions"`
	GroupCount  int      `json:"group_count"`
}

EffectivePermissionsResponse represents the effective permissions for a user.

type EmbeddedCategoryResponse

type EmbeddedCategoryResponse struct {
	ID          string `json:"id"`
	Name        string `json:"name"`         // slug: 'sast', 'dast', etc.
	DisplayName string `json:"display_name"` // 'SAST', 'DAST', etc.
	Icon        string `json:"icon"`
	Color       string `json:"color"`
}

EmbeddedCategoryResponse is a minimal category response for embedding in tools.

type EnrichCVEsRequest

type EnrichCVEsRequest struct {
	CVEIDs []string `json:"cve_ids"`
}

EnrichCVEsRequest is the request for enriching multiple CVEs.

type EnrichmentResponse

type EnrichmentResponse struct {
	CVEID          string   `json:"cve_id"`
	EPSSScore      *float64 `json:"epss_score,omitempty"`
	EPSSPercentile *float64 `json:"epss_percentile,omitempty"`
	InKEV          bool     `json:"in_kev"`
	KEVDateAdded   *string  `json:"kev_date_added,omitempty"`
	KEVDueDate     *string  `json:"kev_due_date,omitempty"`
	KEVRansomware  *string  `json:"kev_ransomware,omitempty"`
	RiskLevel      string   `json:"risk_level"`
}

EnrichmentResponse is the response for CVE enrichment.

type EvaluateQualityGateRequest

type EvaluateQualityGateRequest struct {
	Critical int `json:"critical"`
	High     int `json:"high"`
	Medium   int `json:"medium"`
	Low      int `json:"low"`
	Info     int `json:"info"`
}

EvaluateQualityGateRequest represents the request body for evaluating quality gate.

type ExchangeTokenRequest

type ExchangeTokenRequest struct {
	RefreshToken string `json:"refresh_token"` // Optional if cookie is present
	TenantID     string `json:"tenant_id" validate:"required"`
}

ExchangeTokenRequest is the request body for token exchange. refresh_token can be omitted if sent via httpOnly cookie.

type ExchangeTokenResponse

type ExchangeTokenResponse struct {
	AccessToken string `json:"access_token"`
	TokenType   string `json:"token_type"`
	ExpiresIn   int64  `json:"expires_in"`
	TenantID    string `json:"tenant_id"`
	TenantSlug  string `json:"tenant_slug"`
	Role        string `json:"role"`
}

ExchangeTokenResponse is the response body for token exchange.

type ExposedServiceResponse

type ExposedServiceResponse struct {
	ID           string `json:"id" example:"550e8400-e29b-41d4-a716-446655440000"`
	Name         string `json:"name" example:"api.example.com"`
	Type         string `json:"type" example:"service"`
	Port         int    `json:"port,omitempty" example:"443"`
	Exposure     string `json:"exposure" example:"public"`
	Criticality  string `json:"criticality" example:"high"`
	FindingCount int    `json:"finding_count" example:"3"`
	LastSeen     string `json:"last_seen" example:"2024-01-15T10:30:00Z"`
}

ExposedServiceResponse represents an exposed service.

type ExposureHandler

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

ExposureHandler handles exposure event HTTP requests.

func NewExposureHandler

func NewExposureHandler(svc *app.ExposureService, userSvc *app.UserService, v *validator.Validator, log *logger.Logger) *ExposureHandler

NewExposureHandler creates a new exposure handler.

func (*ExposureHandler) Accept

func (h *ExposureHandler) Accept(w http.ResponseWriter, r *http.Request)

Accept handles POST /api/v1/exposures/{id}/accept @Summary Accept exposure @Description Accept an exposure as a known risk @Tags Exposures @Accept json @Produce json @Param id path string true "Exposure ID" @Param request body ChangeStateRequest false "Accept reason" @Success 200 {object} ExposureResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures/{id}/accept [post]

func (*ExposureHandler) BulkIngest

func (h *ExposureHandler) BulkIngest(w http.ResponseWriter, r *http.Request)

BulkIngest handles POST /api/v1/exposures/ingest @Summary Bulk ingest exposures @Description Ingest multiple exposure events at once @Tags Exposures @Accept json @Produce json @Param request body BulkIngestRequest true "Exposures to ingest" @Success 201 {object} map[string]interface{} @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures/ingest [post]

func (*ExposureHandler) Create

func (h *ExposureHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/exposures @Summary Create exposure @Description Create a new exposure event @Tags Exposures @Accept json @Produce json @Param request body CreateExposureRequest true "Exposure data" @Success 201 {object} ExposureResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures [post]

func (*ExposureHandler) Delete

func (h *ExposureHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/exposures/{id} @Summary Delete exposure @Description Delete an exposure event @Tags Exposures @Accept json @Produce json @Param id path string true "Exposure ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures/{id} [delete]

func (*ExposureHandler) Get

Get handles GET /api/v1/exposures/{id} @Summary Get exposure @Description Get a single exposure event by ID @Tags Exposures @Accept json @Produce json @Param id path string true "Exposure ID" @Success 200 {object} ExposureResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures/{id} [get]

func (*ExposureHandler) GetHistory

func (h *ExposureHandler) GetHistory(w http.ResponseWriter, r *http.Request)

GetHistory handles GET /api/v1/exposures/{id}/history @Summary Get exposure history @Description Get state change history for an exposure @Tags Exposures @Accept json @Produce json @Param id path string true "Exposure ID" @Success 200 {object} map[string]interface{} @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures/{id}/history [get]

func (*ExposureHandler) GetStats

func (h *ExposureHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats handles GET /api/v1/exposures/stats @Summary Get exposure statistics @Description Get aggregated statistics for exposure events @Tags Exposures @Accept json @Produce json @Success 200 {object} map[string]interface{} @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures/stats [get]

func (*ExposureHandler) List

List handles GET /api/v1/exposures @Summary List exposures @Description Get a paginated list of exposure events @Tags Exposures @Accept json @Produce json @Param asset_id query string false "Filter by asset ID" @Param event_type query []string false "Filter by event types" @Param severity query []string false "Filter by severities" @Param state query []string false "Filter by states" @Param search query string false "Search term" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ExposureResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures [get]

func (*ExposureHandler) MarkFalsePositive

func (h *ExposureHandler) MarkFalsePositive(w http.ResponseWriter, r *http.Request)

MarkFalsePositive handles POST /api/v1/exposures/{id}/false-positive @Summary Mark as false positive @Description Mark an exposure as a false positive @Tags Exposures @Accept json @Produce json @Param id path string true "Exposure ID" @Param request body ChangeStateRequest false "Reason" @Success 200 {object} ExposureResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures/{id}/false-positive [post]

func (*ExposureHandler) Reactivate

func (h *ExposureHandler) Reactivate(w http.ResponseWriter, r *http.Request)

Reactivate handles POST /api/v1/exposures/{id}/reactivate @Summary Reactivate exposure @Description Reactivate a resolved or accepted exposure @Tags Exposures @Accept json @Produce json @Param id path string true "Exposure ID" @Success 200 {object} ExposureResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures/{id}/reactivate [post]

func (*ExposureHandler) Resolve

func (h *ExposureHandler) Resolve(w http.ResponseWriter, r *http.Request)

Resolve handles POST /api/v1/exposures/{id}/resolve @Summary Resolve exposure @Description Mark an exposure as resolved @Tags Exposures @Accept json @Produce json @Param id path string true "Exposure ID" @Param request body ChangeStateRequest false "Resolution reason" @Success 200 {object} ExposureResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /exposures/{id}/resolve [post]

type ExposureResponse

type ExposureResponse struct {
	ID string `json:"id"`

	AssetID         string         `json:"asset_id,omitempty"`
	EventType       string         `json:"event_type"`
	Severity        string         `json:"severity"`
	State           string         `json:"state"`
	Title           string         `json:"title"`
	Description     string         `json:"description,omitempty"`
	Details         map[string]any `json:"details,omitempty"`
	Fingerprint     string         `json:"fingerprint"`
	Source          string         `json:"source"`
	FirstSeenAt     time.Time      `json:"first_seen_at"`
	LastSeenAt      time.Time      `json:"last_seen_at"`
	ResolvedAt      *time.Time     `json:"resolved_at,omitempty"`
	ResolvedBy      string         `json:"resolved_by,omitempty"`
	ResolutionNotes string         `json:"resolution_notes,omitempty"`
	CreatedAt       time.Time      `json:"created_at"`
	UpdatedAt       time.Time      `json:"updated_at"`
}

ExposureResponse represents an exposure event in API responses.

type FilteringResultResponse

type FilteringResultResponse struct {
	TotalAssets          int                  `json:"total_assets"`
	ScannedAssets        int                  `json:"scanned_assets"`
	SkippedAssets        int                  `json:"skipped_assets"`
	UnclassifiedAssets   int                  `json:"unclassified_assets"`
	CompatibilityPercent float64              `json:"compatibility_percent"`
	ScannedByType        map[string]int       `json:"scanned_by_type,omitempty"`
	SkippedByType        map[string]int       `json:"skipped_by_type,omitempty"`
	SkipReasons          []SkipReasonResponse `json:"skip_reasons,omitempty"`
	WasFiltered          bool                 `json:"was_filtered"`
	ToolName             string               `json:"tool_name,omitempty"`
	SupportedTargets     []string             `json:"supported_targets,omitempty"`
}

FilteringResultResponse represents smart filtering result in API response.

type FindingActionsHandler added in v0.1.3

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

FindingActionsHandler handles closed-loop finding lifecycle operations.

func NewFindingActionsHandler added in v0.1.3

func NewFindingActionsHandler(svc *app.FindingActionsService, log *logger.Logger) *FindingActionsHandler

NewFindingActionsHandler creates a new FindingActionsHandler.

func (*FindingActionsHandler) AssignToOwners added in v0.1.3

func (h *FindingActionsHandler) AssignToOwners(w http.ResponseWriter, r *http.Request)

AssignToOwners handles POST /api/v1/findings/actions/assign-to-owners

func (*FindingActionsHandler) FixApplied added in v0.1.3

func (h *FindingActionsHandler) FixApplied(w http.ResponseWriter, r *http.Request)

FixApplied handles POST /api/v1/findings/actions/fix-applied

func (*FindingActionsHandler) GetRelatedCVEs added in v0.1.3

func (h *FindingActionsHandler) GetRelatedCVEs(w http.ResponseWriter, r *http.Request)

GetRelatedCVEs handles GET /api/v1/findings/related-cves/{cveId}

func (*FindingActionsHandler) ListFindingGroups added in v0.1.3

func (h *FindingActionsHandler) ListFindingGroups(w http.ResponseWriter, r *http.Request)

ListFindingGroups handles GET /api/v1/findings/groups

func (*FindingActionsHandler) RejectFix added in v0.1.3

RejectFix handles POST /api/v1/findings/actions/reject-fix

func (*FindingActionsHandler) Verify added in v0.1.3

Verify handles POST /api/v1/findings/actions/verify

type FindingActivityHandler

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

FindingActivityHandler handles finding activity HTTP requests.

func NewFindingActivityHandler

func NewFindingActivityHandler(
	actSvc *app.FindingActivityService,
	vulnSvc *app.VulnerabilityService,
	log *logger.Logger,
) *FindingActivityHandler

NewFindingActivityHandler creates a new finding activity handler.

func (*FindingActivityHandler) GetActivity

func (h *FindingActivityHandler) GetActivity(w http.ResponseWriter, r *http.Request)

GetActivity handles GET /api/v1/findings/{id}/activities/{activity_id}

func (*FindingActivityHandler) ListActivities

func (h *FindingActivityHandler) ListActivities(w http.ResponseWriter, r *http.Request)

ListActivities handles GET /api/v1/findings/{id}/activities

type FindingActivityResponse

type FindingActivityResponse struct {
	ID             string                 `json:"id"`
	FindingID      string                 `json:"finding_id"`
	ActivityType   string                 `json:"activity_type"`
	ActorID        *string                `json:"actor_id,omitempty"`
	ActorType      string                 `json:"actor_type"`
	ActorName      string                 `json:"actor_name,omitempty"`
	ActorEmail     string                 `json:"actor_email,omitempty"`
	Changes        map[string]interface{} `json:"changes"`
	Source         string                 `json:"source,omitempty"`
	SourceMetadata map[string]interface{} `json:"source_metadata,omitempty"`
	CreatedAt      time.Time              `json:"created_at"`
}

FindingActivityResponse represents a finding activity in API responses.

type FindingAssetInfo

type FindingAssetInfo struct {
	ID     string `json:"id"`
	Name   string `json:"name"`
	Type   string `json:"type"`
	WebURL string `json:"web_url,omitempty"` // Repository web URL (e.g., github.com/org/repo)
}

FindingAssetInfo contains essential asset info for finding display.

type FindingAssignedUser

type FindingAssignedUser struct {
	ID    string `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
}

FindingAssignedUser contains basic info about the assigned user.

type FindingCommentResponse

type FindingCommentResponse struct {
	ID             string    `json:"id"`
	FindingID      string    `json:"finding_id"`
	AuthorID       string    `json:"author_id"`
	AuthorName     string    `json:"author_name,omitempty"`
	AuthorEmail    string    `json:"author_email,omitempty"`
	Content        string    `json:"content"`
	IsStatusChange bool      `json:"is_status_change"`
	OldStatus      string    `json:"old_status,omitempty"`
	NewStatus      string    `json:"new_status,omitempty"`
	CreatedAt      time.Time `json:"created_at"`
	UpdatedAt      time.Time `json:"updated_at"`
}

FindingCommentResponse represents a finding comment in API responses.

type FindingComponentInfo

type FindingComponentInfo struct {
	ID        string `json:"id"`                 // Global component ID
	Name      string `json:"name"`               // Package name (e.g., "lodash")
	Version   string `json:"version"`            // Package version (e.g., "4.17.20")
	Ecosystem string `json:"ecosystem"`          // Package ecosystem (e.g., "npm", "pypi")
	PURL      string `json:"purl,omitempty"`     // Package URL
	License   string `json:"license,omitempty"`  // License identifier
	IsDirect  bool   `json:"is_direct"`          // true if direct dependency
	Depth     int    `json:"depth"`              // Dependency depth (1=direct, 2+=transitive)
	FixedIn   string `json:"fixed_in,omitempty"` // Version that fixes the vulnerability
}

FindingComponentInfo contains component info for SCA findings. Industry-aligned with CycloneDX, Snyk, and Dependency-Track patterns.

func ToFindingComponentInfo

func ToFindingComponentInfo(c *component.Component, depth int, isDirect bool) *FindingComponentInfo

ToFindingComponentInfo converts a component to FindingComponentInfo. Used to enrich finding responses with component details for SCA findings. Exported so handlers can use it when enriching findings.

type FindingCountsResponse

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

FindingCountsResponse represents finding counts by severity.

type FindingFilterRequest added in v0.1.3

type FindingFilterRequest struct {
	CVEIDs    []string `json:"cve_ids" validate:"max=100,dive,max=255"`
	AssetTags []string `json:"asset_tags" validate:"max=100,dive,max=255"`
}

FindingFilterRequest is the filter in request body.

type FindingRemediationResponse

type FindingRemediationResponse struct {
	Recommendation string            `json:"recommendation,omitempty"` // Human-readable guidance
	FixCode        string            `json:"fix_code,omitempty"`       // Actual code to apply
	FixRegex       *FixRegexResponse `json:"fix_regex,omitempty"`      // Regex-based fix pattern
	Steps          []string          `json:"steps,omitempty"`          // Step-by-step instructions
	References     []string          `json:"references,omitempty"`     // Reference URLs
	Effort         string            `json:"effort,omitempty"`         // trivial, low, medium, high
	FixAvailable   bool              `json:"fix_available,omitempty"`  // Whether a fix is available
	AutoFixable    bool              `json:"auto_fixable,omitempty"`   // Whether the fix can be auto-applied
}

FindingRemediationResponse represents the remediation JSONB in API responses.

type FindingResponse

type FindingResponse struct {
	ID                  string                      `json:"id"`
	TenantID            string                      `json:"tenant_id"`
	VulnerabilityID     *string                     `json:"vulnerability_id,omitempty"`
	AssetID             string                      `json:"asset_id"`
	Asset               *FindingAssetInfo           `json:"asset,omitempty"` // Full asset info
	BranchID            *string                     `json:"branch_id,omitempty"`
	ComponentID         *string                     `json:"component_id,omitempty"`
	Component           *FindingComponentInfo       `json:"component,omitempty"` // Embedded component info for SCA findings
	Source              string                      `json:"source"`
	ToolName            string                      `json:"tool_name"`
	ToolID              *string                     `json:"tool_id,omitempty"`
	ToolVersion         string                      `json:"tool_version,omitempty"`
	RuleID              string                      `json:"rule_id,omitempty"`
	RuleName            string                      `json:"rule_name,omitempty"`
	FilePath            string                      `json:"file_path,omitempty"`
	StartLine           int                         `json:"start_line,omitempty"`
	EndLine             int                         `json:"end_line,omitempty"`
	StartColumn         int                         `json:"start_column,omitempty"`
	EndColumn           int                         `json:"end_column,omitempty"`
	Snippet             string                      `json:"snippet,omitempty"`
	ContextSnippet      string                      `json:"context_snippet,omitempty"`
	ContextStartLine    int                         `json:"context_start_line,omitempty"`
	Title               string                      `json:"title,omitempty"`
	Description         string                      `json:"description,omitempty"`
	Message             string                      `json:"message"`
	Recommendation      string                      `json:"recommendation,omitempty"`
	FixCode             string                      `json:"fix_code,omitempty"`    // Auto-fix code snippet
	FixRegex            *FixRegexResponse           `json:"fix_regex,omitempty"`   // Regex-based fix pattern
	Remediation         *FindingRemediationResponse `json:"remediation,omitempty"` // Full remediation JSONB
	Severity            string                      `json:"severity"`
	CVSSScore           *float64                    `json:"cvss_score,omitempty"`
	CVSSVector          string                      `json:"cvss_vector,omitempty"`
	CVEID               string                      `json:"cve_id,omitempty"`
	CWEIDs              []string                    `json:"cwe_ids,omitempty"`
	OWASPIDs            []string                    `json:"owasp_ids,omitempty"`
	Tags                []string                    `json:"tags,omitempty"`
	Status              string                      `json:"status"`
	Resolution          string                      `json:"resolution,omitempty"`
	ResolvedAt          *time.Time                  `json:"resolved_at,omitempty"`
	ResolvedBy          *string                     `json:"resolved_by,omitempty"` // User ID who resolved
	IsTriaged           bool                        `json:"is_triaged"`            // true if status != "new"
	AssignedTo          *string                     `json:"assigned_to,omitempty"`
	AssignedToUser      *FindingAssignedUser        `json:"assigned_to_user,omitempty"` // Full user info
	AssignedAt          *time.Time                  `json:"assigned_at,omitempty"`
	AssignedBy          *string                     `json:"assigned_by,omitempty"`
	VerifiedAt          *time.Time                  `json:"verified_at,omitempty"`
	VerifiedBy          *string                     `json:"verified_by,omitempty"`
	SLADeadline         *time.Time                  `json:"sla_deadline,omitempty"`
	SLAStatus           string                      `json:"sla_status,omitempty"`
	FirstDetectedAt     time.Time                   `json:"first_detected_at,omitempty"`
	LastSeenAt          time.Time                   `json:"last_seen_at,omitempty"`
	FirstDetectedBranch string                      `json:"first_detected_branch,omitempty"`
	FirstDetectedCommit string                      `json:"first_detected_commit,omitempty"`
	LastSeenBranch      string                      `json:"last_seen_branch,omitempty"`
	LastSeenCommit      string                      `json:"last_seen_commit,omitempty"`
	DuplicateOf         *string                     `json:"duplicate_of,omitempty"`
	DuplicateCount      int                         `json:"duplicate_count"`
	CommentsCount       int                         `json:"comments_count"`
	ScanID              string                      `json:"scan_id,omitempty"`
	Fingerprint         string                      `json:"fingerprint"`
	Location            string                      `json:"location,omitempty"`
	Metadata            map[string]any              `json:"metadata,omitempty"`
	CreatedAt           time.Time                   `json:"created_at"`
	UpdatedAt           time.Time                   `json:"updated_at"`

	// SARIF 2.1.0 Fields
	Confidence          *int                            `json:"confidence,omitempty"`
	Impact              string                          `json:"impact,omitempty"`
	Likelihood          string                          `json:"likelihood,omitempty"`
	VulnerabilityClass  []string                        `json:"vulnerability_class,omitempty"`
	Subcategory         []string                        `json:"subcategory,omitempty"`
	BaselineState       string                          `json:"baseline_state,omitempty"`
	Kind                string                          `json:"kind,omitempty"`
	Rank                *float64                        `json:"rank,omitempty"`
	OccurrenceCount     int                             `json:"occurrence_count,omitempty"`
	CorrelationID       string                          `json:"correlation_id,omitempty"`
	PartialFingerprints map[string]string               `json:"partial_fingerprints,omitempty"`
	RelatedLocations    []vulnerability.FindingLocation `json:"related_locations,omitempty"`
	Stacks              []vulnerability.StackTrace      `json:"stacks,omitempty"`
	Attachments         []vulnerability.Attachment      `json:"attachments,omitempty"`
	WorkItemURIs        []string                        `json:"work_item_uris,omitempty"`
	HostedViewerURI     string                          `json:"hosted_viewer_uri,omitempty"`

	// CTEM Fields
	ExposureVector       string   `json:"exposure_vector,omitempty"`
	IsNetworkAccessible  bool     `json:"is_network_accessible,omitempty"`
	IsInternetAccessible bool     `json:"is_internet_accessible,omitempty"`
	AttackPrerequisites  string   `json:"attack_prerequisites,omitempty"`
	RemediationType      string   `json:"remediation_type,omitempty"`
	EstimatedFixTime     *int     `json:"estimated_fix_time,omitempty"`
	FixComplexity        string   `json:"fix_complexity,omitempty"`
	RemedyAvailable      bool     `json:"remedy_available,omitempty"`
	DataExposureRisk     string   `json:"data_exposure_risk,omitempty"`
	ReputationalImpact   bool     `json:"reputational_impact,omitempty"`
	ComplianceImpact     []string `json:"compliance_impact,omitempty"`

	// Finding Type discriminator
	FindingType string `json:"finding_type,omitempty"` // vulnerability, secret, misconfiguration, compliance, web3

	// Data Flow / Taint Tracking (Attack Path)
	HasDataFlow bool              `json:"has_data_flow,omitempty"` // Lightweight flag for list views
	DataFlow    *DataFlowResponse `json:"data_flow,omitempty"`     // Full data when fetching single finding

	// Secret-specific fields
	SecretType          string     `json:"secret_type,omitempty"`
	SecretService       string     `json:"secret_service,omitempty"`
	SecretValid         *bool      `json:"secret_valid,omitempty"`
	SecretRevoked       *bool      `json:"secret_revoked,omitempty"`
	SecretMaskedValue   string     `json:"secret_masked_value,omitempty"`
	SecretEntropy       *float64   `json:"secret_entropy,omitempty"`
	SecretScopes        []string   `json:"secret_scopes,omitempty"`
	SecretExpiresAt     *time.Time `json:"secret_expires_at,omitempty"`
	SecretRotationDueAt *time.Time `json:"secret_rotation_due_at,omitempty"`
	SecretAgeInDays     *int       `json:"secret_age_in_days,omitempty"`
	SecretCommitCount   *int       `json:"secret_commit_count,omitempty"`
	SecretInHistoryOnly *bool      `json:"secret_in_history_only,omitempty"`
	SecretVerifiedAt    *time.Time `json:"secret_verified_at,omitempty"`

	// Compliance-specific fields
	ComplianceFramework          string `json:"compliance_framework,omitempty"`
	ComplianceFrameworkVersion   string `json:"compliance_framework_version,omitempty"`
	ComplianceControlID          string `json:"compliance_control_id,omitempty"`
	ComplianceControlName        string `json:"compliance_control_name,omitempty"`
	ComplianceControlDescription string `json:"compliance_control_description,omitempty"`
	ComplianceResult             string `json:"compliance_result,omitempty"`
	ComplianceSection            string `json:"compliance_section,omitempty"`

	// Web3-specific fields
	Web3Chain             string `json:"web3_chain,omitempty"`
	Web3ChainID           *int64 `json:"web3_chain_id,omitempty"`
	Web3ContractAddress   string `json:"web3_contract_address,omitempty"`
	Web3SwcID             string `json:"web3_swc_id,omitempty"`
	Web3FunctionSignature string `json:"web3_function_signature,omitempty"`
	Web3TxHash            string `json:"web3_tx_hash,omitempty"`
	Web3FunctionSelector  string `json:"web3_function_selector,omitempty"`
	Web3BytecodeOffset    *int   `json:"web3_bytecode_offset,omitempty"`

	// Misconfiguration-specific fields
	MisconfigPolicyID     string `json:"misconfig_policy_id,omitempty"`
	MisconfigPolicyName   string `json:"misconfig_policy_name,omitempty"`
	MisconfigResourceType string `json:"misconfig_resource_type,omitempty"`
	MisconfigResourceName string `json:"misconfig_resource_name,omitempty"`
	MisconfigResourcePath string `json:"misconfig_resource_path,omitempty"`
	MisconfigExpected     string `json:"misconfig_expected,omitempty"`
	MisconfigActual       string `json:"misconfig_actual,omitempty"`
	MisconfigCause        string `json:"misconfig_cause,omitempty"`
}

FindingResponse represents a finding in API responses.

type FindingSeverityResponse added in v0.1.3

type FindingSeverityResponse struct {
	Critical int `json:"critical"`
	High     int `json:"high"`
	Medium   int `json:"medium"`
	Low      int `json:"low"`
	Info     int `json:"info"`
}

FindingSeverityResponse represents finding counts by severity level.

type FindingSourceCategoryResponse

type FindingSourceCategoryResponse struct {
	ID           string    `json:"id"`
	Code         string    `json:"code"`
	Name         string    `json:"name"`
	Description  string    `json:"description,omitempty"`
	Icon         string    `json:"icon,omitempty"`
	DisplayOrder int       `json:"display_order"`
	IsActive     bool      `json:"is_active"`
	CreatedAt    time.Time `json:"created_at"`
	UpdatedAt    time.Time `json:"updated_at"`
}

FindingSourceCategoryResponse represents a category in API responses.

type FindingSourceHandler

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

FindingSourceHandler handles finding source-related HTTP requests. Finding sources are read-only system configuration.

func NewFindingSourceHandler

NewFindingSourceHandler creates a new finding source handler.

func (*FindingSourceHandler) GetCategory

func (h *FindingSourceHandler) GetCategory(w http.ResponseWriter, r *http.Request)

GetCategory handles GET /api/v1/config/finding-sources/categories/{categoryId} @Summary Get a category by ID @Description Retrieves a single finding source category by its unique identifier @Tags Configuration @Accept json @Produce json @Security BearerAuth @Param categoryId path string true "Category ID (UUID)" @Success 200 {object} FindingSourceCategoryResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /config/finding-sources/categories/{categoryId} [get]

func (*FindingSourceHandler) GetFindingSource

func (h *FindingSourceHandler) GetFindingSource(w http.ResponseWriter, r *http.Request)

GetFindingSource handles GET /api/v1/config/finding-sources/{id} @Summary Get a finding source by ID @Description Retrieves a single system finding source by its unique identifier @Tags Configuration @Accept json @Produce json @Security BearerAuth @Param id path string true "Finding Source ID (UUID)" @Success 200 {object} FindingSourceResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /config/finding-sources/{id} [get]

func (*FindingSourceHandler) GetFindingSourceByCode

func (h *FindingSourceHandler) GetFindingSourceByCode(w http.ResponseWriter, r *http.Request)

GetFindingSourceByCode handles GET /api/v1/config/finding-sources/code/{code} @Summary Get a finding source by code @Description Retrieves a single system finding source by its code (e.g., 'sast', 'dast', 'pentest') @Tags Configuration @Accept json @Produce json @Security BearerAuth @Param code path string true "Finding Source Code" @Success 200 {object} FindingSourceResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /config/finding-sources/code/{code} [get]

func (*FindingSourceHandler) ListCategories

func (h *FindingSourceHandler) ListCategories(w http.ResponseWriter, r *http.Request)

ListCategories handles GET /api/v1/config/finding-sources/categories @Summary List finding source categories @Description Retrieves a paginated list of finding source categories. Use active_only=true to get all active categories without pagination. @Tags Configuration @Accept json @Produce json @Security BearerAuth @Param active_only query bool false "Return only active categories (bypasses pagination)" @Param search query string false "Search by name or code" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} object{data=[]FindingSourceCategoryResponse,total=int,page=int,per_page=int,total_pages=int} @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /config/finding-sources/categories [get]

func (*FindingSourceHandler) ListFindingSources

func (h *FindingSourceHandler) ListFindingSources(w http.ResponseWriter, r *http.Request)

ListFindingSources handles GET /api/v1/config/finding-sources @Summary List finding sources @Description Retrieves a paginated list of system finding sources. Finding sources are read-only configuration. Use active_only=true to get all active sources without pagination. @Tags Configuration @Accept json @Produce json @Security BearerAuth @Param active_only query bool false "Return only active finding sources (bypasses pagination)" @Param include_category query bool false "Include category details in response" @Param search query string false "Search by name or code" @Param category_id query string false "Filter by category ID" @Param category_code query string false "Filter by category code" @Param code query string false "Filter by exact code" @Param is_system query bool false "Filter by system type" @Param sort query string false "Sort field (e.g., 'name', '-display_order')" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(50) @Success 200 {object} object{data=[]FindingSourceResponse,total=int,page=int,per_page=int,total_pages=int} @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /config/finding-sources [get]

type FindingSourceResponse

type FindingSourceResponse struct {
	ID           string                         `json:"id"`
	CategoryID   string                         `json:"category_id,omitempty"`
	Category     *FindingSourceCategoryResponse `json:"category,omitempty"`
	Code         string                         `json:"code"`
	Name         string                         `json:"name"`
	Description  string                         `json:"description,omitempty"`
	Icon         string                         `json:"icon,omitempty"`
	Color        string                         `json:"color,omitempty"`
	DisplayOrder int                            `json:"display_order"`
	IsSystem     bool                           `json:"is_system"`
	IsActive     bool                           `json:"is_active"`
	CreatedAt    time.Time                      `json:"created_at"`
	UpdatedAt    time.Time                      `json:"updated_at"`
}

FindingSourceResponse represents a finding source in API responses.

type FindingStats

type FindingStats struct {
	Total       int            `json:"total"`
	BySeverity  map[string]int `json:"by_severity"`
	ByStatus    map[string]int `json:"by_status"`
	Overdue     int            `json:"overdue"`
	AverageCVSS float64        `json:"average_cvss"`
}

FindingStats represents finding statistics.

type FindingStatsResponse

type FindingStatsResponse struct {
	Total         int64            `json:"total"`
	BySeverity    map[string]int64 `json:"by_severity"`
	ByStatus      map[string]int64 `json:"by_status"`
	BySource      map[string]int64 `json:"by_source"`
	OpenCount     int64            `json:"open_count"`
	ResolvedCount int64            `json:"resolved_count"`
}

FindingStatsResponse represents finding statistics in API responses.

type FindingTrendPoint added in v0.1.2

type FindingTrendPoint struct {
	Date     string `json:"date"`
	Critical int    `json:"critical"`
	High     int    `json:"high"`
	Medium   int    `json:"medium"`
	Low      int    `json:"low"`
	Info     int    `json:"info"`
}

FindingTrendPoint represents one month's finding counts by severity.

type FixAppliedRequest added in v0.1.3

type FixAppliedRequest struct {
	Filter             FindingFilterRequest `json:"filter"`
	IncludeRelatedCVEs bool                 `json:"include_related_cves"`
	Note               string               `json:"note" validate:"max=5000"`
	Reference          string               `json:"reference" validate:"max=1000"`
}

FixAppliedRequest is the request body for POST /api/v1/findings/actions/fix-applied

type FixRegexResponse

type FixRegexResponse struct {
	Regex       string `json:"regex"`           // Regex pattern to match
	Replacement string `json:"replacement"`     // Replacement string
	Count       int    `json:"count,omitempty"` // Number of replacements (0 = all)
}

FixRegexResponse represents a regex-based fix pattern.

type ForgotPasswordRequest

type ForgotPasswordRequest struct {
	Email string `json:"email" validate:"required,email"`
}

ForgotPasswordRequest is the request body for forgot password.

type GCPServiceAccountDataRequest

type GCPServiceAccountDataRequest struct {
	JSONKey string `json:"json_key" validate:"required"`
}

GCPServiceAccountDataRequest represents GCP service account credential data.

type GeneralSettingsResponse

type GeneralSettingsResponse struct {
	Timezone string `json:"timezone"`
	Language string `json:"language"`
	Industry string `json:"industry"`
	Website  string `json:"website"`
}

GeneralSettingsResponse represents general settings.

type GitHubAppDataRequest

type GitHubAppDataRequest struct {
	AppID          string `json:"app_id" validate:"required"`
	InstallationID string `json:"installation_id" validate:"required"`
	PrivateKey     string `json:"private_key" validate:"required"`
}

GitHubAppDataRequest represents GitHub App credential data.

type GitLabTokenDataRequest

type GitLabTokenDataRequest struct {
	Token string `json:"token" validate:"required"`
}

GitLabTokenDataRequest represents GitLab token credential data.

type GroupAssetResponse

type GroupAssetResponse struct {
	ID           string `json:"id"`
	Name         string `json:"name"`
	Type         string `json:"type"`
	Status       string `json:"status"`
	RiskScore    int    `json:"risk_score"`
	FindingCount int    `json:"finding_count"`
	LastSeen     string `json:"last_seen"`
}

GroupAssetResponse represents an asset in group context.

type GroupFindingResponse

type GroupFindingResponse struct {
	ID           string `json:"id"`
	Title        string `json:"title"`
	Severity     string `json:"severity"`
	Status       string `json:"status"`
	AssetID      string `json:"asset_id"`
	AssetName    string `json:"asset_name"`
	AssetType    string `json:"asset_type"`
	DiscoveredAt string `json:"discovered_at"`
}

GroupFindingResponse represents a finding in group context.

type GroupHandler

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

GroupHandler handles group-related HTTP requests for the Access Control system.

func NewGroupHandler

func NewGroupHandler(svc *app.GroupService, v *validator.Validator, log *logger.Logger) *GroupHandler

NewGroupHandler creates a new group handler.

func (*GroupHandler) AddMember

func (h *GroupHandler) AddMember(w http.ResponseWriter, r *http.Request)

AddMember handles POST /api/v1/groups/{groupId}/members @Summary Add a member to a group @Description Add a user as a member of the group @Tags groups @Accept json @Produce json @Param groupId path string true "Group ID" @Param request body AddGroupMemberRequest true "Member details" @Success 201 {object} GroupMemberResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/members [post]

func (*GroupHandler) AssignAsset

func (h *GroupHandler) AssignAsset(w http.ResponseWriter, r *http.Request)

AssignAsset handles POST /api/v1/groups/{groupId}/assets @Summary Assign an asset to a group @Description Assign an asset to the group with specified ownership type @Tags groups @Accept json @Produce json @Param groupId path string true "Group ID" @Param request body AssignAssetRequest true "Asset assignment details" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/assets [post]

func (*GroupHandler) AssignPermissionSet

func (h *GroupHandler) AssignPermissionSet(w http.ResponseWriter, r *http.Request)

AssignPermissionSet handles POST /api/v1/groups/{groupId}/permission-sets @Summary Assign a permission set to a group @Description Assign a permission set to the group @Tags groups @Accept json @Produce json @Param groupId path string true "Group ID" @Param request body AssignPermissionSetRequest true "Permission set details" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/permission-sets [post]

func (*GroupHandler) BulkAssignAssets added in v0.1.2

func (h *GroupHandler) BulkAssignAssets(w http.ResponseWriter, r *http.Request)

BulkAssignAssets handles POST /api/v1/groups/{groupId}/assets/bulk

func (*GroupHandler) CreateGroup

func (h *GroupHandler) CreateGroup(w http.ResponseWriter, r *http.Request)

CreateGroup handles POST /api/v1/groups @Summary Create a new group @Description Create a new group for access control @Tags groups @Accept json @Produce json @Param request body CreateGroupRequest true "Group details" @Success 201 {object} GroupResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 403 {object} apierror.Error @Router /api/v1/groups [post]

func (*GroupHandler) DeleteGroup

func (h *GroupHandler) DeleteGroup(w http.ResponseWriter, r *http.Request)

DeleteGroup handles DELETE /api/v1/groups/{groupId} @Summary Delete a group @Description Delete a group @Tags groups @Param groupId path string true "Group ID" @Success 204 "No Content" @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId} [delete]

func (*GroupHandler) GetGroup

func (h *GroupHandler) GetGroup(w http.ResponseWriter, r *http.Request)

GetGroup handles GET /api/v1/groups/{groupId} @Summary Get a group by ID @Description Get a group's details @Tags groups @Produce json @Param groupId path string true "Group ID" @Success 200 {object} GroupResponse @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId} [get]

func (*GroupHandler) ListAssignedPermissionSets

func (h *GroupHandler) ListAssignedPermissionSets(w http.ResponseWriter, r *http.Request)

ListAssignedPermissionSets handles GET /api/v1/groups/{groupId}/permission-sets @Summary List permission sets assigned to a group @Description Get all permission sets assigned to the group with full details @Tags groups @Produce json @Param groupId path string true "Group ID" @Success 200 {array} PermissionSetResponse @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/permission-sets [get]

func (*GroupHandler) ListGroupAssets

func (h *GroupHandler) ListGroupAssets(w http.ResponseWriter, r *http.Request)

ListGroupAssets handles GET /api/v1/groups/{groupId}/assets @Summary List assets assigned to a group @Description List all assets that belong to this group @Tags groups @Produce json @Param groupId path string true "Group ID" @Success 200 {array} GroupOwnershipResponse @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/assets [get]

func (*GroupHandler) ListGroups

func (h *GroupHandler) ListGroups(w http.ResponseWriter, r *http.Request)

ListGroups handles GET /api/v1/groups @Summary List groups @Description List all groups in the tenant with optional filtering @Tags groups @Produce json @Param type query string false "Filter by group type" @Param active query bool false "Filter by active status" @Param search query string false "Search by name or slug" @Param limit query int false "Limit results" default(20) @Param offset query int false "Offset for pagination" default(0) @Success 200 {object} GroupListResponse @Router /api/v1/groups [get]

func (*GroupHandler) ListMembers

func (h *GroupHandler) ListMembers(w http.ResponseWriter, r *http.Request)

ListMembers handles GET /api/v1/groups/{groupId}/members @Summary List group members @Description List all members of a group with user details @Tags groups @Produce json @Param groupId path string true "Group ID" @Success 200 {array} GroupMemberWithUserResponse @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/members [get]

func (*GroupHandler) ListMyAssets

func (h *GroupHandler) ListMyAssets(w http.ResponseWriter, r *http.Request)

ListMyAssets handles GET /api/v1/me/assets @Summary List current user's accessible assets @Description List all assets the current user can access through their group memberships @Tags assets @Produce json @Success 200 {object} map[string]interface{} @Router /api/v1/me/assets [get]

func (*GroupHandler) ListMyGroups

func (h *GroupHandler) ListMyGroups(w http.ResponseWriter, r *http.Request)

ListMyGroups handles GET /api/v1/me/groups @Summary List current user's groups @Description List all groups the current user belongs to @Tags groups @Produce json @Success 200 {array} GroupWithRoleResponse @Router /api/v1/me/groups [get]

func (*GroupHandler) RemoveMember

func (h *GroupHandler) RemoveMember(w http.ResponseWriter, r *http.Request)

RemoveMember handles DELETE /api/v1/groups/{groupId}/members/{userId} @Summary Remove a member from a group @Description Remove a user from the group @Tags groups @Param groupId path string true "Group ID" @Param userId path string true "User ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/members/{userId} [delete]

func (*GroupHandler) TriggerSync added in v0.1.2

func (h *GroupHandler) TriggerSync(w http.ResponseWriter, r *http.Request)

TriggerSync handles POST /api/v1/groups/sync @Summary Trigger manual group sync @Description Trigger a manual sync of groups from external providers for the current tenant @Tags groups @Produce json @Success 200 {object} map[string]interface{} @Failure 500 {object} apierror.Error @Router /api/v1/groups/sync [post]

func (*GroupHandler) UnassignAsset

func (h *GroupHandler) UnassignAsset(w http.ResponseWriter, r *http.Request)

UnassignAsset handles DELETE /api/v1/groups/{groupId}/assets/{assetId} @Summary Remove an asset from a group @Description Remove an asset ownership from the group @Tags groups @Param groupId path string true "Group ID" @Param assetId path string true "Asset ID" @Success 204 "No Content" @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/assets/{assetId} [delete]

func (*GroupHandler) UnassignPermissionSet

func (h *GroupHandler) UnassignPermissionSet(w http.ResponseWriter, r *http.Request)

UnassignPermissionSet handles DELETE /api/v1/groups/{groupId}/permission-sets/{permissionSetId} @Summary Remove a permission set from a group @Description Remove a permission set assignment from the group @Tags groups @Param groupId path string true "Group ID" @Param permissionSetId path string true "Permission Set ID" @Success 204 "No Content" @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/permission-sets/{permissionSetId} [delete]

func (*GroupHandler) UpdateAssetOwnership

func (h *GroupHandler) UpdateAssetOwnership(w http.ResponseWriter, r *http.Request)

UpdateAssetOwnership handles PUT /api/v1/groups/{groupId}/assets/{assetId} @Summary Update asset ownership type @Description Update the ownership type for an asset in a group @Tags groups @Accept json @Produce json @Param groupId path string true "Group ID" @Param assetId path string true "Asset ID" @Param request body UpdateAssetOwnershipRequest true "Ownership details" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/assets/{assetId} [put]

func (*GroupHandler) UpdateGroup

func (h *GroupHandler) UpdateGroup(w http.ResponseWriter, r *http.Request)

UpdateGroup handles PUT /api/v1/groups/{groupId} @Summary Update a group @Description Update a group's details @Tags groups @Accept json @Produce json @Param groupId path string true "Group ID" @Param request body UpdateGroupRequest true "Update details" @Success 200 {object} GroupResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId} [put]

func (*GroupHandler) UpdateMemberRole

func (h *GroupHandler) UpdateMemberRole(w http.ResponseWriter, r *http.Request)

UpdateMemberRole handles PUT /api/v1/groups/{groupId}/members/{userId} @Summary Update a member's role @Description Update the role of a group member @Tags groups @Accept json @Produce json @Param groupId path string true "Group ID" @Param userId path string true "User ID" @Param request body UpdateGroupMemberRoleRequest true "Role update" @Success 200 {object} GroupMemberResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/groups/{groupId}/members/{userId} [put]

func (*GroupHandler) WithSyncService added in v0.1.2

func (h *GroupHandler) WithSyncService(syncService *app.GroupSyncService) *GroupHandler

WithSyncService sets the group sync service on the handler.

type GroupListResponse

type GroupListResponse struct {
	Groups            []GroupResponse `json:"groups"`
	TotalCount        int64           `json:"total_count"`
	UniqueMemberCount int             `json:"unique_member_count"`
	Limit             int             `json:"limit"`
	Offset            int             `json:"offset"`
}

GroupListResponse represents a paginated list of groups.

type GroupMemberResponse

type GroupMemberResponse struct {
	UserID   string    `json:"user_id"`
	Role     string    `json:"role"`
	JoinedAt time.Time `json:"joined_at"`
	AddedBy  string    `json:"added_by,omitempty"`
}

GroupMemberResponse represents a group member in API responses.

type GroupMemberWithUserResponse

type GroupMemberWithUserResponse struct {
	UserID      string    `json:"user_id"`
	Role        string    `json:"role"`
	JoinedAt    time.Time `json:"joined_at"`
	AddedBy     string    `json:"added_by,omitempty"`
	AddedByName string    `json:"added_by_name,omitempty"`
	Email       string    `json:"email"`
	Name        string    `json:"name"`
	AvatarURL   string    `json:"avatar_url,omitempty"`
}

GroupMemberWithUserResponse represents a member with user details.

type GroupOwnershipResponse added in v0.1.2

type GroupOwnershipResponse struct {
	ID            string              `json:"id"`
	AssetID       string              `json:"asset_id"`
	GroupID       string              `json:"group_id,omitempty"`
	UserID        string              `json:"user_id,omitempty"`
	OwnershipType string              `json:"ownership_type"`
	AssignedAt    string              `json:"assigned_at"`
	AssignedBy    string              `json:"assigned_by,omitempty"`
	Asset         *AssetBriefResponse `json:"asset,omitempty"`
}

GroupOwnershipResponse represents an asset ownership in group API responses.

type GroupResponse

type GroupResponse struct {
	ID                 string                   `json:"id"`
	TenantID           string                   `json:"tenant_id"`
	Name               string                   `json:"name"`
	Slug               string                   `json:"slug"`
	Description        string                   `json:"description,omitempty"`
	GroupType          string                   `json:"group_type"`
	IsActive           bool                     `json:"is_active"`
	Settings           group.GroupSettings      `json:"settings,omitempty"`
	NotificationConfig group.NotificationConfig `json:"notification_config,omitempty"`
	MemberCount        int                      `json:"member_count"`
	AssetCount         int                      `json:"asset_count"`
	CreatedAt          time.Time                `json:"created_at"`
	UpdatedAt          time.Time                `json:"updated_at"`
}

GroupResponse represents a group in API responses.

type GroupWithRoleResponse

type GroupWithRoleResponse struct {
	GroupResponse
	Role     string    `json:"role"`
	JoinedAt time.Time `json:"joined_at"`
}

GroupWithRoleResponse represents a group with the user's role.

type HealthHandler

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

HealthHandler handles health check endpoints.

func NewHealthHandler

func NewHealthHandler(opts ...HealthHandlerOption) *HealthHandler

NewHealthHandler creates a new health handler.

func (*HealthHandler) Health

func (h *HealthHandler) Health(w http.ResponseWriter, _ *http.Request)

Health handles the /health endpoint (liveness probe). @Summary Health check @Description Returns the health status of the service (liveness probe) @Tags Health @Produce json @Success 200 {object} HealthResponse @Router /health [get]

func (*HealthHandler) Ready

func (h *HealthHandler) Ready(w http.ResponseWriter, r *http.Request)

Ready handles the /ready endpoint (readiness probe). @Summary Readiness check @Description Checks all dependencies and returns 503 if any are unhealthy @Tags Health @Produce json @Success 200 {object} ReadyResponse @Failure 503 {object} ReadyResponse @Router /ready [get]

type HealthHandlerOption

type HealthHandlerOption func(*HealthHandler)

HealthHandlerOption configures the health handler.

func WithDatabase

func WithDatabase(db Pinger) HealthHandlerOption

WithDatabase adds database health check.

func WithRedis

func WithRedis(redis Pinger) HealthHandlerOption

WithRedis adds Redis health check.

type HealthResponse

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

HealthResponse represents the health check response.

type HeartbeatRequest

type HeartbeatRequest struct {
	Name          string   `json:"name,omitempty"`
	Status        string   `json:"status"`
	Version       string   `json:"version,omitempty"`
	Hostname      string   `json:"hostname,omitempty"`
	Message       string   `json:"message,omitempty"`
	Scanners      []string `json:"scanners,omitempty"`
	Collectors    []string `json:"collectors,omitempty"`
	Uptime        int64    `json:"uptime_seconds,omitempty"`
	TotalScans    int64    `json:"total_scans,omitempty"`
	Errors        int64    `json:"errors,omitempty"`
	CPUPercent    float64  `json:"cpu_percent,omitempty"`
	MemoryPercent float64  `json:"memory_percent,omitempty"`
	ActiveJobs    int      `json:"active_jobs,omitempty"`
	Region        string   `json:"region,omitempty"`
}

HeartbeatRequest represents the heartbeat payload from agents.

type ImportMetadataRequest

type ImportMetadataRequest struct {
	SourceTool  string `json:"source_tool,omitempty" validate:"max=100"`
	BatchID     string `json:"batch_id,omitempty" validate:"max=100"`
	Description string `json:"description,omitempty" validate:"max=1000"`
}

ImportMetadataRequest represents import metadata in the request.

type ImportOptionsRequest

type ImportOptionsRequest struct {
	DedupStrategy        string `json:"dedup_strategy,omitempty" validate:"omitempty,oneof=skip update upsert"`
	ReactivateResolved   bool   `json:"reactivate_resolved"`
	NotifyReactivated    bool   `json:"notify_reactivated"`
	NotifyNewCritical    bool   `json:"notify_new_critical"`
	AutoClassifySeverity bool   `json:"auto_classify_severity"`
}

ImportOptionsRequest represents import options in the request.

type IngestHandler

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

IngestHandler handles ingestion-related HTTP requests. It supports CTIS, SARIF, Recon, and raw scanner output formats.

func NewIngestHandler

func NewIngestHandler(
	ingestSvc *ingest.Service,
	agentSvc *app.AgentService,
	log *logger.Logger,
) *IngestHandler

NewIngestHandler creates a new ingest handler.

func (*IngestHandler) AuthenticateSource

func (h *IngestHandler) AuthenticateSource(next http.Handler) http.Handler

AuthenticateSource is middleware that authenticates the agent by API key.

func (*IngestHandler) CheckFingerprints

func (h *IngestHandler) CheckFingerprints(w http.ResponseWriter, r *http.Request)

CheckFingerprints handles POST /api/v1/ingest/check @Summary Check fingerprints @Description Check if fingerprints already exist for deduplication @Tags Agent @Accept json @Produce json @Param request body CheckFingerprintsRequest true "Fingerprints to check" @Success 200 {object} CheckFingerprintsResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security ApiKeyAuth @Router /ingest/check [post]

func (*IngestHandler) Heartbeat

func (h *IngestHandler) Heartbeat(w http.ResponseWriter, r *http.Request)

Heartbeat handles POST /api/v1/agent/heartbeat @Summary Agent heartbeat @Description Send a heartbeat to indicate agent is alive @Tags Agent @Accept json @Produce json @Param request body HeartbeatRequest false "Heartbeat data" @Success 200 {object} map[string]interface{} @Failure 401 {object} apierror.Error @Security ApiKeyAuth @Router /agent/heartbeat [post]

func (*IngestHandler) IngestCTIS

func (h *IngestHandler) IngestCTIS(w http.ResponseWriter, r *http.Request)

IngestCTIS handles POST /api/v1/agent/ingest/ctis @Summary Ingest CTIS report @Description Ingest a full CTIS (CTEM Ingest Schema) report containing assets and findings @Tags Agent @Accept json @Produce json @Param request body CTISIngestRequest true "CTIS report" @Success 201 {object} IngestResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security ApiKeyAuth @Router /agent/ingest/ctis [post]

func (*IngestHandler) IngestChunk

func (h *IngestHandler) IngestChunk(w http.ResponseWriter, r *http.Request)

IngestChunk handles POST /api/v1/agent/ingest/chunk @Summary Ingest CTIS report chunk @Description Ingest a single chunk of a large CTIS report. Used for reports that exceed single upload limits. @Tags Agent @Accept json @Produce json @Param request body ChunkIngestRequest true "Chunk data" @Success 201 {object} ChunkIngestResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security ApiKeyAuth @Router /agent/ingest/chunk [post]

func (*IngestHandler) IngestReconReport

func (h *IngestHandler) IngestReconReport(w http.ResponseWriter, r *http.Request)

IngestReconReport handles POST /api/v1/agent/ingest/recon @Summary Ingest recon results @Description Ingest reconnaissance scan results (subdomains, DNS, ports, etc.) @Tags Agent @Accept json @Produce json @Param request body ReconIngestRequest true "Recon results" @Success 201 {object} IngestResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security ApiKeyAuth @Router /agent/ingest/recon [post]

func (*IngestHandler) IngestSARIF

func (h *IngestHandler) IngestSARIF(w http.ResponseWriter, r *http.Request)

IngestSARIF handles POST /api/v1/agent/ingest/sarif @Summary Ingest SARIF results @Description Ingest scan results in SARIF 2.1.0 format @Tags Agent @Accept json @Produce json @Param request body object true "SARIF data" @Success 201 {object} IngestResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security ApiKeyAuth @Router /agent/ingest/sarif [post]

func (*IngestHandler) IngestScan added in v0.1.3

func (h *IngestHandler) IngestScan(w http.ResponseWriter, r *http.Request)

IngestScan handles POST /api/v1/agent/ingest/scan It accepts raw scanner output and uses the appropriate adapter to convert to CTIS.

func (*IngestHandler) ListScanners added in v0.1.3

func (h *IngestHandler) ListScanners(w http.ResponseWriter, r *http.Request)

ListScanners handles GET /api/v1/agent/ingest/scanners It returns the list of supported scanner adapters.

type IngestResponse

type IngestResponse struct {
	ScanID          string   `json:"scan_id"`
	AssetsCreated   int      `json:"assets_created"`
	AssetsUpdated   int      `json:"assets_updated"`
	FindingsCreated int      `json:"findings_created"`
	FindingsUpdated int      `json:"findings_updated"`
	FindingsSkipped int      `json:"findings_skipped"`
	Errors          []string `json:"errors,omitempty"`
}

IngestResponse represents the response from ingestion.

type IntegrationHandler

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

IntegrationHandler handles integration-related HTTP requests.

func NewIntegrationHandler

func NewIntegrationHandler(svc *app.IntegrationService, v *validator.Validator, log *logger.Logger) *IntegrationHandler

NewIntegrationHandler creates a new integration handler.

func (*IntegrationHandler) Create

Create handles POST /api/v1/integrations @Summary Create integration @Description Creates a new integration for connecting with external providers @Tags Integrations @Accept json @Produce json @Param request body CreateIntegrationRequest true "Integration details" @Success 201 {object} IntegrationResponse "Created integration" @Failure 400 {object} map[string]string "Bad request - validation error" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden - insufficient permissions" @Failure 409 {object} map[string]string "Conflict - integration with same name exists" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations [post]

func (*IntegrationHandler) CreateNotification

func (h *IntegrationHandler) CreateNotification(w http.ResponseWriter, r *http.Request)

CreateNotification handles POST /api/v1/integrations/notifications @Summary Create notification integration @Description Creates a new notification integration (Slack, Teams, Telegram, Webhook) @Tags Integrations @Accept json @Produce json @Param request body CreateNotificationIntegrationRequest true "Notification integration details" @Success 201 {object} IntegrationWithNotificationResponse "Created notification integration" @Failure 400 {object} map[string]string "Bad request - validation error" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden" @Failure 409 {object} map[string]string "Conflict - integration with same name exists" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/notifications [post]

func (*IntegrationHandler) Delete

Delete handles DELETE /api/v1/integrations/{id} @Summary Delete integration @Description Permanently deletes an integration. This action cannot be undone. @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Success 204 "No content - successfully deleted" @Failure 400 {object} map[string]string "Bad request - invalid ID" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden - insufficient permissions" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id} [delete]

func (*IntegrationHandler) Disable

Disable handles POST /api/v1/integrations/{id}/disable @Summary Disable integration @Description Disables an active integration @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Success 200 {object} IntegrationResponse "Disabled integration" @Failure 400 {object} map[string]string "Bad request - invalid ID" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id}/disable [post]

func (*IntegrationHandler) Enable

Enable handles POST /api/v1/integrations/{id}/enable @Summary Enable integration @Description Enables a disabled integration @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Success 200 {object} IntegrationResponse "Enabled integration" @Failure 400 {object} map[string]string "Bad request - invalid ID" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id}/enable [post]

func (*IntegrationHandler) Get

Get handles GET /api/v1/integrations/{id} @Summary Get integration @Description Retrieves details of a specific integration by ID @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Success 200 {object} IntegrationResponse "Integration details" @Failure 400 {object} map[string]string "Bad request - invalid ID" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden - insufficient permissions" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id} [get]

func (*IntegrationHandler) GetNotificationEvents

func (h *IntegrationHandler) GetNotificationEvents(w http.ResponseWriter, r *http.Request)

GetNotificationEvents handles GET /api/v1/integrations/{id}/notification-events @Summary Get notification events @Description Retrieves notification events for a specific integration from the audit trail @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Param limit query int false "Maximum number of entries to return" default(50) minimum(1) maximum(100) @Param offset query int false "Number of entries to skip" default(0) minimum(0) @Success 200 {object} app.GetNotificationEventsResult "Notification events with pagination" @Failure 400 {object} map[string]string "Bad request" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id}/notification-events [get]

func (*IntegrationHandler) List

List handles GET /api/v1/integrations @Summary List integrations @Description Returns a paginated list of integrations for the current tenant @Tags Integrations @Accept json @Produce json @Param category query string false "Filter by category" Enums(scm, security, cloud, ticketing, notification) @Param provider query string false "Filter by provider" @Param status query string false "Filter by status" Enums(pending, connected, disconnected, error) @Param search query string false "Search by name" @Param page query int false "Page number" default(1) minimum(1) @Param per_page query int false "Items per page" default(20) minimum(1) maximum(100) @Param sort query string false "Sort field" Enums(name, category, provider, status, created_at, updated_at) @Param order query string false "Sort order" Enums(asc, desc) @Success 200 {object} ListResponse[IntegrationResponse] "List of integrations" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden - insufficient permissions" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations [get]

func (*IntegrationHandler) ListNotifications

func (h *IntegrationHandler) ListNotifications(w http.ResponseWriter, r *http.Request)

ListNotifications handles GET /api/v1/integrations/notifications @Summary List notification integrations @Description Returns a list of notification integrations with their extensions @Tags Integrations @Accept json @Produce json @Success 200 {object} map[string][]IntegrationWithNotificationResponse "List of notification integrations" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/notifications [get]

func (*IntegrationHandler) ListRepositories

func (h *IntegrationHandler) ListRepositories(w http.ResponseWriter, r *http.Request)

ListRepositories handles GET /api/v1/integrations/{id}/repositories @Summary List repositories from SCM integration @Description Lists repositories accessible through an SCM integration @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Param search query string false "Search by repository name" @Param page query int false "Page number" default(1) minimum(1) @Param per_page query int false "Items per page" default(30) minimum(1) maximum(100) @Success 200 {object} ListSCMRepositoriesResponse "List of repositories" @Failure 400 {object} map[string]string "Bad request - invalid ID or not an SCM integration" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden - insufficient permissions" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id}/repositories [get]

func (*IntegrationHandler) ListSCM

ListSCM handles GET /api/v1/integrations/scm @Summary List SCM integrations @Description Returns a list of SCM integrations with their extensions @Tags Integrations @Accept json @Produce json @Success 200 {object} map[string][]IntegrationResponse "List of SCM integrations" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/scm [get]

func (*IntegrationHandler) SendNotification

func (h *IntegrationHandler) SendNotification(w http.ResponseWriter, r *http.Request)

SendNotification handles POST /api/v1/integrations/{id}/send @Summary Send notification @Description Sends a notification through the specified integration @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Param request body SendNotificationRequest true "Notification content" @Success 200 {object} map[string]any "Send result" @Failure 400 {object} map[string]string "Bad request" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id}/send [post]

func (*IntegrationHandler) Sync

Sync handles POST /api/v1/integrations/{id}/sync @Summary Sync integration @Description Triggers a sync for the integration @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Success 200 {object} IntegrationResponse "Integration with updated sync status" @Failure 400 {object} map[string]string "Bad request - invalid ID" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden - insufficient permissions" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id}/sync [post]

func (*IntegrationHandler) Test

Test handles POST /api/v1/integrations/{id}/test @Summary Test integration @Description Tests the integration by verifying credentials and connectivity @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Success 200 {object} IntegrationResponse "Connection test result with updated status" @Failure 400 {object} map[string]string "Bad request - invalid ID" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden - insufficient permissions" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id}/test [post]

func (*IntegrationHandler) TestCredentials

func (h *IntegrationHandler) TestCredentials(w http.ResponseWriter, r *http.Request)

TestCredentials handles POST /api/v1/integrations/test-credentials @Summary Test integration credentials without creating @Description Tests integration credentials by verifying connectivity without persisting @Tags Integrations @Accept json @Produce json @Param request body TestIntegrationCredentialsRequest true "Credentials to test" @Success 200 {object} TestIntegrationCredentialsResponse "Credentials test result" @Failure 400 {object} map[string]string "Bad request - validation error" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden - insufficient permissions" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/test-credentials [post]

func (*IntegrationHandler) TestNotification

func (h *IntegrationHandler) TestNotification(w http.ResponseWriter, r *http.Request)

TestNotification handles POST /api/v1/integrations/{id}/test-notification @Summary Test notification integration @Description Sends a test notification through the integration @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Success 200 {object} map[string]any "Test result" @Failure 400 {object} map[string]string "Bad request" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id}/test-notification [post]

func (*IntegrationHandler) Update

Update handles PUT /api/v1/integrations/{id} @Summary Update integration @Description Updates an existing integration. Only provided fields will be updated. @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Param request body UpdateIntegrationRequest true "Fields to update" @Success 200 {object} IntegrationResponse "Updated integration" @Failure 400 {object} map[string]string "Bad request - validation error" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden - insufficient permissions" @Failure 404 {object} map[string]string "Not found" @Failure 409 {object} map[string]string "Conflict - name already exists" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id} [put]

func (*IntegrationHandler) UpdateNotification

func (h *IntegrationHandler) UpdateNotification(w http.ResponseWriter, r *http.Request)

UpdateNotification handles PUT /api/v1/integrations/{id}/notification @Summary Update notification integration @Description Updates an existing notification integration (Slack, Teams, Telegram, Webhook) @Tags Integrations @Accept json @Produce json @Param id path string true "Integration ID" format(uuid) @Param request body UpdateNotificationIntegrationRequest true "Updated notification integration details" @Success 200 {object} IntegrationWithNotificationResponse "Updated notification integration" @Failure 400 {object} map[string]string "Bad request - validation error" @Failure 401 {object} map[string]string "Unauthorized" @Failure 403 {object} map[string]string "Forbidden" @Failure 404 {object} map[string]string "Not found" @Failure 500 {object} map[string]string "Internal server error" @Security BearerAuth @Router /integrations/{id}/notification [put]

type IntegrationResponse

type IntegrationResponse struct {
	ID                  string                    `json:"id" example:"550e8400-e29b-41d4-a716-446655440000"`
	TenantID            string                    `json:"tenant_id,omitempty" example:"550e8400-e29b-41d4-a716-446655440001"`
	Name                string                    `json:"name" example:"GitHub Production"`
	Description         string                    `json:"description,omitempty" example:"Main GitHub integration"`
	Category            string                    `json:"category" example:"scm" enums:"scm,security,cloud,ticketing,notification"`
	Provider            string                    `json:"provider" example:"github"`
	Status              string                    `json:"status" example:"connected" enums:"pending,connected,disconnected,error"`
	StatusMessage       string                    `json:"status_message,omitempty" example:""`
	AuthType            string                    `json:"auth_type" example:"token" enums:"token,oauth,api_key,basic,app"`
	BaseURL             string                    `json:"base_url,omitempty" example:"https://github.com"`
	LastSyncAt          *time.Time                `json:"last_sync_at,omitempty" example:"2024-01-15T10:30:00Z"`
	NextSyncAt          *time.Time                `json:"next_sync_at,omitempty" example:"2024-01-15T11:30:00Z"`
	SyncIntervalMinutes int                       `json:"sync_interval_minutes" example:"60"`
	SyncError           string                    `json:"sync_error,omitempty" example:""`
	Config              map[string]any            `json:"config,omitempty"`
	Metadata            map[string]any            `json:"metadata,omitempty"`
	Stats               *IntegrationStatsResponse `json:"stats,omitempty"`
	SCMExtension        *SCMExtensionResponse     `json:"scm_extension,omitempty"`
	CreatedAt           time.Time                 `json:"created_at" example:"2024-01-01T00:00:00Z"`
	UpdatedAt           time.Time                 `json:"updated_at" example:"2024-01-15T10:30:00Z"`
	CreatedBy           string                    `json:"created_by,omitempty" example:"user-123"`
}

IntegrationResponse represents an integration in API responses. @Description Integration details including provider info and status

type IntegrationStatsResponse

type IntegrationStatsResponse struct {
	TotalAssets       int `json:"total_assets,omitempty"`
	TotalFindings     int `json:"total_findings,omitempty"`
	TotalRepositories int `json:"total_repositories,omitempty"`
}

IntegrationStatsResponse represents integration statistics.

type IntegrationWithNotificationResponse

type IntegrationWithNotificationResponse struct {
	IntegrationResponse
	NotificationExtension *NotificationExtensionResponse `json:"notification_extension,omitempty"`
}

IntegrationWithNotificationResponse represents an integration with notification extension.

type InvitationResponse

type InvitationResponse struct {
	ID          string    `json:"id"`
	Email       string    `json:"email"`
	Role        string    `json:"role"`     // Deprecated: always "member", use RoleIDs instead
	RoleIDs     []string  `json:"role_ids"` // RBAC role IDs assigned to invitation
	Token       string    `json:"token,omitempty"`
	InvitedBy   string    `json:"invited_by"`
	InviterName string    `json:"inviter_name,omitempty"`
	ExpiresAt   time.Time `json:"expires_at"`
	CreatedAt   time.Time `json:"created_at"`
	Pending     bool      `json:"pending"`
}

InvitationResponse represents an invitation in API responses.

type KEVEntryResponse

type KEVEntryResponse struct {
	CVEID             string   `json:"cve_id"`
	VendorProject     string   `json:"vendor_project"`
	Product           string   `json:"product"`
	VulnerabilityName string   `json:"vulnerability_name"`
	ShortDescription  string   `json:"short_description,omitempty"`
	DateAdded         string   `json:"date_added"`
	DueDate           string   `json:"due_date,omitempty"`
	DaysUntilDue      int      `json:"days_until_due"`
	IsPastDue         bool     `json:"is_past_due"`
	RansomwareUse     string   `json:"ransomware_use,omitempty"`
	Notes             string   `json:"notes,omitempty"`
	CWEs              []string `json:"cwes,omitempty"`
}

KEVEntryResponse is the response for a KEV entry.

type KeycloakInfoResponse

type KeycloakInfoResponse struct {
	AuthURL     string `json:"auth_url"`
	TokenURL    string `json:"token_url"`
	UserInfoURL string `json:"userinfo_url"`
	LogoutURL   string `json:"logout_url"`
	JWKSURL     string `json:"jwks_url"`
	Realm       string `json:"realm"`
	Issuer      string `json:"issuer"`
}

KeycloakInfoResponse is the response body for Keycloak info.

type LicensingModuleResponse

type LicensingModuleResponse struct {
	ID             string  `json:"id"`
	Slug           string  `json:"slug"`
	Name           string  `json:"name"`
	Description    string  `json:"description,omitempty"`
	Icon           string  `json:"icon,omitempty"`
	Category       string  `json:"category"`
	DisplayOrder   int     `json:"display_order"`
	IsActive       bool    `json:"is_active"`
	ReleaseStatus  string  `json:"release_status"`
	ParentModuleID *string `json:"parent_module_id,omitempty"`
}

LicensingModuleResponse represents a module in the response.

type ListCredentialsResponse

type ListCredentialsResponse struct {
	Items      []CredentialResponse `json:"items"`
	TotalCount int                  `json:"total_count"`
	Page       int                  `json:"page"`
	PageSize   int                  `json:"page_size"`
}

ListCredentialsResponse represents the response for listing credentials.

type ListResponse

type ListResponse[T any] struct {
	Data       []T              `json:"data"`
	Total      int64            `json:"total"`
	Page       int              `json:"page"`
	PerPage    int              `json:"per_page"`
	TotalPages int              `json:"total_pages"`
	Links      *PaginationLinks `json:"links,omitempty"`
}

ListResponse represents a paginated list response. This is a generic type that can be reused across all handlers.

type ListSCMRepositoriesResponse

type ListSCMRepositoriesResponse struct {
	Repositories []SCMRepositoryResponse `json:"repositories"`
	Total        int                     `json:"total"`
	HasMore      bool                    `json:"has_more"`
	NextPage     int                     `json:"next_page"`
}

ListSCMRepositoriesResponse represents the response for listing SCM repositories. @Description Response for listing SCM repositories

type ListSourcesResponse

type ListSourcesResponse struct {
	Items      []TemplateSourceResponse `json:"items"`
	TotalCount int                      `json:"total_count"`
	Page       int                      `json:"page"`
	PageSize   int                      `json:"page_size"`
}

ListSourcesResponse represents the response for listing template sources.

type LiveHostResult

type LiveHostResult struct {
	URL           string   `json:"url"`
	Host          string   `json:"host"`
	IP            string   `json:"ip,omitempty"`
	Port          int      `json:"port,omitempty"`
	Scheme        string   `json:"scheme"`
	StatusCode    int      `json:"status_code"`
	ContentLength int64    `json:"content_length,omitempty"`
	Title         string   `json:"title,omitempty"`
	WebServer     string   `json:"web_server,omitempty"`
	ContentType   string   `json:"content_type,omitempty"`
	Technologies  []string `json:"technologies,omitempty"`
	CDN           string   `json:"cdn,omitempty"`
	TLSVersion    string   `json:"tls_version,omitempty"`
	Redirect      string   `json:"redirect,omitempty"`
	ResponseTime  int64    `json:"response_time_ms,omitempty"`
}

LiveHostResult represents an HTTP/HTTPS live host.

type LocalAuthHandler

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

LocalAuthHandler handles local authentication requests.

func NewLocalAuthHandler

func NewLocalAuthHandler(
	authService *app.AuthService,
	sessionService *app.SessionService,
	emailService *app.EmailService,
	authConfig config.AuthConfig,
	log *logger.Logger,
) *LocalAuthHandler

NewLocalAuthHandler creates a new LocalAuthHandler.

func (*LocalAuthHandler) AcceptInvitationWithRefresh

func (h *LocalAuthHandler) AcceptInvitationWithRefresh(w http.ResponseWriter, r *http.Request)

AcceptInvitationWithRefresh handles accepting an invitation using refresh token. POST /api/v1/invitations/{token}/accept-with-refresh This endpoint is for users who were invited but don't have a tenant yet, so they only have a refresh token (no access token). The refresh token is obtained from the httpOnly cookie.

func (*LocalAuthHandler) ChangePassword

func (h *LocalAuthHandler) ChangePassword(w http.ResponseWriter, r *http.Request)

ChangePassword handles password change for authenticated users. @Summary Change password @Description Changes password for authenticated user @Tags Authentication @Accept json @Produce json @Security BearerAuth @Param request body ChangePasswordRequest true "Current and new password" @Success 200 {object} map[string]string @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /users/me/change-password [post]

func (*LocalAuthHandler) CreateFirstTeam

func (h *LocalAuthHandler) CreateFirstTeam(w http.ResponseWriter, r *http.Request)

CreateFirstTeam handles creating the first team for a new user. POST /api/v1/auth/create-first-team This endpoint uses refresh_token for authentication since user has no access_token yet. The refresh token can be provided in the request body OR via httpOnly cookie.

func (*LocalAuthHandler) ExchangeToken

func (h *LocalAuthHandler) ExchangeToken(w http.ResponseWriter, r *http.Request)

ExchangeToken exchanges a global refresh token for a tenant-scoped access token. @Summary Exchange token @Description Exchanges refresh token for tenant-scoped access token @Tags Authentication @Accept json @Produce json @Param request body ExchangeTokenRequest true "Token exchange data" @Success 200 {object} ExchangeTokenResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /auth/token [post]

func (*LocalAuthHandler) ForgotPassword

func (h *LocalAuthHandler) ForgotPassword(w http.ResponseWriter, r *http.Request)

ForgotPassword handles forgot password request. @Summary Forgot password @Description Sends password reset email @Tags Authentication @Accept json @Produce json @Param request body ForgotPasswordRequest true "Email address" @Success 200 {object} map[string]string @Router /auth/forgot-password [post]

func (*LocalAuthHandler) GetWSToken

func (h *LocalAuthHandler) GetWSToken(w http.ResponseWriter, r *http.Request)

GetWSToken returns a short-lived token for WebSocket authentication. This is needed because WebSocket connections cannot use httpOnly cookies when the connection is cross-origin (different port in development). The token is valid for 30 seconds - just enough time to establish the connection. @Summary Get WebSocket token @Description Returns a short-lived token for WebSocket authentication @Tags Authentication @Produce json @Security BearerAuth @Success 200 {object} WSTokenResponse @Failure 401 {object} map[string]string @Router /auth/ws-token [get]

func (*LocalAuthHandler) Info

Info returns authentication provider information. @Summary Auth info @Description Returns authentication provider information @Tags Authentication @Produce json @Success 200 {object} AuthInfoResponse @Router /auth/info [get]

func (*LocalAuthHandler) ListSessions

func (h *LocalAuthHandler) ListSessions(w http.ResponseWriter, r *http.Request)

ListSessions lists all active sessions for the authenticated user. @Summary List sessions @Description Lists all active sessions @Tags Authentication @Produce json @Security BearerAuth @Success 200 {object} SessionsResponse @Failure 401 {object} map[string]string @Router /users/me/sessions [get]

func (*LocalAuthHandler) Login

Login handles user login. @Summary User login @Description Authenticates a user and returns refresh token and tenant list @Tags Authentication @Accept json @Produce json @Param request body LoginRequest true "Login credentials" @Success 200 {object} LoginResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 403 {object} map[string]string @Router /auth/login [post]

func (*LocalAuthHandler) Logout

func (h *LocalAuthHandler) Logout(w http.ResponseWriter, r *http.Request)

Logout handles user logout. @Summary User logout @Description Logs out the current user and invalidates the session @Tags Authentication @Produce json @Security BearerAuth @Success 200 {object} map[string]string @Failure 400 {object} map[string]string @Router /auth/logout [post]

func (*LocalAuthHandler) RefreshToken

func (h *LocalAuthHandler) RefreshToken(w http.ResponseWriter, r *http.Request)

RefreshToken handles token refresh with rotation. @Summary Refresh token @Description Refreshes access token and rotates refresh token @Tags Authentication @Accept json @Produce json @Param request body RefreshTokenRequest true "Refresh token data" @Success 200 {object} RefreshTokenResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /auth/refresh [post]

func (*LocalAuthHandler) Register

func (h *LocalAuthHandler) Register(w http.ResponseWriter, r *http.Request)

Register handles user registration. @Summary Register user @Description Registers a new user with email and password @Tags Authentication @Accept json @Produce json @Param request body RegisterRequest true "Registration data" @Success 201 {object} RegisterResponse @Failure 400 {object} map[string]string @Failure 409 {object} map[string]string @Router /auth/register [post]

func (*LocalAuthHandler) ResetPassword

func (h *LocalAuthHandler) ResetPassword(w http.ResponseWriter, r *http.Request)

ResetPassword handles password reset. @Summary Reset password @Description Resets password using token @Tags Authentication @Accept json @Produce json @Param request body ResetPasswordRequest true "Reset token and new password" @Success 200 {object} map[string]string @Failure 400 {object} map[string]string @Router /auth/reset-password [post]

func (*LocalAuthHandler) RevokeAllSessions

func (h *LocalAuthHandler) RevokeAllSessions(w http.ResponseWriter, r *http.Request)

RevokeAllSessions revokes all sessions except the current one. @Summary Revoke all sessions @Description Revokes all sessions except current @Tags Authentication @Produce json @Security BearerAuth @Success 200 {object} map[string]string @Failure 401 {object} map[string]string @Router /users/me/sessions [delete]

func (*LocalAuthHandler) RevokeSession

func (h *LocalAuthHandler) RevokeSession(w http.ResponseWriter, r *http.Request)

RevokeSession revokes a specific session. @Summary Revoke session @Description Revokes a specific session by ID @Tags Authentication @Produce json @Security BearerAuth @Param sessionId path string true "Session ID" @Success 200 {object} map[string]string @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /users/me/sessions/{sessionId} [delete]

func (*LocalAuthHandler) VerifyEmail

func (h *LocalAuthHandler) VerifyEmail(w http.ResponseWriter, r *http.Request)

VerifyEmail handles email verification. @Summary Verify email @Description Verifies user email with token @Tags Authentication @Accept json @Produce json @Param request body VerifyEmailRequest true "Verification token" @Success 200 {object} map[string]string @Failure 400 {object} map[string]string @Router /auth/verify-email [post]

type LoginRequest

type LoginRequest struct {
	Email    string `json:"email" validate:"required,email"`
	Password string `json:"password" validate:"required"`
}

LoginRequest is the request body for login.

type LoginResponse

type LoginResponse struct {
	RefreshToken string       `json:"refresh_token,omitempty"` // Also set in httpOnly cookie
	TokenType    string       `json:"token_type"`
	ExpiresIn    int64        `json:"expires_in"`
	User         UserInfo     `json:"user"`
	Tenants      []TenantInfo `json:"tenants"`
	// SuspendedTenants is non-empty when the user has memberships that
	// are currently suspended. The client uses this to show a clear
	// "your access to X is suspended" notice instead of bouncing the
	// user to /onboarding/create-team. Suspended tenants are NOT
	// accessible — the user cannot pick one and exchange a token.
	SuspendedTenants []TenantInfo `json:"suspended_tenants,omitempty"`
}

LoginResponse is the response body for login. Returns a global refresh token and list of tenants. Client must call POST /api/v1/auth/token to get tenant-scoped access token. Note: refresh_token is also set as httpOnly cookie for security (XSS protection).

type MapFindingRequest added in v0.1.2

type MapFindingRequest struct {
	ControlID string `json:"control_id"`
	Impact    string `json:"impact"`
}

MapFindingRequest is the API request for mapping a finding to a control.

type MemberRBACRoleResponse

type MemberRBACRoleResponse struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	Slug     string `json:"slug"`
	IsSystem bool   `json:"is_system"`
}

MemberRBACRoleResponse represents a simplified RBAC role in member response.

type MemberResponse

type MemberResponse struct {
	ID        string    `json:"id"`
	UserID    string    `json:"user_id"`
	Role      string    `json:"role"`
	InvitedBy string    `json:"invited_by,omitempty"`
	JoinedAt  time.Time `json:"joined_at"`
}

MemberResponse represents a tenant member in API responses.

type MemberStatsResponse

type MemberStatsResponse struct {
	TotalMembers   int            `json:"total_members"`
	ActiveMembers  int            `json:"active_members"`
	PendingInvites int            `json:"pending_invites"`
	RoleCounts     map[string]int `json:"role_counts"`
}

MemberStatsResponse represents member statistics.

type MemberWithUserResponse

type MemberWithUserResponse struct {
	ID          string     `json:"id"`
	UserID      string     `json:"user_id"`
	Role        string     `json:"role"`
	InvitedBy   string     `json:"invited_by,omitempty"`
	JoinedAt    time.Time  `json:"joined_at"`
	Email       string     `json:"email"`
	Name        string     `json:"name"`
	AvatarURL   string     `json:"avatar_url,omitempty"`
	Status      string     `json:"status"`
	LastLoginAt *time.Time `json:"last_login_at,omitempty"`
	// RBAC roles (included when ?include=roles)
	RBACRoles []MemberRBACRoleResponse `json:"rbac_roles,omitempty"`
}

MemberWithUserResponse represents a member with user details.

type ModuleResponse

type ModuleResponse struct {
	ID           string               `json:"id"`
	Name         string               `json:"name"`
	Description  string               `json:"description,omitempty"`
	Icon         string               `json:"icon,omitempty"`
	DisplayOrder int                  `json:"display_order"`
	IsActive     bool                 `json:"is_active"`
	Permissions  []PermissionResponse `json:"permissions"`
}

ModuleResponse represents a permission module in API responses.

type ModuleToggleRequest added in v0.1.2

type ModuleToggleRequest struct {
	ModuleID  string `json:"module_id" validate:"required"`
	IsEnabled bool   `json:"is_enabled"`
}

ModuleToggleRequest represents a single module toggle.

type NodeConfigRequest

type NodeConfigRequest struct {
	TriggerType        string         `json:"trigger_type,omitempty"`
	TriggerConfig      map[string]any `json:"trigger_config,omitempty"`
	ConditionExpr      string         `json:"condition_expr,omitempty"`
	ActionType         string         `json:"action_type,omitempty"`
	ActionConfig       map[string]any `json:"action_config,omitempty"`
	NotificationType   string         `json:"notification_type,omitempty"`
	NotificationConfig map[string]any `json:"notification_config,omitempty"`
}

NodeConfigRequest represents node configuration.

type NodeConfigResponse

type NodeConfigResponse struct {
	TriggerType        string         `json:"trigger_type,omitempty"`
	TriggerConfig      map[string]any `json:"trigger_config,omitempty"`
	ConditionExpr      string         `json:"condition_expr,omitempty"`
	ActionType         string         `json:"action_type,omitempty"`
	ActionConfig       map[string]any `json:"action_config,omitempty"`
	NotificationType   string         `json:"notification_type,omitempty"`
	NotificationConfig map[string]any `json:"notification_config,omitempty"`
}

NodeConfigResponse represents node configuration in the response.

type NodeRequest

type NodeRequest struct {
	NodeKey     string                     `json:"node_key" validate:"required,min=1,max=100"`
	NodeType    string                     `json:"node_type" validate:"required,oneof=trigger condition action notification"`
	Name        string                     `json:"name" validate:"required,min=1,max=255"`
	Description string                     `json:"description" validate:"max=1000"`
	UIPosition  *WorkflowUIPositionRequest `json:"ui_position"`
	Config      *NodeConfigRequest         `json:"config"`
}

NodeRequest represents a node in the workflow request.

type NodeResponse

type NodeResponse struct {
	ID          string                     `json:"id"`
	WorkflowID  string                     `json:"workflow_id"`
	NodeKey     string                     `json:"node_key"`
	NodeType    string                     `json:"node_type"`
	Name        string                     `json:"name"`
	Description string                     `json:"description,omitempty"`
	UIPosition  WorkflowUIPositionResponse `json:"ui_position"`
	Config      NodeConfigResponse         `json:"config"`
	CreatedAt   string                     `json:"created_at"`
}

NodeResponse represents a node in the workflow response.

type NodeRunResponse

type NodeRunResponse struct {
	ID            string         `json:"id"`
	WorkflowRunID string         `json:"workflow_run_id"`
	NodeID        string         `json:"node_id"`
	NodeKey       string         `json:"node_key"`
	NodeType      string         `json:"node_type"`
	Status        string         `json:"status"`
	Input         map[string]any `json:"input,omitempty"`
	Output        map[string]any `json:"output,omitempty"`
	StartedAt     *string        `json:"started_at,omitempty"`
	CompletedAt   *string        `json:"completed_at,omitempty"`
	ErrorMessage  string         `json:"error_message,omitempty"`
	ErrorCode     string         `json:"error_code,omitempty"`
}

NodeRunResponse represents a node run in the response.

type NotificationExtensionResponse

type NotificationExtensionResponse struct {
	ChannelID          string   `json:"channel_id,omitempty" example:"C123456"`            // Deprecated: use metadata.chat_id
	ChannelName        string   `json:"channel_name,omitempty" example:"#security-alerts"` // Deprecated: use metadata.channel_name
	EnabledSeverities  []string `json:"enabled_severities" example:"[\"critical\",\"high\"]"`
	EnabledEventTypes  []string `json:"enabled_event_types" example:"[\"security_alert\",\"new_finding\",\"new_exposure\"]"`
	MessageTemplate    string   `json:"message_template,omitempty"`
	IncludeDetails     bool     `json:"include_details" example:"true"`
	MinIntervalMinutes int      `json:"min_interval_minutes" example:"5"`
}

NotificationExtensionResponse represents notification-specific extension data. Note: channel_id and channel_name are DEPRECATED. They are now stored in integrations.metadata. For Telegram: read metadata.chat_id For Slack/Teams: read metadata.channel_name For Email: read metadata.smtp_host, metadata.smtp_port, metadata.from_email, etc.

type NotificationHandler added in v0.1.2

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

NotificationHandler handles user notification endpoints.

func NewNotificationHandler added in v0.1.2

func NewNotificationHandler(svc *app.NotificationService, log *logger.Logger) *NotificationHandler

NewNotificationHandler creates a new NotificationHandler.

func (*NotificationHandler) GetPreferences added in v0.1.2

func (h *NotificationHandler) GetPreferences(w http.ResponseWriter, r *http.Request)

GetPreferences godoc @Summary Get notification preferences @Description Get notification preferences for the current user @Tags notifications @Accept json @Produce json @Success 200 {object} PreferencesResponse @Failure 401 {object} apierror.Response @Failure 500 {object} apierror.Response @Router /notifications/preferences [get] @Security BearerAuth

func (*NotificationHandler) GetUnreadCount added in v0.1.2

func (h *NotificationHandler) GetUnreadCount(w http.ResponseWriter, r *http.Request)

GetUnreadCount godoc @Summary Get unread notification count @Description Get the number of unread notifications for the current user @Tags notifications @Accept json @Produce json @Success 200 {object} UnreadCountResponse @Failure 401 {object} apierror.Response @Failure 500 {object} apierror.Response @Router /notifications/unread-count [get] @Security BearerAuth

func (*NotificationHandler) List added in v0.1.2

List godoc @Summary List notifications @Description List notifications for the current user with filtering and pagination @Tags notifications @Accept json @Produce json @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Param severity query string false "Filter by severity" @Param type query string false "Filter by notification type" @Param is_read query string false "Filter by read status (true/false)" @Success 200 {object} pagination.Result[NotificationResponse] @Failure 401 {object} apierror.Response @Failure 500 {object} apierror.Response @Router /notifications [get] @Security BearerAuth

func (*NotificationHandler) MarkAllAsRead added in v0.1.2

func (h *NotificationHandler) MarkAllAsRead(w http.ResponseWriter, r *http.Request)

MarkAllAsRead godoc @Summary Mark all notifications as read @Description Mark all notifications as read for the current user in the current tenant @Tags notifications @Accept json @Produce json @Success 204 "No Content" @Failure 401 {object} apierror.Response @Failure 500 {object} apierror.Response @Router /notifications/read-all [post] @Security BearerAuth

func (*NotificationHandler) MarkAsRead added in v0.1.2

func (h *NotificationHandler) MarkAsRead(w http.ResponseWriter, r *http.Request)

MarkAsRead godoc @Summary Mark notification as read @Description Mark a single notification as read for the current user @Tags notifications @Accept json @Produce json @Param id path string true "Notification ID" @Success 204 "No Content" @Failure 400 {object} apierror.Response @Failure 401 {object} apierror.Response @Failure 404 {object} apierror.Response @Failure 500 {object} apierror.Response @Router /notifications/{id}/read [patch] @Security BearerAuth

func (*NotificationHandler) UpdatePreferences added in v0.1.2

func (h *NotificationHandler) UpdatePreferences(w http.ResponseWriter, r *http.Request)

UpdatePreferences godoc @Summary Update notification preferences @Description Update notification preferences for the current user @Tags notifications @Accept json @Produce json @Param body body NotificationPreferencesRequest true "Updated preferences" @Success 200 {object} PreferencesResponse @Failure 400 {object} apierror.Response @Failure 401 {object} apierror.Response @Failure 422 {object} apierror.Response @Failure 500 {object} apierror.Response @Router /notifications/preferences [put] @Security BearerAuth

type NotificationPreferencesRequest added in v0.1.2

type NotificationPreferencesRequest struct {
	InAppEnabled *bool    `json:"in_app_enabled"`
	EmailDigest  *string  `json:"email_digest"`
	MutedTypes   []string `json:"muted_types"`
	MinSeverity  *string  `json:"min_severity"`
}

NotificationPreferencesRequest represents the request body for updating preferences.

type NotificationResponse added in v0.1.2

type NotificationResponse struct {
	ID               string `json:"id"`
	TenantID         string `json:"tenant_id"`
	Audience         string `json:"audience"`
	AudienceID       string `json:"audience_id,omitempty"`
	NotificationType string `json:"notification_type"`
	Severity         string `json:"severity"`
	Title            string `json:"title"`
	Body             string `json:"body,omitempty"`
	ResourceType     string `json:"resource_type,omitempty"`
	ResourceID       string `json:"resource_id,omitempty"`
	URL              string `json:"url,omitempty"`
	ActorID          string `json:"actor_id,omitempty"`
	IsRead           bool   `json:"is_read"`
	CreatedAt        string `json:"created_at"`
}

NotificationResponse represents a notification in API responses.

type OAuthHandler

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

OAuthHandler handles OAuth authentication requests.

func NewOAuthHandler

func NewOAuthHandler(
	oauthService *app.OAuthService,
	oauthConfig config.OAuthConfig,
	authConfig config.AuthConfig,
	log *logger.Logger,
) *OAuthHandler

NewOAuthHandler creates a new OAuthHandler.

func (*OAuthHandler) Authorize

func (h *OAuthHandler) Authorize(w http.ResponseWriter, r *http.Request)

Authorize returns the OAuth authorization URL for a provider. @Summary Get OAuth authorization URL @Description Returns authorization URL for OAuth login with the specified provider @Tags OAuth @Produce json @Param provider path string true "OAuth provider (google, github, gitlab)" @Param redirect_uri query string false "Callback URL after authorization" @Param final_redirect query string false "Final redirect URL after login" @Success 200 {object} AuthorizeResponse @Failure 400 {object} map[string]string @Router /auth/oauth/{provider}/authorize [get]

func (*OAuthHandler) Callback

func (h *OAuthHandler) Callback(w http.ResponseWriter, r *http.Request)

Callback handles the OAuth callback from the provider. @Summary OAuth callback handler @Description Handles the OAuth callback after user authorization @Tags OAuth @Accept json @Produce json @Param provider path string true "OAuth provider" @Param request body CallbackRequest true "Callback data" @Success 200 {object} CallbackResponse @Failure 400 {object} map[string]string @Router /auth/oauth/{provider}/callback [post]

func (*OAuthHandler) ListProviders

func (h *OAuthHandler) ListProviders(w http.ResponseWriter, r *http.Request)

ListProviders returns the list of available OAuth providers. @Summary List OAuth providers @Description Returns list of available and configured OAuth providers @Tags OAuth @Produce json @Success 200 {object} ProvidersResponse @Router /auth/oauth/providers [get]

type OpenPortResult

type OpenPortResult struct {
	Host     string `json:"host"`
	IP       string `json:"ip,omitempty"`
	Port     int    `json:"port"`
	Protocol string `json:"protocol,omitempty"`
	Service  string `json:"service,omitempty"`
	Version  string `json:"version,omitempty"`
	Banner   string `json:"banner,omitempty"`
}

OpenPortResult represents an open port.

type OutboxEntryResponse

type OutboxEntryResponse struct {
	ID            string         `json:"id"`
	EventType     string         `json:"event_type"`
	AggregateType string         `json:"aggregate_type"`
	AggregateID   *string        `json:"aggregate_id,omitempty"`
	Title         string         `json:"title"`
	Body          string         `json:"body,omitempty"`
	Severity      string         `json:"severity"`
	URL           string         `json:"url,omitempty"`
	Status        string         `json:"status"`
	RetryCount    int            `json:"retry_count"`
	MaxRetries    int            `json:"max_retries"`
	LastError     string         `json:"last_error,omitempty"`
	ScheduledAt   string         `json:"scheduled_at"`
	LockedAt      *string        `json:"locked_at,omitempty"`
	ProcessedAt   *string        `json:"processed_at,omitempty"`
	CreatedAt     string         `json:"created_at"`
	UpdatedAt     string         `json:"updated_at"`
	Metadata      map[string]any `json:"metadata,omitempty"`
}

OutboxEntryResponse represents an outbox entry in API responses.

type OutboxHandler added in v0.1.2

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

OutboxHandler handles notification outbox operations for tenants.

func NewOutboxHandler added in v0.1.2

func NewOutboxHandler(repo outbox.OutboxRepository, log *logger.Logger) *OutboxHandler

NewOutboxHandler creates a new OutboxHandler.

func (*OutboxHandler) Delete added in v0.1.2

func (h *OutboxHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete godoc @Summary Delete outbox entry @Description Delete a specific outbox entry (must belong to current tenant) @Tags notification-outbox @Accept json @Produce json @Param id path string true "Outbox entry ID" @Success 204 "No Content" @Failure 404 {object} apierror.Response @Failure 500 {object} apierror.Response @Router /notification-outbox/{id} [delete] @Security BearerAuth

func (*OutboxHandler) Get added in v0.1.2

Get godoc @Summary Get notification outbox entry @Description Get a specific outbox entry by ID (must belong to current tenant) @Tags notification-outbox @Accept json @Produce json @Param id path string true "Outbox entry ID" @Success 200 {object} OutboxEntryResponse @Failure 404 {object} apierror.Response @Failure 500 {object} apierror.Response @Router /notification-outbox/{id} [get] @Security BearerAuth

func (*OutboxHandler) GetStats added in v0.1.2

func (h *OutboxHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats godoc @Summary Get notification outbox statistics @Description Get counts of outbox entries by status for the current tenant @Tags notification-outbox @Accept json @Produce json @Success 200 {object} OutboxStatsResponse @Failure 500 {object} apierror.Response @Router /notification-outbox/stats [get] @Security BearerAuth

func (*OutboxHandler) List added in v0.1.2

func (h *OutboxHandler) List(w http.ResponseWriter, r *http.Request)

List godoc @Summary List notification outbox entries @Description List notification outbox entries for the current tenant with filtering and pagination @Tags notification-outbox @Accept json @Produce json @Param status query string false "Filter by status (pending, processing, completed, failed, dead)" @Param page query int false "Page number" default(1) @Param page_size query int false "Page size" default(20) @Success 200 {object} pagination.Result[OutboxEntryResponse] @Failure 500 {object} apierror.Response @Router /notification-outbox [get] @Security BearerAuth

func (*OutboxHandler) Retry added in v0.1.2

func (h *OutboxHandler) Retry(w http.ResponseWriter, r *http.Request)

Retry godoc @Summary Retry failed outbox entry @Description Reset a failed/dead outbox entry to pending for retry (must belong to current tenant) @Tags notification-outbox @Accept json @Produce json @Param id path string true "Outbox entry ID" @Success 200 {object} OutboxEntryResponse @Failure 400 {object} apierror.Response @Failure 404 {object} apierror.Response @Failure 500 {object} apierror.Response @Router /notification-outbox/{id}/retry [post] @Security BearerAuth

type OutboxStatsResponse

type OutboxStatsResponse struct {
	Pending    int64 `json:"pending"`
	Processing int64 `json:"processing"`
	Completed  int64 `json:"completed"`
	Failed     int64 `json:"failed"`
	Dead       int64 `json:"dead"`
	Total      int64 `json:"total"`
}

OutboxStatsResponse represents outbox statistics.

type OverrideResponse

type OverrideResponse struct {
	ID               string  `json:"id"`
	TenantID         string  `json:"tenant_id"`
	ToolID           *string `json:"tool_id,omitempty"`
	RulePattern      string  `json:"rule_pattern"`
	IsPattern        bool    `json:"is_pattern"`
	Enabled          bool    `json:"enabled"`
	SeverityOverride string  `json:"severity_override,omitempty"`
	AssetGroupID     *string `json:"asset_group_id,omitempty"`
	ScanProfileID    *string `json:"scan_profile_id,omitempty"`
	Reason           string  `json:"reason,omitempty"`
	CreatedBy        *string `json:"created_by,omitempty"`
	CreatedAt        string  `json:"created_at"`
	UpdatedAt        string  `json:"updated_at"`
	ExpiresAt        *string `json:"expires_at,omitempty"`
}

OverrideResponse represents the response for a rule override.

type OverviewStatsResponse

type OverviewStatsResponse struct {
	Pipelines StatusCountsResponse `json:"pipelines"`
	Scans     StatusCountsResponse `json:"scans"`
	Jobs      StatusCountsResponse `json:"jobs"`
}

OverviewStatsResponse represents the response for scan management overview stats.

type OwnerBriefResponse added in v0.1.2

type OwnerBriefResponse struct {
	ID    string `json:"id"`
	Type  string `json:"type"`
	Name  string `json:"name"`
	Email string `json:"email,omitempty"`
}

OwnerBriefResponse is a lightweight owner representation for asset list responses.

type PaginatedResponse added in v0.1.2

type PaginatedResponse struct {
	Items      any   `json:"items"`
	TotalCount int64 `json:"total_count"`
	Limit      int   `json:"limit"`
	Offset     int   `json:"offset"`
}

PaginatedResponse is a generic paginated API response.

type PaginationLinks struct {
	Self  string `json:"self"`
	First string `json:"first,omitempty"`
	Prev  string `json:"prev,omitempty"`
	Next  string `json:"next,omitempty"`
	Last  string `json:"last,omitempty"`
}

PaginationLinks contains HATEOAS-style pagination links.

func NewPaginationLinks(r *http.Request, page, perPage, totalPages int) *PaginationLinks

NewPaginationLinks creates pagination links based on the current request. It preserves all existing query parameters while updating page number.

type PentestFindingRequest added in v0.1.2

type PentestFindingRequest struct {
	Title               string           `json:"title" validate:"required,min=1,max=500"`
	Description         string           `json:"description" validate:"max=10000"`
	AssetID             string           `json:"asset_id" validate:"omitempty,uuid"`
	Severity            string           `json:"severity" validate:"required,oneof=critical high medium low info"`
	Status              string           `json:"status" validate:"omitempty,oneof=draft open confirmed fix_applied resolved accepted closed"`
	CVSSScore           *float64         `json:"cvss_score" validate:"omitempty,min=0,max=10"`
	CVSSVector          string           `json:"cvss_vector" validate:"max=255"`
	CWEID               string           `json:"cwe_id" validate:"max=20"`
	CVEID               string           `json:"cve_id" validate:"max=20"`
	OWASPCategory       string           `json:"owasp_category" validate:"max=100"`
	StepsToReproduce    []string         `json:"steps_to_reproduce" validate:"max=50,dive,max=2000"`
	PoCCode             string           `json:"poc_code" validate:"max=50000"`
	Evidence            []map[string]any `json:"evidence" validate:"max=50"`
	RequestResponses    []map[string]any `json:"request_responses" validate:"max=50"`
	BusinessImpact      string           `json:"business_impact" validate:"max=5000"`
	TechnicalImpact     string           `json:"technical_impact" validate:"max=5000"`
	RemediationGuidance string           `json:"remediation_guidance" validate:"max=10000"`
	RemediationDeadline *string          `json:"remediation_deadline"`
	AffectedAssetsText  []string         `json:"affected_assets" validate:"max=100,dive,max=500"`
	ReferenceURLs       []string         `json:"reference_urls" validate:"max=50,dive,url,max=1000"`
	AssignedTo          *string          `json:"assigned_to" validate:"omitempty,uuid"`
	ReviewedBy          *string          `json:"reviewed_by" validate:"omitempty,uuid"`
	Tags                []string         `json:"tags" validate:"max=50,dive,max=100"`
	TemplateID          *string          `json:"template_id" validate:"omitempty,uuid"`
}

PentestFindingRequest is the API request for creating/updating a pentest finding.

type PentestFindingResponse added in v0.1.2

type PentestFindingResponse struct {
	ID                  string           `json:"id"`
	CampaignID          string           `json:"campaign_id"`
	Title               string           `json:"title"`
	Description         string           `json:"description,omitempty"`
	AssetID             string           `json:"asset_id,omitempty"`
	AssetName           string           `json:"asset_name,omitempty"`
	Severity            string           `json:"severity"`
	Status              string           `json:"status"`
	CVSSScore           *float64         `json:"cvss_score,omitempty"`
	CVSSVector          string           `json:"cvss_vector,omitempty"`
	CWEID               string           `json:"cwe_id,omitempty"`
	CVEID               string           `json:"cve_id,omitempty"`
	OWASPCategory       string           `json:"owasp_category,omitempty"`
	AffectedAssets      []string         `json:"affected_assets"`
	StepsToReproduce    []string         `json:"steps_to_reproduce"`
	PoCCode             string           `json:"poc_code,omitempty"`
	Evidence            []map[string]any `json:"evidence"`
	RequestResponses    []map[string]any `json:"request_responses"`
	BusinessImpact      string           `json:"business_impact,omitempty"`
	TechnicalImpact     string           `json:"technical_impact,omitempty"`
	RemediationGuidance string           `json:"remediation_guidance,omitempty"`
	RemediationDeadline *string          `json:"remediation_deadline,omitempty"`
	ReferenceURLs       []string         `json:"reference_urls"`
	AssignedTo          *string          `json:"assigned_to,omitempty"`
	ReviewedBy          *string          `json:"reviewed_by,omitempty"`
	Tags                []string         `json:"tags"`
	CreatedAt           time.Time        `json:"created_at"`
	UpdatedAt           time.Time        `json:"updated_at"`
	CreatedBy           *string          `json:"created_by,omitempty"`
}

PentestFindingResponse is the API response for a pentest finding.

type PentestHandler added in v0.1.2

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

PentestHandler handles pentest HTTP requests.

func NewPentestHandler added in v0.1.2

func NewPentestHandler(svc *app.PentestService, userRepo userRepository, log *logger.Logger) *PentestHandler

NewPentestHandler creates a new pentest handler.

func (*PentestHandler) AddCampaignMember added in v0.1.3

func (h *PentestHandler) AddCampaignMember(w http.ResponseWriter, r *http.Request)

AddCampaignMember adds a user to a campaign.

func (*PentestHandler) CreateCampaign added in v0.1.2

func (h *PentestHandler) CreateCampaign(w http.ResponseWriter, r *http.Request)

CreateCampaign creates a new campaign.

func (*PentestHandler) CreateFinding added in v0.1.2

func (h *PentestHandler) CreateFinding(w http.ResponseWriter, r *http.Request)

CreateFinding creates a pentest finding.

func (*PentestHandler) CreateReport added in v0.1.2

func (h *PentestHandler) CreateReport(w http.ResponseWriter, r *http.Request)

CreateReport generates a report for a campaign.

func (*PentestHandler) CreateRetest added in v0.1.2

func (h *PentestHandler) CreateRetest(w http.ResponseWriter, r *http.Request)

CreateRetest creates a retest for a finding.

func (*PentestHandler) CreateTemplate added in v0.1.2

func (h *PentestHandler) CreateTemplate(w http.ResponseWriter, r *http.Request)

CreateTemplate creates a finding template.

func (*PentestHandler) DeleteCampaign added in v0.1.2

func (h *PentestHandler) DeleteCampaign(w http.ResponseWriter, r *http.Request)

DeleteCampaign deletes a campaign.

func (*PentestHandler) DeleteFinding added in v0.1.2

func (h *PentestHandler) DeleteFinding(w http.ResponseWriter, r *http.Request)

DeleteFinding deletes a pentest finding.

func (*PentestHandler) DeleteReport added in v0.1.2

func (h *PentestHandler) DeleteReport(w http.ResponseWriter, r *http.Request)

DeleteReport deletes a report.

func (*PentestHandler) DeleteTemplate added in v0.1.2

func (h *PentestHandler) DeleteTemplate(w http.ResponseWriter, r *http.Request)

DeleteTemplate deletes a template.

func (*PentestHandler) GetCampaign added in v0.1.2

func (h *PentestHandler) GetCampaign(w http.ResponseWriter, r *http.Request)

GetCampaign returns a single campaign.

func (*PentestHandler) GetCampaignStats added in v0.1.2

func (h *PentestHandler) GetCampaignStats(w http.ResponseWriter, r *http.Request)

GetCampaignStats returns campaign finding statistics.

func (*PentestHandler) GetFinding added in v0.1.2

func (h *PentestHandler) GetFinding(w http.ResponseWriter, r *http.Request)

GetFinding returns a single pentest finding from the unified findings table.

func (*PentestHandler) GetReport added in v0.1.2

func (h *PentestHandler) GetReport(w http.ResponseWriter, r *http.Request)

GetReport returns a report.

func (*PentestHandler) GetTemplate added in v0.1.2

func (h *PentestHandler) GetTemplate(w http.ResponseWriter, r *http.Request)

GetTemplate returns a template.

func (*PentestHandler) ListAllFindings added in v0.1.2

func (h *PentestHandler) ListAllFindings(w http.ResponseWriter, r *http.Request)

ListAllFindings lists all pentest findings across all campaigns.

func (*PentestHandler) ListCampaignFindings added in v0.1.2

func (h *PentestHandler) ListCampaignFindings(w http.ResponseWriter, r *http.Request)

ListCampaignFindings lists findings for a campaign from the unified findings table.

func (*PentestHandler) ListCampaignMembers added in v0.1.3

func (h *PentestHandler) ListCampaignMembers(w http.ResponseWriter, r *http.Request)

ListCampaignMembers lists all members of a campaign.

func (*PentestHandler) ListCampaigns added in v0.1.2

func (h *PentestHandler) ListCampaigns(w http.ResponseWriter, r *http.Request)

ListCampaigns lists campaigns with filters.

func (*PentestHandler) ListReports added in v0.1.2

func (h *PentestHandler) ListReports(w http.ResponseWriter, r *http.Request)

ListReports lists reports for a campaign.

func (*PentestHandler) ListRetests added in v0.1.2

func (h *PentestHandler) ListRetests(w http.ResponseWriter, r *http.Request)

ListRetests lists retests for a finding.

func (*PentestHandler) ListTemplates added in v0.1.2

func (h *PentestHandler) ListTemplates(w http.ResponseWriter, r *http.Request)

ListTemplates lists finding templates.

func (*PentestHandler) RemoveCampaignMember added in v0.1.3

func (h *PentestHandler) RemoveCampaignMember(w http.ResponseWriter, r *http.Request)

RemoveCampaignMember removes a user from a campaign.

func (*PentestHandler) UpdateCampaign added in v0.1.2

func (h *PentestHandler) UpdateCampaign(w http.ResponseWriter, r *http.Request)

UpdateCampaign updates a campaign.

func (*PentestHandler) UpdateCampaignMemberRole added in v0.1.3

func (h *PentestHandler) UpdateCampaignMemberRole(w http.ResponseWriter, r *http.Request)

UpdateCampaignMemberRole changes a member's role.

func (*PentestHandler) UpdateCampaignStatus added in v0.1.2

func (h *PentestHandler) UpdateCampaignStatus(w http.ResponseWriter, r *http.Request)

UpdateCampaignStatus transitions campaign status.

func (*PentestHandler) UpdateFinding added in v0.1.2

func (h *PentestHandler) UpdateFinding(w http.ResponseWriter, r *http.Request)

UpdateFinding updates a pentest finding in the unified findings table.

func (*PentestHandler) UpdateFindingStatus added in v0.1.2

func (h *PentestHandler) UpdateFindingStatus(w http.ResponseWriter, r *http.Request)

UpdateFindingStatus transitions finding status.

func (*PentestHandler) UpdateTemplate added in v0.1.2

func (h *PentestHandler) UpdateTemplate(w http.ResponseWriter, r *http.Request)

UpdateTemplate updates a template.

type PentestTemplateResponse added in v0.1.2

type PentestTemplateResponse struct {
	ID               string    `json:"id"`
	TenantID         *string   `json:"tenant_id,omitempty"`
	Name             string    `json:"name"`
	Category         string    `json:"category,omitempty"`
	Severity         string    `json:"severity"`
	OWASPCategory    string    `json:"owasp_category,omitempty"`
	CWEID            string    `json:"cwe_id,omitempty"`
	Description      string    `json:"description,omitempty"`
	StepsToReproduce []string  `json:"steps_to_reproduce"`
	BusinessImpact   string    `json:"business_impact,omitempty"`
	TechnicalImpact  string    `json:"technical_impact,omitempty"`
	Remediation      string    `json:"remediation,omitempty"`
	ReferenceURLs    []string  `json:"reference_urls"`
	Tags             []string  `json:"tags"`
	IsSystem         bool      `json:"is_system"`
	UsageCount       int       `json:"usage_count"`
	CreatedAt        time.Time `json:"created_at"`
	UpdatedAt        time.Time `json:"updated_at"`
}

PentestTemplateResponse is the API response for a finding template.

type PermissionHandler

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

PermissionHandler handles permission-related HTTP requests. This handler provides the real-time permission sync endpoint.

func NewPermissionHandler

func NewPermissionHandler(
	permCacheSvc *app.PermissionCacheService,
	permVersionSvc *app.PermissionVersionService,
	log *logger.Logger,
) *PermissionHandler

NewPermissionHandler creates a new permission handler.

func (*PermissionHandler) GetMyPermissions

func (h *PermissionHandler) GetMyPermissions(w http.ResponseWriter, r *http.Request)

GetMyPermissions returns the current user's permissions. This endpoint supports ETag-based caching for efficient polling.

Headers:

  • If-None-Match: ETag from previous response (returns 304 if unchanged)

Response Headers:

  • ETag: Hash of permissions for conditional requests
  • X-Permission-Version: Current version number

@Summary Get current user permissions @Description Returns the permissions for the authenticated user in the current tenant. @Description Supports ETag-based caching: send If-None-Match header to check for changes. @Tags Permissions @Produce json @Security BearerAuth @Param If-None-Match header string false "ETag from previous response" @Success 200 {object} PermissionsResponse @Success 304 "Not Modified - permissions unchanged" @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Router /me/permissions [get]

type PermissionItemResponse

type PermissionItemResponse struct {
	PermissionID     string `json:"permission_id"`
	ModificationType string `json:"modification_type"`
}

PermissionItemResponse represents a permission item in API responses.

type PermissionResponse

type PermissionResponse struct {
	ID          string `json:"id"`
	ModuleID    string `json:"module_id,omitempty"`
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
	IsActive    bool   `json:"is_active"`
}

PermissionResponse represents a permission in API responses.

type PermissionSetHandler

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

PermissionSetHandler handles permission set related HTTP requests.

func NewPermissionSetHandler

func NewPermissionSetHandler(svc *app.PermissionService, v *validator.Validator, log *logger.Logger) *PermissionSetHandler

NewPermissionSetHandler creates a new permission set handler.

func (*PermissionSetHandler) AddPermission

func (h *PermissionSetHandler) AddPermission(w http.ResponseWriter, r *http.Request)

AddPermission handles POST /api/v1/permission-sets/{id}/permissions @Summary Add a permission to a set @Description Add a permission to a permission set @Tags permission-sets @Accept json @Produce json @Param id path string true "Permission set ID" @Param request body AddPermissionRequest true "Permission details" @Success 201 @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/permission-sets/{id}/permissions [post]

func (*PermissionSetHandler) CreatePermissionSet

func (h *PermissionSetHandler) CreatePermissionSet(w http.ResponseWriter, r *http.Request)

CreatePermissionSet handles POST /api/v1/permission-sets @Summary Create a new permission set @Description Create a new permission set for access control @Tags permission-sets @Accept json @Produce json @Param request body CreatePermissionSetRequest true "Permission set details" @Success 201 {object} PermissionSetResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 403 {object} apierror.Error @Router /api/v1/permission-sets [post]

func (*PermissionSetHandler) DeletePermissionSet

func (h *PermissionSetHandler) DeletePermissionSet(w http.ResponseWriter, r *http.Request)

DeletePermissionSet handles DELETE /api/v1/permission-sets/{id} @Summary Delete a permission set @Description Delete a permission set @Tags permission-sets @Param id path string true "Permission set ID" @Success 204 @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/permission-sets/{id} [delete]

func (*PermissionSetHandler) GetMyEffectivePermissions

func (h *PermissionSetHandler) GetMyEffectivePermissions(w http.ResponseWriter, r *http.Request)

GetMyEffectivePermissions handles GET /api/v1/me/permissions @Summary Get effective permissions for current user @Description Get all effective permissions for the current user based on their group memberships @Tags permissions @Produce json @Success 200 {object} EffectivePermissionsResponse @Router /api/v1/me/permissions [get]

func (*PermissionSetHandler) GetPermissionSet

func (h *PermissionSetHandler) GetPermissionSet(w http.ResponseWriter, r *http.Request)

GetPermissionSet handles GET /api/v1/permission-sets/{id} @Summary Get a permission set by ID @Description Get detailed information about a permission set @Tags permission-sets @Produce json @Param id path string true "Permission set ID" @Success 200 {object} PermissionSetWithItemsResponse @Failure 404 {object} apierror.Error @Router /api/v1/permission-sets/{id} [get]

func (*PermissionSetHandler) ListPermissionSets

func (h *PermissionSetHandler) ListPermissionSets(w http.ResponseWriter, r *http.Request)

ListPermissionSets handles GET /api/v1/permission-sets @Summary List permission sets @Description List all permission sets for the tenant @Tags permission-sets @Produce json @Param include_system query bool false "Include system permission sets" @Param type query string false "Filter by type" @Param search query string false "Search by name" @Param limit query int false "Limit results" default(20) @Param offset query int false "Offset for pagination" default(0) @Success 200 {object} PermissionSetListResponse @Router /api/v1/permission-sets [get]

func (*PermissionSetHandler) ListSystemPermissionSets

func (h *PermissionSetHandler) ListSystemPermissionSets(w http.ResponseWriter, r *http.Request)

ListSystemPermissionSets handles GET /api/v1/permission-sets/system @Summary List system permission sets @Description List all system-defined permission sets @Tags permission-sets @Produce json @Success 200 {array} PermissionSetResponse @Router /api/v1/permission-sets/system [get]

func (*PermissionSetHandler) RemovePermission

func (h *PermissionSetHandler) RemovePermission(w http.ResponseWriter, r *http.Request)

RemovePermission handles DELETE /api/v1/permission-sets/{id}/permissions/{permissionId} @Summary Remove a permission from a set @Description Remove a permission from a permission set @Tags permission-sets @Param id path string true "Permission set ID" @Param permissionId path string true "Permission ID" @Success 204 @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/permission-sets/{id}/permissions/{permissionId} [delete]

func (*PermissionSetHandler) UpdatePermissionSet

func (h *PermissionSetHandler) UpdatePermissionSet(w http.ResponseWriter, r *http.Request)

UpdatePermissionSet handles PUT /api/v1/permission-sets/{id} @Summary Update a permission set @Description Update an existing permission set @Tags permission-sets @Accept json @Produce json @Param id path string true "Permission set ID" @Param request body UpdatePermissionSetRequest true "Update details" @Success 200 {object} PermissionSetResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Router /api/v1/permission-sets/{id} [put]

type PermissionSetListResponse

type PermissionSetListResponse struct {
	PermissionSets []PermissionSetResponse `json:"permission_sets"`
	TotalCount     int64                   `json:"total_count"`
	Limit          int                     `json:"limit"`
	Offset         int                     `json:"offset"`
}

PermissionSetListResponse represents a paginated list of permission sets.

type PermissionSetResponse

type PermissionSetResponse struct {
	ID          string    `json:"id"`
	TenantID    *string   `json:"tenant_id,omitempty"`
	Name        string    `json:"name"`
	Slug        string    `json:"slug"`
	Description string    `json:"description,omitempty"`
	SetType     string    `json:"set_type"`
	ParentSetID *string   `json:"parent_set_id,omitempty"`
	IsActive    bool      `json:"is_active"`
	IsSystem    bool      `json:"is_system"`
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

PermissionSetResponse represents a permission set in API responses.

type PermissionSetWithItemsResponse

type PermissionSetWithItemsResponse struct {
	PermissionSetResponse
	Items       []PermissionItemResponse `json:"items"`
	Permissions []string                 `json:"permissions"` // Resolved permissions
}

PermissionSetWithItemsResponse includes permission items.

type PermissionsResponse

type PermissionsResponse struct {
	Permissions []string `json:"permissions"`
	Version     int      `json:"version"`
}

PermissionsResponse represents the response for GET /me/permissions.

type Pinger

type Pinger interface {
	Ping(ctx context.Context) error
}

Pinger interface for health check dependencies.

type PipelineHandler

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

PipelineHandler handles HTTP requests for pipelines.

func NewPipelineHandler

func NewPipelineHandler(service *pipelinesvc.Service, v *validator.Validator, log *logger.Logger) *PipelineHandler

NewPipelineHandler creates a new PipelineHandler.

func (*PipelineHandler) ActivateTemplate

func (h *PipelineHandler) ActivateTemplate(w http.ResponseWriter, r *http.Request)

ActivateTemplate handles POST /api/v1/pipelines/{id}/activate

func (*PipelineHandler) AddStep

func (h *PipelineHandler) AddStep(w http.ResponseWriter, r *http.Request)

AddStep handles POST /api/v1/pipelines/templates/{id}/steps

func (*PipelineHandler) CancelRun

func (h *PipelineHandler) CancelRun(w http.ResponseWriter, r *http.Request)

CancelRun handles POST /api/v1/pipelines/runs/{id}/cancel

func (*PipelineHandler) CloneTemplate

func (h *PipelineHandler) CloneTemplate(w http.ResponseWriter, r *http.Request)

CloneTemplate handles POST /api/v1/pipelines/{id}/clone

func (*PipelineHandler) CreateTemplate

func (h *PipelineHandler) CreateTemplate(w http.ResponseWriter, r *http.Request)

CreateTemplate handles POST /api/v1/pipelines/templates

func (*PipelineHandler) DeactivateTemplate

func (h *PipelineHandler) DeactivateTemplate(w http.ResponseWriter, r *http.Request)

DeactivateTemplate handles POST /api/v1/pipelines/{id}/deactivate

func (*PipelineHandler) DeleteStep

func (h *PipelineHandler) DeleteStep(w http.ResponseWriter, r *http.Request)

DeleteStep handles DELETE /api/v1/pipelines/templates/{id}/steps/{stepId}

func (*PipelineHandler) DeleteTemplate

func (h *PipelineHandler) DeleteTemplate(w http.ResponseWriter, r *http.Request)

DeleteTemplate handles DELETE /api/v1/pipelines/templates/{id}

func (*PipelineHandler) GetRun

func (h *PipelineHandler) GetRun(w http.ResponseWriter, r *http.Request)

GetRun handles GET /api/v1/pipelines/runs/{id}

func (*PipelineHandler) GetTemplate

func (h *PipelineHandler) GetTemplate(w http.ResponseWriter, r *http.Request)

GetTemplate handles GET /api/v1/pipelines/templates/{id}

func (*PipelineHandler) ListRuns

func (h *PipelineHandler) ListRuns(w http.ResponseWriter, r *http.Request)

ListRuns handles GET /api/v1/pipelines/runs

func (*PipelineHandler) ListTemplates

func (h *PipelineHandler) ListTemplates(w http.ResponseWriter, r *http.Request)

ListTemplates handles GET /api/v1/pipelines/templates

func (*PipelineHandler) TriggerRun

func (h *PipelineHandler) TriggerRun(w http.ResponseWriter, r *http.Request)

TriggerRun handles POST /api/v1/pipelines/runs

func (*PipelineHandler) UpdateStep

func (h *PipelineHandler) UpdateStep(w http.ResponseWriter, r *http.Request)

UpdateStep handles PUT /api/v1/pipelines/templates/{id}/steps/{stepId}

func (*PipelineHandler) UpdateTemplate

func (h *PipelineHandler) UpdateTemplate(w http.ResponseWriter, r *http.Request)

UpdateTemplate handles PUT /api/v1/pipelines/templates/{id}

type PipelineSettingsRequest

type PipelineSettingsRequest struct {
	MaxParallelSteps     int      `json:"max_parallel_steps" validate:"min=0,max=10"`
	FailFast             bool     `json:"fail_fast"`
	RetryFailedSteps     int      `json:"retry_failed_steps" validate:"min=0,max=5"`
	TimeoutSeconds       int      `json:"timeout_seconds" validate:"min=0,max=86400"`
	NotifyOnComplete     bool     `json:"notify_on_complete"`
	NotifyOnFailure      bool     `json:"notify_on_failure"`
	NotificationChannels []string `json:"notification_channels"`
	AgentPreference      string   `json:"agent_preference" validate:"omitempty,oneof=auto tenant platform"`
}

PipelineSettingsRequest represents template settings in the request.

type PipelineSettingsResponse

type PipelineSettingsResponse struct {
	MaxParallelSteps     int      `json:"max_parallel_steps"`
	FailFast             bool     `json:"fail_fast"`
	RetryFailedSteps     int      `json:"retry_failed_steps"`
	TimeoutSeconds       int      `json:"timeout_seconds"`
	NotifyOnComplete     bool     `json:"notify_on_complete"`
	NotifyOnFailure      bool     `json:"notify_on_failure"`
	NotificationChannels []string `json:"notification_channels,omitempty"`
	AgentPreference      string   `json:"agent_preference"`
}

PipelineSettingsResponse represents template settings in the response.

type PlatformStatsHandler added in v0.1.2

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

PlatformStatsHandler handles platform stats API requests.

func NewPlatformStatsHandler added in v0.1.2

func NewPlatformStatsHandler(agentService *app.AgentService, log *logger.Logger) *PlatformStatsHandler

NewPlatformStatsHandler creates a new PlatformStatsHandler.

func (*PlatformStatsHandler) GetStats added in v0.1.2

GetStats returns platform agent statistics for the current tenant.

type PlatformStatsResponse added in v0.1.2

type PlatformStatsResponse struct {
	Enabled         bool                         `json:"enabled"`
	MaxTier         string                       `json:"max_tier"`
	AccessibleTiers []string                     `json:"accessible_tiers"`
	MaxConcurrent   int                          `json:"max_concurrent"`
	MaxQueued       int                          `json:"max_queued"`
	CurrentActive   int                          `json:"current_active"`
	CurrentQueued   int                          `json:"current_queued"`
	AvailableSlots  int                          `json:"available_slots"`
	TierStats       map[string]TierStatsResponse `json:"tier_stats"`
}

PlatformStatsResponse represents the platform stats API response.

type PortCountResponse

type PortCountResponse struct {
	Port  int `json:"port"`
	Count int `json:"count"`
}

PortCountResponse represents a port count entry.

type PreferencesDTO

type PreferencesDTO struct {
	Theme         string `json:"theme,omitempty"`
	Language      string `json:"language,omitempty"`
	Notifications bool   `json:"notifications"`
}

PreferencesDTO represents user preferences in API responses.

type PreferencesResponse added in v0.1.2

type PreferencesResponse struct {
	InAppEnabled bool     `json:"in_app_enabled"`
	EmailDigest  string   `json:"email_digest"`
	MutedTypes   []string `json:"muted_types"`
	MinSeverity  string   `json:"min_severity"`
	UpdatedAt    string   `json:"updated_at"`
}

PreferencesResponse represents notification preferences in API responses.

type ProviderDetailResponse added in v0.1.2

type ProviderDetailResponse struct {
	ID               string   `json:"id"`
	TenantID         string   `json:"tenant_id"`
	Provider         string   `json:"provider"`
	DisplayName      string   `json:"display_name"`
	ClientID         string   `json:"client_id"`
	IssuerURL        string   `json:"issuer_url,omitempty"`
	TenantIdentifier string   `json:"tenant_identifier,omitempty"`
	Scopes           []string `json:"scopes"`
	AllowedDomains   []string `json:"allowed_domains"`
	AutoProvision    bool     `json:"auto_provision"`
	DefaultRole      string   `json:"default_role"`
	IsActive         bool     `json:"is_active"`
	CreatedAt        string   `json:"created_at"`
	UpdatedAt        string   `json:"updated_at"`
	CreatedBy        string   `json:"created_by,omitempty"`
}

ProviderDetailResponse is the JSON response for an identity provider.

type ProvidersResponse

type ProvidersResponse struct {
	Providers []app.ProviderInfo `json:"providers"`
}

ProvidersResponse is the response body for listing available providers.

type QualityGateBreachResponse

type QualityGateBreachResponse struct {
	Metric string `json:"metric"`
	Limit  int    `json:"limit"`
	Actual int    `json:"actual"`
}

QualityGateBreachResponse represents a single threshold violation.

type QualityGateRequest

type QualityGateRequest struct {
	Enabled         bool   `json:"enabled"`
	FailOnCritical  bool   `json:"fail_on_critical"`
	FailOnHigh      bool   `json:"fail_on_high"`
	MaxCritical     int    `json:"max_critical"`
	MaxHigh         int    `json:"max_high"`
	MaxMedium       int    `json:"max_medium"`
	MaxTotal        int    `json:"max_total"`
	NewFindingsOnly bool   `json:"new_findings_only,omitempty"`
	BaselineBranch  string `json:"baseline_branch,omitempty"`
}

QualityGateRequest represents quality gate configuration in request.

type QualityGateResponse

type QualityGateResponse struct {
	Enabled         bool   `json:"enabled"`
	FailOnCritical  bool   `json:"fail_on_critical"`
	FailOnHigh      bool   `json:"fail_on_high"`
	MaxCritical     int    `json:"max_critical"`
	MaxHigh         int    `json:"max_high"`
	MaxMedium       int    `json:"max_medium"`
	MaxTotal        int    `json:"max_total"`
	NewFindingsOnly bool   `json:"new_findings_only,omitempty"`
	BaselineBranch  string `json:"baseline_branch,omitempty"`
}

QualityGateResponse represents quality gate configuration in response.

type QualityGateResultResponse

type QualityGateResultResponse struct {
	Passed   bool                        `json:"passed"`
	Reason   string                      `json:"reason,omitempty"`
	Breaches []QualityGateBreachResponse `json:"breaches,omitempty"`
	Counts   FindingCountsResponse       `json:"counts"`
}

QualityGateResultResponse represents the result of quality gate evaluation.

type QuickScanRequest

type QuickScanRequest struct {
	Targets     []string       `json:"targets" validate:"required,min=1,max=1000"`
	ScannerName string         `json:"scanner_name" validate:"omitempty,max=100"`
	WorkflowID  string         `json:"workflow_id" validate:"omitempty,uuid"`
	Config      map[string]any `json:"config"`
	Tags        []string       `json:"tags" validate:"max=20,dive,max=50"`
}

QuickScanRequest represents the request body for quick scan.

type QuickScanResponse

type QuickScanResponse struct {
	PipelineRunID string `json:"pipeline_run_id"`
	ScanID        string `json:"scan_id"`
	AssetGroupID  string `json:"asset_group_id"`
	Status        string `json:"status"`
	TargetCount   int    `json:"target_count"`
}

QuickScanResponse represents the response for quick scan.

type ReadyResponse

type ReadyResponse struct {
	Status    string                 `json:"status"`
	Timestamp time.Time              `json:"timestamp"`
	Checks    map[string]CheckResult `json:"checks,omitempty"`
}

ReadyResponse represents the readiness check response.

type ReconIngestRequest

type ReconIngestRequest struct {
	// Scanner info
	ScannerName    string `json:"scanner_name"`
	ScannerVersion string `json:"scanner_version,omitempty"`
	ReconType      string `json:"recon_type"` // subdomain, dns, port, http_probe, url_crawl

	// Target
	Target string `json:"target"`

	// Timing
	StartedAt  int64 `json:"started_at,omitempty"`
	FinishedAt int64 `json:"finished_at,omitempty"`
	DurationMs int64 `json:"duration_ms,omitempty"`

	// Results (populated based on recon_type)
	Subdomains []SubdomainResult     `json:"subdomains,omitempty"`
	DNSRecords []DNSRecordResult     `json:"dns_records,omitempty"`
	OpenPorts  []OpenPortResult      `json:"open_ports,omitempty"`
	LiveHosts  []LiveHostResult      `json:"live_hosts,omitempty"`
	URLs       []DiscoveredURLResult `json:"urls,omitempty"`
}

ReconIngestRequest represents reconnaissance scan results to ingest.

type ReferenceResponse

type ReferenceResponse struct {
	Type string `json:"type"`
	URL  string `json:"url"`
}

ReferenceResponse represents a reference in API responses.

type RefreshTokenRequest

type RefreshTokenRequest struct {
	RefreshToken string `json:"refresh_token"` // Optional if cookie is present
	TenantID     string `json:"tenant_id" validate:"required"`
}

RefreshTokenRequest is the request body for token refresh. refresh_token can be omitted if sent via httpOnly cookie.

type RefreshTokenResponse

type RefreshTokenResponse struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token,omitempty"` // Also set in httpOnly cookie
	TokenType    string `json:"token_type"`
	ExpiresIn    int64  `json:"expires_in"`
	TenantID     string `json:"tenant_id"`
	TenantSlug   string `json:"tenant_slug"`
	Role         string `json:"role"`
}

RefreshTokenResponse is the response body for token refresh. Returns both new access token and rotated refresh token. Note: new refresh_token is also set in httpOnly cookie.

type RegisterRequest

type RegisterRequest struct {
	Email    string `json:"email" validate:"required,email,max=255"`
	Password string `json:"password" validate:"required,min=8,max=128"`
	Name     string `json:"name" validate:"required,max=255"`
}

RegisterRequest is the request body for user registration.

type RegisterResponse

type RegisterResponse struct {
	ID                   string `json:"id"`
	Email                string `json:"email"`
	Name                 string `json:"name"`
	RequiresVerification bool   `json:"requires_verification"`
	Message              string `json:"message"`
}

RegisterResponse is the response body for user registration.

type RegisterScanRequest

type RegisterScanRequest struct {
	ScannerName    string `json:"scanner_name" validate:"required"`
	ScannerVersion string `json:"scanner_version"`
	ScannerType    string `json:"scanner_type"`
	AssetType      string `json:"asset_type" validate:"required"`
	AssetValue     string `json:"asset_value" validate:"required"`
	CommitSha      string `json:"commit_sha"`
	Branch         string `json:"branch"`
}

RegisterScanRequest represents the request to register a scan.

type RegisterScanResponse

type RegisterScanResponse struct {
	ScanID        string `json:"scan_id"`
	BaseCommitSha string `json:"base_commit_sha,omitempty"`
	ScanURL       string `json:"scan_url,omitempty"`
}

RegisterScanResponse represents the response from registering a scan.

type RejectApprovalRequest added in v0.1.2

type RejectApprovalRequest struct {
	Reason string `json:"reason" validate:"required,min=1,max=2000"`
}

RejectApprovalRequest represents the request body for rejecting.

type RejectFixRequest added in v0.1.3

type RejectFixRequest struct {
	FindingIDs []string              `json:"finding_ids" validate:"max=100"`
	Filter     *FindingFilterRequest `json:"filter"`
	Reason     string                `json:"reason" validate:"max=5000"`
}

RejectFixRequest supports both finding_ids and filter.

type RejectRuleRequest

type RejectRuleRequest struct {
	Reason string `json:"reason"`
}

RejectRuleRequest represents a request to reject a rule.

type RelationshipResponse

type RelationshipResponse struct {
	ID              string     `json:"id"`
	Type            string     `json:"type"`
	SourceAssetID   string     `json:"source_asset_id"`
	SourceAssetName string     `json:"source_asset_name"`
	SourceAssetType string     `json:"source_asset_type"`
	TargetAssetID   string     `json:"target_asset_id"`
	TargetAssetName string     `json:"target_asset_name"`
	TargetAssetType string     `json:"target_asset_type"`
	Description     string     `json:"description,omitempty"`
	Confidence      string     `json:"confidence"`
	DiscoveryMethod string     `json:"discovery_method"`
	ImpactWeight    int        `json:"impact_weight"`
	Tags            []string   `json:"tags,omitempty"`
	CreatedAt       time.Time  `json:"created_at"`
	UpdatedAt       time.Time  `json:"updated_at"`
	LastVerified    *time.Time `json:"last_verified,omitempty"`
}

RelationshipResponse represents a relationship in API responses.

type RemoveAssetsRequest

type RemoveAssetsRequest struct {
	AssetIDs []string `json:"asset_ids" validate:"required,min=1,dive,uuid"`
}

RemoveAssetsRequest represents the request to remove assets from a group.

type ReportResponse added in v0.1.2

type ReportResponse struct {
	ID           string         `json:"id"`
	CampaignID   string         `json:"campaign_id"`
	Name         string         `json:"name"`
	ReportType   string         `json:"report_type"`
	Format       string         `json:"format"`
	Status       string         `json:"status"`
	Options      map[string]any `json:"options,omitempty"`
	FileSize     int64          `json:"file_size"`
	DownloadURL  string         `json:"download_url,omitempty"`
	GeneratedAt  *time.Time     `json:"generated_at,omitempty"`
	ErrorMessage string         `json:"error_message,omitempty"`
	CreatedAt    time.Time      `json:"created_at"`
	CreatedBy    *string        `json:"created_by,omitempty"`
}

ReportResponse is the API response for a pentest report.

type RepositoryExtensionResponse

type RepositoryExtensionResponse struct {
	AssetID              string           `json:"asset_id"`
	RepoID               string           `json:"repo_id,omitempty"`
	FullName             string           `json:"full_name"`
	SCMOrganization      string           `json:"scm_organization,omitempty"`
	CloneURL             string           `json:"clone_url,omitempty"`
	WebURL               string           `json:"web_url,omitempty"`
	SSHURL               string           `json:"ssh_url,omitempty"`
	DefaultBranch        string           `json:"default_branch,omitempty"`
	Visibility           string           `json:"visibility"`
	Language             string           `json:"language,omitempty"`
	Languages            map[string]int64 `json:"languages,omitempty"`
	Topics               []string         `json:"topics,omitempty"`
	Stars                int              `json:"stars"`
	Forks                int              `json:"forks"`
	Watchers             int              `json:"watchers"`
	OpenIssues           int              `json:"open_issues"`
	ContributorsCount    int              `json:"contributors_count"`
	SizeKB               int              `json:"size_kb"`
	BranchCount          int              `json:"branch_count"`
	ProtectedBranchCount int              `json:"protected_branch_count"`
	ComponentCount       int              `json:"component_count"`
	VulnComponentCount   int              `json:"vulnerable_component_count"`
	FindingCount         int              `json:"finding_count"`
	ScanEnabled          bool             `json:"scan_enabled"`
	ScanSchedule         string           `json:"scan_schedule,omitempty"`
	LastScannedAt        *time.Time       `json:"last_scanned_at,omitempty"`
	RepoCreatedAt        *time.Time       `json:"repo_created_at,omitempty"`
	RepoUpdatedAt        *time.Time       `json:"repo_updated_at,omitempty"`
	RepoPushedAt         *time.Time       `json:"repo_pushed_at,omitempty"`
}

RepositoryExtensionResponse represents a repository extension in API responses.

type RepositoryStats

type RepositoryStats struct {
	Total        int `json:"total"`
	WithFindings int `json:"with_findings"`
}

RepositoryStats represents repository statistics.

type RequestApprovalRequest added in v0.1.2

type RequestApprovalRequest struct {
	RequestedStatus string  `json:"requested_status" validate:"required"`
	Justification   string  `json:"justification" validate:"required,min=1,max=2000"`
	ExpiresAt       *string `json:"expires_at"`
}

RequestApprovalRequest represents the request body for requesting an approval.

type RequestTriageRequest

type RequestTriageRequest struct {
	Mode string `json:"mode"` // "quick" or "detailed" (optional, defaults to quick)
}

RequestTriageRequest represents a request to trigger AI triage.

type RequestTriageResponse

type RequestTriageResponse struct {
	JobID  string `json:"job_id"`
	Status string `json:"status"`
}

RequestTriageResponse represents the response from triggering AI triage.

type ResetPasswordRequest

type ResetPasswordRequest struct {
	Token       string `json:"token" validate:"required"`
	NewPassword string `json:"new_password" validate:"required,min=8,max=128"`
}

ResetPasswordRequest is the request body for password reset.

type RetestResponse added in v0.1.2

type RetestResponse struct {
	ID        string           `json:"id"`
	FindingID string           `json:"finding_id"`
	Status    string           `json:"status"`
	Notes     string           `json:"notes,omitempty"`
	Evidence  []map[string]any `json:"evidence"`
	TestedBy  *string          `json:"tested_by,omitempty"`
	TestedAt  *time.Time       `json:"tested_at,omitempty"`
	CreatedAt time.Time        `json:"created_at"`
}

RetestResponse is the API response for a retest.

type RoleHandler

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

RoleHandler handles role-related HTTP requests.

func NewRoleHandler

func NewRoleHandler(svc *app.RoleService, v *validator.Validator, log *logger.Logger) *RoleHandler

NewRoleHandler creates a new role handler.

func (*RoleHandler) AssignRole

func (h *RoleHandler) AssignRole(w http.ResponseWriter, r *http.Request)

AssignRole handles POST /api/v1/users/{userId}/roles

func (*RoleHandler) BulkAssignRoleMembers

func (h *RoleHandler) BulkAssignRoleMembers(w http.ResponseWriter, r *http.Request)

BulkAssignRoleMembers handles POST /api/v1/roles/{roleId}/members/bulk Assigns a role to multiple users at once.

func (*RoleHandler) CreateRole

func (h *RoleHandler) CreateRole(w http.ResponseWriter, r *http.Request)

CreateRole handles POST /api/v1/roles

func (*RoleHandler) DeleteRole

func (h *RoleHandler) DeleteRole(w http.ResponseWriter, r *http.Request)

DeleteRole handles DELETE /api/v1/roles/{roleId}

func (*RoleHandler) GetMyPermissions

func (h *RoleHandler) GetMyPermissions(w http.ResponseWriter, r *http.Request)

GetMyPermissions handles GET /api/v1/me/permissions

func (*RoleHandler) GetMyRoles

func (h *RoleHandler) GetMyRoles(w http.ResponseWriter, r *http.Request)

GetMyRoles handles GET /api/v1/me/roles

func (*RoleHandler) GetRole

func (h *RoleHandler) GetRole(w http.ResponseWriter, r *http.Request)

GetRole handles GET /api/v1/roles/{roleId}

func (*RoleHandler) GetUserRoles

func (h *RoleHandler) GetUserRoles(w http.ResponseWriter, r *http.Request)

GetUserRoles handles GET /api/v1/users/{userId}/roles

func (*RoleHandler) ListModulesWithPermissions

func (h *RoleHandler) ListModulesWithPermissions(w http.ResponseWriter, r *http.Request)

ListModulesWithPermissions handles GET /api/v1/permissions/modules

func (*RoleHandler) ListPermissions

func (h *RoleHandler) ListPermissions(w http.ResponseWriter, r *http.Request)

ListPermissions handles GET /api/v1/permissions

func (*RoleHandler) ListRoleMembers

func (h *RoleHandler) ListRoleMembers(w http.ResponseWriter, r *http.Request)

ListRoleMembers handles GET /api/v1/roles/{roleId}/members

func (*RoleHandler) ListRoles

func (h *RoleHandler) ListRoles(w http.ResponseWriter, r *http.Request)

ListRoles handles GET /api/v1/roles

func (*RoleHandler) RemoveRole

func (h *RoleHandler) RemoveRole(w http.ResponseWriter, r *http.Request)

RemoveRole handles DELETE /api/v1/users/{userId}/roles/{roleId}

func (*RoleHandler) SetUserRoles

func (h *RoleHandler) SetUserRoles(w http.ResponseWriter, r *http.Request)

SetUserRoles handles PUT /api/v1/users/{userId}/roles

func (*RoleHandler) UpdateRole

func (h *RoleHandler) UpdateRole(w http.ResponseWriter, r *http.Request)

UpdateRole handles PUT /api/v1/roles/{roleId}

type RoleListResponse

type RoleListResponse struct {
	Roles []RoleResponse `json:"roles"`
	Total int            `json:"total"`
}

RoleListResponse represents a list of roles.

type RoleResponse

type RoleResponse struct {
	ID                string    `json:"id"`
	TenantID          *string   `json:"tenant_id,omitempty"`
	Slug              string    `json:"slug"`
	Name              string    `json:"name"`
	Description       string    `json:"description,omitempty"`
	IsSystem          bool      `json:"is_system"`
	HierarchyLevel    int       `json:"hierarchy_level"`
	HasFullDataAccess bool      `json:"has_full_data_access"`
	Permissions       []string  `json:"permissions"`
	PermissionCount   int       `json:"permission_count"`
	CreatedAt         time.Time `json:"created_at"`
	UpdatedAt         time.Time `json:"updated_at"`
}

RoleResponse represents a role in API responses.

type RuleHandler

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

RuleHandler handles HTTP requests for rule management.

func NewRuleHandler

func NewRuleHandler(service *app.RuleService, v *validator.Validator, log *logger.Logger) *RuleHandler

NewRuleHandler creates a new RuleHandler.

func (*RuleHandler) CreateOverride

func (h *RuleHandler) CreateOverride(w http.ResponseWriter, r *http.Request)

CreateOverride handles POST /overrides

func (*RuleHandler) CreateSource

func (h *RuleHandler) CreateSource(w http.ResponseWriter, r *http.Request)

CreateSource handles POST /sources

func (*RuleHandler) DeleteOverride

func (h *RuleHandler) DeleteOverride(w http.ResponseWriter, r *http.Request)

DeleteOverride handles DELETE /overrides/{overrideId}

func (*RuleHandler) DeleteSource

func (h *RuleHandler) DeleteSource(w http.ResponseWriter, r *http.Request)

DeleteSource handles DELETE /sources/{sourceId}

func (*RuleHandler) DisableSource

func (h *RuleHandler) DisableSource(w http.ResponseWriter, r *http.Request)

DisableSource handles POST /sources/{sourceId}/disable

func (*RuleHandler) EnableSource

func (h *RuleHandler) EnableSource(w http.ResponseWriter, r *http.Request)

EnableSource handles POST /sources/{sourceId}/enable

func (*RuleHandler) GetBundle

func (h *RuleHandler) GetBundle(w http.ResponseWriter, r *http.Request)

GetBundle handles GET /bundles/{bundleId}

func (*RuleHandler) GetLatestBundle

func (h *RuleHandler) GetLatestBundle(w http.ResponseWriter, r *http.Request)

GetLatestBundle handles GET /bundles/latest

func (*RuleHandler) GetOverride

func (h *RuleHandler) GetOverride(w http.ResponseWriter, r *http.Request)

GetOverride handles GET /overrides/{overrideId}

func (*RuleHandler) GetRule

func (h *RuleHandler) GetRule(w http.ResponseWriter, r *http.Request)

GetRule handles GET /rules/{ruleId}

func (*RuleHandler) GetSource

func (h *RuleHandler) GetSource(w http.ResponseWriter, r *http.Request)

GetSource handles GET /sources/{sourceId}

func (*RuleHandler) GetSyncHistory

func (h *RuleHandler) GetSyncHistory(w http.ResponseWriter, r *http.Request)

GetSyncHistory handles GET /sources/{sourceId}/sync-history

func (*RuleHandler) ListBundles

func (h *RuleHandler) ListBundles(w http.ResponseWriter, r *http.Request)

ListBundles handles GET /bundles

func (*RuleHandler) ListOverrides

func (h *RuleHandler) ListOverrides(w http.ResponseWriter, r *http.Request)

ListOverrides handles GET /overrides

func (*RuleHandler) ListRules

func (h *RuleHandler) ListRules(w http.ResponseWriter, r *http.Request)

ListRules handles GET /rules

func (*RuleHandler) ListSources

func (h *RuleHandler) ListSources(w http.ResponseWriter, r *http.Request)

ListSources handles GET /sources

func (*RuleHandler) UpdateOverride

func (h *RuleHandler) UpdateOverride(w http.ResponseWriter, r *http.Request)

UpdateOverride handles PUT /overrides/{overrideId}

func (*RuleHandler) UpdateSource

func (h *RuleHandler) UpdateSource(w http.ResponseWriter, r *http.Request)

UpdateSource handles PUT /sources/{sourceId}

type RuleResponse

type RuleResponse struct {
	ID             string   `json:"id"`
	SourceID       string   `json:"source_id"`
	TenantID       string   `json:"tenant_id"`
	ToolID         *string  `json:"tool_id,omitempty"`
	RuleID         string   `json:"rule_id"`
	Name           string   `json:"name,omitempty"`
	Severity       string   `json:"severity,omitempty"`
	Category       string   `json:"category,omitempty"`
	Subcategory    string   `json:"subcategory,omitempty"`
	Tags           []string `json:"tags,omitempty"`
	Description    string   `json:"description,omitempty"`
	Recommendation string   `json:"recommendation,omitempty"`
	References     []string `json:"references,omitempty"`
	CWEIDs         []string `json:"cwe_ids,omitempty"`
	OWASPIDs       []string `json:"owasp_ids,omitempty"`
	FilePath       string   `json:"file_path,omitempty"`
	ContentHash    string   `json:"content_hash,omitempty"`
	CreatedAt      string   `json:"created_at"`
	UpdatedAt      string   `json:"updated_at"`
}

RuleResponse represents the response for a rule.

type RunResponse

type RunResponse struct {
	ID                string                         `json:"id"`
	TenantID          string                         `json:"tenant_id"`
	PipelineID        string                         `json:"pipeline_id"`
	AssetID           *string                        `json:"asset_id,omitempty"`
	ScanID            *string                        `json:"scan_id,omitempty"`
	ScanProfileID     *string                        `json:"scan_profile_id,omitempty"`
	TriggerType       string                         `json:"trigger_type"`
	TriggeredBy       string                         `json:"triggered_by,omitempty"`
	Status            string                         `json:"status"`
	StartedAt         *string                        `json:"started_at,omitempty"`
	CompletedAt       *string                        `json:"completed_at,omitempty"`
	TotalSteps        int                            `json:"total_steps"`
	CompletedSteps    int                            `json:"completed_steps"`
	FailedSteps       int                            `json:"failed_steps"`
	SkippedSteps      int                            `json:"skipped_steps"`
	TotalFindings     int                            `json:"total_findings"`
	QualityGateResult *scanprofile.QualityGateResult `json:"quality_gate_result,omitempty"`
	StepRuns          []StepRunResponse              `json:"step_runs,omitempty"`
	ErrorMessage      string                         `json:"error_message,omitempty"`
	CreatedAt         string                         `json:"created_at"`
	FilteringResult   *FilteringResultResponse       `json:"filtering_result,omitempty"`
}

RunResponse represents the response for a pipeline run.

type SCMExtensionResponse

type SCMExtensionResponse struct {
	SCMOrganization      string     `json:"scm_organization,omitempty" example:"my-organization"`
	RepositoryCount      int        `json:"repository_count" example:"25"`
	WebhookID            string     `json:"webhook_id,omitempty"`
	WebhookURL           string     `json:"webhook_url,omitempty"`
	DefaultBranchPattern string     `json:"default_branch_pattern,omitempty" example:"main,master"`
	AutoImportRepos      bool       `json:"auto_import_repos" example:"false"`
	ImportPrivateRepos   bool       `json:"import_private_repos" example:"true"`
	ImportArchivedRepos  bool       `json:"import_archived_repos" example:"false"`
	IncludePatterns      []string   `json:"include_patterns,omitempty"`
	ExcludePatterns      []string   `json:"exclude_patterns,omitempty"`
	LastRepoSyncAt       *time.Time `json:"last_repo_sync_at,omitempty"`
}

SCMExtensionResponse represents SCM-specific extension data.

type SCMRepositoryResponse

type SCMRepositoryResponse struct {
	ID            string         `json:"id"`
	Name          string         `json:"name"`
	FullName      string         `json:"full_name"`
	Description   string         `json:"description,omitempty"`
	HTMLURL       string         `json:"html_url"`
	CloneURL      string         `json:"clone_url"`
	SSHURL        string         `json:"ssh_url"`
	DefaultBranch string         `json:"default_branch"`
	IsPrivate     bool           `json:"is_private"`
	IsFork        bool           `json:"is_fork"`
	IsArchived    bool           `json:"is_archived"`
	Language      string         `json:"language,omitempty"`
	Languages     map[string]int `json:"languages,omitempty"`
	Topics        []string       `json:"topics,omitempty"`
	Stars         int            `json:"stars"`
	Forks         int            `json:"forks"`
	Size          int            `json:"size"`
	CreatedAt     time.Time      `json:"created_at"`
	UpdatedAt     time.Time      `json:"updated_at"`
	PushedAt      time.Time      `json:"pushed_at"`
}

SCMRepositoryResponse represents a repository from an SCM provider. @Description Repository from SCM provider

type SLAHandler

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

SLAHandler handles SLA policy-related HTTP requests.

func NewSLAHandler

func NewSLAHandler(svc *app.SLAService, v *validator.Validator, log *logger.Logger) *SLAHandler

NewSLAHandler creates a new SLA handler.

func (*SLAHandler) Create

func (h *SLAHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/sla-policies @Summary Create SLA policy @Description Creates a new SLA policy for the tenant @Tags SLA Policies @Accept json @Produce json @Security BearerAuth @Param request body CreateSLAPolicyRequest true "SLA Policy data" @Success 201 {object} SLAPolicyResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Failure 409 {object} map[string]string @Router /sla-policies [post]

func (*SLAHandler) Delete

func (h *SLAHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/sla-policies/{id} @Summary Delete SLA policy @Description Deletes an SLA policy @Tags SLA Policies @Security BearerAuth @Param id path string true "SLA Policy ID" @Success 204 "No Content" @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /sla-policies/{id} [delete]

func (*SLAHandler) Get

func (h *SLAHandler) Get(w http.ResponseWriter, r *http.Request)

Get handles GET /api/v1/sla-policies/{id} @Summary Get SLA policy @Description Retrieves an SLA policy by ID @Tags SLA Policies @Produce json @Security BearerAuth @Param id path string true "SLA Policy ID" @Success 200 {object} SLAPolicyResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /sla-policies/{id} [get]

func (*SLAHandler) GetByAsset

func (h *SLAHandler) GetByAsset(w http.ResponseWriter, r *http.Request)

GetByAsset handles GET /api/v1/assets/{id}/sla-policy @Summary Get asset SLA policy @Description Gets the SLA policy for a specific asset (or default if not set) @Tags SLA Policies @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Success 200 {object} SLAPolicyResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /assets/{id}/sla-policy [get]

func (*SLAHandler) GetDefault

func (h *SLAHandler) GetDefault(w http.ResponseWriter, r *http.Request)

GetDefault handles GET /api/v1/sla-policies/default @Summary Get default SLA policy @Description Gets the default SLA policy for the tenant @Tags SLA Policies @Produce json @Security BearerAuth @Success 200 {object} SLAPolicyResponse @Failure 404 {object} map[string]string @Router /sla-policies/default [get]

func (*SLAHandler) List

func (h *SLAHandler) List(w http.ResponseWriter, r *http.Request)

List handles GET /api/v1/sla-policies @Summary List SLA policies @Description Retrieves all SLA policies for the current tenant @Tags SLA Policies @Produce json @Security BearerAuth @Success 200 {object} map[string]interface{} @Failure 401 {object} map[string]string @Failure 500 {object} map[string]string @Router /sla-policies [get]

func (*SLAHandler) Update

func (h *SLAHandler) Update(w http.ResponseWriter, r *http.Request)

Update handles PUT /api/v1/sla-policies/{id} @Summary Update SLA policy @Description Updates an SLA policy @Tags SLA Policies @Accept json @Produce json @Security BearerAuth @Param id path string true "SLA Policy ID" @Param request body UpdateSLAPolicyRequest true "SLA Policy data" @Success 200 {object} SLAPolicyResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /sla-policies/{id} [put]

type SLAPolicyResponse

type SLAPolicyResponse struct {
	ID                  string         `json:"id"`
	TenantID            string         `json:"tenant_id"`
	AssetID             string         `json:"asset_id,omitempty"`
	Name                string         `json:"name"`
	Description         string         `json:"description,omitempty"`
	IsDefault           bool           `json:"is_default"`
	CriticalDays        int            `json:"critical_days"`
	HighDays            int            `json:"high_days"`
	MediumDays          int            `json:"medium_days"`
	LowDays             int            `json:"low_days"`
	InfoDays            int            `json:"info_days"`
	WarningThresholdPct int            `json:"warning_threshold_pct"`
	EscalationEnabled   bool           `json:"escalation_enabled"`
	EscalationConfig    map[string]any `json:"escalation_config,omitempty"`
	IsActive            bool           `json:"is_active"`
	CreatedAt           time.Time      `json:"created_at"`
	UpdatedAt           time.Time      `json:"updated_at"`
}

SLAPolicyResponse represents an SLA policy in API responses.

type SSHKeyDataRequest

type SSHKeyDataRequest struct {
	PrivateKey string `json:"private_key" validate:"required"`
	Passphrase string `json:"passphrase,omitempty"`
}

SSHKeyDataRequest represents SSH key credential data.

type SSOCallbackRequest added in v0.1.2

type SSOCallbackRequest struct {
	Code        string `json:"code" validate:"required"`
	State       string `json:"state" validate:"required"`
	RedirectURI string `json:"redirect_uri" validate:"required"`
}

SSOCallbackRequest is the request body for SSO callback.

type SSOHandler added in v0.1.2

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

SSOHandler handles per-tenant SSO authentication requests.

func NewSSOHandler added in v0.1.2

func NewSSOHandler(ssoService *app.SSOService, log *logger.Logger) *SSOHandler

NewSSOHandler creates a new SSOHandler.

func (*SSOHandler) Authorize added in v0.1.2

func (h *SSOHandler) Authorize(w http.ResponseWriter, r *http.Request)

Authorize returns the SSO authorization URL for a tenant's provider. GET /api/v1/auth/sso/{provider}/authorize?org={slug}&redirect_uri={uri}

func (*SSOHandler) Callback added in v0.1.2

func (h *SSOHandler) Callback(w http.ResponseWriter, r *http.Request)

Callback handles the SSO OAuth callback. POST /api/v1/auth/sso/{provider}/callback

func (*SSOHandler) CreateProvider added in v0.1.2

func (h *SSOHandler) CreateProvider(w http.ResponseWriter, r *http.Request)

CreateProvider creates a new identity provider configuration. POST /api/v1/settings/identity-providers

func (*SSOHandler) DeleteProvider added in v0.1.2

func (h *SSOHandler) DeleteProvider(w http.ResponseWriter, r *http.Request)

DeleteProvider deletes an identity provider configuration. DELETE /api/v1/settings/identity-providers/{id}

func (*SSOHandler) GetProvider added in v0.1.2

func (h *SSOHandler) GetProvider(w http.ResponseWriter, r *http.Request)

GetProvider retrieves a single identity provider configuration. GET /api/v1/settings/identity-providers/{id}

func (*SSOHandler) ListProviders added in v0.1.2

func (h *SSOHandler) ListProviders(w http.ResponseWriter, r *http.Request)

ListProviders lists all identity provider configurations for the tenant. GET /api/v1/settings/identity-providers

func (*SSOHandler) ListTenantProviders added in v0.1.2

func (h *SSOHandler) ListTenantProviders(w http.ResponseWriter, r *http.Request)

ListTenantProviders returns active SSO providers for a tenant. GET /api/v1/auth/sso/providers?org={slug}

func (*SSOHandler) UpdateProvider added in v0.1.2

func (h *SSOHandler) UpdateProvider(w http.ResponseWriter, r *http.Request)

UpdateProvider updates an identity provider configuration. PUT /api/v1/settings/identity-providers/{id}

type ScanDetailResponse

type ScanDetailResponse struct {
	ID                  string         `json:"id"`
	TenantID            string         `json:"tenant_id"`
	Name                string         `json:"name"`
	Description         string         `json:"description,omitempty"`
	AssetGroupID        string         `json:"asset_group_id,omitempty"`  // Primary asset group (legacy)
	AssetGroupIDs       []string       `json:"asset_group_ids,omitempty"` // Multiple asset groups
	Targets             []string       `json:"targets,omitempty"`         // Direct targets
	ScanType            string         `json:"scan_type"`
	PipelineID          *string        `json:"pipeline_id,omitempty"`
	ScannerName         string         `json:"scanner_name,omitempty"`
	ScannerConfig       map[string]any `json:"scanner_config,omitempty"`
	TargetsPerJob       int            `json:"targets_per_job"`
	ScheduleType        string         `json:"schedule_type"`
	ScheduleCron        string         `json:"schedule_cron,omitempty"`
	ScheduleDay         *int           `json:"schedule_day,omitempty"`
	ScheduleTime        *string        `json:"schedule_time,omitempty"`
	ScheduleTimezone    string         `json:"schedule_timezone"`
	NextRunAt           *string        `json:"next_run_at,omitempty"`
	Tags                []string       `json:"tags,omitempty"`
	RunOnTenantRunner   bool           `json:"run_on_tenant_runner"`
	AgentPreference     string         `json:"agent_preference"`
	ProfileID           *string        `json:"profile_id,omitempty"`
	TimeoutSeconds      int            `json:"timeout_seconds"`
	MaxRetries          int            `json:"max_retries"`
	RetryBackoffSeconds int            `json:"retry_backoff_seconds"`
	Status              string         `json:"status"`
	LastRunID           *string        `json:"last_run_id,omitempty"`
	LastRunAt           *string        `json:"last_run_at,omitempty"`
	LastRunStatus       string         `json:"last_run_status,omitempty"`
	TotalRuns           int            `json:"total_runs"`
	SuccessfulRuns      int            `json:"successful_runs"`
	FailedRuns          int            `json:"failed_runs"`
	CreatedBy           *string        `json:"created_by,omitempty"`
	CreatedByName       *string        `json:"created_by_name,omitempty"`
	CreatedAt           string         `json:"created_at"`
	UpdatedAt           string         `json:"updated_at"`
}

ScanResponse represents the response for a scan.

type ScanHandler

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

ScanHandler handles HTTP requests for scans.

func NewScanHandler

func NewScanHandler(service *scansvc.Service, userRepo user.Repository, v *validator.Validator, log *logger.Logger) *ScanHandler

NewScanHandler creates a new ScanHandler.

func (*ScanHandler) ActivateScan

func (h *ScanHandler) ActivateScan(w http.ResponseWriter, r *http.Request)

ActivateScan handles POST /api/v1/scans/{id}/activate @Summary Activate scan @Description Activate a paused or disabled scan @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Success 200 {object} ScanDetailResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/activate [post]

func (*ScanHandler) BulkActivate

func (h *ScanHandler) BulkActivate(w http.ResponseWriter, r *http.Request)

BulkActivate handles POST /api/v1/scans/bulk/activate @Summary Bulk activate scans @Description Activate multiple scan configurations at once @Tags Scans @Accept json @Produce json @Param request body BulkActionRequest true "Scan IDs to activate" @Success 200 {object} BulkActionResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/bulk/activate [post]

func (*ScanHandler) BulkDelete

func (h *ScanHandler) BulkDelete(w http.ResponseWriter, r *http.Request)

BulkDelete handles POST /api/v1/scans/bulk/delete @Summary Bulk delete scans @Description Delete multiple scan configurations at once @Tags Scans @Accept json @Produce json @Param request body BulkActionRequest true "Scan IDs to delete" @Success 200 {object} BulkActionResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/bulk/delete [post]

func (*ScanHandler) BulkDisable

func (h *ScanHandler) BulkDisable(w http.ResponseWriter, r *http.Request)

BulkDisable handles POST /api/v1/scans/bulk/disable @Summary Bulk disable scans @Description Disable multiple scan configurations at once @Tags Scans @Accept json @Produce json @Param request body BulkActionRequest true "Scan IDs to disable" @Success 200 {object} BulkActionResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/bulk/disable [post]

func (*ScanHandler) BulkPause

func (h *ScanHandler) BulkPause(w http.ResponseWriter, r *http.Request)

BulkPause handles POST /api/v1/scans/bulk/pause @Summary Bulk pause scans @Description Pause multiple scan configurations at once @Tags Scans @Accept json @Produce json @Param request body BulkActionRequest true "Scan IDs to pause" @Success 200 {object} BulkActionResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/bulk/pause [post]

func (*ScanHandler) CloneScan

func (h *ScanHandler) CloneScan(w http.ResponseWriter, r *http.Request)

CloneScan handles POST /api/v1/scans/{id}/clone @Summary Clone scan @Description Create a copy of an existing scan with a new name @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID to clone" @Param request body CloneScanRequest true "New scan name" @Success 201 {object} ScanDetailResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/clone [post]

func (*ScanHandler) CreateScan

func (h *ScanHandler) CreateScan(w http.ResponseWriter, r *http.Request)

CreateScan handles POST /api/v1/scans @Summary Create scan @Description Create a new scan configuration with scheduling options @Tags Scans @Accept json @Produce json @Param request body CreateScanRequest true "Scan configuration" @Success 201 {object} ScanDetailResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans [post]

func (*ScanHandler) DeleteScan

func (h *ScanHandler) DeleteScan(w http.ResponseWriter, r *http.Request)

DeleteScan handles DELETE /api/v1/scans/{id} @Summary Delete scan @Description Delete a scan configuration @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id} [delete]

func (*ScanHandler) DisableScan

func (h *ScanHandler) DisableScan(w http.ResponseWriter, r *http.Request)

DisableScan handles POST /api/v1/scans/{id}/disable @Summary Disable scan @Description Disable a scan completely @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Success 200 {object} ScanDetailResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/disable [post]

func (*ScanHandler) ExportConfig added in v0.1.2

func (h *ScanHandler) ExportConfig(w http.ResponseWriter, r *http.Request)

ExportConfig handles GET /api/v1/scans/{id}/export @Summary Export scan configuration @Description Export a scan configuration as a JSON file for sharing or backup @Tags Scans @Produce application/json @Param id path string true "Scan ID" @Success 200 {object} object "Scan configuration JSON" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/export [get]

func (*ScanHandler) GetLatestScanRun

func (h *ScanHandler) GetLatestScanRun(w http.ResponseWriter, r *http.Request)

GetLatestScanRun handles GET /api/v1/scans/{id}/runs/latest @Summary Get latest scan run @Description Get the most recent run for a scan @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Success 200 {object} map[string]interface{} @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/runs/latest [get]

func (*ScanHandler) GetOverviewStats

func (h *ScanHandler) GetOverviewStats(w http.ResponseWriter, r *http.Request)

GetOverviewStats handles GET /api/v1/scan-management/stats

func (*ScanHandler) GetScan

func (h *ScanHandler) GetScan(w http.ResponseWriter, r *http.Request)

GetScan handles GET /api/v1/scans/{id} @Summary Get scan @Description Get a single scan by ID @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Success 200 {object} ScanDetailResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id} [get]

func (*ScanHandler) GetScanRun

func (h *ScanHandler) GetScanRun(w http.ResponseWriter, r *http.Request)

GetScanRun handles GET /api/v1/scans/{id}/runs/{runId} @Summary Get scan run @Description Get a specific run for a scan @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Param runId path string true "Run ID" @Success 200 {object} map[string]interface{} @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/runs/{runId} [get]

func (*ScanHandler) GetStats

func (h *ScanHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats handles GET /api/v1/scans/stats @Summary Get scan statistics @Description Get aggregated statistics for all scans @Tags Scans @Accept json @Produce json @Success 200 {object} ScanStatsResponse @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/stats [get]

func (*ScanHandler) ImportConfig added in v0.1.2

func (h *ScanHandler) ImportConfig(w http.ResponseWriter, r *http.Request)

ImportConfig handles POST /api/v1/scans/import @Summary Import scan configuration @Description Create a new scan from an imported JSON configuration @Tags Scans @Accept json @Produce json @Param request body object true "Scan configuration JSON (exported format)" @Success 201 {object} ScanDetailResponse @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/import [post]

func (*ScanHandler) ListScanRuns

func (h *ScanHandler) ListScanRuns(w http.ResponseWriter, r *http.Request)

ListScanRuns handles GET /api/v1/scans/{id}/runs @Summary List scan runs @Description Get a paginated list of runs for a scan @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} object @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/runs [get]

func (*ScanHandler) ListScans

func (h *ScanHandler) ListScans(w http.ResponseWriter, r *http.Request)

ListScans handles GET /api/v1/scans @Summary List scans @Description Get a paginated list of scans @Tags Scans @Accept json @Produce json @Param asset_group_id query string false "Filter by asset group" @Param pipeline_id query string false "Filter by pipeline" @Param scan_type query string false "Filter by scan type (workflow, single)" @Param schedule_type query string false "Filter by schedule type" @Param status query string false "Filter by status" @Param search query string false "Search by name" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ScanDetailResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans [get]

func (*ScanHandler) PauseScan

func (h *ScanHandler) PauseScan(w http.ResponseWriter, r *http.Request)

PauseScan handles POST /api/v1/scans/{id}/pause @Summary Pause scan @Description Pause an active scan @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Success 200 {object} ScanDetailResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/pause [post]

func (*ScanHandler) QuickScan

func (h *ScanHandler) QuickScan(w http.ResponseWriter, r *http.Request)

QuickScan performs an immediate scan on provided targets. POST /api/v1/quick-scan

func (*ScanHandler) TriggerScan

func (h *ScanHandler) TriggerScan(w http.ResponseWriter, r *http.Request)

TriggerScan handles POST /api/v1/scans/{id}/trigger @Summary Trigger scan @Description Manually trigger a scan execution. Returns run details with optional filtering_result showing which assets will be scanned vs skipped based on scanner compatibility. @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Param request body TriggerScanExecRequest false "Trigger context" @Success 201 {object} RunResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id}/trigger [post]

func (*ScanHandler) UpdateScan

func (h *ScanHandler) UpdateScan(w http.ResponseWriter, r *http.Request)

UpdateScan handles PUT /api/v1/scans/{id} @Summary Update scan @Description Update an existing scan configuration @Tags Scans @Accept json @Produce json @Param id path string true "Scan ID" @Param request body UpdateScanRequest true "Update data" @Success 200 {object} ScanDetailResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scans/{id} [put]

type ScanIngestRequest added in v0.1.3

type ScanIngestRequest struct {
	// Scanner type: vuls, trivy, nuclei, semgrep, gitleaks (required if auto-detect fails)
	ScannerType string `json:"scanner_type,omitempty"`

	// Raw scanner output data
	Data json.RawMessage `json:"data"`
}

ScanIngestRequest represents the request body for raw scanner output ingestion.

type ScanProfileHandler

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

ScanProfileHandler handles HTTP requests for scan profiles.

func NewScanProfileHandler

func NewScanProfileHandler(service *app.ScanProfileService, v *validator.Validator, log *logger.Logger) *ScanProfileHandler

NewScanProfileHandler creates a new ScanProfileHandler.

func (*ScanProfileHandler) Clone

Clone handles POST /api/v1/scan-profiles/{id}/clone @Summary Clone scan profile @Description Create a copy of an existing scan profile with a new name @Tags Scan Profiles @Accept json @Produce json @Param id path string true "Scan Profile ID to clone" @Param body body CloneScanProfileRequest true "Clone data" @Success 201 {object} ScanProfileResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles/{id}/clone [post]

func (*ScanProfileHandler) Create

Create handles POST /api/v1/scan-profiles @Summary Create scan profile @Description Create a new scan profile with tool configurations @Tags Scan Profiles @Accept json @Produce json @Param body body CreateScanProfileRequest true "Scan profile data" @Success 201 {object} ScanProfileResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles [post]

func (*ScanProfileHandler) Delete

Delete handles DELETE /api/v1/scan-profiles/{id} @Summary Delete scan profile @Description Delete a scan profile (system profiles cannot be deleted) @Tags Scan Profiles @Accept json @Produce json @Param id path string true "Scan Profile ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles/{id} [delete]

func (*ScanProfileHandler) EvaluateQualityGate

func (h *ScanProfileHandler) EvaluateQualityGate(w http.ResponseWriter, r *http.Request)

EvaluateQualityGate handles POST /api/v1/scan-profiles/{id}/evaluate-quality-gate @Summary Evaluate quality gate @Description Evaluate finding counts against a scan profile's quality gate @Tags Scan Profiles @Accept json @Produce json @Param id path string true "Scan Profile ID" @Param body body EvaluateQualityGateRequest true "Finding counts" @Success 200 {object} QualityGateResultResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles/{id}/evaluate-quality-gate [post]

func (*ScanProfileHandler) Get

Get handles GET /api/v1/scan-profiles/{id} @Summary Get scan profile @Description Get a single scan profile by ID @Tags Scan Profiles @Accept json @Produce json @Param id path string true "Scan Profile ID" @Success 200 {object} ScanProfileResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles/{id} [get]

func (*ScanProfileHandler) GetDefault

func (h *ScanProfileHandler) GetDefault(w http.ResponseWriter, r *http.Request)

GetDefault handles GET /api/v1/scan-profiles/default @Summary Get default scan profile @Description Get the default scan profile for the current tenant @Tags Scan Profiles @Accept json @Produce json @Success 200 {object} ScanProfileResponse @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles/default [get]

func (*ScanProfileHandler) List

List handles GET /api/v1/scan-profiles @Summary List scan profiles @Description Get a paginated list of scan profiles for the current tenant @Tags Scan Profiles @Accept json @Produce json @Param is_default query boolean false "Filter by default status" @Param is_system query boolean false "Filter by system status" @Param include_system query boolean false "Include system profiles in results (default: true)" @Param tags query string false "Filter by tags (comma-separated)" @Param search query string false "Search by name or description" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ScanProfileResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles [get]

func (*ScanProfileHandler) SetDefault

func (h *ScanProfileHandler) SetDefault(w http.ResponseWriter, r *http.Request)

SetDefault handles POST /api/v1/scan-profiles/{id}/set-default @Summary Set default scan profile @Description Set a scan profile as the default for the tenant @Tags Scan Profiles @Accept json @Produce json @Param id path string true "Scan Profile ID" @Success 200 {object} ScanProfileResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles/{id}/set-default [post]

func (*ScanProfileHandler) Update

Update handles PUT /api/v1/scan-profiles/{id} @Summary Update scan profile @Description Update an existing scan profile @Tags Scan Profiles @Accept json @Produce json @Param id path string true "Scan Profile ID" @Param body body UpdateScanProfileRequest true "Update data" @Success 200 {object} ScanProfileResponse @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles/{id} [put]

func (*ScanProfileHandler) UpdateQualityGate

func (h *ScanProfileHandler) UpdateQualityGate(w http.ResponseWriter, r *http.Request)

UpdateQualityGate handles PUT /api/v1/scan-profiles/{id}/quality-gate @Summary Update quality gate @Description Update the quality gate configuration for a scan profile @Tags Scan Profiles @Accept json @Produce json @Param id path string true "Scan Profile ID" @Param body body UpdateQualityGateRequest true "Quality gate configuration" @Success 200 {object} ScanProfileResponse @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-profiles/{id}/quality-gate [put]

type ScanProfileResponse

type ScanProfileResponse struct {
	ID                 string                        `json:"id"`
	TenantID           string                        `json:"tenant_id"`
	Name               string                        `json:"name"`
	Description        string                        `json:"description,omitempty"`
	IsDefault          bool                          `json:"is_default"`
	IsSystem           bool                          `json:"is_system"`
	ToolsConfig        map[string]ToolConfigResponse `json:"tools_config"`
	Intensity          string                        `json:"intensity"`
	MaxConcurrentScans int                           `json:"max_concurrent_scans"`
	TimeoutSeconds     int                           `json:"timeout_seconds"`
	Tags               []string                      `json:"tags"`
	Metadata           map[string]any                `json:"metadata,omitempty"`
	QualityGate        QualityGateResponse           `json:"quality_gate"`
	CreatedBy          *string                       `json:"created_by,omitempty"`
	CreatedAt          string                        `json:"created_at"`
	UpdatedAt          string                        `json:"updated_at"`
}

ScanProfileResponse represents the response for a scan profile.

type ScanResponse

type ScanResponse struct {
	Success  bool      `json:"success"`
	Message  string    `json:"message"`
	ScanID   string    `json:"scan_id,omitempty"`
	QueuedAt time.Time `json:"queued_at"`
}

ScanResponse represents the response from a scan trigger.

type ScanScheduleResponse

type ScanScheduleResponse struct {
	ID                   string                 `json:"id"`
	TenantID             string                 `json:"tenant_id"`
	Name                 string                 `json:"name"`
	Description          string                 `json:"description,omitempty"`
	ScanType             string                 `json:"scan_type"`
	TargetScope          string                 `json:"target_scope"`
	TargetIDs            []string               `json:"target_ids,omitempty"`
	TargetTags           []string               `json:"target_tags,omitempty"`
	ScannerConfigs       map[string]interface{} `json:"scanner_configs,omitempty"`
	ScheduleType         string                 `json:"schedule_type"`
	CronExpression       string                 `json:"cron_expression,omitempty"`
	IntervalHours        int                    `json:"interval_hours,omitempty"`
	Enabled              bool                   `json:"enabled"`
	LastRunAt            *time.Time             `json:"last_run_at,omitempty"`
	LastRunStatus        string                 `json:"last_run_status,omitempty"`
	NextRunAt            *time.Time             `json:"next_run_at,omitempty"`
	NotifyOnCompletion   bool                   `json:"notify_on_completion"`
	NotifyOnFindings     bool                   `json:"notify_on_findings"`
	NotificationChannels []string               `json:"notification_channels,omitempty"`
	CreatedBy            string                 `json:"created_by,omitempty"`
	CreatedAt            time.Time              `json:"created_at"`
	UpdatedAt            time.Time              `json:"updated_at"`
}

ScanScheduleResponse represents a scan schedule in API responses.

type ScanSessionHandler

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

ScanSessionHandler handles scan session HTTP requests.

func NewScanSessionHandler

func NewScanSessionHandler(svc *app.ScanSessionService, v *validator.Validator, log *logger.Logger) *ScanSessionHandler

NewScanSessionHandler creates a new ScanSessionHandler.

func (*ScanSessionHandler) Delete

Delete handles DELETE /api/v1/scan-sessions/{id} (admin interface) @Summary Delete scan session @Description Delete a scan session @Tags Scan Sessions @Accept json @Produce json @Param id path string true "Scan session ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-sessions/{id} [delete]

func (*ScanSessionHandler) Get

Get handles GET /api/v1/scan-sessions/{id} (admin interface) @Summary Get scan session @Description Get a single scan session by ID @Tags Scan Sessions @Accept json @Produce json @Param id path string true "Scan session ID" @Success 200 {object} ScanSessionResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-sessions/{id} [get]

func (*ScanSessionHandler) GetScan

GetScan handles GET /api/v1/agent/scans/{id} @Summary Get scan session (agent) @Description Agent retrieves scan session details @Tags Agent @Accept json @Produce json @Param id path string true "Scan session ID" @Success 200 {object} ScanSessionResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security ApiKeyAuth @Router /agent/scans/{id} [get]

func (*ScanSessionHandler) GetStats

func (h *ScanSessionHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats handles GET /api/v1/scan-sessions/stats (admin interface) @Summary Get scan session statistics @Description Get aggregated scan session statistics @Tags Scan Sessions @Accept json @Produce json @Param since query string false "Start date (RFC3339 format)" @Success 200 {object} map[string]interface{} @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-sessions/stats [get]

func (*ScanSessionHandler) List

List handles GET /api/v1/scan-sessions (admin interface) @Summary List scan sessions @Description Get a paginated list of scan sessions for the tenant @Tags Scan Sessions @Accept json @Produce json @Param scanner_name query string false "Filter by scanner name" @Param asset_type query string false "Filter by asset type" @Param status query string false "Filter by status" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ScanSessionResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scan-sessions [get]

func (*ScanSessionHandler) RegisterScan

func (h *ScanSessionHandler) RegisterScan(w http.ResponseWriter, r *http.Request)

RegisterScan handles POST /api/v1/agent/scans @Summary Register scan session @Description Agent registers a new scan session before starting a scan @Tags Agent @Accept json @Produce json @Param request body RegisterScanRequest true "Scan registration data" @Success 201 {object} RegisterScanResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security ApiKeyAuth @Router /agent/scans [post]

func (*ScanSessionHandler) UpdateScan

func (h *ScanSessionHandler) UpdateScan(w http.ResponseWriter, r *http.Request)

UpdateScan handles PATCH /api/v1/agent/scans/{id} @Summary Update scan session @Description Agent updates scan status after completion @Tags Agent @Accept json @Produce json @Param id path string true "Scan session ID" @Param request body UpdateScanSessionRequest true "Update data" @Success 200 {object} map[string]string @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security ApiKeyAuth @Router /agent/scans/{id} [patch]

type ScanSessionResponse

type ScanSessionResponse struct {
	ID             string         `json:"id"`
	TenantID       string         `json:"tenant_id,omitempty"`
	AgentID        string         `json:"agent_id,omitempty"`
	ScannerName    string         `json:"scanner_name"`
	ScannerVersion string         `json:"scanner_version,omitempty"`
	ScannerType    string         `json:"scanner_type,omitempty"`
	AssetType      string         `json:"asset_type"`
	AssetValue     string         `json:"asset_value"`
	AssetID        string         `json:"asset_id,omitempty"`
	CommitSha      string         `json:"commit_sha,omitempty"`
	Branch         string         `json:"branch,omitempty"`
	BaseCommitSha  string         `json:"base_commit_sha,omitempty"`
	Status         string         `json:"status"`
	ErrorMessage   string         `json:"error_message,omitempty"`
	FindingsTotal  int            `json:"findings_total"`
	FindingsNew    int            `json:"findings_new"`
	FindingsFixed  int            `json:"findings_fixed"`
	FindingsBySev  map[string]int `json:"findings_by_severity,omitempty"`
	StartedAt      *time.Time     `json:"started_at,omitempty"`
	CompletedAt    *time.Time     `json:"completed_at,omitempty"`
	DurationMs     int64          `json:"duration_ms,omitempty"`
	CreatedAt      time.Time      `json:"created_at"`
}

ScanSessionResponse represents a scan session in API responses.

type ScanStatsResponse

type ScanStatsResponse struct {
	Total          int64            `json:"total"`
	Active         int64            `json:"active"`
	Paused         int64            `json:"paused"`
	Disabled       int64            `json:"disabled"`
	ByScheduleType map[string]int64 `json:"by_schedule_type"`
	ByScanType     map[string]int64 `json:"by_scan_type"`
}

ScanStatsResponse represents the response for scan statistics.

type ScannerListResponse added in v0.1.3

type ScannerListResponse struct {
	Scanners []string `json:"scanners"`
}

ScannerListResponse lists supported scanner adapters.

type ScannerTemplateHandler

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

ScannerTemplateHandler handles HTTP requests for scanner templates.

func NewScannerTemplateHandler

func NewScannerTemplateHandler(service *app.ScannerTemplateService, v *validator.Validator, log *logger.Logger) *ScannerTemplateHandler

NewScannerTemplateHandler creates a new ScannerTemplateHandler.

func (*ScannerTemplateHandler) Create

Create handles POST /api/v1/scanner-templates @Summary Create scanner template @Description Create a new custom scanner template (Nuclei, Semgrep, or Gitleaks) @Tags Scanner Templates @Accept json @Produce json @Param body body CreateScannerTemplateRequest true "Template data" @Success 201 {object} ScannerTemplateResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 413 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scanner-templates [post]

func (*ScannerTemplateHandler) Delete

Delete handles DELETE /api/v1/scanner-templates/{id} @Summary Delete scanner template @Description Delete a scanner template @Tags Scanner Templates @Accept json @Produce json @Param id path string true "Template ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scanner-templates/{id} [delete]

func (*ScannerTemplateHandler) Deprecate

Deprecate handles POST /api/v1/scanner-templates/{id}/deprecate @Summary Deprecate template @Description Mark a scanner template as deprecated @Tags Scanner Templates @Accept json @Produce json @Param id path string true "Template ID" @Success 200 {object} ScannerTemplateResponse @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scanner-templates/{id}/deprecate [post]

func (*ScannerTemplateHandler) Download

Download handles GET /api/v1/scanner-templates/{id}/download @Summary Download template content @Description Download the raw template content as a file @Tags Scanner Templates @Produce application/octet-stream @Param id path string true "Template ID" @Success 200 {file} binary @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scanner-templates/{id}/download [get]

func (*ScannerTemplateHandler) Get

Get handles GET /api/v1/scanner-templates/{id} @Summary Get scanner template @Description Get a single scanner template by ID @Tags Scanner Templates @Accept json @Produce json @Param id path string true "Template ID" @Success 200 {object} ScannerTemplateResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scanner-templates/{id} [get]

func (*ScannerTemplateHandler) GetUsage

GetUsage handles GET /api/v1/scanner-templates/usage @Summary Get template usage and quota @Description Get the current template usage and quota limits for the tenant @Tags Scanner Templates @Produce json @Success 200 {object} TemplateUsageResponse @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scanner-templates/usage [get]

func (*ScannerTemplateHandler) List

List handles GET /api/v1/scanner-templates @Summary List scanner templates @Description Get a paginated list of scanner templates for the current tenant @Tags Scanner Templates @Accept json @Produce json @Param template_type query string false "Filter by template type (nuclei, semgrep, gitleaks)" @Param status query string false "Filter by status (active, pending_review, deprecated, revoked)" @Param tags query string false "Filter by tags (comma-separated)" @Param search query string false "Search by name or description" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ScannerTemplateResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scanner-templates [get]

func (*ScannerTemplateHandler) Update

Update handles PUT /api/v1/scanner-templates/{id} @Summary Update scanner template @Description Update an existing scanner template @Tags Scanner Templates @Accept json @Produce json @Param id path string true "Template ID" @Param body body UpdateScannerTemplateRequest true "Update data" @Success 200 {object} ScannerTemplateResponse @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 413 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scanner-templates/{id} [put]

func (*ScannerTemplateHandler) Validate

Validate handles POST /api/v1/scanner-templates/validate @Summary Validate template content @Description Validate scanner template content without saving @Tags Scanner Templates @Accept json @Produce json @Param body body ValidateScannerTemplateRequest true "Template content to validate" @Success 200 {object} ValidationResultResponse @Failure 400 {object} apierror.Error @Failure 413 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scanner-templates/validate [post]

type ScannerTemplateResponse

type ScannerTemplateResponse struct {
	ID              string         `json:"id"`
	TenantID        string         `json:"tenant_id"`
	Name            string         `json:"name"`
	TemplateType    string         `json:"template_type"`
	Version         string         `json:"version"`
	ContentHash     string         `json:"content_hash"`
	RuleCount       int            `json:"rule_count"`
	Description     string         `json:"description,omitempty"`
	Tags            []string       `json:"tags"`
	Metadata        map[string]any `json:"metadata,omitempty"`
	Status          string         `json:"status"`
	ValidationError *string        `json:"validation_error,omitempty"`
	CreatedBy       *string        `json:"created_by,omitempty"`
	CreatedAt       string         `json:"created_at"`
	UpdatedAt       string         `json:"updated_at"`
}

ScannerTemplateResponse represents the response for a scanner template.

type ScopeBulkOperationResponse added in v0.1.2

type ScopeBulkOperationResponse struct {
	Success       bool              `json:"success"`
	AffectedCount int               `json:"affected_count"`
	FailedIDs     []string          `json:"failed_ids,omitempty"`
	Errors        map[string]string `json:"errors,omitempty"`
}

BulkOperationResponse represents the response for bulk operations.

type ScopeExclusionResponse

type ScopeExclusionResponse struct {
	ID            string     `json:"id"`
	TenantID      string     `json:"tenant_id"`
	ExclusionType string     `json:"exclusion_type"`
	Pattern       string     `json:"pattern"`
	Reason        string     `json:"reason"`
	Status        string     `json:"status"`
	ExpiresAt     *time.Time `json:"expires_at,omitempty"`
	ApprovedBy    string     `json:"approved_by,omitempty"`
	ApprovedAt    *time.Time `json:"approved_at,omitempty"`
	CreatedBy     string     `json:"created_by,omitempty"`
	CreatedAt     time.Time  `json:"created_at"`
	UpdatedAt     time.Time  `json:"updated_at"`
}

ScopeExclusionResponse represents a scope exclusion in API responses.

type ScopeHandler

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

ScopeHandler handles scope configuration HTTP requests.

func NewScopeHandler

func NewScopeHandler(svc *app.ScopeService, v *validator.Validator, log *logger.Logger) *ScopeHandler

NewScopeHandler creates a new scope handler.

func (*ScopeHandler) ActivateExclusion

func (h *ScopeHandler) ActivateExclusion(w http.ResponseWriter, r *http.Request)

ActivateExclusion handles POST /api/v1/scope/exclusions/{id}/activate @Summary Activate scope exclusion @Description Activate a scope exclusion @Tags Scope @Accept json @Produce json @Param id path string true "Exclusion ID" @Success 200 {object} ScopeExclusionResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/exclusions/{id}/activate [post]

func (*ScopeHandler) ActivateTarget

func (h *ScopeHandler) ActivateTarget(w http.ResponseWriter, r *http.Request)

ActivateTarget handles POST /api/v1/scope/targets/{id}/activate @Summary Activate scope target @Description Activate a scope target @Tags Scope @Accept json @Produce json @Param id path string true "Target ID" @Success 200 {object} ScopeTargetResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/targets/{id}/activate [post]

func (*ScopeHandler) ApproveExclusion

func (h *ScopeHandler) ApproveExclusion(w http.ResponseWriter, r *http.Request)

ApproveExclusion handles POST /api/v1/scope/exclusions/{id}/approve @Summary Approve scope exclusion @Description Approve a scope exclusion, marking it as reviewed and authorized @Tags Scope @Accept json @Produce json @Param id path string true "Exclusion ID" @Success 200 {object} ScopeExclusionResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/exclusions/{id}/approve [post]

func (*ScopeHandler) BulkDeleteExclusions added in v0.1.2

func (h *ScopeHandler) BulkDeleteExclusions(w http.ResponseWriter, r *http.Request)

BulkDeleteExclusions handles POST /api/v1/scope/exclusions/bulk/delete @Summary Bulk delete scope exclusions @Description Delete multiple scope exclusions in a single operation @Tags Scope @Accept json @Produce json @Param body body BulkDeleteExclusionsRequest true "Exclusion IDs to delete" @Success 200 {object} ScopeBulkOperationResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/exclusions/bulk/delete [post]

func (*ScopeHandler) BulkDeleteSchedules added in v0.1.2

func (h *ScopeHandler) BulkDeleteSchedules(w http.ResponseWriter, r *http.Request)

BulkDeleteSchedules handles POST /api/v1/scope/schedules/bulk/delete @Summary Bulk delete scan schedules @Description Delete multiple scan schedules in a single operation @Tags Scope @Accept json @Produce json @Param body body BulkDeleteSchedulesRequest true "Schedule IDs to delete" @Success 200 {object} ScopeBulkOperationResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/schedules/bulk/delete [post]

func (*ScopeHandler) BulkDeleteTargets added in v0.1.2

func (h *ScopeHandler) BulkDeleteTargets(w http.ResponseWriter, r *http.Request)

BulkDeleteTargets handles POST /api/v1/scope/targets/bulk/delete @Summary Bulk delete scope targets @Description Delete multiple scope targets in a single operation @Tags Scope @Accept json @Produce json @Param body body BulkDeleteTargetsRequest true "Target IDs to delete" @Success 200 {object} ScopeBulkOperationResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/targets/bulk/delete [post]

func (*ScopeHandler) CheckScope

func (h *ScopeHandler) CheckScope(w http.ResponseWriter, r *http.Request)

CheckScope handles POST /api/v1/scope/check @Summary Check if value is in scope @Description Check whether a given asset type and value falls within scope targets and exclusions @Tags Scope @Accept json @Produce json @Param body body CheckScopeRequest true "Asset type and value to check" @Success 200 {object} ScopeMatchResponse @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/check [post]

func (*ScopeHandler) CreateExclusion

func (h *ScopeHandler) CreateExclusion(w http.ResponseWriter, r *http.Request)

CreateExclusion handles POST /api/v1/scope/exclusions @Summary Create scope exclusion @Description Create a new scope exclusion @Tags Scope @Accept json @Produce json @Param body body CreateScopeExclusionRequest true "Scope exclusion data" @Success 201 {object} ScopeExclusionResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/exclusions [post]

func (*ScopeHandler) CreateSchedule

func (h *ScopeHandler) CreateSchedule(w http.ResponseWriter, r *http.Request)

CreateSchedule handles POST /api/v1/scope/schedules @Summary Create scan schedule @Description Create a new scan schedule @Tags Scope @Accept json @Produce json @Param body body CreateScanScheduleRequest true "Scan schedule data" @Success 201 {object} ScanScheduleResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/schedules [post]

func (*ScopeHandler) CreateTarget

func (h *ScopeHandler) CreateTarget(w http.ResponseWriter, r *http.Request)

CreateTarget handles POST /api/v1/scope/targets @Summary Create scope target @Description Create a new scope target @Tags Scope @Accept json @Produce json @Param body body CreateScopeTargetRequest true "Scope target data" @Success 201 {object} ScopeTargetResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/targets [post]

func (*ScopeHandler) DeactivateExclusion

func (h *ScopeHandler) DeactivateExclusion(w http.ResponseWriter, r *http.Request)

DeactivateExclusion handles POST /api/v1/scope/exclusions/{id}/deactivate @Summary Deactivate scope exclusion @Description Deactivate a scope exclusion @Tags Scope @Accept json @Produce json @Param id path string true "Exclusion ID" @Success 200 {object} ScopeExclusionResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/exclusions/{id}/deactivate [post]

func (*ScopeHandler) DeactivateTarget

func (h *ScopeHandler) DeactivateTarget(w http.ResponseWriter, r *http.Request)

DeactivateTarget handles POST /api/v1/scope/targets/{id}/deactivate @Summary Deactivate scope target @Description Deactivate a scope target @Tags Scope @Accept json @Produce json @Param id path string true "Target ID" @Success 200 {object} ScopeTargetResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/targets/{id}/deactivate [post]

func (*ScopeHandler) DeleteExclusion

func (h *ScopeHandler) DeleteExclusion(w http.ResponseWriter, r *http.Request)

DeleteExclusion handles DELETE /api/v1/scope/exclusions/{id} @Summary Delete scope exclusion @Description Delete a scope exclusion @Tags Scope @Accept json @Produce json @Param id path string true "Exclusion ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/exclusions/{id} [delete]

func (*ScopeHandler) DeleteSchedule

func (h *ScopeHandler) DeleteSchedule(w http.ResponseWriter, r *http.Request)

DeleteSchedule handles DELETE /api/v1/scope/schedules/{id} @Summary Delete scan schedule @Description Delete a scan schedule @Tags Scope @Accept json @Produce json @Param id path string true "Schedule ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/schedules/{id} [delete]

func (*ScopeHandler) DeleteTarget

func (h *ScopeHandler) DeleteTarget(w http.ResponseWriter, r *http.Request)

DeleteTarget handles DELETE /api/v1/scope/targets/{id} @Summary Delete scope target @Description Delete a scope target @Tags Scope @Accept json @Produce json @Param id path string true "Target ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/targets/{id} [delete]

func (*ScopeHandler) DisableSchedule

func (h *ScopeHandler) DisableSchedule(w http.ResponseWriter, r *http.Request)

DisableSchedule handles POST /api/v1/scope/schedules/{id}/disable @Summary Disable scan schedule @Description Disable a scan schedule so it will no longer run automatically @Tags Scope @Accept json @Produce json @Param id path string true "Schedule ID" @Success 200 {object} ScanScheduleResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/schedules/{id}/disable [post]

func (*ScopeHandler) EnableSchedule

func (h *ScopeHandler) EnableSchedule(w http.ResponseWriter, r *http.Request)

EnableSchedule handles POST /api/v1/scope/schedules/{id}/enable @Summary Enable scan schedule @Description Enable a scan schedule so it will run on its configured schedule @Tags Scope @Accept json @Produce json @Param id path string true "Schedule ID" @Success 200 {object} ScanScheduleResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/schedules/{id}/enable [post]

func (*ScopeHandler) GetExclusion

func (h *ScopeHandler) GetExclusion(w http.ResponseWriter, r *http.Request)

GetExclusion handles GET /api/v1/scope/exclusions/{id} @Summary Get scope exclusion @Description Get a single scope exclusion by ID @Tags Scope @Accept json @Produce json @Param id path string true "Exclusion ID" @Success 200 {object} ScopeExclusionResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/exclusions/{id} [get]

func (*ScopeHandler) GetSchedule

func (h *ScopeHandler) GetSchedule(w http.ResponseWriter, r *http.Request)

GetSchedule handles GET /api/v1/scope/schedules/{id} @Summary Get scan schedule @Description Get a single scan schedule by ID @Tags Scope @Accept json @Produce json @Param id path string true "Schedule ID" @Success 200 {object} ScanScheduleResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/schedules/{id} [get]

func (*ScopeHandler) GetStats

func (h *ScopeHandler) GetStats(w http.ResponseWriter, r *http.Request)

GetStats handles GET /api/v1/scope/stats @Summary Get scope statistics @Description Get aggregate statistics for scope targets, exclusions, and schedules @Tags Scope @Produce json @Success 200 {object} ScopeStatsResponse @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/stats [get]

func (*ScopeHandler) GetTarget

func (h *ScopeHandler) GetTarget(w http.ResponseWriter, r *http.Request)

GetTarget handles GET /api/v1/scope/targets/{id} @Summary Get scope target @Description Get a single scope target by ID @Tags Scope @Accept json @Produce json @Param id path string true "Target ID" @Success 200 {object} ScopeTargetResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/targets/{id} [get]

func (*ScopeHandler) ListExclusions

func (h *ScopeHandler) ListExclusions(w http.ResponseWriter, r *http.Request)

ListExclusions handles GET /api/v1/scope/exclusions @Summary List scope exclusions @Description Get a paginated list of scope exclusions for the current tenant @Tags Scope @Accept json @Produce json @Param types query string false "Filter by exclusion types (comma-separated)" @Param statuses query string false "Filter by statuses (comma-separated)" @Param is_approved query bool false "Filter by approval status" @Param search query string false "Search by pattern" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ScopeExclusionResponse] @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/exclusions [get]

func (*ScopeHandler) ListSchedules

func (h *ScopeHandler) ListSchedules(w http.ResponseWriter, r *http.Request)

ListSchedules handles GET /api/v1/scope/schedules @Summary List scan schedules @Description Get a paginated list of scan schedules for the current tenant @Tags Scope @Accept json @Produce json @Param scan_types query string false "Filter by scan types (comma-separated)" @Param schedule_types query string false "Filter by schedule types (comma-separated)" @Param enabled query bool false "Filter by enabled status" @Param search query string false "Search by name" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ScanScheduleResponse] @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/schedules [get]

func (*ScopeHandler) ListTargets

func (h *ScopeHandler) ListTargets(w http.ResponseWriter, r *http.Request)

ListTargets handles GET /api/v1/scope/targets @Summary List scope targets @Description Get a paginated list of scope targets for the current tenant @Tags Scope @Accept json @Produce json @Param types query string false "Filter by target types (comma-separated)" @Param statuses query string false "Filter by statuses (comma-separated)" @Param tags query string false "Filter by tags (comma-separated)" @Param search query string false "Search by pattern" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ScopeTargetResponse] @Failure 400 {object} apierror.Error @Failure 401 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/targets [get]

func (*ScopeHandler) RunScheduleNow added in v0.1.2

func (h *ScopeHandler) RunScheduleNow(w http.ResponseWriter, r *http.Request)

RunScheduleNow handles POST /api/v1/scope/schedules/{id}/run @Summary Run scan schedule now @Description Trigger an immediate run of a scan schedule @Tags Scope @Accept json @Produce json @Param id path string true "Schedule ID" @Success 200 {object} ScanScheduleResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/schedules/{id}/run [post]

func (*ScopeHandler) UpdateExclusion

func (h *ScopeHandler) UpdateExclusion(w http.ResponseWriter, r *http.Request)

UpdateExclusion handles PUT /api/v1/scope/exclusions/{id} @Summary Update scope exclusion @Description Update an existing scope exclusion @Tags Scope @Accept json @Produce json @Param id path string true "Exclusion ID" @Param body body UpdateScopeExclusionRequest true "Update data" @Success 200 {object} ScopeExclusionResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/exclusions/{id} [put]

func (*ScopeHandler) UpdateSchedule

func (h *ScopeHandler) UpdateSchedule(w http.ResponseWriter, r *http.Request)

UpdateSchedule handles PUT /api/v1/scope/schedules/{id} @Summary Update scan schedule @Description Update an existing scan schedule @Tags Scope @Accept json @Produce json @Param id path string true "Schedule ID" @Param body body UpdateScanScheduleRequest true "Update data" @Success 200 {object} ScanScheduleResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/schedules/{id} [put]

func (*ScopeHandler) UpdateTarget

func (h *ScopeHandler) UpdateTarget(w http.ResponseWriter, r *http.Request)

UpdateTarget handles PUT /api/v1/scope/targets/{id} @Summary Update scope target @Description Update an existing scope target @Tags Scope @Accept json @Produce json @Param id path string true "Target ID" @Param body body UpdateScopeTargetRequest true "Update data" @Success 200 {object} ScopeTargetResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /scope/targets/{id} [put]

type ScopeMatchResponse

type ScopeMatchResponse struct {
	InScope             bool     `json:"in_scope"`
	Excluded            bool     `json:"excluded"`
	MatchedTargetIDs    []string `json:"matched_target_ids,omitempty"`
	MatchedExclusionIDs []string `json:"matched_exclusion_ids,omitempty"`
}

ScopeMatchResponse represents scope matching result in API responses.

type ScopeRuleHandler added in v0.1.2

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

ScopeRuleHandler handles HTTP requests for scope rules.

func NewScopeRuleHandler added in v0.1.2

func NewScopeRuleHandler(svc *app.ScopeRuleService, v *validator.Validator, log *logger.Logger) *ScopeRuleHandler

NewScopeRuleHandler creates a new ScopeRuleHandler.

func (*ScopeRuleHandler) CreateScopeRule added in v0.1.2

func (h *ScopeRuleHandler) CreateScopeRule(w http.ResponseWriter, r *http.Request)

CreateScopeRule handles POST /api/v1/groups/{groupId}/scope-rules

func (*ScopeRuleHandler) DeleteScopeRule added in v0.1.2

func (h *ScopeRuleHandler) DeleteScopeRule(w http.ResponseWriter, r *http.Request)

DeleteScopeRule handles DELETE /api/v1/groups/{groupId}/scope-rules/{ruleId}

func (*ScopeRuleHandler) GetScopeRule added in v0.1.2

func (h *ScopeRuleHandler) GetScopeRule(w http.ResponseWriter, r *http.Request)

GetScopeRule handles GET /api/v1/groups/{groupId}/scope-rules/{ruleId}

func (*ScopeRuleHandler) ListScopeRules added in v0.1.2

func (h *ScopeRuleHandler) ListScopeRules(w http.ResponseWriter, r *http.Request)

ListScopeRules handles GET /api/v1/groups/{groupId}/scope-rules

func (*ScopeRuleHandler) PreviewScopeRule added in v0.1.2

func (h *ScopeRuleHandler) PreviewScopeRule(w http.ResponseWriter, r *http.Request)

PreviewScopeRule handles POST /api/v1/groups/{groupId}/scope-rules/{ruleId}/preview

func (*ScopeRuleHandler) ReconcileGroup added in v0.1.2

func (h *ScopeRuleHandler) ReconcileGroup(w http.ResponseWriter, r *http.Request)

ReconcileGroup handles POST /api/v1/groups/{groupId}/scope-rules/reconcile

func (*ScopeRuleHandler) UpdateScopeRule added in v0.1.2

func (h *ScopeRuleHandler) UpdateScopeRule(w http.ResponseWriter, r *http.Request)

UpdateScopeRule handles PUT /api/v1/groups/{groupId}/scope-rules/{ruleId}

type ScopeStatsResponse

type ScopeStatsResponse struct {
	TotalTargets     int64   `json:"total_targets"`
	ActiveTargets    int64   `json:"active_targets"`
	TotalExclusions  int64   `json:"total_exclusions"`
	ActiveExclusions int64   `json:"active_exclusions"`
	TotalSchedules   int64   `json:"total_schedules"`
	EnabledSchedules int64   `json:"enabled_schedules"`
	Coverage         float64 `json:"coverage"`
}

ScopeStatsResponse represents scope statistics in API responses.

type ScopeTargetResponse

type ScopeTargetResponse struct {
	ID          string    `json:"id"`
	TenantID    string    `json:"tenant_id"`
	TargetType  string    `json:"target_type"`
	Pattern     string    `json:"pattern"`
	Description string    `json:"description,omitempty"`
	Priority    int       `json:"priority"`
	Status      string    `json:"status"`
	Tags        []string  `json:"tags,omitempty"`
	CreatedBy   string    `json:"created_by,omitempty"`
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

ScopeTargetResponse represents a scope target in API responses.

type SecretStoreHandler

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

SecretStoreHandler handles HTTP requests for secret store credentials.

func NewSecretStoreHandler

func NewSecretStoreHandler(service *app.SecretStoreService, v *validator.Validator, log *logger.Logger) *SecretStoreHandler

NewSecretStoreHandler creates a new SecretStoreHandler.

func (*SecretStoreHandler) Create

Create handles POST /api/v1/credentials @Summary Create credential @Description Create a new credential for template sources @Tags Credentials @Accept json @Produce json @Param body body CreateCredentialRequest true "Credential data" @Success 201 {object} CredentialResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /credentials [post]

func (*SecretStoreHandler) Delete

Delete handles DELETE /api/v1/credentials/{id} @Summary Delete credential @Description Delete a credential @Tags Credentials @Accept json @Produce json @Param id path string true "Credential ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /credentials/{id} [delete]

func (*SecretStoreHandler) Get

Get handles GET /api/v1/credentials/{id} @Summary Get credential @Description Get a single credential by ID (without sensitive data) @Tags Credentials @Accept json @Produce json @Param id path string true "Credential ID" @Success 200 {object} CredentialResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /credentials/{id} [get]

func (*SecretStoreHandler) List

List handles GET /api/v1/credentials @Summary List credentials @Description List credentials with optional filters @Tags Credentials @Accept json @Produce json @Param credential_type query string false "Filter by credential type" @Param page query int false "Page number" @Param page_size query int false "Page size" @Success 200 {object} ListCredentialsResponse @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /credentials [get]

func (*SecretStoreHandler) Update

Update handles PUT /api/v1/credentials/{id} @Summary Update credential @Description Update credential metadata (not sensitive data) @Tags Credentials @Accept json @Produce json @Param id path string true "Credential ID" @Param body body UpdateCredentialRequest true "Updated credential data" @Success 200 {object} CredentialResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /credentials/{id} [put]

type SecuritySettingsResponse

type SecuritySettingsResponse struct {
	SSOEnabled            bool     `json:"sso_enabled"`
	SSOProvider           string   `json:"sso_provider,omitempty"`
	MFARequired           bool     `json:"mfa_required"`
	SessionTimeoutMin     int      `json:"session_timeout_min"`
	IPWhitelist           []string `json:"ip_whitelist"`
	AllowedDomains        []string `json:"allowed_domains"`
	EmailVerificationMode string   `json:"email_verification_mode"`
}

SecuritySettingsResponse represents security settings.

type SendNotificationRequest

type SendNotificationRequest struct {
	Title    string            `json:"title" validate:"required,min=1,max=255"`
	Body     string            `json:"body" validate:"required,max=4000"`
	Severity string            `json:"severity" validate:"required,oneof=critical high medium low"`
	URL      string            `json:"url" validate:"omitempty,url"`
	Fields   map[string]string `json:"fields"`
}

SendNotificationRequest represents the request to send a notification.

type SessionsResponse

type SessionsResponse struct {
	Sessions []app.SessionInfo `json:"sessions"`
}

SessionsResponse is the response body for listing sessions.

type SetSyncEnabledRequest

type SetSyncEnabledRequest struct {
	Enabled bool `json:"enabled"`
}

SetSyncEnabledRequest is the request for enabling/disabling sync.

type SetTagsRequest

type SetTagsRequest struct {
	Tags []string `json:"tags" validate:"max=50,dive,max=100"`
}

SetTagsRequest represents the request to set tags on a finding.

type SetUserRolesRequest

type SetUserRolesRequest struct {
	RoleIDs []string `json:"role_ids" validate:"required,min=1,max=50,dive,uuid"`
}

SetUserRolesRequest represents the request to set all roles for a user.

type SettingsResponse

type SettingsResponse struct {
	General     GeneralSettingsResponse    `json:"general"`
	Security    SecuritySettingsResponse   `json:"security"`
	API         APISettingsResponse        `json:"api"`
	Branding    BrandingSettingsResponse   `json:"branding"`
	RiskScoring tenant.RiskScoringSettings `json:"risk_scoring"`
	Pentest     tenant.PentestSettings     `json:"pentest"`
}

SettingsResponse represents tenant settings in API responses.

type SkipReasonResponse

type SkipReasonResponse struct {
	AssetType string `json:"asset_type"`
	Count     int    `json:"count"`
	Reason    string `json:"reason"`
}

SkipReasonResponse explains why assets of a certain type were skipped.

type SourceResponse

type SourceResponse struct {
	ID                  string  `json:"id"`
	TenantID            string  `json:"tenant_id"`
	ToolID              *string `json:"tool_id,omitempty"`
	Name                string  `json:"name"`
	Description         string  `json:"description,omitempty"`
	SourceType          string  `json:"source_type"`
	Config              any     `json:"config,omitempty"`
	CredentialsID       *string `json:"credentials_id,omitempty"`
	SyncEnabled         bool    `json:"sync_enabled"`
	SyncIntervalMinutes int     `json:"sync_interval_minutes"`
	LastSyncAt          *string `json:"last_sync_at,omitempty"`
	LastSyncStatus      string  `json:"last_sync_status"`
	LastSyncError       string  `json:"last_sync_error,omitempty"`
	ContentHash         string  `json:"content_hash,omitempty"`
	RuleCount           int     `json:"rule_count"`
	Priority            int     `json:"priority"`
	IsPlatformDefault   bool    `json:"is_platform_default"`
	Enabled             bool    `json:"enabled"`
	CreatedAt           string  `json:"created_at"`
	UpdatedAt           string  `json:"updated_at"`
}

SourceResponse represents the response for a rule source.

type StateChangeResponse

type StateChangeResponse struct {
	ID         string    `json:"id"`
	TenantID   string    `json:"tenant_id,omitempty"`
	AssetID    string    `json:"asset_id"`
	ChangeType string    `json:"change_type"`
	Field      string    `json:"field,omitempty"`
	OldValue   string    `json:"old_value,omitempty"`
	NewValue   string    `json:"new_value,omitempty"`
	Reason     string    `json:"reason,omitempty"`
	Source     string    `json:"source"`
	ChangedBy  *string   `json:"changed_by,omitempty"`
	ChangedAt  time.Time `json:"changed_at"`
	Metadata   string    `json:"metadata,omitempty"`
	CreatedAt  time.Time `json:"created_at"`
}

StateChangeResponse represents a state change in API responses.

type StateHistoryResponse

type StateHistoryResponse struct {
	ID            string            `json:"id"`
	PreviousState string            `json:"previous_state"`
	NewState      string            `json:"new_state"`
	ChangedBy     string            `json:"changed_by,omitempty"`
	ChangedByUser *StateHistoryUser `json:"changed_by_user,omitempty"`
	Reason        string            `json:"reason,omitempty"`
	CreatedAt     time.Time         `json:"created_at"`
}

StateHistoryResponse represents a state history entry in API responses.

type StateHistoryStatsResponse

type StateHistoryStatsResponse struct {
	TypeCounts   map[string]int `json:"type_counts"`
	SourceCounts map[string]int `json:"source_counts"`
}

StateHistoryStatsResponse represents state history statistics.

type StateHistoryUser

type StateHistoryUser struct {
	ID        string `json:"id"`
	Name      string `json:"name"`
	Email     string `json:"email"`
	AvatarURL string `json:"avatar_url,omitempty"`
}

StateHistoryUser represents the user who changed the state.

type StatusCountsResponse

type StatusCountsResponse struct {
	Total     int64 `json:"total"`
	Running   int64 `json:"running"`
	Pending   int64 `json:"pending"`
	Completed int64 `json:"completed"`
	Failed    int64 `json:"failed"`
	Canceled  int64 `json:"canceled"`
}

StatusCountsResponse represents counts by status.

type StepConditionRequest

type StepConditionRequest struct {
	Type  string `json:"type" validate:"oneof=always never asset_type expression step_result"`
	Value string `json:"value" validate:"max=500"`
}

StepConditionRequest represents a step condition in the request.

type StepConditionResponse

type StepConditionResponse struct {
	Type  string `json:"type"`
	Value string `json:"value,omitempty"`
}

StepConditionResponse represents a step condition in the response.

type StepResponse

type StepResponse struct {
	ID                string                 `json:"id"`
	StepKey           string                 `json:"step_key"`
	Name              string                 `json:"name"`
	Description       string                 `json:"description,omitempty"`
	Order             int                    `json:"order"`
	UIPosition        UIPositionResponse     `json:"ui_position"`
	Tool              string                 `json:"tool,omitempty"`
	Capabilities      []string               `json:"capabilities"`
	Config            map[string]interface{} `json:"config,omitempty"`
	TimeoutSeconds    int                    `json:"timeout_seconds,omitempty"`
	DependsOn         []string               `json:"depends_on,omitempty"`
	Condition         *StepConditionResponse `json:"condition,omitempty"`
	MaxRetries        int                    `json:"max_retries"`
	RetryDelaySeconds int                    `json:"retry_delay_seconds"`
}

StepResponse represents a step in the response.

type StepRunResponse

type StepRunResponse struct {
	ID            string  `json:"id"`
	StepID        string  `json:"step_id"`
	StepKey       string  `json:"step_key"`
	Status        string  `json:"status"`
	StartedAt     *string `json:"started_at,omitempty"`
	CompletedAt   *string `json:"completed_at,omitempty"`
	ErrorMessage  string  `json:"error_message,omitempty"`
	ErrorCode     string  `json:"error_code,omitempty"`
	Attempt       int     `json:"attempt"`
	MaxAttempts   int     `json:"max_attempts"`
	FindingsCount int     `json:"findings_count"`
}

StepRunResponse represents a step run in the response.

type SubdomainResult

type SubdomainResult struct {
	Host   string   `json:"host"`
	Domain string   `json:"domain,omitempty"`
	Source string   `json:"source,omitempty"`
	IPs    []string `json:"ips,omitempty"`
}

SubdomainResult represents a discovered subdomain.

type SuppressionHandler

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

SuppressionHandler handles suppression rule HTTP requests.

func NewSuppressionHandler

func NewSuppressionHandler(svc *suppression.Service, log *logger.Logger) *SuppressionHandler

NewSuppressionHandler creates a new suppression handler.

func (*SuppressionHandler) ApproveRule

func (h *SuppressionHandler) ApproveRule(w http.ResponseWriter, r *http.Request)

ApproveRule handles POST /api/v1/suppressions/{id}/approve

func (*SuppressionHandler) CreateRule

func (h *SuppressionHandler) CreateRule(w http.ResponseWriter, r *http.Request)

CreateRule handles POST /api/v1/suppressions

func (*SuppressionHandler) DeleteRule

func (h *SuppressionHandler) DeleteRule(w http.ResponseWriter, r *http.Request)

DeleteRule handles DELETE /api/v1/suppressions/{id}

func (*SuppressionHandler) GetRule

GetRule handles GET /api/v1/suppressions/{id}

func (*SuppressionHandler) ListActiveRules

func (h *SuppressionHandler) ListActiveRules(w http.ResponseWriter, r *http.Request)

ListActiveRules handles GET /api/v1/suppressions/active This endpoint is used by agents to fetch active suppression rules.

func (*SuppressionHandler) ListRules

func (h *SuppressionHandler) ListRules(w http.ResponseWriter, r *http.Request)

ListRules handles GET /api/v1/suppressions

func (*SuppressionHandler) RejectRule

func (h *SuppressionHandler) RejectRule(w http.ResponseWriter, r *http.Request)

RejectRule handles POST /api/v1/suppressions/{id}/reject

func (*SuppressionHandler) UpdateRule

func (h *SuppressionHandler) UpdateRule(w http.ResponseWriter, r *http.Request)

UpdateRule handles PUT /api/v1/suppressions/{id}

type SuppressionRuleResponse

type SuppressionRuleResponse struct {
	ID              string  `json:"id"`
	TenantID        string  `json:"tenant_id"`
	Name            string  `json:"name"`
	Description     string  `json:"description,omitempty"`
	SuppressionType string  `json:"suppression_type"`
	RuleID          string  `json:"rule_id,omitempty"`
	ToolName        string  `json:"tool_name,omitempty"`
	PathPattern     string  `json:"path_pattern,omitempty"`
	AssetID         *string `json:"asset_id,omitempty"`
	Status          string  `json:"status"`
	RequestedBy     string  `json:"requested_by"`
	RequestedAt     string  `json:"requested_at"`
	ApprovedBy      *string `json:"approved_by,omitempty"`
	ApprovedAt      *string `json:"approved_at,omitempty"`
	RejectedBy      *string `json:"rejected_by,omitempty"`
	RejectedAt      *string `json:"rejected_at,omitempty"`
	RejectionReason string  `json:"rejection_reason,omitempty"`
	ExpiresAt       *string `json:"expires_at,omitempty"`
	CreatedAt       string  `json:"created_at"`
	UpdatedAt       string  `json:"updated_at"`
}

SuppressionRuleResponse represents a suppression rule in API responses.

type SyncHistoryResponse

type SyncHistoryResponse struct {
	ID           string `json:"id"`
	SourceID     string `json:"source_id"`
	Status       string `json:"status"`
	RulesAdded   int    `json:"rules_added"`
	RulesUpdated int    `json:"rules_updated"`
	RulesRemoved int    `json:"rules_removed"`
	DurationMs   int64  `json:"duration_ms"`
	ErrorMessage string `json:"error_message,omitempty"`
	PreviousHash string `json:"previous_hash,omitempty"`
	NewHash      string `json:"new_hash,omitempty"`
	CreatedAt    string `json:"created_at"`
}

SyncHistoryResponse represents a sync history entry.

type SyncResponse

type SyncResponse struct {
	Success       bool      `json:"success"`
	Message       string    `json:"message"`
	SyncedAt      time.Time `json:"synced_at"`
	UpdatedFields []string  `json:"updated_fields,omitempty"`
}

SyncResponse represents the response from a sync operation.

type SyncResultResponse

type SyncResultResponse struct {
	Source        string `json:"source"`
	RecordsSynced int    `json:"records_synced"`
	DurationMs    int64  `json:"duration_ms"`
	Success       bool   `json:"success"`
	Error         string `json:"error,omitempty"`
}

SyncResultResponse is the response for a sync result.

type SyncStatusResponse

type SyncStatusResponse struct {
	Source         string  `json:"source"`
	Enabled        bool    `json:"enabled"`
	LastSyncAt     *string `json:"last_sync_at,omitempty"`
	LastSyncStatus string  `json:"last_sync_status"`
	LastError      string  `json:"last_error,omitempty"`
	RecordsSynced  int     `json:"records_synced"`
	NextSyncAt     *string `json:"next_sync_at,omitempty"`
}

SyncStatusResponse is the response for sync status.

type TargetMappingListResponse

type TargetMappingListResponse struct {
	Data       []TargetMappingResponse `json:"data"`
	Total      int64                   `json:"total"`
	Page       int                     `json:"page"`
	PerPage    int                     `json:"per_page"`
	TotalPages int                     `json:"total_pages"`
}

TargetMappingListResponse represents a paginated list of target mappings.

type TargetMappingResponse

type TargetMappingResponse struct {
	ID          string  `json:"id"`
	TargetType  string  `json:"target_type"`
	AssetType   string  `json:"asset_type"`
	Priority    int     `json:"priority"`
	IsActive    bool    `json:"is_active"`
	IsPrimary   bool    `json:"is_primary"`            // Derived from priority == 10
	Description *string `json:"description,omitempty"` // Optional description
	CreatedBy   *string `json:"created_by,omitempty"`
	CreatedAt   string  `json:"created_at"`
	UpdatedAt   string  `json:"updated_at"`
}

TargetMappingResponse represents a target mapping in API responses.

type TargetMappingStatsResponse

type TargetMappingStatsResponse struct {
	Total         int64            `json:"total"`
	ByTargetType  map[string]int64 `json:"by_target_type"`
	ByAssetType   map[string]int64 `json:"by_asset_type"`
	ActiveCount   int64            `json:"active_count"`
	InactiveCount int64            `json:"inactive_count"`
}

TargetMappingStatsResponse represents aggregated stats for target mappings.

type TeamMemberInfo added in v0.1.2

type TeamMemberInfo struct {
	ID    string `json:"id"`
	Name  string `json:"name"`
	Email string `json:"email"`
	Role  string `json:"role,omitempty"`
}

TeamMemberInfo represents enriched team member data in API responses.

type TemplateQuotaData

type TemplateQuotaData struct {
	MaxTemplates         int   `json:"max_templates"`
	MaxTemplatesNuclei   int   `json:"max_templates_nuclei"`
	MaxTemplatesSemgrep  int   `json:"max_templates_semgrep"`
	MaxTemplatesGitleaks int   `json:"max_templates_gitleaks"`
	MaxTotalStorageBytes int64 `json:"max_total_storage_bytes"`
}

TemplateQuotaData represents quota limits.

type TemplateResponse

type TemplateResponse struct {
	ID               string                   `json:"id"`
	TenantID         string                   `json:"tenant_id"`
	Name             string                   `json:"name"`
	Description      string                   `json:"description,omitempty"`
	Version          int                      `json:"version"`
	IsActive         bool                     `json:"is_active"`
	IsSystemTemplate bool                     `json:"is_system_template"`
	Triggers         []TriggerResponse        `json:"triggers"`
	Settings         PipelineSettingsResponse `json:"settings"`
	Tags             []string                 `json:"tags,omitempty"`
	Steps            []StepResponse           `json:"steps"`
	UIStartPosition  *UIPositionResponse      `json:"ui_start_position,omitempty"`
	UIEndPosition    *UIPositionResponse      `json:"ui_end_position,omitempty"`
	CreatedAt        string                   `json:"created_at"`
	UpdatedAt        string                   `json:"updated_at"`
}

TemplateResponse represents the response for a pipeline template.

type TemplateSourceHandler

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

TemplateSourceHandler handles HTTP requests for template sources.

func NewTemplateSourceHandler

func NewTemplateSourceHandler(service *app.TemplateSourceService, v *validator.Validator, log *logger.Logger) *TemplateSourceHandler

NewTemplateSourceHandler creates a new TemplateSourceHandler.

func (*TemplateSourceHandler) Create

Create handles POST /api/v1/template-sources @Summary Create template source @Description Create a new template source (Git, S3, or HTTP) @Tags Template Sources @Accept json @Produce json @Param body body CreateTemplateSourceRequest true "Source data" @Success 201 {object} TemplateSourceResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /template-sources [post]

func (*TemplateSourceHandler) Delete

Delete handles DELETE /api/v1/template-sources/{id} @Summary Delete template source @Description Delete a template source @Tags Template Sources @Accept json @Produce json @Param id path string true "Source ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /template-sources/{id} [delete]

func (*TemplateSourceHandler) Disable

Disable handles POST /api/v1/template-sources/{id}/disable @Summary Disable template source @Description Disable an active template source @Tags Template Sources @Accept json @Produce json @Param id path string true "Source ID" @Success 200 {object} TemplateSourceResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /template-sources/{id}/disable [post]

func (*TemplateSourceHandler) Enable

Enable handles POST /api/v1/template-sources/{id}/enable @Summary Enable template source @Description Enable a disabled template source @Tags Template Sources @Accept json @Produce json @Param id path string true "Source ID" @Success 200 {object} TemplateSourceResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /template-sources/{id}/enable [post]

func (*TemplateSourceHandler) Get

Get handles GET /api/v1/template-sources/{id} @Summary Get template source @Description Get a single template source by ID @Tags Template Sources @Accept json @Produce json @Param id path string true "Source ID" @Success 200 {object} TemplateSourceResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /template-sources/{id} [get]

func (*TemplateSourceHandler) List

List handles GET /api/v1/template-sources @Summary List template sources @Description List template sources with optional filters @Tags Template Sources @Accept json @Produce json @Param source_type query string false "Filter by source type (git, s3, http)" @Param template_type query string false "Filter by template type (nuclei, semgrep, gitleaks)" @Param enabled query bool false "Filter by enabled status" @Param page query int false "Page number" @Param page_size query int false "Page size" @Param sort_by query string false "Sort by field" @Param sort_order query string false "Sort order (asc, desc)" @Success 200 {object} ListSourcesResponse @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /template-sources [get]

func (*TemplateSourceHandler) Sync

Sync triggers an immediate sync for a template source. POST /api/v1/template-sources/{id}/sync

func (*TemplateSourceHandler) Update

Update handles PUT /api/v1/template-sources/{id} @Summary Update template source @Description Update an existing template source @Tags Template Sources @Accept json @Produce json @Param id path string true "Source ID" @Param body body UpdateTemplateSourceRequest true "Updated source data" @Success 200 {object} TemplateSourceResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /template-sources/{id} [put]

type TemplateSourceResponse

type TemplateSourceResponse struct {
	ID              string               `json:"id"`
	TenantID        string               `json:"tenant_id"`
	Name            string               `json:"name"`
	SourceType      string               `json:"source_type"`
	TemplateType    string               `json:"template_type"`
	Description     string               `json:"description,omitempty"`
	Enabled         bool                 `json:"enabled"`
	AutoSyncOnScan  bool                 `json:"auto_sync_on_scan"`
	CacheTTLMinutes int                  `json:"cache_ttl_minutes"`
	GitConfig       *ts.GitSourceConfig  `json:"git_config,omitempty"`
	S3Config        *ts.S3SourceConfig   `json:"s3_config,omitempty"`
	HTTPConfig      *ts.HTTPSourceConfig `json:"http_config,omitempty"`
	LastSyncAt      *string              `json:"last_sync_at,omitempty"`
	LastSyncHash    string               `json:"last_sync_hash,omitempty"`
	LastSyncStatus  string               `json:"last_sync_status"`
	LastSyncError   *string              `json:"last_sync_error,omitempty"`
	TotalTemplates  int                  `json:"total_templates"`
	LastSyncCount   int                  `json:"last_sync_count"`
	CredentialID    *string              `json:"credential_id,omitempty"`
	CreatedBy       *string              `json:"created_by,omitempty"`
	CreatedAt       string               `json:"created_at"`
	UpdatedAt       string               `json:"updated_at"`
}

TemplateSourceResponse represents the response for a template source.

type TemplateSyncResponse

type TemplateSyncResponse struct {
	Success        bool   `json:"success"`
	TemplatesFound int    `json:"templates_found"`
	TemplatesAdded int    `json:"templates_added"`
	Duration       string `json:"duration"`
	Error          string `json:"error,omitempty"`
}

TemplateSyncResponse represents the response for a template source sync operation.

type TemplateUsageData

type TemplateUsageData struct {
	TotalTemplates    int64 `json:"total_templates"`
	NucleiTemplates   int64 `json:"nuclei_templates"`
	SemgrepTemplates  int64 `json:"semgrep_templates"`
	GitleaksTemplates int64 `json:"gitleaks_templates"`
	TotalStorageBytes int64 `json:"total_storage_bytes"`
}

TemplateUsageData represents current template usage.

type TemplateUsageResponse

type TemplateUsageResponse struct {
	Usage TemplateUsageData `json:"usage"`
	Quota TemplateQuotaData `json:"quota"`
}

TemplateUsageResponse represents the response for template usage and quota.

type TenantCookieData

type TenantCookieData struct {
	ID   string `json:"id"`
	Slug string `json:"slug"`
	Role string `json:"role"`
}

TenantCookieData represents the tenant info stored in cookie. This is read by frontend to know which tenant user is currently in.

type TenantHandler

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

TenantHandler handles tenant-related HTTP requests. Note: "Team" is the UI-facing name for tenants.

func NewTenantHandler

func NewTenantHandler(svc *app.TenantService, v *validator.Validator, log *logger.Logger) *TenantHandler

NewTenantHandler creates a new tenant handler.

func (*TenantHandler) AcceptInvitation

func (h *TenantHandler) AcceptInvitation(w http.ResponseWriter, r *http.Request)

AcceptInvitation handles POST /api/v1/invitations/{token}/accept

func (*TenantHandler) AddMember

func (h *TenantHandler) AddMember(w http.ResponseWriter, r *http.Request)

AddMember handles POST /api/v1/tenants/{tenant}/members

func (*TenantHandler) Create

func (h *TenantHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/tenants

func (*TenantHandler) CreateInvitation

func (h *TenantHandler) CreateInvitation(w http.ResponseWriter, r *http.Request)

CreateInvitation handles POST /api/v1/tenants/{tenant}/invitations

func (*TenantHandler) DeclineInvitation

func (h *TenantHandler) DeclineInvitation(w http.ResponseWriter, r *http.Request)

DeclineInvitation handles POST /api/v1/invitations/{token}/decline This is a public endpoint - having the token is authorization to decline. Similar to email unsubscribe links.

func (*TenantHandler) Delete

func (h *TenantHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/tenants/{tenant}

func (*TenantHandler) DeleteInvitation

func (h *TenantHandler) DeleteInvitation(w http.ResponseWriter, r *http.Request)

DeleteInvitation handles DELETE /api/v1/tenants/{tenant}/invitations/{invitationId}

func (*TenantHandler) Get

Get handles GET /api/v1/tenants/{tenant}

func (*TenantHandler) GetInvitation

func (h *TenantHandler) GetInvitation(w http.ResponseWriter, r *http.Request)

GetInvitation handles GET /api/v1/invitations/{token}

func (*TenantHandler) GetInvitationPreview

func (h *TenantHandler) GetInvitationPreview(w http.ResponseWriter, r *http.Request)

GetInvitationPreview handles GET /api/v1/invitations/{token}/preview (public) Returns limited invitation info without requiring authentication. This allows users to see what team they're invited to before logging in.

func (*TenantHandler) GetMemberStats

func (h *TenantHandler) GetMemberStats(w http.ResponseWriter, r *http.Request)

GetMemberStats handles GET /api/v1/tenants/{tenant}/members/stats

func (*TenantHandler) GetPentestSettings added in v0.1.2

func (h *TenantHandler) GetPentestSettings(w http.ResponseWriter, r *http.Request)

GetPentestSettings handles GET /api/v1/tenants/{tenant}/settings/pentest

func (*TenantHandler) GetRiskScoringPresets added in v0.1.2

func (h *TenantHandler) GetRiskScoringPresets(w http.ResponseWriter, r *http.Request)

GetRiskScoringPresets handles GET /api/v1/tenants/{tenant}/settings/risk-scoring/presets

func (*TenantHandler) GetRiskScoringSettings added in v0.1.2

func (h *TenantHandler) GetRiskScoringSettings(w http.ResponseWriter, r *http.Request)

GetRiskScoringSettings handles GET /api/v1/tenants/{tenant}/settings/risk-scoring

func (*TenantHandler) GetSettings

func (h *TenantHandler) GetSettings(w http.ResponseWriter, r *http.Request)

GetSettings handles GET /api/v1/tenants/{tenant}/settings

func (*TenantHandler) GetTenantModules added in v0.1.2

func (h *TenantHandler) GetTenantModules(w http.ResponseWriter, r *http.Request)

GetTenantModules handles GET /api/v1/tenants/{tenant}/settings/modules

func (*TenantHandler) List

func (h *TenantHandler) List(w http.ResponseWriter, r *http.Request)

List handles GET /api/v1/tenants (lists user's tenants)

func (*TenantHandler) ListInvitations

func (h *TenantHandler) ListInvitations(w http.ResponseWriter, r *http.Request)

ListInvitations handles GET /api/v1/tenants/{tenant}/invitations

func (*TenantHandler) ListMembers

func (h *TenantHandler) ListMembers(w http.ResponseWriter, r *http.Request)

ListMembers handles GET /api/v1/tenants/{tenant}/members Query parameters:

  • include: comma-separated list (user, roles)
  • search: search term for name or email (requires include=user)
  • limit: max results (default 10, max 100)
  • offset: pagination offset

func (*TenantHandler) PreviewRiskScoringChanges added in v0.1.2

func (h *TenantHandler) PreviewRiskScoringChanges(w http.ResponseWriter, r *http.Request)

PreviewRiskScoringChanges handles POST /api/v1/tenants/{tenant}/settings/risk-scoring/preview

func (*TenantHandler) ReactivateMember added in v0.1.5

func (h *TenantHandler) ReactivateMember(w http.ResponseWriter, r *http.Request)

ReactivateMember handles POST /api/v1/tenants/{tenant}/members/{memberId}/reactivate

func (*TenantHandler) RecalculateRiskScores added in v0.1.2

func (h *TenantHandler) RecalculateRiskScores(w http.ResponseWriter, r *http.Request)

RecalculateRiskScores handles POST /api/v1/tenants/{tenant}/settings/risk-scoring/recalculate

func (*TenantHandler) RemoveMember

func (h *TenantHandler) RemoveMember(w http.ResponseWriter, r *http.Request)

RemoveMember handles DELETE /api/v1/tenants/{tenant}/members/{memberId}

func (*TenantHandler) ResendInvitation added in v0.1.5

func (h *TenantHandler) ResendInvitation(w http.ResponseWriter, r *http.Request)

ResendInvitation handles POST /api/v1/tenants/{tenant}/invitations/{invitationId}/resend

Re-sends the invitation email for a pending (unaccepted, unexpired) invitation. Does NOT change the token, expiry, or any other metadata. Idempotent — calling it 3 times sends 3 emails, all containing the same token link. The existing link in the user's inbox stays valid.

Returns 200 on success, 400 if the invitation was already accepted or has expired, 404 if the invitation doesn't exist or belongs to a different tenant.

func (*TenantHandler) ResetTenantModules added in v0.1.2

func (h *TenantHandler) ResetTenantModules(w http.ResponseWriter, r *http.Request)

ResetTenantModules handles POST /api/v1/tenants/{tenant}/settings/modules/reset

func (*TenantHandler) SetAssetService added in v0.1.2

func (h *TenantHandler) SetAssetService(svc *app.AssetService)

SetAssetService sets the asset service for risk scoring operations.

func (*TenantHandler) SetModuleService added in v0.1.2

func (h *TenantHandler) SetModuleService(svc *app.ModuleService)

SetModuleService sets the module service for module management.

func (*TenantHandler) SetRoleService

func (h *TenantHandler) SetRoleService(svc *app.RoleService)

SetRoleService sets the role service for fetching RBAC roles.

func (*TenantHandler) SuspendMember added in v0.1.5

func (h *TenantHandler) SuspendMember(w http.ResponseWriter, r *http.Request)

SuspendMember handles POST /api/v1/tenants/{tenant}/members/{memberId}/suspend

func (*TenantHandler) Update

func (h *TenantHandler) Update(w http.ResponseWriter, r *http.Request)

Update handles PATCH /api/v1/tenants/{tenant}

func (*TenantHandler) UpdateAPISettings

func (h *TenantHandler) UpdateAPISettings(w http.ResponseWriter, r *http.Request)

UpdateAPISettings handles PATCH /api/v1/tenants/{tenant}/settings/api

func (*TenantHandler) UpdateBranchSettings

func (h *TenantHandler) UpdateBranchSettings(w http.ResponseWriter, r *http.Request)

UpdateBranchSettings handles PATCH /api/v1/tenants/{tenant}/settings/branch

func (*TenantHandler) UpdateBrandingSettings

func (h *TenantHandler) UpdateBrandingSettings(w http.ResponseWriter, r *http.Request)

UpdateBrandingSettings handles PATCH /api/v1/tenants/{tenant}/settings/branding

func (*TenantHandler) UpdateGeneralSettings

func (h *TenantHandler) UpdateGeneralSettings(w http.ResponseWriter, r *http.Request)

UpdateGeneralSettings handles PATCH /api/v1/tenants/{tenant}/settings/general

func (*TenantHandler) UpdateMemberRole

func (h *TenantHandler) UpdateMemberRole(w http.ResponseWriter, r *http.Request)

UpdateMemberRole handles PATCH /api/v1/tenants/{tenant}/members/{memberId}

func (*TenantHandler) UpdatePentestSettings added in v0.1.2

func (h *TenantHandler) UpdatePentestSettings(w http.ResponseWriter, r *http.Request)

UpdatePentestSettings handles PATCH /api/v1/tenants/{tenant}/settings/pentest

func (*TenantHandler) UpdateRiskScoringSettings added in v0.1.2

func (h *TenantHandler) UpdateRiskScoringSettings(w http.ResponseWriter, r *http.Request)

UpdateRiskScoringSettings handles PATCH /api/v1/tenants/{tenant}/settings/risk-scoring

func (*TenantHandler) UpdateSecuritySettings

func (h *TenantHandler) UpdateSecuritySettings(w http.ResponseWriter, r *http.Request)

UpdateSecuritySettings handles PATCH /api/v1/tenants/{tenant}/settings/security

func (*TenantHandler) UpdateTenantModules added in v0.1.2

func (h *TenantHandler) UpdateTenantModules(w http.ResponseWriter, r *http.Request)

UpdateTenantModules handles PATCH /api/v1/tenants/{tenant}/settings/modules

type TenantInfo

type TenantInfo struct {
	ID   string `json:"id"`
	Slug string `json:"slug"`
	Name string `json:"name"`
	Role string `json:"role"`
}

TenantInfo represents tenant membership info in login response.

type TenantMembershipResponse

type TenantMembershipResponse struct {
	ID          string    `json:"id"`
	Name        string    `json:"name"`
	Slug        string    `json:"slug"`
	Description string    `json:"description,omitempty"`
	LogoURL     string    `json:"logo_url,omitempty"`
	Plan        string    `json:"plan"`
	Role        string    `json:"role"`
	JoinedAt    time.Time `json:"joined_at"`
	CreatedAt   time.Time `json:"created_at"`
}

TenantMembershipResponse represents a tenant with the user's role.

type TenantModuleListResponse added in v0.1.2

type TenantModuleListResponse struct {
	Modules []TenantModuleResponse      `json:"modules"`
	Summary TenantModuleSummaryResponse `json:"summary"`
}

TenantModuleListResponse wraps the module list with summary.

type TenantModuleResponse added in v0.1.2

type TenantModuleResponse struct {
	ID            string                    `json:"id"`
	Name          string                    `json:"name"`
	Description   string                    `json:"description,omitempty"`
	Icon          string                    `json:"icon,omitempty"`
	Category      string                    `json:"category"`
	DisplayOrder  int                       `json:"display_order"`
	IsCore        bool                      `json:"is_core"`
	IsEnabled     bool                      `json:"is_enabled"`
	ReleaseStatus string                    `json:"release_status"`
	SubModules    []TenantSubModuleResponse `json:"sub_modules,omitempty"`
}

TenantModuleResponse represents a module with tenant-specific state.

type TenantModuleSummaryResponse added in v0.1.2

type TenantModuleSummaryResponse struct {
	Total    int `json:"total"`
	Enabled  int `json:"enabled"`
	Disabled int `json:"disabled"`
	Core     int `json:"core"`
}

TenantModuleSummaryResponse provides module counts.

type TenantModulesResponse

type TenantModulesResponse struct {
	ModuleIDs           []string                             `json:"module_ids"`
	Modules             []LicensingModuleResponse            `json:"modules"`
	SubModules          map[string][]LicensingModuleResponse `json:"sub_modules,omitempty"`
	EventTypes          []string                             `json:"event_types,omitempty"`
	ComingSoonModuleIDs []string                             `json:"coming_soon_module_ids,omitempty"`
	BetaModuleIDs       []string                             `json:"beta_module_ids,omitempty"`
}

TenantModulesResponse represents the modules available to a tenant.

type TenantResponse

type TenantResponse struct {
	ID          string         `json:"id"`
	Name        string         `json:"name"`
	Slug        string         `json:"slug"`
	Description string         `json:"description,omitempty"`
	LogoURL     string         `json:"logo_url,omitempty"`
	Plan        string         `json:"plan"`
	Settings    map[string]any `json:"settings,omitempty"`
	CreatedAt   time.Time      `json:"created_at"`
	UpdatedAt   time.Time      `json:"updated_at"`
}

TenantResponse represents a tenant in API responses.

type TenantSubModuleResponse added in v0.1.2

type TenantSubModuleResponse struct {
	ID            string `json:"id"`
	Name          string `json:"name"`
	Description   string `json:"description,omitempty"`
	Icon          string `json:"icon,omitempty"`
	ReleaseStatus string `json:"release_status"`
	IsEnabled     bool   `json:"is_enabled"`
}

TenantSubModuleResponse represents a sub-module in the response.

type TenantToolConfigRequest

type TenantToolConfigRequest struct {
	Config    map[string]any `json:"config"`
	IsEnabled bool           `json:"is_enabled"`
}

TenantToolConfigRequest represents the request for tenant tool config.

type TenantToolConfigResponse

type TenantToolConfigResponse struct {
	ID              string                   `json:"id"`
	TenantID        string                   `json:"tenant_id"`
	ToolID          string                   `json:"tool_id"`
	Config          map[string]any           `json:"config"`
	CustomTemplates []CustomTemplateResponse `json:"custom_templates,omitempty"`
	CustomPatterns  []CustomPatternResponse  `json:"custom_patterns,omitempty"`
	IsEnabled       bool                     `json:"is_enabled"`
	UpdatedBy       *string                  `json:"updated_by,omitempty"`
	CreatedAt       string                   `json:"created_at"`
	UpdatedAt       string                   `json:"updated_at"`
}

TenantToolConfigResponse represents the response for tenant tool config.

type TenantToolStatsResponse

type TenantToolStatsResponse struct {
	TenantID       string              `json:"tenant_id"`
	TotalRuns      int64               `json:"total_runs"`
	SuccessfulRuns int64               `json:"successful_runs"`
	FailedRuns     int64               `json:"failed_runs"`
	TotalFindings  int64               `json:"total_findings"`
	ToolBreakdown  []ToolStatsResponse `json:"tool_breakdown"`
}

TenantToolStatsResponse represents tenant tool statistics.

type TenantWithRoleResponse

type TenantWithRoleResponse struct {
	TenantResponse
	Role     string    `json:"role"`
	JoinedAt time.Time `json:"joined_at"`
}

TenantWithRoleResponse represents a tenant with the user's role.

type TestIntegrationCredentialsRequest

type TestIntegrationCredentialsRequest struct {
	Category        string `json:"category" validate:"required,oneof=scm security cloud ticketing notification" example:"scm"`
	Provider        string `json:"provider" validate:"required" example:"github"`
	BaseURL         string `json:"base_url" validate:"omitempty,url" example:"https://github.com"`
	AuthType        string `json:"auth_type" validate:"required,oneof=token oauth api_key basic app" example:"token"`
	Credentials     string `json:"credentials" validate:"required,max=5000" example:"YOUR_TOKEN_HERE"`
	SCMOrganization string `json:"scm_organization" validate:"omitempty,max=255" example:"my-organization"`
}

TestIntegrationCredentialsRequest represents the request to test credentials without creating. @Description Request body for testing integration credentials

type TestIntegrationCredentialsResponse

type TestIntegrationCredentialsResponse struct {
	Success         bool   `json:"success" example:"true"`
	Message         string `json:"message" example:"Connection successful"`
	RepositoryCount int    `json:"repository_count,omitempty" example:"25"`
	Organization    string `json:"organization,omitempty" example:"my-org"`
	Username        string `json:"username,omitempty" example:"octocat"`
}

TestIntegrationCredentialsResponse represents the response from testing credentials. @Description Response from testing integration credentials

type ThreatIntelHandler

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

ThreatIntelHandler handles threat intelligence HTTP requests.

func NewThreatIntelHandler

func NewThreatIntelHandler(
	service *app.ThreatIntelService,
	v *validator.Validator,
	log *logger.Logger,
) *ThreatIntelHandler

NewThreatIntelHandler creates a new ThreatIntelHandler.

func (*ThreatIntelHandler) EnrichCVE

func (h *ThreatIntelHandler) EnrichCVE(w http.ResponseWriter, r *http.Request)

EnrichCVE enriches a single CVE with threat intel data. GET /api/v1/threat-intel/enrich/{cve_id}

func (*ThreatIntelHandler) EnrichCVEs

func (h *ThreatIntelHandler) EnrichCVEs(w http.ResponseWriter, r *http.Request)

EnrichCVEs enriches multiple CVEs with threat intel data. POST /api/v1/threat-intel/enrich

func (*ThreatIntelHandler) GetEPSSScore

func (h *ThreatIntelHandler) GetEPSSScore(w http.ResponseWriter, r *http.Request)

GetEPSSScore retrieves an EPSS score by CVE ID. GET /api/v1/threat-intel/epss/{cve_id}

func (*ThreatIntelHandler) GetEPSSStats

func (h *ThreatIntelHandler) GetEPSSStats(w http.ResponseWriter, r *http.Request)

GetEPSSStats returns EPSS statistics. GET /api/v1/threat-intel/epss/stats

func (*ThreatIntelHandler) GetKEVEntry

func (h *ThreatIntelHandler) GetKEVEntry(w http.ResponseWriter, r *http.Request)

GetKEVEntry retrieves a KEV entry by CVE ID. GET /api/v1/threat-intel/kev/{cve_id}

func (*ThreatIntelHandler) GetKEVStats

func (h *ThreatIntelHandler) GetKEVStats(w http.ResponseWriter, r *http.Request)

GetKEVStats returns KEV statistics. GET /api/v1/threat-intel/kev/stats

func (*ThreatIntelHandler) GetSyncStatus

func (h *ThreatIntelHandler) GetSyncStatus(w http.ResponseWriter, r *http.Request)

GetSyncStatus returns sync status for a specific source. GET /api/v1/threat-intel/sync/{source}

func (*ThreatIntelHandler) GetSyncStatuses

func (h *ThreatIntelHandler) GetSyncStatuses(w http.ResponseWriter, r *http.Request)

GetSyncStatuses returns all sync statuses. GET /api/v1/threat-intel/sync

func (*ThreatIntelHandler) GetThreatIntelStats

func (h *ThreatIntelHandler) GetThreatIntelStats(w http.ResponseWriter, r *http.Request)

GetThreatIntelStats returns unified threat intelligence statistics. GET /api/v1/threat-intel/stats

func (*ThreatIntelHandler) SetSyncEnabled

func (h *ThreatIntelHandler) SetSyncEnabled(w http.ResponseWriter, r *http.Request)

SetSyncEnabled enables or disables sync for a source. PATCH /api/v1/threat-intel/sync/{source}

func (*ThreatIntelHandler) TriggerSync

func (h *ThreatIntelHandler) TriggerSync(w http.ResponseWriter, r *http.Request)

TriggerSync triggers a sync for a specific source or all sources. POST /api/v1/threat-intel/sync

type TierStatsResponse added in v0.1.2

type TierStatsResponse struct {
	TotalAgents    int `json:"total_agents"`
	OnlineAgents   int `json:"online_agents"`
	OfflineAgents  int `json:"offline_agents"`
	TotalCapacity  int `json:"total_capacity"`
	CurrentLoad    int `json:"current_load"`
	AvailableSlots int `json:"available_slots"`
}

TierStatsResponse represents statistics for a single platform agent tier.

type ToolCategoryHandler

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

ToolCategoryHandler handles HTTP requests for tool categories.

func NewToolCategoryHandler

func NewToolCategoryHandler(service *app.ToolCategoryService, v *validator.Validator, log *logger.Logger) *ToolCategoryHandler

NewToolCategoryHandler creates a new ToolCategoryHandler.

func (*ToolCategoryHandler) CreateCustomCategory

func (h *ToolCategoryHandler) CreateCustomCategory(w http.ResponseWriter, r *http.Request)

CreateCustomCategory creates a new tenant custom category. POST /api/v1/custom-tool-categories

func (*ToolCategoryHandler) DeleteCustomCategory

func (h *ToolCategoryHandler) DeleteCustomCategory(w http.ResponseWriter, r *http.Request)

DeleteCustomCategory deletes a tenant custom category. DELETE /api/v1/custom-tool-categories/:id

func (*ToolCategoryHandler) GetCategory

func (h *ToolCategoryHandler) GetCategory(w http.ResponseWriter, r *http.Request)

GetCategory returns a category by ID. GET /api/v1/tool-categories/:id

func (*ToolCategoryHandler) ListAllCategories

func (h *ToolCategoryHandler) ListAllCategories(w http.ResponseWriter, r *http.Request)

ListAllCategories lists all categories for dropdowns (no pagination). GET /api/v1/tool-categories/all

func (*ToolCategoryHandler) ListCategories

func (h *ToolCategoryHandler) ListCategories(w http.ResponseWriter, r *http.Request)

ListCategories lists all tool categories (platform + tenant custom). GET /api/v1/tool-categories

func (*ToolCategoryHandler) UpdateCustomCategory

func (h *ToolCategoryHandler) UpdateCustomCategory(w http.ResponseWriter, r *http.Request)

UpdateCustomCategory updates a tenant custom category. PUT /api/v1/custom-tool-categories/:id

type ToolCategoryResponse

type ToolCategoryResponse struct {
	ID          string  `json:"id"`
	TenantID    *string `json:"tenant_id,omitempty"`
	Name        string  `json:"name"`
	DisplayName string  `json:"display_name"`
	Description string  `json:"description,omitempty"`
	Icon        string  `json:"icon"`
	Color       string  `json:"color"`
	IsBuiltin   bool    `json:"is_builtin"`
	SortOrder   int     `json:"sort_order"`
	CreatedBy   *string `json:"created_by,omitempty"`
	CreatedAt   string  `json:"created_at"`
	UpdatedAt   string  `json:"updated_at"`
}

ToolCategoryResponse represents the response for a tool category.

type ToolConfigRequest

type ToolConfigRequest struct {
	Enabled           bool           `json:"enabled"`
	Severity          string         `json:"severity,omitempty"`
	Timeout           int            `json:"timeout,omitempty"`
	Options           map[string]any `json:"options,omitempty"`
	TemplateMode      string         `json:"template_mode,omitempty"`       // "default", "custom", "both"
	CustomTemplateIDs []string       `json:"custom_template_ids,omitempty"` // IDs of custom templates
}

ToolConfigRequest represents tool configuration in request.

type ToolConfigResponse

type ToolConfigResponse struct {
	Enabled           bool           `json:"enabled"`
	Severity          string         `json:"severity,omitempty"`
	Timeout           int            `json:"timeout,omitempty"`
	Options           map[string]any `json:"options,omitempty"`
	TemplateMode      string         `json:"template_mode,omitempty"`       // "default", "custom", "both"
	CustomTemplateIDs []string       `json:"custom_template_ids,omitempty"` // IDs of custom templates
}

ToolConfigResponse represents tool configuration in response.

type ToolHandler

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

ToolHandler handles HTTP requests for tool registry.

func NewToolHandler

func NewToolHandler(service *app.ToolService, v *validator.Validator, log *logger.Logger) *ToolHandler

NewToolHandler creates a new ToolHandler.

func (*ToolHandler) Activate

func (h *ToolHandler) Activate(w http.ResponseWriter, r *http.Request)

Activate handles POST /api/v1/tools/{id}/activate @Summary Activate tool @Description Activate a tool to make it available for use @Tags Tools @Accept json @Produce json @Param id path string true "Tool ID" @Success 200 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tools/{id}/activate [post]

func (*ToolHandler) ActivateCustomTool

func (h *ToolHandler) ActivateCustomTool(w http.ResponseWriter, r *http.Request)

ActivateCustomTool handles POST /api/v1/custom-tools/{id}/activate @Summary Activate custom tool @Description Activate a tenant custom tool @Tags Custom Tools @Accept json @Produce json @Param id path string true "Tool ID" @Success 200 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /custom-tools/{id}/activate [post]

func (*ToolHandler) BulkDisable

func (h *ToolHandler) BulkDisable(w http.ResponseWriter, r *http.Request)

BulkDisable handles POST /api/v1/tenant-tools/bulk-disable @Summary Bulk disable tools @Description Disable multiple tools for the current tenant @Tags Tenant Tools @Accept json @Produce json @Param body body BulkToolIDsRequest true "Tool IDs" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tenant-tools/bulk-disable [post]

func (*ToolHandler) BulkEnable

func (h *ToolHandler) BulkEnable(w http.ResponseWriter, r *http.Request)

BulkEnable handles POST /api/v1/tenant-tools/bulk-enable @Summary Bulk enable tools @Description Enable multiple tools for the current tenant @Tags Tenant Tools @Accept json @Produce json @Param body body BulkToolIDsRequest true "Tool IDs" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tenant-tools/bulk-enable [post]

func (*ToolHandler) Create

func (h *ToolHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/tools @Summary Create tool @Description Create a new tool in the registry (admin only) @Tags Tools @Accept json @Produce json @Param body body CreateToolRequest true "Tool data" @Success 201 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tools [post]

func (*ToolHandler) CreateCustomTool

func (h *ToolHandler) CreateCustomTool(w http.ResponseWriter, r *http.Request)

CreateCustomTool handles POST /api/v1/custom-tools @Summary Create custom tool @Description Create a new tenant custom tool @Tags Custom Tools @Accept json @Produce json @Param body body CreateToolRequest true "Tool data" @Success 201 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 409 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /custom-tools [post]

func (*ToolHandler) Deactivate

func (h *ToolHandler) Deactivate(w http.ResponseWriter, r *http.Request)

Deactivate handles POST /api/v1/tools/{id}/deactivate @Summary Deactivate tool @Description Deactivate a tool to make it unavailable for use @Tags Tools @Accept json @Produce json @Param id path string true "Tool ID" @Success 200 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tools/{id}/deactivate [post]

func (*ToolHandler) DeactivateCustomTool

func (h *ToolHandler) DeactivateCustomTool(w http.ResponseWriter, r *http.Request)

DeactivateCustomTool handles POST /api/v1/custom-tools/{id}/deactivate @Summary Deactivate custom tool @Description Deactivate a tenant custom tool @Tags Custom Tools @Accept json @Produce json @Param id path string true "Tool ID" @Success 200 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /custom-tools/{id}/deactivate [post]

func (*ToolHandler) Delete

func (h *ToolHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/tools/{id} @Summary Delete tool @Description Delete a tool from the registry (admin only, builtin tools cannot be deleted) @Tags Tools @Accept json @Produce json @Param id path string true "Tool ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tools/{id} [delete]

func (*ToolHandler) DeleteCustomTool

func (h *ToolHandler) DeleteCustomTool(w http.ResponseWriter, r *http.Request)

DeleteCustomTool handles DELETE /api/v1/custom-tools/{id} @Summary Delete custom tool @Description Delete a tenant custom tool @Tags Custom Tools @Accept json @Produce json @Param id path string true "Tool ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /custom-tools/{id} [delete]

func (*ToolHandler) DeleteTenantConfig

func (h *ToolHandler) DeleteTenantConfig(w http.ResponseWriter, r *http.Request)

DeleteTenantConfig handles DELETE /api/v1/tenant-tools/{tool_id} @Summary Delete tenant tool config @Description Delete tenant-specific configuration for a tool @Tags Tenant Tools @Accept json @Produce json @Param tool_id path string true "Tool ID" @Success 204 "No Content" @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tenant-tools/{tool_id} [delete]

func (*ToolHandler) Get

func (h *ToolHandler) Get(w http.ResponseWriter, r *http.Request)

Get handles GET /api/v1/tools/{id} @Summary Get tool @Description Get a single tool by ID @Tags Tools @Accept json @Produce json @Param id path string true "Tool ID" @Success 200 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tools/{id} [get]

func (*ToolHandler) GetByName

func (h *ToolHandler) GetByName(w http.ResponseWriter, r *http.Request)

GetByName handles GET /api/v1/tools/name/{name} @Summary Get tool by name @Description Get a single tool by name @Tags Tools @Accept json @Produce json @Param name path string true "Tool name" @Success 200 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tools/name/{name} [get]

func (*ToolHandler) GetCustomTool

func (h *ToolHandler) GetCustomTool(w http.ResponseWriter, r *http.Request)

GetCustomTool handles GET /api/v1/custom-tools/{id} @Summary Get custom tool @Description Get a single tenant custom tool by ID @Tags Custom Tools @Accept json @Produce json @Param id path string true "Tool ID" @Success 200 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /custom-tools/{id} [get]

func (*ToolHandler) GetEffectiveConfig

func (h *ToolHandler) GetEffectiveConfig(w http.ResponseWriter, r *http.Request)

GetEffectiveConfig handles GET /api/v1/tenant-tools/{tool_id}/effective-config @Summary Get effective tool config @Description Get the merged configuration (default + tenant overrides) for a tool @Tags Tenant Tools @Accept json @Produce json @Param tool_id path string true "Tool ID" @Success 200 {object} map[string]any @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tenant-tools/{tool_id}/effective-config [get]

func (*ToolHandler) GetTenantConfig

func (h *ToolHandler) GetTenantConfig(w http.ResponseWriter, r *http.Request)

GetTenantConfig handles GET /api/v1/tenant-tools/{tool_id} @Summary Get tenant tool config @Description Get tenant-specific configuration for a tool @Tags Tenant Tools @Accept json @Produce json @Param tool_id path string true "Tool ID" @Success 200 {object} TenantToolConfigResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tenant-tools/{tool_id} [get]

func (*ToolHandler) GetTenantStats

func (h *ToolHandler) GetTenantStats(w http.ResponseWriter, r *http.Request)

GetTenantStats handles GET /api/v1/tool-stats @Summary Get tenant tool stats @Description Get aggregated tool execution statistics for the current tenant @Tags Tool Stats @Accept json @Produce json @Param days query int false "Number of days to include" default(30) @Success 200 {object} TenantToolStatsResponse @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tool-stats [get]

func (*ToolHandler) GetToolStats

func (h *ToolHandler) GetToolStats(w http.ResponseWriter, r *http.Request)

GetToolStats handles GET /api/v1/tool-stats/{tool_id} @Summary Get tool stats @Description Get execution statistics for a specific tool @Tags Tool Stats @Accept json @Produce json @Param tool_id path string true "Tool ID" @Param days query int false "Number of days to include" default(30) @Success 200 {object} ToolStatsResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tool-stats/{tool_id} [get]

func (*ToolHandler) GetToolWithConfig

func (h *ToolHandler) GetToolWithConfig(w http.ResponseWriter, r *http.Request)

GetToolWithConfig handles GET /api/v1/tenant-tools/{tool_id}/with-config @Summary Get tool with tenant config @Description Get a tool with its tenant-specific configuration and effective config @Tags Tenant Tools @Accept json @Produce json @Param tool_id path string true "Tool ID" @Success 200 {object} ToolWithConfigResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tenant-tools/{tool_id}/with-config [get]

func (*ToolHandler) List

func (h *ToolHandler) List(w http.ResponseWriter, r *http.Request)

List handles GET /api/v1/tools @Summary List tools @Description Get a paginated list of available tools @Tags Tools @Accept json @Produce json @Param category query string false "Filter by category" @Param capabilities query string false "Filter by capabilities (comma-separated)" @Param is_active query boolean false "Filter by active status" @Param is_builtin query boolean false "Filter by builtin status" @Param search query string false "Search by name or description" @Param tags query string false "Filter by tags (comma-separated)" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ToolResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tools [get]

func (*ToolHandler) ListAllTools

func (h *ToolHandler) ListAllTools(w http.ResponseWriter, r *http.Request)

ListAllTools handles GET /api/v1/tenant-tools/all-tools @Summary List all tools with tenant config @Description Get a paginated list of all tools with their tenant-specific enabled status @Tags Tenant Tools @Accept json @Produce json @Param category query string false "Filter by category" @Param is_active query boolean false "Filter by system-wide active status" @Param is_builtin query boolean false "Filter by builtin status" @Param search query string false "Search by name or description" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ToolWithConfigResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tenant-tools/all-tools [get]

func (*ToolHandler) ListCustomTools

func (h *ToolHandler) ListCustomTools(w http.ResponseWriter, r *http.Request)

ListCustomTools handles GET /api/v1/custom-tools @Summary List custom tools @Description Get a paginated list of tenant's custom tools @Tags Custom Tools @Accept json @Produce json @Param category query string false "Filter by category" @Param capabilities query string false "Filter by capabilities (comma-separated)" @Param is_active query boolean false "Filter by active status" @Param search query string false "Search by name or description" @Param tags query string false "Filter by tags (comma-separated)" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ToolResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /custom-tools [get]

func (*ToolHandler) ListPlatformTools

func (h *ToolHandler) ListPlatformTools(w http.ResponseWriter, r *http.Request)

ListPlatformTools handles GET /api/v1/tools/platform @Summary List platform tools @Description Get a paginated list of platform-provided tools (available to all tenants) @Tags Tools @Accept json @Produce json @Param category query string false "Filter by category" @Param capabilities query string false "Filter by capabilities (comma-separated)" @Param is_active query boolean false "Filter by active status" @Param search query string false "Search by name or description" @Param tags query string false "Filter by tags (comma-separated)" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[ToolResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tools/platform [get]

func (*ToolHandler) ListTenantConfigs

func (h *ToolHandler) ListTenantConfigs(w http.ResponseWriter, r *http.Request)

ListTenantConfigs handles GET /api/v1/tenant-tools @Summary List tenant tool configs @Description Get a paginated list of tenant tool configurations @Tags Tenant Tools @Accept json @Produce json @Param tool_id query string false "Filter by tool ID" @Param is_enabled query boolean false "Filter by enabled status" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} ListResponse[TenantToolConfigResponse] @Failure 400 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tenant-tools [get]

func (*ToolHandler) Update

func (h *ToolHandler) Update(w http.ResponseWriter, r *http.Request)

Update handles PUT /api/v1/tools/{id} @Summary Update tool @Description Update an existing tool (admin only) @Tags Tools @Accept json @Produce json @Param id path string true "Tool ID" @Param body body UpdateToolRequest true "Update data" @Success 200 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tools/{id} [put]

func (*ToolHandler) UpdateCustomTool

func (h *ToolHandler) UpdateCustomTool(w http.ResponseWriter, r *http.Request)

UpdateCustomTool handles PUT /api/v1/custom-tools/{id} @Summary Update custom tool @Description Update a tenant custom tool @Tags Custom Tools @Accept json @Produce json @Param id path string true "Tool ID" @Param body body UpdateToolRequest true "Update data" @Success 200 {object} ToolResponse @Failure 400 {object} apierror.Error @Failure 403 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /custom-tools/{id} [put]

func (*ToolHandler) UpdateTenantConfig

func (h *ToolHandler) UpdateTenantConfig(w http.ResponseWriter, r *http.Request)

UpdateTenantConfig handles PUT /api/v1/tenant-tools/{tool_id} @Summary Update tenant tool config @Description Update or create tenant-specific configuration for a tool @Tags Tenant Tools @Accept json @Produce json @Param tool_id path string true "Tool ID" @Param body body TenantToolConfigRequest true "Config data" @Success 200 {object} TenantToolConfigResponse @Failure 400 {object} apierror.Error @Failure 404 {object} apierror.Error @Failure 500 {object} apierror.Error @Security BearerAuth @Router /tenant-tools/{tool_id} [put]

type ToolResponse

type ToolResponse struct {
	ID               string                    `json:"id"`
	TenantID         *string                   `json:"tenant_id,omitempty"` // nil for platform tools, UUID for custom tools
	Name             string                    `json:"name"`
	DisplayName      string                    `json:"display_name"`
	Description      string                    `json:"description,omitempty"`
	LogoURL          string                    `json:"logo_url,omitempty"`
	CategoryID       *string                   `json:"category_id,omitempty"` // Foreign key to tool_categories table
	Category         *EmbeddedCategoryResponse `json:"category,omitempty"`    // Embedded category info for UI grouping
	InstallMethod    string                    `json:"install_method"`
	InstallCmd       string                    `json:"install_cmd,omitempty"`
	UpdateCmd        string                    `json:"update_cmd,omitempty"`
	VersionCmd       string                    `json:"version_cmd,omitempty"`
	VersionRegex     string                    `json:"version_regex,omitempty"`
	CurrentVersion   string                    `json:"current_version,omitempty"`
	LatestVersion    string                    `json:"latest_version,omitempty"`
	HasUpdate        bool                      `json:"has_update"`
	ConfigFilePath   string                    `json:"config_file_path,omitempty"`
	ConfigSchema     map[string]any            `json:"config_schema,omitempty"`
	DefaultConfig    map[string]any            `json:"default_config,omitempty"`
	Capabilities     []string                  `json:"capabilities"`
	SupportedTargets []string                  `json:"supported_targets"`
	OutputFormats    []string                  `json:"output_formats"`
	DocsURL          string                    `json:"docs_url,omitempty"`
	GithubURL        string                    `json:"github_url,omitempty"`
	IsActive         bool                      `json:"is_active"`
	IsBuiltin        bool                      `json:"is_builtin"`
	IsPlatformTool   bool                      `json:"is_platform_tool"` // true for platform tools, false for custom
	Tags             []string                  `json:"tags"`
	Metadata         map[string]any            `json:"metadata,omitempty"`
	CreatedBy        *string                   `json:"created_by,omitempty"` // User ID who created the tool (for custom tools)
	CreatedAt        string                    `json:"created_at"`
	UpdatedAt        string                    `json:"updated_at"`
}

ToolResponse represents the response for a tool.

type ToolStatsResponse

type ToolStatsResponse struct {
	ToolID         string `json:"tool_id"`
	TotalRuns      int64  `json:"total_runs"`
	SuccessfulRuns int64  `json:"successful_runs"`
	FailedRuns     int64  `json:"failed_runs"`
	TotalFindings  int64  `json:"total_findings"`
	AvgDurationMs  int64  `json:"avg_duration_ms"`
}

ToolStatsResponse represents tool statistics.

type ToolWithConfigResponse

type ToolWithConfigResponse struct {
	Tool            *ToolResponse             `json:"tool"`
	TenantConfig    *TenantToolConfigResponse `json:"tenant_config,omitempty"`
	EffectiveConfig map[string]any            `json:"effective_config"`
	IsEnabled       bool                      `json:"is_enabled"`
	IsAvailable     bool                      `json:"is_available"` // True if at least one agent supports this tool
}

ToolWithConfigResponse represents a tool with its tenant config.

type TriageFindingRequest

type TriageFindingRequest struct {
	Reason string `json:"reason" validate:"max=1000"` // Optional reason for confirmation
}

TriageFindingRequest represents the request to triage (confirm) a finding. Triage = confirm the finding is real (transitions from "new" to "confirmed")

type TriageResultResponse

type TriageResultResponse struct {
	ID                      string  `json:"id"`
	Status                  string  `json:"status"`
	SeverityAssessment      string  `json:"severity_assessment,omitempty"`
	SeverityJustification   string  `json:"severity_justification,omitempty"`
	RiskScore               float64 `json:"risk_score,omitempty"`
	Exploitability          string  `json:"exploitability,omitempty"`
	ExploitabilityDetails   string  `json:"exploitability_details,omitempty"`
	BusinessImpact          string  `json:"business_impact,omitempty"`
	PriorityRank            int     `json:"priority_rank,omitempty"`
	FalsePositiveLikelihood float64 `json:"false_positive_likelihood,omitempty"`
	FalsePositiveReason     string  `json:"false_positive_reason,omitempty"`
	Summary                 string  `json:"summary,omitempty"`
	CreatedAt               string  `json:"created_at"`
	CompletedAt             string  `json:"completed_at,omitempty"`
	ErrorMessage            string  `json:"error_message,omitempty"`
}

TriageResultResponse represents a triage result in API responses.

type TriggerRequest

type TriggerRequest struct {
	Type     string         `json:"type" validate:"required,oneof=manual schedule webhook api on_asset_discovery"`
	Schedule string         `json:"schedule"`
	Webhook  string         `json:"webhook"`
	Filters  map[string]any `json:"filters"`
}

TriggerRequest represents a trigger configuration in the request.

type TriggerResponse

type TriggerResponse struct {
	Type     string         `json:"type"`
	Schedule string         `json:"schedule,omitempty"`
	Webhook  string         `json:"webhook,omitempty"`
	Filters  map[string]any `json:"filters,omitempty"`
}

TriggerResponse represents a trigger in the response.

type TriggerRunRequest

type TriggerRunRequest struct {
	TemplateID  string         `json:"template_id" validate:"required,uuid"`
	AssetID     string         `json:"asset_id" validate:"omitempty,uuid"`
	TriggerType string         `json:"trigger_type" validate:"omitempty,oneof=manual schedule webhook api"`
	Context     map[string]any `json:"context"`
}

TriggerRunRequest represents the request body for triggering a pipeline run.

type TriggerScanExecRequest

type TriggerScanExecRequest struct {
	Context map[string]any `json:"context"`
}

TriggerScanRequest represents the request body for triggering a scan.

type TriggerSyncRequest

type TriggerSyncRequest struct {
	Source string `json:"source,omitempty"` // empty or "all" for all sources
}

TriggerSyncRequest is the request for triggering a sync.

type TriggerWorkflowRequest

type TriggerWorkflowRequest struct {
	TriggerType string         `` /* 146-byte string literal not displayed */
	TriggerData map[string]any `json:"trigger_data"`
}

TriggerWorkflowRequest represents the request body for triggering a workflow run.

type UIPositionRequest

type UIPositionRequest struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

UIPositionRequest represents a visual position in the workflow builder.

type UIPositionResponse

type UIPositionResponse struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

UIPositionResponse represents a visual position in the workflow builder response.

type UnreadCountResponse added in v0.1.2

type UnreadCountResponse struct {
	Count int `json:"count"`
}

UnreadCountResponse represents the unread notification count.

type UpdateAPISettingsRequest

type UpdateAPISettingsRequest struct {
	APIKeyEnabled bool     `json:"api_key_enabled"`
	WebhookURL    string   `json:"webhook_url" validate:"omitempty,url"`
	WebhookSecret string   `json:"webhook_secret"`
	WebhookEvents []string `json:"webhook_events"`
}

UpdateAPISettingsRequest represents the request to update API settings.

type UpdateAdminRequest

type UpdateAdminRequest struct {
	Name     *string `json:"name,omitempty"`
	Role     *string `json:"role,omitempty"`
	IsActive *bool   `json:"is_active,omitempty"`
}

UpdateAdminRequest represents the request to update an admin.

type UpdateAgentRequest

type UpdateAgentRequest struct {
	Name              string   `json:"name" validate:"omitempty,min=1,max=255"`
	Description       string   `json:"description" validate:"max=1000"`
	Capabilities      []string `json:"capabilities" validate:"max=20,dive,max=50"`
	Tools             []string `json:"tools" validate:"max=20,dive,max=50"`
	Status            string   `json:"status" validate:"omitempty,oneof=active disabled revoked"` // Admin-controlled
	MaxConcurrentJobs *int     `json:"max_concurrent_jobs" validate:"omitempty,min=1,max=100"`
}

UpdateAgentRequest represents the request body for updating an agent.

type UpdateAssessmentRequest added in v0.1.2

type UpdateAssessmentRequest struct {
	FrameworkID string  `json:"framework_id"`
	Status      string  `json:"status"`
	Priority    string  `json:"priority"`
	Owner       string  `json:"owner"`
	Notes       string  `json:"notes"`
	DueDate     *string `json:"due_date"`
}

UpdateAssessmentRequest is the API request for updating an assessment.

type UpdateAssetGroupRequest

type UpdateAssetGroupRequest struct {
	Name         *string  `json:"name" validate:"omitempty,min=1,max=255"`
	Description  *string  `json:"description" validate:"omitempty,max=1000"`
	Environment  *string  `json:"environment" validate:"omitempty,asset_group_environment"`
	Criticality  *string  `json:"criticality" validate:"omitempty,asset_group_criticality"`
	BusinessUnit *string  `json:"business_unit" validate:"omitempty,max=255"`
	Owner        *string  `json:"owner" validate:"omitempty,max=255"`
	OwnerEmail   *string  `json:"owner_email" validate:"omitempty,email,max=255"`
	Tags         []string `json:"tags" validate:"omitempty,max=20,dive,max=50"`
}

UpdateAssetGroupRequest represents the request to update an asset group.

type UpdateAssetOwnerRequest added in v0.1.2

type UpdateAssetOwnerRequest struct {
	OwnershipType string `json:"ownership_type" validate:"required"`
}

UpdateAssetOwnerRequest represents the request to update an owner's type.

type UpdateAssetOwnershipRequest

type UpdateAssetOwnershipRequest struct {
	OwnershipType string `json:"ownership_type" validate:"required,oneof=primary secondary stakeholder informed"`
}

UpdateAssetOwnershipRequest represents the request to update asset ownership type.

type UpdateAssetRequest

type UpdateAssetRequest struct {
	Name        *string  `json:"name" validate:"omitempty,min=1,max=255"`
	Criticality *string  `json:"criticality" validate:"omitempty,criticality"`
	Scope       *string  `json:"scope" validate:"omitempty,scope"`
	Exposure    *string  `json:"exposure" validate:"omitempty,exposure"`
	Description *string  `json:"description" validate:"omitempty,max=1000"`
	OwnerRef    *string  `json:"owner_ref" validate:"omitempty,max=500"`
	Tags        []string `json:"tags" validate:"omitempty,max=20,dive,max=50"`
}

UpdateAssetRequest represents the request to update an asset.

type UpdateAssetServiceRequest

type UpdateAssetServiceRequest struct {
	Name         *string   `json:"name" validate:"omitempty,max=255"`
	Product      *string   `json:"product" validate:"omitempty,max=255"`
	Version      *string   `json:"version" validate:"omitempty,max=100"`
	Banner       *string   `json:"banner" validate:"omitempty,max=4096"`
	CPE          *string   `json:"cpe" validate:"omitempty,max=500"`
	Technologies *[]string `json:"technologies" validate:"omitempty,max=50,dive,max=100"`
	IsPublic     *bool     `json:"is_public"`
	Exposure     *string   `json:"exposure" validate:"omitempty,oneof=public restricted private"`
	TLSEnabled   *bool     `json:"tls_enabled"`
	TLSVersion   *string   `json:"tls_version" validate:"omitempty,max=20"`
	State        *string   `json:"state" validate:"omitempty,oneof=active inactive filtered"`
}

UpdateAssetServiceRequest represents the request to update an asset service.

type UpdateAssignmentRuleRequest added in v0.1.2

type UpdateAssignmentRuleRequest struct {
	Name          *string                             `json:"name" validate:"omitempty,min=2,max=200"`
	Description   *string                             `json:"description" validate:"omitempty,max=1000"`
	Priority      *int                                `json:"priority"`
	IsActive      *bool                               `json:"is_active"`
	Conditions    *accesscontrol.AssignmentConditions `json:"conditions"`
	TargetGroupID *string                             `json:"target_group_id" validate:"omitempty,uuid"`
	Options       *accesscontrol.AssignmentOptions    `json:"options"`
}

UpdateAssignmentRuleRequest represents the request to update an assignment rule.

type UpdateBranchRequest

type UpdateBranchRequest struct {
	IsProtected            *bool   `json:"is_protected"`
	LastCommitSHA          *string `json:"last_commit_sha" validate:"omitempty,max=40"`
	LastCommitMessage      *string `json:"last_commit_message" validate:"omitempty,max=1000"`
	LastCommitAuthor       *string `json:"last_commit_author" validate:"omitempty,max=100"`
	LastCommitAuthorAvatar *string `json:"last_commit_author_avatar" validate:"omitempty,max=500"`
	ScanOnPush             *bool   `json:"scan_on_push"`
	ScanOnPR               *bool   `json:"scan_on_pr"`
	KeepWhenInactive       *bool   `json:"keep_when_inactive"`
	RetentionDays          *int    `json:"retention_days" validate:"omitempty,min=0,max=365"`
}

UpdateBranchRequest represents the request to update a branch.

type UpdateBranchSettingsRequest

type UpdateBranchSettingsRequest struct {
	TypeRules []app.BranchTypeRuleInput `json:"type_rules" validate:"dive"`
}

UpdateBranchSettingsRequest represents the request to update branch naming convention settings.

type UpdateBrandingSettingsRequest

type UpdateBrandingSettingsRequest struct {
	PrimaryColor string `json:"primary_color"`
	LogoDarkURL  string `json:"logo_dark_url" validate:"omitempty,url"`
	LogoData     string `json:"logo_data"` // Base64 encoded logo (max 150KB)
}

UpdateBrandingSettingsRequest represents the request to update branding settings.

type UpdateCampaignMemberRoleRequest added in v0.1.3

type UpdateCampaignMemberRoleRequest struct {
	Role string `json:"role" validate:"required,oneof=lead tester reviewer observer"`
}

UpdateCampaignMemberRoleRequest is the API request for changing a member's role.

type UpdateCapabilityRequest

type UpdateCapabilityRequest struct {
	DisplayName string `json:"display_name" validate:"required,max=100"`
	Description string `json:"description" validate:"max=500"`
	Icon        string `json:"icon" validate:"max=50"`
	Color       string `json:"color" validate:"max=20"`
	Category    string `json:"category" validate:"max=50"`
}

UpdateCapabilityRequest represents the request body for updating a capability.

type UpdateCommandStatusRequest

type UpdateCommandStatusRequest struct {
	Result       json.RawMessage `json:"result,omitempty"`
	ErrorMessage string          `json:"error_message,omitempty"`
}

UpdateCommandStatusRequest represents the request to update command status.

type UpdateCommentRequest

type UpdateCommentRequest struct {
	Content string `json:"content" validate:"required,min=1,max=10000"`
}

UpdateCommentRequest represents the request to update a comment.

type UpdateComponentRequest

type UpdateComponentRequest struct {
	Version            *string `json:"version" validate:"omitempty,max=100"`
	PackageManager     *string `json:"package_manager" validate:"omitempty,max=50"`
	Namespace          *string `json:"namespace" validate:"omitempty,max=255"`
	ManifestFile       *string `json:"manifest_file" validate:"omitempty,max=255"`
	ManifestPath       *string `json:"manifest_path" validate:"omitempty,max=500"`
	DependencyType     *string `json:"dependency_type" validate:"omitempty"`
	License            *string `json:"license" validate:"omitempty,max=100"`
	Status             *string `json:"status" validate:"omitempty"`
	VulnerabilityCount *int    `json:"vulnerability_count" validate:"omitempty,min=0"`
}

UpdateComponentRequest represents the request to update a component.

type UpdateCredentialRequest

type UpdateCredentialRequest struct {
	Name        string `json:"name" validate:"omitempty,min=1,max=255"`
	Description string `json:"description" validate:"max=1000"`
	ExpiresAt   string `json:"expires_at,omitempty"`
}

UpdateCredentialRequest represents the request body for updating a credential.

type UpdateFindingStatusRequest

type UpdateFindingStatusRequest struct {
	Status     string `json:"status" validate:"required"`
	Resolution string `json:"resolution" validate:"max=1000"`
}

UpdateFindingStatusRequest represents the request to update a finding's status. Note: resolved_by is automatically set from the authenticated user, not from request

type UpdateGeneralSettingsRequest

type UpdateGeneralSettingsRequest struct {
	Timezone string `json:"timezone"`
	Language string `json:"language" validate:"omitempty,oneof=en vi ja ko zh"`
	Industry string `json:"industry" validate:"max=100"`
	Website  string `json:"website" validate:"omitempty,url,max=500"`
}

UpdateGeneralSettingsRequest represents the request to update general settings.

type UpdateGroupMemberRoleRequest

type UpdateGroupMemberRoleRequest struct {
	Role string `json:"role" validate:"required,oneof=owner lead member"`
}

UpdateGroupMemberRoleRequest represents the request to update a member's role.

type UpdateGroupRequest

type UpdateGroupRequest struct {
	Name               *string                   `json:"name" validate:"omitempty,min=2,max=100"`
	Slug               *string                   `json:"slug" validate:"omitempty,min=2,max=100,slug"`
	Description        *string                   `json:"description" validate:"omitempty,max=500"`
	Settings           *group.GroupSettings      `json:"settings,omitempty"`
	NotificationConfig *group.NotificationConfig `json:"notification_config,omitempty"`
	IsActive           *bool                     `json:"is_active,omitempty"`
}

UpdateGroupRequest represents the request to update a group.

type UpdateIntegrationRequest

type UpdateIntegrationRequest struct {
	Name            *string `json:"name" validate:"omitempty,min=1,max=255" example:"GitHub Production Updated"`
	Description     *string `json:"description" validate:"omitempty,max=1000"`
	Credentials     *string `json:"credentials" validate:"omitempty,max=5000"`
	BaseURL         *string `json:"base_url" validate:"omitempty,url"`
	SCMOrganization *string `json:"scm_organization" validate:"omitempty,max=255"`
}

UpdateIntegrationRequest represents the request to update an integration. @Description Request body for updating an existing integration

type UpdateMemberRoleRequest

type UpdateMemberRoleRequest struct {
	Role string `json:"role" validate:"required,oneof=admin member viewer"`
}

UpdateMemberRoleRequest represents the request to update a member's role.

type UpdateNodeRequest

type UpdateNodeRequest struct {
	Name        *string                    `json:"name" validate:"omitempty,min=1,max=255"`
	Description *string                    `json:"description" validate:"omitempty,max=1000"`
	UIPosition  *WorkflowUIPositionRequest `json:"ui_position"`
	Config      *NodeConfigRequest         `json:"config"`
}

UpdateNodeRequest represents the request body for updating a node.

type UpdateNotificationIntegrationRequest

type UpdateNotificationIntegrationRequest struct {
	Name        *string `json:"name" validate:"omitempty,min=1,max=255"`
	Description *string `json:"description" validate:"omitempty,max=1000"`
	Credentials *string `json:"credentials"` // Webhook URL or Bot Token (optional, leave empty to keep current)

	// Notification-specific fields
	ChannelID          *string  `json:"channel_id"`
	ChannelName        *string  `json:"channel_name"`
	EnabledSeverities  []string `json:"enabled_severities"`  // Severity levels to notify on
	EnabledEventTypes  []string `json:"enabled_event_types"` // Event types to receive notifications for
	MessageTemplate    *string  `json:"message_template"`
	IncludeDetails     *bool    `json:"include_details"`
	MinIntervalMinutes *int     `json:"min_interval_minutes"`
}

UpdateNotificationIntegrationRequest represents the request to update a notification integration.

type UpdateOverrideRequest

type UpdateOverrideRequest struct {
	RulePattern      string  `json:"rule_pattern" validate:"omitempty,min=1,max=500"`
	IsPattern        *bool   `json:"is_pattern"`
	Enabled          *bool   `json:"enabled"`
	SeverityOverride string  `json:"severity_override" validate:"omitempty,oneof=critical high medium low info"`
	AssetGroupID     string  `json:"asset_group_id" validate:"omitempty,uuid"`
	ScanProfileID    string  `json:"scan_profile_id" validate:"omitempty,uuid"`
	Reason           string  `json:"reason" validate:"max=1000"`
	ExpiresAt        *string `json:"expires_at"`
}

UpdateOverrideRequest represents the request body for updating a rule override.

type UpdatePentestSettingsRequest added in v0.1.2

type UpdatePentestSettingsRequest struct {
	CampaignTypes []tenant.ConfigOption `json:"campaign_types" validate:"dive"`
	Methodologies []tenant.ConfigOption `json:"methodologies" validate:"dive"`
}

UpdatePentestSettingsRequest represents the request to update pentest settings.

type UpdatePermissionSetRequest

type UpdatePermissionSetRequest struct {
	Name        *string `json:"name" validate:"omitempty,min=2,max=100"`
	Description *string `json:"description" validate:"omitempty,max=500"`
	IsActive    *bool   `json:"is_active,omitempty"`
}

UpdatePermissionSetRequest represents the request to update a permission set.

type UpdatePreferencesRequest

type UpdatePreferencesRequest struct {
	Theme         *string `json:"theme" validate:"omitempty,oneof=light dark system"`
	Language      *string `json:"language" validate:"omitempty,oneof=en vi"`
	Notifications *bool   `json:"notifications"`
}

UpdatePreferencesRequest represents the request to update user preferences.

type UpdateProfileRequest

type UpdateProfileRequest struct {
	Name      *string `json:"name" validate:"omitempty,max=255"`
	Phone     *string `json:"phone" validate:"omitempty,max=50"`
	AvatarURL *string `json:"avatar_url" validate:"omitempty,url,max=500"`
}

UpdateProfileRequest represents the request to update a user profile.

type UpdateProviderRequest added in v0.1.2

type UpdateProviderRequest struct {
	DisplayName      *string  `json:"display_name" validate:"omitempty,min=1,max=255"`
	ClientID         *string  `json:"client_id" validate:"omitempty,max=255"`
	ClientSecret     *string  `json:"client_secret" validate:"omitempty,max=1000"`
	IssuerURL        *string  `json:"issuer_url" validate:"omitempty,url,max=500"`
	TenantIdentifier *string  `json:"tenant_identifier" validate:"omitempty,max=255"`
	Scopes           []string `json:"scopes" validate:"max=20,dive,max=100"`
	AllowedDomains   []string `json:"allowed_domains" validate:"max=50,dive,max=255"`
	AutoProvision    *bool    `json:"auto_provision"`
	DefaultRole      *string  `json:"default_role" validate:"omitempty,oneof=member viewer"`
	IsActive         *bool    `json:"is_active"`
}

UpdateProviderRequest is the request body for updating an identity provider.

type UpdateQualityGateRequest

type UpdateQualityGateRequest struct {
	Enabled         bool   `json:"enabled"`
	FailOnCritical  bool   `json:"fail_on_critical"`
	FailOnHigh      bool   `json:"fail_on_high"`
	MaxCritical     int    `json:"max_critical"`
	MaxHigh         int    `json:"max_high"`
	MaxMedium       int    `json:"max_medium"`
	MaxTotal        int    `json:"max_total"`
	NewFindingsOnly bool   `json:"new_findings_only,omitempty"`
	BaselineBranch  string `json:"baseline_branch,omitempty"`
}

UpdateQualityGateRequest represents the request body for updating quality gate.

type UpdateRelationshipRequest

type UpdateRelationshipRequest struct {
	Description  *string  `json:"description" validate:"omitempty,max=1000"`
	Confidence   *string  `json:"confidence" validate:"omitempty"`
	ImpactWeight *int     `json:"impact_weight" validate:"omitempty,min=1,max=10"`
	Tags         []string `json:"tags" validate:"omitempty,max=20,dive,max=50"`
	MarkVerified bool     `json:"mark_verified"`
}

UpdateRelationshipRequest represents the request to update a relationship.

type UpdateRepositoryExtensionRequest

type UpdateRepositoryExtensionRequest struct {
	RepoID               *string          `json:"repo_id" validate:"omitempty,max=255"`
	FullName             *string          `json:"full_name" validate:"omitempty,max=500"`
	SCMOrganization      *string          `json:"scm_organization" validate:"omitempty,max=255"`
	CloneURL             *string          `json:"clone_url" validate:"omitempty,url"`
	WebURL               *string          `json:"web_url" validate:"omitempty,url"`
	SSHURL               *string          `json:"ssh_url" validate:"omitempty,max=500"`
	DefaultBranch        *string          `json:"default_branch" validate:"omitempty,max=100"`
	Visibility           *string          `json:"visibility" validate:"omitempty"`
	Language             *string          `json:"language" validate:"omitempty,max=50"`
	Languages            map[string]int64 `json:"languages" validate:"omitempty"`
	Topics               []string         `json:"topics" validate:"omitempty,max=50,dive,max=100"`
	Stars                *int             `json:"stars" validate:"omitempty,min=0"`
	Forks                *int             `json:"forks" validate:"omitempty,min=0"`
	Watchers             *int             `json:"watchers" validate:"omitempty,min=0"`
	OpenIssues           *int             `json:"open_issues" validate:"omitempty,min=0"`
	ContributorsCount    *int             `json:"contributors_count" validate:"omitempty,min=0"`
	SizeKB               *int             `json:"size_kb" validate:"omitempty,min=0"`
	BranchCount          *int             `json:"branch_count" validate:"omitempty,min=0"`
	ProtectedBranchCount *int             `json:"protected_branch_count" validate:"omitempty,min=0"`
	ComponentCount       *int             `json:"component_count" validate:"omitempty,min=0"`
}

UpdateRepositoryExtensionRequest represents the request to update a repository extension.

type UpdateRoleRequest

type UpdateRoleRequest struct {
	Name              *string  `json:"name" validate:"omitempty,min=2,max=100"`
	Description       *string  `json:"description" validate:"omitempty,max=500"`
	HierarchyLevel    *int     `json:"hierarchy_level" validate:"omitempty,min=0,max=100"`
	HasFullDataAccess *bool    `json:"has_full_data_access"`
	Permissions       []string `json:"permissions,omitempty" validate:"omitempty,max=200,dive,max=100"`
}

UpdateRoleRequest represents the request to update a role.

type UpdateSLAPolicyRequest

type UpdateSLAPolicyRequest struct {
	Name                *string        `json:"name" validate:"omitempty,min=1,max=100"`
	Description         *string        `json:"description" validate:"omitempty,max=500"`
	IsDefault           *bool          `json:"is_default"`
	CriticalDays        *int           `json:"critical_days" validate:"omitempty,min=1,max=365"`
	HighDays            *int           `json:"high_days" validate:"omitempty,min=1,max=365"`
	MediumDays          *int           `json:"medium_days" validate:"omitempty,min=1,max=365"`
	LowDays             *int           `json:"low_days" validate:"omitempty,min=1,max=365"`
	InfoDays            *int           `json:"info_days" validate:"omitempty,min=1,max=365"`
	WarningThresholdPct *int           `json:"warning_threshold_pct" validate:"omitempty,min=0,max=100"`
	EscalationEnabled   *bool          `json:"escalation_enabled"`
	EscalationConfig    map[string]any `json:"escalation_config"`
	IsActive            *bool          `json:"is_active"`
}

UpdateSLAPolicyRequest represents the request to update an SLA policy.

type UpdateScanProfileRequest

type UpdateScanProfileRequest struct {
	Name               string                       `json:"name" validate:"omitempty,min=1,max=100"`
	Description        string                       `json:"description" validate:"max=500"`
	ToolsConfig        map[string]ToolConfigRequest `json:"tools_config"`
	Intensity          string                       `json:"intensity" validate:"omitempty,oneof=low medium high"`
	MaxConcurrentScans int                          `json:"max_concurrent_scans" validate:"omitempty,min=1,max=100"`
	TimeoutSeconds     int                          `json:"timeout_seconds" validate:"omitempty,min=60,max=86400"`
	Tags               []string                     `json:"tags" validate:"max=20,dive,max=50"`
	QualityGate        *QualityGateRequest          `json:"quality_gate,omitempty"`
}

UpdateScanProfileRequest represents the request body for updating a scan profile.

type UpdateScanRequest

type UpdateScanRequest struct {
	Name                string         `json:"name" validate:"omitempty,min=1,max=200"`
	Description         string         `json:"description" validate:"max=1000"`
	PipelineID          string         `json:"pipeline_id" validate:"omitempty,uuid"`
	ScannerName         string         `json:"scanner_name" validate:"max=100"`
	ScannerConfig       map[string]any `json:"scanner_config"`
	TargetsPerJob       *int           `json:"targets_per_job"`
	ScheduleType        string         `json:"schedule_type" validate:"omitempty,oneof=manual daily weekly monthly crontab"`
	ScheduleCron        string         `json:"schedule_cron" validate:"max=100"`
	ScheduleDay         *int           `json:"schedule_day"`
	ScheduleTime        *string        `json:"schedule_time"`
	Timezone            string         `json:"timezone" validate:"max=50"`
	Tags                []string       `json:"tags" validate:"max=20,dive,max=50"`
	TenantRunner        *bool          `json:"run_on_tenant_runner"`
	AgentPreference     string         `json:"agent_preference" validate:"omitempty,oneof=auto tenant platform"`
	ProfileID           *string        `json:"profile_id" validate:"omitempty"`
	TimeoutSeconds      *int           `json:"timeout_seconds" validate:"omitempty,min=30,max=86400"`
	MaxRetries          *int           `json:"max_retries" validate:"omitempty,min=0,max=10"`
	RetryBackoffSeconds *int           `json:"retry_backoff_seconds" validate:"omitempty,min=10,max=86400"`
}

UpdateScanRequest represents the request body for updating a scan.

type UpdateScanScheduleRequest

type UpdateScanScheduleRequest struct {
	Name                 *string                `json:"name" validate:"omitempty,min=1,max=200"`
	Description          *string                `json:"description" validate:"omitempty,max=1000"`
	TargetScope          *string                `json:"target_scope"`
	TargetIDs            []string               `json:"target_ids" validate:"omitempty,max=100"`
	TargetTags           []string               `json:"target_tags" validate:"omitempty,max=20,dive,max=50"`
	ScannerConfigs       map[string]interface{} `json:"scanner_configs"`
	ScheduleType         *string                `json:"schedule_type"`
	CronExpression       *string                `json:"cron_expression" validate:"omitempty,max=100"`
	IntervalHours        *int                   `json:"interval_hours" validate:"omitempty,min=0,max=8760"`
	NotifyOnCompletion   *bool                  `json:"notify_on_completion"`
	NotifyOnFindings     *bool                  `json:"notify_on_findings"`
	NotificationChannels []string               `json:"notification_channels" validate:"omitempty,max=10,dive,max=50"`
}

UpdateScanScheduleRequest represents the request to update a scan schedule.

type UpdateScanSessionRequest

type UpdateScanSessionRequest struct {
	Status             string         `json:"status" validate:"required,oneof=completed failed canceled"`
	ErrorMessage       string         `json:"error_message"`
	FindingsTotal      int            `json:"findings_total"`
	FindingsNew        int            `json:"findings_new"`
	FindingsFixed      int            `json:"findings_fixed"`
	FindingsBySeverity map[string]int `json:"findings_by_severity"`
}

UpdateScanSessionRequest represents the request to update a scan session.

type UpdateScannerTemplateRequest

type UpdateScannerTemplateRequest struct {
	Name        string   `json:"name" validate:"omitempty,min=1,max=255"`
	Description string   `json:"description" validate:"max=1000"`
	Content     string   `json:"content"` // Base64 encoded, optional
	Tags        []string `json:"tags" validate:"max=20,dive,max=50"`
}

UpdateScannerTemplateRequest represents the request body for updating a template.

type UpdateScopeExclusionRequest

type UpdateScopeExclusionRequest struct {
	Reason    *string    `json:"reason" validate:"omitempty,max=1000"`
	ExpiresAt *time.Time `json:"expires_at"`
}

UpdateScopeExclusionRequest represents the request to update a scope exclusion.

type UpdateScopeTargetRequest

type UpdateScopeTargetRequest struct {
	Description *string  `json:"description" validate:"omitempty,max=1000"`
	Priority    *int     `json:"priority" validate:"omitempty,min=0,max=100"`
	Tags        []string `json:"tags" validate:"omitempty,max=20,dive,max=50"`
}

UpdateScopeTargetRequest represents the request to update a scope target.

type UpdateSecuritySettingsRequest

type UpdateSecuritySettingsRequest struct {
	SSOEnabled            bool     `json:"sso_enabled"`
	SSOProvider           string   `json:"sso_provider" validate:"omitempty,oneof=saml oidc"`
	SSOConfigURL          string   `json:"sso_config_url" validate:"omitempty,url"`
	MFARequired           bool     `json:"mfa_required"`
	SessionTimeoutMin     int      `json:"session_timeout_min" validate:"omitempty,min=15,max=480"`
	IPWhitelist           []string `json:"ip_whitelist"`
	AllowedDomains        []string `json:"allowed_domains"`
	EmailVerificationMode string   `json:"email_verification_mode" validate:"omitempty,oneof=auto always never"`
}

UpdateSecuritySettingsRequest represents the request to update security settings.

type UpdateSeverityRequest

type UpdateSeverityRequest struct {
	Severity string `json:"severity" validate:"required"`
}

UpdateSeverityRequest represents the request to update a finding's severity.

type UpdateSourceRequest

type UpdateSourceRequest struct {
	Name                string          `json:"name" validate:"omitempty,min=1,max=255"`
	Description         string          `json:"description" validate:"max=1000"`
	Config              json.RawMessage `json:"config"`
	CredentialsID       string          `json:"credentials_id" validate:"omitempty,uuid"`
	SyncEnabled         *bool           `json:"sync_enabled"`
	SyncIntervalMinutes int             `json:"sync_interval_minutes" validate:"omitempty,min=5,max=10080"`
	Priority            int             `json:"priority" validate:"omitempty,min=0,max=1000"`
	Enabled             *bool           `json:"enabled"`
}

UpdateSourceRequest represents the request body for updating a rule source.

type UpdateStepRequest

type UpdateStepRequest struct {
	Name              string                 `json:"name" validate:"omitempty,min=1,max=255"`
	Description       string                 `json:"description" validate:"max=1000"`
	Order             int                    `json:"order"`
	UIPosition        *UIPositionRequest     `json:"ui_position"`
	Tool              string                 `json:"tool" validate:"max=100"`
	Capabilities      []string               `json:"capabilities" validate:"max=10,dive,max=50"`
	Config            map[string]interface{} `json:"config"`
	TimeoutSeconds    int                    `json:"timeout_seconds"`
	DependsOn         []string               `json:"depends_on" validate:"max=20,dive,max=50"`
	Condition         *StepConditionRequest  `json:"condition"`
	MaxRetries        int                    `json:"max_retries"`
	RetryDelaySeconds int                    `json:"retry_delay_seconds"`
}

UpdateStepRequest represents the request body for updating a step.

type UpdateSuppressionRuleRequest

type UpdateSuppressionRuleRequest struct {
	Name        *string `json:"name,omitempty"`
	Description *string `json:"description,omitempty"`
	RuleID      *string `json:"rule_id,omitempty"`
	ToolName    *string `json:"tool_name,omitempty"`
	PathPattern *string `json:"path_pattern,omitempty"`
	ExpiresAt   *string `json:"expires_at,omitempty"`
}

UpdateSuppressionRuleRequest represents a request to update a suppression rule.

type UpdateTargetMappingRequest

type UpdateTargetMappingRequest struct {
	Priority    *int    `json:"priority,omitempty"`
	IsPrimary   *bool   `json:"is_primary,omitempty"` // Convenience: sets priority to 10 if true
	IsActive    *bool   `json:"is_active,omitempty"`
	Description *string `json:"description,omitempty"`
}

UpdateTargetMappingRequest represents the request to update a target mapping.

type UpdateTemplateRequest

type UpdateTemplateRequest struct {
	Name            string                   `json:"name" validate:"omitempty,min=1,max=255"`
	Description     string                   `json:"description" validate:"max=1000"`
	Triggers        []TriggerRequest         `json:"triggers" validate:"max=10,dive"`
	Settings        *PipelineSettingsRequest `json:"settings"`
	Tags            []string                 `json:"tags" validate:"max=10,dive,max=50"`
	IsActive        *bool                    `json:"is_active"`
	Steps           []CreateStepRequest      `json:"steps" validate:"max=50,dive"`
	UIStartPosition *UIPositionRequest       `json:"ui_start_position"`
	UIEndPosition   *UIPositionRequest       `json:"ui_end_position"`
}

UpdateTemplateRequest represents the request body for updating a template.

type UpdateTemplateSourceRequest

type UpdateTemplateSourceRequest struct {
	Name            string               `json:"name" validate:"omitempty,min=1,max=255"`
	Description     string               `json:"description" validate:"max=1000"`
	Enabled         *bool                `json:"enabled"`
	AutoSyncOnScan  *bool                `json:"auto_sync_on_scan"`
	CacheTTLMinutes *int                 `json:"cache_ttl_minutes" validate:"omitempty,min=0,max=10080"`
	GitConfig       *ts.GitSourceConfig  `json:"git_config,omitempty"`
	S3Config        *ts.S3SourceConfig   `json:"s3_config,omitempty"`
	HTTPConfig      *ts.HTTPSourceConfig `json:"http_config,omitempty"`
	CredentialID    *string              `json:"credential_id" validate:"omitempty,uuid"`
}

UpdateTemplateSourceRequest represents the request body for updating a template source.

type UpdateTenantModulesRequest added in v0.1.2

type UpdateTenantModulesRequest struct {
	Modules []ModuleToggleRequest `json:"modules" validate:"required,min=1,dive"`
}

UpdateTenantModulesRequest is the request body for toggling modules.

type UpdateTenantRequest

type UpdateTenantRequest struct {
	Name        *string `json:"name" validate:"omitempty,min=2,max=100"`
	Slug        *string `json:"slug" validate:"omitempty,min=3,max=100,slug"`
	Description *string `json:"description" validate:"omitempty,max=500"`
	LogoURL     *string `json:"logo_url" validate:"omitempty,url,max=500"`
}

UpdateTenantRequest represents the request to update a tenant.

type UpdateToolCategoryRequest

type UpdateToolCategoryRequest struct {
	DisplayName string `json:"display_name" validate:"required,max=100"`
	Description string `json:"description" validate:"max=500"`
	Icon        string `json:"icon" validate:"max=50"`
	Color       string `json:"color" validate:"max=20"`
}

UpdateToolCategoryRequest represents the request body for updating a category.

type UpdateToolRequest

type UpdateToolRequest struct {
	DisplayName      string         `json:"display_name" validate:"max=100"`
	Description      string         `json:"description" validate:"max=1000"`
	CategoryID       string         `json:"category_id" validate:"omitempty,uuid"` // Optional: link to tool_categories table
	InstallCmd       string         `json:"install_cmd" validate:"max=500"`
	UpdateCmd        string         `json:"update_cmd" validate:"max=500"`
	VersionCmd       string         `json:"version_cmd" validate:"max=500"`
	VersionRegex     string         `json:"version_regex" validate:"max=200"`
	ConfigSchema     map[string]any `json:"config_schema"`
	DefaultConfig    map[string]any `json:"default_config"`
	Capabilities     []string       `json:"capabilities" validate:"max=20,dive,max=50"`
	SupportedTargets []string       `json:"supported_targets" validate:"max=10,dive,max=50"`
	OutputFormats    []string       `json:"output_formats" validate:"max=10,dive,max=20"`
	DocsURL          string         `json:"docs_url" validate:"omitempty,url,max=500"`
	GithubURL        string         `json:"github_url" validate:"omitempty,url,max=500"`
	LogoURL          string         `json:"logo_url" validate:"omitempty,url,max=500"`
	Tags             []string       `json:"tags" validate:"max=20,dive,max=50"`
}

UpdateToolRequest represents the request body for updating a tool.

type UpdateVulnerabilityRequest

type UpdateVulnerabilityRequest struct {
	Title            *string  `json:"title" validate:"omitempty,min=1,max=500"`
	Description      *string  `json:"description" validate:"omitempty,max=10000"`
	Severity         *string  `json:"severity" validate:"omitempty"`
	CVSSScore        *float64 `json:"cvss_score" validate:"omitempty,min=0,max=10"`
	CVSSVector       *string  `json:"cvss_vector" validate:"omitempty,max=100"`
	EPSSScore        *float64 `json:"epss_score" validate:"omitempty,min=0,max=1"`
	EPSSPercentile   *float64 `json:"epss_percentile" validate:"omitempty,min=0,max=1"`
	ExploitAvailable *bool    `json:"exploit_available"`
	ExploitMaturity  *string  `json:"exploit_maturity" validate:"omitempty"`
	FixedVersions    []string `json:"fixed_versions" validate:"omitempty,max=50,dive,max=100"`
	Remediation      *string  `json:"remediation" validate:"omitempty,max=5000"`
	Status           *string  `json:"status" validate:"omitempty"`
}

UpdateVulnerabilityRequest represents the request to update a vulnerability.

type UpdateWebhookRequest

type UpdateWebhookRequest struct {
	Name              *string  `json:"name" validate:"omitempty,min=1,max=255"`
	Description       *string  `json:"description" validate:"omitempty,max=1000"`
	URL               *string  `json:"url" validate:"omitempty,url,max=1000"`
	Secret            *string  `json:"secret" validate:"omitempty,max=500"`
	EventTypes        []string `json:"event_types" validate:"omitempty,min=1,max=20"`
	SeverityThreshold *string  `json:"severity_threshold" validate:"omitempty,oneof=critical high medium low info"`
	MaxRetries        *int     `json:"max_retries" validate:"omitempty,min=0,max=10"`
	RetryInterval     *int     `json:"retry_interval_seconds" validate:"omitempty,min=0,max=3600"`
}

UpdateWebhookRequest represents the request to update a webhook.

type UpdateWorkflowGraphRequest

type UpdateWorkflowGraphRequest struct {
	Name        *string             `json:"name" validate:"omitempty,min=1,max=255"`
	Description *string             `json:"description" validate:"omitempty,max=1000"`
	Tags        []string            `json:"tags" validate:"max=10,dive,max=50"`
	Nodes       []NodeRequest       `json:"nodes" validate:"min=1,max=50,dive"`
	Edges       []CreateEdgeRequest `json:"edges" validate:"max=100,dive"`
}

UpdateWorkflowGraphRequest represents the request body for updating a workflow's graph.

type UpdateWorkflowRequest

type UpdateWorkflowRequest struct {
	Name        *string  `json:"name" validate:"omitempty,min=1,max=255"`
	Description *string  `json:"description" validate:"omitempty,max=1000"`
	Tags        []string `json:"tags" validate:"max=10,dive,max=50"`
	IsActive    *bool    `json:"is_active"`
}

UpdateWorkflowRequest represents the request body for updating a workflow.

type UserHandler

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

UserHandler handles user-related HTTP requests.

func NewUserHandler

func NewUserHandler(svc *app.UserService, tenantSvc *app.TenantService, v *validator.Validator, log *logger.Logger) *UserHandler

NewUserHandler creates a new user handler.

func (*UserHandler) GetMe

func (h *UserHandler) GetMe(w http.ResponseWriter, r *http.Request)

GetMe returns the current authenticated user's profile. @Summary Get current user profile @Description Returns the profile of the authenticated user @Tags Users @Produce json @Security BearerAuth @Success 200 {object} UserResponse @Failure 401 {object} map[string]string @Router /users/me [get]

func (*UserHandler) GetMyTenants

func (h *UserHandler) GetMyTenants(w http.ResponseWriter, r *http.Request)

GetMyTenants returns all tenants the current user belongs to. @Summary Get user's tenants @Description Returns all tenants the current user belongs to @Tags Users @Produce json @Security BearerAuth @Success 200 {array} TenantMembershipResponse @Failure 401 {object} map[string]string @Failure 500 {object} map[string]string @Router /users/me/tenants [get]

func (*UserHandler) GetPreferences added in v0.1.2

func (h *UserHandler) GetPreferences(w http.ResponseWriter, r *http.Request)

GetPreferences returns the current authenticated user's preferences. @Summary Get user preferences @Description Returns the preferences of the authenticated user @Tags Users @Produce json @Security BearerAuth @Success 200 {object} PreferencesDTO @Failure 401 {object} map[string]string @Router /users/me/preferences [get]

func (*UserHandler) UpdateMe

func (h *UserHandler) UpdateMe(w http.ResponseWriter, r *http.Request)

UpdateMe updates the current authenticated user's profile. @Summary Update current user profile @Description Updates the profile of the authenticated user @Tags Users @Accept json @Produce json @Security BearerAuth @Param request body UpdateProfileRequest true "Profile data" @Success 200 {object} UserResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /users/me [put]

func (*UserHandler) UpdatePreferences

func (h *UserHandler) UpdatePreferences(w http.ResponseWriter, r *http.Request)

UpdatePreferences updates the current authenticated user's preferences. @Summary Update user preferences @Description Updates the preferences of the authenticated user @Tags Users @Accept json @Produce json @Security BearerAuth @Param request body UpdatePreferencesRequest true "Preferences data" @Success 200 {object} UserResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /users/me/preferences [put]

type UserInfo

type UserInfo struct {
	ID    string `json:"id"`
	Email string `json:"email"`
	Name  string `json:"name"`
}

UserInfo contains basic user information.

type UserResponse

type UserResponse struct {
	ID          string         `json:"id"`
	Email       string         `json:"email"`
	Name        string         `json:"name"`
	AvatarURL   string         `json:"avatar_url,omitempty"`
	Phone       string         `json:"phone,omitempty"`
	Status      string         `json:"status"`
	Preferences PreferencesDTO `json:"preferences"`
	LastLoginAt *time.Time     `json:"last_login_at,omitempty"`
	CreatedAt   time.Time      `json:"created_at"`
	UpdatedAt   time.Time      `json:"updated_at"`
}

UserResponse represents a user in API responses.

type UserRoleResponse

type UserRoleResponse struct {
	ID         string       `json:"id"`
	UserID     string       `json:"user_id"`
	TenantID   string       `json:"tenant_id"`
	RoleID     string       `json:"role_id"`
	Role       RoleResponse `json:"role"`
	AssignedAt time.Time    `json:"assigned_at"`
	AssignedBy *string      `json:"assigned_by,omitempty"`

	// User details
	Name      string `json:"name,omitempty"`
	Email     string `json:"email,omitempty"`
	AvatarURL string `json:"avatar_url,omitempty"`
}

UserRoleResponse represents a user's role assignment.

type ValidateResponse

type ValidateResponse struct {
	ID    string `json:"id"`
	Email string `json:"email"`
	Name  string `json:"name"`
	Role  string `json:"role"`
}

ValidateResponse represents the response for API key validation.

type ValidateScannerTemplateRequest

type ValidateScannerTemplateRequest struct {
	TemplateType string `json:"template_type" validate:"required,oneof=nuclei semgrep gitleaks"`
	Content      string `json:"content" validate:"required"` // Base64 encoded
}

ValidateScannerTemplateRequest represents the request body for validating template content.

type ValidationErrorResponse

type ValidationErrorResponse struct {
	Field   string `json:"field"`
	Message string `json:"message"`
	Code    string `json:"code"`
}

ValidationErrorResponse represents a single validation error.

type ValidationResultResponse

type ValidationResultResponse struct {
	Valid     bool                      `json:"valid"`
	Errors    []ValidationErrorResponse `json:"errors,omitempty"`
	RuleCount int                       `json:"rule_count"`
	Metadata  map[string]any            `json:"metadata,omitempty"`
}

ValidationResultResponse represents the response for template validation.

type VerifyEmailRequest

type VerifyEmailRequest struct {
	Token string `json:"token" validate:"required"`
}

VerifyEmailRequest is the request body for email verification.

type VerifyFindingRequest

type VerifyFindingRequest struct {
	Notes string `json:"notes" validate:"max=1000"`
}

VerifyFindingRequest represents the request to verify a finding fix.

type VerifyRequest added in v0.1.3

type VerifyRequest struct {
	FindingIDs []string              `json:"finding_ids" validate:"max=100,dive,uuid"` // verify specific findings
	Filter     *FindingFilterRequest `json:"filter"`                                   // verify all matching filter
	Note       string                `json:"note" validate:"max=5000"`
}

VerifyRequest supports both finding_ids and filter. At least one must be provided.

type VulnerabilityHandler

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

VulnerabilityHandler handles vulnerability and finding HTTP requests.

func NewVulnerabilityHandler

func NewVulnerabilityHandler(svc *app.VulnerabilityService, v *validator.Validator, log *logger.Logger) *VulnerabilityHandler

NewVulnerabilityHandler creates a new vulnerability handler.

func (*VulnerabilityHandler) AddComment

func (h *VulnerabilityHandler) AddComment(w http.ResponseWriter, r *http.Request)

AddComment handles POST /api/v1/findings/{id}/comments

func (*VulnerabilityHandler) ApproveApproval added in v0.1.2

func (h *VulnerabilityHandler) ApproveApproval(w http.ResponseWriter, r *http.Request)

ApproveApproval handles POST /approvals/{id}/approve.

func (*VulnerabilityHandler) AssignFinding

func (h *VulnerabilityHandler) AssignFinding(w http.ResponseWriter, r *http.Request)

AssignFinding handles POST /api/v1/findings/{id}/assign @Summary Assign finding @Description Assigns a finding to a user @Tags Findings @Accept json @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Param request body AssignFindingRequest true "Assignment data" @Success 200 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id}/assign [post]

func (*VulnerabilityHandler) BulkAssignFindings

func (h *VulnerabilityHandler) BulkAssignFindings(w http.ResponseWriter, r *http.Request)

BulkAssignFindings handles POST /api/v1/findings/bulk/assign @Summary Bulk assign findings @Description Assigns multiple findings to a user @Tags Findings @Accept json @Produce json @Security BearerAuth @Param request body BulkAssignRequest true "Bulk assign data" @Success 200 {object} BulkUpdateResponse @Failure 400 {object} map[string]string @Router /findings/bulk/assign [post]

func (*VulnerabilityHandler) BulkUpdateFindingsStatus

func (h *VulnerabilityHandler) BulkUpdateFindingsStatus(w http.ResponseWriter, r *http.Request)

BulkUpdateFindingsStatus handles POST /api/v1/findings/bulk/status @Summary Bulk update finding status @Description Updates the status of multiple findings @Tags Findings @Accept json @Produce json @Security BearerAuth @Param request body BulkUpdateStatusRequest true "Bulk update data" @Success 200 {object} BulkUpdateResponse @Failure 400 {object} map[string]string @Router /findings/bulk/status [post]

func (*VulnerabilityHandler) CancelApproval added in v0.1.2

func (h *VulnerabilityHandler) CancelApproval(w http.ResponseWriter, r *http.Request)

CancelApproval handles POST /approvals/{id}/cancel.

func (*VulnerabilityHandler) ClassifyFinding

func (h *VulnerabilityHandler) ClassifyFinding(w http.ResponseWriter, r *http.Request)

ClassifyFinding handles PATCH /api/v1/findings/{id}/classify @Summary Classify finding @Description Sets CVE, CWE, and CVSS classification for a finding @Tags Findings @Accept json @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Param request body ClassifyFindingRequest true "Classification data" @Success 200 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id}/classify [patch]

func (*VulnerabilityHandler) CreateFinding

func (h *VulnerabilityHandler) CreateFinding(w http.ResponseWriter, r *http.Request)

CreateFinding handles POST /api/v1/findings @Summary Create finding @Description Creates a new finding for the current tenant @Tags Findings @Accept json @Produce json @Security BearerAuth @Param request body CreateFindingRequest true "Finding data" @Success 201 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /findings [post]

func (*VulnerabilityHandler) CreateVulnerability

func (h *VulnerabilityHandler) CreateVulnerability(w http.ResponseWriter, r *http.Request)

CreateVulnerability handles POST /api/v1/vulnerabilities @Summary Create vulnerability @Description Creates a new CVE vulnerability record @Tags Vulnerabilities @Accept json @Produce json @Param request body CreateVulnerabilityRequest true "Vulnerability data" @Success 201 {object} VulnerabilityResponse @Failure 400 {object} map[string]string @Failure 409 {object} map[string]string @Router /vulnerabilities [post]

func (*VulnerabilityHandler) DeleteComment

func (h *VulnerabilityHandler) DeleteComment(w http.ResponseWriter, r *http.Request)

DeleteComment handles DELETE /api/v1/findings/{findingId}/comments/{commentId}

func (*VulnerabilityHandler) DeleteFinding

func (h *VulnerabilityHandler) DeleteFinding(w http.ResponseWriter, r *http.Request)

DeleteFinding handles DELETE /api/v1/findings/{id} @Summary Delete finding @Description Deletes a finding @Tags Findings @Security BearerAuth @Param id path string true "Finding ID" @Success 204 "No Content" @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id} [delete]

func (*VulnerabilityHandler) DeleteVulnerability

func (h *VulnerabilityHandler) DeleteVulnerability(w http.ResponseWriter, r *http.Request)

DeleteVulnerability handles DELETE /api/v1/vulnerabilities/{id} @Summary Delete vulnerability @Description Deletes a vulnerability @Tags Vulnerabilities @Param id path string true "Vulnerability ID" @Success 204 "No Content" @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /vulnerabilities/{id} [delete]

func (*VulnerabilityHandler) GetFinding

func (h *VulnerabilityHandler) GetFinding(w http.ResponseWriter, r *http.Request)

GetFinding handles GET /api/v1/findings/{id} @Summary Get finding @Description Retrieves a finding by ID @Tags Findings @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Success 200 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id} [get]

func (*VulnerabilityHandler) GetFindingDataFlows

func (h *VulnerabilityHandler) GetFindingDataFlows(w http.ResponseWriter, r *http.Request)

GetFindingDataFlows handles GET /api/v1/findings/{id}/dataflows @Summary Get finding data flows @Description Returns the data flow traces (attack paths) for a finding @Tags Findings @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Success 200 {object} DataFlowResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id}/dataflows [get]

func (*VulnerabilityHandler) GetFindingStats

func (h *VulnerabilityHandler) GetFindingStats(w http.ResponseWriter, r *http.Request)

GetFindingStats handles GET /api/v1/findings/stats @Summary Get finding statistics @Description Returns aggregated statistics for findings. Optional asset_id query @Description parameter scopes the stats to a single asset (used by the Findings @Description page when filtered by `?assetId=…` so the severity cards match the @Description filtered table instead of showing global tenant counts). @Tags Findings @Produce json @Security BearerAuth @Param asset_id query string false "Restrict stats to a single asset" @Success 200 {object} FindingStatsResponse @Failure 401 {object} map[string]string @Failure 500 {object} map[string]string @Router /findings/stats [get]

func (*VulnerabilityHandler) GetVulnerability

func (h *VulnerabilityHandler) GetVulnerability(w http.ResponseWriter, r *http.Request)

GetVulnerability handles GET /api/v1/vulnerabilities/{id} @Summary Get vulnerability @Description Retrieves a vulnerability by ID @Tags Vulnerabilities @Produce json @Param id path string true "Vulnerability ID" @Success 200 {object} VulnerabilityResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /vulnerabilities/{id} [get]

func (*VulnerabilityHandler) GetVulnerabilityByCVE

func (h *VulnerabilityHandler) GetVulnerabilityByCVE(w http.ResponseWriter, r *http.Request)

GetVulnerabilityByCVE handles GET /api/v1/vulnerabilities/cve/{cve_id} @Summary Get vulnerability by CVE ID @Description Retrieves a vulnerability by CVE ID @Tags Vulnerabilities @Produce json @Param cve_id path string true "CVE ID" @Success 200 {object} VulnerabilityResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /vulnerabilities/cve/{cve_id} [get]

func (*VulnerabilityHandler) ListAssetFindings

func (h *VulnerabilityHandler) ListAssetFindings(w http.ResponseWriter, r *http.Request)

ListAssetFindings handles GET /api/v1/assets/{id}/findings @Summary List asset findings @Description Retrieves all findings for an asset @Tags Findings @Produce json @Security BearerAuth @Param id path string true "Asset ID" @Param sort query string false "Sort field" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} map[string]interface{} @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /assets/{id}/findings [get]

func (*VulnerabilityHandler) ListComments

func (h *VulnerabilityHandler) ListComments(w http.ResponseWriter, r *http.Request)

ListComments handles GET /api/v1/findings/{id}/comments

func (*VulnerabilityHandler) ListFindingApprovals added in v0.1.2

func (h *VulnerabilityHandler) ListFindingApprovals(w http.ResponseWriter, r *http.Request)

ListFindingApprovals handles GET /findings/{id}/approvals.

func (*VulnerabilityHandler) ListFindings

func (h *VulnerabilityHandler) ListFindings(w http.ResponseWriter, r *http.Request)

ListFindings handles GET /api/v1/findings @Summary List findings @Description Retrieves a paginated list of findings for the current tenant @Tags Findings @Produce json @Security BearerAuth @Param asset_id query string false "Filter by asset ID" @Param branch_id query string false "Filter by branch ID" @Param component_id query string false "Filter by component ID" @Param vulnerability_id query string false "Filter by vulnerability ID" @Param severities query string false "Filter by severities (comma-separated)" @Param statuses query string false "Filter by statuses (comma-separated)" @Param exclude_statuses query string false "Exclude statuses (comma-separated)" @Param sources query string false "Filter by sources" @Param tool_name query string false "Filter by tool name" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} map[string]interface{} @Failure 400 {object} map[string]string @Failure 401 {object} map[string]string @Router /findings [get]

func (*VulnerabilityHandler) ListPendingApprovals added in v0.1.2

func (h *VulnerabilityHandler) ListPendingApprovals(w http.ResponseWriter, r *http.Request)

ListPendingApprovals handles GET /approvals?status=pending.

func (*VulnerabilityHandler) ListVulnerabilities

func (h *VulnerabilityHandler) ListVulnerabilities(w http.ResponseWriter, r *http.Request)

ListVulnerabilities handles GET /api/v1/vulnerabilities @Summary List vulnerabilities @Description Retrieves a paginated list of CVE vulnerabilities @Tags Vulnerabilities @Produce json @Param cve_ids query string false "Filter by CVE IDs (comma-separated)" @Param severities query string false "Filter by severities (comma-separated)" @Param min_cvss query number false "Minimum CVSS score" @Param max_cvss query number false "Maximum CVSS score" @Param min_epss query number false "Minimum EPSS score" @Param exploit_available query bool false "Filter by exploit availability" @Param cisa_kev_only query bool false "Only CISA KEV vulnerabilities" @Param statuses query string false "Filter by statuses" @Param page query int false "Page number" default(1) @Param per_page query int false "Items per page" default(20) @Success 200 {object} map[string]interface{} @Failure 400 {object} map[string]string @Router /vulnerabilities [get]

func (*VulnerabilityHandler) RejectApproval added in v0.1.2

func (h *VulnerabilityHandler) RejectApproval(w http.ResponseWriter, r *http.Request)

RejectApproval handles POST /approvals/{id}/reject.

func (*VulnerabilityHandler) RequestApproval added in v0.1.2

func (h *VulnerabilityHandler) RequestApproval(w http.ResponseWriter, r *http.Request)

RequestApproval handles POST /findings/{id}/approvals.

func (*VulnerabilityHandler) SetAssetService

func (h *VulnerabilityHandler) SetAssetService(svc *app.AssetService)

SetAssetService sets the asset service for fetching asset info.

func (*VulnerabilityHandler) SetFindingTags

func (h *VulnerabilityHandler) SetFindingTags(w http.ResponseWriter, r *http.Request)

SetFindingTags handles PUT /api/v1/findings/{id}/tags @Summary Set finding tags @Description Sets the tags for a finding @Tags Findings @Accept json @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Param request body SetTagsRequest true "Tags data" @Success 200 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id}/tags [put]

func (*VulnerabilityHandler) SetUserService

func (h *VulnerabilityHandler) SetUserService(svc *app.UserService)

SetUserService sets the user service for fetching assigned user info.

func (*VulnerabilityHandler) TriageFinding

func (h *VulnerabilityHandler) TriageFinding(w http.ResponseWriter, r *http.Request)

TriageFinding handles PATCH /api/v1/findings/{id}/triage @Summary Triage finding @Description Sets the triage status of a finding @Tags Findings @Accept json @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Param request body TriageFindingRequest true "Triage data" @Success 200 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id}/triage [patch]

func (*VulnerabilityHandler) UnassignFinding

func (h *VulnerabilityHandler) UnassignFinding(w http.ResponseWriter, r *http.Request)

UnassignFinding handles POST /api/v1/findings/{id}/unassign @Summary Unassign finding @Description Removes assignment from a finding @Tags Findings @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Success 200 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id}/unassign [post]

func (*VulnerabilityHandler) UpdateComment

func (h *VulnerabilityHandler) UpdateComment(w http.ResponseWriter, r *http.Request)

UpdateComment handles PUT /api/v1/findings/{findingId}/comments/{commentId}

func (*VulnerabilityHandler) UpdateFindingSeverity

func (h *VulnerabilityHandler) UpdateFindingSeverity(w http.ResponseWriter, r *http.Request)

UpdateFindingSeverity handles PATCH /api/v1/findings/{id}/severity @Summary Update finding severity @Description Updates the severity level of a finding @Tags Findings @Accept json @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Param request body UpdateSeverityRequest true "Severity data" @Success 200 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id}/severity [patch]

func (*VulnerabilityHandler) UpdateFindingStatus

func (h *VulnerabilityHandler) UpdateFindingStatus(w http.ResponseWriter, r *http.Request)

UpdateFindingStatus handles PATCH /api/v1/findings/{id}/status @Summary Update finding status @Description Updates the status of a finding @Tags Findings @Accept json @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Param request body UpdateFindingStatusRequest true "Status data" @Success 200 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id}/status [patch]

func (*VulnerabilityHandler) UpdateVulnerability

func (h *VulnerabilityHandler) UpdateVulnerability(w http.ResponseWriter, r *http.Request)

UpdateVulnerability handles PUT /api/v1/vulnerabilities/{id} @Summary Update vulnerability @Description Updates a vulnerability @Tags Vulnerabilities @Accept json @Produce json @Param id path string true "Vulnerability ID" @Param request body UpdateVulnerabilityRequest true "Vulnerability data" @Success 200 {object} VulnerabilityResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /vulnerabilities/{id} [put]

func (*VulnerabilityHandler) VerifyFinding

func (h *VulnerabilityHandler) VerifyFinding(w http.ResponseWriter, r *http.Request)

VerifyFinding handles POST /api/v1/findings/{id}/verify @Summary Verify finding fix @Description Marks a resolved finding as verified @Tags Findings @Accept json @Produce json @Security BearerAuth @Param id path string true "Finding ID" @Success 200 {object} FindingResponse @Failure 400 {object} map[string]string @Failure 404 {object} map[string]string @Router /findings/{id}/verify [post]

type VulnerabilityResponse

type VulnerabilityResponse struct {
	ID               string                    `json:"id"`
	CVEID            string                    `json:"cve_id"`
	Aliases          []string                  `json:"aliases,omitempty"`
	Title            string                    `json:"title"`
	Description      string                    `json:"description,omitempty"`
	Severity         string                    `json:"severity"`
	CVSSScore        *float64                  `json:"cvss_score,omitempty"`
	CVSSVector       string                    `json:"cvss_vector,omitempty"`
	EPSSScore        *float64                  `json:"epss_score,omitempty"`
	EPSSPercentile   *float64                  `json:"epss_percentile,omitempty"`
	CISAKEV          *CISAKEVResponse          `json:"cisa_kev,omitempty"`
	ExploitAvailable bool                      `json:"exploit_available"`
	ExploitMaturity  string                    `json:"exploit_maturity"`
	References       []ReferenceResponse       `json:"references,omitempty"`
	AffectedVersions []AffectedVersionResponse `json:"affected_versions,omitempty"`
	FixedVersions    []string                  `json:"fixed_versions,omitempty"`
	Remediation      string                    `json:"remediation,omitempty"`
	PublishedAt      *time.Time                `json:"published_at,omitempty"`
	ModifiedAt       *time.Time                `json:"modified_at,omitempty"`
	Status           string                    `json:"status"`
	RiskScore        float64                   `json:"risk_score"`
	CreatedAt        time.Time                 `json:"created_at"`
	UpdatedAt        time.Time                 `json:"updated_at"`
}

VulnerabilityResponse represents a vulnerability in API responses.

type WSTokenResponse

type WSTokenResponse struct {
	Token     string `json:"token"`
	ExpiresIn int64  `json:"expires_in"` // Seconds until expiration
}

WSTokenResponse is the response body for WebSocket token.

type WebhookHandler

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

WebhookHandler handles HTTP requests for webhook management.

func NewWebhookHandler

func NewWebhookHandler(svc *app.WebhookService, v *validator.Validator, log *logger.Logger) *WebhookHandler

NewWebhookHandler creates a new WebhookHandler.

func (*WebhookHandler) Create

func (h *WebhookHandler) Create(w http.ResponseWriter, r *http.Request)

Create handles POST /api/v1/webhooks

func (*WebhookHandler) Delete

func (h *WebhookHandler) Delete(w http.ResponseWriter, r *http.Request)

Delete handles DELETE /api/v1/webhooks/{id}

func (*WebhookHandler) Disable

func (h *WebhookHandler) Disable(w http.ResponseWriter, r *http.Request)

Disable handles POST /api/v1/webhooks/{id}/disable

func (*WebhookHandler) Enable

func (h *WebhookHandler) Enable(w http.ResponseWriter, r *http.Request)

Enable handles POST /api/v1/webhooks/{id}/enable

func (*WebhookHandler) Get

Get handles GET /api/v1/webhooks/{id}

func (*WebhookHandler) List

List handles GET /api/v1/webhooks

func (*WebhookHandler) ListDeliveries

func (h *WebhookHandler) ListDeliveries(w http.ResponseWriter, r *http.Request)

ListDeliveries handles GET /api/v1/webhooks/{id}/deliveries

func (*WebhookHandler) Update

func (h *WebhookHandler) Update(w http.ResponseWriter, r *http.Request)

Update handles PUT /api/v1/webhooks/{id}

type WebhookResponse

type WebhookResponse struct {
	ID                   string     `json:"id"`
	TenantID             string     `json:"tenant_id"`
	Name                 string     `json:"name"`
	Description          string     `json:"description,omitempty"`
	URL                  string     `json:"url"`
	HasSecret            bool       `json:"has_secret"`
	EventTypes           []string   `json:"event_types"`
	SeverityThreshold    string     `json:"severity_threshold"`
	Status               string     `json:"status"`
	MaxRetries           int        `json:"max_retries"`
	RetryIntervalSeconds int        `json:"retry_interval_seconds"`
	TotalSent            int        `json:"total_sent"`
	TotalFailed          int        `json:"total_failed"`
	LastSentAt           *time.Time `json:"last_sent_at,omitempty"`
	LastError            string     `json:"last_error,omitempty"`
	LastErrorAt          *time.Time `json:"last_error_at,omitempty"`
	CreatedBy            string     `json:"created_by,omitempty"`
	CreatedAt            time.Time  `json:"created_at"`
	UpdatedAt            time.Time  `json:"updated_at"`
}

WebhookResponse represents a webhook in the response.

type WorkflowHandler

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

WorkflowHandler handles HTTP requests for workflows.

func NewWorkflowHandler

func NewWorkflowHandler(service *app.WorkflowService, v *validator.Validator, log *logger.Logger) *WorkflowHandler

NewWorkflowHandler creates a new WorkflowHandler.

func (*WorkflowHandler) AddEdge

func (h *WorkflowHandler) AddEdge(w http.ResponseWriter, r *http.Request)

AddEdge handles POST /api/v1/workflows/{id}/edges

func (*WorkflowHandler) AddNode

func (h *WorkflowHandler) AddNode(w http.ResponseWriter, r *http.Request)

AddNode handles POST /api/v1/workflows/{id}/nodes

func (*WorkflowHandler) CancelRun

func (h *WorkflowHandler) CancelRun(w http.ResponseWriter, r *http.Request)

CancelRun handles POST /api/v1/workflow-runs/{id}/cancel

func (*WorkflowHandler) CreateWorkflow

func (h *WorkflowHandler) CreateWorkflow(w http.ResponseWriter, r *http.Request)

CreateWorkflow handles POST /api/v1/workflows

func (*WorkflowHandler) DeleteEdge

func (h *WorkflowHandler) DeleteEdge(w http.ResponseWriter, r *http.Request)

DeleteEdge handles DELETE /api/v1/workflows/{id}/edges/{edgeId}

func (*WorkflowHandler) DeleteNode

func (h *WorkflowHandler) DeleteNode(w http.ResponseWriter, r *http.Request)

DeleteNode handles DELETE /api/v1/workflows/{id}/nodes/{nodeId}

func (*WorkflowHandler) DeleteWorkflow

func (h *WorkflowHandler) DeleteWorkflow(w http.ResponseWriter, r *http.Request)

DeleteWorkflow handles DELETE /api/v1/workflows/{id}

func (*WorkflowHandler) GetRun

func (h *WorkflowHandler) GetRun(w http.ResponseWriter, r *http.Request)

GetRun handles GET /api/v1/workflow-runs/{id}

func (*WorkflowHandler) GetWorkflow

func (h *WorkflowHandler) GetWorkflow(w http.ResponseWriter, r *http.Request)

GetWorkflow handles GET /api/v1/workflows/{id}

func (*WorkflowHandler) ListRuns

func (h *WorkflowHandler) ListRuns(w http.ResponseWriter, r *http.Request)

ListRuns handles GET /api/v1/workflow-runs

func (*WorkflowHandler) ListWorkflows

func (h *WorkflowHandler) ListWorkflows(w http.ResponseWriter, r *http.Request)

ListWorkflows handles GET /api/v1/workflows

func (*WorkflowHandler) TriggerWorkflow

func (h *WorkflowHandler) TriggerWorkflow(w http.ResponseWriter, r *http.Request)

TriggerWorkflow handles POST /api/v1/workflows/{id}/runs

func (*WorkflowHandler) UpdateNode

func (h *WorkflowHandler) UpdateNode(w http.ResponseWriter, r *http.Request)

UpdateNode handles PUT /api/v1/workflows/{id}/nodes/{nodeId}

func (*WorkflowHandler) UpdateWorkflow

func (h *WorkflowHandler) UpdateWorkflow(w http.ResponseWriter, r *http.Request)

UpdateWorkflow handles PUT /api/v1/workflows/{id}

func (*WorkflowHandler) UpdateWorkflowGraph

func (h *WorkflowHandler) UpdateWorkflowGraph(w http.ResponseWriter, r *http.Request)

UpdateWorkflowGraph handles PUT /api/v1/workflows/{id}/graph This endpoint atomically replaces the entire workflow graph (nodes and edges).

type WorkflowResponse

type WorkflowResponse struct {
	ID             string         `json:"id"`
	TenantID       string         `json:"tenant_id"`
	Name           string         `json:"name"`
	Description    string         `json:"description,omitempty"`
	IsActive       bool           `json:"is_active"`
	Tags           []string       `json:"tags,omitempty"`
	Nodes          []NodeResponse `json:"nodes,omitempty"`
	Edges          []EdgeResponse `json:"edges,omitempty"`
	TotalRuns      int            `json:"total_runs"`
	SuccessfulRuns int            `json:"successful_runs"`
	FailedRuns     int            `json:"failed_runs"`
	LastRunID      *string        `json:"last_run_id,omitempty"`
	LastRunAt      *string        `json:"last_run_at,omitempty"`
	LastRunStatus  string         `json:"last_run_status,omitempty"`
	CreatedBy      *string        `json:"created_by,omitempty"`
	CreatedAt      string         `json:"created_at"`
	UpdatedAt      string         `json:"updated_at"`
}

WorkflowResponse represents the response for a workflow.

type WorkflowRunResponse

type WorkflowRunResponse struct {
	ID             string            `json:"id"`
	WorkflowID     string            `json:"workflow_id"`
	TenantID       string            `json:"tenant_id"`
	TriggerType    string            `json:"trigger_type"`
	TriggerData    map[string]any    `json:"trigger_data,omitempty"`
	Status         string            `json:"status"`
	StartedAt      *string           `json:"started_at,omitempty"`
	CompletedAt    *string           `json:"completed_at,omitempty"`
	TotalNodes     int               `json:"total_nodes"`
	CompletedNodes int               `json:"completed_nodes"`
	FailedNodes    int               `json:"failed_nodes"`
	TriggeredBy    *string           `json:"triggered_by,omitempty"`
	ErrorMessage   string            `json:"error_message,omitempty"`
	NodeRuns       []NodeRunResponse `json:"node_runs,omitempty"`
	CreatedAt      string            `json:"created_at"`
}

WorkflowRunResponse represents the response for a workflow run.

type WorkflowUIPositionRequest

type WorkflowUIPositionRequest struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

WorkflowUIPositionRequest represents a visual position in the workflow builder.

type WorkflowUIPositionResponse

type WorkflowUIPositionResponse struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

WorkflowUIPositionResponse represents a visual position in the response.

Jump to

Keyboard shortcuts

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