Manual for operators and administrators: commissioning and hardening, users and roles, tenants and budgets, adapter governance, policy-as-code, compliance profiles, attestation and audit export, supply chain, operations.
As of version 0.30.0. Deutsche Version:
administrationshandbuch.md. The end-user manual is the user manual.
Contents
- Who this manual is for
- Commissioning and hardening
- Users and roles
- Tenants
- Adapter and model governance
- Approvals and segregation of duties
- Policy-as-code
- Compliance profiles
- Attestation and chain verification
- Why-trace and audit export
- Supply chain: SBOM and dependency scan
- Cost and budgets
- Skill and plugin library
- Operations: monitoring, backup, air-gap
- Settings reference
- Troubleshooting for administrators
- Known limits
1. Who this manual is for
This manual addresses operators (installation, hardening, backup) and administrators (users, tenants, rules, evidence). It assumes the user manual, which covers project creation, runs and the quality gate from an end-user perspective.
Supported operating modes:
| Mode | Description |
|---|---|
| Single seat | One person, one machine, usually a coding CLI in subscription mode |
| Team | Several users on one instance, RBAC active |
| Multi-tenant | Several mutually isolated tenants on one instance |
| Air-gap | No network: local model, network-less sandbox, licence without callback |
Not covered: public SaaS with self-registration (see ../production-scope.md).
2. Commissioning and hardening
2.1 Mandatory values before the first start
| Variable | Requirement |
|---|---|
SOFTWAREFABRIK_DB_PASSWORD |
β₯ 16 chars, random (openssl rand -base64 16) |
SOFTWAREFABRIK_SECRETS_MASTER_KEY |
β₯ 32 chars, random (openssl rand -base64 48) |
SOFTWAREFABRIK_ADMIN_USER / _PASSWORD |
Bootstrap admin; without a password no admin is created |
SOFTWAREFABRIK_WORKSPACES_ROOT |
Directory for project workspaces |
The application deliberately fails fast:
- Docker Compose aborts without
.env(${VAR:?β¦}). - In the
containerprofileSecretsEncryptorhard-rejects known demo values and keys that are too short. DbCredentialsValidatorchecks database credentials at startup.- In the Compose stack PostgreSQL is bound to
127.0.0.1.
2.2 Attestation key
SOFTWAREFABRIK_ATTESTATION_SIGNING_ENABLED=true
SOFTWAREFABRIK_ATTESTATION_KEY_ID=<meaningful-id>
SOFTWAREFABRIK_ATTESTATION_PRIVATE_KEY=/path/to/ed25519-key.pem
# optional: SOFTWAREFABRIK_ATTESTATION_KEYRING_PATH for key rotation
Development and test use an ephemeral key. In the container/prod profiles, enabled without a key is a startup error. Running without signatures must be declared explicitly (β¦SIGNING_ENABLED=false). Security should be a decision, not an oversight.
The key must go into the backup. Without it the audit chain can no longer be verified later.
2.3 Remote hardening
SOFTWAREFABRIK_GIT_ALLOWED_HOSTS=github.com,git.company.com # allowlist
SOFTWAREFABRIK_GIT_PR_FEEDBACK_ENABLED=false # default
The factory uses the GitHub token and issues API calls only for hosts on the allowlist. Without that boundary a manipulated remote URL could exfiltrate the factory-wide token (SSRF). GIT_ALLOW_PROTOCOL is set as well, to rule out attacks via the git ext:: remote helper.
The PR/CI poller is deliberately opt-in: unattended periodic remote contact should be a conscious operational decision.
2.4 Sandbox
Settings β execution.sandbox.variant = local | container
execution.sandbox.image
execution.sandbox.docker-binary
Container mode starts every agent run in an ephemeral container with --cpus 2 --memory 4g --pids-limit 512 --read-only, a bind mount restricted to the workspace and --network=none. If Docker is missing from the PATH the platform falls back to the local process sandbox with a log warning.
Recommendation: build runs execute agent-generated code. Run them on a host without sensitive access and enable container mode.
2.5 Demo profile
The demo profile installs an auto-login filter that treats every visitor as a shared demo user, plus a demo banner. It is meant exclusively for a public demo instance, never for production.
3. Users and roles
UI: /admin/nutzer (ADMIN only)
Create accounts, assign tenant and role, activate/deactivate accounts and reset passwords. A lockout guard kicks in after repeated failures.
Role model
VIEWER < DEVELOPER < MAINTAINER < OWNER < ADMIN
| Capability | from role |
|---|---|
| read | VIEWER |
| execute runs | DEVELOPER |
| approve runs | MAINTAINER |
| manage integrations/secrets | MAINTAINER |
| tenant administration | OWNER |
Important: ADMIN is not a data super-admin. Administrators remain tenant-scoped for projects, runs, logs and cost. Only account management and project assignment are isolation-free. A genuine operator view goes through the operator endpoints, not through an elevated data role.
SSO (OIDC)
Optional and config-gated (see ../sso-oidc.md). JIT-provisioned users deliberately get VIEWER without a tenant β an SSO connection must never widen access by accident. Assigning tenant and role stays an administrative act.
4. Tenants
UI: /mandanten
- Create tenants and assign projects.
- A user belongs to one tenant (
app_user.tenant_id);nullmeans single-tenant operation. - Projects, runs and all derived data are tenant-scoped. Access via a foreign ID fails (covered by an IDOR test).
- Policy, audit, cost and export are separated per tenant.
For hard separation: tenants are sufficient in most cases. Where maximum separation is required (e.g. VS-NfD), one instance per tenant remains the most conservative option.
5. Adapter and model governance
Three levels, from wide to narrow:
- Global:
execution.adapter.defaultandexecution.<adapter>.modelin Settings. - Project: allowed adapters per project (
project_allowed_adapters) plus a model policy (/projects/{id}β model policy). It is enforced when a run is created and attested asRUN_MODELL_AUFGELOEST. - Tenant: policy-as-code (chapter 7) can restrict allowed adapters tenant-wide; a tenant policy can only tighten the global one, never undercut it (global policy floor).
Capability routing: run.routing.plan-model and run.routing.build-model separate model choice for planning and implementation. Planning may get a stronger, more expensive model than mechanical implementation β without hard-wiring a model name anywhere.
Operating mode: betrieb.modus distinguishes single-seat subscription from a team API pool.
Subscription modes (execution.<adapter>.auth-mode = api-key | subscription) for Claude, Codex and Kimi. In subscription mode the factory actively strips the corresponding API key from the subprocess β otherwise the CLI would silently take the paid path.
6. Approvals and segregation of duties
There are two approval points per build run:
| Point | Effect |
|---|---|
before EXECUTION |
The agent only runs after approval |
before the merge (in VALIDATION) |
The validated state is merged or turned into a PR only after approval |
The second point is decisive for regulated profiles: without it the signed assurance would be a faΓ§ade β the code would already be on the base branch before anyone agreed.
Controls:
run.approval-vor-mergeβ mandatory approval before mergingrun.approval-segregationβ segregation of duties: whoever triggered the run (run.triggered_by) cannot approve it- Approval policies under
/policies
Approving requires role MAINTAINER or higher. Every decision is recorded as an approval_decision and as an attested audit event.
7. Policy-as-code
UI: /policy-as-code (ADMIN only)
Rules are not configuration state but a versioned, signed document:
| Field | Meaning |
|---|---|
erlaubteAdapter |
vendor restriction (empty = unrestricted) |
gateModus |
off / advisory / blocking |
pflichtFreigabePhasen |
e.g. EXECUTION, VALIDATION |
pflichtAttestierung |
signing mandatory |
Properties:
- Exactly one active version per tenant β technically enforced.
- Ed25519-signed over the canonical text.
- Enforced twice: when a run is created and again at execution time. Otherwise a run created before activation could bypass the policy; besides, why-trace and export must report the version that was actually enforced.
Workflow: edit content β publish (creates a new signed version and deactivates the previous one) β verify checks the signature.
Rejected runs produce RUN_POLICY_DENIED β the rejection is evidence too.
8. Compliance profiles
UI: /compliance-profile (ADMIN only)
Applying a profile publishes a matching signed policy version and emits COMPLIANCE_PROFILE_APPLIED.
| Profile | Gate | Mandatory approvals | Attestation |
|---|---|---|---|
| Baseline | advisory | β | no |
| EU AI Act | blocking | EXECUTION | yes |
| BAIT / MaRisk / DORA | blocking | EXECUTION, VALIDATION | yes |
| BSI Grundschutz / VS-NfD | blocking | EXECUTION, VALIDATION | yes |
Regulatory reference: EU AI Act = Regulation (EU) 2024/1689, Art. 12 (record-keeping) and Art. 14 (human oversight); BAIT/MaRisk (BaFin) and DORA (EU 2022/2554) = ICT and third-party risk, evidence duties; BSI IT-Grundschutz and VS-NfD for the public sector.
Honest framing: the profiles enforce the technically enforceable parts. They do not replace legal advice and do not cover organisational duties. For VS-NfD the adapter choice must additionally be restricted to local/sovereign backends per project β regional data residency is enforced through gateway configuration, not through the profile.
9. Attestation and chain verification
UI: /attestierung (ADMIN only)
Every audit event carries seq, prev_hash, entry_hash, signature and key_id. Verification distinguishes three failure modes:
| Finding | Meaning |
|---|---|
HASH_MISMATCH |
an entry was modified after the fact |
CHAIN_BREAK |
an entry was removed or inserted |
BAD_SIGNATURE |
the entry does not come from the expected key |
Legacy entries without a signature are reported transparently as such instead of failing the check.
Attested events (selection): run lifecycle, model resolution, policy application and denial, guardrails application, quality-gate result, SBOM creation, artifact signature, policy publication, profile application, approvals.
Operational advice: run the chain check after every restore and on a regular schedule. An incomplete backup shows up as CHAIN_BREAK β the evidence structure doubles as an integrity check of the backup.
10. Why-trace and audit export
Why-trace: /runs/{id}/trace answers, for a single run, why the code came about the way it did: which model, which policy version, which approvals by whom, which gate result, which plan origin, which cost.
Audit export: /export (ADMIN only) produces an auditable bundle per project or run β JSON and HTML β from why-trace, chain verification, the governing policy state and the public key.
The bundle is deliberately serialized deterministically (strings, primitives and UUIDs only, timestamps as ISO-8601). Evidence that looks different depending on the library version is not evidence.
Typical audit case: the auditor asks about a specific change β find the run β the why-trace shows model, rule, approval β export produces the bundle β the auditor verifies signatures offline with the enclosed public key.
11. Supply chain: SBOM and dependency scan
| Building block | Control |
|---|---|
| SBOM per build | run.sbom.mode (default off); requires Trivy on the PATH, degrades gracefully otherwise |
| Artifact signature | Ed25519 over the SBOM digest, event ARTEFAKT_SIGNIERT |
| Dependency/licence scan | Reviewer dependency-scan in the quality gate; CVE findings in the SECURITY category block the merge |
For regulated environments: set SBOM to on and the quality gate to blocking; then every delivered state can be shown to have declared and checked its dependencies.
12. Cost and budgets
Views:
| Route | Content |
|---|---|
/analytics |
cost per project, run, provider, comparison; each as CSV |
/mandanten/kosten |
consumption per tenant (+ .csv) |
/mandanten/seat-kosten |
consumption per seat β the triggering user, derived from run.triggered_by (+ .csv) |
Setting limits:
mandant_budgetβ monthly EUR budget per tenant, either observing only or as a hard cap (enforce). Exceeding it prevents new runs.budget.daily.tokens/budget.weekly.tokensβ token limits with a soft threshold.- The capacity guard limits the number of concurrent runs.
Prices: the model price table lives in application.yml (softwarefabrik.models; input/output/cached per 1M tokens). Unknown models are valued at β¬0 β deliberately conservative. Subscription models (k3, kimi-for-coding) are also at β¬0 because a flat rate incurs no token cost; the cost view therefore reflects marginal cost, not licence cost.
13. Skill and plugin library
UI: /skills
Entries are tenant-scoped and versioned; origin is typed: CATALOG (curated), INSTALLED (adopted), FORKED (adapted). Before each run the platform materializes them into the workspace:
<workspace>/.claude/skills/<name>/SKILL.md
<workspace>/.claude/agents/<role>.md
<workspace>/.claude/settings.local.json
This makes it answerable which extension, in which version, was in the agent's context at the time of a run β the question every reproducibility discussion otherwise founders on.
Engineering guardrails (run.guardrails.mode) are separate: a vendor-neutral behavioural policy projected into the repo as AGENTS.md (plus a minimal CLAUDE.md pointing at it). Its version is a SHA-256 short hash of the content and is recorded as RUN_GUARDRAILS_ANGEWENDET.
14. Operations: monitoring, backup, air-gap
Monitoring
| Endpoint | Content |
|---|---|
/actuator/health |
incl. secrets health indicator |
/actuator/info |
version and build number |
/actuator/prometheus |
metrics (ROLE_ADMIN only) |
Logback writes projectId, runId and phase into the MDC.
Backup
Three things must be backed up:
- the PostgreSQL database,
- the workspace directory (contains the projects' Git repositories),
- the attestation key and the secrets master key.
Procedure: ../backup-restore.md. After a restore, run the chain check under /attestierung.
Air-gap
| Requirement | Implementation |
|---|---|
| No vendor cloud access | adapter local-llm (Ollama/vLLM/LM Studio) |
| No network for the agent | container sandbox with --network=none |
| No licence callback | ADR-0009 (refresh-required=false) |
| No remote coupling | PR poller off, allowlist empty or internal |
Delivery: ../runbooks/airgap-auslieferung.md.
15. Settings reference
All settings follow the scope hierarchy PROJECT > USER > GLOBAL > YAML and take effect without a restart (max. 5 minutes of caching).
| Key | Meaning |
|---|---|
betrieb.modus |
single-seat subscription or team API pool |
execution.adapter.default |
default adapter |
execution.<adapter>.model |
default model per adapter |
execution.<adapter>.auth-mode |
api-key or subscription (claude, codex, kimi) |
execution.<adapter>.subscription.config-dir |
alternate credential directory |
execution.sandbox.variant |
local or container |
execution.sandbox.image / .docker-binary |
container sandbox details |
run.quality-gate.mode |
off / advisory / blocking |
run.quality-gate.policy |
strict or lenient |
run.approval-vor-merge |
mandatory approval before merging |
run.approval-segregation |
segregation of duties |
run.auto-followup-plan |
follow-up plan run after a successful build |
run.guardrails.mode |
guardrails projection |
run.sbom.mode |
SBOM creation per build |
run.routing.plan-model / .build-model |
capability routing |
budget.daily.tokens / budget.weekly.tokens |
token limits |
git.pr-feedback.enabled |
PR/CI poller |
workspace.root |
workspace root |
Vendor keys are not managed here but under /integrations (AES-GCM encrypted, with provider validation for Anthropic, OpenAI, Gemini, Kimi, GitHub and NVD).
16. Troubleshooting for administrators
- Application won't start, message about master key / demo value β the
containerprofile deliberately forbids demo values and short keys. Set a random value. - Startup aborts with an attestation error β signing is enabled but no key is configured. Either provide a key or set
β¦SIGNING_ENABLED=falseexplicitly. - Chain check reports
BAD_SIGNATUREafter a key rotation β keep the old key available via the keyring path; otherwise older entries can no longer be verified. - A user (even ADMIN) does not see foreign projects β correct:
ADMINis not a data super-admin. Work through tenant assignment. - Run rejected with
RUN_POLICY_DENIEDβ the active policy does not allow the chosen adapter or model. Check the policy or switch adapters; the rejection is documented in the audit trail. - Run stuck in
WAITING_FOR_APPROVALβ mandatory approval is active. Check who may approve (MAINTAINERand above) and whether segregation of duties excludes the triggering user. - Quality gate reports
ERRORβ a reviewer crashed (e.g. missing CLI). Deliberately not a silent pass: install the CLI or adjust the gate mode. - No SBOM produced β
run.sbom.modeisoffor Trivy is missing from the PATH. - Cost shows β¬0 β either a subscription model (flat rate, correct) or a model without an entry in the price table.
17. Known limits
| Limit | Meaning |
|---|---|
| One active run per project | Different projects run in parallel; runs of the same project run sequentially |
| Budget caps per tenant | The seat view reports but does not constrain |
| PR/CI feedback for GitHub only | GitLab/Bitbucket/Azure DevOps not connected; the local merge applies there |
| Cloud gateways experimental | Bedrock/Vertex/Azure OpenAI not verified end-to-end |
| Sandbox default is local | Container mode is available but not the default |
Current version: ../production-scope.md. Technical depth: ../governance-compliance.md.