Documentation
¶
Overview ¶
Package ipc is the console's local transport: a Unix domain socket in a directory private to the user (on Linux and macOS), newline-delimited JSON-RPC 2.0 framing capped at 1 MiB, and a peer check.
Index ¶
- Constants
- Variables
- func Compatible(major int) bool
- func Listen(path string) (net.Listener, error)
- func ListenShared(path string, gid int) (net.Listener, error)
- func Methods() []string
- func PeerAllowed(c net.Conn) (bool, error)
- func ReadMsg(r *bufio.Reader, v any) error
- func SharedSocketPath(dir, projectHash, profile string) (string, error)
- func SocketPath(projectHash, profile string) (string, error)
- func WriteMsg(w io.Writer, v any) error
- type ChangeParams
- type ChangeResult
- type Cred
- type DescribeParams
- type Health
- type HelloParams
- type HelloResult
- type PIIAddParams
- type PIIListResult
- type PlanParams
- type PlanResult
- type RPCError
- type Request
- type Response
- type RunParams
- type RunResult
- type StatusResult
- type TablesParams
- type TablesResult
Constants ¶
const ( MethodHello = "hello" MethodStatus = "status" MethodCatalogList = "catalog.list" MethodCatalogDescribe = "catalog.describe" MethodQueryPlan = "query.plan" MethodQueryRun = "query.run" MethodPIIList = "pii.list" MethodPIIAdd = "pii.add" MethodChangeRequest = "change.request" MethodLogout = "logout" )
Methods, spec §7. None of them loosens policy: change.request only queues a proposal that the console shows to the human.
const ( CodeRefused = -32001 // classifier, tier or weight check refused CodeDenied = -32002 // the human denied CodeTimeout = -32003 // no answer within the approval timeout CodeNoSuchPlan = -32004 // unknown, used or expired plan id CodeConnLost = -32005 // the database connection was lost CodePolicyPending = -32006 // a policy change awaits the human CodeParseError = -32700 CodeInvalidRequest = -32600 CodeMethodNotFound = -32601 CodeInvalidParams = -32602 CodeInternal = -32603 )
Error codes. The -320xx range is reserved by JSON-RPC for implementation errors; the standard codes are kept for protocol faults.
const MaxMessage = 1 << 20
MaxMessage is the largest message, excluding the newline, in bytes.
const ProtocolMajor = 1
ProtocolMajor is exchanged in the hello handshake. A client and a console with different majors refuse to talk.
const RuntimeDirEnv = "LOCKSQL_RUNTIME_DIR"
RuntimeDirEnv overrides the runtime dir on every OS when set to an absolute path: the sockets then live in $LOCKSQL_RUNTIME_DIR/locksql. The console and its clients must see the same value. Tests use it to keep sockets in a temp dir.
Variables ¶
var ErrAlreadyRunning = errors.New("ipc: a console is already running for this profile")
ErrAlreadyRunning means a live console already listens on the socket.
var ErrTooLarge = errors.New("ipc: message larger than 1 MiB")
ErrTooLarge means a message is over MaxMessage. After a read error the stream is out of step and the connection must be closed.
Functions ¶
func Compatible ¶
Compatible reports whether a peer's protocol major can talk to this one.
func Listen ¶
Listen opens the console socket at path. The parent directory is made private (0700 and owned by the user) and the socket is 0600. A socket left by a dead console is replaced; one with a live console gives ErrAlreadyRunning; any other kind of file at path is left alone and refused. Closing the listener removes the socket.
func ListenShared ¶
ListenShared opens a console socket in the shared socket directory of a separated setup (see package sysconf): the directory must already exist (locksql install creates it), belong to the console's user and to the client group gid, and give others no access; the socket is made read-write for that group only (0660). The peer check still decides who is served.
func PeerAllowed ¶
PeerAllowed reports whether the process at the other end of c runs as the same user as the console (SO_PEERCRED).
func ReadMsg ¶
ReadMsg reads one line of at most MaxMessage bytes (a trailing CR is dropped) and decodes it into v. It returns io.EOF at a clean end of stream and ErrTooLarge as soon as the line passes the cap, without buffering the rest.
func SharedSocketPath ¶
SharedSocketPath is SocketPath in the shared socket directory of a separated setup.
func SocketPath ¶
SocketPath returns the console socket of a project and profile: <runtime dir>/locksql/<project-hash>-<profile>.sock, where the runtime dir is $LOCKSQL_RUNTIME_DIR when set, else $XDG_RUNTIME_DIR (Linux) or $TMPDIR (macOS). When $XDG_RUNTIME_DIR or $TMPDIR is unusable the directory is <temp>/locksql-<uid>. A name that would exceed the OS socket path limit is replaced by <project-hash>-~<sha256(profile)[:16]>.sock, which is still stable, so the client and the console agree on it.
Types ¶
type ChangeParams ¶
type ChangeParams struct {
Change string `json:"change"`
}
ChangeParams queues a policy change proposal for the human.
type ChangeResult ¶
type ChangeResult struct {
Queued bool `json:"queued"`
}
ChangeResult answers change.request.
type Cred ¶
type Cred struct {
UID, GID, PID int
}
Cred is what the kernel says about the process at the other end of a socket. PID is -1 when the platform does not report it.
type DescribeParams ¶
DescribeParams describes one table (catalog.describe); the result is an engine.TableInfo.
type Health ¶
type Health struct {
// Separated is set when the console runs as a dedicated account,
// apart from the agent (sysconf).
Separated bool `json:"separated"`
Display string `json:"display"`
// Privileges are the privilege audit's findings: what the database
// account can do beyond the profile tier.
Privileges []string `json:"privileges"`
// ExplainOK reports that EXPLAIN works on the server.
ExplainOK bool `json:"explain_ok"`
// ReadOnly reports that the session is read-only on the server.
ReadOnly bool `json:"read_only"`
}
Health is the console's own diagnosis of its setup.
type HelloParams ¶
type HelloParams struct {
ProtocolMajor int `json:"protocol_major"`
Client string `json:"client,omitempty"`
}
HelloParams opens a session; Client is a free-form name and version.
type HelloResult ¶
type HelloResult struct {
ProtocolMajor int `json:"protocol_major"`
ConsoleVersion string `json:"console_version,omitempty"`
Profile string `json:"profile"`
}
HelloResult answers hello.
type PIIAddParams ¶
type PIIAddParams struct {
Pattern string `json:"pattern"`
}
PIIAddParams proposes a mask pattern "db.table.column".
type PIIListResult ¶
PIIListResult answers pii.list with the column rules.
type PlanParams ¶
type PlanParams struct {
DB string `json:"db"`
SQL string `json:"sql"`
Unmask bool `json:"unmask,omitempty"`
}
PlanParams asks for a plan (classification, EXPLAIN, weight, approval).
type PlanResult ¶
type PlanResult struct {
PlanID string `json:"plan_id"`
Profile string `json:"profile"`
Host string `json:"host"`
DB string `json:"db"`
SQL string `json:"sql"`
Class string `json:"class"`
Verdict string `json:"verdict"`
Summary string `json:"summary"`
Reasons []string `json:"reasons,omitempty"`
Unmask bool `json:"unmask,omitempty"`
// Values are the placeholder names the human typed in this console
// session: '${name}' reuses a value without a prompt.
Values []string `json:"values,omitempty"`
}
PlanResult is an approved, one-shot plan.
type RPCError ¶
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data,omitempty"`
}
RPCError is a JSON-RPC 2.0 error object. Message must never carry a secret; the console sanitises it.
type Request ¶
type Request struct {
JSONRPC string `json:"jsonrpc"`
ID int64 `json:"id"`
Method string `json:"method"`
Params json.RawMessage `json:"params"`
}
Request is a JSON-RPC 2.0 request.
type Response ¶
type Response struct {
JSONRPC string `json:"jsonrpc"`
ID int64 `json:"id"`
Result json.RawMessage `json:"result,omitempty"`
Error *RPCError `json:"error,omitempty"`
}
Response is a JSON-RPC 2.0 response: Result or Error, never both.
type RunParams ¶
type RunParams struct {
PlanID string `json:"plan_id"`
}
RunParams runs an approved plan.
type RunResult ¶
type RunResult struct {
Columns []string `json:"columns"`
Rows [][]any `json:"rows"`
Truncated bool `json:"truncated"`
Affected int64 `json:"affected,omitempty"`
// DurationMS is no longer filled: timings stay on the console.
DurationMS int64 `json:"duration_ms,omitempty"`
Text string `json:"text,omitempty"`
}
RunResult is a capped, masked result. Text is the rendered TSV.
type StatusResult ¶
type StatusResult struct {
Profile string `json:"profile"`
Engine string `json:"engine"`
Host string `json:"host"`
HostConfirmed bool `json:"host_confirmed"`
Production bool `json:"production"`
SkipPermissions bool `json:"skip_permissions"`
Tier string `json:"tier"`
Databases []string `json:"databases"`
Limits config.Limits `json:"limits"`
IdleTimeoutInS int `json:"idle_timeout_in_s"`
SessionEndsInS int `json:"session_ends_in_s"`
// Health is what the console found at start-up, for locksql doctor.
Health *Health `json:"health,omitempty"`
}
StatusResult describes the console session.
type TablesParams ¶
type TablesParams struct {
DB string `json:"db"`
}
TablesParams lists the tables of a database (catalog.list).
type TablesResult ¶
TablesResult answers catalog.list.