# v0.87.9 - Core Lifecycle Security

> **Status:** Planned
> **Scope:** 6 person-weeks
> **User promise:** *"An owner can manage a stream table without private-schema grants."*
> **Blocked by:** [v0.87.8](v0.87.8.md)
> **Program:** [Lifecycle security reimplementation](../plans/pg_trickle_lifecycle_security_reimplementation_plan.md)

## Theme

Fix issue #941 for create-or-replace, alter, and drop. Public entry points may
use a pinned `SECURITY DEFINER` path only after they capture the original caller
and resolve caller-controlled names under that caller's context.

Privileged phases accept canonical OIDs and quoted catalog-derived identifiers.
Create and alter run defining SQL as the stream owner. Drop authorizes the
complete dependency plan before the first mutation.

## Scope allocation

| Work package | Person-weeks |
|---|---:|
| Canonical resolution and prepared lifecycle plans | 1.25 |
| Create-or-replace and alter hardening | 1.50 |
| Atomic cascade and bulk-ready drop planning | 1.00 |
| Lifecycle, exploit, rollback, upgrade, and documentation tests | 2.25 |
| **Total** | **6.00** |

## Items

### LSEC-7: Canonical caller-context resolution

Resolve existing relations through PostgreSQL under the caller role and path.
Resolve new targets through the caller's effective schema. After resolution,
private phases use only OIDs or one shared qualified-identifier type.

Remove ad hoc dotted-name splitting, hard-coded `public`, and definer-context
`current_schema()` from the affected paths.

### LSEC-8: Prepared create and alter phases

Preflight source `SELECT`, source-schema `USAGE`, target-schema `CREATE`, query
validation, and dependency resolution as the caller. Create private state as
the definer, transfer storage ownership before population, execute population
as owner, and finalize private state last.

Alter preserves the exact pre-change owner across every storage recreation.
Query migration, partition-key changes, mode changes, and full repopulation
remain atomic.

### LSEC-9: Fully authorized drop plans

Build a deterministic child-first plan without mutation. Deduplicate targets,
detect cycles, and check every affected stream table against the original
caller. Reject the complete operation before dropping anything when one target
is unauthorized.

## Required tests

- Minimal-grant fixtures provide exact function grants and normal source and
  target privileges, with no private catalog or change-schema grants.
- Owner, non-owner, superuser, quoted-name, custom-path, and `$user` cases cover
  both create and replace branches.
- Query-changing, partition-changing, mode-changing, no-op, and failing alter
  cases verify owner, path, data, catalog, CDC, and frontier state.
- Same-owner cascade succeeds. Mixed-owner and injected-failure cascades leave
  every relation and catalog row intact.
- Malicious functions, operators, views, casts, RLS policies, and target names
  cannot observe or use extension-owner authority.
- Fresh install and v0.87.8 upgrade tests verify exact `prosecdef`, `proconfig`,
  overload identity, and retained ACLs.

## Exit criteria

- [ ] The three issue #941 APIs work for an owner with exact public grants.
- [ ] The same owner has no direct private-schema access.
- [ ] Every caller-controlled name resolves under the original caller context.
- [ ] Every recreation preserves the exact storage owner and stored path.
- [ ] Unauthorized cascade targets cause zero mutations.
- [ ] Security, rollback, upgrade, and full repository CI gates pass.
