Fix PDF table layout and restructure appendices F–H.
Add a Pandoc tables.lua filter that rebalances column widths, breaks long code tokens, and scales wide tables so dense catalogs no longer overlap. Split the eight-column framework matrix, insert the Flue mapping appendix, and renumber the 30-day and startup guides; rebuild the book PDF.
This commit is contained in:
1 parent
0f4ac6373e
commit
9575aa4979
19 files changed
+575
-52
No files matched your search
@@ -3,7 +3,7 @@
|
||||
Begleitdokument zu *Secure Coding Agents with Flue* (Martin Richardt, 2026).
|
||||
**Zweck:** die bekannten Buch-Schwächen (Credentials, fehlende Fallstudien, kein Production-Code, DACH/Enterprise-Bias, junges Flue, Tabellen-Dichte) **operativ abfedern** – nicht das Buch nacherzählen.
|
||||
|
||||
**Buch-Fassung:** `manuskript/appendix-f-einfuehrungs-paket-30-tage.md` (Anhang F im PDF).
|
||||
**Buch-Fassung:** `manuskript/appendix-g-einfuehrungs-paket-30-tage.md` (Anhang G im PDF).
|
||||
Inhaltlich spiegeln; bei Abweichungen gilt die Manuskript-Fassung für den Build.
|
||||
|
||||
| Feld | Inhalt |
|
||||
@@ -12,7 +12,7 @@ Inhaltlich spiegeln; bei Abweichungen gilt die Manuskript-Fassung für den Build
|
||||
| **Doc-Version** | `v1.1.0` |
|
||||
| **policy_version** | Living Doc: jede inhaltliche Änderung an Controls, Checklisten oder DoD erhöht die Version und wird im Changelog/PR festgehalten |
|
||||
| **Framework** | agnostisch (Flue, Mastra, Eve, Sandcastle, Eigenbau) – Nahtstellen, keine Vendor-APIs |
|
||||
| **Kanonische Ablage** | Manuskript (Anhang F) + dieses Design-Doc; Notion/Linear nur als Spiegel |
|
||||
| **Kanonische Ablage** | Manuskript (Anhang G) + dieses Design-Doc; Notion/Linear nur als Spiegel |
|
||||
|
||||
---
|
||||
|
||||
@@ -282,3 +282,4 @@ Muster, keine Firmen-Retellings.
|
||||
|---------|-------|----------|
|
||||
| `v1.0.0` | 2026-07-24 | Erstfassung: Strategie, 30-Tage-Plan, 8 MVC, Living Checklists, Quellen, Risiken, DoD |
|
||||
| `v1.1.0` | 2026-07-24 | Als Anhang F ins Manuskript/PDF übernommen |
|
||||
| `v1.1.1` | 2026-07-24 | Umnummeriert zu Anhang G (neues F: Flue-Pattern-Mapping) |
|
||||
Vendored
BIN
Binary file not shown.
@@ -5,8 +5,8 @@
|
||||
**Autor:** Martin Richardt
|
||||
**Genre:** Fachbuch / Security Engineering für Software- und Plattform-Teams
|
||||
**Sprache:** Deutsch (Titel und Untertitel Englisch)
|
||||
**Umfang (Stand 2026-07-24):** ca. 150–175 PDF-Seiten (A4), davon Kern (Prolog–Epilog) ≈ 70 S., Anhänge A–G, Front/Backmatter Rest
|
||||
**Status:** 2. Auflage / Update – Empirie-Fallstudien, TypeScript-Referenzbeispiele, Startup-Schnelleinstieg (Anhang G), Flue-Reife in Anhang E; Lektorat Runde 1–2 + inhaltliches Update
|
||||
**Umfang (Stand 2026-07-24):** ca. 150–175 PDF-Seiten (A4), davon Kern (Prolog–Epilog) ≈ 70 S., Anhänge A–H, Front/Backmatter Rest
|
||||
**Status:** 2. Auflage / Update – Empirie-Fallstudien, TypeScript-Referenzbeispiele, Flue-Pattern-Mapping (Anhang F), 30-Tage-Paket (G), Startup-Schnelleinstieg (H), Flue-Reife in Anhang E; Lektorat Runde 1–2 + inhaltliches Update
|
||||
|
||||
---
|
||||
|
||||
@@ -72,7 +72,7 @@ Harness entwerfen, messen und im Incident abarbeiten.
|
||||
| 2 Datenschutz | 4–6 | Datenfluss, DLP, Entropie |
|
||||
| 3 Isolation | 7–8 | Sandbox, Tool-Permissions |
|
||||
| 4 Compliance | 9–11 | Logging/Audit, Enterprise-Patterns, Playbooks |
|
||||
| Back | Epilog; Anhänge A–G (Bedrohungsmodell, Empirie+Fallstudien, Audit-Reife, DX, Frameworks+Flue-Reife, 30-Tage-Paket, Startup-Schnelleinstieg); Glossar, Literatur, Autor, Kolophon | |
|
||||
| Back | Epilog; Anhänge A–H (Bedrohungsmodell, Empirie+Fallstudien, Audit-Reife, DX, Frameworks+Flue-Reife, Flue-Pattern-Mapping, 30-Tage-Paket, Startup-Schnelleinstieg); Glossar, Literatur, Autor, Kolophon | |
|
||||
|
||||
Drei Leitfragen durchgängig:
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ pdf-styled: assemble
|
||||
--metadata-file=pdf/metadata.yaml \
|
||||
--lua-filter=pdf/filters/toc-unlisted.lua \
|
||||
--lua-filter=pdf/filters/boxes.lua \
|
||||
--lua-filter=pdf/filters/tables.lua \
|
||||
--resource-path=.:manuskript:assets \
|
||||
-V lang=de-DE -V papersize=a4 -V colorlinks \
|
||||
--toc -o dist/secure-coding-agents-flue.pdf
|
||||
@@ -47,6 +48,7 @@ pdf-sample:
|
||||
--metadata-file=pdf/metadata.yaml \
|
||||
--lua-filter=pdf/filters/toc-unlisted.lua \
|
||||
--lua-filter=pdf/filters/boxes.lua \
|
||||
--lua-filter=pdf/filters/tables.lua \
|
||||
--resource-path=.:manuskript:assets \
|
||||
-V lang=de-DE \
|
||||
-V papersize=a4 \
|
||||
|
||||
@@ -22,8 +22,9 @@ Quellen für den PDF-Build. Reihenfolge steuert `scripts/assemble_book.py`.
|
||||
| `appendix-c-audit-freigabe-reife.md` | Back (Anhang) | **Vollfassung** |
|
||||
| `appendix-d-developer-experience.md` | Back (Anhang) | **Vollfassung** |
|
||||
| `appendix-e-alternativen-frameworks.md` | Back (Anhang) | **Vollfassung** |
|
||||
| `appendix-f-einfuehrungs-paket-30-tage.md` | Back (Anhang) | **Vollfassung** |
|
||||
| `appendix-g-schnelleinstieg-startups.md` | Back (Anhang) | **Vollfassung** (2. Aufl.) |
|
||||
| `appendix-f-mapping-flue-patterns.md` | Back (Anhang) | **Vollfassung** (optional) |
|
||||
| `appendix-g-einfuehrungs-paket-30-tage.md` | Back (Anhang) | **Vollfassung** |
|
||||
| `appendix-h-schnelleinstieg-startups.md` | Back (Anhang) | **Vollfassung** (2. Aufl.) |
|
||||
| `glossar.md` | Back | **Vollfassung** |
|
||||
| `literatur.md` | Back | **Vollfassung** |
|
||||
| `ueber-den-autor.md` | Back | **Vollfassung** |
|
||||
|
||||
@@ -649,7 +649,7 @@ ohne SIEM.
|
||||
| Adoption (aktive Nutzer/Woche) | 9/12 | **11/12**; Consumer-Chat-Bypass 5 → 1 |
|
||||
|
||||
**Lehrpunkt.** Ohne Shadow wäre Enforce an Tag 1 bei ~18 % Reibung gescheitert.
|
||||
Dieselben sechs Controls wie in Anhang G – ohne Rollenmatrix.
|
||||
Dieselben sechs Controls wie in Anhang H – ohne Rollenmatrix.
|
||||
|
||||
### Fallstudie 2 — Scale-up (~180 Entwickler, Platform 4 FTE)
|
||||
|
||||
|
||||
@@ -726,23 +726,39 @@ Hinweis, **Harness- und Security-Patterns sprachübergreifend zu standardisieren
|
||||
|
||||
## Vergleichende Übersicht
|
||||
|
||||
Die nächste Tabelle verdichtet die Dimensionen aus der Einleitung. Sie ersetzt
|
||||
keinen Proof-of-Concept: „Sandbox-Stärke“ und „Lock-in“ hängen vom konkreten
|
||||
Profil, von Platform-Optionen und von dem ab, was Sie *tatsächlich* nutzen –
|
||||
nicht vom Marketing-Label „hat Sandbox“. Wer die Tabelle als Rangliste liest,
|
||||
verfehlt den Zweck; wer sie als Checkliste gegen eigene Constraints liest,
|
||||
spart sich teure Fehlentscheidungen.
|
||||
Die nächsten Tabellen verdichten die Dimensionen aus der Einleitung (in zwei
|
||||
Blöcken, damit der A4-Satzspiegel lesbar bleibt). Sie ersetzen keinen
|
||||
Proof-of-Concept: „Sandbox-Stärke“ und „Lock-in“ hängen vom konkreten Profil,
|
||||
von Platform-Optionen und von dem ab, was Sie *tatsächlich* nutzen – nicht vom
|
||||
Marketing-Label „hat Sandbox“. Wer die Tabellen als Rangliste liest, verfehlt
|
||||
den Zweck; wer sie als Checkliste gegen eigene Constraints liest, spart sich
|
||||
teure Fehlentscheidungen.
|
||||
|
||||
| Framework | Philosophie | Deployment | Lock-in | Sandbox-Stärke | Observability | Beste Use Cases | Nähe zu Flue |
|
||||
|-----------|-------------|------------|---------|----------------|---------------|-----------------|--------------|
|
||||
| **Flue** | Harness-first | hoch (viele Targets) | niedrig | hoch (explizit) | Adapter (OTel u. a.) | Portable Agents, Security-Harness, CI/Multi-Runtime | — |
|
||||
| **Mastra** | Product-first | hoch (Node + Deployer + optional Platform) | mittel (Platform optional höher) | mittel–hoch (Workspaces/Platform wachsend) | sehr hoch (Traces, Evals, Studio) | Agent-Produkte, Workflows, Memory | mittel |
|
||||
| **Eve** | Platform-first | Vercel-happy-path | mittel–hoch (Gravity) | hoch (managed + Adapter) | hoch (Tracing, Evals) | Multi-Channel Agents auf Vercel | hoch (Authoring), niedrig (Deploy) |
|
||||
| **Sandcastle** | Coding-Orchestrierung | lokal/CI/Cloud-Sandbox-Provider | niedrig–mittel | sehr hoch (Kern) | Logs/Streams, selbst verdrahten | AFK-Coding, Review-Pipelines | mittel (komplementär) |
|
||||
| **AI SDK** | Thin model/UI layer | app-gebunden | niedrig–mittel | gering (allein) | grundlegend / extern | Chat-UI, Streaming, Tools im App-Feature | niedrig (Schicht darunter) |
|
||||
| **LangGraph.js** | Graph/state machine | je nach Host; Platform-Eigenheiten | mittel (Ökosystem) | variabel | hoch im LC-Ökosystem | komplexe Control Flows | niedrig–mittel |
|
||||
| **OpenAI Agents SDK** | Lightweight vendor SDK | app-/vendor-nah | mittel–hoch | vorhanden (Sandbox Agents) | hoch in OpenAI-Tooling | Handoffs, OpenAI-first Apps, Voice | niedrig–mittel |
|
||||
| **CrewAI** | Multi-agent roles (Python) | Python-Stack | mittel | variabel | je nach Setup | Python Multi-Agent Teams | niedrig (anderes Ökosystem) |
|
||||
**Block A — Hosting und Isolation**
|
||||
|
||||
| Framework | Philosophie | Deployment | Lock-in | Sandbox-Stärke |
|
||||
|-----------|-------------|------------|---------|----------------|
|
||||
| **Flue** | Harness-first | hoch (viele Targets) | niedrig | hoch (explizit) |
|
||||
| **Mastra** | Product-first | hoch (Node + Deployer + optional Platform) | mittel (Platform optional höher) | mittel–hoch (Workspaces/Platform wachsend) |
|
||||
| **Eve** | Platform-first | Vercel-happy-path | mittel–hoch (Gravity) | hoch (managed + Adapter) |
|
||||
| **Sandcastle** | Coding-Orchestrierung | lokal/CI/Cloud-Sandbox-Provider | niedrig–mittel | sehr hoch (Kern) |
|
||||
| **AI SDK** | Thin model/UI layer | app-gebunden | niedrig–mittel | gering (allein) |
|
||||
| **LangGraph.js** | Graph/state machine | je nach Host; Platform-Eigenheiten | mittel (Ökosystem) | variabel |
|
||||
| **OpenAI Agents SDK** | Lightweight vendor SDK | app-/vendor-nah | mittel–hoch | vorhanden (Sandbox Agents) |
|
||||
| **CrewAI** | Multi-agent roles (Python) | Python-Stack | mittel | variabel |
|
||||
|
||||
**Block B — Betrieb, Use Cases und Nähe zu Flue**
|
||||
|
||||
| Framework | Observability | Beste Use Cases | Nähe zu Flue |
|
||||
|-----------|---------------|-----------------|--------------|
|
||||
| **Flue** | Adapter (OTel u. a.) | Portable Agents, Security-Harness, CI/Multi-Runtime | — |
|
||||
| **Mastra** | sehr hoch (Traces, Evals, Studio) | Agent-Produkte, Workflows, Memory | mittel |
|
||||
| **Eve** | hoch (Tracing, Evals) | Multi-Channel Agents auf Vercel | hoch (Authoring), niedrig (Deploy) |
|
||||
| **Sandcastle** | Logs/Streams, selbst verdrahten | AFK-Coding, Review-Pipelines | mittel (komplementär) |
|
||||
| **AI SDK** | grundlegend / extern | Chat-UI, Streaming, Tools im App-Feature | niedrig (Schicht darunter) |
|
||||
| **LangGraph.js** | hoch im LC-Ökosystem | komplexe Control Flows | niedrig–mittel |
|
||||
| **OpenAI Agents SDK** | hoch in OpenAI-Tooling | Handoffs, OpenAI-first Apps, Voice | niedrig–mittel |
|
||||
| **CrewAI** | je nach Setup | Python Multi-Agent Teams | niedrig (anderes Ökosystem) |
|
||||
|
||||
### Textliche Einordnung der Differenzen
|
||||
|
||||
@@ -882,3 +898,5 @@ Python). Vergleichen Sie entlang Deployment, Abstraktion, Observability,
|
||||
Sandbox, Lock-in, DX und Use-Case – nicht entlang Marketing-Listen. Wählen Sie
|
||||
das Framework, das zu Gravity und Agent-Typ passt; bauen Sie Gateway, DLP,
|
||||
Permissions, Sandbox-Profile und Audit so, dass die Wahl austauschbar bleibt.
|
||||
Wie die Buch-Nähte optional auf Flue-Erweiterungspunkte mappen, skizziert
|
||||
**Anhang F** – ohne die Framework-Wahl zu ersetzen.
|
||||
@@ -0,0 +1,189 @@
|
||||
# Anhang F Mapping der Buch-Patterns auf Flue (optional)
|
||||
|
||||
## Kern in einem Satz
|
||||
|
||||
Die Buch-Patterns sitzen an stabilen Kontrollnähten; in einem TypeScript-Harness
|
||||
wie Flue mappt ihr sie auf Hooks, Middleware und Policy-as-Code – nicht auf
|
||||
Framework-Marketing oder Default-Konfigurationen.
|
||||
|
||||
## Einleitung
|
||||
|
||||
Dieser Anhang ist **optional**. Er ersetzt weder die harness-übergreifenden
|
||||
Patterns der Kapitel 3–11 noch die Anhänge A–E. Wer die Patterns versteht und
|
||||
einen anderen Harness betreibt, kann ihn überspringen. Wer Flue (oder einen
|
||||
flue-ähnlichen TypeScript-Harness) einsetzt und wissen will, *wo* die Buch-
|
||||
Kontrollen typischerweise andocken, findet hier eine schlanke Landkarte.
|
||||
|
||||
Flue ist ausschließlich **Bezugspunkt und Umsetzungsbeispiel**. Formulierungen
|
||||
meinen: *so könnt ihr die Patterns in Flue umsetzen* – nicht: *so macht es Flue
|
||||
richtig* und nicht: *Flue bietet out-of-the-box Sicherheit*. Die fachliche Policy,
|
||||
die Deny-by-default-Haltung und der Nachweis im Audit bleiben eure Arbeit.
|
||||
Kapitel 2 beschreibt die Schichten; Anhang E ordnet Alternativen und Reife ein.
|
||||
Hier geht es nur um das Mapping der zentralen Nähte.
|
||||
|
||||
**Versionshinweis:** Stand Flue Beta / 1.x-Linie Mitte 2026 – APIs können sich
|
||||
noch ändern. Patterns bleiben primär. Pinnt Versionen; bindet Controls an
|
||||
eigene Module und Hooks, nicht an Tutorial-Copy-Paste.
|
||||
|
||||
---
|
||||
|
||||
## Mapping-Tabelle der Kontrollnähte
|
||||
|
||||
Die nächste Tabelle ordnet die Kontrollkette des Buchs den typischen
|
||||
Erweiterungsflächen in einem Flue-ähnlichen Harness zu. Die Reihenfolge ist die
|
||||
des Happy Paths (Context → Filter → Modell → Aktion → Nachweis), nicht die
|
||||
Priorität im Incident.
|
||||
|
||||
| Buch-Naht | Kapitel | Typische Flue-Erweiterungsfläche | Was ihr dort steuert |
|
||||
|-----------|---------|----------------------------------|----------------------|
|
||||
| Context Builder / Policy Gate | 2, 4, 8 | Context-Assemblierung, Pre-Model-Hooks, policy-as-code | Quellen, Pfade, Rollen-Scopes, Budget |
|
||||
| DLP + Entropie | 5–6 | Middleware auf Chunks und Tool-Outputs (Egress und Re-Ingress) | Redact/Deny, Shadow-Metriken, FP-Kalibrierung |
|
||||
| Model Gateway | 4, 10 | Model-Client-Wrapper / einziger Provider-Adapter | Allowlist, Identity, Residenz, kein Seiteneinstieg |
|
||||
| Tool Permissions | 8 | Tool-Definitionen, Pre-Exec-Gate, Approval-Hook | Schema, Scope, Risk R0–R4, Session-Binding |
|
||||
| Sandbox | 7 | Sandbox-Binding und Profil-IDs pro Risk-Klasse | Isolation, Netz-Deny, Secret-Trennung |
|
||||
| Observability / Audit | 9, 11 | Event-Emitter an denselben Hooks; exportierbares Schema | `session_id`, `policy_version`, Deny-Gründe, Retention |
|
||||
|
||||
Wer die Tabelle ausfüllt und pro Zelle *Owner + Artefakt* benennt, hat die
|
||||
Minimale Landkarte für Reviews – unabhängig davon, wie die npm-Exports heißen.
|
||||
|
||||
---
|
||||
|
||||
## Die Nähte im Einzelnen
|
||||
|
||||
### Context Builder und Policy Gate
|
||||
|
||||
Im Harness-Loop entsteht der Prompt nicht „im Modell“, sondern in der Context-
|
||||
Assemblierung: Dateien, Diffs, Suchtreffer, frühere Tool-Outputs. In Flue
|
||||
erweitert ihr typischerweise den Pfad **nach** dem Sammeln der Chunks und
|
||||
**vor** dem Model-Call – als Hook, Middleware oder reines Policy-Modul, das der
|
||||
Orchestrator aufruft. Dort vergeben und prüfen Source-IDs, Pfad- und
|
||||
Repo-Labels, Rollen-Default-Scopes und Token-Budgets.
|
||||
|
||||
Das Policy Gate ist deny-by-default: was nicht freigegeben ist, kommt nicht in
|
||||
die Message-Liste. Implementiert die Regeln als **testbare Funktionen** mit
|
||||
`policy_version`, nicht als verstreute `if`-Zweige in Adaptern. Flue (oder
|
||||
jeder vergleichbare Loop) liefert die Naht; die Datenklassen und Allowlists
|
||||
liefert ihr. Details und Trust-Zonen: Kapitel 4 und 8.
|
||||
|
||||
### DLP und Entropie
|
||||
|
||||
Pattern-Matching und Entropie-Filter sind **keine** Einmal-Schicht vor dem
|
||||
ersten Model-Call. Sie gehören auf den Egress zum Modell *und* auf den
|
||||
Re-Ingress von Tool-Outputs in den Context Builder. In einem Flue-Harness
|
||||
hängt ihr die Pipeline an dieselben Pre-Model- und After-Tool-Hooks: Chunk rein,
|
||||
redact/deny/allow raus, Metrik schreiben.
|
||||
|
||||
Frameworks stellen oft Logging- oder Middleware-Primitive bereit – keine
|
||||
fachliche DLP. Regeln, Denylist-Pfade, Secret-Muster, Sliding-Window-Entropie
|
||||
und der Übergang Shadow → Enforce bleiben euer Code (Kapitel 5–6). Kalibriert
|
||||
False Positives an euren Diffs; „Default an“ ohne Baseline erzeugt Workarounds
|
||||
(Anhang D).
|
||||
|
||||
### Model Gateway
|
||||
|
||||
Jeder Model-Call sollte genau **einen** kontrollierten Ausgang haben: den
|
||||
Gateway-Adapter. In Flue mappt ihr das auf den austauschbaren Model-Client bzw.
|
||||
Provider-Wrapper, den der Orchestrator nutzt – nicht auf ad-hoc-SDK-Calls aus
|
||||
Tools oder Utility-Skripten. Dort sitzen Allowlist von Endpoint und Modell,
|
||||
Workload-Identity, Residenz- und Retention-Flags sowie harte Ablehnung
|
||||
unbekannter Ziele.
|
||||
|
||||
Deny-by-default heißt hier: unbekannte Modelle und Regionen sind blockiert,
|
||||
bis freigeschaltet. Der Harness macht den Aufruf sichtbar; die vertragliche und
|
||||
technische Gateway-Policy bleibt bei euch (Kapitel 4, 10). Seiteneinstiege am
|
||||
Harness vorbei sind Architekturfehler, keine Konfigurationsnuance.
|
||||
|
||||
### Tool Permissions
|
||||
|
||||
Tool-Vorschläge des Modells sind Absichten, keine Freigaben. Vor der Ausführung
|
||||
greift in Flue typischerweise die Kette Schema-Validierung → Scope-Check →
|
||||
Risk-Klasse → optionales Approval → Sandbox-Profil. Die Erweiterungspunkte
|
||||
liegen an typisierten Tool-Definitionen und am zentralen Pre-Exec-Hook – nicht
|
||||
im System-Prompt.
|
||||
|
||||
Least Privilege ist Daten und Code: erlaubte Tools pro Rolle/Session, Argument-
|
||||
Constraints, Risk R0–R4, Session-Binding. Was nicht registriert und freigegeben
|
||||
ist, läuft nicht. Approvals für R3/R4 sind Harness-Hooks plus euer Freigabe-
|
||||
Workflow; Flue orchestriert den Wait-State höchstens, entscheidet aber nicht
|
||||
über eure Risikoklassen (Kapitel 8).
|
||||
|
||||
### Sandbox
|
||||
|
||||
Die Sandbox trennt Ausführung von Host-, Netz- und Geheimnisraum. In Flue
|
||||
koppelt ihr Risk-Klassen an **explizite Sandbox-Profile** (IDs mit dokumentierter
|
||||
Semantik): lokaler Workspace, Container, remote Runner – je nach Binding.
|
||||
Erweiterungspunkt ist die Stelle, an der der Tool-Router das Profil wählt und
|
||||
übergibt, nicht eine implizite Default-Umgebung aus dem Tutorial.
|
||||
|
||||
Defaults ungetestet zu übernehmen ist riskant: Isolation ist nur so stark wie
|
||||
Netz-Policy, Mounts und Secret-Injection. Testet Profile wie Produktcode;
|
||||
wechselt das Binding, bleibt die Profil-ID und ihre Semantik euer Vertrag
|
||||
(Kapitel 7). Der Harness startet die Umgebung; die Grenzziehung ist eure.
|
||||
|
||||
### Observability und Audit
|
||||
|
||||
Was ihr im Audit nicht zeigen könnt, gilt als nicht kontrolliert. Hängt
|
||||
strukturierte Events an **dieselben** Nähte wie Policy und DLP: Context-Deny,
|
||||
Gateway-Call, Permission-Deny, Sandbox-Start, Approval, Kill-Switch. In Flue
|
||||
nutzt ihr typischerweise Logger/Tracer-Hooks oder einen eigenen Event-Emitter
|
||||
im Orchestrator – mit `session_id`, `policy_version`, Tool-Name, Risk und
|
||||
Deny-Grund, ohne Secret-Klartext und ohne volle Prompt-Payloads in denselben
|
||||
Buckets wie Metriken.
|
||||
|
||||
Exportierbarkeit schlägt Vendor-Trace: ein Minimal-Schema (Kapitel 9), das
|
||||
unabhängig vom Framework bleibt, ist die Naht für Incidents und Evidence
|
||||
(Anhang C). Playbooks und Kill-Switch (Kapitel 11) lesen dieselben IDs – sonst
|
||||
sind Logs Dekoration.
|
||||
|
||||
---
|
||||
|
||||
## Was ihr trotzdem selbst bauen müsst
|
||||
|
||||
Kein Agent-Harness nimmt euch die Security-Arbeit ab. Typische Lücken, die ihr
|
||||
auch mit Flue **selbst** schließt:
|
||||
|
||||
1. **Fachliche Policy** – Datenklassen, Pfad- und Tool-Regeln, Rollen-Defaults,
|
||||
versioniert als `policy_version` und unit-testbar.
|
||||
2. **DLP-Inhalt und Kalibrierung** – Muster, Entropie-Schwellen, Shadow-Baseline,
|
||||
FP-Stichproben, Enforce-Freigabe.
|
||||
3. **Gateway-Vertrag** – Allowlist, Identity, Residenz, AVV/DPA, kein Shadow-SDK
|
||||
neben dem Harness.
|
||||
4. **Tool-Surface-Disziplin** – schlanke Registries, Risk-Klassen, Approvals,
|
||||
Argument-Constraints; keine „Debug-Shell für alle“.
|
||||
5. **Sandbox-Semantik** – Profilwahl, Netz-Deny, Secret-Mounts, regelmäßige
|
||||
Regressionstests pro Binding.
|
||||
6. **Nachweis und Betrieb** – Audit-Schema, Retention-Tiers, Stichproben,
|
||||
Playbooks, Kill-Switch, Re-Zertifizierung (Kapitel 9–11, Anhang C).
|
||||
7. **Identity und DX** – Session-Attribution; Controls, die Entwickler nicht
|
||||
systematisch umgehen (Anhang D).
|
||||
|
||||
Kurz: Flue kann Nähte und Primitive liefern. **Kontrolle als Produkt** baut ihr
|
||||
darüber – deny-by-default, messbar, austauschbar.
|
||||
|
||||
---
|
||||
|
||||
## Wann dieser Anhang hilft – und wann nicht
|
||||
|
||||
**Hilft**, wenn ihr Flue oder einen vergleichbaren TypeScript-Harness betreibt
|
||||
und die Buch-Controls an konkrete Erweiterungspunkte hängen wollt; wenn Reviews
|
||||
fragen „wo sitzt das bei uns?“; wenn API-Namen wechseln und ihr die stabilen
|
||||
Nähte festhalten müsst.
|
||||
|
||||
**Hilft nicht**, wenn ihr die Patterns noch nicht kennt (dann Kapitel 3–11);
|
||||
wenn ihr Frameworks vergleichen oder Exit planen wollt (**Anhang E**); wenn ihr
|
||||
einen 30-Tage-Rollout mit Shadow und DoD braucht (**Anhang G**); wenn ein
|
||||
Startup in zwei Wochen die Minimale Kette sucht (**Anhang H**). Er ersetzt
|
||||
kein Bedrohungsmodell, keine DLP-Regeln und keinen Audit-Nachweis.
|
||||
|
||||
---
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
Die zentralen Buch-Patterns mappt ihr in Flue auf wenige, wiederkehrende
|
||||
Erweiterungsflächen: Pre-Model- und Pre-Tool-Hooks, Gateway-Adapter,
|
||||
Sandbox-Profile und Audit-Events an denselben Stellen. APIs der 1.x-Linie
|
||||
können sich ändern; die Nähte und die Deny-by-default-Haltung bleiben der
|
||||
Maßstab. Was fachliche Policy, Filterinhalt, Verträge und Betrieb angeht, baut
|
||||
ihr selbst – der Harness ist Bezugspunkt, nicht fertige Security. Nutzt diesen
|
||||
Anhang als optionale Landkarte, nicht als Ersatz für die Kapitel und die übrigen
|
||||
Anhänge.
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
# Anhang F Schwächen-resistentes Einführungs-Paket (30 Tage)
|
||||
# Anhang G Schwächen-resistentes Einführungs-Paket (30 Tage)
|
||||
|
||||
## Kern in einem Satz
|
||||
|
||||
@@ -421,7 +421,7 @@ Postmortem-Übung an Near-Miss oder Game-day-Befund durchführen.
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
Anhang F macht aus den Mustern der Kapitel 4–11 einen **30-Tage-Start**: messen
|
||||
Anhang G macht aus den Mustern der Kapitel 4–11 einen **30-Tage-Start**: messen
|
||||
vor blockieren, acht Minimal-Controls, Living Checklists und eine harte
|
||||
Definition of Done. Was fehlt, ersetzen Sie durch eigene Zahlen und Artefakte –
|
||||
nicht durch weiteres Lesen allein. Deny by default, Shadow vor Enforce und
|
||||
+9
-9
@@ -1,4 +1,4 @@
|
||||
# Anhang G Schnelleinstieg für Startups & kleine Teams
|
||||
# Anhang H Schnelleinstieg für Startups & kleine Teams
|
||||
|
||||
## Kern in einem Satz
|
||||
|
||||
@@ -7,7 +7,7 @@ Team ohne Security-Abteilung in zwei Wochen spürbar absichern kann.
|
||||
|
||||
## Überblick
|
||||
|
||||
Dieser Anhang ist die **leichte Einstiegsvariante** zu Anhang F (30-Tage-Paket
|
||||
Dieser Anhang ist die **leichte Einstiegsvariante** zu Anhang G (30-Tage-Paket
|
||||
für Platform/Security) und zu Kapitel 10 (Governance). Er ersetzt weder
|
||||
Bedrohungsmodell noch DLP-Kapitel – er priorisiert.
|
||||
|
||||
@@ -15,13 +15,13 @@ Ziel ist eine **minimale, messbare Kontrollkette**: Secret-Abfluss und
|
||||
unkontrollierte Tool-Wirkung im Alltag begrenzen, bevor Formalismen und
|
||||
Enterprise-Artefakte greifen. Wer später Audit, AVV oder Multi-Team-Betrieb
|
||||
braucht, zieht nach – mit den Triggern am Ende dieses Anhangs und den
|
||||
Vertiefungen in Kapitel 5–11 sowie Anhang C und F.
|
||||
Vertiefungen in Kapitel 5–11 sowie Anhang C und G.
|
||||
|
||||
## Worum es hier *nicht* geht
|
||||
|
||||
Nicht um Evidence-Pakete, RACI-Matrizen oder Residenz-Zonen-Kataloge. Die kommen,
|
||||
wenn Kunden, Auditoren oder ein Platform-Team sie verlangen (Kapitel 10, Anhang
|
||||
C und F). Hier geht es um die **minimale Kette**, die Secret-Abfluss und
|
||||
C und G). Hier geht es um die **minimale Kette**, die Secret-Abfluss und
|
||||
unkontrollierte Tool-Wirkung im Alltag begrenzt.
|
||||
|
||||
Was hier bewusst fehlt, ist kein Qualitätsurteil gegen das restliche Buch. Es
|
||||
@@ -139,7 +139,7 @@ bzw. welcher Anhang fällig wird – nicht „irgendwann Security nachziehen“.
|
||||
| Erster Enterprise-Kunde / AVV | Kap. 10, Gateway-Pattern |
|
||||
| Break-glass > ~10/1000 Sessions | Kap. 11, Policy-Schuld, Anhang B |
|
||||
| Unbekannte Tokens in Diffs | Kap. 6 Entropie kalibrieren |
|
||||
| Mehrere Teams, ein Harness | Kap. 8 Profile, Anhang F 30-Tage |
|
||||
| Mehrere Teams, ein Harness | Kap. 8 Profile, Anhang G 30-Tage |
|
||||
| Audit fragt operating effectiveness | Kap. 9 Events, Anhang C |
|
||||
|
||||
**Mini-Szenario:** Der erste Enterprise-Prospect verlangt AVV und
|
||||
@@ -147,12 +147,12 @@ Nachvollziehbarkeit von Freigaben. Das ist der Trigger für Kapitel 10 und
|
||||
Gateway-Pattern – nicht der Zeitpunkt, die sechs Controls zu verwerfen, sondern
|
||||
sie mit Governance und Evidence zu erweitern.
|
||||
|
||||
## Abgrenzung zu Anhang F
|
||||
## Abgrenzung zu Anhang G
|
||||
|
||||
Anhang G und Anhang F teilen dieselben Sicherheitsnähte. Sie unterscheiden sich
|
||||
Anhang H und Anhang G teilen dieselben Sicherheitsnähte. Sie unterscheiden sich
|
||||
in Audience, Horizont und Formalismus – nicht in der Richtung der Controls.
|
||||
|
||||
| | Anhang G (dieser) | Anhang F |
|
||||
| | Anhang H (dieser) | Anhang G |
|
||||
|--|-------------------|----------|
|
||||
| Audience | Startup / kleines Team | Platform + Security |
|
||||
| Horizont | 2 Wochen | 30 Tage |
|
||||
@@ -160,7 +160,7 @@ in Audience, Horizont und Formalismus – nicht in der Richtung der Controls.
|
||||
| Erfolg | messbare Minimale Kette | Shadow→Enforce mit Artefakten |
|
||||
|
||||
Wer die sechs Controls in zwei Wochen greifbar hat und danach Team, Kunde oder
|
||||
Audit skaliert, wechselt den Lesepfad zu Anhang F – ohne die Einstiegskette
|
||||
Audit skaliert, wechselt den Lesepfad zu Anhang G – ohne die Einstiegskette
|
||||
zurückzubauen.
|
||||
|
||||
## Ton zum Schluss
|
||||
@@ -66,7 +66,7 @@ ist die Fähigkeit, im Alltag drei Fragen zu beantworten: *Was hat der Agent
|
||||
gesehen? Was hat er getan? Können wir beides belegen und begrenzen?*
|
||||
|
||||
Teams ohne Freigabeprozess brauchen dieselbe Fähigkeit in schlankerer Form –
|
||||
oft reichen die sechs Controls im Schnelleinstieg (Anhang G). Teams mit
|
||||
oft reichen die sechs Controls im Schnelleinstieg (Anhang H). Teams mit
|
||||
Revision brauchen dieselben Antworten als anschlussfähige Nachweise (Kapitel
|
||||
9–10). Der Unterschied ist der **Formalismus**, nicht die Physik der Daten-
|
||||
und Aktionspfade.
|
||||
@@ -136,7 +136,7 @@ Kap. 9–11 Nachweis und Betrieb
|
||||
- [ ] Agents lesen mehr, als der Nutzer einfügt – oder schreiben/shellen
|
||||
- [ ] Kontext geht an Modelle außerhalb des reinen Intranet-Trusts
|
||||
- [ ] Keine versionierte Policy / kein Session-Audit – oder Ausnahmen ohne TTL
|
||||
*Wenn ja:* Anhang G starten; nicht auf „Enterprise-Projekt“ warten
|
||||
*Wenn ja:* Anhang H starten; nicht auf „Enterprise-Projekt“ warten
|
||||
|
||||
Je mehr Haken, desto teurer wird Warten.
|
||||
|
||||
|
||||
@@ -220,5 +220,6 @@ Der Agent-Harness ist die Kontrollfläche: Identity, Context, Policy, Gateway,
|
||||
Tools, Sandbox, Audit. Flue ist ein TypeScript-Beispiel für genau diese Schicht;
|
||||
die Patterns lassen sich auf andere Harnesses mappen. Einen vergleichenden
|
||||
Überblick über Mastra, Eve, Sandcastle und weitere TypeScript-Optionen liefert
|
||||
**Anhang E**. Kapitel 3 ergänzt die Architektur um ein explizites
|
||||
**Anhang E**. Ein optionales Mapping der Buch-Nähte auf Flue-Erweiterungspunkte
|
||||
steht in **Anhang F**. Kapitel 3 ergänzt die Architektur um ein explizites
|
||||
Bedrohungsmodell – damit die Hooks an den richtigen Risiken ansetzen.
|
||||
@@ -147,7 +147,7 @@ zusätzlichen `curl`-Tool – und erneut mit dem ersten persistenten Summary-Sto
|
||||
- [ ] Mindestens Pfade D1–D3 bewertet; STRIDE mit Control-Verweis
|
||||
- [ ] Annahmen und Non-Goals dokumentiert
|
||||
- [ ] Review-Trigger definiert; Mapping auf Backlog
|
||||
*Startup:* eine Seite Threat Sketch reicht (Anhang G Woche 1)
|
||||
*Startup:* eine Seite Threat Sketch reicht (Anhang H Woche 1)
|
||||
*Erweitert:* Memory/Multi-Agent/MCP → Anhang A
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
@@ -515,7 +515,7 @@ und Ausnahmeweg ab – nicht die gesamte Enterprise-Policy.
|
||||
- [ ] Fixture-Tests in CI, keine echten Secrets
|
||||
- [ ] p95-Latenz-Budget gemessen
|
||||
- [ ] Exception-Prozess mit TTL
|
||||
*Startup:* nur Path-Deny + PEM/Cloud-Keys + Shadow-Woche (Anhang G)
|
||||
*Startup:* nur Path-Deny + PEM/Cloud-Keys + Shadow-Woche (Anhang H)
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ anschlussfähig an Einkauf, Rechtsabteilung, interne Revision und
|
||||
Linienmanagement. „Freigabefähig“ heißt hier nicht Feature-Liste auf einer
|
||||
Folie, sondern: **erklären, freigeben und prüfen können**.
|
||||
|
||||
**Zwei Lesepfade.** Kleine Teams und Startups: zuerst **Anhang G** (sechs
|
||||
**Zwei Lesepfade.** Kleine Teams und Startups: zuerst **Anhang H** (sechs
|
||||
Controls, zwei Wochen). Die Patterns unten sind dann Erweiterungen, sobald AVV,
|
||||
Revision oder mehrere BU-Profile greifen – nicht die Einstiegshürde. Platform-
|
||||
und Security-Teams in größeren Orgs: dieses Kapitel linear, ergänzt um Anhang C
|
||||
@@ -309,12 +309,12 @@ manuell zusammenführen – und findet Lücken, die niemand designed hat.
|
||||
## Checkliste
|
||||
|
||||
Bevor Sie Enterprise-Patterns „fertig“ nennen, sollten die folgenden Punkte
|
||||
grün sein – oder bewusst auf später terminiert (Startup-Pfad: Anhang G).
|
||||
grün sein – oder bewusst auf später terminiert (Startup-Pfad: Anhang H).
|
||||
|
||||
- [ ] Freigegebene Gateways erzwungen; Policy-Change mit Canary
|
||||
- [ ] Pilot→Enforce-Kriterien schriftlich
|
||||
- [ ] Bei Bedarf: Residenz, Retention-Owner, IAM↔Scopes, Evidence-Paket
|
||||
*Startup:* dieses Kapitel warten, bis AVV/Audit greift – bis dahin Anhang G
|
||||
*Startup:* dieses Kapitel warten, bis AVV/Audit greift – bis dahin Anhang H
|
||||
|
||||
## Zusammenfassung
|
||||
|
||||
|
||||
@@ -99,8 +99,8 @@ wichtig werden:
|
||||
|
||||
- **linear**, wenn Sie eine Plattform von Grund auf absichern,
|
||||
- **Startup-Lesepfad**, wenn Sie ohne Security-Abteilung starten: Prolog →
|
||||
Kapitel 1–2 skimming → **Anhang G** (sechs Controls, zwei Wochen) → bei Bedarf
|
||||
Kapitel 5, 8 und 9 für die Implementierungsnähte; Kapitel 10 und Anhang F erst
|
||||
Kapitel 1–2 skimming → **Anhang H** (sechs Controls, zwei Wochen) → bei Bedarf
|
||||
Kapitel 5, 8 und 9 für die Implementierungsnähte; Kapitel 10 und Anhang G erst
|
||||
bei wachsendem Formalismus,
|
||||
- **ab Kapitel 4**, wenn Architektur und Bedrohungsmodell klar sind und Sie
|
||||
sofort DLP und Gateway brauchen,
|
||||
@@ -110,7 +110,8 @@ wichtig werden:
|
||||
|
||||
Am Ende jedes Hauptkapitels stehen Checklisten. Sie sind zum Abhaken gedacht,
|
||||
nicht als Dekoration. Fallstudien mit Messwerten: **Anhang B**. Flue-Reife und
|
||||
Kombinationsstrategie: **Anhang E**.
|
||||
Kombinationsstrategie: **Anhang E**. Optionales Mapping der Buch-Nähte auf Flue:
|
||||
**Anhang F**.
|
||||
|
||||
## Ein Satz vor dem ersten Kapitel
|
||||
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
-- tables.lua — PDF table layout for *Secure Coding Agents with Flue*
|
||||
--
|
||||
-- Fixes overlapping / overflowing longtable columns:
|
||||
-- 1) Rebalance ColWidth from content (code columns need more room)
|
||||
-- 2) Make inline Code breakable at _, ., -, / inside tables
|
||||
-- 3) Scale font + tabcolsep by column count for wide tables
|
||||
--
|
||||
-- Only affects LaTeX/PDF output.
|
||||
|
||||
local function is_latex()
|
||||
return FORMAT:match("latex") ~= nil
|
||||
end
|
||||
|
||||
local function escape_tex(s)
|
||||
s = s:gsub("\\", "\\textbackslash{}")
|
||||
s = s:gsub("([&%%%$#_{}])", "\\%1")
|
||||
s = s:gsub("~", "\\textasciitilde{}")
|
||||
s = s:gsub("%^", "\\textasciicircum{}")
|
||||
return s
|
||||
end
|
||||
|
||||
--- Breakable monospace: allow line breaks after common token separators.
|
||||
local function breakable_texttt(text)
|
||||
local s = escape_tex(text)
|
||||
s = s:gsub("\\_", "\\_\\allowbreak{}")
|
||||
s = s:gsub("%.", ".\\allowbreak{}")
|
||||
s = s:gsub("%-", "-\\allowbreak{}")
|
||||
s = s:gsub("/", "/\\allowbreak{}")
|
||||
return pandoc.RawInline("latex", "\\texttt{" .. s .. "}")
|
||||
end
|
||||
|
||||
local function make_code_breakable(blocks)
|
||||
return pandoc.walk_block(pandoc.Div(blocks), {
|
||||
Code = function(el)
|
||||
return breakable_texttt(el.text)
|
||||
end,
|
||||
}).content
|
||||
end
|
||||
|
||||
local function walk_cell_contents(cell, fn)
|
||||
if cell.contents then
|
||||
cell.contents = fn(cell.contents)
|
||||
end
|
||||
end
|
||||
|
||||
local function for_each_cell(tbl, fn)
|
||||
if tbl.head and tbl.head.rows then
|
||||
for _, row in ipairs(tbl.head.rows) do
|
||||
for j, cell in ipairs(row.cells) do
|
||||
fn(cell, j)
|
||||
end
|
||||
end
|
||||
end
|
||||
if tbl.bodies then
|
||||
for _, body in ipairs(tbl.bodies) do
|
||||
if body.head then
|
||||
for _, row in ipairs(body.head) do
|
||||
for j, cell in ipairs(row.cells) do
|
||||
fn(cell, j)
|
||||
end
|
||||
end
|
||||
end
|
||||
if body.body then
|
||||
for _, row in ipairs(body.body) do
|
||||
for j, cell in ipairs(row.cells) do
|
||||
fn(cell, j)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if tbl.foot and tbl.foot.rows then
|
||||
for _, row in ipairs(tbl.foot.rows) do
|
||||
for j, cell in ipairs(row.cells) do
|
||||
fn(cell, j)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function collect_column_stats(tbl, ncols)
|
||||
local plain = {}
|
||||
local code = {}
|
||||
for i = 1, ncols do
|
||||
plain[i] = 0
|
||||
code[i] = 0
|
||||
end
|
||||
|
||||
for_each_cell(tbl, function(cell, j)
|
||||
if j < 1 or j > ncols then
|
||||
return
|
||||
end
|
||||
local text = pandoc.utils.stringify(cell) or ""
|
||||
if #text > plain[j] then
|
||||
plain[j] = #text
|
||||
end
|
||||
pandoc.walk_block(pandoc.Div(cell.contents or {}), {
|
||||
Code = function(el)
|
||||
if #el.text > code[j] then
|
||||
code[j] = #el.text
|
||||
end
|
||||
end,
|
||||
})
|
||||
end)
|
||||
|
||||
return plain, code
|
||||
end
|
||||
|
||||
local function rebalance_widths(ncols, plain, code)
|
||||
if ncols < 1 then
|
||||
return {}
|
||||
end
|
||||
|
||||
local weights = {}
|
||||
local has_code = {}
|
||||
for i = 1, ncols do
|
||||
local p = plain[i] or 0
|
||||
local c = code[i] or 0
|
||||
has_code[i] = c > 0
|
||||
-- Monospace is wider than proportional body text.
|
||||
weights[i] = math.max(p, c * 1.45, 4)
|
||||
end
|
||||
|
||||
local min_w = math.max(0.08, 0.72 / ncols)
|
||||
local max_w = 0.50
|
||||
if ncols >= 5 then
|
||||
max_w = 0.38
|
||||
end
|
||||
if ncols >= 6 then
|
||||
max_w = 0.30
|
||||
min_w = math.max(0.07, 0.68 / ncols)
|
||||
end
|
||||
if ncols >= 8 then
|
||||
max_w = 0.22
|
||||
min_w = math.max(0.06, 0.64 / ncols)
|
||||
end
|
||||
|
||||
-- Code-heavy columns need a floor so IDs don't spill into neighbors.
|
||||
local code_floor = 0.15
|
||||
if ncols >= 5 then
|
||||
code_floor = 0.185
|
||||
end
|
||||
if ncols >= 6 then
|
||||
code_floor = 0.13
|
||||
end
|
||||
|
||||
local sum = 0
|
||||
for i = 1, ncols do
|
||||
sum = sum + weights[i]
|
||||
end
|
||||
if sum <= 0 then
|
||||
sum = ncols
|
||||
for i = 1, ncols do
|
||||
weights[i] = 1
|
||||
end
|
||||
end
|
||||
|
||||
local widths = {}
|
||||
for i = 1, ncols do
|
||||
local w = weights[i] / sum
|
||||
local floor = min_w
|
||||
if has_code[i] then
|
||||
floor = math.max(floor, code_floor)
|
||||
end
|
||||
if w < floor then
|
||||
w = floor
|
||||
end
|
||||
if w > max_w then
|
||||
w = max_w
|
||||
end
|
||||
widths[i] = w
|
||||
end
|
||||
|
||||
-- Renormalize; if sum drifts, scale then re-clamp lightly.
|
||||
for _ = 1, 4 do
|
||||
local s = 0
|
||||
for i = 1, ncols do
|
||||
s = s + widths[i]
|
||||
end
|
||||
if s <= 0 then
|
||||
break
|
||||
end
|
||||
local factor = 1.0 / s
|
||||
local again = false
|
||||
for i = 1, ncols do
|
||||
widths[i] = widths[i] * factor
|
||||
local floor = min_w
|
||||
if has_code[i] then
|
||||
floor = math.max(floor, math.min(code_floor, 0.95 / ncols))
|
||||
end
|
||||
if widths[i] < floor * 0.98 then
|
||||
widths[i] = floor
|
||||
again = true
|
||||
end
|
||||
end
|
||||
if not again then
|
||||
-- final normalize without clamp
|
||||
s = 0
|
||||
for i = 1, ncols do
|
||||
s = s + widths[i]
|
||||
end
|
||||
if s > 0 then
|
||||
for i = 1, ncols do
|
||||
widths[i] = widths[i] / s
|
||||
end
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Round to 4 decimals; fix residual on last column.
|
||||
local acc = 0
|
||||
for i = 1, ncols - 1 do
|
||||
widths[i] = math.floor(widths[i] * 10000 + 0.5) / 10000
|
||||
acc = acc + widths[i]
|
||||
end
|
||||
widths[ncols] = math.max(0.05, 1.0 - acc)
|
||||
|
||||
return widths
|
||||
end
|
||||
|
||||
local function apply_widths(tbl, widths)
|
||||
for i, colspec in ipairs(tbl.colspecs) do
|
||||
local align = colspec[1]
|
||||
local w = widths[i]
|
||||
if w and w > 0 then
|
||||
tbl.colspecs[i] = { align, w }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function max_plain_len(plain)
|
||||
local m = 0
|
||||
for _, v in ipairs(plain) do
|
||||
if v > m then
|
||||
m = v
|
||||
end
|
||||
end
|
||||
return m
|
||||
end
|
||||
|
||||
local function wrap_style(ncols, max_cell)
|
||||
-- Returns (font_cmd or nil, tabcolsep or nil)
|
||||
if ncols >= 6 then
|
||||
return "\\footnotesize", "2.5pt"
|
||||
end
|
||||
if ncols >= 4 then
|
||||
return "\\small", "3.2pt"
|
||||
end
|
||||
if ncols >= 3 and max_cell >= 90 then
|
||||
return "\\small", "3.8pt"
|
||||
end
|
||||
if ncols == 2 and max_cell >= 160 then
|
||||
return "\\small", nil
|
||||
end
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
function Table(tbl)
|
||||
if not is_latex() then
|
||||
return nil
|
||||
end
|
||||
|
||||
local ncols = #tbl.colspecs
|
||||
if ncols < 1 then
|
||||
return nil
|
||||
end
|
||||
|
||||
local plain, code = collect_column_stats(tbl, ncols)
|
||||
local widths = rebalance_widths(ncols, plain, code)
|
||||
apply_widths(tbl, widths)
|
||||
|
||||
-- Breakable code only inside this table's cells.
|
||||
for_each_cell(tbl, function(cell, _)
|
||||
walk_cell_contents(cell, make_code_breakable)
|
||||
end)
|
||||
|
||||
local font_cmd, sep = wrap_style(ncols, max_plain_len(plain))
|
||||
-- Always wrap multi-column tables: emergencystretch reduces overfull
|
||||
-- hboxes in narrow p-columns (German compounds, long headers).
|
||||
if ncols < 2 and not font_cmd and not sep then
|
||||
return tbl
|
||||
end
|
||||
|
||||
local open = "\\begingroup"
|
||||
if font_cmd then
|
||||
open = open .. font_cmd
|
||||
end
|
||||
if sep then
|
||||
open = open .. "\\setlength{\\tabcolsep}{" .. sep .. "}"
|
||||
end
|
||||
if ncols >= 3 then
|
||||
open = open .. "\\sloppy\\setlength{\\emergencystretch}{2.5em}"
|
||||
end
|
||||
|
||||
return {
|
||||
pandoc.RawBlock("latex", open),
|
||||
tbl,
|
||||
pandoc.RawBlock("latex", "\\endgroup"),
|
||||
}
|
||||
end
|
||||
@@ -88,14 +88,22 @@
|
||||
\KOMAoptions{toc=chapterentrywithdots}
|
||||
|
||||
% ===========================================================================
|
||||
% 5) Pandoc-Shaded
|
||||
% 5) Tabellen (longtable aus Pandoc-Pipe-Tables)
|
||||
% ===========================================================================
|
||||
% Engere Defaults + etwas Zeilenhöhe für umbrechende p-Spalten.
|
||||
% Breite/Schrift pro Tabelle steuert pdf/filters/tables.lua.
|
||||
\setlength{\tabcolsep}{4.5pt}
|
||||
\renewcommand{\arraystretch}{1.12}
|
||||
|
||||
% ===========================================================================
|
||||
% 6) Pandoc-Shaded
|
||||
% ===========================================================================
|
||||
\usepackage{framed}
|
||||
\usepackage{color}
|
||||
\definecolor{shadecolor}{RGB}{248,248,248}
|
||||
|
||||
% ===========================================================================
|
||||
% 6) Zitat-Box
|
||||
% 7) Zitat-Box
|
||||
% ===========================================================================
|
||||
\usepackage{mdframed}
|
||||
\newmdenv[
|
||||
@@ -121,7 +129,7 @@
|
||||
{\end{secureagentsquotebox}}
|
||||
|
||||
% ===========================================================================
|
||||
% 7) tcolorbox (boxes.lua → nexttoken* env names for filter reuse)
|
||||
% 8) tcolorbox (boxes.lua → nexttoken* env names for filter reuse)
|
||||
% ===========================================================================
|
||||
\usepackage{tcolorbox}
|
||||
\tcbuselibrary{breakable,skins}
|
||||
@@ -220,7 +228,7 @@
|
||||
}
|
||||
|
||||
% ===========================================================================
|
||||
% 8) Cover- und Part-Page-Befehle
|
||||
% 9) Cover- und Part-Page-Befehle
|
||||
% ===========================================================================
|
||||
\usepackage{eso-pic}
|
||||
|
||||
|
||||
@@ -38,8 +38,9 @@ CHAPTER_ORDER = [
|
||||
("appendix-c-audit-freigabe-reife.md", "body"),
|
||||
("appendix-d-developer-experience.md", "body"),
|
||||
("appendix-e-alternativen-frameworks.md", "body"),
|
||||
("appendix-f-einfuehrungs-paket-30-tage.md", "body"),
|
||||
("appendix-g-schnelleinstieg-startups.md", "body"),
|
||||
("appendix-f-mapping-flue-patterns.md", "body"),
|
||||
("appendix-g-einfuehrungs-paket-30-tage.md", "body"),
|
||||
("appendix-h-schnelleinstieg-startups.md", "body"),
|
||||
("glossar.md", "body"),
|
||||
("literatur.md", "body"),
|
||||
("ueber-den-autor.md", "body"),
|
||||
|
||||
Reference in new issue
Block a user