Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix circular deps in analysis graph and add purl migration for get_purl psql func #1012

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions migration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ mod m0000700_advisory_add_reserved;
mod m0000710_create_user_prefs;
mod m0000720_alter_sbom_fix_null_array;
mod m0000730_alter_importer_add_progress;
mod m0000740_ensure_get_purl_fns;

pub struct Migrator;

Expand Down Expand Up @@ -189,6 +190,7 @@ impl MigratorTrait for Migrator {
Box::new(m0000710_create_user_prefs::Migration),
Box::new(m0000720_alter_sbom_fix_null_array::Migration),
Box::new(m0000730_alter_importer_add_progress::Migration),
Box::new(m0000740_ensure_get_purl_fns::Migration),
]
}
}
Expand Down
26 changes: 26 additions & 0 deletions migration/src/m0000740_ensure_get_purl_fns.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use sea_orm_migration::prelude::*;

#[derive(DeriveMigrationName)]
pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.get_connection()
.execute_unprepared(include_str!("m0000740_ensure_get_purl_fns/get_purl.sql"))
.await
.map(|_| ())?;

Ok(())
}

async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
manager
.get_connection()
.execute_unprepared(include_str!("m0000590_get_purl_fns/get_purl.sql"))
.await?;

Ok(())
}
}
33 changes: 33 additions & 0 deletions migration/src/m0000740_ensure_get_purl_fns/get_purl.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
CREATE OR REPLACE FUNCTION get_purl(qualified_purl_id UUID)
RETURNS TEXT AS $$
DECLARE
result TEXT;
BEGIN
SELECT
COALESCE(
'pkg:' || bp.type ||
'/' || COALESCE(bp.namespace, '') || '/' ||
bp.name ||
'@' || vp.version ||
CASE
WHEN qp.qualifiers IS NOT NULL AND qp.qualifiers <> '{}'::jsonb THEN
'?' || (
SELECT string_agg(key || '=' || value, '&')
FROM jsonb_each_text(qp.qualifiers)
)
ELSE
''
END,
qualified_purl_id::text
)
INTO result
FROM
qualified_purl qp
LEFT JOIN versioned_purl vp ON vp.id = qp.versioned_purl_id
LEFT JOIN base_purl bp ON bp.id = vp.base_purl_id
WHERE
qp.id = qualified_purl_id;

RETURN result;
END;
$$ LANGUAGE plpgsql IMMUTABLE PARALLEL SAFE;
1 change: 1 addition & 0 deletions modules/analysis/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ pub struct AncestorSummary {
pub struct DepNode {
pub sbom_id: String,
pub node_id: String,
pub relationship: String,
pub purl: String,
pub name: String,
pub version: String,
Expand Down
33 changes: 20 additions & 13 deletions modules/analysis/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ pub struct AnalysisService {
pub fn dep_nodes(
graph: &petgraph::Graph<PackageNode, Relationship, petgraph::Directed>,
node: NodeIndex,
visited: &mut HashSet<NodeIndex>,
) -> Vec<DepNode> {
let mut depnodes = Vec::new();
let mut visited = HashSet::new();
fn dfs(
graph: &petgraph::Graph<PackageNode, Relationship, petgraph::Directed>,
node: NodeIndex,
Expand All @@ -51,16 +51,23 @@ pub fn dep_nodes(
visited.insert(node);
for neighbor in graph.neighbors_directed(node, Direction::Incoming) {
if let Some(dep_packagenode) = graph.node_weight(neighbor).cloned() {
let dep_node = DepNode {
sbom_id: dep_packagenode.sbom_id,
node_id: dep_packagenode.node_id,
purl: dep_packagenode.purl.to_string(),
name: dep_packagenode.name.to_string(),
version: dep_packagenode.version.to_string(),
deps: Vec::new(), // Avoid recursive call to dep_nodes
};
depnodes.push(dep_node);
dfs(graph, neighbor, depnodes, visited);
// Attempt to find the edge and get the relationship in a more elegant way
if let Some(relationship) = graph
.find_edge(neighbor, node)
.and_then(|edge_index| graph.edge_weight(edge_index))
{
let dep_node = DepNode {
sbom_id: dep_packagenode.sbom_id,
node_id: dep_packagenode.node_id,
relationship: relationship.to_string(),
purl: dep_packagenode.purl.to_string(),
name: dep_packagenode.name.to_string(),
version: dep_packagenode.version.to_string(),
deps: dep_nodes(graph, neighbor, visited),
};
depnodes.push(dep_node);
dfs(graph, neighbor, depnodes, visited);
}
} else {
log::warn!(
"Processing descendants node weight for neighbor {:?} not found",
Expand All @@ -69,7 +76,7 @@ pub fn dep_nodes(
}
}
}
dfs(graph, node, &mut depnodes, &mut visited);
dfs(graph, node, &mut depnodes, visited);
depnodes
}

Expand Down Expand Up @@ -530,7 +537,7 @@ impl AnalysisService {
product_version: find_match_package_node
.product_version
.to_string(),
deps: dep_nodes(graph, node_index),
deps: dep_nodes(graph, node_index, &mut HashSet::new()),
});
}
}
Expand Down
3 changes: 3 additions & 0 deletions openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2457,6 +2457,7 @@ components:
required:
- sbom_id
- node_id
- relationship
- purl
- name
- version
Expand All @@ -2472,6 +2473,8 @@ components:
type: string
purl:
type: string
relationship:
type: string
sbom_id:
type: string
version:
Expand Down