CP1.1: PRE_HERMES Control Plane SOT closure - 5-control scope (trading_execution removed), RED_QUEEN_TRADING_AUTHORITY=NEVER, reproducible deployment
This commit is contained in:
parent
b6c9da3e12
commit
058c92e5d0
4 changed files with 176 additions and 66 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
# PRE_HERMES Control Plane — Betriebsvertrag (CP1)
|
# PRE_HERMES Control Plane — Betriebsvertrag (CP1 / CP1.1)
|
||||||
|
|
||||||
Autoritative SoT für die produktive PRE_HERMES Autonomy Control Plane.
|
Autoritative SoT für die produktive PRE_HERMES Autonomy Control Plane.
|
||||||
Dieses Verzeichnis ist die **einzige** Quelle für den produktiven Control-Plane-Code.
|
Dieses Verzeichnis ist die **einzige** Quelle für den produktiven Control-Plane-Code.
|
||||||
|
|
@ -9,18 +9,52 @@ Produktiver Deploy-Pfad: `red-queen-architecture/control-plane/` → `/opt/contr
|
||||||
Minimale, fail-closed Sicherheitsgrundlage für zukünftige Red-Queen/Hermes-Autonomie.
|
Minimale, fail-closed Sicherheitsgrundlage für zukünftige Red-Queen/Hermes-Autonomie.
|
||||||
**CP1 ist KEINE Autonomie-Aktivierung.** Nach CP1 ist das System mindestens so restriktiv wie vorher.
|
**CP1 ist KEINE Autonomie-Aktivierung.** Nach CP1 ist das System mindestens so restriktiv wie vorher.
|
||||||
|
|
||||||
## 2. Komponenten
|
## 2. Architektur-Boundary (CP1.0S, permanent)
|
||||||
|
|
||||||
|
**RED_QUEEN_TRADING_AUTHORITY = NEVER**
|
||||||
|
|
||||||
|
Trading ist NICHT Bestandteil der Hermes Control Plane. Red Queen ist ein
|
||||||
|
**autonomes Arbeits-, Wissens-, Planungs-, Prüfungs- und Orchestrierungssystem** — kein Trading-System.
|
||||||
|
Hermes Autonomy und Trading Authority sind **zwei getrennte Sicherheitsdomänen**.
|
||||||
|
|
||||||
|
**Hermes Control Plane besteht ausschließlich aus:**
|
||||||
|
```
|
||||||
|
global_autonomy
|
||||||
|
productive_mutations
|
||||||
|
save_execution
|
||||||
|
delete_execution
|
||||||
|
emergency_stop
|
||||||
|
```
|
||||||
|
|
||||||
|
**KEIN** `trading_execution`, Trading-Gate, Broker-Gate, Broker-Credential oder
|
||||||
|
Trading-Execution-Control darf Bestandteil dieser Control Plane sein. Das bestehende
|
||||||
|
Trading-System ist eine separate Security-Domain (eigene Architektur, Execution,
|
||||||
|
Credentials, Risk Control, Kill-Switch, Freigabelogik).
|
||||||
|
|
||||||
|
`PRODUCTIVE_MUTATIONS` innerhalb der Hermes Control Plane bedeutet Hermes-/Knowledge-/
|
||||||
|
Mission-Domain-Mutationen — NICHT Order/Trade/Broker/Position-Mutation oder Trading-Execution.
|
||||||
|
|
||||||
|
**Red-Queen-Autonomie-Level (Arbeitsautonomie, KEIN Trading-Level):**
|
||||||
|
- L0 = Disabled / Manual
|
||||||
|
- L1 = Read-only Observation
|
||||||
|
- L2 = Autonomous Planning / Preparation
|
||||||
|
- L3 = bounded authorized SAVE / productive knowledge work
|
||||||
|
- L4 = human-authorized DELETE / höhere Arbeitsautonomie
|
||||||
|
|
||||||
|
## 3. Komponenten
|
||||||
|
|
||||||
| Datei | Zweck |
|
| Datei | Zweck |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `control_reader.py` | Fail-closed, deterministischer Control-State-Reader (produktiver Code) |
|
| `control_reader.py` | Fail-closed, deterministischer Control-State-Reader (produktiver Code) |
|
||||||
| `test_control_reader.py` | Statische + adversariale Tests (A–J, 25 Fälle) |
|
| `test_control_reader.py` | Statische + adversariale Tests (A–J, 22 Fälle) |
|
||||||
| `deploy_control_plane.sh` | Reproduzierbarer Deployment-Pfad (root, idempotent) |
|
| `deploy_control_plane.sh` | Reproduzierbarer Deployment-Pfad (root, idempotent) |
|
||||||
|
| `README_CP1OS_SCOPE.md` | CP1.0S Domain-Boundary + Level-Model |
|
||||||
| `README.md` | Dieser Betriebsvertrag |
|
| `README.md` | Dieser Betriebsvertrag |
|
||||||
|
|
||||||
## 3. Control State (Source of Truth)
|
## 4. Control State (Source of Truth)
|
||||||
|
|
||||||
Produktiver Pfad: `/opt/control-plane/state/` (root:root, 0700, Dateien 0600).
|
Produktiver Pfad: `/opt/control-plane/state/` (root:root, 0700, Dateien 0600).
|
||||||
|
**Runtime State ist NICHT Teil der SoT** (nie committen).
|
||||||
|
|
||||||
| Datei | Typ | Erlaubte RAW-Werte |
|
| Datei | Typ | Erlaubte RAW-Werte |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
|
|
@ -28,7 +62,6 @@ Produktiver Pfad: `/opt/control-plane/state/` (root:root, 0700, Dateien 0600).
|
||||||
| `productive_mutations` | positiv | `ON` / `OFF` (+ `boot_id=`) |
|
| `productive_mutations` | positiv | `ON` / `OFF` (+ `boot_id=`) |
|
||||||
| `save_execution` | positiv | `ON` / `OFF` (+ `boot_id=`) |
|
| `save_execution` | positiv | `ON` / `OFF` (+ `boot_id=`) |
|
||||||
| `delete_execution` | positiv | `ON` / `OFF` (+ `boot_id=`) |
|
| `delete_execution` | positiv | `ON` / `OFF` (+ `boot_id=`) |
|
||||||
| `trading_execution` | positiv | `ON` / `OFF` (+ `boot_id=`) |
|
|
||||||
| `emergency_stop` | negativ | `ON` / `OFF` |
|
| `emergency_stop` | negativ | `ON` / `OFF` |
|
||||||
|
|
||||||
**Positives ON-Grant-Format:**
|
**Positives ON-Grant-Format:**
|
||||||
|
|
@ -37,48 +70,61 @@ ON
|
||||||
boot_id=<current_kernel_boot_id>
|
boot_id=<current_kernel_boot_id>
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4. Gate-Semantik (fail-closed)
|
## 5. Gate-Semantik (fail-closed)
|
||||||
|
|
||||||
- **Positives Gate:** `EFFECTIVE=ON` nur wenn `RAW==ON` UND `grant_boot_id == current_boot_id` UND `EMERGENCY_EFFECTIVE==OFF`. Sonst `OFF`.
|
- **Positives Gate:** `EFFECTIVE=ON` nur wenn `RAW==ON` UND `grant_boot_id == current_boot_id` UND `EMERGENCY_EFFECTIVE==OFF`. Sonst `OFF`.
|
||||||
- **Emergency Stop (negativ):** `EFFECTIVE=ON` wenn `RAW==ON` ODER Datei fehlt ODER malformed. `OFF` nur bei explizitem `RAW==OFF`.
|
- **Emergency Stop (negativ):** `EFFECTIVE=ON` wenn `RAW==ON` ODER Datei fehlt ODER malformed. `OFF` nur bei explizitem `RAW==OFF`.
|
||||||
- **UNKNOWN = MORE RESTRICTIVE.** Fehlende/unlesbare/malformed Datei → positives Gate `OFF`, Emergency `ON`.
|
- **UNKNOWN = MORE RESTRICTIVE.** Fehlende/unlesbare/malformed Datei → positives Gate `OFF`, Emergency `ON`.
|
||||||
- **Hierarchie:** `SAVE/DELETE/TRADING_EFFECTIVE` benötigen `GLOBAL_AUTONOMY_EFFECTIVE==ON` UND `MUTATIONS_EFFECTIVE==ON` UND eigenen Grant gültig UND `EMERGENCY_EFFECTIVE==OFF`. Kein spezifischer Execution-Switch umgeht den globalen Mutation-Gate.
|
- **Fail-closed:** Positive missing→OFF, malformed→OFF, raw!=ON→OFF, ON+wrong boot_id→OFF. Emergency missing→ON, malformed→ON, raw ON→ON, raw OFF→OFF.
|
||||||
|
|
||||||
## 5. Boot-ID-Validierung
|
## 6. Effective-State-Hierarchie
|
||||||
|
|
||||||
- Quelle: `/proc/sys/kernel/random/boot_id` (Kernel-Boot-ID, ändert sich bei jedem Host-Boot).
|
- **GLOBAL effective** erfordert: global_autonomy raw ON + gültige boot_id + emergency OFF
|
||||||
- Positiver Grant ist nur gültig, wenn `grant_boot_id == current_boot_id`.
|
- **MUTATIONS effective** erfordert: GLOBAL ON + productive_mutations raw ON + gültige boot_id + emergency OFF
|
||||||
|
- **SAVE effective** erfordert: GLOBAL ON + MUTATIONS ON + save_execution raw ON + gültige boot_id + emergency OFF
|
||||||
|
- **DELETE effective** erfordert: GLOBAL ON + MUTATIONS ON + delete_execution raw ON + gültige boot_id + emergency OFF
|
||||||
|
|
||||||
|
**IMPORTANT:** DELETE effective ON allein autorisiert NIEMALS einen DELETE.
|
||||||
|
**AUTH.4D + Human Authorization bleiben zusätzliche, unabhängige Pflichtbedingungen.**
|
||||||
|
**COMMAND != AUTHORIZATION.**
|
||||||
|
|
||||||
|
## 7. Boot-ID-Validierung
|
||||||
|
|
||||||
|
- Quelle: `/proc/sys/kernel/random/boot_id` (Kernel-Boot-ID).
|
||||||
|
- Positiver Grant gültig nur wenn `grant_boot_id == current_boot_id`.
|
||||||
- `missing boot_id` → `EFFECTIVE=OFF`. `malformed boot_id` → `EFFECTIVE=OFF`.
|
- `missing boot_id` → `EFFECTIVE=OFF`. `malformed boot_id` → `EFFECTIVE=OFF`.
|
||||||
- **Keine manuell gepflegte Epoch, kein persistenter Alt-Grant.**
|
- **Keine manuell gepflegte Epoch, kein persistenter Alt-Grant.**
|
||||||
|
|
||||||
## 6. Restart-Semantik (korrekt dokumentiert)
|
## 8. Boot-Semantik (KORREKT dokumentiert)
|
||||||
|
|
||||||
- **HOST REBOOT:** `current_boot_id` ändert sich → alle alten positiven Grants ungültig → `EFFECTIVE=OFF`. Operator muss erneut autorisieren.
|
- **HOST REBOOT:** Kernel `boot_id` ändert sich → alte positive Grants ungültig → positive effective Gates fallen fail-closed auf **OFF**. Operator muss erneut autorisieren.
|
||||||
- **CONTAINER RESTART OHNE HOST REBOOT:** `current_boot_id` bleibt gleich → ein gültiger positiver Grant kann weiterhin gültig bleiben (kein neuer Boot, keine neue Autorisierung nötig).
|
- **CONTAINER RESTART:** Host `boot_id` ändert sich normalerweise NICHT → ein gültiger positiver Grant kann weiterhin gültig bleiben.
|
||||||
- **Negative/Deny-States** (`emergency_stop=ON`, `*_execution=OFF`) persistieren über Restart hinweg (fail-closed).
|
- **NICHT dokumentieren:** "jeder Container-Neustart setzt Grants zurück" (das wäre falsch).
|
||||||
|
- Negative/Deny-States (`emergency_stop=ON`, `*_execution=OFF`) persistieren über Restart (fail-closed).
|
||||||
|
|
||||||
## 7. Status Projection Contract
|
## 9. Status Projection Contract
|
||||||
|
|
||||||
- Produktiver Pfad: `/opt/control-plane/status/latest.txt` (root:root, 0444, read-only).
|
- Produktiver Pfad: `/opt/control-plane/status/latest.txt` (root:root, 0444, read-only).
|
||||||
- **STATUS PROJECTION != AUTHORITY.**
|
- **STATUS PROJECTION != AUTHORITY.**
|
||||||
- **Authority ist ausschließlich:** Control State + aktuelle Kernel-Boot-ID + fail-closed effective-state evaluation.
|
- **Authority ist ausschließlich:** Runtime State + aktuelle Kernel-Boot-ID + fail-closed Evaluator.
|
||||||
- `latest.txt` dient **ausschließlich der Observability**.
|
- `latest.txt` dient **ausschließlich der Observability**.
|
||||||
- Wenn die Projection fehlt/stale/malformed ist, darf das **niemals eine positive Freigabe erzeugen** (die Authority-Evaluation ist davon unabhängig).
|
- Fehlende/stale/malformed Projection darf **niemals eine Capability aktivieren**.
|
||||||
|
|
||||||
## 8. Ownership / Permissions
|
## 10. Ownership / Permissions
|
||||||
|
|
||||||
- Control State: root:root, 0700 (dir), 0600 (Dateien).
|
- Control State: root:root, 0700 (dir), 0600 (Dateien).
|
||||||
- Status Projection: root:root, 0444.
|
- Status Projection: root:root, 0444.
|
||||||
- Audit: root:root, `chattr +a` (append-only).
|
- Audit: root:root, `chattr +a` (append-only).
|
||||||
- **Red Queen:** kein Host-Root, kein Docker-Socket, kein Schreibzugriff auf `/opt/control-plane`. RQ kann State nicht lesen (0700) und nicht schreiben. RQ erhält später nur read-only Status-Projection (Observability).
|
- **Red Queen:** kein Host-Root, kein Docker-Socket, kein Schreibzugriff auf `/opt/control-plane`. RQ kann State nicht lesen (0700) und nicht schreiben. RQ erhält später nur read-only Status-Projection (Observability).
|
||||||
|
|
||||||
## 9. Audit-Foundation
|
## 11. Audit-Foundation
|
||||||
|
|
||||||
- Pfad: `/opt/control-plane/audit/control_audit.log` (root:root, append-only `+a`).
|
- Pfad: `/opt/control-plane/audit/control_audit.log` (root:root, append-only `+a`).
|
||||||
- Format: `WHEN | WHO | WHAT | OLD | NEW | WHY | BOOT_ID`.
|
- Format: `WHEN | WHO | WHAT | OLD | NEW | WHY | BOOT_ID`.
|
||||||
- RQ kann Audit nicht überschreiben (root-owned, append-only).
|
- RQ kann Audit nicht überschreiben (root-owned, append-only).
|
||||||
|
- **Runtime Audit Log ist NICHT Teil der SoT** (nie committen).
|
||||||
|
|
||||||
## 10. Deployment (reproduzierbar)
|
## 12. Deployment (reproduzierbar)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Als root auf dem Host, aus frischem Forgejo-Checkout:
|
# Als root auf dem Host, aus frischem Forgejo-Checkout:
|
||||||
|
|
@ -88,23 +134,40 @@ cd red-queen-architecture/control-plane
|
||||||
|
|
||||||
- Reproduziert ausschließlich die CP1-Artefakte.
|
- Reproduziert ausschließlich die CP1-Artefakte.
|
||||||
- **Überschreibt KEINE bestehenden State-Dateien** (Runtime-State bleibt unangetastet).
|
- **Überschreibt KEINE bestehenden State-Dateien** (Runtime-State bleibt unangetastet).
|
||||||
- Rollback: `rm -rf /opt/control-plane`.
|
- Ein Redeploy darf NICHT `/opt/control-plane/state/` überschreiben/neu initialisieren, wenn produktiver State existiert.
|
||||||
|
- Audit bleibt erhalten.
|
||||||
|
|
||||||
## 11. NICHT in Git
|
## 13. Rollback-Semantik
|
||||||
|
|
||||||
- Aktuelle produktive State-Werte als Authority (State ist Runtime, nicht SoT).
|
`rm -rf /opt/control-plane` ist NICHT der langfristige Sicherheits-Rollback.
|
||||||
- Aktuelle `boot_id` als persistente Authority.
|
Für CP1.1 existiert ein versionsgebundener Code-Rollback, der:
|
||||||
- Secrets, Tokens, private Keys.
|
- Runtime State erhält
|
||||||
- Runtime Audit Log.
|
- Audit erhält
|
||||||
|
- keine positiven Gates aktiviert
|
||||||
|
- Emergency State nicht abschwächt
|
||||||
|
- auf einen bekannten SoT-Commit zurückgeht
|
||||||
|
|
||||||
## 12. Sicherheitszustand (CP1 initial)
|
**Code-Rollback:** Aus dem gewünschten bekannten SoT-Commit den `control_reader.py` extrahieren und per `deploy_control_plane.sh` neu deployen (State bleibt unangetastet). Kein komplexer Rollback-Manager nötig.
|
||||||
|
|
||||||
|
## 14. NICHT in Git (Runtime Authority)
|
||||||
|
|
||||||
|
Forgejo ersetzt NICHT die produktive Laufzeit-Autorität. Nicht committen:
|
||||||
|
- Aktuelle produktive Gate-Werte, produktive Grant-Dateien
|
||||||
|
- Aktuelle `boot_id` als Authority
|
||||||
|
- Produktive Audit-Logs
|
||||||
|
- Secrets, Tokens, private Keys, Credentials
|
||||||
|
- SAVE/DELETE-Tokens, Human Authorization Private Key
|
||||||
|
- Runtime SQLite DBs
|
||||||
|
|
||||||
|
Forgejo enthält: **CODE, SCHEMA, TESTS, DEPLOYMENT LOGIC, DOCUMENTATION** — aber NICHT den aktuellen produktiven Sicherheitszustand.
|
||||||
|
|
||||||
|
## 15. Sicherheitszustand (CP1 initial)
|
||||||
|
|
||||||
```
|
```
|
||||||
GLOBAL_AUTONOMY_EFFECTIVE=OFF
|
GLOBAL_AUTONOMY_EFFECTIVE=OFF
|
||||||
MUTATIONS_EFFECTIVE=OFF
|
MUTATIONS_EFFECTIVE=OFF
|
||||||
SAVE_EFFECTIVE=OFF
|
SAVE_EFFECTIVE=OFF
|
||||||
DELETE_EFFECTIVE=OFF
|
DELETE_EFFECTIVE=OFF
|
||||||
TRADING_EFFECTIVE=OFF
|
|
||||||
EMERGENCY_EFFECTIVE=ON
|
EMERGENCY_EFFECTIVE=ON
|
||||||
A2-A5=NOT_PRESENT HEARTBEAT=NOT_PRESENT SCHEDULER=NOT_PRESENT
|
A2-A5=NOT_PRESENT HEARTBEAT=NOT_PRESENT SCHEDULER=NOT_PRESENT
|
||||||
AUTH.4D=FROZEN P15=FALSE DELETE_CANARY=FALSE
|
AUTH.4D=FROZEN P15=FALSE DELETE_CANARY=FALSE
|
||||||
|
|
|
||||||
73
red-queen-architecture/control-plane/README_CP1OS_SCOPE.md
Normal file
73
red-queen-architecture/control-plane/README_CP1OS_SCOPE.md
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
# PRE_HERMES Control Plane — CP1.0S Scope-Korrektur & Permanente Domain-Boundary
|
||||||
|
|
||||||
|
Scope-Korrektur der produktiven PRE_HERMES Control Plane (CP1.0S, 28.08.).
|
||||||
|
Wird in CP1.1 in die SoT/README übernommen.
|
||||||
|
|
||||||
|
## PERMANENT INVARIANT
|
||||||
|
|
||||||
|
```
|
||||||
|
RED_QUEEN_TRADING_AUTHORITY = NEVER
|
||||||
|
```
|
||||||
|
|
||||||
|
Red Queen ist ein **autonomes Arbeits-, Wissens-, Planungs-, Prüfungs- und
|
||||||
|
Orchestrierungssystem** — NICHT ein Trading-System.
|
||||||
|
|
||||||
|
Red Queen darf insbesondere **niemals** allein aufgrund ihrer Hermes-Autonomie erhalten:
|
||||||
|
- Broker Credentials
|
||||||
|
- Broker API Execution
|
||||||
|
- Order Execution
|
||||||
|
- Trading Execution Tokens
|
||||||
|
- Trading Kill-Switch Authority
|
||||||
|
- Trading Enable Authority
|
||||||
|
|
||||||
|
**Hermes Autonomy und Trading Authority sind zwei getrennte Sicherheitsdomänen.**
|
||||||
|
|
||||||
|
## Domain Boundary
|
||||||
|
|
||||||
|
### RED QUEEN = AUTONOMOUS WORK SYSTEM — RED QUEEN MAY:
|
||||||
|
- observe
|
||||||
|
- research
|
||||||
|
- plan
|
||||||
|
- orchestrate
|
||||||
|
- delegate
|
||||||
|
- verify
|
||||||
|
- document
|
||||||
|
- maintain mission state
|
||||||
|
- use authorized knowledge SAVE paths
|
||||||
|
- use separately human-authorized DELETE paths
|
||||||
|
|
||||||
|
### RED QUEEN MUST NOT:
|
||||||
|
- receive Trading Execution Authority
|
||||||
|
|
||||||
|
### TRADING SYSTEM = SEPARATE SECURITY DOMAIN
|
||||||
|
Eigene: Architektur, Security Boundary, Execution, Broker-Anbindung,
|
||||||
|
Credentials, Risk Control, Kill-Switch-Logik, Freigabelogik.
|
||||||
|
|
||||||
|
**PRODUCTIVE_MUTATIONS in der Hermes Control Plane bedeutet NICHT Trading/Orders/Broker-Mutationen.**
|
||||||
|
|
||||||
|
## Hermes Control Plane (nach CP1.0S) — 5 Controls
|
||||||
|
|
||||||
|
| Control | Bedeutung |
|
||||||
|
|---|---|
|
||||||
|
| `global_autonomy` | autonome Arbeit von Red Queen |
|
||||||
|
| `productive_mutations` | produktive Mutationen innerhalb der Hermes-/Knowledge-Domäne |
|
||||||
|
| `save_execution` | SAVE-Pfad der Hermes-/Knowledge-Domäne |
|
||||||
|
| `delete_execution` | DELETE-Pfad der Hermes-/Knowledge-Domäne (zusätzlich AUTH.4D + Human Authorization) |
|
||||||
|
| `emergency_stop` | stoppt Red-Queen/Hermes-Autonomie |
|
||||||
|
|
||||||
|
**KEIN Switch dieser Control Plane kontrolliert das Trading-System.**
|
||||||
|
`trading_execution` wurde entfernt (irrtümlicher Control aus korrigierter Architekturannahme).
|
||||||
|
|
||||||
|
## Level Model Correction (Red-Queen-Autonomie-Level)
|
||||||
|
|
||||||
|
Autonomie-Level beziehen sich ausschließlich auf **Arbeitsautonomie**. KEIN Trading-Level.
|
||||||
|
|
||||||
|
| Level | Bedeutung |
|
||||||
|
|---|---|
|
||||||
|
| L0 | Disabled / Manual |
|
||||||
|
| L1 | Read-only Observation |
|
||||||
|
| L2 | Autonomous Planning / Preparation |
|
||||||
|
| L3 | bounded authorized SAVE / productive knowledge work |
|
||||||
|
| L4 | human-authorized DELETE / höhere Arbeitsautonomie |
|
||||||
|
|
||||||
|
Weitere Arbeitsautonomie-Level können später separat definiert werden. KEIN Trading-Level.
|
||||||
|
|
@ -32,13 +32,12 @@ ON = "ON"
|
||||||
OFF = "OFF"
|
OFF = "OFF"
|
||||||
_ALLOWED = {ON, OFF}
|
_ALLOWED = {ON, OFF}
|
||||||
|
|
||||||
# Die sechs Controls
|
# Die fünf Controls (Hermes/Red-Queen-Domäne; Trading ist eine separate Security-Domain)
|
||||||
POSITIVE_GATES = (
|
POSITIVE_GATES = (
|
||||||
"global_autonomy",
|
"global_autonomy",
|
||||||
"productive_mutations",
|
"productive_mutations",
|
||||||
"save_execution",
|
"save_execution",
|
||||||
"delete_execution",
|
"delete_execution",
|
||||||
"trading_execution",
|
|
||||||
)
|
)
|
||||||
EMERGENCY = "emergency_stop"
|
EMERGENCY = "emergency_stop"
|
||||||
|
|
||||||
|
|
@ -124,7 +123,7 @@ def _positive_effective(raw, grant_boot_id, current_boot_id, emergency_effective
|
||||||
|
|
||||||
def read_control_state():
|
def read_control_state():
|
||||||
"""
|
"""
|
||||||
Berechnet den vollständigen Control-State (RAW + EFFECTIVE für alle 6 Controls).
|
Berechnet den vollständigen Control-State (RAW + EFFECTIVE für alle 5 Controls).
|
||||||
Rückgabe: dict mit allen Feldern für die Status-Projection.
|
Rückgabe: dict mit allen Feldern für die Status-Projection.
|
||||||
"""
|
"""
|
||||||
current_boot_id = read_boot_id()
|
current_boot_id = read_boot_id()
|
||||||
|
|
@ -146,19 +145,18 @@ def read_control_state():
|
||||||
"productive_mutations": "productive_mutations",
|
"productive_mutations": "productive_mutations",
|
||||||
"save_execution": "save",
|
"save_execution": "save",
|
||||||
"delete_execution": "delete",
|
"delete_execution": "delete",
|
||||||
"trading_execution": "trading",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# 2) Positive Gates (Boot-gebunden, hierarchisch)
|
# 2) Positive Gates (Boot-gebunden, hierarchisch)
|
||||||
for gate in POSITIVE_GATES:
|
for gate in POSITIVE_GATES:
|
||||||
raw, grant_boot = _parse_raw(os.path.join(STATE_DIR, gate))
|
raw, grant_boot = _parse_raw(os.path.join(STATE_DIR, gate))
|
||||||
short = _short[gate]
|
short = _short[gate]
|
||||||
# Abhängigkeit: SAVE/DELETE/TRADING brauchen zusätzlich die Master-Gates (siehe unten).
|
# Abhängigkeit: SAVE/DELETE brauchen zusätzlich die Master-Gates (siehe unten).
|
||||||
eff = _positive_effective(raw, grant_boot, current_boot_id, emergency_effective)
|
eff = _positive_effective(raw, grant_boot, current_boot_id, emergency_effective)
|
||||||
result[f"{short}_raw"] = raw if raw is not None else "MISSING"
|
result[f"{short}_raw"] = raw if raw is not None else "MISSING"
|
||||||
result[f"{short}_effective"] = eff
|
result[f"{short}_effective"] = eff
|
||||||
|
|
||||||
# 3) Hierarchische Berechnung (MISSIONS: Mutationen, SAVE, DELETE, TRADING)
|
# 3) Hierarchische Berechnung (MISSIONS: Mutationen, SAVE, DELETE)
|
||||||
global_eff = result["global_autonomy_effective"]
|
global_eff = result["global_autonomy_effective"]
|
||||||
mutations_eff = result["productive_mutations_effective"]
|
mutations_eff = result["productive_mutations_effective"]
|
||||||
|
|
||||||
|
|
@ -166,8 +164,8 @@ def read_control_state():
|
||||||
if mutations_eff == ON and global_eff == OFF:
|
if mutations_eff == ON and global_eff == OFF:
|
||||||
result["productive_mutations_effective"] = OFF
|
result["productive_mutations_effective"] = OFF
|
||||||
|
|
||||||
# SAVE / DELETE / TRADING brauchen: GLOBAL=ON AND MUTATIONS=ON AND eigener Grant gültig
|
# SAVE / DELETE brauchen: GLOBAL=ON AND MUTATIONS=ON AND eigener Grant gültig
|
||||||
for gate in ("save_execution", "delete_execution", "trading_execution"):
|
for gate in ("save_execution", "delete_execution"):
|
||||||
short = _short[gate]
|
short = _short[gate]
|
||||||
raw = result[f"{short}_raw"]
|
raw = result[f"{short}_raw"]
|
||||||
grant_boot = _parse_raw(os.path.join(STATE_DIR, gate))[1]
|
grant_boot = _parse_raw(os.path.join(STATE_DIR, gate))[1]
|
||||||
|
|
@ -191,8 +189,6 @@ def format_projection(state):
|
||||||
"save_effective",
|
"save_effective",
|
||||||
"delete_raw",
|
"delete_raw",
|
||||||
"delete_effective",
|
"delete_effective",
|
||||||
"trading_raw",
|
|
||||||
"trading_effective",
|
|
||||||
"emergency_raw",
|
"emergency_raw",
|
||||||
"emergency_effective",
|
"emergency_effective",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""CP1 statische + adversariale Tests (A-J) für control_reader.py."""
|
"""CP1 statische + adversariale Tests (A-J) für control_reader.py.
|
||||||
|
|
||||||
|
CP1.0S: trading_execution aus der Hermes Control Plane entfernt (separate
|
||||||
|
Security-Domain). Test E (trading-Gate) wurde entfernt, da der Gate nicht mehr
|
||||||
|
existiert. Alle übrigen Tests prüfen die 5 Hermes-Controls.
|
||||||
|
"""
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -53,14 +58,12 @@ e.write("global_autonomy", "OFF")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "ON")
|
e.write("emergency_stop", "ON")
|
||||||
s = read()
|
s = read()
|
||||||
check("initial global=OFF", s["global_autonomy_effective"] == "OFF")
|
check("initial global=OFF", s["global_autonomy_effective"] == "OFF")
|
||||||
check("initial mutations=OFF", s["productive_mutations_effective"] == "OFF")
|
check("initial mutations=OFF", s["productive_mutations_effective"] == "OFF")
|
||||||
check("initial save=OFF", s["save_effective"] == "OFF")
|
check("initial save=OFF", s["save_effective"] == "OFF")
|
||||||
check("initial delete=OFF", s["delete_effective"] == "OFF")
|
check("initial delete=OFF", s["delete_effective"] == "OFF")
|
||||||
check("initial trading=OFF", s["trading_effective"] == "OFF")
|
|
||||||
check("initial emergency=ON", s["emergency_effective"] == "ON")
|
check("initial emergency=ON", s["emergency_effective"] == "ON")
|
||||||
|
|
||||||
# ---------- TEST A: positive ON mit falscher Boot-ID -> OFF ----------
|
# ---------- TEST A: positive ON mit falscher Boot-ID -> OFF ----------
|
||||||
|
|
@ -70,7 +73,6 @@ e.write("global_autonomy", "ON\nboot_id=other-boot\n")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "OFF")
|
e.write("emergency_stop", "OFF")
|
||||||
s = read()
|
s = read()
|
||||||
check("A global OFF bei falscher boot_id", s["global_autonomy_effective"] == "OFF")
|
check("A global OFF bei falscher boot_id", s["global_autonomy_effective"] == "OFF")
|
||||||
|
|
@ -82,7 +84,6 @@ e.write("global_autonomy", f"ON\nboot_id={e.cur_boot}\n")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "ON")
|
e.write("emergency_stop", "ON")
|
||||||
s = read()
|
s = read()
|
||||||
check("B global OFF bei emergency ON", s["global_autonomy_effective"] == "OFF")
|
check("B global OFF bei emergency ON", s["global_autonomy_effective"] == "OFF")
|
||||||
|
|
@ -95,7 +96,6 @@ e.write("global_autonomy", f"ON\nboot_id={e.cur_boot}\n")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", f"ON\nboot_id={e.cur_boot}\n")
|
e.write("save_execution", f"ON\nboot_id={e.cur_boot}\n")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "OFF")
|
e.write("emergency_stop", "OFF")
|
||||||
s = read()
|
s = read()
|
||||||
check("C save OFF bei mutations OFF", s["save_effective"] == "OFF")
|
check("C save OFF bei mutations OFF", s["save_effective"] == "OFF")
|
||||||
|
|
@ -108,25 +108,11 @@ e.write("global_autonomy", "OFF")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", f"ON\nboot_id={e.cur_boot}\n")
|
e.write("delete_execution", f"ON\nboot_id={e.cur_boot}\n")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "OFF")
|
e.write("emergency_stop", "OFF")
|
||||||
s = read()
|
s = read()
|
||||||
check("D delete OFF bei global OFF", s["delete_effective"] == "OFF")
|
check("D delete OFF bei global OFF", s["delete_effective"] == "OFF")
|
||||||
check("D global OFF", s["global_autonomy_effective"] == "OFF")
|
check("D global OFF", s["global_autonomy_effective"] == "OFF")
|
||||||
|
|
||||||
# ---------- TEST E: trading ON aber emergency ON -> TRADING OFF ----------
|
|
||||||
print("== TEST E: trading ON, emergency ON -> TRADING OFF ==")
|
|
||||||
e = Env()
|
|
||||||
e.write("global_autonomy", "OFF")
|
|
||||||
e.write("productive_mutations", "OFF")
|
|
||||||
e.write("save_execution", "OFF")
|
|
||||||
e.write("delete_execution", "OFF")
|
|
||||||
e.write("trading_execution", f"ON\nboot_id={e.cur_boot}\n")
|
|
||||||
e.write("emergency_stop", "ON")
|
|
||||||
s = read()
|
|
||||||
check("E trading OFF bei emergency ON", s["trading_effective"] == "OFF")
|
|
||||||
check("E emergency ON", s["emergency_effective"] == "ON")
|
|
||||||
|
|
||||||
# ---------- TEST F: fehlende emergency_stop -> EMERGENCY ON ----------
|
# ---------- TEST F: fehlende emergency_stop -> EMERGENCY ON ----------
|
||||||
print("== TEST F: missing emergency_stop -> ON ==")
|
print("== TEST F: missing emergency_stop -> ON ==")
|
||||||
e = Env()
|
e = Env()
|
||||||
|
|
@ -134,7 +120,6 @@ e.write("global_autonomy", "OFF")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
# KEIN emergency_stop schreiben
|
# KEIN emergency_stop schreiben
|
||||||
s = read()
|
s = read()
|
||||||
check("F emergency ON bei fehlender Datei", s["emergency_effective"] == "ON")
|
check("F emergency ON bei fehlender Datei", s["emergency_effective"] == "ON")
|
||||||
|
|
@ -146,7 +131,6 @@ e.write("global_autonomy", "OFF")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "MAYBE\n")
|
e.write("emergency_stop", "MAYBE\n")
|
||||||
s = read()
|
s = read()
|
||||||
check("G emergency ON bei malformed", s["emergency_effective"] == "ON")
|
check("G emergency ON bei malformed", s["emergency_effective"] == "ON")
|
||||||
|
|
@ -158,7 +142,6 @@ e.write("global_autonomy", f"ON\nboot_id={e.cur_boot}\n")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "OFF")
|
e.write("emergency_stop", "OFF")
|
||||||
s = read()
|
s = read()
|
||||||
check("H vor Reboot global ON", s["global_autonomy_effective"] == "ON")
|
check("H vor Reboot global ON", s["global_autonomy_effective"] == "ON")
|
||||||
|
|
@ -175,7 +158,6 @@ e.write("global_autonomy", f"ON\nboot_id={e.cur_boot}\n")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "OFF")
|
e.write("emergency_stop", "OFF")
|
||||||
e.missing_boot()
|
e.missing_boot()
|
||||||
s = read()
|
s = read()
|
||||||
|
|
@ -188,7 +170,6 @@ e.write("global_autonomy", "ON") # no boot_id -> invalid anyway
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "ON")
|
e.write("emergency_stop", "ON")
|
||||||
os.chmod(os.path.join(e.state_dir, "emergency_stop"), 0o000)
|
os.chmod(os.path.join(e.state_dir, "emergency_stop"), 0o000)
|
||||||
s = read()
|
s = read()
|
||||||
|
|
@ -202,7 +183,6 @@ e.write("global_autonomy", "ON\n") # no boot_id line
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "OFF")
|
e.write("emergency_stop", "OFF")
|
||||||
s = read()
|
s = read()
|
||||||
check("ON ohne boot_id -> global OFF", s["global_autonomy_effective"] == "OFF")
|
check("ON ohne boot_id -> global OFF", s["global_autonomy_effective"] == "OFF")
|
||||||
|
|
@ -214,7 +194,6 @@ e.write("global_autonomy", "") # empty
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "OFF")
|
e.write("emergency_stop", "OFF")
|
||||||
s = read()
|
s = read()
|
||||||
check("empty positive -> global OFF", s["global_autonomy_effective"] == "OFF")
|
check("empty positive -> global OFF", s["global_autonomy_effective"] == "OFF")
|
||||||
|
|
@ -227,7 +206,6 @@ e.write("global_autonomy", "ON\nfoo=bar\nboot_id=xyz\n")
|
||||||
e.write("productive_mutations", "OFF")
|
e.write("productive_mutations", "OFF")
|
||||||
e.write("save_execution", "OFF")
|
e.write("save_execution", "OFF")
|
||||||
e.write("delete_execution", "OFF")
|
e.write("delete_execution", "OFF")
|
||||||
e.write("trading_execution", "OFF")
|
|
||||||
e.write("emergency_stop", "OFF")
|
e.write("emergency_stop", "OFF")
|
||||||
s = read()
|
s = read()
|
||||||
check("unknown field -> global OFF", s["global_autonomy_effective"] == "OFF")
|
check("unknown field -> global OFF", s["global_autonomy_effective"] == "OFF")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue