Fix Docker static build: staging, C bootstrap, and missing Rust symbols

ober

4ae18ea187228439e0d4d10bc6ee08274d641c68

diff --git a/Dockerfile b/Dockerfile
index b9e9cf3..7412010 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -21,6 +21,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
     git \
     ca-certificates \
     curl \
+    libncurses-dev \
     uuid-dev \
     pkg-config \
     file \
@@ -68,7 +69,12 @@ RUN git clone https://github.com/ober/ChezScheme.git chez-musl-src && \
 
 # ── Clone jerboa framework ──────────────────────────────────────────────────
 WORKDIR /build/mine
-RUN git clone --depth 1 https://github.com/ober/jerboa.git
+ARG JERBOA_CACHE_BUST=1
+RUN git clone --depth 1 https://github.com/ober/jerboa.git && echo "bust=$JERBOA_CACHE_BUST"
+
+# ── Patch jerboa-native-rs with files not yet pushed to remote ──────────────
+# x25519.rs, process_ctl.rs, updated Cargo.toml/lib.rs needed for secmon
+COPY patches/jerboa-native-rs/ /build/mine/jerboa/jerboa-native-rs/
 
 # ── Build Rust native library (static, musl target) ─────────────────────────
 RUN cd /build/mine/jerboa/jerboa-native-rs && \
diff --git a/Makefile b/Makefile
index 3c3f10a..c0394b2 100644
--- a/Makefile
+++ b/Makefile
@@ -56,7 +56,7 @@ analyze:
 
 secmon-musl: docker
 
-secmon-musl-local: compile
+secmon-musl-local:
 	@echo "=== Building static secmon-agent with musl (local) ==="
 	./build-secmon-musl.sh
 
diff --git a/build-secmon-musl.ss b/build-secmon-musl.ss
index 9e88696..e26d715 100644
--- a/build-secmon-musl.ss
+++ b/build-secmon-musl.ss
@@ -4,8 +4,8 @@
 ;;; Usage: scheme -q --libdirs lib:<jerboa-lib> < build-secmon-musl.ss
 ;;;
 ;;; This script:
-;;;   1. Patches load-shared-object calls for static build
-;;;   2. Compiles all secmon modules
+;;;   1. Stages jerboa modules with load-shared-object patched out
+;;;   2. Compiles all jerboa + secmon modules from staged/patched sources
 ;;;   3. Creates boot file + optimized program .so
 ;;;   4. Generates C files with embedded boot data + FFI symbol registration
 ;;;   5. Compiles C with musl-gcc against musl-built Chez's scheme.h
@@ -49,7 +49,7 @@
 
 (printf "Native lib: ~a~n~n" native-lib-path)
 
-;; ========== Step 0: Stage and patch jerboa std modules for static builds ==========
+;; ========== Step 0: Stage and patch jerboa modules for static builds ==========
 ;; Modules that call (load-shared-object ...) need to be patched to (void)
 ;; since dlopen is unavailable in static musl builds. FFI symbols are
 ;; pre-registered via Sforeign_symbol() in the C bootstrap.
@@ -60,28 +60,68 @@
 (system (format "rm -rf '~a'" jerboa-stage))
 (system (format "mkdir -p '~a'" jerboa-stage))
 
-;; Copy the jerboa lib tree to staging
-(system (format "cp -a '~a/' '~a/'" jerboa-dir jerboa-stage))
+;; Copy the jerboa lib tree contents to staging
+(system (format "cp -a '~a/.' '~a/'" jerboa-dir jerboa-stage))
 
 ;; Patch all load-shared-object calls in staged copies
-(system (format "find '~a' -name '*.sls' -exec sed -i 's/(load-shared-object[^)]*)/(void)/g' {} +" jerboa-stage))
+;; NOTE: Space after "load-shared-object" prevents matching "(load-shared-object* name)"
+;; in jerboa/ffi.sls which would corrupt the define form
+(system (format "find '~a' -name '*.sls' -exec sed -i 's/(load-shared-object [^)]*)/(void)/g' {} +" jerboa-stage))
 ;; Delete pre-compiled .so/.wpo files to force recompilation from patched sources
 (system (format "find '~a' -name '*.so' -delete" jerboa-stage))
 (system (format "find '~a' -name '*.wpo' -delete" jerboa-stage))
 
 (printf "  Patched jerboa sources staged in ~a~n" jerboa-stage)
 
-;; ========== Step 1: Compile all secmon modules ==========
+;; ========== Override library-directories ==========
+;; CRITICAL: Use ONLY the stage dir for jerboa, NOT the original.
+;; The original jerboa dir has unpatched load-shared-object calls that would
+;; fail during compilation (no .so to dlopen in static builds).
+;; We set this globally so ALL compilation steps use the right paths.
 
-(printf "~n[1/7] Compiling secmon modules...~n")
+(define build-lib-dirs
+  (list (cons "lib" "lib")
+        (cons jerboa-stage jerboa-stage)))
+
+;; ========== Step 1: Compile jerboa boot modules from staged sources ==========
+
+(printf "~n[1/7] Compiling jerboa modules (patched, from stage)...~n")
+
+(define jerboa-boot-modules
+  '("jerboa/core" "jerboa/runtime"
+    "std/error" "std/format" "std/sort" "std/pregexp" "std/sugar"
+    "std/misc/string" "std/misc/list" "std/misc/alist" "std/misc/thread"
+    "std/misc/ports"
+    "std/foreign"
+    "std/os/path" "std/os/file-info"
+    "std/text/hex" "std/text/json"
+    "std/match2"
+    "std/crypto/native-rust"
+    "std/db/sqlite-native"
+    "std/gambit-compat"
+    "jerboa/ffi"
+    "jerboa/prelude/clean"))
+
+(parameterize ([compile-imported-libraries #t]
+               [optimize-level 2]
+               [generate-inspector-information #f]
+               [library-directories build-lib-dirs])
+  (for-each
+    (lambda (m)
+      (let ([sls (format "~a/~a.sls" jerboa-stage m)])
+        (when (file-exists? sls)
+          (printf "  Compiling ~a~n" m)
+          (compile-library sls))))
+    jerboa-boot-modules))
+
+;; ========== Step 2: Compile all secmon modules ==========
+
+(printf "~n[2/7] Compiling secmon modules...~n")
 
-;; Use the staged (patched) jerboa as primary library path
 (parameterize ([optimize-level 2]
                [generate-inspector-information #f]
                [compile-imported-libraries #t]
-               [library-directories
-                 (cons (cons jerboa-stage jerboa-stage)
-                       (library-directories))])
+               [library-directories build-lib-dirs])
   ;; Crypto modules (dependency order)
   (for-each
     (lambda (m)
@@ -142,9 +182,9 @@
         (compile-library path)))
     '("anti-debug" "masquerade" "env-sanitize" "integrity" "init")))
 
-;; ========== Step 2: Compile agent program ==========
+;; ========== Step 3: Compile agent program ==========
 
-(printf "~n[2/7] Compiling bin/agent.ss (optimize-level 3)...~n")
+(printf "~n[3/7] Compiling bin/agent.ss (optimize-level 3)...~n")
 
 (parameterize ([compile-imported-libraries #t]
                [optimize-level 3]
@@ -157,63 +197,37 @@
                [enable-arithmetic-left-associative #t]
                [debug-level 0]
                [generate-inspector-information #f]
-               [library-directories
-                 (cons (cons jerboa-stage jerboa-stage)
-                       (library-directories))])
+               [library-directories build-lib-dirs])
   (compile-program "bin/agent.ss"))
 
-;; ========== Step 3: Pre-compile boot-file dependencies ==========
-;; Ensure all jerboa std modules used by secmon are compiled
-
-(printf "~n[3/7] Pre-compiling boot file dependencies...~n")
-
-(define jerboa-boot-modules
-  '("jerboa/core" "jerboa/runtime"
-    "std/error" "std/format" "std/sort" "std/pregexp" "std/sugar"
-    "std/misc/string" "std/misc/list" "std/misc/alist" "std/misc/thread"
-    "std/foreign"
-    "std/os/path" "std/os/file-info"
-    "std/crypto/native-rust"
-    "std/db/sqlite-native"
-    "std/gambit-compat"))
-
-(parameterize ([compile-imported-libraries #t]
-               [optimize-level 2]
-               [generate-inspector-information #f]
-               [library-directories
-                 (cons (cons jerboa-stage jerboa-stage)
-                       (library-directories))])
-  (for-each
-    (lambda (m)
-      (let ([sls (format "~a/~a.sls" jerboa-stage m)]
-            [so  (format "~a/~a.so" jerboa-stage m)])
-        (when (and (file-exists? sls) (not (file-exists? so)))
-          (printf "  Pre-compiling ~a~n" sls)
-          (compile-library sls))))
-    jerboa-boot-modules))
-
 ;; ========== Step 4: Create libs-only boot file ==========
 
 (printf "~n[4/7] Creating boot file...~n")
 
 (define boot-libs
   (append
-    ;; Jerboa runtime + stdlib
+    ;; Jerboa runtime + stdlib (from STAGE dir — patched, no load-shared-object)
     (map (lambda (m) (format "~a/~a.so" jerboa-stage m))
       '("jerboa/core"
         "jerboa/runtime"
+        "jerboa/ffi"
+        "jerboa/prelude/clean"
         "std/error"
         "std/format"
         "std/sort"
         "std/pregexp"
         "std/sugar"
+        "std/match2"
         "std/misc/string"
         "std/misc/list"
         "std/misc/alist"
         "std/misc/thread"
+        "std/misc/ports"
         "std/foreign"
         "std/os/path"
         "std/os/file-info"
+        "std/text/hex"
+        "std/text/json"
         "std/gambit-compat"
         "std/crypto/native-rust"
         "std/db/sqlite-native"))
@@ -258,7 +272,8 @@
 ;; Generate the C source
 (call-with-output-file "secmon-program.c"
   (lambda (out)
-    ;; Headers
+    ;; Headers — _GNU_SOURCE must come before any includes for memfd_create
+    (display "#define _GNU_SOURCE\n" out)
     (display "#include \"scheme.h\"\n" out)
     (display "#include <string.h>\n" out)
     (display "#include <stdlib.h>\n" out)
@@ -266,6 +281,7 @@
     (display "#include <signal.h>\n" out)
     (display "#include <unistd.h>\n" out)
     (display "#include <errno.h>\n" out)
+    (display "#include <fcntl.h>\n" out)
     (display "#include <sys/types.h>\n" out)
     (display "#include <sys/socket.h>\n" out)
     (display "#include <sys/wait.h>\n" out)
@@ -331,8 +347,7 @@
         "getpid" "getppid" "prctl" "mlockall"
         "readlink" "unsetenv" "access"
         "__errno_location"
-        "read" "write" "close" "open"
-        "memfd_create"))
+        "read" "write" "close"))
     ;; Rust native symbols
     (for-each
       (lambda (sym)
@@ -386,31 +401,32 @@
     (display "    return \"dlopen not supported in static build\";\n" out)
     (display "}\n\n" out)
 
-    ;; memfd_create stub if not available
-    (display "#ifndef __NR_memfd_create\n" out)
-    (display "#define __NR_memfd_create 319\n" out)
-    (display "#endif\n\n" out)
+    ;; _dl_find_object — referenced by libgcc_eh.a unwinding code (from Rust static lib)
+    ;; Not available in musl; stub returns failure (unwinding falls back to frame pointers)
+    (display "int _dl_find_object(void *a, void *b) { (void)a; (void)b; return -1; }\n\n" out)
 
     ;; Main function: bootstrap Chez and run the agent
     ;; Uses Sscheme_script for threading support (unlike Sscheme_program
     ;; which evaluates at heap build time before threads are ready)
     (display "int main(int argc, const char *argv[]) {\n" out)
     (display "    Sscheme_init(NULL);\n" out)
-    (display "    register_ffi_symbols();\n\n" out)
     (display "    Sregister_boot_file_bytes(\"petite\", petite_boot, petite_boot_len);\n" out)
     (display "    Sregister_boot_file_bytes(\"scheme\", scheme_boot, scheme_boot_len);\n" out)
-    (display "    Sregister_boot_file_bytes(\"app\", app_boot, app_boot_len);\n\n" out)
-    (display "    Sbuild_heap(argv[0], NULL);\n\n" out)
+    (display "    Sregister_boot_file_bytes(\"secmon\", app_boot, app_boot_len);\n" out)
+    (display "    Sbuild_heap(NULL, NULL);\n\n" out)
+    (display "    /* Register FFI symbols after heap is built */\n" out)
+    (display "    register_ffi_symbols();\n\n" out)
     ;; Write program .so to a temp memfd and load via Sscheme_script
     ;; This allows the program to run with threading support
     (display "    /* Load program via memfd for threading support */\n" out)
-    (display "    int fd = memfd_create(\"secmon\", MFD_CLOEXEC);\n" out)
+    (display "    int fd = memfd_create(\"secmon\", 1 /* MFD_CLOEXEC */);\n" out)
     (display "    if (fd < 0) { fd = memfd_create(\"secmon\", 0); }\n" out)
     (display "    if (fd >= 0) {\n" out)
     (display "        write(fd, program_so, program_so_len);\n" out)
     (display "        char fdpath[64];\n" out)
     (display "        snprintf(fdpath, sizeof(fdpath), \"/proc/self/fd/%d\", fd);\n" out)
-    (display "        Sscheme_script(fdpath);\n" out)
+    (display "        const char *script_args[] = { argv[0] };\n" out)
+    (display "        Sscheme_script(fdpath, 1, script_args);\n" out)
     (display "        close(fd);\n" out)
     (display "    } else {\n" out)
     (display "        /* Fallback: write to /tmp */\n" out)
@@ -418,7 +434,8 @@
     (display "        if (f) {\n" out)
     (display "            fwrite(program_so, 1, program_so_len, f);\n" out)
     (display "            fclose(f);\n" out)
-    (display "            Sscheme_script(\"/tmp/.secmon-program.so\");\n" out)
+    (display "            const char *script_args[] = { argv[0] };\n" out)
+    (display "            Sscheme_script(\"/tmp/.secmon-program.so\", 1, script_args);\n" out)
     (display "            unlink(\"/tmp/.secmon-program.so\");\n" out)
     (display "        }\n" out)
     (display "    }\n\n" out)
diff --git a/patches/jerboa-native-rs/Cargo.lock b/patches/jerboa-native-rs/Cargo.lock
new file mode 100644
index 0000000..c306761
--- /dev/null
+++ b/patches/jerboa-native-rs/Cargo.lock
@@ -0,0 +1,1402 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "ahash"
+version = "0.8.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "base64ct"
+version = "1.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
+
+[[package]]
+name = "bitflags"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.20.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "bytes"
+version = "1.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
+
+[[package]]
+name = "cc"
+version = "1.2.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cipher"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
+dependencies = [
+ "crypto-common",
+ "inout",
+]
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "4.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "curve25519-dalek-derive",
+ "fiat-crypto",
+ "rustc_version",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "curve25519-dalek-derive"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "deranged"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
+dependencies = [
+ "powerfmt",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
+[[package]]
+name = "fallible-iterator"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
+
+[[package]]
+name = "fallible-streaming-iterator"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
+
+[[package]]
+name = "fiat-crypto"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "flate2"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d"
+
+[[package]]
+name = "futures-sink"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893"
+
+[[package]]
+name = "futures-task"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393"
+
+[[package]]
+name = "futures-util"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "futures-task",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashlink"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
+dependencies = [
+ "hashbrown",
+]
+
+[[package]]
+name = "hkdf"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
+dependencies = [
+ "hmac",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
+[[package]]
+name = "inotify"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd5b3eaf1a28b758ac0faa5a4254e8ab2705605496f1b1f3fbbc3988ad73d199"
+dependencies = [
+ "bitflags",
+ "inotify-sys",
+ "libc",
+]
+
+[[package]]
+name = "inotify-sys"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "inout"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "jerboa-native"
+version = "0.1.0"
+dependencies = [
+ "flate2",
+ "hkdf",
+ "inotify",
+ "libc",
+ "postgres",
+ "rcgen",
+ "regex",
+ "ring",
+ "rusqlite",
+ "rustls",
+ "rustls-pemfile",
+ "rustls-pki-types",
+ "scrypt",
+ "sha2",
+ "time",
+ "webpki-roots 0.26.11",
+ "x25519-dalek",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.91"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.183"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
+
+[[package]]
+name = "libredox"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "libsqlite3-sys"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
+dependencies = [
+ "cc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+
+[[package]]
+name = "md-5"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
+dependencies = [
+ "cfg-if",
+ "digest",
+]
+
+[[package]]
+name = "memchr"
+version = "2.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+ "simd-adler32",
+]
+
+[[package]]
+name = "mio"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
+dependencies = [
+ "libc",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "num-conv"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
+
+[[package]]
+name = "objc2-core-foundation"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "objc2-system-configuration"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7216bd11cbda54ccabcab84d523dc93b858ec75ecfb3a7d89513fa22464da396"
+dependencies = [
+ "objc2-core-foundation",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "password-hash"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"
+dependencies = [
+ "base64ct",
+ "rand_core 0.6.4",
+ "subtle",
+]
+
+[[package]]
+name = "pbkdf2"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
+dependencies = [
+ "digest",
+ "hmac",
+]
+
+[[package]]
+name = "pem"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be"
+dependencies = [
+ "base64",
+ "serde_core",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
+
+[[package]]
+name = "phf"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
+dependencies = [
+ "phf_shared",
+ "serde",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
+name = "postgres"
+version = "0.19.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7c48ece1c6cda0db61b058c1721378da76855140e9214339fa1317decacb176"
+dependencies = [
+ "bytes",
+ "fallible-iterator 0.2.0",
+ "futures-util",
+ "log",
+ "tokio",
+ "tokio-postgres",
+]
+
+[[package]]
+name = "postgres-protocol"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ee9dd5fe15055d2b6806f4736aa0c9637217074e224bbec46d4041b91bb9491"
+dependencies = [
+ "base64",
+ "byteorder",
+ "bytes",
+ "fallible-iterator 0.2.0",
+ "hmac",
+ "md-5",
+ "memchr",
+ "rand",
+ "sha2",
+ "stringprep",
+]
+
+[[package]]
+name = "postgres-types"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54b858f82211e84682fecd373f68e1ceae642d8d751a1ebd13f33de6257b3e20"
+dependencies = [
+ "bytes",
+ "fallible-iterator 0.2.0",
+ "postgres-protocol",
+]
+
+[[package]]
+name = "powerfmt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
+dependencies = [
+ "rand_chacha",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.9.5",
+]
+
+[[package]]
+name = "rand_core"