# Design Document: Monorepo-Consolidation ## Overview Dieses Design beschreibt die technische Architektur für die Konsolidierung von 18+ einzelnen Repositories in eine einheitliche Monorepo-Struktur. Das System vereint Projekte aus drei Arbeitskontexten (privat, dhive, bahn) mit einem shared-Bereich, implementiert Sicherheitsgrenzen zwischen Kontexten, einen übergreifenden Wissensspeicher basierend auf der DB-Wissensdatenbank-ETL-Pipeline, integriert den bestehenden AI-Orchestrator, speichert Secrets verschlüsselt im Repository mittels git-crypt, und ermöglicht eine föderierte Zusammenarbeit über eigenständige Team-Repositories in einer Hub-and-Spoke-Topologie. ### Kernentscheidungen 1. **Git-Subtrees statt Submodules** für externe Repos und Team-Repos: Subtrees ermöglichen flache Checkouts ohne rekursive Init-Schritte und erlauben bidirektionale Synchronisation mit Upstream und Team-Repositories. 2. **Dateibasierte Zugriffskontrolle** statt OS-Level-Permissions: Ein Wrapper-Script (`ctx-guard`) prüft Kontextzugehörigkeit und kontrolliert den Zugriff auf .env-Dateien und Secrets. 3. **ETL-Pipeline-Fork** der DB-Wissensdatenbank als Basis für den Wissensspeicher: Wiederverwendung der bewährten Quellstrategien und Erweiterung um persönliche Arbeitskontexte. 4. **YAML-Frontmatter + YAML-Index** als Progressive-Disclosure-System: Agenten lesen zuerst den kompakten Index und laden nur bei Bedarf vollständige Dokumente. 5. **git-crypt für Encryption-at-Rest**: Secrets werden verschlüsselt im Repository gespeichert statt via .gitignore ausgeschlossen. Pro Arbeitskontext ein eigener GPG-/symmetrischer Schlüssel ermöglicht granulare Entschlüsselung per Maschinenkontext. 6. **Hub-and-Spoke-Föderation** für Multi-Team-Zusammenarbeit: Das Monorepo ist der zentrale Hub (nur Andre sieht alles), Team-Repos sind unabhängige Spokes. Synchronisation via Git-Subtrees bewahrt vollständige Historie. ## Architecture ```mermaid graph TB subgraph Monorepo["Monorepo Root (Hub)"] direction TB subgraph Contexts["Arbeitskontexte"] privat["privat/"] dhive["dhive/"] bahn["bahn/"] shared["shared/"] end subgraph SharedArea["shared/ Bereich"] tools["tools/"] powers["powers/"] knowledge["knowledge-store/"] config["config/"] mcpservers["mcp-servers/"] end subgraph Security["Sicherheitsschicht"] ctxguard["ctx-guard"] envfiles[".env pro Kontext (verschlüsselt)"] accessconfig["access-config.yaml"] auditlog["audit.log"] end subgraph Encryption["Verschlüsselungsschicht"] gitcrypt["git-crypt"] contextkeys["Kontext-Schlüssel (privat/dhive/bahn)"] machineconfig["machine-context.yaml"] end subgraph Federation["Föderationsschicht"] fedmanager["Federation-Manager"] syncengine["Sync-Engine (git-subtree)"] teamconfig["team-repos.yaml"] end end subgraph External["Externe Repos"] extro1["Read-Only Repos"] upstream["Upstream Repos"] end subgraph TeamRepos["Team-Repos (Spokes)"] teamPrivat["Team-Repo: privat"] teamDhive["Team-Repo: dhive"] teamBahn["Team-Repo: bahn"] end subgraph Orchestrator["AI-Orchestrator"] taskrouter["Task-Router"] ctxresolver["Context-Resolver"] agentrunner["Agent-Runner"] end Orchestrator --> Security Security --> Encryption Encryption --> Contexts External --> Contexts knowledge --> Contexts Federation -.->|"bidirektionaler Sync"| TeamRepos teamPrivat -.-> privat teamDhive -.-> dhive teamBahn -.-> bahn ``` ### Schichtenarchitektur ```mermaid graph LR subgraph L1["Schicht 1: Dateisystem"] folders["Ordnerstruktur"] gitconfig["Git-Konfiguration"] end subgraph L2["Schicht 2: Verschlüsselung"] gitcrypt["git-crypt"] keymanagement["Schlüsselverwaltung"] machinecontext["Maschinenkontext"] end subgraph L3["Schicht 3: Zugriffskontrolle"] guard["ctx-guard Wrapper"] hooks["Git-Hooks"] envloader["Env-Loader"] end subgraph L4["Schicht 4: Wissensspeicher"] etl["ETL-Pipeline"] index["YAML-Index"] search["Suche"] end subgraph L5["Schicht 5: Integration"] orch["Orchestrator-Adapter"] bridge["Kontextbrücke"] sync["Repo-Sync"] end subgraph L6["Schicht 6: Föderation"] fedmgr["Federation-Manager"] subtreesync["Subtree-Sync"] teamisolation["Team-Isolation"] end L1 --> L2 --> L3 --> L4 --> L5 --> L6 ``` ## Components and Interfaces ### 1. Ordnerstruktur-Manager (`structure-manager`) **Verantwortung:** Anlegen, Validieren und Verwalten der Monorepo-Ordnerstruktur. ```python class StructureManager: """Verwaltet die 3-Ebenen-Ordnerhierarchie.""" CONTEXTS = ("privat", "dhive", "bahn", "shared") NAME_PATTERN = re.compile(r'^[a-z0-9][a-z0-9\-]{0,48}[a-z0-9]$') def create_project(self, context: str, name: str) -> Path: """Erstellt ein neues Projekt im gegebenen Kontext.""" ... def validate_name(self, name: str) -> bool: """Prüft kebab-case Namenskonvention (2-50 Zeichen).""" ... def list_projects(self, context: str | None = None) -> list[ProjectInfo]: """Listet alle Projekte, optional gefiltert nach Kontext.""" ... def resolve_context(self, project_path: Path) -> str: """Ermittelt den Arbeitskontext eines Projekts anhand seines Pfads.""" ... ``` ### 2. Sicherheits-Guard (`ctx-guard`) **Verantwortung:** Zugriffskontrolle auf Secrets und .env-Dateien basierend auf Ausführungskontext. ```python class ContextGuard: """Erzwingt Sicherheitsgrenzen zwischen Arbeitskontexten.""" def __init__(self, config_path: Path): self.config = self._load_access_config(config_path) self.audit_log = AuditLogger() def check_access(self, requesting_context: str, target_path: Path) -> bool: """Prüft ob der Zugriff auf target_path vom requesting_context erlaubt ist.""" ... def load_env(self, context: str) -> dict[str, str]: """Lädt die .env-Datei des gegebenen Kontexts.""" ... def log_violation(self, event: SecurityEvent) -> None: """Protokolliert einen Zugriffsverletzungs-Versuch.""" ... ``` **Konfigurationsdatei (`access-config.yaml`):** ```yaml contexts: privat: env_file: privat/.env allowed_shared: - shared/tools/ - shared/powers/ - shared/config/ dhive: env_file: dhive/.env allowed_shared: - shared/tools/ - shared/powers/ - shared/config/ bahn: env_file: bahn/.env allowed_shared: - shared/tools/ - shared/powers/ - shared/config/ - shared/knowledge-store/ shared: env_file: shared/.env allowed_shared: ["*"] ``` ### 3. Wissensspeicher (`knowledge-store`) **Verantwortung:** ETL-Pipeline für kontextübergreifendes Wissen, basierend auf der DB-Wissensdatenbank-Architektur. ```python class KnowledgeStore: """Zentraler Wissensspeicher mit ETL-Pipeline.""" def __init__(self, base_path: Path, scope_config: ScopeConfig): self.base_path = base_path self.scope_config = scope_config self.index = YAMLIndex(base_path / "_index.yaml") def ingest(self, source: Source, context: str) -> list[Artifact]: """Verarbeitet eine Quelle und legt Artefakte ab.""" ... def search(self, query: str, allowed_scopes: list[str]) -> list[SearchResult]: """Volltextsuche über den Index, gefiltert nach Berechtigung.""" ... def get_index(self, scope: str | None = None) -> IndexData: """Liefert den kompakten YAML-Index (Progressive Disclosure Schicht 1).""" ... def link_artifacts(self, source_id: str, target_id: str, relation: str) -> None: """Verknüpft zwei Artefakte als gerichtete Graph-Kante.""" ... ``` **ETL-Pipeline-Komponenten:** ```mermaid graph LR Sources["Quellen"] --> Extract["Extract"] Extract --> Transform["Transform"] Transform --> Load["Load"] Load --> Index["Index Update"] Sources --- Confluence Sources --- Webseiten Sources --- PDFs Sources --- Markdown Sources --- GitLab ``` ### 4. Externes-Repo-Manager (`repo-manager`) **Verantwortung:** Einbindung, Synchronisation und Schutzmechanismen für externe Repositories. ```python class RepoManager: """Verwaltet externe und Upstream-Repository-Einbindungen.""" def __init__(self, config_path: Path): self.config = self._load_repos_config(config_path) def add_repo(self, entry: RepoEntry) -> None: """Bindet ein externes Repo ein (Subtree oder Submodule).""" ... def sync(self, repo_name: str) -> SyncResult: """Synchronisiert ein Repo mit seinem Remote.""" ... def protect_readonly(self, repo_path: Path) -> None: """Installiert Git-Hooks zum Schutz vor Schreibzugriffen.""" ... ``` **Konfigurationsdatei (`repos.yaml`):** ```yaml repos: - name: db-wissensdatenbank url: https://gitlab.2700.2db.it/... mode: upstream target: bahn/db-wissensdatenbank pinned: main - name: symphony-spec url: https://github.com/openai/symphony mode: read-only target: shared/references/symphony pinned: v1.0.0 ``` ### 5. Kontextbrücke (`context-bridge`) **Verantwortung:** Kontextübergreifendes Teilen von Wissensartefakten unter Wahrung der Sicherheitsgrenzen. ```python class ContextBridge: """Ermöglicht kontextübergreifenden Wissenstransfer.""" SENSITIVE_PATTERNS = [ r'(?i)(api[_-]?key|token|password|secret)\s*[:=]', r'(?i)(endpoint|url)\s*[:=]\s*https?://', r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', ] def share_artifact(self, artifact_id: str, user_confirmed: bool = False) -> ShareResult: """Gibt ein Artefakt kontextübergreifend frei.""" ... def check_sensitive_content(self, content: str) -> list[SensitiveMatch]: """Prüft Inhalt auf kontextspezifische Geheimnisse und PII.""" ... def revoke_share(self, artifact_id: str) -> None: """Widerruft die Freigabe eines geteilten Artefakts.""" ... ``` ### 6. Migrations-Engine (`migration-engine`) **Verantwortung:** Inkrementelle Migration bestehender Repositories unter Bewahrung der Git-Historie. ```python class MigrationEngine: """Migriert bestehende Repos in die Monorepo-Struktur.""" def migrate(self, plan: MigrationPlan) -> MigrationResult: """Führt die Migration eines einzelnen Repos durch.""" ... def validate(self, repo_name: str) -> ValidationResult: """Validiert eine abgeschlossene Migration.""" ... def rollback(self, repo_name: str) -> None: """Macht die Migration eines Repos rückgängig.""" ... ``` ### 7. Orchestrator-Adapter (`orchestrator-adapter`) **Verantwortung:** Integration des AI-Orchestrators mit der Monorepo-Struktur. ```python class OrchestratorAdapter: """Adaptiert den AI-Orchestrator für die Monorepo-Struktur.""" def resolve_context(self, task: Task) -> str: """Ermittelt den Arbeitskontext aus Task-Metadaten.""" ... def create_workspace(self, task: Task, context: str) -> Path: """Erstellt ein kontextgebundenes Workspace.""" ... def build_prompt(self, task: Task, context: str) -> str: """Erstellt den Agenten-Prompt mit Wissenskontext.""" ... def inject_knowledge(self, prompt: str, context: str) -> str: """Fügt relevante Artefakt-Pfade aus dem YAML-Index hinzu.""" ... ``` ### 8. Secret-Encryption-Manager (`secret-encryption`) **Verantwortung:** Verschlüsselung von Secrets im Repository mittels git-crypt, Schlüsselverwaltung pro Arbeitskontext, und Maschinenkontext-basierte Entschlüsselung. ```python class SecretEncryptionManager: """Verwaltet git-crypt-basierte Verschlüsselung pro Arbeitskontext.""" SUPPORTED_TOOLS = ("git-crypt", "sops", "age") SECRET_PATTERNS = [ "**/.env", "**/*.pem", "**/*.key", "**/*token*", "**/*secret*", ] def __init__(self, config_path: Path, machine_context: MachineContext): self.config = self._load_encryption_config(config_path) self.machine_context = machine_context self.tool = self._init_encryption_tool() def encrypt_file(self, file_path: Path, context: str) -> EncryptionResult: """Verschlüsselt eine Datei mit dem Schlüssel des gegebenen Kontexts.""" ... def decrypt_file(self, file_path: Path) -> DecryptionResult: """Entschlüsselt eine Datei, sofern der Maschinenkontext autorisiert ist.""" ... def is_authorized(self, context: str) -> bool: """Prüft ob der aktuelle Maschinenkontext für den Kontext autorisiert ist.""" return context in self.machine_context.authorized_contexts def get_context_key(self, context: str) -> Optional[EncryptionKey]: """Liefert den Schlüssel für einen Kontext (aus Keyring/Passwort-Manager).""" ... def setup_gitcrypt_filters(self, context: str) -> None: """Installiert git-crypt-Filter für den gegebenen Kontext.""" ... def onboard_machine(self, machine_name: str, authorized_contexts: list[str]) -> OnboardingResult: """Richtet eine neue Maschine mit den autorisierten Schlüsseln ein.""" ... def resolve_merge(self, file_path: Path, ours: bytes, theirs: bytes) -> bytes: """Löst Merge-Konflikte auf verschlüsselter Ebene.""" ... ``` **Maschinenkontext-Konfiguration (`machine-context.yaml`):** ```yaml machine: name: "andre-hauptrechner" description: "Andres Hauptrechner mit vollem Zugriff" authorized_contexts: - privat - dhive - bahn key_source: "keyring" # keyring | file | password-manager password_manager: type: "bitwarden" # bitwarden | 1password | keepass vault: "monorepo-keys" ``` **git-crypt-Konfiguration (`.gitattributes` pro Kontext):** ```gitattributes # privat/.gitattributes .env filter=git-crypt-privat diff=git-crypt-privat *.pem filter=git-crypt-privat diff=git-crypt-privat *.key filter=git-crypt-privat diff=git-crypt-privat # dhive/.gitattributes .env filter=git-crypt-dhive diff=git-crypt-dhive *.pem filter=git-crypt-dhive diff=git-crypt-dhive # bahn/.gitattributes .env filter=git-crypt-bahn diff=git-crypt-bahn *.pem filter=git-crypt-bahn diff=git-crypt-bahn ``` ### 9. Federation-Manager (`federation-manager`) **Verantwortung:** Verwaltung der Hub-and-Spoke-Topologie, bidirektionale Synchronisation zwischen Monorepo und Team-Repos via Git-Subtrees, Team-Isolation und Shared-Bereich-Spiegelung. ```python class FederationManager: """Verwaltet die föderierte Repo-Struktur (Hub-and-Spoke).""" def __init__(self, config_path: Path, encryption_manager: SecretEncryptionManager): self.config = self._load_team_repos_config(config_path) self.encryption = encryption_manager self.sync_engine = SubtreeSyncEngine() def sync_from_team(self, context: str) -> SyncResult: """Synchronisiert Änderungen vom Team_Repo in den Monorepo-Kontextordner.""" ... def sync_to_team(self, context: str) -> SyncResult: """Synchronisiert Änderungen vom Monorepo-Kontextordner zum Team_Repo.""" ... def full_sync(self, context: str) -> SyncResult: """Bidirektionale Synchronisation mit Konflikt-Erkennung.""" ... def verify_isolation(self, team_repo_path: Path, context: str) -> IsolationReport: """Prüft ob ein Team_Repo keine Referenzen auf andere Kontexte enthält.""" ... def mirror_shared(self, context: str, paths: list[str]) -> MirrorResult: """Spiegelt ausgewählte shared-Dateien als Read-Only in das Team_Repo.""" ... def prepare_team_repo(self, context: str) -> Path: """Erzeugt ein Team_Repo mit nur dem eigenen Kontext (Secrets entschlüsselt/re-keyed).""" ... def resolve_conflict(self, context: str, strategy: str = "team-wins") -> ConflictResult: """Löst Sync-Konflikte auf (Standard: Team_Repo hat Vorrang).""" ... def onboard_member(self, context: str, member_info: MemberInfo) -> OnboardingResult: """Erteilt Zugang nur zum Team_Repo ohne Kenntnis des Monorepos.""" ... class SubtreeSyncEngine: """Git-Subtree-basierte Synchronisation mit Historie-Bewahrung.""" def subtree_pull(self, remote: str, prefix: str, branch: str) -> SyncResult: """Zieht Änderungen vom Team_Repo per git subtree pull.""" ... def subtree_push(self, remote: str, prefix: str, branch: str) -> SyncResult: """Pusht Änderungen zum Team_Repo per git subtree push.""" ... def detect_conflicts(self, context: str) -> list[ConflictInfo]: """Erkennt Merge-Konflikte vor der Synchronisation.""" ... def preserve_history(self, repo_path: Path) -> bool: """Verifiziert, dass die Git-Historie nach Sync vollständig ist.""" ... ``` **Team-Repos-Konfiguration (`team-repos.yaml`):** ```yaml version: "1.0" federation: topology: "hub-and-spoke" hub_owner: "andre" conflict_strategy: "team-wins" # Team_Repo hat Vorrang team_repos: - context: privat url: "https://github.com/andreknie/privat-team.git" branch: main sync_direction: bidirectional sync_frequency: "on-push" # on-push | hourly | daily | manual shared_mirror: enabled: true paths: - "shared/tools/common-scripts/" - "shared/config/base-config.yaml" mode: read-only - context: dhive url: "https://gitlab.dhive.io/team/dhive-mono.git" branch: main sync_direction: bidirectional sync_frequency: "on-push" shared_mirror: enabled: true paths: - "shared/tools/" - "shared/powers/db-dxp-platform/" - "shared/mcp-servers/" mode: read-only - context: bahn url: "https://gitlab.2700.2db.it/team/bahn-workspace.git" branch: main sync_direction: bidirectional sync_frequency: "daily" shared_mirror: enabled: true paths: - "shared/tools/" - "shared/powers/" - "shared/knowledge-store/_index.yaml" mode: read-only ``` ## Data Models ### Ordnerstruktur ``` monorepo-root/ ├── privat/ │ ├── project-a/ │ │ ├── module-1/ │ │ └── module-2/ │ ├── project-b/ │ ├── .env (verschlüsselt via git-crypt-privat) │ └── .gitattributes (git-crypt-Filter-Regeln) ├── dhive/ │ ├── project-c/ │ ├── .env (verschlüsselt via git-crypt-dhive) │ └── .gitattributes ├── bahn/ │ ├── db-wissensdatenbank/ (Upstream) │ ├── project-d/ │ ├── .env (verschlüsselt via git-crypt-bahn) │ └── .gitattributes ├── shared/ │ ├── tools/ │ ├── powers/ │ ├── knowledge-store/ │ ├── config/ │ │ ├── access-config.yaml │ │ ├── repos.yaml │ │ ├── scopes.yaml │ │ ├── machine-context.yaml (Maschinenkontext-Mapping) │ │ └── team-repos.yaml (Föderations-Konfiguration) │ ├── mcp-servers/ │ └── .env ├── .gitattributes (Root-Level git-crypt-Regeln) ├── .gitignore (nur Build-Artefakte, Caches, Temp-Dateien) ├── .gitmodules └── monorepo.yaml (Zentrale Monorepo-Konfiguration) ``` ### Wissensartefakt (Markdown mit YAML-Frontmatter) ```yaml --- type: decision # decision | note | meeting | reference | pattern title: "API-Designprinzipien für Microservices" tags: [api, microservices, architecture, rest] source_context: bahn # Quellkontext created: 2024-12-15 updated: 2025-01-10 shareable: true # Kontextübergreifend teilbar? links: - target: "privat/notes/rest-patterns.md" relation: "implements" - target: "shared/knowledge-store/patterns/api-versioning.md" relation: "references" content_hash: "sha256:abc123..." --- # API-Designprinzipien für Microservices ... ``` ### YAML-Index (Progressive Disclosure – Schicht 1) ```yaml # shared/knowledge-store/_index.yaml version: "1.0" last_updated: "2025-01-15T10:30:00Z" artifacts: - id: "bahn/decisions/api-design" title: "API-Designprinzipien für Microservices" type: decision tags: [api, microservices, architecture] scope: bahn summary: "REST-API-Konventionen für DB-InfraGO-Dienste" path: "bahn/decisions/api-design.md" content_hash: "sha256:abc123..." links: ["shared/patterns/api-versioning"] - id: "privat/notes/rest-patterns" title: "REST-Patterns Notizen" type: note tags: [api, rest, patterns] scope: privat summary: "Sammlung bewährter REST-Patterns" path: "privat/notes/rest-patterns.md" content_hash: "sha256:def456..." links: ["bahn/decisions/api-design"] ``` ### Zentrale Monorepo-Konfiguration (`monorepo.yaml`) ```yaml version: "1.0" contexts: - name: privat description: "Persönliche Projekte" - name: dhive description: "dhive GmbH Projekte" - name: bahn description: "DB InfraGO Projekte" - name: shared description: "Kontextübergreifende Tools und Wissen" naming: pattern: "^[a-z0-9][a-z0-9\\-]{0,48}[a-z0-9]$" min_length: 2 max_length: 50 security: config: shared/config/access-config.yaml audit_log: .audit/access.log encryption: tool: git-crypt machine_context_config: shared/config/machine-context.yaml key_source: keyring federation: config: shared/config/team-repos.yaml conflict_strategy: team-wins ``` ### Repository-Eintrag (für `repos.yaml`) ```python @dataclass class RepoEntry: name: str # Eindeutiger Name url: str # Repository-URL mode: Literal["read-only", "upstream"] target: str # Zielpfad im Monorepo pinned: str # Git-SHA, Tag oder Branch mechanism: Literal["subtree", "submodule"] = "subtree" ``` ### Migrations-Plan ```python @dataclass class MigrationPlan: source_repo: str # Pfad zum Quell-Repository target_context: str # Ziel-Kontextordner target_name: str # Projektname im Ziel mode: Literal["direct", "subtree", "upstream"] dependencies: list[str] # Abhängigkeiten zu anderen Repos order: int # Migrationsreihenfolge ``` ### Sicherheits-Event ```python @dataclass class SecurityEvent: timestamp: datetime requesting_context: str target_context: str resource: str action: str # read | write | execute outcome: Literal["denied", "allowed"] ``` ### Maschinenkontext ```python @dataclass class MachineContext: name: str # z.B. "andre-hauptrechner", "dhive-laptop" description: str authorized_contexts: list[str] # ["privat", "dhive", "bahn"] oder Subset key_source: Literal["keyring", "file", "password-manager"] password_manager: Optional[PasswordManagerConfig] = None @dataclass class PasswordManagerConfig: type: Literal["bitwarden", "1password", "keepass"] vault: str # Name des Vaults/der Datenbank entry_prefix: str = "monorepo-key-" # Prefix für Schlüssel-Einträge @dataclass class EncryptionKey: context: str # Zugehöriger Arbeitskontext key_id: str # GPG Key-ID oder symmetrischer Key-Name key_type: Literal["gpg", "symmetric"] source: Literal["keyring", "file", "password-manager"] ``` ### Team-Repo-Konfiguration ```python @dataclass class TeamRepoEntry: context: str # Zugehöriger Arbeitskontext (privat/dhive/bahn) url: str # Repository-URL branch: str # Sync-Branch (z.B. "main") sync_direction: Literal["bidirectional", "hub-to-spoke", "spoke-to-hub"] sync_frequency: Literal["on-push", "hourly", "daily", "manual"] shared_mirror: Optional[SharedMirrorConfig] = None @dataclass class SharedMirrorConfig: enabled: bool paths: list[str] # Pfade aus shared/ die gespiegelt werden mode: Literal["read-only"] # Immer read-only im Team_Repo @dataclass class SyncResult: success: bool context: str direction: str # "pull" | "push" | "full" commits_synced: int conflicts: list[ConflictInfo] timestamp: datetime @dataclass class ConflictInfo: file_path: str conflict_type: Literal["content", "rename", "delete-modify"] source: str # "monorepo" | "team-repo" details: str @dataclass class IsolationReport: context: str is_isolated: bool leaks: list[IsolationLeak] # Gefundene Referenzen auf andere Kontexte @dataclass class IsolationLeak: file_path: str line_number: int leaked_context: str # Welcher fremde Kontext referenziert wird leak_type: Literal["path", "env_var", "config_ref", "comment"] ``` ## Correctness Properties *A property is a characteristic or behavior that should hold true across all valid executions of a system — essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* ### Property 1: Namensvalidierung akzeptiert nur gültiges kebab-case *For any* String, die `validate_name`-Funktion soll genau dann `true` zurückgeben, wenn der String ausschließlich aus Kleinbuchstaben, Ziffern und Bindestrichen besteht, zwischen 2 und 50 Zeichen lang ist und nicht mit einem Bindestrich beginnt oder endet. **Validates: Requirements 1.3** ### Property 2: Namenskollision verhindert doppelte Projekterstellung *For any* Sequenz von Projekt-Erstellungsaufrufen im gleichen Kontext, wenn ein Projektname bereits existiert, muss der zweite Aufruf mit diesem Namen fehlschlagen und die bestehende Projektstruktur unverändert lassen. **Validates: Requirements 1.6** ### Property 3: Kontextübergreifender Secret-Zugriff wird verweigert *For any* Kombination aus anfragendem Kontext A und Zielkontext B (wobei A ≠ B und B ≠ shared), muss der Zugriff auf .env-Dateien und Secret-Dateien von B verweigert werden, und es muss ein Audit-Log-Eintrag mit Zeitstempel, anfragendem Kontext, Zielkontext und Ressource erzeugt werden. **Validates: Requirements 2.1, 2.3, 2.5, 2.7** ### Property 4: Shared-Tool-Isolation *For any* Tool aus dem shared-Bereich, das in einem bestimmten Arbeitskontext ausgeführt wird, darf es ausschließlich auf die Secrets des aktiven Kontexts und auf explizit freigegebene shared-Ressourcen zugreifen. Jeder andere Zugriff muss blockiert werden. **Validates: Requirements 2.7, 8.5** ### Property 5: Wissensartefakt-Ingestion erzeugt vollständige Metadaten im Index *For any* gültiges Wissensartefakt aus einem beliebigen Kontext, nach der Verarbeitung durch die ETL-Pipeline muss es im YAML-Index erscheinen mit korrektem YAML-Frontmatter (mindestens Typ, Titel, Tags, Quellkontext, Erstelldatum, Content-Hash) und der Pfad muss der Scope-basierten Ordnerstruktur entsprechen. **Validates: Requirements 3.2, 3.4, 3.6, 3.11, 3.13, 3.17, 3.21** ### Property 6: Suche respektiert Scope-Berechtigungen *For any* Suchanfrage und beliebige Menge autorisierter Scopes, dürfen die Ergebnisse ausschließlich Artefakte enthalten, deren Scope in der autorisierten Menge liegt. Artefakte aus nicht-autorisierten Scopes dürfen weder in der Ergebnisliste erscheinen noch darf deren Existenz offengelegt werden. **Validates: Requirements 3.3, 3.9** ### Property 7: Progressive-Disclosure-Index enthält nur kompakte Einträge *For any* Abfrage des YAML-Index (Schicht 1) müssen die zurückgegebenen Einträge Titel, Tags, Beziehungen und Kurzbeschreibungen enthalten, aber niemals den vollständigen Dokumentinhalt. Suchergebnisse liefern ausschließlich Pfade zurück. **Validates: Requirements 3.16, 3.18** ### Property 8: Inkrementelle Verarbeitung erkennt Änderungen über Content-Hash *For any* Quelle, wenn der Content-Hash seit der letzten Verarbeitung unverändert ist, darf kein Update erfolgen. Wenn sich der Hash geändert hat, muss genau das betroffene Artefakt aktualisiert werden. **Validates: Requirements 3.12** ### Property 9: Volltextsuche findet indexierte Inhalte *For any* indexiertes Artefakt mit einem bestimmten Suchbegriff im Inhalt, muss eine Volltextsuche nach diesem Begriff das Artefakt in den Ergebnissen zurückliefern (sofern der Scope autorisiert ist), sortiert nach Relevanz. **Validates: Requirements 3.7** ### Property 10: ETL-Fehlerresilienz bewahrt erfolgreiche Artefakte *For any* ETL-Durchlauf, in dem eine Quelle fehlschlägt, müssen alle zuvor erfolgreich verarbeiteten Artefakte erhalten bleiben, der Fehler mit Quellidentifikator und Zeitstempel protokolliert werden, und die fehlgeschlagene Quelle beim nächsten Durchlauf erneut verarbeitet werden. **Validates: Requirements 3.20** ### Property 11: Graph-Verknüpfungen werden in beiden Artefakten reflektiert *For any* zwei Artefakte, wenn eine gerichtete Verknüpfung von A nach B erstellt wird, muss die Kante sowohl im YAML-Frontmatter von A als auch im Frontmatter von B erscheinen. **Validates: Requirements 3.8** ### Property 12: Read-Only-Repos blockieren Schreibzugriffe *For any* Schreiboperation (Datei anlegen, ändern oder löschen) auf ein als read-only konfiguriertes eingebundenes Repository muss die Operation blockiert werden und eine Fehlermeldung ausgegeben werden, die den Read-Only-Status und den Repository-Namen enthält. **Validates: Requirements 4.2, 4.5** ### Property 13: Fehlgeschlagene Synchronisation bewahrt lokalen Stand *For any* fehlgeschlagene Synchronisation mit einem Upstream-Repository (Netzwerkfehler, Authentifizierungsfehler, Merge-Konflikt) muss der lokale Dateizustand identisch zum Zustand vor dem Sync-Versuch sein. **Validates: Requirements 4.9** ### Property 14: Sensitive-Content-Filter blockiert Freigabe *For any* Wissensartefakt, das Muster für kontextspezifische Geheimnisse, Zugangsdaten oder personenbezogene Daten enthält, muss die kontextübergreifende Freigabe verweigert werden mit einer Fehlermeldung, die den Ablehnungsgrund benennt. **Validates: Requirements 5.1, 5.3** ### Property 15: Freigabe-Lebenszyklus (Share → Update → Revoke) *For any* geteiltes Artefakt gilt: (a) nach Freigabe ist es in allen Kontexten als schreibgeschützte Lesereferenz sichtbar, (b) Aktualisierungen im Quellkontext werden beim nächsten Lesezugriff reflektiert, (c) nach Widerruf ist es in keinem Zielkontext mehr sichtbar. **Validates: Requirements 5.2, 5.5, 5.6** ### Property 16: Freigabe erfordert explizite Nutzerbestätigung *For any* Versuch ein Artefakt kontextübergreifend zu teilen, ohne dass `user_confirmed=True` gesetzt ist, muss die Operation fehlschlagen. **Validates: Requirements 5.4** ### Property 17: Migrations-Validierung prüft Vollständigkeit *For any* migrierten Repository-Zustand muss die Validierungsfunktion korrekt prüfen: Übereinstimmung der Commit-Anzahl, Vorhandensein aller Branches und Tags, Vollständigkeit des Dateibaums. **Validates: Requirements 6.4** ### Property 18: Migrations-Rollback stellt Vor-Zustand wieder her *For any* fehlgeschlagene Migration eines einzelnen Repositories muss der Rollback den exakten Zustand vor der Migration wiederherstellen, ohne andere bereits migrierte Repositories zu beeinflussen. **Validates: Requirements 6.7** ### Property 19: Orchestrator-Kontextauflösung und Workspace-Isolation *For any* Task mit gültigen Kontext-Metadaten muss der Orchestrator (a) das Workspace unter dem korrekten Kontextordner anlegen und (b) ausschließlich die .env-Datei dieses Kontexts laden. Für Tasks ohne gültigen Kontext muss der Start verweigert werden. **Validates: Requirements 7.1, 7.2, 7.3, 7.6** ### Property 20: Orchestrator-Kontextverletzung bricht Task ab *For any* Zugriff des Orchestrators auf Dateien oder Secrets außerhalb des zugewiesenen Kontextordners muss der laufende Task abgebrochen, der Vorfall protokolliert und der Nutzer benachrichtigt werden. **Validates: Requirements 7.5** ### Property 21: MCP-Konfiguration-Merge mit Kontext-Vorrang *For any* MCP-Server-Konfiguration, bei der sowohl eine shared-Konfiguration als auch eine kontextspezifische Konfiguration existiert, muss die effektive Konfiguration die kontextspezifischen Werte bevorzugen (Merge mit Override). **Validates: Requirements 8.4, 8.6** ### Property 22: Shared-Tool-Versionierung ohne manuelle Synchronisation *For any* Aktualisierung eines Tools im shared-Bereich müssen alle Kontexte bei ihrer nächsten Ausführung die aktualisierte Version verwenden, ohne manuelle Schritte in einzelnen Kontexten. **Validates: Requirements 8.2** ### Property 23: Verschlüsselte Secrets können nur mit autorisiertem Kontextschlüssel entschlüsselt werden *For any* verschlüsselte Secret-Datei eines Arbeitskontexts X und für jeden Entschlüsselungsversuch mit einem Schlüssel des Kontexts Y (wobei X ≠ Y), muss die Entschlüsselung fehlschlagen und die Datei im verschlüsselten Zustand verbleiben. Nur der Schlüssel des zugehörigen Kontexts X darf die Datei erfolgreich entschlüsseln. **Validates: Requirements 9.3, 9.8** ### Property 24: Maschinenkontext beschränkt Entschlüsselung auf autorisierte Kontexte *For any* Maschinenkontext-Konfiguration mit einer definierten Menge autorisierter Arbeitskontexte, muss gelten: (a) Secrets der autorisierten Kontexte sind entschlüsselbar, (b) Secrets aller nicht-autorisierten Kontexte verbleiben als verschlüsselte Binärdaten im Working Tree, (c) die Fehlermeldung bei fehlgeschlagener Entschlüsselung gibt keinen Hinweis auf den Dateiinhalt, (d) das Repository bleibt vollständig funktionsfähig (Code, Konfiguration, Dokumentation zugänglich). **Validates: Requirements 9.4, 9.5, 9.8, 9.10** ### Property 25: Team-Repos enthalten ausschließlich Inhalte des eigenen Kontexts *For any* Team_Repo für einen Arbeitskontext X muss gelten: (a) es enthält keine Dateien, Pfade, Konfigurationsreferenzen oder Umgebungsvariablen, die auf einen anderen Arbeitskontext Y (Y ≠ X) verweisen, (b) es enthält keine Secrets anderer Kontexte (weder verschlüsselt noch unverschlüsselt), (c) optional gespiegelte Dateien aus dem shared-Bereich sind als Read-Only markiert und enthalten keine kontextfremden Referenzen. **Validates: Requirements 10.5, 10.9, 10.10, 10.12** ### Property 26: Bidirektionale Synchronisation bewahrt Git-Historie und löst Konflikte korrekt *For any* Sequenz von Commits in einem Team_Repo oder einem Monorepo-Kontextordner, nach einer bidirektionalen Synchronisation muss gelten: (a) alle Commits erscheinen mit vollständiger Autoren- und Zeitstempel-Information auf beiden Seiten, (b) bei Merge-Konflikten wird die Synchronisation abgebrochen, der Konflikt mit betroffenen Dateien und Quellen protokolliert, und dem Hub-Besitzer manuelle Auflösung ermöglicht, (c) das Team_Repo gilt als Single Source of Truth — bei Konflikten hat es Vorrang. **Validates: Requirements 10.3, 10.4, 10.6, 10.7, 10.8** ### Property 27: Team-Mitglieder können die Existenz anderer Kontexte nicht entdecken *For any* Team_Repo und jeden Dateipfad, Konfigurationseintrag, Git-Remote-URL, Commit-Message oder Metadaten-Feld innerhalb des Team_Repos darf kein Hinweis auf die Existenz des Monorepos, anderer Arbeitskontexte oder anderer Team_Repos enthalten sein. Das Team_Repo muss als vollständig eigenständiges Repository erscheinen. **Validates: Requirements 10.5, 10.9** ## Error Handling ### Sicherheitsgrenzen | Fehlerfall | Verhalten | |---|---| | Zugriff auf fremden Kontext | Zugriff blockiert, Audit-Log-Eintrag, Operation gibt Fehler zurück | | Ungültige access-config.yaml | System startet nicht, Fehlermeldung mit Validierungsdetails | | Shared-Tool ohne gültige Autorisierung | Ausführung wird verhindert, Fehler mit Kontextinfo | ### Wissensspeicher | Fehlerfall | Verhalten | |---|---| | ETL-Quellenfehler | Fehler protokolliert (Quelle + Zeitstempel), vorhandene Artefakte bewahrt, Retry beim nächsten Lauf | | Ungültiges YAML-Frontmatter | Artefakt als fehlerhaft markiert, nicht indexiert, Fehler protokolliert | | Index-Korruption | Vollständiger Index-Rebuild aus den Artefakt-Dateien | | Suchanfrage-Timeout (>5s) | Abbruch mit Teilergebnis-Warnung | | Duplikat-Content-Hash | Vorhandenes Artefakt beibehalten, neues als Konflikt melden | ### Repository-Management | Fehlerfall | Verhalten | |---|---| | Sync fehlgeschlagen (Netzwerk) | Lokaler Stand unverändert, Fehlergrund protokolliert, Nutzer informiert | | Merge-Konflikt bei Upstream-Sync | Sync abgebrochen, Konflikt protokolliert, manuelle Auflösung ermöglicht | | Schreibversuch auf Read-Only-Repo | Operation blockiert, Fehlermeldung mit Repo-Name und Status | | Submodule/Subtree-Init-Fehler | Fehlgeschlagenes Repo übersprungen, andere Repos weiter verfügbar | ### Migration | Fehlerfall | Verhalten | |---|---| | Pfadkollision | Migration pausiert, Konflikt mit Dateipfad und Quell-Repos protokolliert | | Branch-Namenskonflikt | Migration pausiert, betroffene Branches gelistet | | Validierung fehlgeschlagen | Ergebnis dokumentiert, Rollback angeboten | | Migration fehlgeschlagen | Automatischer Rollback auf Vor-Zustand, andere Repos unberührt | ### Orchestrator | Fehlerfall | Verhalten | |---|---| | Kein Kontext ermittelbar | Task nicht gestartet, Fehlermeldung an Nutzer | | Out-of-Context-Zugriff | Task abgebrochen, Vorfall protokolliert, Nutzer über OrgMyLife benachrichtigt | | Wissensspeicher-Index nicht verfügbar | Task ohne Wissenskontext fortsetzen, Warnung protokolliert | ### Verschlüsselung (Secret Encryption) | Fehlerfall | Verhalten | |---|---| | Entschlüsselung ohne autorisierten Schlüssel | Zugriff verweigert, Datei bleibt verschlüsselt, keine inhaltsbezogene Fehlermeldung | | git-crypt nicht installiert | Setup-Fehler mit Installationsanleitung ausgeben, Repository im Nur-Lesen-Modus | | Passwort-Manager nicht erreichbar | Fallback auf lokalen Keyring versuchen, Warnung protokollieren | | Beschädigter Schlüssel im Keyring | Schlüssel als ungültig markieren, Neu-Import aus Passwort-Manager anbieten | | Merge-Konflikt bei verschlüsselten Dateien | git-crypt-Merge-Treiber verwenden, bei Scheitern: Konflikt protokollieren, manuelle Auflösung | | Maschinenkontext-Konfiguration fehlt | Alle Secrets verschlüsselt belassen, Warnung mit Setup-Verweis ausgeben | | Ungültiger Maschinenkontext (unbekannter Kontext referenziert) | Konfiguration ablehnen, Validierungsfehler mit gültigen Kontexten ausgeben | ### Föderation (Team-Repos) | Fehlerfall | Verhalten | |---|---| | Sync-Konflikt (Merge-Conflict) | Synchronisation abgebrochen, Konflikt mit Dateien und Quellen protokolliert, Hub-Besitzer informiert | | Team_Repo nicht erreichbar (Netzwerk/Auth) | Sync übersprungen, Fehler protokolliert, nächster Versuch bei nächstem Trigger | | Cross-Context-Leakage erkannt bei Isolation-Check | Sync blockiert, betroffene Dateien gelistet, manuelle Bereinigung erforderlich | | Shared-Mirror-Quelle nicht vorhanden | Mirror-Schritt übersprungen, Warnung protokolliert, restlicher Sync fortgesetzt | | Team_Repo-Branch divergiert stark (>100 Commits Differenz) | Warnung an Hub-Besitzer, Sync nur nach expliziter Bestätigung | | Subtree-Push fehlgeschlagen | Lokaler Monorepo-Stand unverändert, Fehler mit Remote-Details protokolliert | | Neues Team-Mitglied erhält falschen Kontext-Zugang | Sicherheitswarnung, Zugang sofort revoken, Vorfall im Audit-Log | ## Testing Strategy ### Testebenen 1. **Property-Based Tests (Hypothesis)**: Universelle Eigenschaften über alle gültigen Eingaben (Minimum 100 Iterationen pro Property) 2. **Unit Tests (pytest)**: Spezifische Beispiele, Edge Cases, Fehlerbehandlung 3. **Integration Tests**: Git-Operationen, Dateisystem-Interaktionen, ETL-Pipeline-Durchläufe 4. **Smoke Tests**: Strukturprüfungen (Ordner existieren, Konfigurationen parsebar) ### Property-Based Testing **Library:** Hypothesis (Python) Jeder Property-Test wird mit mindestens 100 Iterationen konfiguriert und referenziert die zugehörige Design-Property: ```python from hypothesis import given, settings from hypothesis import strategies as st @settings(max_examples=100) @given(name=st.text(min_size=1, max_size=60)) def test_name_validation_property(name): """Feature: monorepo-consolidation, Property 1: Namensvalidierung akzeptiert nur gültiges kebab-case""" result = validate_name(name) expected = bool(re.match(r'^[a-z0-9][a-z0-9\-]{0,48}[a-z0-9]$', name)) assert result == expected ``` ### Testabdeckung nach Komponente | Komponente | Property Tests | Unit Tests | Integration Tests | |---|---|---|---| | StructureManager | P1, P2 | Beispiel-Projekte, Edge Cases | — | | ContextGuard | P3, P4 | Konfigurationsvalidierung | Dateisystem-Zugriffe | | KnowledgeStore | P5–P11 | Frontmatter-Parsing, Fehlerszenarien | ETL-Pipeline mit Mock-Quellen | | RepoManager | P12, P13 | Git-Hook-Installation | Subtree/Submodule-Operationen | | ContextBridge | P14–P16 | Regex-Muster, Freigabelogik | — | | MigrationEngine | P17, P18 | Migrationsplan-Validierung | git filter-repo-Operationen | | OrchestratorAdapter | P19–P22 | YAML-Index-Abfrage, Prompt-Build | Workspace-Erstellung | | SecretEncryptionManager | P23, P24 | Schlüssel-Validierung, Konfigurationsschema | git-crypt-Operationen, Passwort-Manager-Integration | | FederationManager | P25, P26, P27 | Isolation-Check-Logik, Konfigurationsschema | Git-Subtree-Operationen, Sync-Szenarien | ### Abgrenzung - **Kein PBT für**: Git-Remote-Operationen (Push/Pull/Sync), CI/CD-Konfigurationen, GitLab-Pages-Deployment, git-crypt-Tooling-Installation, Passwort-Manager-API - **Integration Tests für**: Tatsächliche Git-Operationen, Dateisystem-Berechtigungen, Netzwerk-Sync, git-crypt encrypt/decrypt-Zyklen, Subtree-Push/Pull gegen Test-Repos - **Smoke Tests für**: Konfigurationsdateien existieren und sind parsebar, Ordnerstruktur ist korrekt initialisiert, git-crypt ist installiert, Maschinenkontext-Konfiguration vorhanden