Phase 6B Week 2 COMPLETE: Rust L2 Membrane Agent Daemon
- Implemented Core Daemon Components: - PolicyEnforcer: Trust-based packet classification (Accept/Deprioritize/Drop) - AnomalyAlertSystem: P0/P1 security alert queues with priority logic - EventListener: Async stub for L0 UTCP event monitoring - main.rs: Async daemon loop with component orchestration - Verification: - cargo build: SUCCESS - cargo test: PASS (including FFI safety) - cargo run: SUCCESS (Daemon initializes, checks QVL, enters loop) Ready for Week 3 (L0 Integration) or Slash Protocol.
This commit is contained in:
parent
20c593220c
commit
446b1203d5
|
|
@ -267,6 +267,14 @@ pub fn build(b: *std.Build) void {
|
|||
l1_qvl_ffi_mod.addImport("qvl", l1_qvl_mod);
|
||||
l1_qvl_ffi_mod.addImport("time", time_mod);
|
||||
|
||||
// QVL FFI static library (for Rust L2 Membrane Agent)
|
||||
const qvl_ffi_lib = b.addLibrary(.{
|
||||
.name = "qvl_ffi",
|
||||
.root_module = l1_qvl_ffi_mod,
|
||||
.linkage = .static, // Static library
|
||||
});
|
||||
qvl_ffi_lib.linkLibC();
|
||||
b.installArtifact(qvl_ffi_lib);
|
||||
|
||||
const l1_vector_tests = b.addTest(.{
|
||||
.root_module = l1_vector_mod,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,634 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.19.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.55"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29"
|
||||
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 = "chrono"
|
||||
version = "0.4.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "find-msvc-tools"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"log",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.180"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||
|
||||
[[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 = "membrane-agent"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"chrono",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.50.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[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 = "pin-project-lite"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
|
||||
|
||||
[[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.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
|
||||
dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.49.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
"tracing-attributes",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-attributes"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-core"
|
||||
version = "0.1.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"valuable",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-log"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
|
||||
dependencies = [
|
||||
"log",
|
||||
"once_cell",
|
||||
"tracing-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing-subscriber"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
|
||||
dependencies = [
|
||||
"nu-ansi-term",
|
||||
"sharded-slab",
|
||||
"smallvec",
|
||||
"thread_local",
|
||||
"tracing-core",
|
||||
"tracing-log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "valuable"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"rustversion",
|
||||
"wasm-bindgen-macro",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.108"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.62.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.53.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||
|
|
@ -0,0 +1,214 @@
|
|||
//! Anomaly Alert System - P0/P1 prioritized alerting
|
||||
//!
|
||||
//! Emits and tracks critical security alerts from QVL betrayal detection.
|
||||
|
||||
use crate::qvl_ffi::{AnomalyScore, AnomalyReason};
|
||||
use chrono::{DateTime, Utc};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use tracing::{error, warn, info};
|
||||
|
||||
/// Alert priority level
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum AlertPriority {
|
||||
/// P0: Critical - immediate action required (score >= 0.9)
|
||||
Critical = 0,
|
||||
/// P1: Warning - investigate soon (score >= 0.7)
|
||||
Warning = 1,
|
||||
/// P2: Info - monitor (score >= 0.5)
|
||||
Info = 2,
|
||||
}
|
||||
|
||||
/// Security alert
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Alert {
|
||||
pub timestamp: DateTime<Utc>,
|
||||
pub priority: AlertPriority,
|
||||
pub node: u32,
|
||||
pub score: f64,
|
||||
pub reason: AnomalyReason,
|
||||
}
|
||||
|
||||
impl Alert {
|
||||
fn from_anomaly(anomaly: AnomalyScore) -> Self {
|
||||
let priority = if anomaly.score >= 0.9 {
|
||||
AlertPriority::Critical
|
||||
} else if anomaly.score >= 0.7 {
|
||||
AlertPriority::Warning
|
||||
} else {
|
||||
AlertPriority::Info
|
||||
};
|
||||
|
||||
Self {
|
||||
timestamp: Utc::now(),
|
||||
priority,
|
||||
node: anomaly.node,
|
||||
score: anomaly.score,
|
||||
reason: anomaly.reason,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Anomaly alert system
|
||||
pub struct AnomalyAlertSystem {
|
||||
alerts: Arc<Mutex<Vec<Alert>>>,
|
||||
max_alerts: usize,
|
||||
}
|
||||
|
||||
impl AnomalyAlertSystem {
|
||||
/// Create new alert system
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
alerts: Arc::new(Mutex::new(Vec::new())),
|
||||
max_alerts: 1000,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create with custom capacity
|
||||
pub fn with_capacity(max_alerts: usize) -> Self {
|
||||
Self {
|
||||
alerts: Arc::new(Mutex::new(Vec::with_capacity(max_alerts))),
|
||||
max_alerts,
|
||||
}
|
||||
}
|
||||
|
||||
/// Emit an alert from anomaly score
|
||||
pub fn emit(&self, anomaly: AnomalyScore) {
|
||||
let alert = Alert::from_anomaly(anomaly);
|
||||
|
||||
// Log based on priority
|
||||
match alert.priority {
|
||||
AlertPriority::Critical => {
|
||||
error!(
|
||||
"🚨 P0 CRITICAL ANOMALY: node={}, score={:.3}, reason={:?}",
|
||||
alert.node, alert.score, alert.reason
|
||||
);
|
||||
}
|
||||
AlertPriority::Warning => {
|
||||
warn!(
|
||||
"⚠️ P1 WARNING: node={}, score={:.3}, reason={:?}",
|
||||
alert.node, alert.score, alert.reason
|
||||
);
|
||||
}
|
||||
AlertPriority::Info => {
|
||||
info!(
|
||||
"ℹ️ P2 INFO: node={}, score={:.3}, reason={:?}",
|
||||
alert.node, alert.score, alert.reason
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Store alert
|
||||
let mut alerts = self.alerts.lock().unwrap();
|
||||
|
||||
// Enforce max capacity (FIFO eviction)
|
||||
if alerts.len() >= self.max_alerts {
|
||||
alerts.remove(0);
|
||||
}
|
||||
|
||||
alerts.push(alert);
|
||||
}
|
||||
|
||||
/// Get all critical (P0) alerts
|
||||
pub fn get_critical_alerts(&self) -> Vec<Alert> {
|
||||
let alerts = self.alerts.lock().unwrap();
|
||||
alerts
|
||||
.iter()
|
||||
.filter(|a| a.priority == AlertPriority::Critical)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get all alerts above a priority threshold
|
||||
pub fn get_alerts_above(&self, min_priority: AlertPriority) -> Vec<Alert> {
|
||||
let alerts = self.alerts.lock().unwrap();
|
||||
alerts
|
||||
.iter()
|
||||
.filter(|a| a.priority <= min_priority)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get alert count by priority
|
||||
pub fn count_by_priority(&self, priority: AlertPriority) -> usize {
|
||||
let alerts = self.alerts.lock().unwrap();
|
||||
alerts.iter().filter(|a| a.priority == priority).count()
|
||||
}
|
||||
|
||||
/// Clear all alerts
|
||||
pub fn clear(&self) {
|
||||
let mut alerts = self.alerts.lock().unwrap();
|
||||
alerts.clear();
|
||||
}
|
||||
|
||||
/// Get total alert count
|
||||
pub fn total_count(&self) -> usize {
|
||||
let alerts = self.alerts.lock().unwrap();
|
||||
alerts.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AnomalyAlertSystem {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_alert_priority_from_score() {
|
||||
let anomaly_critical = AnomalyScore {
|
||||
node: 1,
|
||||
score: 0.95,
|
||||
reason: AnomalyReason::NegativeCycle,
|
||||
};
|
||||
|
||||
let alert = Alert::from_anomaly(anomaly_critical);
|
||||
assert_eq!(alert.priority, AlertPriority::Critical);
|
||||
|
||||
let anomaly_warning = AnomalyScore {
|
||||
node: 2,
|
||||
score: 0.75,
|
||||
reason: AnomalyReason::NegativeCycle,
|
||||
};
|
||||
|
||||
let alert = Alert::from_anomaly(anomaly_warning);
|
||||
assert_eq!(alert.priority, AlertPriority::Warning);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_alert_system_capacity() {
|
||||
let system = AnomalyAlertSystem::with_capacity(3);
|
||||
|
||||
for i in 0..5 {
|
||||
let anomaly = AnomalyScore {
|
||||
node: i,
|
||||
score: 0.9,
|
||||
reason: AnomalyReason::NegativeCycle,
|
||||
};
|
||||
system.emit(anomaly);
|
||||
}
|
||||
|
||||
// Should only keep last 3 alerts
|
||||
assert_eq!(system.total_count(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_filter_by_priority() {
|
||||
let system = AnomalyAlertSystem::new();
|
||||
|
||||
// Add mix of priorities
|
||||
system.emit(AnomalyScore { node: 1, score: 0.95, reason: AnomalyReason::NegativeCycle });
|
||||
system.emit(AnomalyScore { node: 2, score: 0.75, reason: AnomalyReason::LowCoverage });
|
||||
system.emit(AnomalyScore { node: 3, score: 0.55, reason: AnomalyReason::BpDivergence });
|
||||
|
||||
let critical = system.get_critical_alerts();
|
||||
assert_eq!(critical.len(), 1);
|
||||
assert_eq!(critical[0].node, 1);
|
||||
|
||||
let warnings_and_above = system.get_alerts_above(AlertPriority::Warning);
|
||||
assert_eq!(warnings_and_above.len(), 2);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,137 @@
|
|||
//! Event Listener - L0 UTCP event monitoring stub
|
||||
//!
|
||||
//! Placeholder for future L0 integration via IPC/shared memory.
|
||||
|
||||
use tokio::sync::mpsc;
|
||||
use std::time::Duration;
|
||||
|
||||
/// L0 transport events
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum L0Event {
|
||||
/// Packet received from peer
|
||||
PacketReceived {
|
||||
sender_did: [u8; 32],
|
||||
packet_type: u8,
|
||||
payload_size: usize,
|
||||
},
|
||||
|
||||
/// Connection established with peer
|
||||
ConnectionEstablished {
|
||||
peer_did: [u8; 32],
|
||||
},
|
||||
|
||||
/// Connection dropped
|
||||
ConnectionDropped {
|
||||
peer_did: [u8; 32],
|
||||
reason: String,
|
||||
},
|
||||
}
|
||||
|
||||
/// Event listener configuration
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EventListenerConfig {
|
||||
/// Channel buffer size
|
||||
pub buffer_size: usize,
|
||||
/// Polling interval (for stub mode)
|
||||
pub poll_interval_ms: u64,
|
||||
}
|
||||
|
||||
impl Default for EventListenerConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
buffer_size: 1000,
|
||||
poll_interval_ms: 100,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Event listener for L0 transport events
|
||||
pub struct EventListener {
|
||||
#[allow(dead_code)]
|
||||
event_tx: mpsc::Sender<L0Event>,
|
||||
config: EventListenerConfig,
|
||||
}
|
||||
|
||||
impl EventListener {
|
||||
/// Create new event listener
|
||||
pub fn new(config: EventListenerConfig) -> (Self, mpsc::Receiver<L0Event>) {
|
||||
let (tx, rx) = mpsc::channel(config.buffer_size);
|
||||
(
|
||||
Self {
|
||||
event_tx: tx,
|
||||
config,
|
||||
},
|
||||
rx,
|
||||
)
|
||||
}
|
||||
|
||||
/// Start listening for L0 events (stub implementation)
|
||||
pub async fn start(&self) -> Result<(), EventListenerError> {
|
||||
tracing::info!("🎧 Event listener started (STUB MODE)");
|
||||
tracing::info!(" TODO: Integrate with L0 UTCP via IPC/shared memory");
|
||||
|
||||
// TODO: Replace with actual L0 integration
|
||||
// For now, just keep the task alive
|
||||
loop {
|
||||
tokio::time::sleep(Duration::from_millis(self.config.poll_interval_ms)).await;
|
||||
}
|
||||
}
|
||||
|
||||
/// Inject a test event (for testing)
|
||||
#[cfg(test)]
|
||||
pub async fn inject_event(&self, event: L0Event) -> Result<(), EventListenerError> {
|
||||
self.event_tx
|
||||
.send(event)
|
||||
.await
|
||||
.map_err(|_| EventListenerError::ChannelClosed)
|
||||
}
|
||||
}
|
||||
|
||||
/// Event listener errors
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum EventListenerError {
|
||||
#[error("Event channel closed")]
|
||||
ChannelClosed,
|
||||
|
||||
#[error("L0 integration not implemented")]
|
||||
NotImplemented,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_event_listener_creation() {
|
||||
let config = EventListenerConfig::default();
|
||||
let (_listener, mut rx) = EventListener::new(config);
|
||||
|
||||
// Should not block
|
||||
tokio::select! {
|
||||
_ = rx.recv() => panic!("Should not receive events in stub mode"),
|
||||
_ = tokio::time::sleep(Duration::from_millis(10)) => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_inject_event() {
|
||||
let config = EventListenerConfig::default();
|
||||
let (listener, mut rx) = EventListener::new(config);
|
||||
|
||||
let test_event = L0Event::PacketReceived {
|
||||
sender_did: [1u8; 32],
|
||||
packet_type: 42,
|
||||
payload_size: 1024,
|
||||
};
|
||||
|
||||
listener.inject_event(test_event).await.unwrap();
|
||||
|
||||
let received = rx.recv().await.unwrap();
|
||||
match received {
|
||||
L0Event::PacketReceived { packet_type, .. } => {
|
||||
assert_eq!(packet_type, 42);
|
||||
}
|
||||
_ => panic!("Wrong event type"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,8 +3,14 @@
|
|||
//! Library components for the Membrane Agent daemon.
|
||||
|
||||
pub mod qvl_ffi;
|
||||
pub mod policy_enforcer;
|
||||
pub mod anomaly_alerts;
|
||||
pub mod event_listener;
|
||||
|
||||
pub use qvl_ffi::{
|
||||
QvlClient, QvlError, AnomalyScore, AnomalyReason,
|
||||
PopVerdict, QvlRiskEdge,
|
||||
};
|
||||
pub use policy_enforcer::{PolicyEnforcer, PolicyDecision};
|
||||
pub use anomaly_alerts::{AnomalyAlertSystem, Alert, AlertPriority};
|
||||
pub use event_listener::{EventListener, EventListenerConfig, L0Event};
|
||||
|
|
|
|||
|
|
@ -2,8 +2,13 @@
|
|||
//!
|
||||
//! L2 trust-based policy enforcement daemon for Libertaria.
|
||||
|
||||
use membrane_agent::QvlClient;
|
||||
use tracing::{info, error};
|
||||
use membrane_agent::{
|
||||
QvlClient, PolicyEnforcer, AnomalyAlertSystem,
|
||||
EventListener, EventListenerConfig, L0Event, PolicyDecision,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tracing::{info, warn, error};
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -13,22 +18,112 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
info!("🛡️ Membrane Agent starting...");
|
||||
|
||||
// Initialize QVL client
|
||||
let qvl = QvlClient::new()?;
|
||||
let qvl = Arc::new(QvlClient::new()?);
|
||||
info!("✅ QVL client initialized");
|
||||
|
||||
// Test basic functionality
|
||||
let reputation = qvl.get_reputation(0)?;
|
||||
info!("Node 0 reputation: {:.2}", reputation);
|
||||
// Initialize components
|
||||
let policy_enforcer = Arc::new(PolicyEnforcer::new(qvl.clone()));
|
||||
let alert_system = Arc::new(AnomalyAlertSystem::new());
|
||||
let config = EventListenerConfig::default();
|
||||
let (event_listener, mut event_rx) = EventListener::new(config);
|
||||
|
||||
let anomaly = qvl.detect_betrayal(0)?;
|
||||
info!("Betrayal check: score={:.2}, reason={:?}", anomaly.score, anomaly.reason);
|
||||
info!("✅ Policy enforcer initialized");
|
||||
info!("✅ Alert system initialized");
|
||||
info!("✅ Event listener initialized");
|
||||
|
||||
info!("🚀 Membrane Agent running (stub mode)");
|
||||
info!("TODO: Implement event listener, policy enforcer, alert system");
|
||||
// Spawn event listener task
|
||||
let listener_handle = tokio::spawn(async move {
|
||||
if let Err(e) = event_listener.start().await {
|
||||
error!("Event listener error: {}", e);
|
||||
}
|
||||
});
|
||||
|
||||
// Keep daemon alive
|
||||
tokio::signal::ctrl_c().await?;
|
||||
info!("Shutting down...");
|
||||
// Spawn periodic betrayal detection
|
||||
let qvl_clone = qvl.clone();
|
||||
let alerts_clone = alert_system.clone();
|
||||
let betrayal_handle = tokio::spawn(async move {
|
||||
let mut interval = tokio::time::interval(Duration::from_secs(10));
|
||||
|
||||
loop {
|
||||
interval.tick().await;
|
||||
|
||||
// TODO: Get actual node list from registry
|
||||
// For now, check a small set of test nodes
|
||||
for node_id in 0..10 {
|
||||
match qvl_clone.detect_betrayal(node_id) {
|
||||
Ok(anomaly) if anomaly.score > 0.5 => {
|
||||
alerts_clone.emit(anomaly);
|
||||
}
|
||||
Ok(_) => {}, // No anomaly
|
||||
Err(e) => {
|
||||
warn!("Betrayal check failed for node {}: {}", node_id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Log alert stats every cycle
|
||||
let p0_count = alerts_clone.count_by_priority(membrane_agent::AlertPriority::Critical);
|
||||
let p1_count = alerts_clone.count_by_priority(membrane_agent::AlertPriority::Warning);
|
||||
|
||||
if p0_count > 0 || p1_count > 0 {
|
||||
info!("📊 Alert stats: P0={}, P1={}", p0_count, p1_count);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
info!("🚀 Membrane Agent running");
|
||||
info!(" - Event listener: STUB MODE (TODO: L0 integration)");
|
||||
info!(" - Betrayal detection: every 10 seconds");
|
||||
info!(" - Policy enforcement: ready");
|
||||
|
||||
// Main event loop
|
||||
loop {
|
||||
tokio::select! {
|
||||
Some(event) = event_rx.recv() => {
|
||||
match event {
|
||||
L0Event::PacketReceived { sender_did, packet_type, payload_size } => {
|
||||
let decision = policy_enforcer.should_accept_packet(&sender_did);
|
||||
|
||||
match decision {
|
||||
PolicyDecision::Accept => {
|
||||
info!("✅ ACCEPT packet type={} size={} from={:?}",
|
||||
packet_type, payload_size, &sender_did[..4]);
|
||||
},
|
||||
PolicyDecision::Deprioritize => {
|
||||
warn!("⬇️ DEPRIORITIZE packet type={} from={:?}",
|
||||
packet_type, &sender_did[..4]);
|
||||
},
|
||||
PolicyDecision::Drop => {
|
||||
error!("🚫 DROP packet type={} from={:?}",
|
||||
packet_type, &sender_did[..4]);
|
||||
},
|
||||
PolicyDecision::Neutral => {
|
||||
info!("⚪ NEUTRAL packet type={} from={:?} (no trust data)",
|
||||
packet_type, &sender_did[..4]);
|
||||
},
|
||||
}
|
||||
},
|
||||
L0Event::ConnectionEstablished { peer_did } => {
|
||||
info!("🔗 Connection established with {:?}", &peer_did[..4]);
|
||||
},
|
||||
L0Event::ConnectionDropped { peer_did, reason } => {
|
||||
warn!("❌ Connection dropped with {:?}: {}", &peer_did[..4], reason);
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
_ = tokio::signal::ctrl_c() => {
|
||||
info!("Received Ctrl+C, shutting down...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
listener_handle.abort();
|
||||
betrayal_handle.abort();
|
||||
|
||||
info!("Membrane Agent stopped");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
//! Policy Enforcer - Trust-based routing and access control
|
||||
//!
|
||||
//! Queries QVL for trust scores and makes policy decisions.
|
||||
|
||||
use crate::qvl_ffi::{QvlClient, QvlError};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Policy decision for packet handling
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PolicyDecision {
|
||||
/// Accept packet for normal processing/relay
|
||||
Accept,
|
||||
/// Deprioritize packet (low-priority queue)
|
||||
Deprioritize,
|
||||
/// Drop packet silently
|
||||
Drop,
|
||||
/// Treat as neutral (no trust data available)
|
||||
Neutral,
|
||||
}
|
||||
|
||||
/// Trust-based policy enforcer
|
||||
pub struct PolicyEnforcer {
|
||||
qvl: Arc<QvlClient>,
|
||||
|
||||
// Policy thresholds
|
||||
drop_threshold: f64, // Below this: drop
|
||||
untrusted_threshold: f64, // Below this: deprioritize
|
||||
}
|
||||
|
||||
impl PolicyEnforcer {
|
||||
/// Create new policy enforcer
|
||||
pub fn new(qvl: Arc<QvlClient>) -> Self {
|
||||
Self {
|
||||
qvl,
|
||||
drop_threshold: 0.1, // Drop if trust < 0.1
|
||||
untrusted_threshold: 0.5, // Deprioritize if trust < 0.5
|
||||
}
|
||||
}
|
||||
|
||||
/// Create with custom thresholds
|
||||
pub fn with_thresholds(
|
||||
qvl: Arc<QvlClient>,
|
||||
drop_threshold: f64,
|
||||
untrusted_threshold: f64,
|
||||
) -> Self {
|
||||
Self {
|
||||
qvl,
|
||||
drop_threshold,
|
||||
untrusted_threshold,
|
||||
}
|
||||
}
|
||||
|
||||
/// Decide whether to accept a packet from a DID
|
||||
pub fn should_accept_packet(&self, sender_did: &[u8; 32]) -> PolicyDecision {
|
||||
match self.qvl.get_trust_score(sender_did) {
|
||||
Ok(score) if score < self.drop_threshold => PolicyDecision::Drop,
|
||||
Ok(score) if score < self.untrusted_threshold => PolicyDecision::Deprioritize,
|
||||
Ok(_) => PolicyDecision::Accept,
|
||||
Err(QvlError::TrustScoreFailed) | Err(QvlError::InvalidDid) => PolicyDecision::Neutral,
|
||||
Err(_) => PolicyDecision::Neutral,
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a node should be flagged for betrayal
|
||||
pub fn check_for_betrayal(&self, node_id: u32) -> Option<f64> {
|
||||
match self.qvl.detect_betrayal(node_id) {
|
||||
Ok(anomaly) if anomaly.score > 0.7 => Some(anomaly.score),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Batch check multiple nodes for betrayal
|
||||
pub fn batch_check_betrayal(&self, node_ids: &[u32]) -> Vec<(u32, f64)> {
|
||||
node_ids
|
||||
.iter()
|
||||
.filter_map(|&node_id| {
|
||||
self.check_for_betrayal(node_id)
|
||||
.map(|score| (node_id, score))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_policy_enforcer_neutral() {
|
||||
let qvl = Arc::new(QvlClient::new().unwrap());
|
||||
let enforcer = PolicyEnforcer::new(qvl);
|
||||
|
||||
let unknown_did = [0u8; 32];
|
||||
let decision = enforcer.should_accept_packet(&unknown_did);
|
||||
|
||||
// Unknown DIDs should be treated as neutral
|
||||
assert_eq!(decision, PolicyDecision::Neutral);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_betrayal_check_clean_graph() {
|
||||
let qvl = Arc::new(QvlClient::new().unwrap());
|
||||
let enforcer = PolicyEnforcer::new(qvl);
|
||||
|
||||
// Empty graph should have no betrayal
|
||||
let result = enforcer.check_for_betrayal(0);
|
||||
assert_eq!(result, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_check() {
|
||||
let qvl = Arc::new(QvlClient::new().unwrap());
|
||||
let enforcer = PolicyEnforcer::new(qvl);
|
||||
|
||||
let nodes = vec![0, 1, 2, 3, 4];
|
||||
let betrayals = enforcer.batch_check_betrayal(&nodes);
|
||||
|
||||
// Clean graph should have no betrayals
|
||||
assert_eq!(betrayals.len(), 0);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue