Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Synthetic placeholders only. Never commit a real database URL or AWS resource name.
AUTH_MODE=demo
DATABASE_URL=postgresql://USER:PASSWORD@HOST:26257/defaultdb?sslmode=verify-full
EMBEDDING_PROVIDER=deterministic
BEDROCK_MODEL_ID=amazon.titan-embed-text-v2:0
Expand Down
40 changes: 32 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ To run only the SAM validation/build gate:
.\scripts\verify.ps1 -WithSam
```

Before a separately approved live synthetic E2E, the repository provides two fail-fast read-only
guards and one bounded runner:

```powershell
.\scripts\bedrock-quota-preflight.ps1 -Region us-west-2 -Profile <DEPLOY_PROFILE>
.\scripts\aws-cost-preflight.ps1 -BudgetName <USD_5_BUDGET> -Profile <DEPLOY_PROFILE>
.\scripts\live-bedrock-e2e.ps1 -ApiUrl <HTTPS_API_URL> -BudgetName <USD_5_BUDGET> -Profile <DEPLOY_PROFILE>
```

The live runner accepts only a short-lived synthetic Cognito ID token from the process environment,
performs exactly two application actions that require embeddings, prints no token or memory content,
and stops before calls when quota or cost checks fail. Preparing the runner does not authorize or
perform a live invocation.

## CockroachDB integration

`schema.sql` defines:
Expand All @@ -103,12 +117,18 @@ the application automatically.
Current CockroachDB documentation confirms `VECTOR`, `<=>` cosine distance, and prefix columns for
vector indexes: [Vector Indexes](https://www.cockroachlabs.com/docs/stable/vector-indexes).

The project also used the CockroachDB Cloud Managed MCP Server as a separate read-only development
and operations inspection path. See
[docs/COCKROACHDB_TOOLS.md](docs/COCKROACHDB_TOOLS.md) for the exact operations, evidence, and
runtime boundary.

## AWS SAM

`template.yaml` includes explicit root/proxy routes, throttling, a retained encrypted/versioned S3
bucket, exact Secrets Manager access, and a foundation-model-scoped Bedrock permission. No CORS is
enabled; the bundled UI is same-origin. Production authentication is deliberately left to the
deploying environment.
`template.yaml` includes a Cognito user pool/client/domain, OAuth 2.0 Authorization Code + PKCE for
the browser demo, an API Gateway JWT authorizer, explicit public demo/health/auth-config routes,
protected `/v1/*` routes, throttling, a retained encrypted/versioned S3 bucket, exact Secrets
Manager access, and a foundation-model-scoped Bedrock permission. No API CORS is enabled; protected
requests from the bundled UI are same-origin.

See [docs/AWS_DEPLOYMENT.md](docs/AWS_DEPLOYMENT.md) for validation, parameters, deployment steps,
cost/security gates, and rollback notes. **No AWS deployment is performed by this repository.**
Expand All @@ -118,6 +138,7 @@ cost/security gates, and rollback notes. **No AWS deployment is performed by thi
| Method | Path | Purpose |
|---|---|---|
| `GET` | `/healthz` | Runtime mode; never returns secrets |
| `GET` | `/auth/config` | Public OAuth client/domain/callback settings; never returns secrets |
| `POST` | `/v1/memories/propose` | Evaluate and optionally persist a proposal |
| `POST` | `/v1/memories/{id}/approve` | Activate a pending memory |
| `POST` | `/v1/memories/search` | Scoped vector retrieval with `max_sensitivity` |
Expand All @@ -126,19 +147,22 @@ cost/security gates, and rollback notes. **No AWS deployment is performed by thi

## Security boundary

This MVP demonstrates memory governance; it does not provide end-user authentication or
authorization. The demo accepts tenant, actor, and clearance from the request. A production gateway
must derive these fields from verified identity claims and restrict approval/export operations.
AWS mode derives tenant, actor, groups, and clearance from API Gateway-verified Cognito JWT claims.
The required claims are `sub`, `custom:tenant_id`, and optional `custom:clearance` (defaults to
`public`). Approval requires `memoryguard-reviewer` or `memoryguard-admin`; evidence export requires
`memoryguard-auditor` or `memoryguard-admin`. Client-supplied identity fields remain only for local
`AUTH_MODE=demo` compatibility and are ignored in Cognito mode.

Never commit a real `.env`, connection string, credential, or customer dataset. See
[SECURITY.md](SECURITY.md) for the threat model and production gaps.

## Hackathon material

- [Devpost draft](docs/DEVPOST.md)
- [90-second demo script](docs/DEMO_SCRIPT.md)
- [75-second demo script](docs/DEMO_SCRIPT.md)
- [Architecture and trust boundaries](docs/ARCHITECTURE.md)
- [AWS/SAM runbook](docs/AWS_DEPLOYMENT.md)
- [Local verification record](docs/VERIFICATION.md)
- [CockroachDB tool usage and MCP proof](docs/COCKROACHDB_TOOLS.md)

License: MIT.
10 changes: 6 additions & 4 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

## Scope

OME MemoryGuard is an MVP policy and persistence layer. It reduces persistent-memory risk but is not
a complete authorization system, DLP product, secrets scanner, or compliance control.
OME MemoryGuard is an MVP policy and persistence layer. It reduces persistent-memory risk and adds
Cognito JWT/group gates, but is not a complete IAM, DLP, secrets-scanning, or compliance product.

## Threats addressed

Expand All @@ -23,11 +23,13 @@ a complete authorization system, DLP product, secrets scanner, or compliance con
- Secrets Manager errors exclude connection-string contents;
- S3 evidence keys hash tenant identifiers and use encryption/checksum parameters;
- SAM IAM scopes secret, bucket prefix, and foundation model.
- protected AWS routes require API Gateway-verified Cognito JWTs;
- tenant/actor/clearance are server-derived in Cognito mode, and privileged actions require groups.

## Production gaps

- add JWT/OIDC authentication and server-derived tenant, actor, role, and clearance;
- restrict approval and evidence export to privileged identities;
- add a production login UI, account lifecycle/recovery controls, and fine-grained scopes;
- verify group administration and token-revocation behavior in live integration tests;
- add policy versioning, revocation, retention, reconciliation, and tamper-evident audit chaining;
- add rate limits/WAF controls and structured logs with privacy review;
- run live integration, backup/restore, failure-injection, and authorization tests;
Expand Down
59 changes: 37 additions & 22 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
# Architecture and trust boundaries

![OME MemoryGuard architecture](assets/architecture.svg)

The rendered diagram is optimized for a 3:2 Devpost gallery image. Its editable Mermaid source is
available in [`assets/architecture.mmd`](assets/architecture.mmd).

## Runtime topology

```text
Client / agent
|
v
API Gateway HTTP API -> AWS Lambda (Mangum + FastAPI)
|
+-------------+-------------+
| |
v v
Amazon Bedrock Amazon S3
Titan Embeddings V2 audit metadata bundles
| (AES-256 + checksum)
v
CockroachDB Cloud
- memory_items VECTOR(1024)
- memory_audit_events
- agent_checkpoints
- prefix-filtered cosine ANN index
```mermaid
flowchart LR
A["AI agent or browser"] -->|"Cognito JWT"| B["API Gateway HTTP API"]
B -->|"JWT authorizer"| C["AWS Lambda<br/>FastAPI + Mangum"]
C --> D["Deterministic policy gate"]
D -->|"allowed or review"| E["Amazon Bedrock<br/>Titan Embeddings V2"]
E --> F["CockroachDB Cloud<br/>memory + audit transaction<br/>VECTOR(1024)"]
D -->|"denied metadata only"| F
C -->|"audit metadata export"| G["Amazon S3<br/>AES-256 + checksum"]
H["AWS Secrets Manager"] -->|"database URL at cold start"| C

subgraph Local["Local deterministic demo"]
I["InMemoryRepository"]
J["Deterministic embeddings"]
end
D -.->|"local mode"| J
J --> I
```

Local mode replaces CockroachDB with `InMemoryRepository` and Bedrock with reproducible deterministic
vectors. The health endpoint reports which mode is active without returning configuration values.
The Lambda and Bedrock inference Regions are configured independently: the runtime calls the exact
approved `BEDROCK_REGION`, while CockroachDB and the rest of the dev stack remain in Frankfurt.

## Write path

Expand Down Expand Up @@ -58,6 +64,13 @@ transaction. If the database event fails after S3 succeeds, reconciliation is re

## Trust boundaries

- API Gateway validates Cognito issuer/audience/signature before protected `/v1/*` routes reach the
application. The app fails closed if the verified claims are absent in `AUTH_MODE=cognito`.
- The browser demo uses Cognito Authorization Code + PKCE. It receives only public OAuth settings
from `/auth/config`, keeps its short-lived ID token in `sessionStorage`, and sends it only to
same-origin `/v1/*` routes.
- Tenant and actor come from `custom:tenant_id` and `sub`; clearance is clamped to the verified
claim. Approval/export require dedicated Cognito groups.
- The policy engine is before persistent memory writes, not after retrieval.
- The application never logs a database URL and fails closed on malformed Secrets Manager values.
- IAM in `template.yaml` is limited to one secret, one S3 object prefix, and one Bedrock foundation
Expand All @@ -67,13 +80,15 @@ transaction. If the database event fails after S3 succeeds, reconciliation is re

## Known MVP limitations

- There is no built-in authentication/authorization. Tenant, actor, approver, and clearance must be
derived from authenticated claims in production; request fields are only a demo contract.
- Cognito JWT authentication, PKCE browser sign-in, and coarse group authorization are present, but
lifecycle automation, account recovery policy, access-token claim customization, and fine-grained
scopes are not.
- Policy pattern matching is a guardrail, not full DLP, malware scanning, or prompt-injection proof.
- There is no revoke endpoint, retention worker, checkpoint API, rate-limiter in local mode, or audit
signature chain.
- `schema.sql` and the AWS stack are not applied automatically. Live database/AWS behavior requires
a separately approved deployment and integration test.
- `schema.sql` and the AWS stack are not applied automatically by the source tree. They were applied
only to the separately approved, synthetic `ome-memoryguard-dev` environment; production remains
undeployed.
- Vector-index feature availability and Bedrock model availability must be verified in the chosen
CockroachDB version and AWS Region.

Expand Down
116 changes: 104 additions & 12 deletions docs/AWS_DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@ may incur cost. The repository does not deploy automatically.

- Python 3.12 and AWS SAM CLI.
- An approved AWS account/Region and least-privilege deployment identity.
- Never deploy with the AWS account root identity. Use root only to bootstrap a narrowly scoped
deployer role, then run all stack commands through that role.
- A pre-created Secrets Manager secret whose `SecretString` is either the CockroachDB URL or:

```json
{"DATABASE_URL":"postgresql://REDACTED"}
```

- A CockroachDB database where `schema.sql` has been reviewed and applied by an authorized operator.
- Bedrock access to `amazon.titan-embed-text-v2:0` in the selected Region.
- The Lambda package keeps `sslmode=verify-full`. If the URL does not provide `sslrootcert`, the
application uses the packaged `certifi` CA bundle instead of depending on Lambda/libpq trust-store
discovery. An explicit CA path in the URL is preserved.
- Bedrock access to `amazon.titan-embed-text-v2:0` in the approved `BedrockRegion`. The inference
Region may differ from the Lambda Region only after an explicit data-residency review.

Do not place the real URL in `samconfig.toml`, terminal history, screenshots, logs, or CloudFormation
parameters. Pass only the secret ARN to SAM.
Expand All @@ -40,23 +46,67 @@ Optional read-only account checks:
```powershell
aws sts get-caller-identity
aws secretsmanager describe-secret --secret-id <SECRET_ARN> --region <REGION>
aws bedrock get-foundation-model --model-identifier amazon.titan-embed-text-v2:0 --region <REGION>
aws bedrock get-foundation-model --model-identifier amazon.titan-embed-text-v2:0 --region <BEDROCK_REGION>
```

Do not run `get-secret-value` during routine validation.

Before any paid Bedrock invocation, run the read-only quota preflight for the approved inference
Region. It checks the Titan V2 on-demand requests-per-minute and tokens-per-minute quotas and exits
nonzero when both are not positive:

```powershell
.\scripts\bedrock-quota-preflight.ps1 -Region us-west-2
```

Several candidate Regions can be checked without invoking a model:

```powershell
.\scripts\bedrock-quota-preflight.ps1 -Region us-west-2,us-east-1,eu-west-3
```

The script requires an authenticated AWS CLI profile, prints no identity ARN or secret value, and
emits `BEDROCK_QUOTA_READY=true` only for a Region with nonzero RPM and TPM allocations. A passing
quota preflight is necessary but does not itself prove model access or successful inference.

Confirm that the approved AWS Budget exists, uses USD, is no higher than USD 5, and has not reached
the approved maximum. This call is read-only and prints only the limit and current actual amount:

```powershell
.\scripts\aws-cost-preflight.ps1 -BudgetName <USD_5_BUDGET> -Profile <DEPLOY_PROFILE>
```

The AWS Budget is an alerting and preflight control, not a hard account spending cap.

On Windows paths containing non-ASCII characters, package from the isolated ASCII-only staging
copy instead of calling `sam package` directly from the repository:

```powershell
.\scripts\sam-package.ps1 -S3Bucket <PRIVATE_ARTIFACT_BUCKET> -Profile <DEPLOY_PROFILE> -Region <REGION>
```

The helper excludes `.env`, Git metadata, virtual environments, generated files, bytecode, and
logs. It writes only the generated `.aws-sam/deploy/packaged.yaml` back to the project.

## Parameters and generated resources

| Item | Purpose |
|---|---|
| `DatabaseUrlSecretArn` | Exact secret readable by the Lambda role |
| `BedrockModelId` | Foundation model ID; defaults to Titan Embeddings V2 |
| `BedrockRegion` | Direct regional Bedrock endpoint; defaults to Paris for the isolated dev stack |
| `EnableDevAdminAuth` | Defaults to `false`; set to `true` only for isolated admin-driven smoke tests |
| `DemoCallbackUrl` | Exact HTTPS callback/logout URL registered for the browser demo |
| `MemoryGuardUserPool` | Cognito users with tenant/clearance custom claims |
| `MemoryGuardUserPoolClient` | Public app client; no client secret |
| `MemoryGuardUserPoolDomain` | Cognito prefix domain for OAuth Authorization Code + PKCE |
| `MemoryGuardHttpApi` | Public demo/health routes and JWT-protected `/v1/*` routes |
| `MemoryGuardFunction` | Python 3.12 Lambda, 30 s, 512 MB |
| `ServerlessHttpApi` | Root and proxy routes with per-route throttling |
| `MemoryGuardFunctionLogGroup` | Explicit Lambda log group with seven-day dev retention |
| `EvidenceBucket` | Private encrypted/versioned S3 bucket retained on deletion |

IAM permits only `GetSecretValue` on the supplied ARN, `InvokeModel` on the selected foundation-model
ARN, and `PutObject` under the generated bucket's `evidence/*` prefix.
IAM permits only `GetSecretValue` on the supplied ARN, `InvokeModel` on the selected model in the
exact `BedrockRegion`, and `PutObject` under the generated bucket's `evidence/*` prefix.

## Deployment (requires explicit approval)

Expand All @@ -70,23 +120,65 @@ Recommended guided answers:

- use a dedicated stack name and approved Region;
- supply only `DatabaseUrlSecretArn`, never its value;
- set `BedrockRegion` only to a Region with verified on-demand quota and approved data processing;
- set `DemoCallbackUrl` to the exact deployed demo URL, including its trailing slash;
- save configuration only if the file will not capture sensitive values;
- require explicit confirmation before CloudFormation changes;
- do not disable rollback for a normal deployment.

The default API is public and has no application authorizer. For any real/customer data, add a JWT
authorizer and derive tenant/actor/clearance from verified claims before deployment.
The root demo page, `/healthz`, and `/auth/config` are public. `/v1/*` uses an API Gateway JWT
authorizer backed by the generated Cognito user pool/client. The browser starts Cognito Authorization
Code + PKCE and keeps the returned ID token only in `sessionStorage`; it never handles a Cognito
password or client secret. In `AUTH_MODE=cognito`, the application requires verified claims and
ignores client-supplied tenant/actor/clearance values. Do not create test users with real personal or
customer data.

For an isolated automated smoke test, deploy with `EnableDevAdminAuth=true`, create a synthetic
user with `MessageAction=SUPPRESS`, and use `ADMIN_USER_PASSWORD_AUTH`. Keep the generated password
and JWT only in process memory, never logs or shell history. Leave the parameter at its default
`false` outside that short-lived dev test.

## Bounded Bedrock application E2E (requires separate live-call approval)

After quota and cost preflights pass, place a short-lived synthetic Cognito ID token only in the
current process environment and run:

```powershell
$env:MEMORYGUARD_E2E_ID_TOKEN = '<SHORT_LIVED_SYNTHETIC_ID_TOKEN>'
.\scripts\live-bedrock-e2e.ps1 `
-ApiUrl <HTTPS_API_URL> `
-BudgetName <USD_5_BUDGET> `
-BedrockRegion us-west-2 `
-Profile <DEPLOY_PROFILE>
Remove-Item Env:MEMORYGUARD_E2E_ID_TOKEN
```

The runner uses fixed synthetic content and a unique synthetic namespace. It executes one proposal
and one search (two application actions that require embeddings), then verifies the associated audit
events. It does not create AWS resources, export evidence, print the JWT, print content, or read a
database secret. Provider retries inside the deployed Lambda remain bounded by its runtime
configuration; the USD 5 Budget remains an alert, not a transactional hard cap.

## Post-deployment verification

Use synthetic data only:

1. Call `/healthz`; expect `storage=cockroachdb` and `embeddings=bedrock`.
2. Submit one non-sensitive synthetic proposal and verify active + audit rows.
3. Submit one synthetic denied pattern and verify no raw denied row exists.
4. Retrieve within the same tenant/namespace.
5. Export audit metadata and verify S3 encryption/checksum/versioning.
6. Inspect CloudWatch errors and Lambda duration without printing configuration values.
2. Call a protected `/v1/*` route without a token; expect `401`.
3. Open the demo, sign in through Cognito, and verify the callback returns without exposing tokens in
the URL.
4. With an approved synthetic Cognito user, submit one non-sensitive proposal and verify active +
audit rows inside the claim-derived tenant.
5. Attempt a spoofed tenant/client clearance and verify the JWT claims win.
6. Verify reviewer/auditor group gates, then inspect S3 encryption/checksum/versioning.

The Bedrock client uses bounded adaptive retries for transient throttling. If Bedrock remains
throttled or unavailable after the retry budget, the API returns a sanitized HTTP 503 with
`embedding_provider_unavailable`. The proposal/search fails closed and no memory or audit row is
written. `BedrockRegion` selects a direct regional endpoint, not a cross-Region inference profile.
When it differs from the Lambda Region, request text is processed in that selected Region; use only
approved data and record the residency decision.
7. Inspect CloudWatch errors and Lambda duration without printing token or configuration values.

## Rollback and cleanup

Expand Down
Loading
Loading