serve

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package serve answers read-only questions about a warehouse, over HTTP, so the console never holds a warehouse credential.

Everything here runs on the far side of that line. The console forwards a request; this decides what may run, bounds it, runs it and says what it did. A limit the console could change is not a limit, which is why none of them live there.

Index

Constants

View Source
const CodeNoConnection = "no-connection"

CodeNoConnection is what the console matches on. See ErrNoConnection.

View Source
const EnvLocal = "local"

EnvLocal is the one environment where an open endpoint is allowed.

Variables

View Source
var ErrNoConnection = errors.New("no connection is declared for that destination")

ErrNoConnection is what an opener returns when nothing is DECLARED for a destination, as opposed to declared and unreachable.

THE DIFFERENCE IS THE WHOLE POINT. "Unreachable" is an incident and says nothing a reader can act on; "nobody has declared where that database is" is a sentence with an action in it, and V4 puts it on the screen. A 502 would bury the second inside the first.

Functions

func BytesText

func BytesText(n int64) string

BytesText is a byte count somebody can judge at a glance.

A refusal saying "10737418240 bytes" is one somebody has to count the digits of, and the number IS the content of that message: it is the difference between a typo and a query worth waiting for.

func ReadOnly

func ReadOnly(dialect, statement string) error

ReadOnly refuses any statement that is not a single query.

THIS IS THE FUNCTION BETWEEN A BROWSER AND A CUSTOMER'S WAREHOUSE, and it is written to be read by somebody deciding whether to trust it.

OVER A TOKENISER AND NOT A REGEX, which is the whole reason `sqltok` exists as its own package. A pattern matching `DELETE` cannot tell code from a string literal or a comment, so it refuses `WHERE note = 'please DELETE this row'` -- a legitimate query -- and it accepts `/* SELECT */ DROP TABLE t`. Both of those are cases below.

WHAT IT CANNOT DO, said plainly so nobody discovers it as a bug: a function call writes whatever the function writes. `SELECT nextval('s')` advances a sequence and `SELECT dblink_exec(...)` runs anything at all, and no classifier that is not a planner can see inside them. THE READ-ONLY ROLE IS THE DEFENCE THERE, not this -- which is exactly the question CHECKPOINT B exists to answer before this is deployed anywhere.

WHEN IT CANNOT FOLLOW THE STATEMENT, IT REFUSES. A parser that gives up and allows is a parser that can be made to give up on purpose.

Types

type Caller

type Caller struct {
	// Name is what the audit line carries. It reaches a JSON document and
	// somebody's grep, so it is checked at boot rather than escaped later.
	Name string

	// Token is the bearer this caller presents.
	Token string
}

Caller is one named bearer.

CHECKPOINT B's F7: the audit line carried connection, hash, rows, bytes, duration and outcome, and nothing about WHO asked. With one operator that was a note; with two it means the log cannot answer the only question it is read for.

IDENTITY IS THE CREDENTIAL, not a header. A caller that announced its own name would be making a CLAIM, and an audit of claims is an audit of whatever an attacker typed. A token the operator issued is a FACT: the line cannot say anything the holder of that token did not actually hold.

The Name is not a secret -- it is printed at boot and written to every line. The Token is, and appears in neither.

type Options

type Options struct {
	// Env decides whether an unauthenticated service may exist. It comes from
	// BREVIS_ENV and NEVER from a configuration file -- the gateway's rule,
	// and its reason: "a config file that could declare itself local would be
	// a file that turns off authentication."
	Env string

	// Token is the bearer every request must carry, with NO NAME attached.
	// Required outside local unless Callers names one.
	//
	// It is what every deployment has today and it keeps working. Its audit
	// lines carry no caller, which is itself the finding: a shared secret
	// with nobody's name on it.
	Token string

	// Callers are named bearers, and the audit line carries whichever one
	// asked. See caller.go for why identity is the credential rather than a
	// header. Folded together with Token into one list at boot.
	Callers []Caller

	// Addr is where this will listen, and it is EVIDENCE rather than
	// configuration: see New. Empty means nobody is deploying anything --
	// a test, or something embedding this -- and no rule is drawn from it.
	Addr string

	// Rows is the ceiling. A caller may ask for fewer and cannot ask for more.
	Rows int

	// Bytes is the most a single query may SCAN. A caller cannot raise it
	// and cannot name one at all: it is money, and the browser is not the
	// place that decides how much of it to spend.
	//
	// IT BOUNDS THE PREVIEW TOO, and that was a hole rather than a choice.
	// A preview is `SELECT * FROM t LIMIT 20`, and a LIMIT does not reduce
	// what BigQuery scans -- twenty rows off a petabyte table reads the
	// petabyte and bills for it. The row ceiling bounds the screen and
	// bounds nothing else.
	Bytes int64

	// Budget is the most one CONNECTION may scan in an hour, across every
	// query. Zero is no budget, which is the default.
	//
	// A CONCURRENCY LIMIT IS NOT A BUDGET -- CHECKPOINT B's F6. Four queries
	// at a time, each under the per-query ceiling, repeated forever, is
	// unbounded: the ceiling bounds one query and nothing bounds the sum.
	// For a single authenticated operator no budget may well be the right
	// answer, but it has to be a CHOICE, and an absence is not one. The boot
	// banner states whichever it is.
	//
	// PER CONNECTION, because a connection is what pays the bill: two
	// warehouses are two accounts, and exhausting one must not close the
	// other.
	//
	// IT BOUNDS WHAT IS METERED, which is not everything. A warehouse that
	// charges for a machine by the hour reports no bytes, so a budget bounds
	// BigQuery and bounds nothing on Postgres. That is fine -- Postgres is
	// not billed by the byte -- and dangerous only if somebody believes
	// otherwise, which is why the banner says which connections it can
	// actually bound.
	Budget int64

	// Writable NAMES THE CONNECTIONS on which a statement may write. Empty
	// is the default and is every deployment that has not asked otherwise.
	//
	// IT COMES FROM BREVIS_SQL_SERVE_WRITES AND NEVER FROM A FILE, which is
	// the rule Token already follows one field up and for the same reason: a
	// config file that could declare itself local would be a file that turns
	// off authentication, and one that could declare itself writable would
	// be a file that turns off every limit on this surface at once.
	//
	// NAMES AND NOT A BOOLEAN. One service reaches several warehouses, and
	// unlocking the one somebody develops against must not unlock the one
	// beside it. The accident this exists to prevent is a development
	// service that is also pointed at a production DSN, and a switch cannot
	// tell those apart.
	//
	// A NAME HERE STANDS DOWN EVERY LAYER AT ONCE -- the tokeniser, the
	// warehouse's verdict and the warehouse's enforcement -- so on a named
	// connection this service is exactly as powerful as its credential. The
	// row ceiling bounds a screen and the byte ceiling bounds MONEY; neither
	// bounds damage, because an UPDATE scans almost nothing and changes
	// everything.
	Writable []string

	// Audit is where one line per query goes. Nil writes none, which is what
	// a test wants and never what a deployment does.
	Audit io.Writer

	// Concurrent is how many queries may run at once. Over that, a caller is
	// REFUSED rather than queued: a queue behind a browser is a browser that
	// waits with no way to know why, and every waiting request still holds a
	// connection to the warehouse.
	Concurrent int

	// Timeout bounds one query, the dry run and the read together.
	Timeout time.Duration

	// Open connects to one warehouse. A field so a test can hand over a fake
	// without a warehouse, and so this package holds no driver of its own.
	//
	// IT TAKES THE WHOLE TARGET and not just a name, because a name is not
	// unique on its own: `app` can be a BigQuery project and a Postgres
	// database at once, and the registry matches on both halves.
	Open func(ctx context.Context, t Table) (dialect.Conn, error)
}

Options is what a Service needs.

type Service

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

Service answers read-only questions about a warehouse.

func New

func New(opt Options) (*Service, error)

New builds the service, or refuses to.

REFUSING TO EXIST IS THE POINT. A service that started without a token and logged a warning would be an open endpoint onto a customer's warehouse, with a line in a log nobody reads. Failing at boot is the only refusal that cannot be ignored.

func (*Service) Handler

func (s *Service) Handler() http.Handler

Handler is the service's routes.

func (*Service) Metrics

func (s *Service) Metrics() http.Handler

Metrics is the exposition, and it is a SEPARATE HANDLER on purpose.

The rule this repository states twice, in the engine and in the gateway: a scrape endpoint on the port that answers requests would either need a session no scraper has, or publish every connection name to whoever can reach that port. `Handler` does not route /metrics at all, and a test says so.

It carries no authentication of its own, for the same reason the gateway's does not: it is bound to an address an operator chooses, and a scraper cannot hold a token.

type Table

type Table struct {
	// Connection is which warehouse: the BigQuery project.
	Connection string
	// Dialect is whose SQL this is, which the classifier needs: `#` opens a
	// comment in one of them and is an operator in the other, and reading
	// the wrong one wrong is how `# SELECT\nDROP TABLE t` gets through.
	Dialect string
	// Relation is `dataset.table`, ready to be written into SQL -- which is
	// safe only because both halves matched `identifier`.
	Relation string
}

Table is a target this service can read.

func ParseTarget

func ParseTarget(target string) (Table, error)

ParseTarget turns a catalog target into something readable, or refuses it.

THE MOST DANGEROUS FUNCTION IN THIS PACKAGE. What it returns is written into a statement, so nothing here escapes an input and then uses it: every segment must ALREADY be a name BigQuery could hold, and anything else is refused whole. A semicolon, a comment marker, a backtick or a space each turn one statement into two.

BIGQUERY ONLY, FOR NOW, and that is a shape rather than an omission: a `bigquery://` target carries its project, and the project IS the connection. `postgres://database/schema/table` carries a database name and no host, port or user -- a target is an identity and never an address -- so it cannot be reached without a connection somebody declared, which is a later slice.

`s3`, `gs`, `file` and `pubsub` are not tables. They are in the catalog because Brevis lands them, and they have no rows to preview.

Jump to

Keyboard shortcuts

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