server

package
v0.11.6 Latest Latest
Warning

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

Go to latest
Published: Apr 10, 2026 License: AGPL-3.0 Imports: 29 Imported by: 0

Documentation

Overview

Package server implements the HTTP proxy server that sits between Claude Code and the Anthropic API.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CAManager added in v0.6.0

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

CAManager manages the proxy's root CA certificate and generates per-host TLS certificates for MITM interception of HTTPS CONNECT tunnels.

func NewCAManager added in v0.6.0

func NewCAManager(baseDir string) *CAManager

NewCAManager creates a CAManager that stores CA files under baseDir.

func (*CAManager) CACertPath added in v0.6.0

func (m *CAManager) CACertPath() string

CACertPath returns the path to the CA certificate PEM file.

func (*CAManager) EnsureCA added in v0.6.0

func (m *CAManager) EnsureCA() error

EnsureCA loads the CA from disk if it exists, or generates a new one and saves it. The cert is written to <baseDir>/ca.pem and the key to <baseDir>/ca-key.pem (permissions 0600).

func (*CAManager) GenerateHostCert added in v0.6.0

func (m *CAManager) GenerateHostCert(hostname string) (*tls.Certificate, error)

GenerateHostCert returns a TLS certificate for hostname signed by the CA. Results are cached in-memory keyed by hostname.

func (*CAManager) GetTLSConfig added in v0.6.0

func (m *CAManager) GetTLSConfig(hostname string) (*tls.Config, error)

GetTLSConfig returns a *tls.Config with a certificate for hostname, suitable for use in tls.Server().

type ConnectHandler added in v0.6.0

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

ConnectHandler handles HTTP CONNECT requests. For known AI API hosts it performs TLS MITM to inspect and optionally modify streamed responses. For all other hosts it proxies raw TCP bidirectionally.

func NewConnectHandler added in v0.6.0

func NewConnectHandler(
	caManager *CAManager,
	engine *trap.Engine,
	selector *trap.Selector,
	callbackHandler *trap.CallbackHandler,
	apiClient *client.Client,
	logger *slog.Logger,
) *ConnectHandler

NewConnectHandler creates a ConnectHandler with the given dependencies.

func (*ConnectHandler) HandleConnect added in v0.6.0

func (ch *ConnectHandler) HandleConnect(w http.ResponseWriter, r *http.Request)

HandleConnect processes an HTTP CONNECT request. It hijacks the connection, replies with "200 Connection Established", then either performs TLS MITM (for AI API hosts) or plain TCP tunnel (for everything else).

type ContentBlockState

type ContentBlockState struct {
	Index          int
	IsToolUse      bool
	ToolName       string
	ToolID         string
	BufferedEvents []SSEEvent
	PartialJSON    strings.Builder
}

ContentBlockState tracks the state of a single content block being streamed.

type HookHandler

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

HookHandler handles PreToolUse hook requests from Claude Code and Copilot.

func NewHookHandler

func NewHookHandler(
	engine *trap.Engine,
	selector *trap.Selector,
	callbackHandler *trap.CallbackHandler,
	logger *slog.Logger,
	hookSecret string,
	port int,
) *HookHandler

NewHookHandler creates a HookHandler wired to the trap engine and callback handler.

func (*HookHandler) HandleInjectTrap added in v0.6.0

func (hh *HookHandler) HandleInjectTrap(w http.ResponseWriter, r *http.Request)

HandleInjectTrap decides whether to inject a trap for a given command. Used by the hook bridge for Copilot (which can't proxy API traffic).

func (*HookHandler) HandlePreToolUse

func (hh *HookHandler) HandlePreToolUse(w http.ResponseWriter, r *http.Request)

HandlePreToolUse processes a PreToolUse hook request from Claude Code.

type HookOutput

type HookOutput struct {
	HookEventName            string `json:"hookEventName"`
	PermissionDecision       string `json:"permissionDecision"`
	PermissionDecisionReason string `json:"permissionDecisionReason,omitempty"`
}

HookOutput contains the permission decision for Claude Code.

type HookRequest

type HookRequest struct {
	SessionID     string          `json:"session_id"`
	HookEventName string          `json:"hook_event_name"`
	ToolName      string          `json:"tool_name"`
	ToolInput     json.RawMessage `json:"tool_input"`
	ToolUseID     string          `json:"tool_use_id"`
}

HookRequest is the JSON body sent by Claude Code's PreToolUse hook.

type HookResponse

type HookResponse struct {
	HookSpecificOutput *HookOutput `json:"hookSpecificOutput,omitempty"`
}

HookResponse is the JSON response sent back to Claude Code.

type InjectTrapResponse added in v0.6.0

type InjectTrapResponse struct {
	Inject      bool   `json:"inject"`
	TrapCommand string `json:"trap_command,omitempty"`
}

InjectTrapResponse is the JSON response for the inject-trap endpoint.

type OAIStreamInterceptor added in v0.6.0

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

OAIStreamInterceptor parses OpenAI-format SSE lines (data: {...}), detects shell/bash tool calls, and optionally replaces the command argument with a trap command for security awareness training.

func NewOAIStreamInterceptor added in v0.6.0

func NewOAIStreamInterceptor(
	engine *trap.Engine,
	selector *trap.Selector,
	injectTrapFn TrapInjectionFunc,
	logger *slog.Logger,
) *OAIStreamInterceptor

NewOAIStreamInterceptor creates a new OAIStreamInterceptor wired to the trap engine, selector, and an injection function called when a trap is to be inserted.

func (*OAIStreamInterceptor) ProcessLine added in v0.6.0

func (oi *OAIStreamInterceptor) ProcessLine(line string) ([]string, error)

ProcessLine processes a single raw SSE line and returns zero or more output lines. Shell tool_call lines are buffered until finish_reason/[DONE] triggers a flush, at which point the interceptor decides whether to inject a trap command. Non-shell, non-data, and empty lines pass through immediately.

type OAIToolCallState added in v0.6.0

type OAIToolCallState struct {
	Index           int
	FunctionName    string
	ArgumentsBuffer strings.Builder
	BufferedLines   []string
	ToolCallID      string
	// Chunk metadata preserved from the first buffered line for synthetic deltas.
	ChunkID      string
	ChunkCreated int64
	ChunkModel   string
}

OAIToolCallState tracks a single tool call being assembled from SSE chunks.

type ProxyHandler

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

ProxyHandler forwards HTTP requests to the Anthropic API, intercepts SSE streaming responses to detect and optionally replace bash tool_use commands with trap commands, and relays everything else unchanged.

func NewProxyHandler

func NewProxyHandler(
	anthropicURL string,
	httpClient *http.Client,
	engine *trap.Engine,
	selector *trap.Selector,
	callbackHandler *trap.CallbackHandler,
	apiClient *client.Client,
	logger *slog.Logger,
) *ProxyHandler

NewProxyHandler creates a ProxyHandler that forwards requests to the given Anthropic API base URL and optionally injects traps via the callback handler.

func (*ProxyHandler) HandleProxy

func (ph *ProxyHandler) HandleProxy(w http.ResponseWriter, r *http.Request)

HandleProxy is the main HTTP handler that proxies requests to the Anthropic API. It detects SSE streaming responses and pipes them through the StreamInterceptor; non-streaming responses are checked for tool_use blocks in the JSON body.

type ResponsesInterceptor added in v0.8.0

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

ResponsesInterceptor handles the OpenAI Responses API streaming format used by VS Code Copilot for GPT models. Events use proper SSE with event: + data: lines. Function calls stream via:

  • response.output_item.added (name + call_id)
  • response.function_call_arguments.delta (argument fragments)
  • response.function_call_arguments.done (complete arguments)
  • response.output_item.done (full item)

func NewResponsesInterceptor added in v0.8.0

func NewResponsesInterceptor(
	engine *trap.Engine,
	selector *trap.Selector,
	injectTrapFn TrapInjectionFunc,
	logger *slog.Logger,
) *ResponsesInterceptor

NewResponsesInterceptor creates a ResponsesInterceptor for the OpenAI Responses API.

func (*ResponsesInterceptor) ProcessEvent added in v0.8.0

func (ri *ResponsesInterceptor) ProcessEvent(event SSEEvent) ([]SSEEvent, error)

ProcessEvent takes a single SSE event and returns zero or more events to emit. Shell function call events are buffered until arguments.done, then the interceptor decides whether to inject a trap.

type SSEEvent

type SSEEvent struct {
	Event string // event type (message_start, content_block_start, etc.)
	Data  string // JSON data
}

SSEEvent represents a single Server-Sent Event with its event type and JSON data payload.

type Server

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

Server is the AgentsAegis proxy HTTP server that intercepts traffic between Claude Code and the Anthropic API, injecting security awareness traps.

func New

func New(
	cfg *config.Config,
	engine *trap.Engine,
	selector *trap.Selector,
	apiClient *client.Client,
	logger *slog.Logger,
	hookSecret ...string,
) *Server

New creates a new proxy server wired with the trap engine, selector, API client, and configuration.

func (*Server) SetSuperDebug

func (s *Server) SetSuperDebug()

SetSuperDebug disables cooldown and jitter on the hook handler for testing.

func (*Server) Shutdown

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

Shutdown gracefully shuts down the server with the given context deadline.

func (*Server) Start

func (s *Server) Start() error

Start begins listening for requests. It blocks until the server is shut down.

type StreamInterceptor

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

StreamInterceptor parses SSE events from an Anthropic streaming response, detects bash tool_use content blocks, and optionally replaces the command payload with a trap command while preserving valid SSE structure.

func NewStreamInterceptor

func NewStreamInterceptor(
	engine *trap.Engine,
	selector *trap.Selector,
	injectTrapFn TrapInjectionFunc,
	logger *slog.Logger,
) *StreamInterceptor

NewStreamInterceptor creates a StreamInterceptor wired to the trap engine, selector, and an injection function that is called to register and build the trap command whenever a bash tool_use block is selected for trapping.

func (*StreamInterceptor) ProcessEvent

func (si *StreamInterceptor) ProcessEvent(event SSEEvent) ([]SSEEvent, error)

ProcessEvent takes a single SSE event and returns zero or more events to emit. When buffering a bash tool_use block the return slice may be empty; on flush it may contain many events at once.

type TrapInjectionFunc

type TrapInjectionFunc func(originalCmd string, template *trap.Template, toolUseID string) (trapCmd string)

TrapInjectionFunc is called when a trap should be injected. It receives the original command and the selected template, registers the trap, and returns the actual trap command string to embed in the stream.

Jump to

Keyboard shortcuts

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