Documentation
¶
Overview ¶
Package sql is the SQL protocol-family facet. It owns the SQL CEL environment (verb / tables / functions / statement, exposed as fields on the `sql` variable), the matcher that walks a parsed SQL statement, the Meta type wire-frame frontends (postgres, clickhouse) populate on match.Request.Meta, and the per-family report fields the dashboard shows for a SQL query.
SQL endpoints derive Meta themselves from the wire frame (the postgres / clickhouse runtimes parse the Query message and stash a *Meta on the request before dispatch), so PrepareRequest is a no-op. The matcher type-asserts req.Meta to *Meta and fails the match cleanly when the assertion fails — e.g. when an https- family request accidentally reaches a sql rule.
Index ¶
- type Facet
- func (Facet) CELContrib() facet.CELContrib
- func (Facet) EndpointFamilies() []string
- func (Facet) HITLQueryLabel() string
- func (Facet) HostIsResource() bool
- func (Facet) Name() string
- func (f Facet) NewMatcher(condition string) (match.Matcher, error)
- func (Facet) PrepareRequest(*match.Request)
- func (Facet) Report(req *match.Request) map[string]any
- func (Facet) ReportFields() []facet.ReportFieldSpec
- func (Facet) Transport() string
- type Fields
- type Meta
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Facet ¶
type Facet struct{}
Facet is the SQL facet Runtime. Singleton.
func (Facet) CELContrib ¶
func (Facet) CELContrib() facet.CELContrib
CELContrib declares the SQL facet's CEL contribution: the `sql` variable backed by Fields and the path lists CompileCondition needs.
lowercasedPaths: sql.verb's activation value is lowercased so rules written as `sql.verb == "SELECT"` match a select statement.
truncatablePaths: every SQL field, because the wire frontends (postgres pgClientToServer, clickhouse_native chHandleQuery) feed the matcher one piece of text — the raw statement — and every CEL field (verb, tables, functions, statement) is derived from the same parsed bytes. When the frontend caps the frame, all four are simultaneously untrustworthy — they become CEL unknowns, so any condition whose outcome depends on one fails closed on a truncated request.
Note credential and database are intentionally absent: they resolve off-wire (StartupMessage user / database, Hello username / database, HTTPS query+header), never from frame bytes, so predicates on either still evaluate correctly on a truncated request. The dispatcher applies r.Credential before the matcher runs (config/runtime/dispatch.go), and the database value flows through req.Database / meta.Database which the wire frontend populates before any SQL bytes are read. unparseablePaths declares the SQL fields a wire frontend's parser derives from the Query bytes — verb, tables, functions. When the parser refuses the input, the frontend leaves these zero and sets req.Unparseable=true; the matcher then marks these paths as CEL unknowns and any rule whose outcome depends on one is denied.
sql.statement is intentionally absent: the frontend populates it with the raw bytes regardless of parse success, so a rule keyed on `sql.statement` / `sql.statement.matches(...)` can still evaluate honestly on an unparseable request.
func (Facet) EndpointFamilies ¶
EndpointFamilies enumerates endpoint families a sql rule may attach to.
func (Facet) HITLQueryLabel ¶
HITLQueryLabel is the dashboard / Slack label for a SQL query.
func (Facet) HostIsResource ¶
HostIsResource reports that a SQL request's Host is typically a virtual IP, not a label the operator would recognise.
func (Facet) NewMatcher ¶
NewMatcher compiles a CEL condition into a Matcher. Delegates to the package-level composer (the sql family composes only its own sql facet today — postgres / clickhouse_native wire protocols are binary, not HTTPS, so there is no http facet to add).
func (Facet) PrepareRequest ¶
PrepareRequest is a no-op: SQL endpoint runtimes set req.Meta directly from the wire frame.
func (Facet) Report ¶
Report extracts the SQL report fields from a request. When Meta isn't a *Meta (e.g. a request that never ran through a SQL frontend) the result is empty rather than panicking.
func (Facet) ReportFields ¶
func (Facet) ReportFields() []facet.ReportFieldSpec
ReportFields declares the per-family columns the SQL facet emits.
type Fields ¶
type Fields struct {
Verb string `cel:"verb"`
Tables []string `cel:"tables"`
Functions []string `cel:"functions"`
Statement string `cel:"statement"`
Database string `cel:"database"`
}
Fields is the CEL-facing view of a SQL statement. Exposed as the `sql` variable in rule conditions (`sql.verb`, `sql.tables`, `sql.functions`, `sql.statement`, `sql.database`). The plural `functions` matches the multi-valued shape (a statement can reference multiple functions) and parallels `tables`.
type Meta ¶
type Meta struct {
Verb string // select | insert | update | delete | merge | ...
Tables []string // unqualified table names referenced
Functions []string // unqualified function names called
Statement string // the raw text — exposed for `statement` /
// `statement_regex` matchers
Database string // session-scoped database name; postgres
}
Meta carries the per-request SQL fields the matcher reads. The postgres and clickhouse endpoint runtimes build one of these from the parsed wire frame and assign it to match.Request.Meta.