queryaccess

package
v0.490.0 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

README

Domain Query Access Module

Transport-neutral domain types for query access analysis, including read classification, admission decisions, relation/column references, and permission requirements.

Files

File Responsibility
doc.go Declares the queryaccess package boundary
model.go Defines core domain types: Mode, ReadClassification, Admission, RelationKind, UsageContext, ReasonCode, WarningCode, and Result
normalize.go Pure deterministic helpers for mode normalization, classification folding, admission validation, sorting, deduplication, and result validation
model_test.go Verifies JSON round-trip, omitted empty fields, forbidden field absence, and constant correctness
normalize_test.go Verifies each normalize function independently with edge cases

Exports

  • Mode
    • ModeStrict
    • ModeProjectionOnly
  • ReadClassification
    • ReadOnly
    • NotReadOnly
    • Indeterminate
  • Admission
    • Admissible
    • Rejected
    • IndeterminateAdmission
  • RelationKind
    • RelationTable
    • RelationView
    • RelationCTE
    • RelationDerived
  • UsageContext
    • UsageProjection
    • UsageFilter
    • UsageJoin
    • UsageGrouping
    • UsageHaving
    • UsageOrdering
    • UsageWindow
  • ReasonCode
    • ReasonParseFailure
    • ReasonUnsupportedDialect
    • ReasonWriteOperation
    • ReasonMultiStatement
    • ReasonSchemaUnavailable
    • ReasonAmbiguousReference
    • ReasonFunctionEffect
    • ReasonUnprovenOperatorEffect
    • ReasonUnprovenFunctionEffect
    • ReasonUnprovenCastEffect
    • ReasonIdentityResolverUnavailable
    • ReasonIdentityUnknown
    • ReasonIdentityLookupFailed
    • ReasonIdentityAmbiguous
    • ReasonIdentityCoercionGap
  • IdentityFailure
    • IdentityFailureUnavailable
    • IdentityFailureUnknown
    • IdentityFailureError
    • IdentityFailureAmbiguous
    • IdentityFailureCoercionGap
  • IdentityStatus (per-candidate resolver outcome; includes resolved)
    • IdentityStatusResolved
    • IdentityStatusUnknown
    • IdentityStatusAmbiguous
    • IdentityStatusCoercionGap
    • IdentityStatusLookupFailed
    • IdentityStatusUnavailable
  • WarningCode
    • WarningAmbiguousColumn
    • WarningMissingSchema
    • WarningDeprecatedSyntax
    • WarningInferenceRisk
  • RelationReference
    • Unbound field: marks relations that must not produce physical requirements or be resolved against DefaultSchema
  • ColumnReference
    • Unbound field: inherited marker for columns referencing unbound relations
  • OutputColumn
  • Requirement
  • Unresolved
  • Result
  • NormalizeMode()
  • ValidateMode()
  • FoldReadClassification()
  • ValidateAdmission()
  • SortRelations()
  • SortColumns()
  • SortRequirements()
  • DeduplicateUsages()
  • DeduplicateReasonCodes()
  • NormalizeReasonCodes()
  • ReasonForIdentityFailure()
  • ValidIdentityStatus()
  • IdentityStatusIsFailClosed()
  • IdentityStatusToFailure()
  • ReasonForIdentityStatus()
  • ValidateResult()
  • FormatRelationKey()
  • FormatColumnKey()

Notes

  • All types use json struct tags with omitempty for optional fields.
  • Result intentionally excludes raw SQL, severity, literal, password, and credential fields.
  • Sorting functions return new slices; they do not mutate input.
  • FoldReadClassification priority: not_read_only > indeterminate > read_only.
  • ValidateAdmission rejects admissible + non-read_only combinations.
  • Unproven-effect reason codes (unproven_*, identity_*) are additive machine identifiers only; they never embed SQL, OIDs, object names, or driver errors.
  • ReasonForIdentityFailure maps only bounded IdentityFailure categories; free-text cannot be injected as a trusted reason.
  • IdentityStatus is the per-candidate resolver outcome enum (resolved + fail-closed statuses). lookup_failed maps to IdentityFailureError / identity_lookup_failed. Free-text statuses are invalid. resolved is not a trust claim.

Dependencies

  • Upstream: internal/application/queryaccess
  • Downstream: none inside the domain core

Update Rule

  • If members/interfaces/dependencies change, update this file in same change.

Documentation

Overview

Package queryaccess defines transport-neutral domain types for query access analysis. input: SQL statement references, relation references, column references, and usage contexts output: pure domain models for query access requirements, read classification, and admission decisions pos: domain model for the query access analysis foundation shared across CLI, HTTP, and MCP surfaces note: if this file changes, update this header and module README.md.

Package queryaccess defines transport-neutral domain types for query access analysis. input: SQL statement references, relation references, column references, and usage contexts output: pure domain models for query access requirements, read classification, and admission decisions pos: domain model for the query access analysis foundation shared across CLI, HTTP, and MCP surfaces note: if this file changes, update this header and module README.md.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrInvalidMode indicates the mode is not a recognized value.
	ErrInvalidMode = errors.New("invalid mode: must be strict or projection_only")
	// ErrInvalidAdmission indicates an invalid admission/classification combination.
	ErrInvalidAdmission = errors.New("invalid admission: admissible requires read_only classification")
	// ErrUnknownAdmission indicates an unrecognized admission value.
	ErrUnknownAdmission = errors.New("unknown admission value")
	// ErrForbiddenField indicates the result contains a forbidden field.
	ErrForbiddenField = errors.New("result contains forbidden field")
)

Functions

func FormatColumnKey

func FormatColumnKey(schema, table, column string) string

FormatColumnKey returns a canonical "schema.table.column" or "table.column" key for a column.

func FormatRelationKey

func FormatRelationKey(schema, name string) string

FormatRelationKey returns a canonical "schema.name" or "name" key for a relation.

func IdentityStatusIsFailClosed added in v0.390.0

func IdentityStatusIsFailClosed(s IdentityStatus) bool

IdentityStatusIsFailClosed reports whether the status forbids pure-read promotion for that candidate. Only resolved is non-fail-closed; free-text and empty statuses are treated as fail-closed.

func ValidIdentityStatus added in v0.390.0

func ValidIdentityStatus(s IdentityStatus) bool

ValidIdentityStatus reports whether s is a known bounded identity status. Free-text and empty strings return false.

func ValidateAdmission

func ValidateAdmission(rc ReadClassification, adm Admission) error

ValidateAdmission rejects invalid admission/classification combinations. Admissible requires read_only classification. Unknown admission values are rejected.

func ValidateMode

func ValidateMode(m Mode) error

ValidateMode checks whether the mode is a recognized value.

func ValidateResult

func ValidateResult(r *Result) error

ValidateResult checks the result for forbidden fields and structural invariants.

Types

type Admission

type Admission string

Admission describes whether SQL is eligible for caller authorization.

const (
	// Admissible indicates the statement is eligible for authorization checks.
	Admissible Admission = "admissible"
	// Rejected indicates the statement is not eligible for authorization checks.
	Rejected Admission = "rejected"
	// IndeterminateAdmission indicates the admission status could not be determined.
	IndeterminateAdmission Admission = "indeterminate"
)

type ColumnReference

type ColumnReference struct {
	Schema  string         `json:"schema,omitempty"`
	Table   string         `json:"table"`
	Column  string         `json:"column"`
	Usages  []UsageContext `json:"usages"`
	Unbound bool           `json:"unbound,omitempty"`
}

ColumnReference represents a source column reference with usage contexts.

func SortColumns

func SortColumns(refs []ColumnReference) []ColumnReference

SortColumns sorts column references by schema+table+column+usages for deterministic output.

type IdentityFailure added in v0.390.0

type IdentityFailure string

IdentityFailure is a bounded category for effect-identity resolution outcomes. Callers map transport/catalog errors to these categories before attaching a reason code; free-text error strings must never become reason codes.

const (
	// IdentityFailureUnavailable means no identity resolver was configured.
	IdentityFailureUnavailable IdentityFailure = "unavailable"
	// IdentityFailureUnknown means the resolver returned unknown / no rows.
	IdentityFailureUnknown IdentityFailure = "unknown"
	// IdentityFailureError means the resolver hit a transport or catalog error.
	IdentityFailureError IdentityFailure = "error"
	// IdentityFailureAmbiguous means multi-match non-unique identity.
	IdentityFailureAmbiguous IdentityFailure = "ambiguous"
	// IdentityFailureCoercionGap means required coercion is unsupported.
	IdentityFailureCoercionGap IdentityFailure = "coercion_gap"
)

func IdentityStatusToFailure added in v0.390.0

func IdentityStatusToFailure(s IdentityStatus) (IdentityFailure, bool)

IdentityStatusToFailure maps a non-resolved bounded status to IdentityFailure. Resolved and free-text statuses return false (callers must not invent failures from success or inject error strings).

type IdentityStatus added in v0.390.0

type IdentityStatus string

IdentityStatus is the bounded per-candidate outcome of effect-identity resolution. It extends IdentityFailure with a success value (resolved). Free-text strings are never valid statuses; unknown strings map to fail-closed via helpers.

Naming aligns with public identity_* reason codes where possible: lookup_failed (status) ↔ IdentityFailureError ("error") ↔ identity_lookup_failed.

const (
	// IdentityStatusResolved means a unique catalog identity was established.
	// Facts may be present; this is NOT a trust claim.
	IdentityStatusResolved IdentityStatus = "resolved"
	// IdentityStatusUnknown means no matching catalog row / no unique identity.
	IdentityStatusUnknown IdentityStatus = "unknown"
	// IdentityStatusAmbiguous means multi-match non-unique identity.
	IdentityStatusAmbiguous IdentityStatus = "ambiguous"
	// IdentityStatusCoercionGap means required coercion is outside the bounded graph.
	IdentityStatusCoercionGap IdentityStatus = "coercion_gap"
	// IdentityStatusLookupFailed means transport/catalog error during lookup.
	IdentityStatusLookupFailed IdentityStatus = "lookup_failed"
	// IdentityStatusUnavailable means no identity resolver was configured or usable.
	IdentityStatusUnavailable IdentityStatus = "unavailable"
)

type Mode

type Mode string

Mode controls which column references become requirements.

const (
	// ModeStrict requires all referenced columns to be authorized.
	ModeStrict Mode = "strict"
	// ModeProjectionOnly requires only projected (SELECT-list) columns to be authorized.
	ModeProjectionOnly Mode = "projection_only"
)

func NormalizeMode

func NormalizeMode(m Mode) Mode

NormalizeMode defaults empty mode to strict.

type OutputColumn

type OutputColumn struct {
	Name    string   `json:"name"`
	Sources []string `json:"sources"`
}

OutputColumn represents a final output column with source lineage.

func SortOutputs

func SortOutputs(outputs []OutputColumn) []OutputColumn

SortOutputs sorts output columns by name for deterministic output.

type ReadClassification

type ReadClassification string

ReadClassification describes whether SQL is demonstrably read-only.

const (
	// ReadOnly indicates the statement contains no write operations.
	ReadOnly ReadClassification = "read_only"
	// NotReadOnly indicates the statement contains at least one write operation.
	NotReadOnly ReadClassification = "not_read_only"
	// Indeterminate indicates the read-only status could not be determined.
	Indeterminate ReadClassification = "indeterminate"
)

func FoldReadClassification

func FoldReadClassification(classifications []ReadClassification) ReadClassification

FoldReadClassification folds multi-statement read classifications into a single result. Rules: any not_read_only → not_read_only; any indeterminate → indeterminate; all read_only → read_only.

type ReasonCode

type ReasonCode string

ReasonCode is a bounded machine identifier for why something is indeterminate or rejected. Reason codes are stable machine identifiers only: never SQL text, object names, function/operator/cast spellings, OIDs, literals, credentials, or driver errors.

const (
	// ReasonParseFailure indicates the statement could not be parsed.
	ReasonParseFailure ReasonCode = "parse_failure"
	// ReasonUnsupportedDialect indicates the dialect is not supported.
	ReasonUnsupportedDialect ReasonCode = "unsupported_dialect"
	// ReasonWriteOperation indicates a write operation was detected.
	ReasonWriteOperation ReasonCode = "write_operation"
	// ReasonMultiStatement indicates multiple statements were provided.
	ReasonMultiStatement ReasonCode = "multi_statement"
	// ReasonSchemaUnavailable indicates schema metadata was not available.
	ReasonSchemaUnavailable ReasonCode = "schema_unavailable"
	// ReasonAmbiguousReference indicates a reference could not be uniquely resolved.
	ReasonAmbiguousReference ReasonCode = "ambiguous_reference"
	// ReasonFunctionEffect indicates a function call with unknown side effects.
	// Used by MySQL/TiDB empty-allowlist path (legacy name).
	ReasonFunctionEffect ReasonCode = "unknown_function_effect"

	// ReasonUnprovenOperatorEffect indicates an operator expression was present
	// but its catalog identity was not proven trusted for pure-read admission.
	ReasonUnprovenOperatorEffect ReasonCode = "unproven_operator_effect"
	// ReasonUnprovenFunctionEffect indicates a function or aggregate call was
	// present but its catalog identity was not proven trusted.
	ReasonUnprovenFunctionEffect ReasonCode = "unproven_function_effect"
	// ReasonUnprovenCastEffect indicates a cast expression was present but its
	// cast path identity was not proven trusted.
	ReasonUnprovenCastEffect ReasonCode = "unproven_cast_effect"

	// ReasonIdentityResolverUnavailable indicates effect-identity resolution was
	// required but no identity resolver was configured.
	ReasonIdentityResolverUnavailable ReasonCode = "identity_resolver_unavailable"
	// ReasonIdentityUnknown indicates the resolver returned an unknown / no-match identity.
	ReasonIdentityUnknown ReasonCode = "identity_unknown"
	// ReasonIdentityLookupFailed indicates the resolver failed with a transport or catalog error.
	// Public results must never embed the underlying error text.
	ReasonIdentityLookupFailed ReasonCode = "identity_lookup_failed"
	// ReasonIdentityAmbiguous indicates multi-match identity resolution (non-unique).
	ReasonIdentityAmbiguous ReasonCode = "identity_ambiguous"
	// ReasonIdentityCoercionGap indicates type coercion required for unique identity
	// is outside the supported bounded resolution graph.
	ReasonIdentityCoercionGap ReasonCode = "identity_coercion_gap"

	// ReasonUnqualifiedRelationBlocked indicates that an unqualified relation
	// was present in a PostgreSQL query with a trusted bundle, which blocks
	// promotion to admissible due to search_path ambiguity.
	ReasonUnqualifiedRelationBlocked ReasonCode = "unqualified_relation_blocked"

	// ReasonViewExpansionRequired indicates that a query involves a view
	// whose definition must be expanded to determine base-table requirements.
	// Without view expansion, the query cannot be promoted to admissible
	// because hidden reads may exist that requirements cannot cover.
	ReasonViewExpansionRequired ReasonCode = "view_expansion_required"

	// ReasonUnsupportedTraversal indicates that a SQL clause could not be fully
	// traversed. Emitted for JOIN USING clauses where column names require
	// catalog resolution, and for unhandled AST node types that may contain
	// hidden expression subnodes with operators/functions/casts.
	ReasonUnsupportedTraversal ReasonCode = "unsupported_traversal"
)

func DeduplicateReasonCodes added in v0.390.0

func DeduplicateReasonCodes(codes []ReasonCode) []ReasonCode

DeduplicateReasonCodes removes duplicate reason codes, preserving first-seen order.

func NormalizeReasonCodes added in v0.390.0

func NormalizeReasonCodes(codes []ReasonCode) []ReasonCode

NormalizeReasonCodes deduplicates and sorts reason codes for stable public output.

func ReasonForIdentityFailure added in v0.390.0

func ReasonForIdentityFailure(f IdentityFailure) (ReasonCode, bool)

ReasonForIdentityFailure maps a bounded identity-failure category to a stable reason code. Unknown categories return false so callers cannot inject free-text or ad-hoc strings as trusted reasons.

func ReasonForIdentityStatus added in v0.390.0

func ReasonForIdentityStatus(s IdentityStatus) (ReasonCode, bool)

ReasonForIdentityStatus maps a non-resolved bounded status to a reason code. Resolved and free-text statuses return false so callers cannot inject arbitrary strings as trusted reasons. Resolved never yields a reason code from this helper (trust/promotion is a later policy step).

func SortReasonCodes

func SortReasonCodes(codes []ReasonCode) []ReasonCode

SortReasonCodes sorts reason codes for deterministic output.

type RelationKind

type RelationKind string

RelationKind describes the type of relation reference.

const (
	// RelationTable indicates a base table reference.
	RelationTable RelationKind = "table"
	// RelationView indicates a view reference.
	RelationView RelationKind = "view"
	// RelationCTE indicates a common table expression reference.
	RelationCTE RelationKind = "cte"
	// RelationDerived indicates a derived table (subquery) reference.
	RelationDerived RelationKind = "derived"
)

type RelationReference

type RelationReference struct {
	Schema             string       `json:"schema,omitempty"`
	Name               string       `json:"name"`
	Alias              string       `json:"alias,omitempty"`
	Kind               RelationKind `json:"kind"`
	PermissionRequired bool         `json:"permission_required"`
	Unbound            bool         `json:"unbound,omitempty"`
}

RelationReference represents a permission-bearing relation read by the query.

func SortRelations

func SortRelations(refs []RelationReference) []RelationReference

SortRelations sorts relation references by schema+name+alias+kind for deterministic output.

type Requirement

type Requirement struct {
	Object    string `json:"object"`
	Privilege string `json:"privilege"`
}

Requirement represents a permission the caller must authorize.

func SortRequirements

func SortRequirements(reqs []Requirement) []Requirement

SortRequirements sorts requirements by object+privilege for deterministic output.

type Result

type Result struct {
	Dialect            string              `json:"dialect"`
	Mode               Mode                `json:"mode"`
	ReadClassification ReadClassification  `json:"read_classification"`
	Admission          Admission           `json:"admission"`
	ReasonCodes        []ReasonCode        `json:"reason_codes,omitempty"`
	Relations          []RelationReference `json:"relations,omitempty"`
	ReferencedColumns  []ColumnReference   `json:"referenced_columns,omitempty"`
	Outputs            []OutputColumn      `json:"outputs,omitempty"`
	Requirements       []Requirement       `json:"requirements,omitempty"`
	Unresolved         []Unresolved        `json:"unresolved,omitempty"`
	Warnings           []WarningCode       `json:"warnings,omitempty"`
}

Result is the complete query access analysis result.

type Unresolved

type Unresolved struct {
	Reference string     `json:"reference"`
	Reason    ReasonCode `json:"reason"`
}

Unresolved represents a reference that could not be resolved.

func SortUnresolved

func SortUnresolved(unresolved []Unresolved) []Unresolved

SortUnresolved sorts unresolved references by reference+reason for deterministic output.

type UsageContext

type UsageContext string

UsageContext describes how a source column is used.

const (
	// UsageProjection indicates the column appears in the SELECT list.
	UsageProjection UsageContext = "projection"
	// UsageFilter indicates the column appears in a WHERE clause or aggregate FILTER clause.
	UsageFilter UsageContext = "filter"
	// UsageJoin indicates the column appears in a JOIN condition.
	UsageJoin UsageContext = "join"
	// UsageGrouping indicates the column appears in a GROUP BY clause.
	UsageGrouping UsageContext = "grouping"
	// UsageHaving indicates the column appears in a HAVING clause.
	UsageHaving UsageContext = "having"
	// UsageOrdering indicates the column appears in an ORDER BY clause.
	UsageOrdering UsageContext = "ordering"
	// UsageWindow indicates the column appears in a window PARTITION BY or frame bound.
	UsageWindow UsageContext = "window"
	// UsageDistinctOn indicates the column appears in a DISTINCT ON clause.
	UsageDistinctOn UsageContext = "distinct_on"
	// UsageLimit indicates the column appears in a LIMIT or OFFSET expression.
	UsageLimit UsageContext = "limit"
)

func DeduplicateUsages

func DeduplicateUsages(usages []UsageContext) []UsageContext

DeduplicateUsages deduplicates usage contexts preserving first-seen order.

type WarningCode

type WarningCode string

WarningCode is a bounded machine identifier for warnings.

const (
	// WarningAmbiguousColumn indicates a column reference matched multiple relations.
	WarningAmbiguousColumn WarningCode = "ambiguous_column"
	// WarningMissingSchema indicates the default schema was not specified.
	WarningMissingSchema WarningCode = "missing_schema"
	// WarningDeprecatedSyntax indicates deprecated SQL syntax was encountered.
	WarningDeprecatedSyntax WarningCode = "deprecated_syntax"
	// WarningInferenceRisk indicates projection-only mode may leak data via non-projected columns.
	WarningInferenceRisk WarningCode = "projection_only_inference_risk"
)

func SortWarningCodes

func SortWarningCodes(codes []WarningCode) []WarningCode

SortWarningCodes sorts warning codes for deterministic output.

Jump to

Keyboard shortcuts

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