console

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: Apache-2.0 Imports: 43 Imported by: 0

Documentation

Overview

Package console is the human side of locksql: it holds the credentials and the only database connection, enforces the approved policy, shows every query to the human for approval, masks the results and writes the audit trail. Clients (the CLI and the MCP server) reach it over the per-profile socket and never see a secret.

Index

Constants

View Source
const (
	ApprovalTimeout = 5 * time.Minute
	IdleTimeout     = 20 * time.Minute
	MaxSession      = 4 * time.Hour
	PlanTTL         = 10 * time.Minute
	// PolicyPoll is how often the config files are checked for changes.
	PolicyPoll = 2 * time.Second
)

Session timeouts, spec §6.

View Source
const ResponseQuantum = 250 * time.Millisecond

ResponseQuantum levels the time a statement takes, as the client sees it: the answer to query.run, success or failure, leaves at the next multiple of it after the run started. A query cannot turn the time it takes into a fine-grained signal (a timing side channel).

Variables

View Source
var ErrConfig = errors.New("configuration error")

ErrConfig marks usage and configuration errors (exit code 3).

Functions

func Run

func Run(ctx context.Context, o Options) error

Run is `locksql console`: the start-up sequence of spec §6, then the request loop until Ctrl-C, logout, :quit or a timeout.

func SameUserRefused added in v0.1.2

func SameUserRefused(sys *sysconf.Config) error

SameUserRefused is the refusal of a console without a separated setup (sys nil, as sysconf.Load returns it), or nil.

Types

type IO

type IO interface {
	Println(s string)
	// Ask prints prompt and reads one line. It returns false when no answer
	// came within timeout, when ctx ended (Ctrl-C, client gone) or when the
	// terminal is closed.
	Ask(ctx context.Context, prompt string, timeout time.Duration) (string, bool)
	// AskSecret reads a line with echo off.
	AskSecret(ctx context.Context, prompt string) ([]byte, error)
}

IO is the console's terminal. Ask and AskSecret discard pending input before prompting, so type-ahead never answers a prompt.

type LineSource

type LineSource interface {
	Lines() <-chan string
}

LineSource is implemented by an IO that also delivers the lines the human types between requests (console commands such as :review).

type Options

type Options struct {
	Profile         string
	SkipPermissions bool
	// AllowUnmask lets clients ask for unmasked output (--allow-unmask).
	AllowUnmask bool
	Cwd         string
	IO          IO
	// Now defaults to time.Now.
	Now func() time.Time
	// StateDir defaults to config.StateDir().
	StateDir string
	// Version is the console version reported to clients.
	Version string
	// TTY is the console's terminal device (nil when unknown): its owner
	// must be the console's account in a separated setup.
	TTY *os.File
}

Options configure Run.

type Server

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

Server serves client requests one at a time against one session. It is not safe for concurrent use: Serve runs every request on one goroutine.

func NewServer

func NewServer(cfg ServerConfig) (*Server, error)

NewServer checks cfg and returns a server enforcing cfg.Policy.

func (*Server) CheckPolicy

func (s *Server) CheckPolicy()

CheckPolicy re-reads the policy from the config files. Changes that only tighten are applied at once; a loosening waits for :review, and plans are refused with CodePolicyPending meanwhile.

func (*Server) Command

func (s *Server) Command(ctx context.Context, line string)

Command runs a console command typed by the human between requests.

func (*Server) End

func (s *Server) End(reason string)

End stops the session after the current request.

func (*Server) Ended

func (s *Server) Ended() (string, bool)

Ended reports whether the session is over, and why.

func (*Server) Handle

func (s *Server) Handle(ctx context.Context, req ipc.Request) ipc.Response

Handle serves one request. It is the whole client surface of the console: none of the methods loosens the policy.

func (*Server) Serve

func (s *Server) Serve(ctx context.Context, ln net.Listener, lines <-chan string) error

Serve accepts clients on ln and serves their requests one at a time until ctx ends or the session ends (logout, timeouts, :quit). lines are the console commands typed by the human (nil for none). ln is closed on return, which removes the socket.

func (*Server) Tick

func (s *Server) Tick()

Tick ends the session on idle or maximum session timeout.

type ServerConfig

type ServerConfig struct {
	// Policy is the approved policy the server enforces.
	Policy config.Policy
	// RulesPath is the PII rules file: <project>/.locksql/pii.toml, or
	// pii.toml in the user config directory outside a project.
	RulesPath string
	// StateDir and ApprovedKey locate the approved policy file.
	StateDir    string
	ApprovedKey string
	Session     engine.Session
	// DBUser is the database account in use (it may have been asked for).
	DBUser    string
	Databases []string
	Audit     *audit.Log
	IO        IO
	Now       func() time.Time
	// SkipPermissions auto-approves on non-production profiles (never
	// unmask, never REFUSE).
	SkipPermissions bool
	// AllowUnmask lets clients ask for unmasked output; without it an
	// unmask plan is refused before anything else.
	AllowUnmask bool
	Version     string
	// LoadPolicy re-reads the current policy from the config files. Nil
	// disables CheckPolicy.
	LoadPolicy func() (config.Policy, error)
	// Reconnect opens a new session after a lost connection, under p, the
	// profile in force at that time. Nil means a lost connection ends the
	// console.
	Reconnect func(ctx context.Context, p config.Profile) (engine.Session, error)
	// Quantum levels the response time of query.run (ResponseQuantum in
	// the real console, 0 to disable).
	Quantum time.Duration
	// PeerAllowed decides which clients are served, from the kernel's
	// credentials of the peer. Nil serves the console's own account only.
	PeerAllowed func(ipc.Cred) bool
	// Health is reported in status for locksql doctor.
	Health *ipc.Health
}

ServerConfig holds what a Server needs once the start-up sequence is done. Run builds it; tests build it directly.

type Terminal

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

Terminal is the IO of a real console: prompts and messages go to out, answers and console commands are read line by line from in, which must be the controlling terminal.

One goroutine reads in from the first prompt on, so that the console can wait for a request and for a typed command at the same time. Before each prompt the kernel's pending input is flushed and the lines already read are dropped: type-ahead never answers a prompt.

func NewTerminal

func NewTerminal(in *os.File, out io.Writer) *Terminal

NewTerminal returns the IO over in and out (normally os.Stdin and os.Stdout).

func (*Terminal) Ask

func (t *Terminal) Ask(ctx context.Context, prompt string, timeout time.Duration) (string, bool)

Ask flushes pending input, prints prompt and waits for one line.

func (*Terminal) AskSecret

func (t *Terminal) AskSecret(ctx context.Context, prompt string) ([]byte, error)

AskSecret reads a line with echo off. Before the reader goroutine runs it uses secrets.PromptPassword; afterwards it turns echo off on in itself.

func (*Terminal) Lines

func (t *Terminal) Lines() <-chan string

Lines delivers the lines typed while no prompt is active.

func (*Terminal) Println

func (t *Terminal) Println(s string)

Println writes one line.

Jump to

Keyboard shortcuts

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