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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ tmp-generated
generated
out-tsc

# Stray tsc output next to TypeScript library sources
libs/domains/shared/backend/util-dynamic-provider-registry/src/index.js
libs/domains/shared/backend/util-dynamic-provider-registry/src/index.js.map
libs/domains/shared/backend/util-dynamic-provider-registry/src/lib/*.js
libs/domains/shared/backend/util-dynamic-provider-registry/src/lib/*.js.map

# dependencies
node_modules

Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ The product intentionally departs from stricter baselines in a few places. Each

| ID | Area | What we accept | Mitigations (short) | Next review |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| **AR-001** | **Provisioning SSH** (cloud-init templates) | **`PermitRootLogin yes`** and **root** `authorized_keys` installed via provisioning scripts (`libs/domains/agenstra/backend/feature-billing-manager/.../agent-controller.utils.ts`, `agent-manager.utils.ts`) | SSH **key-based** access; **password authentication disabled** in generated `sshd` config; deployers should restrict network access, rotate keys, and monitor instances | **2027-05-06**, or sooner if cloud-init/SSH templates change materially |
| **AR-001** | **Provisioning SSH** (cloud-init templates) | **`PermitRootLogin yes`** and **root** `authorized_keys` installed via provisioning scripts (`libs/domains/decabill/backend/feature-billing-manager/src/lib/utils/cloud-init/agent-controller.utils.ts`, `agent-manager.utils.ts`) | SSH **key-based** access; **password authentication disabled** in generated `sshd` config; deployers should restrict network access, rotate keys, and monitor instances | **2027-05-06**, or sooner if cloud-init/SSH templates change materially |
| **AR-002** | **Desktop app** (`agenstra-native-agent-console`) | **No OS-trusted code signing** and **no in-app auto-update** in the Electron Forge pipeline (`apps/agenstra/native-agent-console/forge.config.js`) | Release artifacts include **`SHA256SUMS`** and **`integrity-manifest.json`** produced by [`tools/release-integrity`](./tools/release-integrity/README.md); CI/release pipelines **generate and verify** these manifests. Users should verify checksums after download. The web browser remains the primary client; the native build is a secondary channel. | **2027-05-06**, or sooner if desktop becomes the primary distribution path |
| **AR-003** | **Web frontends** (`frontend-*`) | **Content Security Policy** allows **`'unsafe-inline'`** and **`'unsafe-eval'`** so **Monaco Editor** and related tooling work; policy is sent as **`Content-Security-Policy-Report-Only`** by default (violations are reported, not blocked) | Set **`CSP_ENFORCE=true`** only in environments where compatibility is validated. Implementation: `libs/domains/shared/frontend/util-express-server/src/lib/security-headers.ts`. Hardening path: stricter CSP with a validated Monaco/worker/nonce strategy. | **2027-05-06**, or sooner if CSP middleware changes materially |
| **AR-004** | **Backend authentication mode resolution** (`getAuthenticationMethod` in `libs/domains/identity/backend/util-auth/src/lib/hybrid-auth.guard.ts`) | We do **not** require **`AUTHENTICATION_METHOD`** to always be set. When it is unset: if **`STATIC_API_KEY`** is set → **api-key** mode; otherwise → **keycloak** (OIDC / **Keycloak** integration with the deployer’s IdP). **Protected routes are not anonymous**—Keycloak- or users-mode guards still enforce authentication per configuration. | **Default `keycloak`** favors the most integrated, enterprise-typical option (customer IdP). For **api-key** or **users** deployments, set **`AUTHENTICATION_METHOD`** explicitly and treat **`STATIC_API_KEY`** as a high-value secret (rotation, least exposure). | **2027-05-06**, or sooner if hybrid auth resolution changes materially |
Expand Down
9 changes: 8 additions & 1 deletion apps/agenstra/backend-agent-controller/Dockerfile.api
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ RUN . "${NVM_DIR}/nvm.sh" && npm i && npm cache clean --force && \

COPY --chown=agenstra:agenstra . /app

RUN mkdir -p /var/lib/forepath/provider-plugins && \
chown agenstra:agenstra /var/lib/forepath/provider-plugins

RUN printf '%s\n' \
'#!/bin/bash' \
'set -euo pipefail' \
Expand All @@ -79,7 +82,11 @@ RUN printf '%s\n' \
' sudo groupadd -g "${docker_sock_gid}" docker' \
' fi' \
' sudo usermod -aG docker agenstra' \
' exec sg docker -c '"'"'set -euo pipefail; . "${NVM_DIR}/nvm.sh"; exec node main.js'"'"'' \
' exec sg docker -c '"'"'set -euo pipefail; . "${NVM_DIR}/nvm.sh"; if [ -n "${DYNAMIC_PROVIDER_PLUGIN_PATH:-}" ]; then node install-provider-plugins.js; fi; exec node main.js'"'"'' \
'fi' \
'if [ -n "${DYNAMIC_PROVIDER_PLUGIN_PATH:-}" ]; then' \
' . "${NVM_DIR}/nvm.sh"' \
' node install-provider-plugins.js' \
'fi' \
'. "${NVM_DIR}/nvm.sh"' \
'exec node main.js' \
Expand Down
17 changes: 17 additions & 0 deletions apps/agenstra/backend-agent-controller/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,23 @@ See the [library documentation](../../libs/domains/agenstra/backend/feature-agen
- `DIGITALOCEAN_API_TOKEN` - DigitalOcean API token (for server provisioning)
- `ENCRYPTION_KEY` - Encryption key for sensitive data

**Dynamic provider plugins (optional):**

- `DYNAMIC_PROVISIONING_PROVIDERS` - Comma-separated extra provisioning packages (`alias=@forepath/pkg` or `alias=file:dir`)
- `DYNAMIC_CONTEXT_IMPORT_PROVIDERS` - Comma-separated extra context import provider packages
- `DYNAMIC_PROVIDERS_FAIL_FAST` - When `true`, abort startup if critical dynamic providers fail to load (recommended in production when `DYNAMIC_PROVISIONING_PROVIDERS` is set)
- `DYNAMIC_PROVIDER_PLUGIN_PATH` - Absolute plugin root for post-build loading (unset by default; set to `/var/lib/forepath/provider-plugins` when using the compose volume)
- `DYNAMIC_PROVIDER_PLUGIN_INSTALL` - Comma-separated packages/tarballs to `npm install` into the plugin path at container startup

See `@forepath/shared/backend/util-dynamic-provider-registry` README for plugin export contract, baked-in vs mounted loading, and the post-build operator workflow.

### Post-build plugins (no image rebuild)

1. Build the plugin package (`nx build <plugin-lib>`) to produce compiled JS and `package.json`
2. Copy the plugin into `./provider-plugins/` on the host (mounted read-only in compose) and/or set `DYNAMIC_PROVIDER_PLUGIN_INSTALL`
3. Set `DYNAMIC_PROVISIONING_PROVIDERS` (or other `DYNAMIC_*` vars) to reference the package name
4. Restart the container

## Docker Deployment

The application includes Dockerfiles for containerized deployment:
Expand Down
12 changes: 12 additions & 0 deletions apps/agenstra/backend-agent-controller/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ x-backend-agent-controller-environment: &backend-agent-controller-environment
QUEUE_BULL_BOARD_PASSWORD: ${QUEUE_BULL_BOARD_PASSWORD:-bullmq}
HETZNER_API_TOKEN: ${HETZNER_API_TOKEN:-}
DIGITALOCEAN_API_TOKEN: ${DIGITALOCEAN_API_TOKEN:-}
# Dynamic provider plugins (baked-in runtime deps and/or mounted plugin path)
DYNAMIC_PROVISIONING_PROVIDERS: ${DYNAMIC_PROVISIONING_PROVIDERS:-}
DYNAMIC_CONTEXT_IMPORT_PROVIDERS: ${DYNAMIC_CONTEXT_IMPORT_PROVIDERS:-}
DYNAMIC_PROVIDERS_FAIL_FAST: ${DYNAMIC_PROVIDERS_FAIL_FAST:-false}
DYNAMIC_PROVIDER_PLUGIN_PATH: ${DYNAMIC_PROVIDER_PLUGIN_PATH:-}
DYNAMIC_PROVIDER_PLUGIN_INSTALL: ${DYNAMIC_PROVIDER_PLUGIN_INSTALL:-}
AUTHENTICATION_METHOD: ${AUTHENTICATION_METHOD:-api-key}
DISABLE_SIGNUP: ${DISABLE_SIGNUP:-false}
STATIC_API_KEY: ${STATIC_API_KEY:-}
Expand Down Expand Up @@ -108,6 +114,8 @@ services:
ports:
- '${PORT:-3100}:${PORT:-3100}'
- '${WEBSOCKET_PORT:-8081}:${WEBSOCKET_PORT:-8081}'
volumes:
- ./provider-plugins:/var/lib/forepath/provider-plugins
depends_on:
postgres:
condition: service_healthy
Expand All @@ -127,6 +135,8 @@ services:
<<: *backend-agent-controller-environment
QUEUE_ROLE: worker
QUEUE_BULL_BOARD_ENABLED: false
volumes:
- ./provider-plugins:/var/lib/forepath/provider-plugins
depends_on:
backend-agent-controller:
condition: service_healthy
Expand All @@ -148,6 +158,8 @@ services:
<<: *backend-agent-controller-environment
QUEUE_ROLE: scheduler
QUEUE_BULL_BOARD_ENABLED: false
volumes:
- ./provider-plugins:/var/lib/forepath/provider-plugins
depends_on:
backend-agent-controller:
condition: service_healthy
Expand Down
14 changes: 12 additions & 2 deletions apps/agenstra/backend-agent-controller/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,25 @@
"commands": [
"mkdir -p dist/apps/agenstra/backend-agent-controller/src/migrations",
"(npx tsc $(find apps/agenstra/backend-agent-controller/src/migrations -name '*.ts' 2>/dev/null || echo '') --outDir dist/apps/agenstra/backend-agent-controller/src/migrations --module commonjs --target es2021 --moduleResolution node --esModuleInterop --skipLibCheck --resolveJsonModule --declaration false --rootDir apps/agenstra/backend-agent-controller/src/migrations 2>/dev/null || true)",
"npx tsc $(find libs/domains/identity/backend/util-auth/src/lib/migrations -name '*.ts') --outDir dist/apps/agenstra/backend-agent-controller/src/migrations --module commonjs --target es2021 --moduleResolution node --esModuleInterop --skipLibCheck --resolveJsonModule --declaration false --rootDir libs/domains/identity/backend/util-auth/src/lib/migrations"
"npx tsc $(find libs/domains/identity/backend/util-auth/src/lib/migrations -name '*.ts') --outDir dist/apps/agenstra/backend-agent-controller/src/migrations --module commonjs --target es2021 --moduleResolution node --esModuleInterop --skipLibCheck --resolveJsonModule --declaration false --rootDir libs/domains/identity/backend/util-auth/src/lib/migrations",
"npx esbuild apps/agenstra/backend-agent-controller/src/scripts/install-provider-plugins.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/apps/agenstra/backend-agent-controller/install-provider-plugins.js --tsconfig=tsconfig.base.json --packages=external"
]
}
},
"verify-install-provider-plugins": {
"dependsOn": ["compile-migrations"],
"executor": "nx:run-commands",
"options": {
"command": "bash tools/ci/verify-install-provider-plugins.sh dist/apps/agenstra/backend-agent-controller/install-provider-plugins.js",
"cwd": "{workspaceRoot}"
}
},
"prune": {
"dependsOn": [
"prune-lockfile",
"copy-workspace-modules",
"compile-migrations"
"compile-migrations",
"verify-install-provider-plugins"
],
"executor": "nx:noop"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { installProviderPluginsFromEnv } from '@forepath/shared/backend/util-dynamic-provider-registry';

async function main(): Promise<void> {
await installProviderPluginsFromEnv();
}

main().catch((error: unknown) => {
console.error(error);
process.exit(1);
});
9 changes: 8 additions & 1 deletion apps/agenstra/backend-agent-manager/Dockerfile.api
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ RUN . "${NVM_DIR}/nvm.sh" && npm i && npm cache clean --force && \

COPY --chown=agenstra:agenstra . /app

RUN mkdir -p /var/lib/forepath/provider-plugins && \
chown agenstra:agenstra /var/lib/forepath/provider-plugins

RUN printf '%s\n' \
'#!/bin/bash' \
'set -euo pipefail' \
Expand All @@ -79,7 +82,11 @@ RUN printf '%s\n' \
' sudo groupadd -g "${docker_sock_gid}" docker' \
' fi' \
' sudo usermod -aG docker agenstra' \
' exec sg docker -c '"'"'set -euo pipefail; . "${NVM_DIR}/nvm.sh"; exec node main.js'"'"'' \
' exec sg docker -c '"'"'set -euo pipefail; . "${NVM_DIR}/nvm.sh"; if [ -n "${DYNAMIC_PROVIDER_PLUGIN_PATH:-}" ]; then node install-provider-plugins.js; fi; exec node main.js'"'"'' \
'fi' \
'if [ -n "${DYNAMIC_PROVIDER_PLUGIN_PATH:-}" ]; then' \
' . "${NVM_DIR}/nvm.sh"' \
' node install-provider-plugins.js' \
'fi' \
'. "${NVM_DIR}/nvm.sh"' \
'exec node main.js' \
Expand Down
11 changes: 11 additions & 0 deletions apps/agenstra/backend-agent-manager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,17 @@ See the [library documentation](../../libs/domains/agenstra/backend/feature-agen
- `RATE_LIMIT_TTL` - Time window in seconds (default: `60`)
- `RATE_LIMIT_LIMIT` - Maximum requests per window (default: `100`)

**Dynamic provider plugins (optional):**

- `DYNAMIC_AGENT_PROVIDERS` - Comma-separated extra agent backend packages
- `DYNAMIC_PIPELINE_PROVIDERS` - Comma-separated extra CI/CD provider packages
- `DYNAMIC_CHAT_FILTERS` - Comma-separated extra chat filter packages
- `DYNAMIC_PROVIDERS_FAIL_FAST` - When `true`, abort startup if critical dynamic providers fail to load
- `DYNAMIC_PROVIDER_PLUGIN_PATH` - Plugin root for post-build loading (unset by default; set to `/var/lib/forepath/provider-plugins` when using the compose volume)
- `DYNAMIC_PROVIDER_PLUGIN_INSTALL` - Startup `npm install` targets into the plugin path

See `@forepath/shared/backend/util-dynamic-provider-registry` README for export contract and post-build mount workflow. Mount `./provider-plugins` (see `docker-compose.yaml`) to add providers without rebuilding the image.

## Docker Deployment

The application includes Dockerfiles for containerized deployment:
Expand Down
8 changes: 8 additions & 0 deletions apps/agenstra/backend-agent-manager/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ services:
# Cursor agent configuration
CURSOR_API_KEY: ${CURSOR_API_KEY:-}
AGENT_DEFAULT_IMAGE: ${AGENT_DEFAULT_IMAGE:-ghcr.io/forepath/agenstra-manager-worker:latest}
# Dynamic provider plugins (baked-in runtime deps and/or mounted plugin path)
DYNAMIC_AGENT_PROVIDERS: ${DYNAMIC_AGENT_PROVIDERS:-}
DYNAMIC_PIPELINE_PROVIDERS: ${DYNAMIC_PIPELINE_PROVIDERS:-}
DYNAMIC_CHAT_FILTERS: ${DYNAMIC_CHAT_FILTERS:-}
DYNAMIC_PROVIDERS_FAIL_FAST: ${DYNAMIC_PROVIDERS_FAIL_FAST:-false}
DYNAMIC_PROVIDER_PLUGIN_PATH: ${DYNAMIC_PROVIDER_PLUGIN_PATH:-}
DYNAMIC_PROVIDER_PLUGIN_INSTALL: ${DYNAMIC_PROVIDER_PLUGIN_INSTALL:-}
# Database configuration
DB_HOST: ${DB_HOST:-postgres}
DB_PORT: ${DB_PORT:-5432}
Expand Down Expand Up @@ -79,6 +86,7 @@ services:
volumes:
# Mount Docker socket for Docker-in-Docker functionality
- /var/run/docker.sock:/var/run/docker.sock
- ./provider-plugins:/var/lib/forepath/provider-plugins
depends_on:
postgres:
condition: service_healthy
Expand Down
17 changes: 15 additions & 2 deletions apps/agenstra/backend-agent-manager/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,27 @@
"dependsOn": ["build"],
"executor": "nx:run-commands",
"options": {
"command": "mkdir -p dist/apps/agenstra/backend-agent-manager/src/migrations && npx tsc $(find apps/agenstra/backend-agent-manager/src/migrations -name '*.ts') --outDir dist/apps/agenstra/backend-agent-manager/src/migrations --module commonjs --target es2021 --moduleResolution node --esModuleInterop --skipLibCheck --resolveJsonModule --declaration false --rootDir apps/agenstra/backend-agent-manager/src/migrations"
"commands": [
"mkdir -p dist/apps/agenstra/backend-agent-manager/src/migrations",
"npx tsc $(find apps/agenstra/backend-agent-manager/src/migrations -name '*.ts') --outDir dist/apps/agenstra/backend-agent-manager/src/migrations --module commonjs --target es2021 --moduleResolution node --esModuleInterop --skipLibCheck --resolveJsonModule --declaration false --rootDir apps/agenstra/backend-agent-manager/src/migrations",
"npx esbuild apps/agenstra/backend-agent-manager/src/scripts/install-provider-plugins.ts --bundle --platform=node --target=node20 --format=cjs --outfile=dist/apps/agenstra/backend-agent-manager/install-provider-plugins.js --tsconfig=tsconfig.base.json --packages=external"
]
}
},
"verify-install-provider-plugins": {
"dependsOn": ["compile-migrations"],
"executor": "nx:run-commands",
"options": {
"command": "bash tools/ci/verify-install-provider-plugins.sh dist/apps/agenstra/backend-agent-manager/install-provider-plugins.js",
"cwd": "{workspaceRoot}"
}
},
"prune": {
"dependsOn": [
"prune-lockfile",
"copy-workspace-modules",
"compile-migrations"
"compile-migrations",
"verify-install-provider-plugins"
],
"executor": "nx:noop"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { installProviderPluginsFromEnv } from '@forepath/shared/backend/util-dynamic-provider-registry';

async function main(): Promise<void> {
await installProviderPluginsFromEnv();
}

main().catch((error: unknown) => {
console.error(error);
process.exit(1);
});
5 changes: 5 additions & 0 deletions apps/agenstra/frontend-docs/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@
"glob": "**/*.yaml",
"input": "libs/domains/agenstra/backend/feature-agent-manager/spec",
"output": "spec/agent-manager"
},
{
"glob": "**/*.yaml",
"input": "libs/domains/decabill/backend/feature-billing-manager/spec",
"output": "spec/billing-manager"
}
],
"styles": [
Expand Down
Loading
Loading