Skip to content

feat(query)!: harden structured SQL boundaries - #21

Open
abdul-kaioum wants to merge 11 commits into
mainfrom
security/sql-structure-hardening
Open

feat(query)!: harden structured SQL boundaries#21
abdul-kaioum wants to merge 11 commits into
mainfrom
security/sql-structure-hardening

Conversation

@abdul-kaioum

Copy link
Copy Markdown
Member

Description

Hardens wp-database 2.x across identifier rendering, structured clauses, joins, relationships, writes, and raw SQL. Adds typed identifier/operator/join/raw-template primitives and comprehensive regression coverage for SQL structure injection.

Motivation & Context

Prepared value bindings do not protect table names, columns, sort directions, operators, join types, or raw SQL fragments. This change makes those structural boundaries explicit, rejects malformed input early, and provides a typed raw-template API for the rare cases where raw SQL is required.

Type of Change

  • Security hardening
  • New typed query APIs
  • Intentional breaking validation changes
  • Tests and migration documentation

Security Behavior

  • Structured identifiers are validated and rendered by context.
  • Sort directions, operators, joins, groups, and write schemas reject unsupported structure.
  • Relationship definitions and pivot identifiers pass through the hardened compiler.
  • Empty prepared writes and hostile/ragged keys fail closed.
  • RawTemplate separates value bindings from typed identifiers and directions.
  • Explicit join aliases retain precedence while unshadowed base qualifiers resolve to the active FROM alias.

Breaking Changes

This PR intentionally rejects SQL structure that older versions accepted implicitly. See docs/breaking-changes.md and docs/usage.md for migration guidance. The branch alias is prepared for the 2.x line; no tag or release is created by this PR.

Verification

  • PHP 8.4: 500 tests, 784 assertions
  • PHP 8.5: 500 tests, 784 assertions
  • PHPCompatibility 8.0: 14/14 checked paths
  • Syntax, Composer validation/audit, code style, and diff checks passed during final review
  • Independent per-task and whole-branch security reviews completed

Checklist

  • Code follows project style and PHP 8 compatibility requirements
  • Self-review and independent security review completed
  • Regression and integration tests added
  • Breaking-change and usage documentation updated
  • No package tag or release published

Preserve logical-to-physical qualification while validating and quoting every structured column segment.

BREAKING CHANGE: unknown or schema-qualified names and pre-quoted structured identifiers now fail closed; register the table or alias, or use a reviewed raw API.
Validate finite operators, join types, identifiers, and boolean connectors before execution. Split join operands into column, bound-value, and explicit raw APIs.

BREAKING CHANGE: structured table declarations are quoted and ordinary join/on operands must be columns; use joinWhere/onValue for values and onRaw for expressions.
Compile UPDATE bindings in placeholder order, constrain operators by clause shape, reject unsupported FULL joins, and qualify bare columns through active base aliases.
Normalize array-valued WHERE and HAVING operators through the list boundary, compile empty lists safely, and reject undeclared base aliases on UPDATE and DELETE.
Keep generated relation aggregates, subqueries, and pivot projections in structured state so identifiers and aliases reach the shared renderer before execution.
Map logical and physical base-table qualifiers to the active SELECT alias at the rendering boundary, and document the strict quoted identifier behavior.
Resolve registered aliases before remapping hidden base-table qualifiers to the active FROM alias, preventing colliding join aliases from collapsing onto the base.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant