|
| 1 | +# SPDX-License-Identifier: PMPL-1.0-or-later |
| 2 | +# stapeln.toml — Layer-based container build for formatrix-docs |
| 3 | +# |
| 4 | +# stapeln builds containers as composable layers (German: "to stack"). |
| 5 | +# Each layer is independently cacheable, verifiable, and signable. |
| 6 | +# |
| 7 | +# Formatrix Docs is a cross-platform document editor / knowledge tool nexus |
| 8 | +# with format tabs (TXT, MD, ADOC, DJOT, ORG, RST, TYP). It comprises a |
| 9 | +# Rust core, Gossamer+ReScript GUI, Ada TUI, ArangoDB storage, and Nickel |
| 10 | +# pipelines. Optional sidecar services: Vosk (speech-to-text), Tesseract (OCR). |
| 11 | + |
| 12 | +[metadata] |
| 13 | +name = "formatrix-docs" |
| 14 | +version = "0.1.0" |
| 15 | +description = "Cross-platform document editor and knowledge tool nexus with format tabs" |
| 16 | +author = "Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>" |
| 17 | +license = "PMPL-1.0-or-later" |
| 18 | +registry = "ghcr.io/hyperpolymath" |
| 19 | + |
| 20 | +[build] |
| 21 | +containerfile = "container/Containerfile" |
| 22 | +context = "." |
| 23 | +runtime = "podman" |
| 24 | + |
| 25 | +# ── Layer Definitions ────────────────────────────────────────── |
| 26 | + |
| 27 | +[layers.base] |
| 28 | +description = "Chainguard Wolfi minimal base" |
| 29 | +from = "cgr.dev/chainguard/wolfi-base:latest" |
| 30 | +cache = true |
| 31 | +verify = true |
| 32 | + |
| 33 | +# ── Rust Build Chain ────────────────────────────────────────── |
| 34 | + |
| 35 | +[layers.rust-toolchain] |
| 36 | +description = "Rust compiler and build tooling" |
| 37 | +extends = "base" |
| 38 | +packages = ["rust", "cargo", "openssl-dev", "pkgconf", "build-base"] |
| 39 | +cache = true |
| 40 | + |
| 41 | +[layers.rust-deps] |
| 42 | +description = "Pre-cached Rust workspace dependencies" |
| 43 | +extends = "rust-toolchain" |
| 44 | +commands = [ |
| 45 | + "mkdir -p /build", |
| 46 | + "cp Cargo.toml Cargo.lock /build/", |
| 47 | + "cp -r crates /build/crates", |
| 48 | +] |
| 49 | +workdir = "/build" |
| 50 | +cache = true |
| 51 | + |
| 52 | +[layers.rust-build] |
| 53 | +description = "Compile Rust workspace crates (core, gui, db, pipeline, bridges)" |
| 54 | +extends = "rust-deps" |
| 55 | +commands = [ |
| 56 | + "cargo build --release -p formatrix-core -p formatrix-gui -p formatrix-db -p formatrix-pipeline -p formatrix-bridges", |
| 57 | +] |
| 58 | +workdir = "/build" |
| 59 | + |
| 60 | +# ── Ada TUI Build Chain ────────────────────────────────────── |
| 61 | + |
| 62 | +[layers.ada-toolchain] |
| 63 | +description = "GNAT Ada compiler and gprbuild" |
| 64 | +extends = "base" |
| 65 | +packages = ["gcc-gnat", "gprbuild", "ncurses-dev", "build-base"] |
| 66 | +cache = true |
| 67 | + |
| 68 | +[layers.ada-build] |
| 69 | +description = "Compile Ada TUI binary" |
| 70 | +extends = "ada-toolchain" |
| 71 | +commands = [ |
| 72 | + "mkdir -p /build/tui", |
| 73 | + "cp -r tui /build/tui", |
| 74 | + "cd /build/tui && gprbuild -P formatrix_tui.gpr -XMODE=release", |
| 75 | +] |
| 76 | +workdir = "/build" |
| 77 | + |
| 78 | +# ── Zig FFI Build Chain ───────────────────────────────────── |
| 79 | + |
| 80 | +[layers.zig-toolchain] |
| 81 | +description = "Zig compiler for FFI layer" |
| 82 | +extends = "base" |
| 83 | +packages = ["zig"] |
| 84 | +cache = true |
| 85 | + |
| 86 | +[layers.zig-build] |
| 87 | +description = "Compile Zig FFI bindings" |
| 88 | +extends = "zig-toolchain" |
| 89 | +commands = [ |
| 90 | + "mkdir -p /build/ffi/zig", |
| 91 | + "cp -r ffi/zig /build/ffi/zig", |
| 92 | + "cd /build/ffi/zig && zig build -Doptimize=ReleaseSafe", |
| 93 | +] |
| 94 | +workdir = "/build" |
| 95 | + |
| 96 | +# ── ReScript UI Build Chain ────────────────────────────────── |
| 97 | + |
| 98 | +[layers.deno-toolchain] |
| 99 | +description = "Deno runtime for ReScript UI build" |
| 100 | +extends = "base" |
| 101 | +packages = ["deno"] |
| 102 | +cache = true |
| 103 | + |
| 104 | +[layers.ui-build] |
| 105 | +description = "Build ReScript frontend assets" |
| 106 | +extends = "deno-toolchain" |
| 107 | +commands = [ |
| 108 | + "mkdir -p /build/ui", |
| 109 | + "cp -r ui /build/ui", |
| 110 | + "cd /build/ui && deno task build", |
| 111 | +] |
| 112 | +workdir = "/build" |
| 113 | + |
| 114 | +# ── Runtime Image ──────────────────────────────────────────── |
| 115 | + |
| 116 | +[layers.runtime] |
| 117 | +description = "Minimal production runtime with all compiled artifacts" |
| 118 | +from = "cgr.dev/chainguard/wolfi-base:latest" |
| 119 | +packages = [ |
| 120 | + "ca-certificates", |
| 121 | + "curl", |
| 122 | + "openssl", |
| 123 | + "ncurses", |
| 124 | + "gtk+3.0", |
| 125 | + "webkit2gtk", |
| 126 | + "libsoup", |
| 127 | + "tesseract-ocr", |
| 128 | + "tesseract-ocr-eng", |
| 129 | + "espeak-ng", |
| 130 | + "hunspell", |
| 131 | + "hunspell-en-us", |
| 132 | + "pandoc", |
| 133 | +] |
| 134 | +copy-from = [ |
| 135 | + { layer = "rust-build", src = "/build/target/release/formatrix-gui", dst = "/usr/local/bin/formatrix-gui" }, |
| 136 | + { layer = "rust-build", src = "/build/target/release/formatrix-core", dst = "/usr/local/lib/libformatrix_core.so" }, |
| 137 | + { layer = "ada-build", src = "/build/tui/bin/formatrix-tui", dst = "/usr/local/bin/formatrix-tui" }, |
| 138 | + { layer = "zig-build", src = "/build/ffi/zig/zig-out/lib/", dst = "/usr/local/lib/" }, |
| 139 | + { layer = "ui-build", src = "/build/ui/dist/", dst = "/opt/formatrix-docs/ui/" }, |
| 140 | +] |
| 141 | +entrypoint = ["/usr/local/bin/formatrix-gui"] |
| 142 | +user = "formatrix" |
| 143 | + |
| 144 | +[layers.runtime-tui] |
| 145 | +description = "TUI-only runtime (no GUI dependencies)" |
| 146 | +from = "cgr.dev/chainguard/wolfi-base:latest" |
| 147 | +packages = [ |
| 148 | + "ca-certificates", |
| 149 | + "curl", |
| 150 | + "openssl", |
| 151 | + "ncurses", |
| 152 | + "tesseract-ocr", |
| 153 | + "tesseract-ocr-eng", |
| 154 | + "hunspell", |
| 155 | + "hunspell-en-us", |
| 156 | +] |
| 157 | +copy-from = [ |
| 158 | + { layer = "rust-build", src = "/build/target/release/formatrix-core", dst = "/usr/local/lib/libformatrix_core.so" }, |
| 159 | + { layer = "ada-build", src = "/build/tui/bin/formatrix-tui", dst = "/usr/local/bin/formatrix-tui" }, |
| 160 | + { layer = "zig-build", src = "/build/ffi/zig/zig-out/lib/", dst = "/usr/local/lib/" }, |
| 161 | +] |
| 162 | +entrypoint = ["/usr/local/bin/formatrix-tui"] |
| 163 | +user = "formatrix" |
| 164 | + |
| 165 | +# ── Sidecar: ArangoDB ─────────────────────────────────────── |
| 166 | + |
| 167 | +[layers.arangodb] |
| 168 | +description = "ArangoDB graph+document database sidecar" |
| 169 | +from = "arangodb/arangodb:3.12" |
| 170 | +env = { ARANGO_NO_AUTH = "0" } |
| 171 | +healthcheck = { test = ["CMD", "curl", "-f", "http://localhost:8529/_api/version"], interval = "30s", timeout = "10s", retries = 5 } |
| 172 | + |
| 173 | +# ── Sidecar: Vosk ─────────────────────────────────────────── |
| 174 | + |
| 175 | +[layers.vosk] |
| 176 | +description = "Vosk speech-to-text sidecar (optional, profile: speech)" |
| 177 | +from = "alphacep/kaldi-vosk-server:latest" |
| 178 | +expose = [2700] |
| 179 | + |
| 180 | +# ── Security ─────────────────────────────────────────────────── |
| 181 | + |
| 182 | +[security] |
| 183 | +non-root = true |
| 184 | +read-only-root = true |
| 185 | +no-new-privileges = true |
| 186 | +cap-drop = ["ALL"] |
| 187 | +seccomp-profile = "default" |
| 188 | + |
| 189 | +[security.signing] |
| 190 | +algorithm = "ML-DSA-87" |
| 191 | +provider = "cerro-torre" |
| 192 | + |
| 193 | +[security.sbom] |
| 194 | +format = "spdx-json" |
| 195 | +output = "sbom.spdx.json" |
| 196 | +include-deps = true |
| 197 | + |
| 198 | +# ── Verification ─────────────────────────────────────────────── |
| 199 | + |
| 200 | +[verify] |
| 201 | +vordr = true |
| 202 | +svalinn = true |
| 203 | +scan-on-build = true |
| 204 | +fail-on = ["critical", "high"] |
| 205 | + |
| 206 | +# ── Targets ──────────────────────────────────────────────────── |
| 207 | + |
| 208 | +[targets.development] |
| 209 | +description = "Full dev environment with all toolchains and debug logging" |
| 210 | +layers = ["base", "rust-toolchain", "rust-deps", "rust-build", "ada-toolchain", "ada-build", "zig-toolchain", "zig-build", "deno-toolchain", "ui-build"] |
| 211 | +env = { LOG_LEVEL = "debug", FORMATRIX_DB_URL = "http://arangodb:8529", FORMATRIX_DB_NAME = "formatrix" } |
| 212 | + |
| 213 | +[targets.production] |
| 214 | +description = "Minimal GUI runtime image" |
| 215 | +layers = ["runtime"] |
| 216 | +env = { LOG_LEVEL = "info", FORMATRIX_DB_URL = "http://arangodb:8529", FORMATRIX_DB_NAME = "formatrix" } |
| 217 | + |
| 218 | +[targets.production-tui] |
| 219 | +description = "Minimal TUI-only runtime image (headless / terminal)" |
| 220 | +layers = ["runtime-tui"] |
| 221 | +env = { LOG_LEVEL = "info", TERM = "xterm-256color", FORMATRIX_DB_URL = "http://arangodb:8529", FORMATRIX_DB_NAME = "formatrix" } |
| 222 | + |
| 223 | +[targets.test] |
| 224 | +description = "Build environment for CI test runs" |
| 225 | +layers = ["base", "rust-toolchain", "rust-deps", "rust-build", "ada-toolchain", "ada-build", "zig-toolchain", "zig-build", "deno-toolchain", "ui-build"] |
| 226 | +env = { LOG_LEVEL = "debug", RUST_BACKTRACE = "1", FORMATRIX_DB_URL = "http://arangodb:8529", FORMATRIX_DB_NAME = "formatrix_test" } |
| 227 | + |
| 228 | +# ── Compose (sidecar orchestration) ────────────────────────── |
| 229 | + |
| 230 | +[compose] |
| 231 | +description = "Full stack with ArangoDB and optional Vosk" |
| 232 | + |
| 233 | +[compose.services.formatrix] |
| 234 | +target = "production" |
| 235 | +ports = [] |
| 236 | +volumes = [ |
| 237 | + "formatrix-data:/home/formatrix/.local/share/formatrix-docs", |
| 238 | + "${HOME}/Documents:/home/formatrix/Documents:rw", |
| 239 | +] |
| 240 | +depends-on = ["arangodb"] |
| 241 | +network = "formatrix-net" |
| 242 | + |
| 243 | +[compose.services.formatrix-tui] |
| 244 | +target = "production-tui" |
| 245 | +volumes = [ |
| 246 | + "formatrix-data:/home/formatrix/.local/share/formatrix-docs", |
| 247 | + "${HOME}/Documents:/home/formatrix/Documents:rw", |
| 248 | +] |
| 249 | +depends-on = ["arangodb"] |
| 250 | +network = "formatrix-net" |
| 251 | +profiles = ["tui"] |
| 252 | + |
| 253 | +[compose.services.arangodb] |
| 254 | +layer = "arangodb" |
| 255 | +ports = ["8529:8529"] |
| 256 | +volumes = ["arangodb-data:/var/lib/arangodb3", "arangodb-apps:/var/lib/arangodb3-apps"] |
| 257 | +network = "formatrix-net" |
| 258 | + |
| 259 | +[compose.services.vosk] |
| 260 | +layer = "vosk" |
| 261 | +ports = ["2700:2700"] |
| 262 | +network = "formatrix-net" |
| 263 | +profiles = ["speech"] |
| 264 | + |
| 265 | +[compose.networks.formatrix-net] |
| 266 | +driver = "bridge" |
| 267 | + |
| 268 | +[compose.volumes] |
| 269 | +formatrix-data = {} |
| 270 | +arangodb-data = {} |
| 271 | +arangodb-apps = {} |
0 commit comments