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

Extensions API #407

Merged
merged 66 commits into from
Jun 16, 2022
Merged
Show file tree
Hide file tree
Changes from 65 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
d53d74e
Extensions subcommand entry points
andreaphylum May 2, 2022
29e0323
Construct extension from path (with manifest)
andreaphylum May 3, 2022
d7d53e4
Install and load methods for Extension
andreaphylum May 4, 2022
596f7e7
Acceptance criteria tests
andreaphylum May 5, 2022
2e3fe42
Acceptance criteria tests
andreaphylum May 5, 2022
e0b2d17
Acceptance criteria tests
andreaphylum May 6, 2022
5bd4ec8
Extensions base documentation
andreaphylum May 6, 2022
3f059a3
Clippy lints, conditional compilation fix for compiling with no features
andreaphylum May 6, 2022
e54eddc
Cargo fmt
andreaphylum May 6, 2022
a13e64b
Update cli/Cargo.toml
andreaphylum May 6, 2022
5f5105c
Update cli/src/commands/extensions/mod.rs
andreaphylum May 6, 2022
3140baf
Review fixes
andreaphylum May 6, 2022
9e7412d
Merge branch 'andrea/extensions-install-mgmt' of github.com:phylum-de…
andreaphylum May 6, 2022
aa4adc2
Review fixes
andreaphylum May 6, 2022
3817764
Merge branch 'main' of github.com:phylum-dev/cli into andrea/extensio…
andreaphylum May 9, 2022
5ee23e7
Documentation with new format
andreaphylum May 9, 2022
88d23d4
Env var cleanup skip; cargo fmt
andreaphylum May 9, 2022
a7b0342
Merge branch 'main' of github.com:phylum-dev/cli into andrea/extensio…
andreaphylum May 19, 2022
df7fac2
Anyhow error simplification
andreaphylum May 19, 2022
3ad428b
Lints and cargo alias
andreaphylum May 19, 2022
2eb4f4c
Phylum Analyze extension API draft
andreaphylum May 19, 2022
29703e9
Extensions API functions
andreaphylum May 20, 2022
bf2b1dd
Cargo fmt
andreaphylum May 20, 2022
6e0f5cb
Apply suggestions from code review
andreaphylum May 20, 2022
ba7ac03
More code review fixes
andreaphylum May 20, 2022
6749307
Merge branch 'main' into andrea/extensions-install-mgmt
andreaphylum May 23, 2022
6dc926b
Fix typo
andreaphylum May 23, 2022
35bfa96
Merge branch 'andrea/extensions-install-mgmt' of github.com:phylum-de…
andreaphylum May 23, 2022
211b99e
Injected dependencies and `deno_core::OpState` support
andreaphylum May 23, 2022
637aee2
Merge branch 'main' of github.com:phylum-dev/cli into andrea/extensio…
andreaphylum May 24, 2022
5af618c
Use `DirBuilder`
andreaphylum May 24, 2022
f23530c
Rename `extensions_subcommands`
andreaphylum May 24, 2022
815430a
Env mutex for tests
andreaphylum May 24, 2022
2c885ca
Merge branch 'andrea/extensions-install-mgmt' of github.com:phylum-de…
andreaphylum May 24, 2022
d4c966d
Renamed, re-scoped and documented extensions API functions
andreaphylum May 24, 2022
1d1833f
Handle run extension placeholder, refactor if/else chain in binary to…
andreaphylum May 24, 2022
5f7e0ba
Changed extension name regex
andreaphylum May 24, 2022
9904883
Merge branch 'main' of github.com:phylum-dev/cli into andrea/extensio…
andreaphylum May 31, 2022
35a9708
Adapted Parse::parse_file to allow trait objects
andreaphylum May 31, 2022
5701365
Removed unused `handle_run_extension` function
andreaphylum May 31, 2022
d08dd12
Merge branch 'main' of github.com:phylum-dev/cli into andrea/extensio…
andreaphylum Jun 1, 2022
5192642
Made API methods require const ref, created deno ops
andreaphylum Jun 1, 2022
5a99cfb
BROKEN: added ops to Deno
andreaphylum Jun 2, 2022
00033fa
PhylumApi owns Config
andreaphylum Jun 2, 2022
1d7021e
Cargo fmt
andreaphylum Jun 2, 2022
63e2f98
Extension state newtype
andreaphylum Jun 6, 2022
7758185
Op wrappers in fixture
andreaphylum Jun 6, 2022
54c3652
Separated wrapper module, op calls tests
andreaphylum Jun 6, 2022
1de4535
Merge branch 'main' of github.com:phylum-dev/cli into andrea/extensio…
andreaphylum Jun 7, 2022
3d15da0
Cleanup, comments
andreaphylum Jun 7, 2022
aa11c52
Merge branch 'main' of github.com:phylum-dev/cli into andrea/extensio…
andreaphylum Jun 7, 2022
67e33ee
Cleanup deps insertion into Deno
andreaphylum Jun 8, 2022
5d6fea0
Removed "allow unused" and cleaned up
andreaphylum Jun 8, 2022
59b1160
Removed test
andreaphylum Jun 8, 2022
fcb1eda
Refactored var name
andreaphylum Jun 8, 2022
837a455
Cleaned comment
andreaphylum Jun 8, 2022
d60a1ef
Moved and expanded comment
andreaphylum Jun 8, 2022
5ccea39
ExtensionStateRef wrapper type
andreaphylum Jun 10, 2022
699b1dc
Update cli/src/commands/extensions/api.rs
andreaphylum Jun 13, 2022
2af429b
Applied change requests
andreaphylum Jun 13, 2022
59467d8
Merge branch 'andrea/extensions-api' of github.com:phylum-dev/cli int…
andreaphylum Jun 13, 2022
c2d12d3
Removed pub qualifier
andreaphylum Jun 13, 2022
6850223
Merge branch 'main' of github.com:phylum-dev/cli into andrea/extensio…
andreaphylum Jun 13, 2022
ef38455
Reverted trait generic removal
andreaphylum Jun 15, 2022
1cfc30c
Renamed analyze_package into get_package_details
andreaphylum Jun 15, 2022
e35d703
Merge remote-tracking branch 'origin/main' into andrea/extensions-api
cd-work Jun 15, 2022
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ url = { version = "2", features = ["serde"] }
zip = "0.6.2"
walkdir = "2.3.2"
regex = "1.5.5"
once_cell = "1.12.0"
deno_core = { version = "0.135.0", optional = true }
deno_ast = { version = "0.15.0", features = ["transpiling"], optional = true }

Expand Down
159 changes: 95 additions & 64 deletions cli/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,16 @@ use crate::auth::handle_auth_flow;
use crate::auth::handle_refresh_tokens;
use crate::auth::{AuthAction, UserInfo};
use crate::config::AuthInfo;
use crate::config::Config;
use crate::types::PingResponse;

use self::endpoints::BaseUriError;

type Result<T> = std::result::Result<T, PhylumApiError>;

pub struct PhylumApi {
config: Config,
client: Client,
api_uri: String,
ignore_certs: bool,
}

Expand Down Expand Up @@ -110,20 +111,21 @@ impl PhylumApi {
/// must be obtained, the auth_info struct will be updated with the new
/// information. It is the duty of the calling code to save any changes
pub async fn new(
auth_info: &mut AuthInfo,
api_uri: &str,
mut config: Config,
request_timeout: Option<u64>,
ignore_certs: bool,
) -> Result<Self> {
// Do we have a refresh token?
let tokens: TokenResponse = match &auth_info.offline_access {
let tokens: TokenResponse = match &config.auth_info.offline_access {
Some(refresh_token) => {
handle_refresh_tokens(refresh_token, ignore_certs, api_uri).await?
handle_refresh_tokens(refresh_token, ignore_certs, &config.connection.uri).await?
}
None => {
handle_auth_flow(&AuthAction::Login, ignore_certs, &config.connection.uri).await?
}
None => handle_auth_flow(&AuthAction::Login, ignore_certs, api_uri).await?,
};

auth_info.offline_access = Some(tokens.refresh_token.clone());
config.auth_info.offline_access = Some(tokens.refresh_token.clone());

let version = env!("CARGO_PKG_VERSION");
let mut headers = HeaderMap::new();
Expand All @@ -146,8 +148,8 @@ impl PhylumApi {
.build()?;

Ok(Self {
config,
client,
api_uri: api_uri.to_string(),
ignore_certs,
})
}
Expand Down Expand Up @@ -179,22 +181,25 @@ impl PhylumApi {
}

/// Ping the system and verify it's up
pub async fn ping(&mut self) -> Result<String> {
let response: PingResponse = self.get(endpoints::get_ping(&self.api_uri)?).await?;
Ok(response.response)
pub async fn ping(&self) -> Result<String> {
Ok(self
.get::<PingResponse, _>(endpoints::get_ping(&self.config.connection.uri)?)
.await?
.response)
}

/// Get information about the authenticated user
pub async fn user_info(&self) -> Result<UserInfo> {
let oidc_settings = fetch_oidc_server_settings(self.ignore_certs, &self.api_uri).await?;
let oidc_settings =
fetch_oidc_server_settings(self.ignore_certs, &self.config.connection.uri).await?;
self.get(oidc_settings.userinfo_endpoint).await
}

/// Create a new project
pub async fn create_project(&mut self, name: &str, group: Option<&str>) -> Result<ProjectId> {
let response: CreateProjectResponse = self
.put(
endpoints::put_create_project(&self.api_uri)?,
endpoints::put_create_project(&self.config.connection.uri)?,
CreateProjectRequest {
name: name.to_owned(),
group_name: group.map(String::from),
Expand All @@ -205,34 +210,34 @@ impl PhylumApi {
}

/// Get a list of projects
pub async fn get_projects(
&mut self,
group: Option<&str>,
) -> Result<Vec<ProjectSummaryResponse>> {
pub async fn get_projects(&self, group: Option<&str>) -> Result<Vec<ProjectSummaryResponse>> {
let uri = match group {
Some(group) => endpoints::group_project_summary(&self.api_uri, group)?,
None => endpoints::get_project_summary(&self.api_uri)?,
Some(group) => endpoints::group_project_summary(&self.config.connection.uri, group)?,
None => endpoints::get_project_summary(&self.config.connection.uri)?,
};

self.get(uri).await
}

/// Get user settings
pub async fn get_user_settings(&mut self) -> Result<UserSettings> {
self.get(endpoints::get_user_settings(&self.api_uri)?).await
pub async fn get_user_settings(&self) -> Result<UserSettings> {
self.get(endpoints::get_user_settings(&self.config.connection.uri)?)
.await
}

/// Put updated user settings
pub async fn put_user_settings(&mut self, settings: &UserSettings) -> Result<bool> {
let _response: UserSettings = self
.put(endpoints::put_user_settings(&self.api_uri)?, &settings)
.await?;
pub async fn put_user_settings(&self, settings: &UserSettings) -> Result<bool> {
self.put::<UserSettings, _, _>(
endpoints::put_user_settings(&self.config.connection.uri)?,
&settings,
)
.await?;
Ok(true)
}

/// Submit a new request to the system
pub async fn submit_request(
&mut self,
&self,
req_type: &PackageType,
package_list: &[PackageDescriptor],
is_user: bool,
Expand All @@ -250,47 +255,58 @@ impl PhylumApi {
};
log::debug!("==> Sending package submission: {:?}", req);
let resp: SubmitPackageResponse = self
.put(endpoints::put_submit_package(&self.api_uri)?, req)
.put(
endpoints::put_submit_package(&self.config.connection.uri)?,
req,
)
.await?;
Ok(resp.job_id)
}

/// Get the status of a previously submitted job
pub async fn get_job_status(
&mut self,
job_id: &JobId,
) -> Result<JobStatusResponse<PackageStatus>> {
self.get(endpoints::get_job_status(&self.api_uri, job_id, false)?)
.await
pub async fn get_job_status(&self, job_id: &JobId) -> Result<JobStatusResponse<PackageStatus>> {
self.get(endpoints::get_job_status(
&self.config.connection.uri,
job_id,
false,
)?)
.await
}

/// Get the status of a previously submitted job (verbose output)
pub async fn get_job_status_ext(
&mut self,
&self,
job_id: &JobId,
) -> Result<JobStatusResponse<PackageStatusExtended>> {
self.get(endpoints::get_job_status(&self.api_uri, job_id, true)?)
.await
self.get(endpoints::get_job_status(
&self.config.connection.uri,
job_id,
true,
)?)
.await
}

/// Get the status of all jobs
pub async fn get_status(&mut self) -> Result<AllJobsStatusResponse> {
self.get(endpoints::get_all_jobs_status(&self.api_uri, 30)?)
.await
pub async fn get_status(&self) -> Result<AllJobsStatusResponse> {
self.get(endpoints::get_all_jobs_status(
&self.config.connection.uri,
30,
)?)
.await
}

/// Get the details of a specific project
pub async fn get_project_details(
&mut self,
project_name: &str,
) -> Result<ProjectDetailsResponse> {
self.get(endpoints::get_project_details(&self.api_uri, project_name)?)
.await
pub async fn get_project_details(&self, project_name: &str) -> Result<ProjectDetailsResponse> {
self.get(endpoints::get_project_details(
&self.config.connection.uri,
project_name,
)?)
.await
}

/// Resolve a Project Name to a Project ID
pub async fn get_project_id(
&mut self,
&self,
project_name: &str,
group_name: Option<&str>,
) -> Result<ProjectId> {
Expand All @@ -310,27 +326,32 @@ impl PhylumApi {
}

/// Get package details
pub async fn get_package_details(&mut self, pkg: &PackageDescriptor) -> Result<Package> {
self.get(
endpoints::get_package_status(&self.api_uri, pkg)
.map_err(|e| PhylumApiError::Other(e.into()))?,
)
pub async fn get_package_details(&self, pkg: &PackageDescriptor) -> Result<Package> {
self.get(endpoints::get_package_status(
&self.config.connection.uri,
pkg,
)?)
.await
}

/// Get all groups the user is part of.
pub async fn get_groups_list(&mut self) -> Result<ListUserGroupsResponse> {
self.get(endpoints::group_list(&self.api_uri)?).await
pub async fn get_groups_list(&self) -> Result<ListUserGroupsResponse> {
self.get(endpoints::group_list(&self.config.connection.uri)?)
.await
}

/// Get all groups the user is part of.
pub async fn create_group(&mut self, group_name: &str) -> Result<CreateGroupResponse> {
pub async fn create_group(&self, group_name: &str) -> Result<CreateGroupResponse> {
let group = CreateGroupRequest {
group_name: group_name.into(),
};
self.post(endpoints::group_create(&self.api_uri)?, group)
self.post(endpoints::group_create(&self.config.connection.uri)?, group)
.await
}

pub fn config(&self) -> &Config {
&self.config
}
}

/// Tests
Expand All @@ -343,6 +364,7 @@ mod tests {
use wiremock::matchers::{method, path, path_regex, query_param};
use wiremock::{Mock, ResponseTemplate};

use crate::config::ConnectionInfo;
use crate::test::mockito::*;

use super::*;
Expand All @@ -356,11 +378,20 @@ mod tests {
#[tokio::test]
async fn when_creating_unauthenticated_phylum_api_it_auths_itself() -> Result<()> {
let mock_server = build_mock_server().await;
let mut auth_info = build_unauthenticated_auth_info();
PhylumApi::new(&mut auth_info, mock_server.uri().as_str(), None, false).await?;
let auth_info = build_unauthenticated_auth_info();

let config = Config {
connection: ConnectionInfo {
uri: mock_server.uri(),
},
auth_info,
..Default::default()
};

let api = PhylumApi::new(config, None, false).await?;
// After auth, auth_info should have a offline access token
assert!(
auth_info.offline_access.is_some(),
api.config().auth_info.offline_access.is_some(),
"Offline access token was not set"
);

Expand Down Expand Up @@ -392,7 +423,7 @@ mod tests {
.mount(&mock_server)
.await;

let mut client = build_phylum_api(&mock_server).await?;
let client = build_phylum_api(&mock_server).await?;

let pkg = PackageDescriptor {
name: "react".to_string(),
Expand Down Expand Up @@ -424,7 +455,7 @@ mod tests {
.mount(&mock_server)
.await;

let mut client = build_phylum_api(&mock_server).await?;
let client = build_phylum_api(&mock_server).await?;

let pkg = PackageDescriptor {
name: "react".to_string(),
Expand Down Expand Up @@ -499,7 +530,7 @@ mod tests {
.mount(&mock_server)
.await;

let mut client = build_phylum_api(&mock_server).await?;
let client = build_phylum_api(&mock_server).await?;
client.get_status().await?;
Ok(())
}
Expand Down Expand Up @@ -559,7 +590,7 @@ mod tests {
.mount(&mock_server)
.await;

let mut client = build_phylum_api(&mock_server).await?;
let client = build_phylum_api(&mock_server).await?;

let pkg = PackageDescriptor {
name: "@schematics/angular".to_string(),
Expand Down Expand Up @@ -617,7 +648,7 @@ mod tests {
.mount(&mock_server)
.await;

let mut client = build_phylum_api(&mock_server).await?;
let client = build_phylum_api(&mock_server).await?;

let job = JobId::from_str("59482a54-423b-448d-8325-f171c9dc336b").unwrap();
client.get_job_status(&job).await?;
Expand Down Expand Up @@ -693,7 +724,7 @@ mod tests {
.mount(&mock_server)
.await;

let mut client = build_phylum_api(&mock_server).await?;
let client = build_phylum_api(&mock_server).await?;

let job = JobId::from_str("59482a54-423b-448d-8325-f171c9dc336b").unwrap();
client.get_job_status_ext(&job).await?;
Expand Down
Loading