|
| 1 | +# Native MariaDB Runtime Service |
| 2 | + |
| 3 | +`provider: "native"` provisions a short-lived MariaDB process for MySQL-compatible workloads on Docker-free hosts. The generic runtime-service layer owns its complete lifecycle. Recipes may select only `provider: "native"` and `engine: "mariadb"`; host, port, credentials, sockets, configuration files, and filesystem paths are not configurable. |
| 4 | + |
| 5 | +## Isolation Contract |
| 6 | + |
| 7 | +- The provider rejects UID 0 and resolves and validates `mariadbd`, `mariadb-install-db`, `mariadb`, util-linux `prlimit`, `truncate`, `mkfs.ext4`, `fuse2fs`, and `fusermount3` identities before allocation. |
| 8 | +- Default executable discovery ignores the caller's `PATH`, searches fixed system directories, resolves symlinks, and requires every executable and ancestor to be UID-0-owned and not group/other writable. Child processes receive a fixed minimal `PATH`. |
| 9 | +- Every run gets a mode-`0700` `mkdtemp` root. MariaDB's data directory, temporary directory, socket, PID file, error log, plugin directory, secure-file directory, home, and working directory are all inside the bounded image. |
| 10 | +- Initialization, daemon, and administrative clients run through fixed hard rlimits; each database command itself begins with `--no-defaults`. No shell or default socket is used. |
| 11 | +- Administration uses only the private Unix socket. Workloads receive a generated least-privilege `runtime` account over loopback TCP through the existing ephemeral connector-secret channel. |
| 12 | +- Initialization, FUSE, and daemon commands each run in a new owned process group. Cleanup addresses the retained group, not a PID file; it waits for the complete group to disappear after graceful shutdown, then applies group-wide `SIGTERM` and `SIGKILL` as needed. Linux captures the leader start-time token and revalidates it while the leader is alive. Root device/inode identity and a symlink-free tree are revalidated before recursive removal. |
| 13 | +- Failures, aborts, timeouts, startup crashes, and partial initialization all enter the same graceful-shutdown, forced-shutdown, wait, and verified-removal state machine. Cleanup failure is terminal and retained in bounded lifecycle evidence. |
| 14 | +- Address space is capped at 2 GiB, CPU at 300 seconds, individual daemon files at 128 MiB, open files at 512, and processes/threads at 512. Core files and locked memory are disabled. The datadir is a provider-owned 256 MiB ext4 image formatted with 4,096 inodes and mounted through unprivileged FUSE; device, byte, and inode geometry must be proven before initialization. Hosts without this containment fail closed. |
| 15 | +- Recipes may declare at most two native services, bounding the aggregate native ceiling to two 2-GiB address spaces, two 256-MiB images, and the corresponding process/file limits. |
| 16 | +- The daemon uses an empty bounded plugin directory and a bounded `secure-file-priv` directory. Startup fails unless every enabled storage engine is on the fixed local-only allowlist; FEDERATED, CONNECT, SPIDER, S3, and unknown enabled engines are rejected. The runtime account has privileges only on its generated database and cannot install plugins. |
| 17 | +- Runtime descriptor discovery distinguishes package support from host availability. It advertises the active native capability only after trusted tools and a real create, mount, geometry, write, unmount, process-group-exit, and removal probe succeed; unavailable reasons are stable codes without private paths. |
| 18 | +- Cleanup is single-flight for concurrent callers. A failed attempt may be retried, and evidence transitions from `teardown: failed` to a consistent released/completed state only after the retry proves cleanup. |
| 19 | +- Evidence contains service ID, engine/provider version, lifecycle state, and memory measurements only. It never contains credentials or private absolute paths. |
| 20 | + |
| 21 | +## Daemon Arguments |
| 22 | + |
| 23 | +The provider starts `mariadbd` through `prlimit` with these fixed controls plus provider-owned absolute paths and a freshly allocated loopback port: |
| 24 | + |
| 25 | +```text |
| 26 | +--no-defaults |
| 27 | +--datadir=<bounded-image>/database |
| 28 | +--socket=<bounded-image>/runtime/server.sock |
| 29 | +--pid-file=<bounded-image>/runtime/server.pid |
| 30 | +--log-error=<bounded-image>/runtime/server.log |
| 31 | +--tmpdir=<bounded-image>/tmp |
| 32 | +--plugin-dir=<bounded-image>/plugins |
| 33 | +--secure-file-priv=<bounded-image>/files |
| 34 | +--bind-address=127.0.0.1 |
| 35 | +--port=<ephemeral> |
| 36 | +--skip-name-resolve |
| 37 | +--skip-log-bin |
| 38 | +--skip-host-cache |
| 39 | +--skip-slave-start |
| 40 | +--skip-symbolic-links |
| 41 | +--local-infile=OFF |
| 42 | +--performance-schema=OFF |
| 43 | +--skip-feedback |
| 44 | +--innodb-buffer-pool-size=32M |
| 45 | +--innodb-buffer-pool-size-max=32M |
| 46 | +--innodb-log-buffer-size=4M |
| 47 | +--key-buffer-size=8M |
| 48 | +--aria-pagecache-buffer-size=8M |
| 49 | +--thread-handling=pool-of-threads |
| 50 | +--thread-pool-size=1 |
| 51 | +--aria-log-file-size=16M |
| 52 | +--innodb-file-per-table=OFF |
| 53 | +--innodb-data-file-path=ibdata1:32M:autoextend:max:96M |
| 54 | +--innodb-temp-data-file-path=ibtmp1:16M:autoextend:max:32M |
| 55 | +--innodb-log-file-size=32M |
| 56 | +--max-connections=10 |
| 57 | +--max-prepared-stmt-count=256 |
| 58 | +--max-session-mem-used=32M |
| 59 | +--open-files-limit=512 |
| 60 | +--thread-cache-size=0 |
| 61 | +--table-open-cache=128 |
| 62 | +--table-definition-cache=128 |
| 63 | +--tmp-table-size=8M |
| 64 | +--max-heap-table-size=8M |
| 65 | +``` |
| 66 | + |
| 67 | +The hard address-space ceiling is 2 GiB. Linux runs record the owned daemon's post-readiness RSS in evidence; the MariaDB 10.11 integration gate additionally requires observed RSS to remain at or below 128 MiB. |
| 68 | + |
| 69 | +## Integration Contract |
| 70 | + |
| 71 | +Homeboy Extensions issue #2412 may select this provider by emitting the generic runtime-service recipe declaration below. WP Codebox performs all provisioning and cleanup; callers do not supply or manage native process details. |
| 72 | + |
| 73 | +```json |
| 74 | +{ |
| 75 | + "id": "wordpress-database", |
| 76 | + "kind": "mysql", |
| 77 | + "configuration": { "provider": "native", "engine": "mariadb" }, |
| 78 | + "outputs": { |
| 79 | + "host": "DB_HOST", |
| 80 | + "port": "DB_PORT", |
| 81 | + "username": "DB_USER", |
| 82 | + "password": "DB_PASSWORD", |
| 83 | + "database": "DB_NAME" |
| 84 | + } |
| 85 | +} |
| 86 | +``` |
0 commit comments