Skip to content

Releases: klinux/dbportal

v0.9.1

Choose a tag to compare

@klinux klinux released this 21 Sep 02:05

The Vault token is renewed from boot

Every datasource with a Vault credential failed at once after a quiet period: the deployment's periodic token had expired. Renewal ran only inside a Vault read, and a read happens only when such a datasource is resolved past the five-minute credential cache, so a 24-hour period could pass with nobody asking (docs/CONTEXT.md §4.5).

  • The token is now renewed in the background from boot, in the studio, the worker and the agent alike: a one-minute tick, each renewing only when half the lease has passed. The token lives as long as any pod does.
  • The first tick runs at boot, so an already-expired token is a warning (Vault token renewal failed, status 403) in the process's first minute rather than the first failed datasource.
  • A 403 at renewal is asked again in a minute instead of silencing the renewal for the life of the process; a 400 (a token Vault does not renew) is still asked once.

Recovery for a token that already expired: create a new periodic token (vault token create -policy=dbportal -period=24h -orphan), store it as vault_token, sync.

Image: ghcr.io/klinux/dbportal:0.9.1 · chart 0.1.35.

v0.9.0

Choose a tag to compare

@klinux klinux released this 21 Sep 01:41

The bot holds its own request, and the thread decides

Two additions to the bot API, POST /api/v1/executions (docs/CONTEXT.md §4.57):

  • review: { reason } holds the request for a reviewer whatever the datasource's policy would have let run, like a guardrail the bot raised itself. The reason (trimmed, at most 500 characters) is stored on the record, shown as a badge on the reviewers' page, in the Slack announcement and in what GET /api/v1/executions/[id] returns. 400 for a review without a reason.
  • The announcement goes into the request's thread. The "waiting for approval" message with its Approve/Reject buttons is posted into the thread the request named (reply) as well as to SLACK_APPROVALS_CHANNEL, so the team that watches the thread decides where the request was made. Either copy settles the request; the other answers "already decided" when pressed later. A deployment with no reviewers' channel still announces in the thread.

Nothing else moved: who may decide is still the datasource's approverRoles (Slack users through a named role with user:slack:<id> members), two reviewers still means two, and the outcome still lands in the thread.

Image: ghcr.io/klinux/dbportal:0.9.0 · chart 0.1.34.

v0.8.1

Choose a tag to compare

@klinux klinux released this 19 Sep 01:54

Monitoring follows the object rules

A statement somebody else ran was the one place a hidden name could still appear: the monitoring panel listed every table's statistics and every slow query and active session to anyone who could open the datasource.

  • The scoped provider now covers the five monitoring reads: a table's and an index's statistics by the table's address, and a slow query or an active session by the statement it carries, kept only when the same scanner the execution gate uses finds it names nothing hidden, and dropped when it cannot be read at all.
  • /api/db/monitoring and the agent's operations readings go through it. An engine with no containers reports an empty schema, so the address there is the name alone.

See docs/CONTEXT.md §4.56.

Image: ghcr.io/klinux/dbportal:0.8.1 · chart 0.1.33.

v0.8.0

Choose a tag to compare

@klinux klinux released this 19 Sep 01:26

Which objects each person sees, decided on the datasource

A datasource may now carry objects: rules of match (a name pattern) and roles (the same principal vocabulary as roles). With no rule nothing changes. With any, a person sees exactly the objects some rule they hold matches, and may name only those in a statement. An administrator always sees everything.

  • Patterns. Matched against the object's dotted path (public.orders, apim-2026.*) with * for any run and ? for one character, case-insensitively; a pattern with no dot matches the relation's own name in any schema, the natural spelling on a search cluster. A matched object covers what nests under it.
  • Visibility. Applied on the provider every object route reads through: the tree, the counts, the autocomplete, the schema diff and the agent's grounding show the same thing. A hidden object's detail is "not found", and the rules are never sent to the browser.
  • Enforcement. Every statement on /api/db/query, multi-query, transaction, maintenance, export (route and worker), profile, the bot's /api/v1/executions, an alert's run and the agent's statement runner is scanned for the relations it names; the first one outside the scope is refused with 403 and audited object_forbidden, with the fix: qualify the name, spell out the wildcard, or write a statement whose reach can be read (CALL, COPY, SYS are refused as unreadable rather than guessed at). MongoDB and Redis get visibility only.
  • Admin form. A rule list on the datasource sheet, pattern and principals per row. A virtual datasource can neither carry rules nor include a member that has any.
  • Agent. The persisted actor records the session's groups and named roles, so a drive judges the rules as the person who opened the run.

Limits, stated: the rules are the portal's; the datasource's credential still sees the whole engine, and monitoring's table statistics are not filtered yet. See docs/CONTEXT.md §4.56 and docs/SEED_CONNECTIONS.md "Object rules".

Image: ghcr.io/klinux/dbportal:0.8.0 · chart 0.1.32.

v0.7.2

Choose a tag to compare

@klinux klinux released this 19 Sep 00:20

Elasticsearch 6.x: no more "Invalid index name [_data_stream]"

On 6.x, GET /_data_stream and GET /_index_template are read as index names ("Invalid index name [data_stream], must not start with ''"), and that one refusal sank the whole object inventory the sidebar loads on connect, as a toast on every open.

  • Composable templates arrived in 7.8 and data streams in 7.9. The transport keeps the release it already reads for the SQL path (major and minor, once per connection) and answers those two listings with an empty list, without a request, on a cluster that predates the kind. Zero is the truth there: the objects are not in its model.
  • A cluster the client cannot date, or one naming another distribution, is asked and answers for itself.

See docs/providers/elasticsearch.md §3.12 and docs/CONTEXT.md §4.55.

Image: ghcr.io/klinux/dbportal:0.7.2 · chart 0.1.31.

v0.7.1

Choose a tag to compare

@klinux klinux released this 18 Sep 23:50

Elasticsearch 6.x

A 6.x cluster with SQL enabled refused the connect probe with HTTP 405 on /_sql: the cluster read _sql as an index name, because 6.x serves SQL at /_xpack/sql and the prefix only went away in 7.0.

  • The transport reads GET / once per connection, before the first statement, and takes /_xpack/sql when the payload names no other distribution and a major below 7. OpenSearch is at 3.x, so the number alone is not enough; an Elasticsearch connection pointed at OpenSearch still gets the measured refusal of /_sql.
  • The cursor close follows the same path; a refusal of / is reported as that refusal; an unreadable version takes the modern path.
  • The mapping read goes through the type level 6.x still has (mappings.<type>.properties), for the single and the bulk read alike.
  • The routing message no longer claims the SQL endpoint, since the same envelope answers a listing 6.x has no endpoint for (_index_template, _data_stream report the refusal as their unavailable reason).

Measured live: the 405 on /_sql and the 401 on /_xpack/sql. The rest is replay; see docs/providers/elasticsearch.md §3.12 and docs/CONTEXT.md §4.55.

Image: ghcr.io/klinux/dbportal:0.7.1 · chart 0.1.30.

0.7.0

Choose a tag to compare

@klinux klinux released this 18 Sep 13:54

Seed a MySQL datasource from its schema

Seeding from the schema (Operations → Seed from schemas) was PostgreSQL only. The same plan, panel and job now run on MySQL:

  • The catalog comes from information_schema, MySQL's types mapped onto the generators (tinyint(1)/bit(1) as booleans, DATETIME as a Date, ENUM and SET labels, AUTO_INCREMENT as the identity; a generated column is never written nor copied).
  • What MySQL has no spelling for is done another way: no RETURNING, so a batch's numbered keys are read back; no TRUNCATE CASCADE, so the tables are emptied with DELETE children first and the counters reset; ? binds and a bounded IN list for a copied sample.
  • The schema is the datasource's own database unless named; a sample is copied from a datasource of the same engine only.
  • The Seed tab now says which reason keeps a datasource out (the engine, or production).

Not verified against a live MySQL yet.

Image: ghcr.io/klinux/dbportal:0.7.0 · chart 0.1.29.

0.6.6

Choose a tag to compare

@klinux klinux released this 18 Sep 02:39

The environment beside every datasource's name

The same application lives in several environments under one name, and pickers that showed name and engine alone showed identical rows (two smb (mysql)). An environment tag now sits beside the name in the operations, monitoring, schema-diff, command-palette and mobile-header pickers; the seed-data and alerts option lists carry it as a suffix (smb · STAGING). A declared environment shows its label; one the list lacks shows its id.

Image: ghcr.io/klinux/dbportal:0.6.6 · chart 0.1.28.

0.6.5

Choose a tag to compare

@klinux klinux released this 18 Sep 02:20

MySQL account plan: what the bootstrap cannot pass on is said, not attempted

Measured on Cloud SQL for MySQL: the whole plan ran and the default user could not pass CONNECTION_ADMIN on, so the report ended on a refused optional grant. The plan now reads the global privileges the bootstrap holds with the grant option (dynamic ones included), leaves such a grant out, and shows a note before anything runs: what the account lacks (kill from the sessions panel, or the sessions of others) and the statement an administrator may run later.

Image: ghcr.io/klinux/dbportal:0.6.5 · chart 0.1.27.

0.6.4

Choose a tag to compare

@klinux klinux released this 18 Sep 01:57

The same datasource name in another environment

A new datasource's id was the slug of its name alone, so the same application in two environments (smb in production, smb in staging) could not be saved twice. The id is a key everywhere (seed:<id>, the Vault path, the audit target) and stays unique; the name is what people read and may repeat. When the slug is taken, the environment is appended (smb-staging), then a counter, and the toast says the id the datasource was created under.

Image: ghcr.io/klinux/dbportal:0.6.4 · chart 0.1.26.