Skip to content

Commit

Permalink
accept artifactory token as input
Browse files Browse the repository at this point in the history
  • Loading branch information
afujiwara-roblox committed Mar 5, 2024
1 parent 75deeeb commit 7c30980
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 4 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ default-members = [".", "artiaa_auth"]
[package]
name = "foreman"
description = "Toolchain manager for simple binary tools"
version = "1.5.0"
version = "1.6.0"
authors = [
"Lucien Greathouse <[email protected]>",
"Matt Hargett <[email protected]>",
Expand Down
72 changes: 72 additions & 0 deletions src/artifactory_auth_store.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use crate::error::ForemanError;
use crate::{error::ForemanResult, fs};
use artiaa_auth::{error::ArtifactoryAuthError, Credentials};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

use std::{
ops::{Deref, DerefMut},
path::Path,
};
/// Contains stored user tokens that Foreman can use to download tools.
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct ArtifactoryAuthStore {
tokens: HashMap<String, Credentials>,
}

impl Deref for ArtifactoryAuthStore {
type Target = HashMap<String, Credentials>;

fn deref(&self) -> &Self::Target {
&self.tokens
}
}

impl DerefMut for ArtifactoryAuthStore {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.tokens
}
}

impl ArtifactoryAuthStore {
pub fn set_token(auth_file: &Path, key: &str, token: &str) -> ForemanResult<()> {
let contents = fs::try_read_to_string(auth_file)?;

let mut store: ArtifactoryAuthStore = if let Some(contents) = contents {
serde_json::from_str(&contents).map_err(|err: serde_json::Error| {
ForemanError::ArtiAAError {
error: ArtifactoryAuthError::auth_parsing(auth_file, err.to_string()),
}
})?
} else {
ArtifactoryAuthStore::default()
};

store.insert(
key.to_owned(),
Credentials {
username: "".to_owned(),
token: token.to_owned(),
},
);

let serialized =
serde_json::to_string_pretty(&store).map_err(|err: serde_json::Error| {
ForemanError::ArtiAAError {
error: ArtifactoryAuthError::auth_parsing(auth_file, err.to_string()),
}
})?;

if let Some(dir) = auth_file.parent() {
fs::create_dir_all(dir)?;
fs::write(auth_file, serialized)
} else {
Err(ForemanError::ArtiAAError {
error: ArtifactoryAuthError::auth_parsing(
auth_file,
"Could not find parent directory of auth file".to_owned(),
),
})
}
}
}
62 changes: 61 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod aliaser;
mod artifact_choosing;
mod artifactory_auth_store;
mod artifactory_path;
mod auth_store;
mod ci_string;
Expand All @@ -11,8 +12,13 @@ mod process;
mod tool_cache;
mod tool_provider;

use std::{env, ffi::OsStr};
use std::{
env,
ffi::OsStr,
io::{stdout, Write},
};

use artifactory_auth_store::ArtifactoryAuthStore;
use paths::ForemanPaths;
use structopt::StructOpt;

Expand Down Expand Up @@ -153,6 +159,11 @@ enum Subcommand {
#[structopt(name = "gitlab-auth")]
GitLabAuth(GitLabAuthCommand),

/// Set the Artifactory Token that Foreman should use with the
/// Artifactory API.
#[structopt(name = "artifactory-auth")]
ArtifactoryAuth(ArtifactoryAuthCommand),

/// Create a path to publish to artifactory
///
/// Foreman does not support uploading binaries to artifactory directly, but it can generate the path where it would expect to find a given artifact. Use this command to generate paths that can be input to generic artifactory upload solutions.
Expand All @@ -176,6 +187,12 @@ struct GitLabAuthCommand {
token: Option<String>,
}

#[derive(Debug, StructOpt)]
struct ArtifactoryAuthCommand {
url: Option<String>,
token: Option<String>,
}

#[derive(Debug, StructOpt)]
struct GenerateArtifactoryPathCommand {
repo: String,
Expand Down Expand Up @@ -297,11 +314,54 @@ fn actual_main(paths: ForemanPaths) -> ForemanResult<()> {
)?;
println!("{}", artifactory_path);
}
Subcommand::ArtifactoryAuth(subcommand) => {
let url = prompt_url(subcommand.url)?;

let token = prompt_auth_token(
subcommand.token,
"Artifactory",
"https://jfrog.com/help/r/jfrog-platform-administration-documentation/access-tokens",
)?;

ArtifactoryAuthStore::set_token(&paths.artiaa_path()?, &url, &token)?;
}
}

Ok(())
}

fn prompt_url(url: Option<String>) -> Result<String, ForemanError> {
match url {
Some(url) => Ok(url),
None => {
println!("Artifactory auth saved successfully.");
println!("Foreman requires a specific URL to authenticate to Artifactory.");
println!();

loop {
let mut input = String::new();

print!("Artifactory URL: ");
stdout().flush().map_err(|err| {
ForemanError::io_error_with_context(
err,
"an error happened trying to flush stdout",
)
})?;
std::io::stdin().read_line(&mut input).map_err(|err| {
ForemanError::io_error_with_context(err, "an error happened trying to read url")
})?;

if input.is_empty() {
println!("Token must be non-empty.");
} else {
break Ok(input);
}
}
}
}
}

fn prompt_auth_token(
token: Option<String>,
provider: &str,
Expand Down
2 changes: 1 addition & 1 deletion src/tool_provider/artifactory.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Slice of GitHub's API that Foreman consumes.
//! Slice of Artifactory's API that Foreman consumes.
use super::{Release, ReleaseAsset, ToolProviderImpl};
use crate::{
Expand Down

0 comments on commit 7c30980

Please sign in to comment.