Mirror Phase 1's TestSecurity_SEC* pattern for the memory substrate: 10+ ISO-* cases proving tenant isolation end-to-end with real Postgres+pgvector+Redis, CI-gated via memory-security-integration job.
Milestone 3.E.1 — Memory Security Integration Test Suite
Status: Planned
Goal: Track E — Exit Gate
Phase: 3 — Core Memory Substrate
Estimated effort: 3 days
Why This Milestone Exists
Mirrors Phase 1's 1.5.1 pattern: prove the composed system (real Postgres with RLS, real pgvector HNSW index, real Redis hot cache) enforces tenant isolation end-to-end — not just that each service's unit tests pass in isolation. Individual milestone acceptance criteria only verify their own narrow slice; this gate catches emergent security failures when the pieces are composed together.
Test Matrix
| Test ID | Scenario | Expected |
|---|---|---|
| ISO-1.1 | Org A writes memory, Org B searches with identical query text | Empty result set, not an error |
| ISO-1.2 | Org A agent ID used with Org B's PAT/org_id context | 403, mirrors proxy's AGENT_NOT_AUTHORIZED semantics |
| ISO-1.3 | Direct SQL query bypassing service layer, SET LOCAL app.current_org_id to Org A | Org B rows invisible even with malformed WHERE clause (RLS floor) |
| ISO-1.4 | memory_relationships edge referencing a memory from a different org | Insert rejected |
| ISO-1.5 | HNSW ANN search across a mixed corpus (Org A + Org B rows in same index) | Zero cross-org leakage in top-K at every ef_search value |
| ISO-1.6 | Redis hot cache key collision test: two orgs' agents with colliding hash suffixes | No cross-tenant cache read possible |
| ISO-2.1 | GDPR delete cascade: delete org | All memories, memory_relationships, memory_versions removed; MinIO archive objects also removed |
| ISO-2.2 | GDPR delete cascade partial failure (MinIO delete fails, Postgres succeeds) | Orphan detection job flags mismatch |
| ISO-3.1 | PII redaction stage bypassed via direct DB write | Read-path redaction re-check as defense-in-depth |
| ISO-3.2 | Quarantined memory (status='quarantined') | Never returned by search, regardless of similarity score |
Test Infrastructure
Reuses the securityTestEnv-equivalent pattern, ported to Python:
# Illustrative — exact path may differ
@pytest.fixture
async def isolation_env() -> IsolationTestEnv:
pg = await start_postgres_testcontainer()
redis = await start_redis_testcontainer()
org_a, org_b = await seed_two_orgs(pg)
yield IsolationTestEnv(pg=pg, redis=redis, org_a=org_a, org_b=org_b)
await teardown(pg, redis)CI Wiring
New job in .github/workflows/ci.yml, modeled on the existing security-integration job. Must use a pgvector-enabled Postgres image (pgvector/pgvector:pg16), not plain postgres:16.
Orientation (indicative)
Named paths, package layouts, libraries, schemas, env vars, and commands anywhere on this page are rough sketches for orientation — inspiration and a baseline, not a required change list.
During implementation, expect to:
- open the live tree and follow existing patterns before inventing new ones
- research current constraints (latency, tenancy, deploy shape, libraries) more deeply than this page can
- advance the design beyond the sketch where measurement or code reality says so
- land work in different filenames, merged packages, deferred docs, or new surfaces when the situation calls for it
Prefer outcomes over matching any particular file tree or command sequence.
Areas that may be involved (situational — not a checklist):
- Evaluation / benchmarks
- Memory service / repositories
Success signals
Outcome-oriented signals that the milestone is in good shape. Exact filenames, package layouts, and commands may differ from any sketches above.
- All 10+ ISO-* cases pass with real Postgres+pgvector+Redis containers
-
memory-security-integrationadded to required branch-protection checks - Suite runs in <90s in CI
- Repo guards / CI checks still pass
Prerequisites
- Milestones 3.D.1–3.D.3 (read/ranking pipeline complete)
- Phase 3 Track C milestones (write pipeline)
Last updated on