fuzz_introspector_client/
introspector.rs

1use anyhow::Result;
2use serde::de::DeserializeOwned;
3use thiserror::Error;
4
5fn render_url(endpoint: &str, project: &str) -> String {
6    format!("https://introspector.oss-fuzz.com/api/{endpoint}?project={project}")
7}
8
9#[derive(Debug, Error)]
10pub enum IntroSpectorAPIError {
11    #[error(transparent)]
12    ReqWestError(#[from] reqwest::Error),
13    #[error("Introspector api query unsuccesful.")]
14    IntrospectorAPIError,
15}
16
17async fn get<T: DeserializeOwned>(
18    endpoint: &str,
19    project: &str,
20) -> std::result::Result<T, reqwest::Error> {
21    let url = render_url(endpoint, project);
22    let response = reqwest::get(&url).await?;
23    Ok(response.json().await?)
24}
25
26pub async fn annotated_config(project: &str) -> Result<types::annotated_config::Project> {
27    let root: types::annotated_config::Root = get("annotated-cfg", project).await?;
28    if root.result != "success" {
29        return Err(IntroSpectorAPIError::IntrospectorAPIError.into());
30    }
31    Ok(root.project)
32}
33
34pub async fn far_reach_but_low_coverage(
35    project: &str,
36) -> Result<Vec<types::far_but_reach_low_coverage::Function>> {
37    let root: types::far_but_reach_low_coverage::Root =
38        get("far-reach-but-low-coverage", project).await?;
39    if root.result != "success" {
40        return Err(IntroSpectorAPIError::IntrospectorAPIError.into());
41    }
42    Ok(root.functions)
43}
44
45pub async fn project_summary(project: &str) -> Result<types::project_summary::Project> {
46    let root: types::project_summary::Root = get("project-summary", project).await?;
47    if root.result != "success" {
48        return Err(IntroSpectorAPIError::IntrospectorAPIError.into());
49    }
50    Ok(root.project)
51}
52
53pub async fn branch_blockers(project: &str) -> Result<Vec<types::branch_blockers::Blocker>> {
54    let root: types::branch_blockers::Root = get("branch-blockers", project).await?;
55    if root.result != "success" {
56        return Err(IntroSpectorAPIError::IntrospectorAPIError.into());
57    }
58    Ok(root.project_blockers)
59}
60
61pub async fn all_functions(project: &str) -> Result<Vec<types::all_functions::Function>> {
62    let root: types::all_functions::Root = get("all-functions", project).await?;
63    if root.result != "success" {
64        return Err(IntroSpectorAPIError::IntrospectorAPIError.into());
65    }
66    Ok(root.functions)
67}
68
69pub mod types {
70    pub mod annotated_config {
71        use serde_derive::Deserialize;
72        use serde_derive::Serialize;
73
74        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
75        pub struct Root {
76            pub project: Project,
77            pub result: String,
78        }
79
80        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
81        pub struct Project {
82            pub annotated_cfg: Vec<AnnotatedCfg>,
83            pub name: String,
84        }
85
86        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
87        pub struct AnnotatedCfg {
88            pub destinations: Vec<Destination>,
89            pub fuzzer_name: String,
90            pub source_file: String,
91        }
92
93        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
94        pub struct Destination {
95            pub accummulated_cyclomatic_complexity: i64,
96            pub arg_names: Vec<String>,
97            pub arg_types: Vec<String>,
98            pub cyclomatic_complexity: i64,
99            pub function_name: String,
100            pub raw_function_name: String,
101            pub return_type: String,
102            pub source_file: String,
103        }
104    }
105
106    pub mod far_but_reach_low_coverage {
107        use serde_derive::Deserialize;
108        use serde_derive::Serialize;
109
110        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
111        pub struct Root {
112            pub functions: Vec<Function>,
113            pub result: String,
114        }
115
116        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
117        pub struct Function {
118            pub accummulated_complexity: usize,
119            pub function_argument_names: Vec<String>,
120            pub function_arguments: Vec<String>,
121            pub function_name: String,
122            pub function_filename: String,
123            pub is_reached: bool,
124            pub raw_function_name: String,
125            pub reached_by_fuzzers: Vec<String>,
126            pub return_type: String,
127            pub runtime_coverage_percent: f64,
128        }
129    }
130
131    pub mod project_summary {
132        use serde_derive::Deserialize;
133        use serde_derive::Serialize;
134
135        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
136        pub struct Root {
137            pub project: Project,
138            pub result: String,
139        }
140
141        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
142        pub struct Project {
143            pub introspector_data: IntrospectorData,
144            pub name: String,
145            pub runtime_coverage_data: RuntimeCoverageData,
146        }
147
148        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
149        pub struct IntrospectorData {
150            pub annotated_cfg: Vec<AnnotatedCfg>,
151            pub branch_pairs: Vec<BranchPair>,
152            pub coverage_lines: f64,
153            pub function_count: i64,
154            pub functions_covered_estimate: f64,
155            pub fuzzer_count: i64,
156            pub introspector_report_url: String,
157            pub static_reachability: f64,
158        }
159
160        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
161        pub struct AnnotatedCfg {
162            pub destinations: Vec<Destination>,
163            pub fuzzer_name: String,
164            pub source_file: String,
165        }
166
167        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
168        pub struct Destination {
169            pub accummulated_cyclomatic_complexity: i64,
170            pub arg_names: Vec<String>,
171            pub arg_types: Vec<String>,
172            pub cyclomatic_complexity: i64,
173            pub function_name: String,
174            pub raw_function_name: String,
175            pub return_type: String,
176            pub source_file: String,
177        }
178
179        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
180        pub struct BranchPair {
181            pub blocked_runtime_coverage: i64,
182            pub blocked_unique_functions: Vec<String>,
183            pub function_name: String,
184            pub linenumber: String,
185            pub project: String,
186            pub source_file: String,
187        }
188
189        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
190        pub struct RuntimeCoverageData {
191            pub coverage_url: String,
192            pub line_coverage: LineCoverage,
193        }
194
195        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
196        pub struct LineCoverage {
197            pub count: i64,
198            pub covered: i64,
199            pub percent: f64,
200        }
201    }
202
203    pub mod branch_blockers {
204        use serde_derive::Deserialize;
205        use serde_derive::Serialize;
206
207        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
208        pub struct Root {
209            pub project_blockers: Vec<Blocker>,
210            pub result: String,
211        }
212
213        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
214        pub struct Blocker {
215            pub blocked_unique_functions: Vec<String>,
216            pub function_name: String,
217            pub project_name: String,
218            pub source_file: String,
219            pub src_linenumber: String,
220            pub unique_blocked_coverage: i64,
221        }
222    }
223
224    pub mod all_functions {
225        use serde_derive::Deserialize;
226        use serde_derive::Serialize;
227
228        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
229        pub struct Root {
230            pub functions: Vec<Function>,
231            pub result: String,
232        }
233
234        #[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
235        pub struct Function {
236            pub accummulated_complexity: i64,
237            pub function_argument_names: Vec<String>,
238            pub function_arguments: Vec<String>,
239            pub function_filename: String,
240            pub function_name: String,
241            pub is_reached: bool,
242            pub raw_function_name: String,
243            pub reached_by_fuzzers: Vec<String>,
244            pub return_type: String,
245            pub runtime_coverage_percent: f64,
246        }
247    }
248}