dalgo2openvaultdb

package module
v0.4.12 Latest Latest
Warning

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

Go to latest
Published: Nov 9, 2026 License: MIT Imports: 24 Imported by: 0

README

dalgo2openvaultdb

A DALgo driver for OpenVaultDB.

It talks to an ovdb serve HTTP server over its REST API (/v1/...). The driver uses only the Go standard library — no third-party HTTP client.

Usage

import (
    "context"
    "github.com/dal-go/dalgo/dal"
    dalgo2openvaultdb "github.com/dal-go/dalgo2openvaultdb"
)

db, err := dalgo2openvaultdb.NewDB("http://127.0.0.1:6832", "sneat-dev")
if err != nil {
    log.Fatal(err)
}

// Direct read (no transaction required)
key := dal.NewKeyWithID("contacts", "c1")
data := &ContactData{}
rec := dal.NewRecordWithData(key, data)
if err := db.Get(ctx, rec); err != nil {
    log.Fatal(err)
}
if rec.Exists() {
    fmt.Println(data.Name)
}

// Write — must be inside a transaction
err = db.RunReadwriteTransaction(ctx, func(ctx context.Context, tx dal.ReadwriteTransaction) error {
    rec := dal.NewRecordWithData(dal.NewKeyWithID("contacts", "c2"), &ContactData{Name: "Bob"})
    return tx.Set(ctx, rec)
}, dal.TxWithMessage("create Bob"))
Custom HTTP client
db, err := dalgo2openvaultdb.NewDB("http://127.0.0.1:6832", "sneat-dev",
    dalgo2openvaultdb.WithHTTPClient(&http.Client{Timeout: 5 * time.Second}))
Guarded reads for an operator-bound credential

When an operator, not the caller, decides where a bearer token may be sent (for example a CLI daemon that reads OVDB on behalf of one local session), use WithGuardedReads:

db, err := dalgo2openvaultdb.NewDB(baseURL, "crm",
    dalgo2openvaultdb.WithBearerToken(token),
    dalgo2openvaultdb.WithGuardedReads("alice"))

The DB then only runs structured queries, and only for a context whose access.Principal has the legacy ID "alice" and no Subject. Queries go to the ACL-evaluated /v1/databases/{db}/tugql route as TugQL. A 401/403 the server explains comes back as *AuthorizationError (its Decision is the validated tugql/authorization result; it wraps access.ErrAccessDenied). Requests are capped at 1 MiB, responses at 8 MiB and each query at 10 s; redirects are refused; the response must be one JSON object without duplicate keys; record keys must be <collection>/<escaped id>; errors never include response text, the URL or the token. Get, Exists, GetMulti and transactions return dal.ErrNotSupported. NewDB rejects a base URL that is not plain http(s) (user info, query or fragment), a database ID with path characters or padding, and an empty token or principal.

Supported DALgo capabilities

Capability Status
Get / Exists / GetMulti supported
RunReadonlyTransaction supported (pass-through reads)
RunReadwriteTransaction supported (client-side buffer → POST /batch)
Set / Insert / Delete (in tx) supported
Update (in tx, field-level) supported
SetMulti / InsertMulti / DeleteMulti supported
UpdateRecord / UpdateMulti supported
Incomplete-key Insert (auto-ID) supported (random 16-char string, 5 retries)
ExecuteQueryToRecordsReader supported
Structured query: From, Where, OrderBy, Limit supported
Query Where operators: ==, <, <=, >, >=, In supported
Query WhereInArrayField / WhereArrayContains supported (array-contains)
Query WhereArrayContainsAny supported (array-contains-any via FieldRef In Array)
Query direct field projections (FieldRef) supported (trimmed client-side)
Read-your-writes in same transaction (Set/Insert) supported (buffer)
SupportsConcurrentConnections() true (HTTP pooling)
Schema() returns nil (schemaless)
Unsupported
Update preconditions ErrNotSupported
ExecuteQueryToRecordsetReader ErrNotSupported
Query cursors / StartFrom ErrNotSupported
Query Offset ErrNotSupported
Query expression, aggregate, wildcard, and nested field projections ErrNotSupported
Query GroupBy / Having ErrNotSupported
Collection-group queries not supported by OpenVaultDB MVP
Cross-transaction isolation / optimistic concurrency not in OpenVaultDB MVP
Read-your-writes for Update ops inside same tx server resolves in batch order

Direct field projections are applied by the client adapter after the regular OpenVaultDB query response arrives. The HTTP query API has no projection parameter, so this does not reduce the fields transferred over HTTP. The server remains authoritative for authorization, and the adapter removes unselected fields before returning records to DALgo callers. Aggregate queries may use these projections as source reads and calculate results in DALgo; aggregates themselves are not sent to OpenVaultDB.

Source rights and live-read evidence

Query readers preserve optional sourceRights and usedSourceIds inventories. Use dal.ReadQueryMetadata(reader) before Next to read a detached snapshot, including attribution, original free-source links and transformations. Omitted metadata remains unknown; supplied empty arrays remain known-empty. Source usage comes from execution metadata, including empty results and projected-away fields. These inventories describe source terms, not a licence assigned to query output.

For an independently admitted proxy query, call RequireProviderReads(ctx, plan, admittedUsedSourceIDs) before executing it. The providerreads.Plan must come from trusted admission metadata, separately from the response, and bind the expected executor, database, collection, original resource, definition, decoder and complete source rights. Supply independently admitted actual-use expectations and a fresh 32-character lowercase hex execution ID for each query. The returned context is for that single query execution.

The adapter freezes the plan and usage expectations, sends OVDB-Execution-ID and request Cache-Control: no-store, refuses redirects, caps the response at 4 MiB and caps the HTTP client timeout at ten seconds. It requires response no-store and validates full rights/usage equality plus the closed ovdb-provider-read/1 envelope before parsing records or returning a reader. Missing or malformed required evidence fails closed, including on empty results. Required-mode response, metadata and row-decoding failures use fixed errors without response content or an underlying decoder cause. The trusted dal.ErrNoMoreRecords sentinel is preserved. Optional legacy diagnostics retain their existing behavior. ReadProviderReads(reader) returns a detached envelope with reference date, fetch time, consumed-body digest and byte count. It carries executor observations; it does not certify immutable live input or grant source rights.

Without the required context, supplied envelopes are decoded and preserved as provider claims. They are not checked against independent admission. The strict path supports direct structured adapter queries, including transaction query methods. DALgo's generic joins, aggregation and federation are outside this admitted route; generic wrappers can omit adapter-local capabilities. Consumers must require ReadProviderReads on the returned reader before accessing data. No source activation, retained-copy fallback or data persistence is provided by this capability. Callers remain responsible for trusted endpoint selection and their own storage, cache, logging and result-lifetime controls.

Local development

  1. Start the server:
    ovdb serve --db-path ./local-data sneat-dev
    
  2. Point the driver at it:
    db, _ := dalgo2openvaultdb.NewDB("http://127.0.0.1:6832", "sneat-dev")
    
  3. Run tests:
    go test ./...
    

Releases

Every push to main that passes CI is tagged automatically by the shared strongo/cicd workflow's Bump version job. The next SemVer comes from the conventional commits since the last tag: feat: → minor, a breaking change → minor while the module is v0, and anything else (including fix:, ci:, docs:, chore:) → patch. PR titles must therefore be conventional. Do not push version tags by hand — the bumper would mint a second version on the same commit.

Documentation

Overview

Package dalgo2openvaultdb provides a DALgo driver for OpenVaultDB.

Use NewDB to create a dal.DB that talks to an OpenVaultDB server over HTTP. Reads (Get, Exists, GetMulti, queries) are available directly on the DB. Writes must happen inside a RunReadwriteTransaction callback.

Package dalgo2openvaultdb implements the DALgo driver for OpenVaultDB.

Index

Constants

View Source
const (
	GuardedMaxRequestBytes  = 1 << 20
	GuardedMaxResponseBytes = 8 << 20
	GuardedQueryTimeout     = 10 * time.Second
)

Bounds of the guarded read profile (see WithGuardedReads).

Variables

This section is empty.

Functions

func NewDB

func NewDB(baseURL, databaseID string, opts ...Option) (dal.DB, error)

NewDB creates a new DALgo DB backed by OpenVaultDB. The returned dal.DB is sealed by dal.NewDB: every read-write transaction it starts hands the worker a transaction whose writes run the framework's BeforeSave validation and hooks before reaching this adapter's code.

db, err := dalgo2openvaultdb.NewDB("http://127.0.0.1:6832", "sneat-dev")

func ReadProviderReads added in v0.4.0

func ReadProviderReads(reader dal.Reader) (providerreads.Envelope, bool)

ReadProviderReads returns detached executor-observed evidence when supplied. Without RequireProviderReads, this is a decoded provider claim, not evidence checked against independent admission. DALgo's generic metadata carries rights; this adapter-local capability carries the additional live-read envelope.

func RequireProviderReads added in v0.4.0

func RequireProviderReads(ctx context.Context, plan providerreads.Plan, usedSourceIDs []string) (context.Context, error)

RequireProviderReads freezes independently admitted evidence for one query execution. Never construct plan or usedSourceIDs from the query response. The returned context requires proxy evidence and no-store before any reader is returned. Give each execution a fresh 32-character lowercase hex ID. This capability does not grant source rights or activate a live source.

Types

type AuthorizationError added in v0.4.0

type AuthorizationError struct{ Decision az.Result }

AuthorizationError carries the server's validated structured denial. Its Error string is deliberately generic so it is safe to show to callers.

func (*AuthorizationError) Error added in v0.4.0

func (*AuthorizationError) Error() string

func (*AuthorizationError) Unwrap added in v0.4.0

func (*AuthorizationError) Unwrap() error

type Option

type Option func(*database)

Option configures a DB created by NewDB.

func WithBearerToken added in v0.2.0

func WithBearerToken(token string) Option

WithBearerToken sends the token as an Authorization: Bearer header on every request — required when the server runs `ovdb serve --auth` (either the owner token or an app token from the connect flow).

func WithGuardedReads added in v0.4.0

func WithGuardedReads(principalID string) Option

WithGuardedReads turns the DB into a read-only, query-only source for a credential bound to one principal — the profile a host uses when an operator, not the caller, configures where a bearer token may be sent.

Every query must run in a context whose access.Principal has no Subject and the legacy ID principalID; any other caller is refused with access.ErrAccessDenied before a request is made. Queries are serialized as TugQL and sent to the ACL-evaluated /tugql route. A 401/403 decision the server explains is returned as *AuthorizationError. Requests are capped at GuardedMaxRequestBytes, responses at GuardedMaxResponseBytes, each query at GuardedQueryTimeout; redirects are refused, the response must be a JSON object without duplicate keys, and no error carries response text, the URL or the token. Get, Exists, GetMulti, transactions and recordset readers return dal.ErrNotSupported.

NewDB validates the target when this option is set: an http(s) base URL without user info, query or fragment, a database ID without path characters or padding, and a non-empty bearer token.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient sets a custom *http.Client. If not provided, http.DefaultClient is used.

Jump to

Keyboard shortcuts

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