Skip to content
Draft
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
47 changes: 46 additions & 1 deletion scenarios/full-20250604.json5
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,50 @@
"urn:uuid:01973122-3bdd-78a3-898a-fb67c06387ed"
],
"download_advisory": "24ae57c3-4b57-4f4e-82c1-83ae26059a89",
"get_advisory": "24ae57c3-4b57-4f4e-82c1-83ae26059a89"
"get_advisory": "24ae57c3-4b57-4f4e-82c1-83ae26059a89",
"count_by_package": "pkg:generic/redhat/commons-beanutils-commons-beanutils@",
"patch_sbom_lables": [
"urn:uuid:0199413a-8792-7220-9690-aae13ffe6691",
"urn:uuid:0199413b-05e6-77f1-8dff-5c03486296c4",
"urn:uuid:0199413b-0145-7b03-92a9-69c18ff90406",
"urn:uuid:0199413a-f755-76d2-a9e2-8e05f73ef286",
"urn:uuid:0199413b-0d68-70c3-b733-6b4f7e8628ee",
"urn:uuid:0199413b-8389-7b32-91e7-c109400b584b",
"urn:uuid:0199413b-6db5-7162-958a-095039ab032d",
"urn:uuid:0199413c-0319-7231-af5c-1b04b500645c",
"urn:uuid:0199413c-8802-7dc2-8ec2-821ecf33ab36",
"urn:uuid:0199413c-8d8b-7f81-a848-f394c6772167",
"urn:uuid:0199413c-9470-73f1-ae40-69a64c099fe1",
"urn:uuid:0199412f-5359-7cf3-9390-2d1c6294345c",
"urn:uuid:01994138-48fe-7db2-a5eb-74c3e80f3271",
"urn:uuid:0199413a-ff9d-7563-a7aa-e72f5a7272e8",
"urn:uuid:0199413a-c5c7-7ec2-8583-2006df4eda8d",
"urn:uuid:0199413b-3075-7020-826b-cb3eb5a18713",
"urn:uuid:0199413b-386a-70d0-b9c9-e99305bc8c85",
"urn:uuid:0199413b-7f43-7803-bde8-8e8f8d5b299e",
"urn:uuid:0199413b-d18b-7781-8ab0-07cc429a0901",
"urn:uuid:0199413b-e7a2-7c92-8214-52e59375cdc4"
],
"put_sbom_lables": [
"urn:uuid:01994138-3f44-7c41-8879-ad7d7f2013ed",
"urn:uuid:0199412e-b3ec-70d3-aaae-a88e9eb25f92",
"urn:uuid:01994138-4479-7963-9c61-f3367c43b5b8",
"urn:uuid:0199412f-101d-7892-a82f-bdfe8b286ca6",
"urn:uuid:01994133-abd3-7bc3-b1a2-7a2dcae1d428",
"urn:uuid:01994130-62bd-71f2-870e-b1e678394ea2",
"urn:uuid:01994130-17d9-7641-91d2-1c977dd01424",
"urn:uuid:0199412f-c637-7c11-b6d6-b30281445b6d",
"urn:uuid:0199412e-5b37-78a3-b999-256ba95b2139",
"urn:uuid:01994138-f1d2-7dd3-b17a-9fbca167f650",
"urn:uuid:01994139-3448-7ac0-81be-f238be804471",
"urn:uuid:01994138-8ce7-7e40-b51a-3196e8c44aac",
"urn:uuid:0199412f-6f85-7970-ab1f-dfbacddd192b",
"urn:uuid:01994139-6eb1-79d2-b998-4a5bba02104e",
"urn:uuid:01994139-bc49-7521-9d8d-4572f6436451",
"urn:uuid:0199413a-0969-70d1-b54d-5cf687af0511",
"urn:uuid:0199413a-53de-7d91-afcb-708d31473bd6",
"urn:uuid:0199413a-106c-7f71-8de9-427c1fd89ebb",
"urn:uuid:0199413b-0363-7780-95e8-9f7f053710e9",
"urn:uuid:0199413a-6a5d-7853-ab62-c220322590da"
]
}
21 changes: 20 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ async fn main() -> Result<(), anyhow::Error> {
.register_transaction(tx!(list_sboms_paginated))
.register_transaction(tx!(get_analysis_status))
.register_transaction(tx!(get_analysis_latest_cpe))
.register_transaction(tx!(list_advisory_labels));
.register_transaction(tx!(list_advisory_labels))
.register_transaction(tx!(list_sbom_labels));

tx!(s.get_sbom?(scenario.get_sbom.clone()));
tx!(s.get_sbom_advisories?(scenario.get_sbom_advisories.clone()));
Expand All @@ -195,6 +196,24 @@ async fn main() -> Result<(), anyhow::Error> {

tx!(s.download_advisory?(scenario.download_advisory.clone()));
tx!(s.get_advisory?(scenario.get_advisory.clone()));
tx!(s.count_by_package?(scenario.count_by_package.clone()));

// Register put sbom labels transaction if pool is available
let put_sbom_labels_counter = Arc::new(std::sync::atomic::AtomicUsize::new(0));
if let Some(_sbom_ids) = scenario.put_sbom_lables.clone() {
tx!(s.put_sbom_labels?(scenario.put_sbom_lables.clone(),
put_sbom_labels_counter.clone()),
name: format!("put_sbom_labels"));
}

// Register patch sbom labels transaction if pool is available
let patch_sbom_labels_counter = Arc::new(std::sync::atomic::AtomicUsize::new(0));
if let Some(_sbom_ids) = scenario.patch_sbom_lables.clone() {
tx!(s.patch_sbom_labels?(scenario.patch_sbom_lables.clone(),
patch_sbom_labels_counter.clone()),
name: format!("patch_sbom_labels"));
}

s
})
.register_scenario({
Expand Down
105 changes: 104 additions & 1 deletion src/restapi.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,79 @@
use crate::utils::DisplayVec;
use goose::goose::{GooseUser, TransactionResult};
use goose::goose::{GooseMethod, GooseRequest, GooseUser, TransactionResult};
use reqwest::{Client, RequestBuilder};
use serde_json::Value as JsonValue;
use serde_json::json;
use std::sync::{
Arc,
atomic::{AtomicUsize, Ordering},
};
use urlencoding::encode;

// send_request sends a request to the server
//
// path is the path of the request, e.g. "/api/v2/sbom/count-by-package"
// user is the GooseUser to send the request with
// method is the HTTP method to use, e.g. GooseMethod::Get
// value is the JSON value to send in the request body
// client_method is the reqwest method to use, e.g. Client::get
async fn send_request(
path: String,
user: &mut GooseUser,
method: GooseMethod,
value: JsonValue,
client_method: fn(&Client, String) -> RequestBuilder,
) -> TransactionResult {
let url = user.build_url(&path)?;

let reqwest_request_builder = client_method(&user.client, url);
let goose_request = GooseRequest::builder()
.method(method)
.path(path.as_str())
.set_request_builder(reqwest_request_builder.json(&value))
.build();
let _response = user.request(goose_request).await?;

Ok(())
}

/// Send Sbom labels request using PUT method
pub async fn put_sbom_labels(
sbom_ids: Vec<String>,
counter: Arc<AtomicUsize>,
user: &mut GooseUser,
) -> TransactionResult {
let path = format!(
"/api/v2/sbom/{}/label",
sbom_ids[counter.fetch_add(1, Ordering::Relaxed) % sbom_ids.len()].clone()
);
let json = json!({
"source": "It's a put request",
"foo": "bar",
"space": "with space",
"empty": "",
});
send_request(path, user, GooseMethod::Put, json, Client::put).await
}

/// Send Sbom labels request using PATCH method
pub async fn patch_sbom_labels(
sbom_ids: Vec<String>,
counter: Arc<AtomicUsize>,
user: &mut GooseUser,
) -> TransactionResult {
let path = format!(
"/api/v2/sbom/{}/label",
sbom_ids[counter.fetch_add(1, Ordering::Relaxed) % sbom_ids.len()].clone()
);
let json = json!({
"source": "It's a patch request",
"foo": "bar",
"space": "with space",
"empty": "",
});
send_request(path, user, GooseMethod::Patch, json, Client::patch).await
}

pub async fn get_advisory(id: String, user: &mut GooseUser) -> TransactionResult {
let uri = format!("/api/v2/advisory/{}", encode(&format!("urn:uuid:{}", id)));

Expand All @@ -26,6 +93,42 @@ pub async fn download_advisory(id: String, user: &mut GooseUser) -> TransactionR
Ok(())
}

pub async fn list_sbom_labels(user: &mut GooseUser) -> TransactionResult {
let filter_text = json!([
{ "key": "source"},
]);

let uri = format!(
"/api/v2/sbom-labels?filter_text={}&limit={}",
encode(&filter_text.to_string()),
1000
);

let _response = user.get(&uri).await?;

Ok(())
}

pub async fn count_by_package(purl: String, user: &mut GooseUser) -> TransactionResult {
let filter_text = json!([
{
"purl": purl,
"cpe": null
}
]);

send_request(
"/api/v2/sbom/count-by-package".to_string(),
user,
GooseMethod::Get,
filter_text,
Client::get,
)
.await?;

Ok(())
}

pub async fn list_advisory_labels(user: &mut GooseUser) -> TransactionResult {
let uri = format!(
"/api/v2/advisory-labels?filter_text={}&limit={}",
Expand Down
75 changes: 75 additions & 0 deletions src/scenario/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,15 @@ pub(crate) struct Scenario {

#[serde(with = "required")]
pub get_advisory: Option<String>,

#[serde(with = "required")]
pub count_by_package: Option<String>,

#[serde(default, skip_serializing_if = "Option::is_none")]
pub patch_sbom_lables: Option<Vec<String>>,

#[serde(default, skip_serializing_if = "Option::is_none")]
pub put_sbom_lables: Option<Vec<String>>,
}

impl Scenario {
Expand Down Expand Up @@ -143,6 +152,26 @@ impl Scenario {
);
let download_advisory = Some(loader.download_advisory().await?);
let get_advisory = Some(loader.download_advisory().await?);
let count_by_package_result = Some(loader.count_by_package().await?);
let count_by_package =
count_by_package_result.ok_or_else(|| anyhow!("no count-by-package result"))?;
let count_by_package = serde_json::from_str::<serde_json::Value>(&count_by_package)?;
let put_sbom_lables = Some(
loader
.put_sbom_lables()
.await?
.iter()
.map(|sbom_id| format!("urn:uuid:{sbom_id}"))
.collect(),
);
let patch_sbom_lables = Some(
loader
.patch_sbom_lables()
.await?
.iter()
.map(|sbom_id| format!("urn:uuid:{sbom_id}"))
.collect(),
);

Ok(Self {
get_sbom: large_sbom_digest.clone(),
Expand All @@ -160,6 +189,15 @@ impl Scenario {
delete_sbom_pool,
download_advisory,
get_advisory,
count_by_package: Some(format!(
"pkg:{}/{}/{}@{}",
count_by_package["type"].as_str().unwrap_or(""),
count_by_package["namespace"].as_str().unwrap_or(""),
count_by_package["name"].as_str().unwrap_or(""),
count_by_package["version"].as_str().unwrap_or("")
)),
patch_sbom_lables,
put_sbom_lables,
})
}
}
Expand Down Expand Up @@ -376,6 +414,43 @@ FROM public.advisory order by modified desc limit 1;"#,
)
.await
}

/// A purl for count-by-package query
pub async fn count_by_package(&self) -> anyhow::Result<String> {
self.find(
r#"
select purl::text as result from qualified_purl qp order by qp.timestamp desc limit 1;"#,
)
.await
}

/// sbom IDs for put labels
pub async fn put_sbom_lables(&self) -> anyhow::Result<Vec<String>> {
let mut db = crate::db::connect(&self.db).await?;

let rows = sqlx::query(
"SELECT sbom_id::text as id FROM public.sbom order by published desc limit 20;",
)
.fetch_all(&mut db)
.await?;
Ok(rows
.into_iter()
.map(|row| row.get::<String, _>("id"))
.collect())
}

/// sbom IDs for patch labels
pub async fn patch_sbom_lables(&self) -> anyhow::Result<Vec<String>> {
let mut db = crate::db::connect(&self.db).await?;

let rows = sqlx::query("SELECT sbom_id::text as id FROM public.sbom order by published desc OFFSET 20 limit 20;")
.fetch_all(&mut db)
.await?;
Ok(rows
.into_iter()
.map(|row| row.get::<String, _>("id"))
.collect())
}
}

#[cfg(test)]
Expand Down
Loading