- STATUS.md: migration count 18→23, endpoint count 86→~140, add approval workflows, solver service, workstations, edit sessions, SSE targeted delivery rows, update test file count 9→31, add migrations 019-023 - MODULES.md: add solver and sessions to registry, dependencies, endpoint mappings (sections 3.11, 3.12), discovery response, admin settings, config YAML, and future considerations - CONFIGURATION.md: add Approval Workflows, Solver, and Modules config sections, add SILO_SOLVER_DEFAULT env var - ROADMAP.md: mark Job Queue Complete (Tier 0), Audit Trail Complete (Tier 1), Approval/ECO Complete (Tier 4), update Workflow Engine tasks, add Recently Completed section, update counts, resolve job queue question - GAP_ANALYSIS.md: mark approval workflow Implemented, locking Partial, update workflow comparison (C.2), update check-in/check-out to Partial, task scheduler to Full, update endpoint counts, rewrite Appendix A - INSTALL.md: add MODULES.md, WORKERS.md, SOLVER.md to Further Reading - WORKERS.md: status Draft→Implemented - SOLVER.md: add spec doc, mark Phase 3b as complete
427 lines
14 KiB
Markdown
427 lines
14 KiB
Markdown
# Configuration Reference
|
|
|
|
**Last Updated:** 2026-03-01
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Silo is configured via a YAML file. Copy the example and edit for your environment:
|
|
|
|
```bash
|
|
cp config.example.yaml config.yaml
|
|
```
|
|
|
|
The server reads the config file at startup:
|
|
|
|
```bash
|
|
./silod -config config.yaml # default: config.yaml
|
|
go run ./cmd/silod -config config.yaml
|
|
```
|
|
|
|
YAML values support environment variable expansion using `${VAR_NAME}` syntax. Environment variable overrides (listed per-key below) take precedence over YAML values.
|
|
|
|
---
|
|
|
|
## Server
|
|
|
|
| Key | Type | Default | Description |
|
|
|-----|------|---------|-------------|
|
|
| `server.host` | string | `"0.0.0.0"` | Bind address |
|
|
| `server.port` | int | `8080` | HTTP port |
|
|
| `server.base_url` | string | — | External URL (e.g. `https://silo.example.com`). Used for OIDC callback URLs and session cookie domain. Required when OIDC is enabled. |
|
|
| `server.read_only` | bool | `false` | Start in read-only mode. All write endpoints return 503. Can be toggled at runtime with `SIGUSR1`. |
|
|
|
|
```yaml
|
|
server:
|
|
host: "0.0.0.0"
|
|
port: 8080
|
|
base_url: "https://silo.example.com"
|
|
read_only: false
|
|
```
|
|
|
|
---
|
|
|
|
## Database
|
|
|
|
| Key | Type | Default | Env Override | Description |
|
|
|-----|------|---------|-------------|-------------|
|
|
| `database.host` | string | — | `SILO_DB_HOST` | PostgreSQL host |
|
|
| `database.port` | int | `5432` | — | PostgreSQL port |
|
|
| `database.name` | string | — | `SILO_DB_NAME` | Database name |
|
|
| `database.user` | string | — | `SILO_DB_USER` | Database user |
|
|
| `database.password` | string | — | `SILO_DB_PASSWORD` | Database password |
|
|
| `database.sslmode` | string | `"require"` | — | SSL mode: `disable`, `require`, `verify-ca`, `verify-full` |
|
|
| `database.max_connections` | int | `10` | — | Connection pool size |
|
|
|
|
**SSL mode guidance:**
|
|
- `disable` — development only, no encryption
|
|
- `require` — encrypted but no certificate verification (default)
|
|
- `verify-ca` — verify server certificate is signed by trusted CA
|
|
- `verify-full` — verify CA and hostname match (recommended for production)
|
|
|
|
```yaml
|
|
database:
|
|
host: "localhost"
|
|
port: 5432
|
|
name: "silo"
|
|
user: "silo"
|
|
password: "" # use SILO_DB_PASSWORD env var
|
|
sslmode: "require"
|
|
max_connections: 10
|
|
```
|
|
|
|
---
|
|
|
|
## Storage (Filesystem)
|
|
|
|
Files are stored on the local filesystem under a configurable root directory.
|
|
|
|
| Key | Type | Default | Description |
|
|
|-----|------|---------|-------------|
|
|
| `storage.backend` | string | `"filesystem"` | Storage backend (`filesystem`) |
|
|
| `storage.filesystem.root_dir` | string | — | Root directory for file storage (required) |
|
|
|
|
```yaml
|
|
storage:
|
|
backend: "filesystem"
|
|
filesystem:
|
|
root_dir: "/opt/silo/data"
|
|
```
|
|
|
|
Ensure the directory exists and is writable by the `silo` user:
|
|
|
|
```bash
|
|
sudo mkdir -p /opt/silo/data
|
|
sudo chown silo:silo /opt/silo/data
|
|
```
|
|
|
|
---
|
|
|
|
## Schemas
|
|
|
|
| Key | Type | Default | Description |
|
|
|-----|------|---------|-------------|
|
|
| `schemas.directory` | string | `"/etc/silo/schemas"` | Path to directory containing YAML schema files |
|
|
| `schemas.default` | string | — | Default schema name for part number generation |
|
|
|
|
Schema files define part numbering formats, category codes, and property definitions. See `schemas/kindred-rd.yaml` for an example.
|
|
|
|
```yaml
|
|
schemas:
|
|
directory: "./schemas"
|
|
default: "kindred-rd"
|
|
```
|
|
|
|
---
|
|
|
|
## FreeCAD
|
|
|
|
| Key | Type | Default | Description |
|
|
|-----|------|---------|-------------|
|
|
| `freecad.uri_scheme` | string | `"silo"` | URI scheme for "Open in FreeCAD" links in the web UI |
|
|
| `freecad.executable` | string | — | Path to FreeCAD binary (for CLI operations) |
|
|
|
|
```yaml
|
|
freecad:
|
|
uri_scheme: "silo"
|
|
executable: "/usr/bin/freecad"
|
|
```
|
|
|
|
---
|
|
|
|
## Odoo ERP Integration
|
|
|
|
| Key | Type | Default | Description |
|
|
|-----|------|---------|-------------|
|
|
| `odoo.enabled` | bool | `false` | Enable Odoo integration |
|
|
| `odoo.url` | string | — | Odoo server URL |
|
|
| `odoo.database` | string | — | Odoo database name |
|
|
| `odoo.username` | string | — | Odoo username |
|
|
| `odoo.api_key` | string | — | Odoo API key |
|
|
|
|
The Odoo integration currently supports configuration and sync-log CRUD. Push/pull sync operations are stubs.
|
|
|
|
```yaml
|
|
odoo:
|
|
enabled: false
|
|
url: "https://odoo.example.com"
|
|
database: "odoo"
|
|
username: "silo-service"
|
|
api_key: ""
|
|
```
|
|
|
|
---
|
|
|
|
## Approval Workflows
|
|
|
|
| Key | Type | Default | Description |
|
|
|-----|------|---------|-------------|
|
|
| `workflows.directory` | string | `"/etc/silo/workflows"` | Path to directory containing YAML workflow definition files |
|
|
|
|
Workflow definition files describe multi-stage approval processes using a state machine pattern. Each file defines a workflow with states, transitions, and approver requirements.
|
|
|
|
```yaml
|
|
workflows:
|
|
directory: "/etc/silo/workflows"
|
|
```
|
|
|
|
---
|
|
|
|
## Solver
|
|
|
|
| Key | Type | Default | Env Override | Description |
|
|
|-----|------|---------|-------------|-------------|
|
|
| `solver.default_solver` | string | `""` | `SILO_SOLVER_DEFAULT` | Default solver backend name |
|
|
| `solver.max_context_size_mb` | int | `10` | — | Maximum SolveContext payload size in MB |
|
|
| `solver.default_timeout` | int | `300` | — | Default solver job timeout in seconds |
|
|
| `solver.auto_diagnose_on_commit` | bool | `false` | — | Auto-submit diagnose job on assembly revision commit |
|
|
|
|
The solver module depends on the `jobs` module being enabled. See [SOLVER.md](SOLVER.md) for the full solver service specification.
|
|
|
|
```yaml
|
|
solver:
|
|
default_solver: "ondsel"
|
|
max_context_size_mb: 10
|
|
default_timeout: 300
|
|
auto_diagnose_on_commit: true
|
|
```
|
|
|
|
---
|
|
|
|
## Modules
|
|
|
|
Optional module toggles. Each module can be explicitly enabled or disabled. If not listed, the module's built-in default applies. See [MODULES.md](MODULES.md) for the full module system specification.
|
|
|
|
```yaml
|
|
modules:
|
|
projects:
|
|
enabled: true
|
|
audit:
|
|
enabled: true
|
|
odoo:
|
|
enabled: false
|
|
freecad:
|
|
enabled: true
|
|
jobs:
|
|
enabled: false
|
|
dag:
|
|
enabled: false
|
|
solver:
|
|
enabled: false
|
|
sessions:
|
|
enabled: true
|
|
```
|
|
|
|
The `auth.enabled` field controls the `auth` module directly (not duplicated under `modules:`). The `sessions` module depends on `auth` and is enabled by default.
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
Authentication has a master toggle and three independent backends. When `auth.enabled` is `false`, all routes are accessible without login and a synthetic admin user (`dev`) is injected into every request.
|
|
|
|
| Key | Type | Default | Env Override | Description |
|
|
|-----|------|---------|-------------|-------------|
|
|
| `auth.enabled` | bool | `false` | — | Master toggle. Set `true` for production. |
|
|
| `auth.session_secret` | string | — | `SILO_SESSION_SECRET` | Secret for signing session cookies. Required when auth is enabled. |
|
|
|
|
### Local Auth
|
|
|
|
Built-in username/password accounts stored in the Silo database with bcrypt-hashed passwords.
|
|
|
|
| Key | Type | Default | Env Override | Description |
|
|
|-----|------|---------|-------------|-------------|
|
|
| `auth.local.enabled` | bool | — | — | Enable local accounts |
|
|
| `auth.local.default_admin_username` | string | — | `SILO_ADMIN_USERNAME` | Default admin account created on first startup |
|
|
| `auth.local.default_admin_password` | string | — | `SILO_ADMIN_PASSWORD` | Password for default admin (bcrypt-hashed on creation) |
|
|
|
|
The default admin account is only created if both username and password are set and the user does not already exist. This is idempotent.
|
|
|
|
### LDAP / FreeIPA
|
|
|
|
| Key | Type | Default | Env Override | Description |
|
|
|-----|------|---------|-------------|-------------|
|
|
| `auth.ldap.enabled` | bool | `false` | — | Enable LDAP authentication |
|
|
| `auth.ldap.url` | string | — | — | LDAP server URL (e.g. `ldaps://ipa.example.com`) |
|
|
| `auth.ldap.base_dn` | string | — | — | Base DN for the LDAP tree |
|
|
| `auth.ldap.user_search_dn` | string | — | — | DN under which to search for users |
|
|
| `auth.ldap.bind_dn` | string | — | — | Service account DN for user lookups (optional; omit for direct user bind) |
|
|
| `auth.ldap.bind_password` | string | — | `SILO_LDAP_BIND_PASSWORD` | Service account password |
|
|
| `auth.ldap.user_attr` | string | `"uid"` | — | LDAP attribute for username |
|
|
| `auth.ldap.email_attr` | string | `"mail"` | — | LDAP attribute for email |
|
|
| `auth.ldap.display_attr` | string | `"displayName"` | — | LDAP attribute for display name |
|
|
| `auth.ldap.group_attr` | string | `"memberOf"` | — | LDAP attribute for group membership |
|
|
| `auth.ldap.role_mapping` | map | — | — | Maps LDAP group DNs to Silo roles (see example below) |
|
|
| `auth.ldap.tls_skip_verify` | bool | `false` | — | Skip TLS certificate verification (testing only) |
|
|
|
|
**Role mapping** maps LDAP group DNs to Silo roles. Groups are checked in priority order: admin, then editor, then viewer. The first match wins.
|
|
|
|
```yaml
|
|
auth:
|
|
ldap:
|
|
enabled: true
|
|
url: "ldaps://ipa.example.com"
|
|
base_dn: "dc=example,dc=com"
|
|
user_search_dn: "cn=users,cn=accounts,dc=example,dc=com"
|
|
role_mapping:
|
|
admin:
|
|
- "cn=silo-admins,cn=groups,cn=accounts,dc=example,dc=com"
|
|
editor:
|
|
- "cn=silo-users,cn=groups,cn=accounts,dc=example,dc=com"
|
|
- "cn=engineers,cn=groups,cn=accounts,dc=example,dc=com"
|
|
viewer:
|
|
- "cn=silo-viewers,cn=groups,cn=accounts,dc=example,dc=com"
|
|
```
|
|
|
|
### OIDC / Keycloak
|
|
|
|
| Key | Type | Default | Env Override | Description |
|
|
|-----|------|---------|-------------|-------------|
|
|
| `auth.oidc.enabled` | bool | `false` | — | Enable OIDC authentication |
|
|
| `auth.oidc.issuer_url` | string | — | — | OIDC provider issuer URL (e.g. Keycloak realm URL) |
|
|
| `auth.oidc.client_id` | string | — | — | OAuth2 client ID |
|
|
| `auth.oidc.client_secret` | string | — | `SILO_OIDC_CLIENT_SECRET` | OAuth2 client secret |
|
|
| `auth.oidc.redirect_url` | string | — | — | OAuth2 callback URL (typically `{base_url}/auth/callback`) |
|
|
| `auth.oidc.scopes` | []string | `["openid", "profile", "email"]` | — | OAuth2 scopes to request |
|
|
| `auth.oidc.admin_role` | string | — | — | Keycloak realm role that grants admin access |
|
|
| `auth.oidc.editor_role` | string | — | — | Keycloak realm role that grants editor access |
|
|
| `auth.oidc.default_role` | string | `"viewer"` | — | Fallback role when no role claim matches |
|
|
|
|
Roles are extracted from the Keycloak `realm_access.roles` claim. If the user has the `admin_role`, they get admin. Otherwise if they have `editor_role`, they get editor. Otherwise `default_role` applies.
|
|
|
|
```yaml
|
|
auth:
|
|
oidc:
|
|
enabled: true
|
|
issuer_url: "https://keycloak.example.com/realms/silo"
|
|
client_id: "silo"
|
|
client_secret: "" # use SILO_OIDC_CLIENT_SECRET env var
|
|
redirect_url: "https://silo.example.com/auth/callback"
|
|
admin_role: "silo-admin"
|
|
editor_role: "silo-editor"
|
|
default_role: "viewer"
|
|
```
|
|
|
|
### CORS
|
|
|
|
| Key | Type | Default | Description |
|
|
|-----|------|---------|-------------|
|
|
| `auth.cors.allowed_origins` | []string | — | Origins allowed for cross-origin requests from browser-based clients |
|
|
|
|
FreeCAD and other non-browser clients use direct HTTP and are not affected by CORS. This setting is for browser-based tools running on different origins.
|
|
|
|
```yaml
|
|
auth:
|
|
cors:
|
|
allowed_origins:
|
|
- "https://silo.example.com"
|
|
```
|
|
|
|
---
|
|
|
|
## Environment Variables
|
|
|
|
All environment variable overrides. These take precedence over values in `config.yaml`.
|
|
|
|
| Variable | Config Key | Description |
|
|
|----------|-----------|-------------|
|
|
| `SILO_DB_HOST` | `database.host` | PostgreSQL host |
|
|
| `SILO_DB_NAME` | `database.name` | PostgreSQL database name |
|
|
| `SILO_DB_USER` | `database.user` | PostgreSQL user |
|
|
| `SILO_DB_PASSWORD` | `database.password` | PostgreSQL password |
|
|
| `SILO_SESSION_SECRET` | `auth.session_secret` | Session cookie signing secret |
|
|
| `SILO_ADMIN_USERNAME` | `auth.local.default_admin_username` | Default admin username |
|
|
| `SILO_ADMIN_PASSWORD` | `auth.local.default_admin_password` | Default admin password |
|
|
| `SILO_LDAP_BIND_PASSWORD` | `auth.ldap.bind_password` | LDAP service account password |
|
|
| `SILO_OIDC_CLIENT_SECRET` | `auth.oidc.client_secret` | OIDC client secret |
|
|
| `SILO_SOLVER_DEFAULT` | `solver.default_solver` | Default solver backend name |
|
|
|
|
Additionally, YAML values can reference environment variables directly using `${VAR_NAME}` syntax, which is expanded at load time via `os.ExpandEnv()`.
|
|
|
|
---
|
|
|
|
## Deployment Examples
|
|
|
|
### Development (no auth)
|
|
|
|
```yaml
|
|
server:
|
|
host: "0.0.0.0"
|
|
port: 8080
|
|
base_url: "http://localhost:8080"
|
|
|
|
database:
|
|
host: "localhost"
|
|
port: 5432
|
|
name: "silo"
|
|
user: "silo"
|
|
password: "silodev"
|
|
sslmode: "disable"
|
|
|
|
storage:
|
|
backend: "filesystem"
|
|
filesystem:
|
|
root_dir: "./data"
|
|
|
|
schemas:
|
|
directory: "./schemas"
|
|
default: "kindred-rd"
|
|
|
|
auth:
|
|
enabled: false
|
|
```
|
|
|
|
### Local Auth Only
|
|
|
|
```yaml
|
|
auth:
|
|
enabled: true
|
|
session_secret: "change-me-to-a-random-string"
|
|
local:
|
|
enabled: true
|
|
default_admin_username: "admin"
|
|
default_admin_password: "change-me"
|
|
```
|
|
|
|
### LDAP / FreeIPA
|
|
|
|
```yaml
|
|
auth:
|
|
enabled: true
|
|
session_secret: "${SILO_SESSION_SECRET}"
|
|
local:
|
|
enabled: false
|
|
ldap:
|
|
enabled: true
|
|
url: "ldaps://ipa.example.com"
|
|
base_dn: "dc=example,dc=com"
|
|
user_search_dn: "cn=users,cn=accounts,dc=example,dc=com"
|
|
role_mapping:
|
|
admin:
|
|
- "cn=silo-admins,cn=groups,cn=accounts,dc=example,dc=com"
|
|
editor:
|
|
- "cn=engineers,cn=groups,cn=accounts,dc=example,dc=com"
|
|
viewer:
|
|
- "cn=silo-viewers,cn=groups,cn=accounts,dc=example,dc=com"
|
|
```
|
|
|
|
### OIDC / Keycloak
|
|
|
|
```yaml
|
|
auth:
|
|
enabled: true
|
|
session_secret: "${SILO_SESSION_SECRET}"
|
|
local:
|
|
enabled: false
|
|
oidc:
|
|
enabled: true
|
|
issuer_url: "https://keycloak.example.com/realms/silo"
|
|
client_id: "silo"
|
|
client_secret: "${SILO_OIDC_CLIENT_SECRET}"
|
|
redirect_url: "https://silo.example.com/auth/callback"
|
|
admin_role: "silo-admin"
|
|
editor_role: "silo-editor"
|
|
default_role: "viewer"
|
|
```
|