Documentation
¶
Overview ¶
Package dbviewer runs read-only (and, when explicitly allowed, write) SQL against a managed database by exec'ing the engine's own client inside its container. Credentials never leave the container.
Index ¶
- Constants
- Variables
- func HistoryKeepFromEnv(lookup func(string) (string, bool)) int
- type Column
- type Dialect
- type Evidence
- type Execer
- type Filter
- type ForeignKey
- type Index
- type Limits
- type Page
- type PageQuery
- type QueryError
- type RedisKey
- type RedisScan
- type RedisValue
- type Result
- type SchemaNode
- type Statement
- type Structure
- type Table
- type Target
- func (t Target) Evidence(ctx context.Context) (Evidence, error)
- func (t Target) Explain(ctx context.Context, st Statement, analyze bool) (Result, error)
- func (t Target) GetKey(ctx context.Context, key string) (RedisValue, error)
- func (t Target) Run(ctx context.Context, st Statement, write bool) (Result, error)
- func (t Target) RunTrusted(ctx context.Context, sql string) (Result, error)
- func (t Target) ScanKeys(ctx context.Context, cursor, pattern string, count int) (RedisScan, error)
- func (t Target) Schema(ctx context.Context) ([]SchemaNode, error)
- func (t Target) SchemaOutline(ctx context.Context) ([]SchemaNode, error)
- func (t Target) TablePage(ctx context.Context, q PageQuery) (Page, error)
- func (t Target) TableStructure(ctx context.Context, schema, table string) (Structure, error)
Constants ¶
const ( KindQuery = "query" KindExplain = "explain" KindShow = "show" KindWrite = "write" )
Statement kinds the guard classifies an accepted statement into.
const ( EnvQueryTimeout = "APP_DB_QUERY_TIMEOUT" EnvQueryMaxRows = "APP_DB_QUERY_MAX_ROWS" EnvQueryMaxBytes = "APP_DB_QUERY_MAX_BYTES" EnvQueryMaxCell = "APP_DB_QUERY_MAX_CELL_BYTES" EnvSchemaMaxRows = "APP_DB_SCHEMA_MAX_ROWS" EnvQueryMaxSQL = "APP_DB_QUERY_MAX_SQL_BYTES" EnvHistoryKeep = "APP_DB_QUERY_HISTORY_KEEP" )
Environment variables that tune the console. Each has a default so an unset variable behaves the same on every install.
const ( OpContains = "contains" OpEquals = "equals" OpIsNull = "is_null" OpNotNull = "not_null" )
Filter operators accepted by a table page.
const MaxFilters = 8
MaxFilters bounds how many column filters one page request may combine.
Variables ¶
var ( ErrEmpty = errors.New("statement is empty") ErrMultiStatement = errors.New("only a single statement is allowed") ErrBackslash = errors.New("backslash is not allowed in console statements") ErrControlChar = errors.New("statement contains a control character") ErrUnterminated = errors.New("unterminated string, identifier, or comment") ErrExecutableComment = errors.New("executable comments are not allowed") ErrUnicodeEscape = errors.New("unicode escape syntax is not allowed") ErrNotAllowed = errors.New("statement type is not allowed in read-only mode") ErrDenied = errors.New("statement uses a function or keyword that is not allowed") )
Rejection reasons, exported so handlers can map them to a 400.
var ErrNotFound = errors.New("not found")
ErrNotFound reports a table or column the database does not have.
var ErrTimeout = errors.New("query exceeded the configured timeout")
ErrTimeout reports that the statement ran past the configured timeout.
Functions ¶
Types ¶
type Column ¶
type Column struct {
Name string `json:"name"`
Type string `json:"type"`
Nullable bool `json:"nullable"`
Default string `json:"default,omitempty"`
PrimaryKey bool `json:"primary_key"`
}
Column is one table column.
type Dialect ¶
type Dialect string
Dialect selects the lexing and deny-list rules for one SQL family.
type Evidence ¶
type Evidence struct {
DatabaseSizeBytes int64 `json:"database_size_bytes"`
SchemasScanned int `json:"schemas_scanned"`
UserTables int64 `json:"user_tables"`
ExcludedSchemas []string `json:"excluded_schemas"`
}
Evidence is what the catalog says about a database independent of the schema listing, so an empty listing can be checked against it.
type Execer ¶
type Execer interface {
ExecWithInput(ctx context.Context, containerID string, cmd []string, stdin io.Reader) (io.ReadCloser, error)
}
Execer is the slice of docker.Runtime the console needs.
type Filter ¶
type Filter struct {
Column string `json:"column"`
Op string `json:"op"`
Value string `json:"value"`
}
Filter restricts one column of a table page.
type ForeignKey ¶
type ForeignKey struct {
Name string `json:"name"`
Schema string `json:"schema"`
Table string `json:"table"`
Columns []string `json:"columns"`
RefSchema string `json:"ref_schema"`
RefTable string `json:"ref_table"`
RefColumns []string `json:"ref_columns"`
}
ForeignKey is one foreign key constraint. Schema and Table name the table that owns it; RefSchema and RefTable the table it points at.
type Index ¶
type Index struct {
Name string `json:"name"`
Definition string `json:"definition"`
Unique bool `json:"unique"`
Primary bool `json:"primary"`
}
Index is one table index.
type Limits ¶
type Limits struct {
Timeout time.Duration
MaxRows int
MaxBytes int
MaxCellBytes int
SchemaRows int
SQLBytes int
}
Limits bounds one console execution.
type PageQuery ¶
type PageQuery struct {
Schema, Table string
Limit, Offset int
SortColumn string
SortDesc bool
FilterColumn string
FilterOp string
FilterValue string
Filters []Filter
}
PageQuery asks for one page of a table. FilterColumn/FilterOp/FilterValue are the first filter; Filters adds more, all combined with AND.
type QueryError ¶
type QueryError struct{ Message string }
QueryError carries the database's own error text, which is safe to show: it describes the caller's statement and never contains credentials.
func (*QueryError) Error ¶
func (e *QueryError) Error() string
type RedisValue ¶
type RedisValue struct {
Type string `json:"type"`
TTL int64 `json:"ttl"`
Lines []string `json:"lines"`
Truncated bool `json:"truncated"`
}
RedisValue is a key's value rendered as text lines, capped by Limits.
type Result ¶
type Result struct {
Columns []string `json:"columns"`
Rows [][]*string `json:"rows"`
RowCount int `json:"row_count"`
Truncated bool `json:"truncated"`
DurationMs int64 `json:"duration_ms"`
}
Result is one statement's output. A nil cell is SQL NULL.
type SchemaNode ¶
SchemaNode groups tables under one schema (a MySQL database).
type Statement ¶
type Statement struct {
// SQL is the statement with its trailing semicolon removed.
SQL string
Kind string
Fingerprint string
// First is the lowercased leading keyword.
First string
}
Statement is a statement the guard accepted.
type Structure ¶
type Structure struct {
Schema string `json:"schema"`
Name string `json:"name"`
Kind string `json:"kind"`
RowEstimate int64 `json:"row_estimate"`
SizeBytes int64 `json:"size_bytes"`
Columns []Column `json:"columns"`
Indexes []Index `json:"indexes"`
ForeignKeys []ForeignKey `json:"foreign_keys"`
ReferencedBy []ForeignKey `json:"referenced_by"`
DDL string `json:"ddl"`
}
Structure is the full detail of one table, what the schema outline leaves out. ForeignKeys point away from the table, ReferencedBy point at it.
type Table ¶
type Table struct {
Name string `json:"name"`
Kind string `json:"kind"`
RowEstimate int64 `json:"row_estimate"`
SizeBytes int64 `json:"size_bytes"`
Columns []Column `json:"columns"`
Indexes []Index `json:"indexes"`
}
Table is a table, view, or other relation.
type Target ¶
type Target struct {
Exec Execer
ContainerID string
Dialect Dialect
Limits Limits
// External marks a database this platform does not run: Exec starts a
// helper that carries the connection, and ContainerID is unused.
External bool
}
Target is one running database container.
func (Target) Explain ¶
Explain returns the plan for a read statement as text lines (Postgres, MySQL, and MariaDB all accept an EXPLAIN prefix).
func (Target) Run ¶
Run executes a guard-approved statement. write must match the allowWrites value the statement was checked with.
func (Target) RunTrusted ¶
RunTrusted executes SQL the control plane built itself (introspection, table pages). It still runs in a read-only transaction.
func (Target) Schema ¶
func (t Target) Schema(ctx context.Context) ([]SchemaNode, error)
Schema lists every user schema with its tables, columns, and indexes.
func (Target) SchemaOutline ¶
func (t Target) SchemaOutline(ctx context.Context) ([]SchemaNode, error)
SchemaOutline lists every user schema with its tables, row estimates and sizes but no columns or indexes, so a database with thousands of tables stays a small document. Per-table detail comes from TableStructure.