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}