Redact work set fields (#34)

- Provide full set of `expose[..]` methods for `Secret`
- Redact serialized work unit config in logging
- Use `BlobContainerUrl` for work set setup URL
This commit is contained in:
Joe Ranweiler
2020-09-28 14:59:57 -07:00
committed by GitHub
parent 2f285f8a6f
commit d1cfa2abd6
10 changed files with 49 additions and 25 deletions

View File

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. // Copyright (c) Microsoft Corporation.
// Licensed under the MIT License. // Licensed under the MIT License.
use url::Url; use onefuzz::blob::BlobContainerUrl;
use uuid::Uuid; use uuid::Uuid;
use crate::coordinator::double::*; use crate::coordinator::double::*;
@ -68,12 +68,13 @@ impl Fixture {
} }
} }
pub fn setup_url(&self) -> Url { pub fn setup_url(&self) -> BlobContainerUrl {
"https://contoso.com/my-setup-container".parse().unwrap() let url = "https://contoso.com/my-setup-container";
BlobContainerUrl::parse(&url).unwrap()
} }
pub fn work_unit(&self) -> WorkUnit { pub fn work_unit(&self) -> WorkUnit {
let config = r#"{ "hello": "world" }"#.into(); let config = r#"{ "hello": "world" }"#.to_owned().into();
WorkUnit { WorkUnit {
job_id: self.job_id(), job_id: self.job_id(),

View File

@ -11,9 +11,17 @@ use uuid::Uuid;
pub struct Secret<T>(T); pub struct Secret<T>(T);
impl<T> Secret<T> { impl<T> Secret<T> {
pub fn expose(&self) -> &T { pub fn expose(self) -> T {
self.0
}
pub fn expose_ref(&self) -> &T {
&self.0 &self.0
} }
pub fn expose_mut(&mut self) -> &mut T {
&mut self.0
}
} }
impl<T> From<T> for Secret<T> { impl<T> From<T> for Secret<T> {
@ -28,6 +36,12 @@ impl<T> fmt::Debug for Secret<T> {
} }
} }
impl<T> fmt::Display for Secret<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<REDACTED>")
}
}
#[derive(Clone, Deserialize, Eq, PartialEq)] #[derive(Clone, Deserialize, Eq, PartialEq)]
pub struct AccessToken { pub struct AccessToken {
secret: Secret<String>, secret: Secret<String>,

View File

@ -126,7 +126,7 @@ impl Registration {
let response = reqwest::Client::new() let response = reqwest::Client::new()
.post(url.clone()) .post(url.clone())
.header("Content-Length", "0") .header("Content-Length", "0")
.bearer_auth(token.secret().expose()) .bearer_auth(token.secret().expose_ref())
.body("") .body("")
.send() .send()
.await? .await?
@ -174,7 +174,7 @@ impl Registration {
let response = reqwest::Client::new() let response = reqwest::Client::new()
.get(url) .get(url)
.bearer_auth(token.secret().expose()) .bearer_auth(token.secret().expose_ref())
.send() .send()
.await? .await?
.error_for_status()?; .error_for_status()?;

View File

@ -242,7 +242,7 @@ impl Coordinator {
let request = self let request = self
.client .client
.get(url) .get(url)
.bearer_auth(self.token.secret().expose()) .bearer_auth(self.token.secret().expose_ref())
.json(&request) .json(&request)
.build()?; .build()?;
@ -259,7 +259,7 @@ impl Coordinator {
let request = self let request = self
.client .client
.delete(url) .delete(url)
.bearer_auth(self.token.secret().expose()) .bearer_auth(self.token.secret().expose_ref())
.json(&request) .json(&request)
.build()?; .build()?;
@ -271,7 +271,7 @@ impl Coordinator {
let request = self let request = self
.client .client
.post(url) .post(url)
.bearer_auth(self.token.secret().expose()) .bearer_auth(self.token.secret().expose_ref())
.json(event) .json(event)
.build()?; .build()?;
@ -294,7 +294,7 @@ impl Coordinator {
let request = self let request = self
.client .client
.get(url) .get(url)
.bearer_auth(self.token.secret().expose()) .bearer_auth(self.token.secret().expose_ref())
.json(&task_search) .json(&task_search)
.build()?; .build()?;

View File

@ -4,6 +4,7 @@
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use onefuzz::blob::BlobContainerUrl;
use structopt::StructOpt; use structopt::StructOpt;
use url::Url; use url::Url;
use uuid::Uuid; use uuid::Uuid;
@ -136,13 +137,13 @@ fn debug_run_worker(opt: RunWorkerOpt) -> Result<()> {
}; };
let work_unit = WorkUnit { let work_unit = WorkUnit {
config, config: config.into(),
job_id: Uuid::new_v4(), job_id: Uuid::new_v4(),
task_id, task_id,
}; };
let work_set = WorkSet { let work_set = WorkSet {
reboot: false, reboot: false,
setup_url: opt.setup_url, setup_url: BlobContainerUrl::new(opt.setup_url)?,
script: opt.script, script: opt.script,
work_units: vec![work_unit], work_units: vec![work_unit],
}; };

View File

@ -7,7 +7,6 @@ use std::process::Stdio;
use anyhow::Result; use anyhow::Result;
use downcast_rs::Downcast; use downcast_rs::Downcast;
use onefuzz::az_copy; use onefuzz::az_copy;
use onefuzz::blob::BlobContainerUrl;
use tokio::fs; use tokio::fs;
use tokio::process::Command; use tokio::process::Command;
@ -40,17 +39,15 @@ impl SetupRunner {
info!("running setup for work set"); info!("running setup for work set");
// Download the setup container. // Download the setup container.
let setup_url = work_set.setup_url.clone(); let setup_url = work_set.setup_url.url();
let setup_url = BlobContainerUrl::new(setup_url)?; let setup_dir = work_set.setup_url.container();
let setup_dir = setup_url.container();
let setup_dir = onefuzz::fs::onefuzz_root()? let setup_dir = onefuzz::fs::onefuzz_root()?
.join("blob-containers") .join("blob-containers")
.join(setup_dir); .join(setup_dir);
// `azcopy sync` requires the local dir to exist. // `azcopy sync` requires the local dir to exist.
fs::create_dir_all(&setup_dir).await?; fs::create_dir_all(&setup_dir).await?;
az_copy::sync(work_set.setup_url.to_string(), &setup_dir).await?; az_copy::sync(setup_url.to_string(), &setup_dir).await?;
verbose!( verbose!(
"synced setup container from {} to {}", "synced setup container from {} to {}",

View File

@ -5,10 +5,11 @@ use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use downcast_rs::Downcast; use downcast_rs::Downcast;
use onefuzz::blob::BlobContainerUrl;
use storage_queue::QueueClient; use storage_queue::QueueClient;
use url::Url;
use uuid::Uuid; use uuid::Uuid;
use crate::auth::Secret;
use crate::config::Registration; use crate::config::Registration;
pub type JobId = Uuid; pub type JobId = Uuid;
@ -18,7 +19,7 @@ pub type TaskId = Uuid;
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct WorkSet { pub struct WorkSet {
pub reboot: bool, pub reboot: bool,
pub setup_url: Url, pub setup_url: BlobContainerUrl,
pub script: bool, pub script: bool,
pub work_units: Vec<WorkUnit>, pub work_units: Vec<WorkUnit>,
} }
@ -32,7 +33,7 @@ pub struct WorkUnit {
pub task_id: TaskId, pub task_id: TaskId,
/// JSON-serialized task config. /// JSON-serialized task config.
pub config: String, pub config: Secret<String>,
} }
impl WorkUnit { impl WorkUnit {

View File

@ -199,7 +199,7 @@ impl IWorkerRunner for WorkerRunner {
let config_path = work.config_path()?; let config_path = work.config_path()?;
fs::write(&config_path, &work.config).await?; fs::write(&config_path, work.config.expose_ref()).await?;
verbose!( verbose!(
"wrote worker config to config_path = {}", "wrote worker config to config_path = {}",

View File

@ -11,7 +11,7 @@ impl Fixture {
fn work(&self) -> WorkUnit { fn work(&self) -> WorkUnit {
let job_id = "d4e6cb4a-917e-4826-8a44-7646938c80a8".parse().unwrap(); let job_id = "d4e6cb4a-917e-4826-8a44-7646938c80a8".parse().unwrap();
let task_id = "1cfcdfe6-df10-42a5-aab7-1a45db0d0e48".parse().unwrap(); let task_id = "1cfcdfe6-df10-42a5-aab7-1a45db0d0e48".parse().unwrap();
let config = r#"{ "some": "config" }"#.to_owned(); let config = r#"{ "some": "config" }"#.to_owned().into();
WorkUnit { WorkUnit {
job_id, job_id,

View File

@ -5,7 +5,7 @@ use std::fmt;
use anyhow::Result; use anyhow::Result;
use reqwest::Url; use reqwest::Url;
use serde::de; use serde::{de, Serialize, Serializer};
#[derive(Clone, Eq, PartialEq)] #[derive(Clone, Eq, PartialEq)]
pub struct BlobUrl { pub struct BlobUrl {
@ -219,6 +219,16 @@ fn possible_blob_container_url(url: &Url) -> bool {
possible_blob_storage_url(url, true) possible_blob_storage_url(url, true)
} }
impl Serialize for BlobContainerUrl {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
let url = self.url.to_string();
serializer.serialize_str(&url)
}
}
impl<'de> de::Deserialize<'de> for BlobContainerUrl { impl<'de> de::Deserialize<'de> for BlobContainerUrl {
fn deserialize<D>(de: D) -> std::result::Result<BlobContainerUrl, D::Error> fn deserialize<D>(de: D) -> std::result::Result<BlobContainerUrl, D::Error>
where where