From 7f8e4e4d21603e45fa99ba12051ae1f100f3aa93 Mon Sep 17 00:00:00 2001 From: Avery Harnish Date: Fri, 12 Feb 2021 13:16:56 -0600 Subject: [PATCH] feat: adds useful info to logs - environment variables print with values when accessed do not print at all if they do not exist - each response from rover-client is logged - some misc. refactors/cleanup associated with the above changes --- crates/houston/src/lib.rs | 1 + crates/houston/src/profile/mod.rs | 58 ++-- crates/houston/src/profile/sensitive.rs | 3 +- crates/rover-client/src/blocking/client.rs | 12 +- installers/npm/package-lock.json | 298 ++++++++++++++++++++- src/utils/env.rs | 34 ++- 6 files changed, 361 insertions(+), 45 deletions(-) diff --git a/crates/houston/src/lib.rs b/crates/houston/src/lib.rs index 0615acf54e..22b6a42b27 100644 --- a/crates/houston/src/lib.rs +++ b/crates/houston/src/lib.rs @@ -9,6 +9,7 @@ mod profile; pub use config::Config; pub use error::HoustonProblem; +pub use profile::mask_key; /// Utilites for saving, loading, and deleting configuration profiles. pub use profile::LoadOpts; pub use profile::Profile; diff --git a/crates/houston/src/profile/mod.rs b/crates/houston/src/profile/mod.rs index e89ba1a5ed..c3b682dc6a 100644 --- a/crates/houston/src/profile/mod.rs +++ b/crates/houston/src/profile/mod.rs @@ -1,12 +1,12 @@ mod sensitive; use crate::{Config, HoustonProblem}; +use regex::Regex; use sensitive::Sensitive; use serde::{Deserialize, Serialize}; -use std::fmt; -use std::fs; use std::path::PathBuf; +use std::{fmt, fs, io}; /// Collects configuration related to a profile. #[derive(Debug, Serialize, Deserialize)] @@ -51,14 +51,20 @@ impl Profile { /// /// Takes an optional `profile` argument. Defaults to `"default"`. pub fn get_api_key(name: &str, config: &Config) -> Result { - tracing::debug!(APOLLO_KEY = ?mask_key(&config.override_api_key)); - match &config.override_api_key { + let api_key: Result = match &config.override_api_key { Some(api_key) => Ok(api_key.to_string()), None => { let opts = LoadOpts { sensitive: true }; - Ok(Profile::load(name, config, opts)?.sensitive.api_key) + let profile = Profile::load(name, config, opts)?; + Ok(profile.sensitive.api_key) } - } + }; + + let api_key = api_key?; + + tracing::debug!("using API key {}", mask_key(&api_key)); + + Ok(api_key) } /// Saves configuration options for a specific profile to the file system, @@ -89,7 +95,7 @@ impl Profile { let dir = Profile::dir(name, config); tracing::debug!(dir = ?dir); Ok(fs::remove_dir_all(dir).map_err(|e| match e.kind() { - std::io::ErrorKind::NotFound => HoustonProblem::ProfileNotFound(name.to_string()), + io::ErrorKind::NotFound => HoustonProblem::ProfileNotFound(name.to_string()), _ => HoustonProblem::IOError(e), })?) } @@ -107,7 +113,7 @@ impl Profile { let entry_path = entry?.path(); if entry_path.is_dir() { let profile = entry_path.file_stem().unwrap(); - tracing::debug!(profile = ?profile); + tracing::debug!(?profile); profiles.push(profile.to_string_lossy().into_owned()); } } @@ -122,18 +128,14 @@ impl fmt::Display for Profile { } } -// Masks all but the first 4 and last 4 chars of a key with a set number of * -// valid keys are all at least 22 chars. We don't care if invalid keys +/// Masks all but the first 4 and last 4 chars of a key with a set number of * +/// valid keys are all at least 22 chars. +// We don't care if invalid keys // are printed, so we don't need to worry about strings 8 chars or less, // which this fn would just print back out -pub fn mask_key(key: &Option) -> Option { - if let Some(key) = key { - let ex = regex::Regex::new(r"(?im)^(.{4})(.*)(.{4})$").unwrap(); - let masked = ex.replace(key, "$1******************$3").into(); - Some(masked) - } else { - None - } +pub fn mask_key(key: &str) -> String { + let ex = Regex::new(r"(?im)^(.{4})(.*)(.{4})$").expect("Could not create regular expression."); + ex.replace(key, "$1******************$3").to_string() } #[cfg(test)] @@ -143,15 +145,15 @@ mod tests { #[test] #[allow(clippy::many_single_char_names)] fn masks_valid_keys_properly() { - let a = Some("user:gh.foo:djru4788dhsg3657fhLOLO".to_string()); - assert_eq!(mask_key(&a), Some("user******************LOLO".to_string())); - let b = Some("service:foo:dh47dh27sg18aj49dkLOLO".to_string()); - assert_eq!(mask_key(&b), Some("serv******************LOLO".to_string())); - let c = Some("some nonsense".to_string()); - assert_eq!(mask_key(&c), Some("some******************ense".to_string())); - let d = Some("".to_string()); - assert_eq!(mask_key(&d), Some("".to_string())); - let e = Some("short".to_string()); - assert_eq!(mask_key(&e), Some("short".to_string())); + let a = "user:gh.foo:djru4788dhsg3657fhLOLO"; + assert_eq!(mask_key(a), "user******************LOLO".to_string()); + let b = "service:foo:dh47dh27sg18aj49dkLOLO"; + assert_eq!(mask_key(b), "serv******************LOLO".to_string()); + let c = "some nonsense"; + assert_eq!(mask_key(c), "some******************ense".to_string()); + let d = ""; + assert_eq!(mask_key(d), "".to_string()); + let e = "short"; + assert_eq!(mask_key(e), "short".to_string()); } } diff --git a/crates/houston/src/profile/sensitive.rs b/crates/houston/src/profile/sensitive.rs index 23c2f62d3f..581627f94c 100644 --- a/crates/houston/src/profile/sensitive.rs +++ b/crates/houston/src/profile/sensitive.rs @@ -1,9 +1,8 @@ use crate::{profile::Profile, Config, HoustonProblem}; use serde::{Deserialize, Serialize}; -use std::fmt; -use std::fs; use std::path::PathBuf; +use std::{fmt, fs}; /// Holds sensitive information regarding authentication. #[derive(Debug, Serialize, Deserialize)] diff --git a/crates/rover-client/src/blocking/client.rs b/crates/rover-client/src/blocking/client.rs index d94a2c8ba9..92339d1c4d 100644 --- a/crates/rover-client/src/blocking/client.rs +++ b/crates/rover-client/src/blocking/client.rs @@ -1,10 +1,11 @@ use crate::{headers, RoverClientError}; use graphql_client::GraphQLQuery; +use reqwest::blocking::{Client as ReqwestClient, Response}; use std::collections::HashMap; /// Represents a generic GraphQL client for making http requests. pub struct Client { - client: reqwest::blocking::Client, + client: ReqwestClient, uri: String, } @@ -13,7 +14,7 @@ impl Client { /// This client is used for generic GraphQL requests, such as introspection. pub fn new(uri: &str) -> Client { Client { - client: reqwest::blocking::Client::new(), + client: ReqwestClient::new(), uri: uri.to_string(), } } @@ -46,9 +47,12 @@ impl Client { /// /// If successful, it will return body.data, unwrapped pub fn handle_response( - response: reqwest::blocking::Response, + response: Response, ) -> Result { - let response_body: graphql_client::Response = response.json()?; + let response_text = response.text()?; + tracing::debug!("{}", &response_text); + let response_body: graphql_client::Response = + serde_json::from_str(&response_text)?; if let Some(errs) = response_body.errors { return Err(RoverClientError::GraphQL { diff --git a/installers/npm/package-lock.json b/installers/npm/package-lock.json index 0b5ab15185..4d398512c6 100644 --- a/installers/npm/package-lock.json +++ b/installers/npm/package-lock.json @@ -1,8 +1,304 @@ { "name": "@apollo/rover", "version": "0.0.1", - "lockfileVersion": 1, + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "@apollo/rover", + "version": "0.0.1", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "binary-install": "^0.1.1", + "console.table": "^0.10.0" + }, + "bin": { + "rover": "run.js" + }, + "devDependencies": { + "prettier": "^2.2.1" + } + }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/binary-install": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/binary-install/-/binary-install-0.1.1.tgz", + "integrity": "sha512-DqED0D/6LrS+BHDkKn34vhRqOGjy5gTMgvYZsGK2TpNbdPuz4h+MRlNgGv5QBRd7pWq/jylM4eKNCizgAq3kNQ==", + "dependencies": { + "axios": "^0.21.1", + "rimraf": "^3.0.2", + "tar": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/console.table": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/console.table/-/console.table-0.10.0.tgz", + "integrity": "sha1-CRcCVYiHW+/XDPLv9L7yxuLXXQQ=", + "dependencies": { + "easy-table": "1.1.0" + }, + "engines": { + "node": "> 0.10" + } + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "optional": true, + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/easy-table": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/easy-table/-/easy-table-1.1.0.tgz", + "integrity": "sha1-hvmrTBAvA3G3KXuSplHVgkvIy3M=", + "dependencies": { + "wcwidth": ">=1.0.1" + }, + "optionalDependencies": { + "wcwidth": ">=1.0.1" + } + }, + "node_modules/follow-redirects": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.2.tgz", + "integrity": "sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/tar": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "optional": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, "dependencies": { "axios": { "version": "0.21.1", diff --git a/src/utils/env.rs b/src/utils/env.rs index 02ac894d21..0145d79a85 100644 --- a/src/utils/env.rs +++ b/src/utils/env.rs @@ -1,6 +1,5 @@ use std::collections::HashMap; -use std::env; -use std::fmt; +use std::{env, fmt, io}; use heck::ShoutySnekCase; @@ -32,12 +31,11 @@ impl RoverEnv { } /// returns the value of the environment variable if it exists - pub fn get(&self, key: RoverEnvKey) -> std::io::Result> { - let key = key.to_string(); - tracing::debug!("reading {}", &key); - match &self.mock_store { - Some(mock_store) => Ok(mock_store.get(&key).map(|v| v.to_owned())), - None => match env::var(&key) { + pub fn get(&self, key: RoverEnvKey) -> io::Result> { + let key_str = key.to_string(); + let result = match &self.mock_store { + Some(mock_store) => Ok(mock_store.get(&key_str).map(|v| v.to_owned())), + None => match env::var(&key_str) { Ok(data) => Ok(Some(data)), Err(e) => match e { env::VarError::NotPresent => Ok(None), @@ -45,18 +43,34 @@ impl RoverEnv { std::io::ErrorKind::InvalidInput, format!( "The value of the environment variable \"{}\" is not valid Unicode.", - &key + &key_str ), )), }, }, + }?; + + if let Some(result) = &result { + tracing::debug!("read {}", self.get_debug_value(key, result)); } + + Ok(result) + } + + fn get_debug_value(&self, key: RoverEnvKey, value: &str) -> String { + let value = if let RoverEnvKey::Key = key { + houston::mask_key(value) + } else { + value.to_string() + }; + + format!("environment variable ${} = {}", key.to_string(), value) } /// sets an environment variable to a value pub fn insert(&mut self, key: RoverEnvKey, value: &str) { + tracing::debug!("writing {}", self.get_debug_value(key, value)); let key = key.to_string(); - tracing::debug!("writing {}:{}", &key, value); match &mut self.mock_store { Some(mock_store) => { mock_store.insert(key, value.into());