diff --git a/.github/workflows/ci-ai.yaml b/.github/workflows/ci-ai.yaml index 8dfaf85ec..22757b112 100644 --- a/.github/workflows/ci-ai.yaml +++ b/.github/workflows/ci-ai.yaml @@ -43,7 +43,7 @@ jobs: ollama serve & ollama pull llama3.1:8b - name: Test - run: cargo test -p trustify-module-fundamental ai:: -- --nocapture + run: 'cargo test -p trustify-module-fundamental ai:: -- --nocapture' env: RUST_LOG: trustify_module_fundamental::ai=info,langchain_rust=info OPENAI_API_KEY: ollama diff --git a/Cargo.lock b/Cargo.lock index 19c59bd8e..5daa68b87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1523,6 +1523,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "coolor" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "691defa50318376447a73ced869862baecfab35f6aabaa91a4cd726b315bfe1a" +dependencies = [ + "crossterm", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1624,6 +1633,45 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "crokey" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520e83558f4c008ac06fa6a86e5c1d4357be6f994cce7434463ebcdaadf47bb1" +dependencies = [ + "crokey-proc_macros", + "crossterm", + "once_cell", + "serde", + "strict", +] + +[[package]] +name = "crokey-proc_macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "370956e708a1ce65fe4ac5bb7185791e0ece7485087f17736d54a23a0895049f" +dependencies = [ + "crossterm", + "proc-macro2", + "quote", + "strict", + "syn 1.0.109", +] + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.13" @@ -3841,6 +3889,29 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" +[[package]] +name = "lazy-regex" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d8e41c97e6bc7ecb552016274b99fbb5d035e8de288c582d9b933af6677bfda" +dependencies = [ + "lazy-regex-proc_macros", + "once_cell", + "regex", +] + +[[package]] +name = "lazy-regex-proc_macros" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e1d8b05d672c53cb9c7b920bbba8783845ae4f0b076e02a3db1d02c81b4163" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.85", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -4269,6 +4340,15 @@ dependencies = [ "rxml", ] +[[package]] +name = "minimad" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c5d708226d186590a7b6d4a9780e2bdda5f689e0d58cd17012a298efd745d2" +dependencies = [ + "once_cell", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -7521,6 +7601,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a8348af2d9fc3258c8733b8d9d8db2e56f54b2363a4b5b81585c7875ed65e65" +[[package]] +name = "strict" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f42444fea5b87a39db4218d9422087e66a85d0e7a0963a439b07bcdf91804006" + [[package]] name = "string_cache" version = "0.8.7" @@ -7817,6 +7903,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "termimad" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cda3a7471f9978706978454c45ef8dda67e9f8f3cdb9319eb2e9323deb6ae62" +dependencies = [ + "coolor", + "crokey", + "crossbeam", + "lazy-regex", + "minimad", + "serde", + "thiserror", + "unicode-width", +] + [[package]] name = "test-context" version = "0.3.0" @@ -8537,6 +8639,7 @@ dependencies = [ "spdx", "spdx-rs", "strum 0.26.3", + "termimad", "test-context", "test-log", "thiserror", diff --git a/modules/fundamental/Cargo.toml b/modules/fundamental/Cargo.toml index 461158e07..b5a7deb73 100644 --- a/modules/fundamental/Cargo.toml +++ b/modules/fundamental/Cargo.toml @@ -68,8 +68,9 @@ tokio-util = { workspace = true } trustify-cvss = { workspace = true } trustify-test-context = { workspace = true } urlencoding = { workspace = true } -walkdir = { workspace = true } +walkdir = { workspace = true } zip = { workspace = true } +termimad = "0.31.0" [[bench]] name = "bench" diff --git a/modules/fundamental/src/ai/endpoints/test.rs b/modules/fundamental/src/ai/endpoints/test.rs index 038456d49..91663d022 100644 --- a/modules/fundamental/src/ai/endpoints/test.rs +++ b/modules/fundamental/src/ai/endpoints/test.rs @@ -23,7 +23,7 @@ async fn configure(ctx: &TrustifyContext) -> anyhow::Result<()> { let app = caller(ctx).await?; let mut req = ChatState::new(); - req.add_human_message("What is the latest version of Trusted Profile Analyzer?".into()); + req.add_human_message("Give me information about the SBOMs available for quarkus reporting its name, SHA and URL.".into()); let request = TestRequest::post() .uri("/api/v1/ai/completions") @@ -36,7 +36,12 @@ async fn configure(ctx: &TrustifyContext) -> anyhow::Result<()> { let result: ChatState = actix_web::test::read_body_json(response).await; log::info!("result: {:?}", result); - assert!(result.messages.last().unwrap().content.contains("37.17.9")); + assert!(result + .messages + .last() + .unwrap() + .content + .contains("quarkus-bom")); Ok(()) } diff --git a/modules/fundamental/src/ai/service/test.rs b/modules/fundamental/src/ai/service/test.rs index 6f45baf62..830fb0fee 100644 --- a/modules/fundamental/src/ai/service/test.rs +++ b/modules/fundamental/src/ai/service/test.rs @@ -37,6 +37,8 @@ pub async fn ingest_fixtures(ctx: &TrustifyContext) -> Result<(), anyhow::Error> ctx.ingest_documents(["osv/RUSTSEC-2021-0079.json", "cve/CVE-2021-32714.json"]) .await?; + ctx.ingest_document("quarkus/v1/quarkus-bom-2.13.8.Final-redhat-00004.json") + .await?; Ok(()) } @@ -70,12 +72,22 @@ async fn completions(ctx: &TrustifyContext) -> Result<(), anyhow::Error> { ingest_fixtures(ctx).await?; let mut req = ChatState::new(); - req.add_human_message("What is the latest version of Trusted Profile Analyzer?".into()); + req.add_human_message( + "Give me information about the SBOMs available for quarkus reporting its name, SHA and URL." + .into(), + ); let result = service.completions(&req, ()).await?; - log::info!("result: {:?}", result); - assert!(result.messages.last().unwrap().content.contains("37.17.9")); + log::info!("result: {:#?}", result); + let last_message_content = result.messages.last().unwrap().content.clone(); + println!( + "Test formatted output:\n\n{}\n", + termimad::inline(last_message_content.as_str()) + ); + assert!(last_message_content.contains("quarkus-bom")); + assert!(last_message_content + .contains("5a370574a991aa42f7ecc5b7d88754b258f81c230a73bea247c0a6fcc6f608ab")); Ok(()) }