From 4a244c90d6d10a113d266e9daeb3f29f3be69656 Mon Sep 17 00:00:00 2001 From: prayingperceptions Date: Wed, 9 Sep 2026 17:31:52 -0500 Subject: [PATCH 1/7] ci: add CodeQL security analysis --- .github/workflows/codeql.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..778d02d --- /dev/null +++ b/.github/workflows/codeql.yml @@ -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 From 4a42813cbeea05493bd04252c2b5800235bdb050 Mon Sep 17 00:00:00 2001 From: prayingperceptions Date: Wed, 9 Sep 2026 17:31:57 -0500 Subject: [PATCH 2/7] ci: add Dependabot npm updates --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..54d3fbb --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: npm + directory: "/" + schedule: + interval: weekly + open-pull-requests-limit: 10 From c03eb0fb26fc0233e82d8b65f96d2636838fb4a9 Mon Sep 17 00:00:00 2001 From: prayingperceptions Date: Wed, 9 Sep 2026 17:32:03 -0500 Subject: [PATCH 3/7] deploy: add non-root enterprise service container --- Dockerfile.enterprise | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Dockerfile.enterprise diff --git a/Dockerfile.enterprise b/Dockerfile.enterprise new file mode 100644 index 0000000..8e88a4a --- /dev/null +++ b/Dockerfile.enterprise @@ -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"] From 79da4fc812a43b9ea025bcb31704805b08c88ef3 Mon Sep 17 00:00:00 2001 From: prayingperceptions Date: Wed, 9 Sep 2026 17:32:08 -0500 Subject: [PATCH 4/7] deploy: add enterprise environment template --- packages/enterprise/.env.example | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 packages/enterprise/.env.example diff --git a/packages/enterprise/.env.example b/packages/enterprise/.env.example new file mode 100644 index 0000000..fc71052 --- /dev/null +++ b/packages/enterprise/.env.example @@ -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 From 74dcc6b6d718d5d8222a6cb85b2b6310d4f36e09 Mon Sep 17 00:00:00 2001 From: prayingperceptions Date: Wed, 9 Sep 2026 17:32:15 -0500 Subject: [PATCH 5/7] deploy: add explicit enterprise database migration --- .../enterprise/migrations/001_enterprise.sql | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 packages/enterprise/migrations/001_enterprise.sql diff --git a/packages/enterprise/migrations/001_enterprise.sql b/packages/enterprise/migrations/001_enterprise.sql new file mode 100644 index 0000000..d927214 --- /dev/null +++ b/packages/enterprise/migrations/001_enterprise.sql @@ -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) +); From 30b9acd71f2b52b0a0318046551f794f5a51d737 Mon Sep 17 00:00:00 2001 From: prayingperceptions Date: Wed, 9 Sep 2026 17:32:22 -0500 Subject: [PATCH 6/7] docs: add enterprise production deployment guide --- docs/PRODUCTION-DEPLOYMENT.md | 47 +++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/PRODUCTION-DEPLOYMENT.md diff --git a/docs/PRODUCTION-DEPLOYMENT.md b/docs/PRODUCTION-DEPLOYMENT.md new file mode 100644 index 0000000..64aec3d --- /dev/null +++ b/docs/PRODUCTION-DEPLOYMENT.md @@ -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. From c06f60cf720c353767151418725b4c50c2387387 Mon Sep 17 00:00:00 2001 From: prayingperceptions Date: Wed, 9 Sep 2026 17:32:29 -0500 Subject: [PATCH 7/7] deploy: add container build exclusions --- .dockerignore | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2b25c16 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,7 @@ +node_modules +.git +.github +.tmp* +dist +coverage +*.log