docs: commit all Phase 6 documentation updates and OpenSpec archives
- devops docs: 8 files updated for Phase 6 state; field-trial.md added (946-line runbook) - developer docs: api-reference (50+ endpoints), quick-start, 5 existing guides updated, 5 new guides added - engineering docs: all 12 files updated (services, architecture, SDK guide, testing, overview) - OpenSpec archives: phase-7-devops-field-trial, developer-docs-phase6-update, engineering-docs-phase6-update - VALIDATOR.md + scripts/start-validator.sh: V&V Architect tooling added - .gitignore: exclude session artifacts, build artifacts, and agent workspaces Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,7 +20,7 @@ PostgreSQL connection string.
|
||||
| **Format** | `postgresql://<user>:<password>@<host>:<port>/<database>` |
|
||||
| **Example** | `postgresql://sentryagent:sentryagent@localhost:5432/sentryagent_idp` |
|
||||
|
||||
The application uses `pg.Pool` with this connection string. Connection pool size uses the `pg` default (10 connections).
|
||||
The application uses `pg.Pool` with this connection string. Pool sizing is controlled by the optional `DB_POOL_*` variables documented below.
|
||||
|
||||
---
|
||||
|
||||
@@ -72,6 +72,10 @@ Every authenticated request verifies the JWT signature using this key. If this k
|
||||
|
||||
---
|
||||
|
||||
> **Note on Billing:** `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`, and `STRIPE_PRICE_ID` are
|
||||
> required when `BILLING_ENABLED=true`. For local development, set `BILLING_ENABLED=false` and
|
||||
> use placeholder values.
|
||||
|
||||
## Optional Variables
|
||||
|
||||
These variables have defaults and do not need to be set for local development.
|
||||
@@ -117,6 +121,257 @@ KV v2 secrets engine mount path.
|
||||
|
||||
---
|
||||
|
||||
### `BILLING_ENABLED`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `false` |
|
||||
| **Values** | `true`, `false` |
|
||||
| **Example** | `BILLING_ENABLED=false` |
|
||||
|
||||
Gates Stripe billing integration and free-tier agent limit enforcement. When `false`, no Stripe
|
||||
API calls are made and all tier limits are unenforced. Set to `false` for in-house testing.
|
||||
|
||||
---
|
||||
|
||||
### `STRIPE_SECRET_KEY`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | Only when `BILLING_ENABLED=true` |
|
||||
| **Format** | Stripe secret key string (`sk_live_*` or `sk_test_*`) |
|
||||
| **Example** | `STRIPE_SECRET_KEY=sk_test_placeholder` |
|
||||
|
||||
Stripe API key used to create Checkout Sessions for tier upgrades. Never use a live key in
|
||||
development.
|
||||
|
||||
---
|
||||
|
||||
### `STRIPE_WEBHOOK_SECRET`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | Only when `BILLING_ENABLED=true` |
|
||||
| **Format** | Stripe webhook signing secret (`whsec_*`) |
|
||||
| **Example** | `STRIPE_WEBHOOK_SECRET=whsec_placeholder` |
|
||||
|
||||
Used to verify the HMAC signature on incoming Stripe webhook events. Without this, the billing
|
||||
webhook endpoint will reject all events.
|
||||
|
||||
---
|
||||
|
||||
### `STRIPE_PRICE_ID`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | Only when `BILLING_ENABLED=true` |
|
||||
| **Format** | Stripe Price ID string (`price_*`) |
|
||||
| **Example** | `STRIPE_PRICE_ID=price_placeholder` |
|
||||
|
||||
The Stripe Price object used when creating a Checkout Session for the Pro tier upgrade.
|
||||
|
||||
---
|
||||
|
||||
### `ANALYTICS_ENABLED`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `true` |
|
||||
| **Values** | `true`, `false` |
|
||||
| **Example** | `ANALYTICS_ENABLED=true` |
|
||||
|
||||
Feature flag that gates the `/api/v1/analytics/*` routes. When `false`, the analytics router is
|
||||
not mounted and all analytics endpoints return 404. Events are still recorded internally
|
||||
regardless of this flag.
|
||||
|
||||
---
|
||||
|
||||
### `TIER_ENFORCEMENT`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `true` |
|
||||
| **Values** | `true`, `false` |
|
||||
| **Example** | `TIER_ENFORCEMENT=true` |
|
||||
|
||||
Enables Redis-backed tier limit enforcement per tenant. When `true`, the `tierEnforcement`
|
||||
middleware checks daily API call and token counts against per-tier limits defined in
|
||||
`src/config/tiers.ts`. Enterprise tenants with `maxCallsPerDay: Infinity` bypass enforcement.
|
||||
When `false`, no tier limits are enforced.
|
||||
|
||||
---
|
||||
|
||||
### `COMPLIANCE_ENABLED`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `true` |
|
||||
| **Values** | `true`, `false` |
|
||||
| **Example** | `COMPLIANCE_ENABLED=true` |
|
||||
|
||||
Feature flag that gates the report and agent-card export endpoints under
|
||||
`/api/v1/compliance/*`. When `false`, those endpoints return 404. The SOC2 controls endpoint
|
||||
(`/api/v1/compliance/controls`) and audit chain verification (`/api/v1/audit/verify`) are
|
||||
always enabled regardless of this flag.
|
||||
|
||||
---
|
||||
|
||||
### `REDIS_RATE_LIMIT_ENABLED`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `false` |
|
||||
| **Values** | `true`, `false` |
|
||||
| **Example** | `REDIS_RATE_LIMIT_ENABLED=true` |
|
||||
|
||||
When `true`, rate limiting uses a Redis-backed sliding-window counter per `client_id`. When
|
||||
`false`, rate limiting uses an in-process `RateLimiterMemory` store (does not share state
|
||||
across multiple app instances).
|
||||
|
||||
---
|
||||
|
||||
### `RATE_LIMIT_WINDOW_MS`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `60000` |
|
||||
| **Format** | Integer (milliseconds) |
|
||||
| **Example** | `RATE_LIMIT_WINDOW_MS=60000` |
|
||||
|
||||
Duration of the sliding-window rate limit period in milliseconds. Only effective when
|
||||
`REDIS_RATE_LIMIT_ENABLED=true`.
|
||||
|
||||
---
|
||||
|
||||
### `RATE_LIMIT_MAX_REQUESTS`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `100` |
|
||||
| **Format** | Integer |
|
||||
| **Example** | `RATE_LIMIT_MAX_REQUESTS=100` |
|
||||
|
||||
Maximum number of requests allowed per `client_id` within `RATE_LIMIT_WINDOW_MS`. Requests
|
||||
exceeding this limit receive `429 RATE_LIMIT_EXCEEDED`.
|
||||
|
||||
---
|
||||
|
||||
### `DB_POOL_MAX`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `20` |
|
||||
| **Format** | Integer |
|
||||
| **Example** | `DB_POOL_MAX=20` |
|
||||
|
||||
Maximum number of PostgreSQL connections in the pool. Increase for high-throughput production
|
||||
deployments. Ensure your PostgreSQL instance's `max_connections` is set to at least
|
||||
`DB_POOL_MAX × number_of_app_instances + 5`.
|
||||
|
||||
---
|
||||
|
||||
### `DB_POOL_MIN`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `2` |
|
||||
| **Format** | Integer |
|
||||
| **Example** | `DB_POOL_MIN=2` |
|
||||
|
||||
Minimum number of idle connections kept alive in the pool.
|
||||
|
||||
---
|
||||
|
||||
### `DB_POOL_IDLE_TIMEOUT_MS`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `30000` |
|
||||
| **Format** | Integer (milliseconds) |
|
||||
| **Example** | `DB_POOL_IDLE_TIMEOUT_MS=30000` |
|
||||
|
||||
Milliseconds a connection can sit idle before being evicted from the pool.
|
||||
|
||||
---
|
||||
|
||||
### `DB_POOL_CONNECTION_TIMEOUT_MS`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `5000` |
|
||||
| **Format** | Integer (milliseconds) |
|
||||
| **Example** | `DB_POOL_CONNECTION_TIMEOUT_MS=5000` |
|
||||
|
||||
Milliseconds the pool waits for a connection to become available before throwing a connection
|
||||
timeout error.
|
||||
|
||||
---
|
||||
|
||||
### `VAULT_KV_MOUNT`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `secret` |
|
||||
| **Format** | String (no leading or trailing slash) |
|
||||
| **Example** | `VAULT_KV_MOUNT=agentidp` |
|
||||
|
||||
KV v2 secrets engine mount path used by `VaultService`. Equivalent to the existing `VAULT_MOUNT`
|
||||
variable — note that `.env.example` uses `VAULT_KV_MOUNT`; the underlying service reads either.
|
||||
|
||||
---
|
||||
|
||||
### `OPA_URL`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Format** | URL string |
|
||||
| **Example** | `OPA_URL=http://localhost:8181` |
|
||||
|
||||
URL of a running OPA server for external policy evaluation. When unset, the application falls
|
||||
back to the embedded Wasm or JSON policy in `POLICY_DIR`. Used for health check reporting.
|
||||
|
||||
---
|
||||
|
||||
### `KAFKA_BROKERS`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Format** | Comma-separated broker addresses |
|
||||
| **Example** | `KAFKA_BROKERS=localhost:9092` |
|
||||
|
||||
When set, the `KafkaAdapter` publishes domain events to Kafka. When unset, Kafka publishing is
|
||||
disabled and events are only delivered via the `WebhookService`.
|
||||
|
||||
---
|
||||
|
||||
### `ENFORCE_TLS`
|
||||
|
||||
| | |
|
||||
|-|-|
|
||||
| **Required** | No |
|
||||
| **Default** | `false` |
|
||||
| **Values** | `true`, `false` |
|
||||
| **Example** | `ENFORCE_TLS=true` |
|
||||
|
||||
When `true`, the `tlsEnforcementMiddleware` redirects all HTTP requests to HTTPS. Enable in
|
||||
production deployments where TLS termination is handled at the application layer.
|
||||
|
||||
---
|
||||
|
||||
### `POLICY_DIR`
|
||||
|
||||
Directory containing OPA policy files (`authz.rego`, `authz.wasm`, `data/scopes.json`).
|
||||
@@ -178,33 +433,53 @@ In production, set this to the specific origin(s) that should be permitted to ca
|
||||
## Complete `.env` Example
|
||||
|
||||
```
|
||||
# Database
|
||||
DATABASE_URL=postgresql://sentryagent:sentryagent@localhost:5432/sentryagent_idp
|
||||
|
||||
# Redis
|
||||
REDIS_URL=redis://localhost:6379
|
||||
|
||||
# Application
|
||||
PORT=3000
|
||||
# ── Server ──────────────────────────────────────────────────────────────────
|
||||
NODE_ENV=development
|
||||
CORS_ORIGIN=*
|
||||
PORT=3000
|
||||
CORS_ORIGIN=http://localhost:3001
|
||||
|
||||
# JWT Keys (generate with openssl — see docs/devops/security.md)
|
||||
JWT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEA...
|
||||
-----END RSA PRIVATE KEY-----"
|
||||
# ── Database ─────────────────────────────────────────────────────────────────
|
||||
DATABASE_URL=postgresql://sentryagent:sentryagent@localhost:5432/sentryagent_idp
|
||||
DB_POOL_MAX=20
|
||||
DB_POOL_MIN=2
|
||||
DB_POOL_IDLE_TIMEOUT_MS=30000
|
||||
DB_POOL_CONNECTION_TIMEOUT_MS=5000
|
||||
|
||||
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkq...
|
||||
-----END PUBLIC KEY-----"
|
||||
# ── Redis ────────────────────────────────────────────────────────────────────
|
||||
REDIS_URL=redis://localhost:6379
|
||||
REDIS_RATE_LIMIT_ENABLED=true
|
||||
RATE_LIMIT_WINDOW_MS=60000
|
||||
RATE_LIMIT_MAX_REQUESTS=100
|
||||
|
||||
# HashiCorp Vault (Phase 2 — optional, omit to use bcrypt mode)
|
||||
# ── JWT Keys (generate with openssl — see docs/devops/security.md) ──────────
|
||||
JWT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIEow...\n-----END RSA PRIVATE KEY-----"
|
||||
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIIBIj...\n-----END PUBLIC KEY-----"
|
||||
|
||||
# ── Billing (Stripe) — set BILLING_ENABLED=false for local/in-house testing ─
|
||||
BILLING_ENABLED=false
|
||||
STRIPE_SECRET_KEY=sk_test_placeholder
|
||||
STRIPE_WEBHOOK_SECRET=whsec_placeholder
|
||||
STRIPE_PRICE_ID=price_placeholder
|
||||
|
||||
# ── Phase 6 Feature Flags ─────────────────────────────────────────────────────
|
||||
ANALYTICS_ENABLED=true
|
||||
TIER_ENFORCEMENT=true
|
||||
COMPLIANCE_ENABLED=true
|
||||
|
||||
# ── HashiCorp Vault (optional) ────────────────────────────────────────────────
|
||||
# VAULT_ADDR=http://127.0.0.1:8200
|
||||
# VAULT_TOKEN=hvs.XXXXXXXXXXXXXXXXXXXXXX
|
||||
# VAULT_MOUNT=secret
|
||||
# VAULT_KV_MOUNT=secret
|
||||
|
||||
# OPA Policy Engine (Phase 2 — optional, defaults to <cwd>/policies)
|
||||
# ── OPA (optional) ───────────────────────────────────────────────────────────
|
||||
# POLICY_DIR=/etc/sentryagent/policies
|
||||
# OPA_URL=http://localhost:8181
|
||||
|
||||
# ── Kafka (optional) ─────────────────────────────────────────────────────────
|
||||
# KAFKA_BROKERS=localhost:9092
|
||||
|
||||
# ── TLS ──────────────────────────────────────────────────────────────────────
|
||||
# ENFORCE_TLS=true
|
||||
```
|
||||
|
||||
> Do not commit `.env` to version control. Add it to `.gitignore`.
|
||||
@@ -220,3 +495,8 @@ The application validates required variables at startup in this order:
|
||||
3. `REDIS_URL` — checked when `getRedisClient()` is first called (during `createApp()`)
|
||||
|
||||
If any required variable is missing, the process exits with an error before binding to any port.
|
||||
|
||||
> **Feature flags** (`BILLING_ENABLED`, `ANALYTICS_ENABLED`, `TIER_ENFORCEMENT`,
|
||||
> `COMPLIANCE_ENABLED`) are read at startup. `ANALYTICS_ENABLED` and `COMPLIANCE_ENABLED`
|
||||
> determine whether their respective routers are mounted — changing these values requires a
|
||||
> process restart.
|
||||
|
||||
Reference in New Issue
Block a user