diff --git a/README.md b/README.md index 88d6e687..277d9d9c 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ Currently, the following modules are available as of version `0.17`. - [`teams`] Teams. - [`gists`] GitHub's gists API - [`users`] Users. +- [`code_scannings`] Code scannings [`models`]: https://docs.rs/octocrab/latest/octocrab/models/index.html [`auth`]: https://docs.rs/octocrab/latest/octocrab/auth/index.html diff --git a/src/api.rs b/src/api.rs index 01e9e530..9dc161c5 100644 --- a/src/api.rs +++ b/src/api.rs @@ -2,6 +2,7 @@ pub mod actions; pub mod activity; pub mod apps; pub mod checks; +pub mod code_scannings; pub mod commits; pub mod current; pub mod events; diff --git a/src/api/code_scannings.rs b/src/api/code_scannings.rs new file mode 100644 index 00000000..b390eee5 --- /dev/null +++ b/src/api/code_scannings.rs @@ -0,0 +1,43 @@ +//! The code scanning API. +use crate::{models, params, Octocrab, Result}; + +mod list; + +/// Handler for GitHub's code scanning API. +/// +/// Created with [`Octocrab::code_scannings`]. +pub struct CodeScanningHandler<'octo> { + crab: &'octo Octocrab, + owner: String, + repo: Option, +} + +impl<'octo> CodeScanningHandler<'octo> { + pub(crate) fn new(crab: &'octo Octocrab, owner: String, repo: Option) -> Self { + Self { crab, owner, repo } + } + + /// Gets an code scanning from the repository. + /// ```no_run + /// # async fn run() -> octocrab::Result<()> { + /// # let octocrab = octocrab::Octocrab::default(); + /// let code_scanning = octocrab.code_scannings("owner", "repo").get(3).await?; + /// # Ok(()) + /// # } + /// ``` + pub async fn get(&mut self, number: u64) -> Result { + let route = format!( + "/repos/{owner}/{repo}/code-scanning/alerts/{number}", + owner = self.owner, + repo = self.repo.as_mut().expect("Repository must be specified"), + number = number, + ); + + self.crab.get(route, None::<&()>).await + } + + /// List code scannings in the repository. + pub fn list(&self) -> list::ListCodeScanningsBuilder<'_, '_> { + list::ListCodeScanningsBuilder::new(self) + } +} diff --git a/src/api/code_scannings/list.rs b/src/api/code_scannings/list.rs new file mode 100644 index 00000000..1571ea97 --- /dev/null +++ b/src/api/code_scannings/list.rs @@ -0,0 +1,100 @@ +use super::*; +use crate::params::Direction; + +#[derive(crate::Serialize)] +pub struct ListCodeScanningsBuilder<'octo, 'b> { + #[serde(skip)] + handler: &'b CodeScanningHandler<'octo>, + #[serde(skip_serializing_if = "Option::is_none")] + tool_name: Option, + #[serde(skip_serializing_if = "Option::is_none")] + tool_guid: Option, + #[serde(skip_serializing_if = "Option::is_none")] + per_page: Option, + #[serde(skip_serializing_if = "Option::is_none")] + page: Option, + #[serde(skip_serializing_if = "Option::is_none")] + reference: Option, + #[serde(skip_serializing_if = "Option::is_none")] + direction: Option, + #[serde(skip_serializing_if = "Option::is_none")] + sort: Option, + #[serde(skip_serializing_if = "Option::is_none")] + state: Option, + #[serde(skip_serializing_if = "Option::is_none")] + severity: Option, +} + +impl<'octo, 'b, 'c, 'd> ListCodeScanningsBuilder<'octo, 'b> { + pub(crate) fn new(handler: &'b CodeScanningHandler<'octo>) -> Self { + Self { + handler, + tool_name: None, + tool_guid: None, + per_page: None, + page: None, + reference: None, + direction: None, + sort: None, + state: None, + severity: None, + } + } + + /// Filter pull requests by `state`. + pub fn state(mut self, state: params::State) -> Self { + self.state = Some(state); + self + } + + /// What to sort results by. Can be either `created`, `updated`, + /// `popularity` (comment count) or `long-running` (age, filtering by pulls + /// updated in the last month). + pub fn sort(mut self, sort: impl Into) -> Self { + self.sort = Some(sort.into()); + self + } + + /// The direction of the sort. Can be either ascending or descending. + /// Default: descending when sort is `created` or sort is not specified, + /// otherwise ascending sort. + pub fn direction(mut self, direction: impl Into) -> Self { + self.direction = Some(direction.into()); + self + } + + /// Results per page (max 100). + pub fn per_page(mut self, per_page: impl Into) -> Self { + self.per_page = Some(per_page.into()); + self + } + + /// Page number of the results to fetch. + pub fn page(mut self, page: impl Into) -> Self { + self.page = Some(page.into()); + self + } + + /// Sends the actual request. + pub async fn send( + self, + ) -> crate::Result> { + let route = self + .handler + .repo + .as_ref() + .map(|r| { + format!( + "/repos/{owner}/{repo}/code-scanning/alerts", + owner = self.handler.owner, + repo = r, + ) + }) + .unwrap_or(format!( + "/orgs/{owner}/code-scanning/alerts", + owner = self.handler.owner, + )); + + self.handler.crab.get(route, Some(&self)).await + } +} diff --git a/src/lib.rs b/src/lib.rs index 087649e5..41c81969 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -247,7 +247,7 @@ use crate::service::middleware::extra_headers::ExtraHeadersLayer; #[cfg(feature = "retry")] use crate::service::middleware::retry::RetryConfig; -use crate::api::users; +use crate::api::{code_scannings, users}; use auth::{AppAuth, Auth}; use models::{AppId, InstallationId, InstallationToken}; @@ -1080,6 +1080,25 @@ impl Octocrab { issues::IssueHandler::new(self, owner.into(), repo.into()) } + /// Creates a [`code_scanning::CodeSCanningHandler`] for the repo specified at `owner/repo`, + /// that allows you to access GitHub's Code scanning API. + pub fn code_scannings( + &self, + owner: impl Into, + repo: impl Into, + ) -> code_scannings::CodeScanningHandler { + code_scannings::CodeScanningHandler::new(self, owner.into(), Option::from(repo.into())) + } + + /// Creates a [`code_scanning::CodeSCanningHandler`] for the org specified at `owner`, + /// that allows you to access GitHub's Code scanning API. + pub fn code_scannings_organisation( + &self, + owner: impl Into, + ) -> code_scannings::CodeScanningHandler { + code_scannings::CodeScanningHandler::new(self, owner.into(), None) + } + /// Creates a [`commits::CommitHandler`] for the repo specified at `owner/repo`, pub fn commits( &self, diff --git a/src/models.rs b/src/models.rs index bca2e3f6..7d55c8be 100644 --- a/src/models.rs +++ b/src/models.rs @@ -14,6 +14,7 @@ pub mod actions; pub mod activity; pub mod apps; pub mod checks; +pub mod code_scannings; pub mod commits; pub mod events; pub mod gists; @@ -105,6 +106,7 @@ id_type!( CardId, CheckSuiteId, CheckRunId, + CodeScanningId, CommentId, InstallationId, IssueEventId, diff --git a/src/models/code_scannings.rs b/src/models/code_scannings.rs new file mode 100644 index 00000000..68407d6a --- /dev/null +++ b/src/models/code_scannings.rs @@ -0,0 +1,107 @@ +use super::*; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct CodeScanningAlert { + pub number: i64, + pub created_at: String, + pub updated_at: Option, + pub url: String, + pub html_url: String, + pub state: String, + pub fixed_at: Option, + pub dismissed_by: Dismisser, + pub dismissed_at: String, + pub dismissed_reason: String, + pub dismissed_comment: String, + pub rule: Rule, + pub tool: Tool, + pub most_recent_instance: MostRecentInstance, + pub instances_url: String, +} + +#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct Dismisser { + pub login: String, + pub id: UserId, + pub node_id: String, + pub avatar_url: Url, + pub gravatar_id: String, + pub url: Url, + pub html_url: Url, + pub followers_url: Url, + pub following_url: Url, + pub gists_url: Url, + pub starred_url: Url, + pub subscriptions_url: Url, + pub organizations_url: Url, + pub repos_url: Url, + pub events_url: Url, + pub received_events_url: Url, + pub r#type: String, + pub site_admin: bool, + pub patch_url: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub email: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct Rule { + pub id: String, + pub severity: String, + pub description: String, + pub name: String, + pub tags: Vec, + pub security_severity_level: String, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct Tool { + pub name: String, + pub guid: Option, + pub version: String, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct MostRecentInstance { + #[serde(rename = "ref")] + pub ref_field: String, + pub analysis_key: String, + pub environment: Environment, + pub category: String, + pub state: String, + pub commit_sha: String, + pub message: Message, + pub location: Location, + pub classifications: Vec, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct Environment { + #[serde(rename = "build-mode")] + pub build_mode: Option, + pub category: Option, + pub language: Option, + pub runner: Option>, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct Message { + pub text: String, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct Location { + pub path: String, + pub start_line: i64, + pub end_line: i64, + pub start_column: i64, + pub end_column: i64, +} diff --git a/src/params.rs b/src/params.rs index 8ab1760e..06096610 100644 --- a/src/params.rs +++ b/src/params.rs @@ -174,6 +174,93 @@ pub mod checks { } } +pub mod code_scannings { + //! Parameter types for the code scanning API. + + /// What to sort the results by. Can be either `created`, `updated`, + /// or `comments`. + #[derive(Debug, Clone, Copy, serde::Serialize)] + #[serde(rename_all = "snake_case")] + #[non_exhaustive] + pub enum Sort { + Created, + Updated, + } + + /// The reference for the code scanning alert. + /// This can be a branch, tag, or commit. + #[derive(Debug, Clone, serde::Serialize)] + #[serde(rename_all = "snake_case")] + #[non_exhaustive] + pub enum Reference { + Branch(String), + Tag(String), + Commit(String), + } + + /// The severity of the alert. + #[derive(Debug, Clone, Copy, serde::Serialize)] + #[serde(rename_all = "snake_case")] + #[non_exhaustive] + pub enum Severity { + Info, + Low, + Medium, + High, + Critical, + } + + /// A generic filter type that allows you to filter either by exact match, + /// any match, or no matches. + #[derive(Debug, Clone, Copy)] + #[non_exhaustive] + pub enum Filter { + Matches(T), + Any, + None, + } + + impl serde::Serialize for crate::params::code_scannings::Filter { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match self { + Self::Matches(val) => val.serialize(serializer), + Self::Any => serializer.serialize_str("*"), + Self::None => serializer.serialize_str("none"), + } + } + } + + impl From for crate::params::code_scannings::Filter { + fn from(value: T) -> Self { + Self::Matches(value) + } + } + + #[cfg(test)] + mod tests { + + #[test] + fn serialize() { + assert_eq!( + "1234", + serde_json::to_string(&crate::params::code_scannings::Filter::Matches(1234)) + .unwrap() + ); + assert_eq!( + r#""*""#, + serde_json::to_string(&crate::params::code_scannings::Filter::<()>::Any).unwrap() + ); + assert_eq!( + r#""none""#, + serde_json::to_string(&crate::params::code_scannings::Filter::<()>::None).unwrap() + ); + } + } +} + pub mod issues { //! Parameter types for the issues API. diff --git a/tests/code_scanning_alerts_list_test.rs b/tests/code_scanning_alerts_list_test.rs new file mode 100644 index 00000000..e27c75a8 --- /dev/null +++ b/tests/code_scanning_alerts_list_test.rs @@ -0,0 +1,102 @@ +use wiremock::{ + matchers::{method, path}, + Mock, MockServer, ResponseTemplate, +}; + +use mock_error::setup_error_handler; +use octocrab::models::code_scannings::CodeScanningAlert; +use octocrab::Octocrab; + +mod mock_error; + +const OWNER: &str = "org"; +const REPO: &str = "some-repo"; + +async fn setup_codescanning_list_api(template: ResponseTemplate, is_org: bool) -> MockServer { + let mock_server = MockServer::start().await; + + if is_org { + Mock::given(method("GET")) + .and(path(format!( + "/orgs/{owner}/code-scanning/alerts", + owner = OWNER + ))) + .respond_with(template.clone()) + .mount(&mock_server) + .await; + setup_error_handler( + &mock_server, + &format!( + "GET on /org/{owner}/code-scanning/alerts was not received", + owner = OWNER + ), + ) + .await; + } else { + Mock::given(method("GET")) + .and(path(format!( + "/repos/{owner}/{repo}/code-scanning/alerts", + owner = OWNER, + repo = REPO + ))) + .respond_with(template.clone()) + .mount(&mock_server) + .await; + setup_error_handler( + &mock_server, + &format!( + "GET on /repos/{owner}/{repo}/code-scanning/alerts was not received", + owner = OWNER, + repo = REPO + ), + ) + .await; + } + mock_server +} + +fn setup_octocrab(uri: &str) -> Octocrab { + Octocrab::builder().base_uri(uri).unwrap().build().unwrap() +} + +#[tokio::test] +async fn check_list_200() { + let s = include_str!("resources/codescanning_alerts_multiple.json"); + let alert: Vec = serde_json::from_str(s).unwrap(); + let template = ResponseTemplate::new(200).set_body_json(&alert); + let mock_server = setup_codescanning_list_api(template, false).await; + let client = setup_octocrab(&mock_server.uri()); + + let result = client + .code_scannings(OWNER.to_owned(), REPO.to_owned()) + .list() + .send() + .await; + + assert!( + result.is_ok(), + "expected successful result, got error: {:?}", + result + ); +} + +#[tokio::test] +async fn check_list_organisation_200() { + let s = include_str!("resources/codescanning_alerts_multiple.json"); + let alert: Vec = serde_json::from_str(s).unwrap(); + let template = ResponseTemplate::new(200).set_body_json(&alert); + let mock_server = setup_codescanning_list_api(template, true).await; + let client = setup_octocrab(&mock_server.uri()); + + let result = client + .code_scannings_organisation(OWNER.to_owned()) + .list() + .send() + .await; + + assert!( + result.is_ok(), + "expected successful result, got error: {:?}", + result + ); +} diff --git a/tests/code_scanning_analysis_test.rs b/tests/code_scanning_analysis_test.rs new file mode 100644 index 00000000..581cde19 --- /dev/null +++ b/tests/code_scanning_analysis_test.rs @@ -0,0 +1,109 @@ +use serde::{Deserialize, Serialize}; +use wiremock::{ + matchers::{method, path}, + Mock, MockServer, ResponseTemplate, +}; + +use mock_error::setup_error_handler; +use octocrab::models::code_scannings::CodeScanningAlert; +use octocrab::Octocrab; + +mod mock_error; + +async fn setup_issue_check_assignee_api(template: ResponseTemplate) -> MockServer { + let owner: &str = "org"; + let repo: &str = "some-repo"; + let number: &str = "1"; + + let mock_server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path(format!( + "/repos/{owner}/{repo}/code-scanning/alerts/{number}", + owner = owner, + repo = repo + ))) + .respond_with(template.clone()) + .mount(&mock_server) + .await; + + setup_error_handler( + &mock_server, + &format!("GET on /repos/{owner}/{repo}/code-scanning/alerts was not received"), + ) + .await; + mock_server +} + +fn setup_octocrab(uri: &str) -> Octocrab { + Octocrab::builder().base_uri(uri).unwrap().build().unwrap() +} + +const OWNER: &str = "org"; +const REPO: &str = "some-repo"; +const ASSIGNEE: &str = "some-user"; + +#[tokio::test] +async fn check_get_200() { + let s = include_str!("resources/codescanning_alert_single.json"); + let alert: CodeScanningAlert = serde_json::from_str(s).unwrap(); + let template = ResponseTemplate::new(200).set_body_json(&alert); + let mock_server = setup_issue_check_assignee_api(template).await; + let client = setup_octocrab(&mock_server.uri()); + + let result = client + .code_scannings(OWNER.to_owned(), REPO.to_owned()) + .get(1) + .await; + + assert!( + result.is_ok(), + "expected successful result, got error: {:#?}", + result + ); +} + +#[tokio::test] +async fn check_get_404() { + let s = include_str!("resources/codescanning_alert_error.json"); + let alert: GitHubErrorBody = serde_json::from_str(s).unwrap(); + let template = ResponseTemplate::new(404).set_body_json(&alert); + let mock_server = setup_issue_check_assignee_api(template).await; + let client = setup_octocrab(&mock_server.uri()); + + let result = client + .code_scannings(OWNER.to_owned(), REPO.to_owned()) + .get(1) + .await; + + assert!( + result.is_err(), + "expected error result, got success somehow: {:#?}", + result + ); +} + +#[tokio::test] +async fn check_get_500() { + let template = ResponseTemplate::new(500); + let mock_server = setup_issue_check_assignee_api(template).await; + let client = setup_octocrab(&mock_server.uri()); + + let result = client + .issues(OWNER.to_owned(), REPO.to_owned()) + .check_assignee(ASSIGNEE) + .await; + + assert!( + result.is_err(), + "expected error result, got success: {:#?}", + result + ); +} + +#[derive(Debug, Deserialize, Serialize)] +struct GitHubErrorBody { + pub documentation_url: Option, + pub message: Option, + pub status: Option, +} diff --git a/tests/resources/codescanning_alert_error.json b/tests/resources/codescanning_alert_error.json new file mode 100644 index 00000000..b807a5c5 --- /dev/null +++ b/tests/resources/codescanning_alert_error.json @@ -0,0 +1,5 @@ +{ + "message": "No alert found for alert number 2", + "documentation_url": "https://docs.github.com/rest/code-scanning/code-scanning#get-a-code-scanning-alert", + "status": "404" +} \ No newline at end of file diff --git a/tests/resources/codescanning_alert_single.json b/tests/resources/codescanning_alert_single.json new file mode 100644 index 00000000..50e2d3c5 --- /dev/null +++ b/tests/resources/codescanning_alert_single.json @@ -0,0 +1,72 @@ +{ + "number": 42, + "created_at": "2020-06-19T11:21:34Z", + "url": "https://api.github.com/repos/octocat/hello-world/code-scanning/alerts/42", + "html_url": "https://github.com/octocat/hello-world/code-scanning/42", + "state": "dismissed", + "fixed_at": null, + "dismissed_by": { + "login": "octocat", + "id": 54933897, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "dismissed_at": "2020-02-14T12:29:18Z", + "dismissed_reason": "false positive", + "dismissed_comment": "This alert is not actually correct, because there's a sanitizer included in the library.", + "rule": { + "id": "js/zipslip", + "severity": "error", + "security_severity_level": "high", + "description": "Arbitrary file write during zip extraction (\"Zip Slip\")", + "name": "js/zipslip", + "full_description": "Extracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten.", + "tags": [ + "security", + "external/cwe/cwe-022" + ], + "help": "# Arbitrary file write during zip extraction (\"Zip Slip\")\\nExtracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten ...", + "help_uri": "https://codeql.github.com/" + }, + "tool": { + "name": "CodeQL", + "guid": null, + "version": "2.4.0" + }, + "most_recent_instance": { + "ref": "refs/heads/main", + "analysis_key": ".github/workflows/codeql-analysis.yml:CodeQL-Build", + "category": ".github/workflows/codeql-analysis.yml:CodeQL-Build", + "environment": {}, + "state": "dismissed", + "commit_sha": "39406e42cb832f683daa691dd652a8dc36ee8930", + "message": { + "text": "This path depends on a user-provided value." + }, + "location": { + "path": "spec-main/api-session-spec.ts", + "start_line": 917, + "end_line": 917, + "start_column": 7, + "end_column": 18 + }, + "classifications": [ + "test" + ] + }, + "instances_url": "https://api.github.com/repos/octocat/hello-world/code-scanning/alerts/42/instances" +} \ No newline at end of file diff --git a/tests/resources/codescanning_alerts_multiple.json b/tests/resources/codescanning_alerts_multiple.json new file mode 100644 index 00000000..bdfaf5c0 --- /dev/null +++ b/tests/resources/codescanning_alerts_multiple.json @@ -0,0 +1,146 @@ +[ + { + "number": 1, + "created_at": "2020-06-19T11:21:34Z", + "url": "https://api.github.com/repos/octocat/hello-world/code-scanning/alerts/1", + "html_url": "https://github.com/octocat/hello-world/code-scanning/1", + "state": "dismissed", + "fixed_at": null, + "dismissed_by": { + "login": "octocat", + "id": 54933897, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "dismissed_at": "2020-02-14T12:29:18Z", + "dismissed_reason": "false positive", + "dismissed_comment": "This alert is not actually correct, because there's a sanitizer included in the library.", + "rule": { + "id": "js/zipslip", + "severity": "error", + "security_severity_level": "high", + "description": "Arbitrary file write during zip extraction (\"Zip Slip\")", + "name": "js/zipslip", + "full_description": "Extracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten.", + "tags": [ + "security", + "external/cwe/cwe-022" + ], + "help": "# Arbitrary file write during zip extraction (\"Zip Slip\")\\nExtracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten ...", + "help_uri": "https://codeql.github.com/" + }, + "tool": { + "name": "CodeQL", + "guid": null, + "version": "2.4.0" + }, + "most_recent_instance": { + "ref": "refs/heads/main", + "analysis_key": ".github/workflows/codeql-analysis.yml:CodeQL-Build", + "category": ".github/workflows/codeql-analysis.yml:CodeQL-Build", + "environment": {}, + "state": "dismissed", + "commit_sha": "39406e42cb832f683daa691dd652a8dc36ee8930", + "message": { + "text": "This path depends on a user-provided value." + }, + "location": { + "path": "spec-main/api-session-spec.ts", + "start_line": 917, + "end_line": 917, + "start_column": 7, + "end_column": 18 + }, + "classifications": [ + "test" + ] + }, + "instances_url": "https://api.github.com/repos/octocat/hello-world/code-scanning/alerts/1/instances" + }, + { + "number": 42, + "created_at": "2020-06-19T11:21:34Z", + "url": "https://api.github.com/repos/octocat/hello-world/code-scanning/alerts/42", + "html_url": "https://github.com/octocat/hello-world/code-scanning/42", + "state": "dismissed", + "fixed_at": null, + "dismissed_by": { + "login": "octocat", + "id": 54933897, + "node_id": "MDQ6VXNlcjE=", + "avatar_url": "https://github.com/images/error/octocat_happy.gif", + "gravatar_id": "", + "url": "https://api.github.com/users/octocat", + "html_url": "https://github.com/octocat", + "followers_url": "https://api.github.com/users/octocat/followers", + "following_url": "https://api.github.com/users/octocat/following{/other_user}", + "gists_url": "https://api.github.com/users/octocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/octocat/subscriptions", + "organizations_url": "https://api.github.com/users/octocat/orgs", + "repos_url": "https://api.github.com/users/octocat/repos", + "events_url": "https://api.github.com/users/octocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/octocat/received_events", + "type": "User", + "site_admin": false + }, + "dismissed_at": "2020-02-14T12:29:18Z", + "dismissed_reason": "false positive", + "dismissed_comment": "This alert is not actually correct, because there's a sanitizer included in the library.", + "rule": { + "id": "js/zipslip", + "severity": "error", + "security_severity_level": "high", + "description": "Arbitrary file write during zip extraction (\"Zip Slip\")", + "name": "js/zipslip", + "full_description": "Extracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten.", + "tags": [ + "security", + "external/cwe/cwe-022" + ], + "help": "# Arbitrary file write during zip extraction (\"Zip Slip\")\\nExtracting files from a malicious zip archive without validating that the destination file path is within the destination directory can cause files outside the destination directory to be overwritten ...", + "help_uri": "https://codeql.github.com/" + }, + "tool": { + "name": "CodeQL", + "guid": null, + "version": "2.4.0" + }, + "most_recent_instance": { + "ref": "refs/heads/main", + "analysis_key": ".github/workflows/codeql-analysis.yml:CodeQL-Build", + "category": ".github/workflows/codeql-analysis.yml:CodeQL-Build", + "environment": {}, + "state": "dismissed", + "commit_sha": "39406e42cb832f683daa691dd652a8dc36ee8930", + "message": { + "text": "This path depends on a user-provided value." + }, + "location": { + "path": "spec-main/api-session-spec.ts", + "start_line": 917, + "end_line": 917, + "start_column": 7, + "end_column": 18 + }, + "classifications": [ + "test" + ] + }, + "instances_url": "https://api.github.com/repos/octocat/hello-world/code-scanning/alerts/42/instances" +} +] \ No newline at end of file diff --git a/tests/user_deserialize_test.rs b/tests/user_deserialize_test.rs index 11e70281..c91d8b26 100644 --- a/tests/user_deserialize_test.rs +++ b/tests/user_deserialize_test.rs @@ -2,9 +2,7 @@ mod mock_error; use mock_error::setup_error_handler; use octocrab::models::UserProfile; -use octocrab::{Error, Octocrab}; -use serde::{Deserialize, Serialize}; -use serde_json::{json, Value}; +use octocrab::Octocrab; use wiremock::{ matchers::{method, path}, Mock, MockServer, ResponseTemplate,