Locy Use Case: Compliance Remediation (Rust)¶
Compute exposed + vulnerable services and emit prioritized remediation actions.
This notebook uses schema-first mode and mirrors the Python flow using the Rust API (uni_db).
How To Read This Notebook¶
- Define schema first, then load data.
- Keep Locy rules declarative and focused.
- Read output rows together with materialization stats.
1) Setup¶
Initialize an in-memory database and import DataType for schema definitions.
In [ ]:
Copied!
use uni_db::{DataType, Uni, Result};
let db = Uni::in_memory().build().await?;
use uni_db::{DataType, Uni, Result};
let db = Uni::in_memory().build().await?;
2) Define Schema (Recommended)¶
Define labels, typed properties, and edge types before inserting graph facts.
In [ ]:
Copied!
db.schema()
.label("Internet")
.property("name", DataType::String)
.label("Service")
.property("name", DataType::String)
.property("cve_score", DataType::Float64)
.edge_type("EXPOSES", &["Internet"], &["Service"])
.edge_type("DEPENDS_ON", &["Service"], &["Service"])
.apply()
.await?;
println!("Schema created");
db.schema()
.label("Internet")
.property("name", DataType::String)
.label("Service")
.property("name", DataType::String)
.property("cve_score", DataType::Float64)
.edge_type("EXPOSES", &["Internet"], &["Service"])
.edge_type("DEPENDS_ON", &["Service"], &["Service"])
.apply()
.await?;
println!("Schema created");
3) Seed Graph Data¶
Insert the minimal graph needed for the scenario.
In [ ]:
Copied!
db.execute("CREATE (:Internet {name: 'public'})").await?;
db.execute("CREATE (:Service {name: 'api', cve_score: 9.1})").await?;
db.execute("CREATE (:Service {name: 'worker', cve_score: 4.0})").await?;
db.execute("CREATE (:Service {name: 'db', cve_score: 8.4})").await?;
db.execute("MATCH (i:Internet {name:'public'}), (s:Service {name:'api'}) CREATE (i)-[:EXPOSES]->(s)").await?;
db.execute("MATCH (a:Service {name:'api'}), (w:Service {name:'worker'}) CREATE (a)-[:DEPENDS_ON]->(w)").await?;
db.execute("MATCH (w:Service {name:'worker'}), (d:Service {name:'db'}) CREATE (w)-[:DEPENDS_ON]->(d)").await?;
println!("Seeded graph data");
db.execute("CREATE (:Internet {name: 'public'})").await?;
db.execute("CREATE (:Service {name: 'api', cve_score: 9.1})").await?;
db.execute("CREATE (:Service {name: 'worker', cve_score: 4.0})").await?;
db.execute("CREATE (:Service {name: 'db', cve_score: 8.4})").await?;
db.execute("MATCH (i:Internet {name:'public'}), (s:Service {name:'api'}) CREATE (i)-[:EXPOSES]->(s)").await?;
db.execute("MATCH (a:Service {name:'api'}), (w:Service {name:'worker'}) CREATE (a)-[:DEPENDS_ON]->(w)").await?;
db.execute("MATCH (w:Service {name:'worker'}), (d:Service {name:'db'}) CREATE (w)-[:DEPENDS_ON]->(d)").await?;
println!("Seeded graph data");
4) Locy Program¶
Rules derive relations, then QUERY ... WHERE ... RETURN ... projects the final answer.
In [ ]:
Copied!
let program = r#"CREATE RULE depends_on AS\nMATCH (a:Service)-[:DEPENDS_ON]->(b:Service)\nYIELD KEY a, KEY b\n\nCREATE RULE depends_on AS\nMATCH (a:Service)-[:DEPENDS_ON]->(mid:Service)\nWHERE mid IS depends_on TO b\nYIELD KEY a, KEY b\n\nCREATE RULE exposed AS\nMATCH (i:Internet)-[:EXPOSES]->(s:Service)\nYIELD KEY s\n\nCREATE RULE exposed AS\nMATCH (i:Internet)-[:EXPOSES]->(entry:Service)\nWHERE entry IS depends_on TO s\nYIELD KEY s\n\nCREATE RULE vulnerable AS\nMATCH (s:Service)\nWHERE s.cve_score >= 7\nYIELD KEY s\n\nCREATE RULE non_compliant AS\nMATCH (s:Service)\nWHERE s IS vulnerable, s IS exposed\nYIELD KEY s, 'patch-now' AS action\n\nQUERY non_compliant WHERE s.name = s.name RETURN s.name AS service, action"#;
let program = r#"CREATE RULE depends_on AS\nMATCH (a:Service)-[:DEPENDS_ON]->(b:Service)\nYIELD KEY a, KEY b\n\nCREATE RULE depends_on AS\nMATCH (a:Service)-[:DEPENDS_ON]->(mid:Service)\nWHERE mid IS depends_on TO b\nYIELD KEY a, KEY b\n\nCREATE RULE exposed AS\nMATCH (i:Internet)-[:EXPOSES]->(s:Service)\nYIELD KEY s\n\nCREATE RULE exposed AS\nMATCH (i:Internet)-[:EXPOSES]->(entry:Service)\nWHERE entry IS depends_on TO s\nYIELD KEY s\n\nCREATE RULE vulnerable AS\nMATCH (s:Service)\nWHERE s.cve_score >= 7\nYIELD KEY s\n\nCREATE RULE non_compliant AS\nMATCH (s:Service)\nWHERE s IS vulnerable, s IS exposed\nYIELD KEY s, 'patch-now' AS action\n\nQUERY non_compliant WHERE s.name = s.name RETURN s.name AS service, action"#;
5) Evaluate¶
Evaluate the Locy program and inspect stats/rows.
In [ ]:
Copied!
let result = db.locy().evaluate(program).await?;
println!("Derived relations: {:?}", result.derived.keys().collect::<Vec<_>>());
println!("Iterations: {}", result.stats().total_iterations);
println!("Queries executed: {}", result.stats().queries_executed);
for (name, rows) in &result.derived {
println!("{}: {} row(s)", name, rows.len());
}
if let Some(rows) = result.rows() {
println!("Rows: {:?}", rows);
}
let result = db.locy().evaluate(program).await?;
println!("Derived relations: {:?}", result.derived.keys().collect::>());
println!("Iterations: {}", result.stats().total_iterations);
println!("Queries executed: {}", result.stats().queries_executed);
for (name, rows) in &result.derived {
println!("{}: {} row(s)", name, rows.len());
}
if let Some(rows) = result.rows() {
println!("Rows: {:?}", rows);
}
6) What To Expect¶
Use these checks to validate output after evaluation:
non_compliantshould includeapianddb(reachable from internet and CVE >= 7).workershould not appear in remediation rows because its CVE score is below threshold.Queries executedshould be 1 for this program.
Notes¶
- Rust notebooks are included for API parity and learning.
- In this docs build, Rust notebooks are rendered without execution.