Files
sentryagent-idp/docs/engineering/07-dev-setup.md
SentryAgent.ai Developer f9a6a8aafb docs(devops): update all documentation for DockerSpec compliance
- Replace all docker-compose.yml/docker-compose.monitoring.yml references with
  compose.yaml/compose.monitoring.yaml (modern Compose Spec naming)
- Replace all `docker-compose` CLI commands with `docker compose` (plugin syntax)
- Update Dockerfile stage descriptions: node:18-alpine → node:20.11-bookworm-slim,
  built-in node user → explicit nodeapp:1001 non-root user
- Update image version references: postgres:14-alpine → postgres:14.12-alpine3.19,
  redis:7-alpine → redis:7.2-alpine3.19
- Externalize postgres credentials: hardcoded values → POSTGRES_USER/PASSWORD/DB env vars
- Externalize Grafana admin password: hardcoded 'agentidp' → GF_ADMIN_PASSWORD env var
- Add Docker Compose Variables section to environment-variables.md (POSTGRES_*, GF_ADMIN_PASSWORD)
- Update local-development.md Step 3: cp .env.example .env, document POSTGRES_* purpose
- Update quick-start.md: cp .env.example .env, use awk/sed for JWT key injection
- Update 07-dev-setup.md: remove 'no .env.example' claim, reference cp .env.example
- Update docker-compose.yml key file description in 04-codebase-structure.md
- Update monitoring overlay launch commands across all docs (compose.yaml + compose.monitoring.yaml)
- Update volume names to kebab-case: postgres_data → postgres-data, redis_data → redis-data
- Fix compliance encryption-runbook: docker-compose restart agentidp → docker compose restart app

All docs now consistent with compose.yaml in repo root.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 08:27:37 +00:00

15 KiB
Raw Blame History

07 — Development Environment Setup

This guide takes you from a fresh machine to a running AgentIdP server with a passing smoke test. Estimated time: 1520 minutes.


8.1 Prerequisites

Install all of these before proceeding.

Prerequisite Minimum version Install link
Node.js 18.x LTS https://nodejs.org/en/download — use the LTS version
npm 9.x (ships with Node.js 18) Included with Node.js
Docker Desktop Latest stable https://docs.docker.com/get-docker/
Git 2.x https://git-scm.com/downloads

Verify your versions:

node --version    # Should print v18.x.x or higher
npm --version     # Should print 9.x or higher
docker --version  # Should print Docker version 24.x or higher
git --version     # Should print git version 2.x

8.2 Clone and Install

# Clone the repository
git clone https://github.com/sentryagent-ai/sentryagent-idp.git
cd sentryagent-idp

# Install Node.js dependencies
npm install

This installs all production dependencies (Express, pg, Redis, etc.) and development dependencies (TypeScript, Jest, ts-jest, eslint).


8.3 Environment Variables Setup

The server requires a .env file at the project root. Copy the template:

cp .env.example .env

The template includes all required variables with sensible local defaults. Edit .env to set your values. Key variables are documented below.

# ─────────────────────────────────────────────────────────────
# PostgreSQL — individual credentials for compose.yaml
# ─────────────────────────────────────────────────────────────
POSTGRES_USER=sentryagent
POSTGRES_PASSWORD=sentryagent
POSTGRES_DB=sentryagent_idp

# ─────────────────────────────────────────────────────────────
# PostgreSQL connection (application reads this directly)
# ─────────────────────────────────────────────────────────────
DATABASE_URL=postgresql://sentryagent:sentryagent@localhost:5432/sentryagent_idp

# ─────────────────────────────────────────────────────────────
# Redis connection
# ─────────────────────────────────────────────────────────────
REDIS_URL=redis://localhost:6379

# ─────────────────────────────────────────────────────────────
# HTTP server port
# ─────────────────────────────────────────────────────────────
PORT=3000

# ─────────────────────────────────────────────────────────────
# JWT RSA keys (generate these below)
# ─────────────────────────────────────────────────────────────
JWT_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"

# ─────────────────────────────────────────────────────────────
# CORS (optional — defaults to '*' which allows all origins)
# ─────────────────────────────────────────────────────────────
CORS_ORIGIN=*

# ─────────────────────────────────────────────────────────────
# Node environment
# ─────────────────────────────────────────────────────────────
NODE_ENV=development

# ─────────────────────────────────────────────────────────────
# OPA policy directory (optional — defaults to ./policies)
# ─────────────────────────────────────────────────────────────
# POLICY_DIR=/path/to/policies

# ─────────────────────────────────────────────────────────────
# HashiCorp Vault (optional — omit to use bcrypt mode)
# ─────────────────────────────────────────────────────────────
# VAULT_ADDR=http://127.0.0.1:8200
# VAULT_TOKEN=your-vault-token
# VAULT_MOUNT=secret

Complete environment variable reference:

Variable Required Default Description
DATABASE_URL Yes PostgreSQL connection string. Format: postgresql://user:password@host:port/dbname
REDIS_URL Yes Redis connection URL. Format: redis://host:port[/db]
PORT No 3000 TCP port the HTTP server listens on
JWT_PRIVATE_KEY Yes PEM-encoded RSA private key (2048-bit minimum) for signing tokens
JWT_PUBLIC_KEY Yes PEM-encoded RSA public key (matching the private key above) for verifying tokens
CORS_ORIGIN No * CORS allowed origin. Use * for development, set to your dashboard domain in production
NODE_ENV No development Set to test to suppress Morgan HTTP logging during tests
POLICY_DIR No ./policies Absolute path to the directory containing authz.wasm or data/scopes.json
VAULT_ADDR No HashiCorp Vault server address (e.g. http://127.0.0.1:8200). When omitted, bcrypt mode is used
VAULT_TOKEN No Vault authentication token. Required when VAULT_ADDR is set
VAULT_MOUNT No secret Vault KV v2 mount path. Only used when Vault is configured

Generating JWT keys:

# Generate RSA 2048-bit private key
openssl genrsa -out private.pem 2048

# Extract public key
openssl rsa -in private.pem -pubout -out public.pem

# Print private key as single-line for .env (replace newlines with \n)
awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' private.pem

# Print public key as single-line for .env
awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' public.pem

Paste the output (including the -----BEGIN/END----- lines) as the value for JWT_PRIVATE_KEY and JWT_PUBLIC_KEY in your .env file, surrounded by double quotes.


8.4 Docker Compose Startup and Health Checks

Docker Compose starts PostgreSQL 14 and Redis 7. The application reads the DATABASE_URL and REDIS_URL from your .env file to connect to them.

# Start PostgreSQL and Redis in the background
docker compose up postgres redis -d

# Wait for health checks to pass (usually 10-15 seconds)
docker compose ps

Expected output when both services are healthy:

NAME                     STATUS                   PORTS
sentryagent-idp-postgres-1   Up (healthy)         0.0.0.0:5432->5432/tcp
sentryagent-idp-redis-1      Up (healthy)         0.0.0.0:6379->6379/tcp

Manual health check:

# Test PostgreSQL connection
docker exec sentryagent-idp-postgres-1 pg_isready -U sentryagent -d sentryagent_idp
# Expected: /var/run/postgresql:5432 - accepting connections

# Test Redis connection
docker exec sentryagent-idp-redis-1 redis-cli ping
# Expected: PONG

8.5 Database Migrations

Run the migration script to create all required tables:

npm run db:migrate

Expected output:

Running database migrations...
  ✓ Applied: 001_create_agents.sql
  ✓ Applied: 002_create_credentials.sql
  ✓ Applied: 003_create_audit_events.sql
  ✓ Applied: 004_create_tokens.sql
  ✓ Applied: 005_add_vault_path.sql

Migrations complete. 5 migration(s) applied.

Running npm run db:migrate a second time is safe — it skips already-applied migrations:

  - Skipped (already applied): 001_create_agents.sql
  ...
Migrations complete. 0 migration(s) applied.

Migration internals: The migration runner (scripts/migrate.ts) reads .sql files from src/db/migrations/ in alphabetical order, wraps each in a transaction, and records the filename in the schema_migrations table. If a migration fails, the transaction rolls back and the runner exits with code 1.


8.6 Start the Server

npm run dev
# Expected: SentryAgent.ai AgentIdP listening on port 3000

npm run dev uses ts-node to execute src/server.ts directly without compiling. This is faster for development. For a production-style start, compile first:

npm run build
npm start

8.7 Smoke Test

Verify the server is working with these three curl commands.

1. Health check:

curl http://localhost:3000/health

Expected response (200 OK):

{
  "status": "healthy",
  "checks": {
    "database": "healthy",
    "redis": "healthy"
  }
}

2. Register an agent: First, you need a token to authenticate. But to get a token, you need credentials. And to get credentials, you need an agent. The chicken-and-egg is resolved by the fact that agent registration requires an agents:write scoped token — which means you need to bootstrap the first agent another way.

For local development, temporarily test without auth by using the /api/v1 prefix directly (the server accepts requests; OPA will enforce scope).

The easiest approach: generate a test token programmatically:

# Generate test keys
openssl genrsa -out /tmp/test_private.pem 2048 2>/dev/null
openssl rsa -in /tmp/test_private.pem -pubout -out /tmp/test_public.pem 2>/dev/null

# Set them in your environment temporarily
export JWT_PRIVATE_KEY="$(cat /tmp/test_private.pem)"
export JWT_PUBLIC_KEY="$(cat /tmp/test_public.pem)"

# Start server with these keys and use a tool or short Node.js script to mint a test token

3. Token endpoint with seeded credentials:

Once you have an agent with credentials (e.g. created via the API or seeded in development), issue a token:

curl -X POST http://localhost:3000/api/v1/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_AGENT_ID" \
  -d "client_secret=sk_live_YOUR_SECRET" \
  -d "scope=agents:read agents:write"

Expected response (200 OK):

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "agents:read agents:write"
}

8.8 Troubleshooting

Error: connection refused on PostgreSQL or Redis

Cause: Docker services not running or not yet healthy. Fix:

docker compose ps  # Check status
docker compose up postgres redis -d  # Start if not running
docker compose logs postgres  # Check for startup errors

Error: DATABASE_URL environment variable is required

Cause: .env file missing or not being loaded. Fix: Ensure .env exists at the project root. npm run dev loads it via dotenv.config() in src/server.ts.

Error: JWT_PRIVATE_KEY and JWT_PUBLIC_KEY environment variables are required

Cause: JWT keys not in .env, or newlines in the PEM keys are not properly escaped. Fix: Ensure the keys are wrapped in double quotes and newlines are represented as \n. Use the awk command from section 8.3 to format them correctly.

Error: Cannot find module 'ts-node'

Cause: npm install was not run, or ran against a different Node.js version. Fix:

node --version  # Confirm Node.js 18+
rm -rf node_modules package-lock.json
npm install

Error: Cannot connect to Redis (during migration or server start)

Cause: Redis container not running or REDIS_URL is incorrect. Fix:

docker exec sentryagent-idp-redis-1 redis-cli ping
# If container is not running:
docker compose up redis -d

Port 3000 already in use

Cause: Another process is listening on port 3000. Fix:

lsof -i :3000   # Find the process
kill <PID>      # Kill it
# Or: set PORT=3001 in .env and restart

8.9 Running Tests Locally

# Run all tests (unit + integration)
npm test

# Run tests with coverage report
npm run test:unit -- --coverage
# Coverage report: coverage/lcov-report/index.html

# Run only unit tests
npm run test:unit

# Run only integration tests (requires running PostgreSQL and Redis)
npm run test:integration

# Run a single test file
npx jest tests/unit/services/AgentService.test.ts

# Run tests matching a pattern
npx jest --testNamePattern="registerAgent"

# Watch mode (re-runs on file changes)
npx jest --watch

Integration test requirements: Integration tests connect to real PostgreSQL and Redis. Set these environment variables before running integration tests:

TEST_DATABASE_URL=postgresql://sentryagent:sentryagent@localhost:5432/sentryagent_idp_test
TEST_REDIS_URL=redis://localhost:6379/1

The integration tests create their own tables (using CREATE TABLE IF NOT EXISTS) and clean up after themselves with DELETE FROM statements in afterAll.


8.10 Web Dashboard Local Development

The web dashboard is a separate Vite project in the dashboard/ directory.

# From the project root
cd dashboard
npm install

# Start the Vite development server
npm run dev
# Dashboard available at http://localhost:5173

The Vite dev server proxies all /api/* requests to http://localhost:3000, so the API server must be running concurrently (in a separate terminal).

Build for production:

cd dashboard
npm run build
# Output: dashboard/dist/  (served by Express at /dashboard)

After building, the Express server serves the built dashboard at http://localhost:3000/dashboard. You do not need to run the Vite dev server for this — the static files are served directly by Express.