Company as Code: Es braucht keine neue DSL
Foto ist KI-generiert

Wer schon einmal ein Compliance-Audit begleitet hat, kennt das Muster. Jemand fragt nach dem Nachweis, dass Richtlinie X für System Y gilt. Man durchsucht SharePoint, Confluence oder – im schlimmsten Fall – das Postfach eines Kollegen. Man stellt ein PDF zusammen. Der Auditor nickt. Sechs Monate später beginnt das Spiel von vorn.

Die Information existiert. Sie steckt nur in Formaten, die keine Fragen beantworten können.

Daniel Rothmann hat diese Lücke kürzlich beschrieben und sie Company as Code genannt. Seine Beobachtung: Wir versionieren unsere Infrastruktur, unsere Deployments, unsere Policy-as-Code-Regeln – aber nicht das organisatorische Gerüst, das alles zusammenhält. Richtlinien, Rollen, Organisationseinheiten, Compliance-Zuordnungen – all das lebt in Dokumenten, die niemand abfragen kann. Er schlägt eine eigene DSL vor, um das zu lösen.

Die Diagnose stimmt. Aber die Therapie übersieht etwas: Das Werkzeug existiert bereits.

Das Traceability-Problem ist nicht neu

In der automobilen Cybersicherheit ist Nachverfolgbarkeit keine Option – sie ist vorgeschrieben. ISO 21434 verlangt, dass man Bedrohungen über Risiken zu Anforderungen zu Maßnahmen bis hin zur Verifikation nachverfolgen kann. Eine TARA (Threat Analysis and Risk Assessment) erzeugt Dutzende miteinander verknüpfter Artefakte. Wenn ein Auditor fragt: “Welche Sicherheitsanforderung adressiert Bedrohung T-042, und wie wird sie verifiziert?” – dann braucht man eine Antwort in Sekunden, nicht in Stunden.

Das ist exakt das gleiche Problem, das Rothmann auf Organisationsebene beschreibt. Richtlinien referenzieren Rollen. Rollen sind Personen zugeordnet. Personen betreiben Systeme. Systeme müssen externe Anforderungen erfüllen. Es ist ein Graph von Beziehungen – und wir speichern ihn in flachen Dokumenten.

Die Compliance-Welt hat das Traceability-Problem für Requirements Engineering längst gelöst. Die Werkzeuge existieren. Sie wurden nur noch nicht auf Organisationsstrukturen angewendet.

sphinx-needs kann das bereits

Rothmann definiert fünf Anforderungen an ein Company-as-Code-System: abfragbar, versionierbar, integrierbar, testbar und zugänglich. sphinx-needs erfüllt vier davon direkt.

Abfragbar. needtable und needfilter ermöglichen Abfragen über alle definierten Objekte nach Typ, Status, Tags oder beliebigen eigenen Feldern. “Zeige mir alle Richtlinien, die der Rolle R_CISO zugeordnet sind” – das ist ein Einzeiler.

Versionierbar. Es ist Sphinx. Es lebt in Git. Jede Änderung an einer Richtlinie, Rolle oder Organisationseinheit hat einen Commit-Hash, ein Diff und ein Blame.

Testbar. Hier geht sphinx-needs über das hinaus, was Rothmann skizziert. Es bietet nicht nur Prüfungen – es liefert Schema-Validierung und damit effektiv Strong Typing für Dokumentation. Man definiert erlaubte Status-Werte, erzwingt ID-Formate per Regex, verlangt explizite IDs, schränkt Tags ein und setzt strukturelle Constraints über needs_warnings, die den Build fehlschlagen lassen. Eine Richtlinie ohne Verantwortlichen? Build schlägt fehl. Eine Rolle, die auf eine nicht existierende Organisationseinheit verweist? Build schlägt fehl. Die CI-Pipeline gated nicht nur Code – sie gated die Organisationsdokumentation mit derselben Strenge. Es ist Type-Checking für das Unternehmen.

Zugänglich. Es rendert zu HTML. Nicht-technische Stakeholder lesen eine Website, keine RST-Dateien.

Die fünfte Anforderung – integrierbar – ist der Punkt, an dem man erweitern muss. sphinx-needs zieht nicht von allein das Organigramm aus Azure AD. Aber seine Import/Export-Mechanismen und needs.json liefern die Schnittstellen, um genau das zu bauen.

So sieht es aus

Die Konfiguration lebt in einer ubproject.toml. Kein Python. Nur TOML. Das Compliance-Team kann das lesen.

# ubproject.toml
"$schema" = "https://ubcode.useblocks.com/ubproject.schema.json"

[project]
name = "ACME Corp - Company as Code"
description = "Organizational policies, roles, and compliance as code"
srcdir = "."

[needs]
id_required = true
id_regex = "[A-Z_]{2,10}(_[\d]{1,3})*"

extra_options = [
    "owner",
    "department",
    "effective_date",
]

[[needs.types]]
directive = "role"
title = "Role"
prefix = "R_"
color = "#BFD8D2"
style = "actor"

[[needs.types]]
directive = "policy"
title = "Policy"
prefix = "P_"
color = "#DCB239"
style = "node"

[[needs.types]]
directive = "org"
title = "Org Unit"
prefix = "OU_"
color = "#9856a5"
style = "frame"

[[needs.extra_links]]
option = "governs"
outgoing = "governs"
incoming = "governed by"

[[needs.extra_links]]
option = "assigned_to"
outgoing = "assigned to"
incoming = "has role"

Dann definiert man die organisatorischen Artefakte in RST – genauso wie man Anforderungen definieren würde:

.. role:: Chief Information Security Officer
   :id: R_CISO
   :status: active
   :assigned_to: OU_SECURITY

   Responsible for information security strategy and compliance.

.. policy:: Data Retention Policy
   :id: P_DATA_RET
   :status: active
   :governs: R_CISO
   :owner: Legal Department
   :effective_date: 2025-01-01

   All customer data must be retained for 5 years and deleted
   after the retention period unless legally required otherwise.

Wenn der Auditor kommt, durchsucht man kein SharePoint. Man fragt ab:

.. needtable::
   :filter: type == 'policy' and 'R_CISO' in governs
   :columns: id;title;status
   :style: table

Das war’s. Eine gerenderte Tabelle aller Richtlinien, die der CISO-Rolle zugeordnet sind – generiert aus Quelldateien, die die CI bereits validiert.

Wo es passt und wo es an Grenzen stößt

sphinx-needs deckt die Dokumentationsschicht gut ab. Richtlinien, Rollen, Organisationseinheiten und ihre Beziehungen leben in versionskontrollierten RST-Dateien. Die CI validiert sie. Der Auditor liest gerendertes HTML. Das ist der 80%-Fall.

Aber Rothmanns Vision geht weiter. Er will Runtime-Integration – Organigramme aus Azure AD ziehen, Rollenzuweisungen aus HR-Systemen synchronisieren, Slack-Benachrichtigungen auslösen, wenn sich eine Richtlinie ändert. Dafür wurde sphinx-needs nicht gebaut. Es ist ein Build-Time-Tool, keine Runtime-Plattform.

Hier würde ich die Grenze ziehen: sphinx-needs als Single Source of Truth nutzen, nicht als Integrationsbus. Man exportiert needs.json aus dem Build. Eine separate Pipeline synchronisiert dieses JSON mit den tatsächlichen Systemen. Wenn Azure AD sagt, jemand hat die CISO-Rolle, aber das Manifest nicht – dann ist das ein Drift-Alert. Dasselbe Muster, das GitOps für Infrastruktur nutzt.

Man braucht am ersten Tag keine eigene DSL, keine Graph-Datenbank und keinen Event Store. Man braucht eine Textdatei in Git, die das Build-System validiert. Alles andere ist Iteration.

Der erste Commit zählt

Die besten Infrastructure-as-Code-Tools haben nicht als große Plattformen angefangen. Terraform begann als eine Möglichkeit, Cloud-Ressourcen in Textdateien zu beschreiben. Kubernetes-Manifeste sind einfach YAML. Die Kraft kommt aus dem Ökosystem, das um ein einfaches, korrektes Primitiv wächst.

sphinx-needs ist dieses Primitiv für Documentation-as-Code. Rothmann hat recht, dass Company as Code die fehlende Schicht ist. Aber die Antwort liegt nicht darin, etwas Neues von Grund auf zu bauen. Sie liegt darin, ein Werkzeug zu nehmen, das bereits typisierte Objekte, Traceability, Schema-Validierung und abfragbare Beziehungen beherrscht – und es auf eine neue Domäne zu richten.

Die Werkzeuge existieren. Die Community existiert. Was fehlt, ist der erste Commit.