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
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
.git
.github
.tmp*
dist
coverage
*.log
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
25 changes: 25 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CodeQL

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '30 3 * * 1'

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- uses: github/codeql-action/init@v3
with:
languages: javascript-typescript
- uses: github/codeql-action/autobuild@v3
- uses: github/codeql-action/analyze@v3
21 changes: 21 additions & 0 deletions Dockerfile.enterprise
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
FROM node:22-bookworm-slim AS build
WORKDIR /app
COPY package*.json ./
COPY packages/core/package*.json packages/core/package.json ./packages/core/
COPY packages/enterprise/package*.json packages/enterprise/package.json ./packages/enterprise/
RUN npm install
COPY . .
RUN npm run build:core && npm run build:enterprise

FROM node:22-bookworm-slim AS runtime
ENV NODE_ENV=production
WORKDIR /app
RUN useradd --system --create-home --uid 10001 authority
COPY --from=build /app/package*.json ./
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/packages/core/dist ./packages/core/dist
COPY --from=build /app/packages/enterprise/dist ./packages/enterprise/dist
COPY --from=build /app/packages/enterprise/package.json ./packages/enterprise/package.json
USER authority
EXPOSE 8080
CMD ["node", "packages/enterprise/dist/serve.js"]
47 changes: 47 additions & 0 deletions docs/PRODUCTION-DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Enterprise production deployment

The enterprise package has two runtime modes:

- `InMemoryEnterpriseStore` for tests and local development.
- `PostgresEnterpriseStore` for production deployments.

The production entrypoint requires PostgreSQL and OIDC/JWKS configuration.

## Required environment

Copy `packages/enterprise/.env.example` and provide real values through your deployment secret/configuration system. Do not commit credentials.

Required:

- `DATABASE_URL`
- `AUTHORITY_JWT_ISSUER`
- `AUTHORITY_JWT_AUDIENCE`
- `AUTHORITY_JWKS_URI`

The service listens on port `8080` by default.

## Database

Apply `packages/enterprise/migrations/001_enterprise.sql` through the organization's migration process. The runtime also performs an idempotent schema initialization so a reference deployment can bootstrap itself, but mature production environments should treat migrations as the authoritative schema lifecycle.

Use a PostgreSQL deployment with encryption in transit, encryption at rest, automated backups, point-in-time recovery, monitoring, and a documented recovery procedure.

## Network

Terminate TLS at the managed load balancer or ingress layer. Restrict network access so the authorization service and database are reachable only from trusted application paths. Put rate limiting and request-size limits at the edge as well as the service.

## Identity

Use short-lived OIDC access tokens. Validate issuer, audience, signature, expiration, not-before, algorithm, and signing key identifier. Tenant identity comes from the authenticated principal rather than a client-selected routing value.

## Authorization

Keep policy administration, contract administration, security administration, and approval authority separated organizationally where practical. A human approval must bind to the exact action digest and must not be issued by the requester.

## Operations

Export authorization events and receipts to the organization's audit/SIEM pipeline. Monitor denied actions, repeated nonce failures, approval failures, authentication failures, and database health. Protect signing keys with KMS/HSM-backed systems when deployment architecture requires server-managed signing keys.

## Security assessment

Before allowing high-impact financial, production, destructive, or privileged actions, run an independent application and infrastructure security assessment against the deployed service. The repository's red-team tests are regression tests, not a substitute for an external assessment.
15 changes: 15 additions & 0 deletions packages/enterprise/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Runtime
NODE_ENV=production
HOST=0.0.0.0
PORT=8080
DB_POOL_MAX=20

# PostgreSQL
DATABASE_URL=postgresql://USER:PASSWORD@HOST:5432/agent_authority
DATABASE_SSL=true
DATABASE_SSL_REJECT_UNAUTHORIZED=true

# OIDC/JWKS
AUTHORITY_JWT_ISSUER=https://idp.example.com/
AUTHORITY_JWT_AUDIENCE=agent-authority
AUTHORITY_JWKS_URI=https://idp.example.com/.well-known/jwks.json
61 changes: 61 additions & 0 deletions packages/enterprise/migrations/001_enterprise.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
CREATE TABLE IF NOT EXISTS aa_enterprise_policies (
tenant_id TEXT NOT NULL,
policy_id TEXT NOT NULL,
version INTEGER NOT NULL,
status TEXT NOT NULL CHECK (status IN ('draft','active','retired')),
document JSONB NOT NULL,
created_by TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
activated_at TIMESTAMPTZ,
PRIMARY KEY (tenant_id, policy_id, version)
);

CREATE UNIQUE INDEX IF NOT EXISTS aa_enterprise_active_policy
ON aa_enterprise_policies (tenant_id, policy_id) WHERE status='active';

CREATE TABLE IF NOT EXISTS aa_enterprise_contracts (
tenant_id TEXT NOT NULL,
contract_id TEXT NOT NULL,
document JSONB NOT NULL,
revoked_at TIMESTAMPTZ,
PRIMARY KEY (tenant_id, contract_id)
);

CREATE TABLE IF NOT EXISTS aa_enterprise_nonces (
tenant_id TEXT NOT NULL,
nonce TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (tenant_id, nonce)
);

CREATE TABLE IF NOT EXISTS aa_enterprise_events (
tenant_id TEXT NOT NULL,
event_id TEXT NOT NULL,
correlation_id TEXT NOT NULL,
document JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
PRIMARY KEY (tenant_id, event_id)
);

CREATE TABLE IF NOT EXISTS aa_enterprise_approvals (
tenant_id TEXT NOT NULL,
approval_id TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('pending','approved','rejected','consumed')),
request JSONB NOT NULL,
receipt JSONB,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
PRIMARY KEY (tenant_id, approval_id)
);

CREATE TABLE IF NOT EXISTS aa_enterprise_receipts (
tenant_id TEXT NOT NULL,
receipt_id TEXT NOT NULL,
event_id TEXT NOT NULL,
action_digest TEXT NOT NULL,
previous_receipt_hash TEXT,
receipt_hash TEXT NOT NULL,
document JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
PRIMARY KEY (tenant_id, receipt_id)
);
Loading