db

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: GPL-3.0 Imports: 7 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FindMatch

func FindMatch[T any](in []T, pred func(T) bool) (T, bool)

FindMatch returns the first element of in for which pred is true, and whether one was found. It is the generic form of the per-domain "find the matching row in this slice" helpers (identity/absorbable/same-host lookups) so they need not each re-spell the loop.

func Preload

func Preload(database *gorm.DB, filts map[string]bool) *gorm.DB

Preload loads a database with the base clause.Associations preload plus every association named with a true value in filts (a false entry is skipped, so callers can gate a preload on a request flag). It is the map-driven form used when the set of associations is conditional; PreloadAll is the plainer variadic form for the unconditional case.

func PreloadAll

func PreloadAll(database *gorm.DB, names ...string) *gorm.DB

PreloadAll loads a database with the base clause.Associations preload plus each named association, unconditionally. It is the single place association preloading is expressed, so the per-domain servers do not each re-implement the clause.Associations + range loop.

func QueryToPBs added in v0.3.0

func QueryToPBs[O pbConvertible[P], P any](ctx context.Context, query *gorm.DB, single bool) ([]*P, error)

QueryToPBs runs a built query and returns the matching rows as their protobuf twins. It captures the tail every domain server's Read/List repeats verbatim: run First (single==true) or Find (single==false), treat gorm.ErrRecordNotFound as an empty result rather than an error (an unmatched filter is a valid "nothing here" answer the caller's len==0 branch renders, not a failure), then convert the ORM rows via ToPBs. The caller still owns everything type-specific — building/scoping/preloading the query and marshalling the typed request/response — so only the identical middle is shared. O is the ORM row type (e.g. *host.HostORM), P its protobuf twin.

func ScopeByHost added in v0.3.0

func ScopeByHost(query *gorm.DB, joinTable, objectFK, hostFK string, hostIDs *gorm.DB) *gorm.DB

ScopeByHost restricts a query to the objects attached to a given host — the second query-scoping axis, orthogonal to (and freely composable with) ScopeBySource: "only MY objects" narrows by the tool that contributed them, "only objects on THIS host" narrows by where they live. Chaining both answers "services contributed by nmap, on 10.0.0.0/24"-style questions in one round trip, and both shrink the result set (and so the wire payload) rather than changing what an object means.

Domains differ in how their objects reach a host, so the join is a parameter rather than baked in: joinTable is a table carrying BOTH a column referencing the queried object (objectFK) and one referencing its host (hostFK) — for services that is `ports` (service_id + host_id). hostIDs is the subquery selecting the host ids to scope to, as returned by host.IDsMatching; nil means the caller sent no host filter and the query is returned untouched, so a request's Host field can be threaded through unconditionally.

Not every domain fits this shape. Credentials reach a host through their provenance sources rather than a two-FK join table (sources.service_id -> ports.host_id), and use the Metasploit-style credential.WhereLoggedInHost scope instead; it is the same axis expressed through that domain's own path, not a second mechanism.

func ScopeBySource

func ScopeBySource(query *gorm.DB, joinTable, objectFK, tool string) *gorm.DB

ScopeBySource restricts a query to the objects contributed by the named tool, via that object's provenance m2m join (e.g. "host_sources"/"host_id"). An empty tool is a no-op, so callers can thread a request's Source filter through unconditionally. It is the one-liner wrapper the per-domain servers share instead of each repeating the same Scopes(...) block.

func ToPBs

func ToPBs[O pbConvertible[P], P any](ctx context.Context, in []O) ([]*P, error)

ToPBs converts a slice of ORM rows to pointers to their protobuf twins, returning the first conversion error rather than swallowing it. It replaces the identical ORM→PB range loop the domain servers each hand-rolled (and which discarded the ToPB error with `pb, _ :=`).

func WrapDBError added in v0.3.0

func WrapDBError(err error) error

WrapDBError maps a raw database (or other server-internal) error to a coded gRPC status, so a client never receives an ungraded/Unknown-coded gorm/sql error off a server/<domain> return site (audit finding R4). It is deliberately a single, simple policy: nil passes through unchanged; an error that already carries a gRPC status (e.g. an InvalidArgument a caller raised earlier in the same method) passes through unchanged too, so WrapDBError is safe to call defensively without risking a double-wrap or downgrading a status a caller deliberately chose; everything else — a failed query, a broken write, an ORM<->PB conversion error — becomes codes.Internal, since it reflects a server-side failure rather than a caller mistake.

gorm.ErrRecordNotFound is deliberately NOT special-cased to codes.NotFound here. The established convention on filtered Read/List paths (see QueryToPBs) is to swallow ErrRecordNotFound internally and return an empty, successful result: an unmatched filter is a valid "nothing here" answer the caller's len==0 branch renders, not a failure. QueryToPBs already implements that swallow, so any error reaching WrapDBError from a Read/List path is a real failure worth a coded status. A call site resolving a *required* row (e.g. a delete/update target that must already exist) may still special-case ErrRecordNotFound to codes.NotFound itself before calling WrapDBError, rather than letting it fall through to codes.Internal.

Types

This section is empty.

Jump to

Keyboard shortcuts

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