Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion FULL_HELP_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1179,7 +1179,9 @@ Prints the environment variables

Prints to stdout in a format that can be used as .env file. Environment variables have precedence over defaults.

Pass a name to get the value of a single environment variable.
By default, secret values are concealed. To display them, use `--reveal`.

Pass a name to get the value of a single environment variable. Its value is printed without shell quoting (control characters are neutralized), suitable for command substitution. Concealed variables print nothing unless `--reveal` is passed.

If there are no environment variables in use, prints the defaults.

Expand All @@ -1195,6 +1197,10 @@ If there are no environment variables in use, prints the defaults.

- `--config-dir <CONFIG_DIR>` — Location of config directory. By default, it uses `$XDG_CONFIG_HOME/stellar` if set, falling back to `~/.config/stellar` otherwise. Contains configuration files, aliases, and other persistent settings

###### **Options:**

- `--reveal` — Whether to reveal the value of concealed env vars. By default, concealed env vars are hidden behind a placeholder value
Comment thread
fnando marked this conversation as resolved.

## `stellar keys`

Create and manage identities including keys and addresses
Expand Down
32 changes: 32 additions & 0 deletions cmd/crates/soroban-test/tests/it/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,23 @@ fn env_does_not_display_secret_key() {
.success();
}

#[test]
fn env_does_display_secret_key_when_reveal_is_provided() {
let sandbox = TestEnv::default();
sandbox
.new_assert_cmd("env")
.arg("--reveal")
.env(
"STELLAR_SECRET_KEY",
"SDIY6AQQ75WMD4W46EYB7O6UYMHOCGQHLAQGQTKHDX4J2DYQCHVCQYFD",
)
.assert()
.stdout(predicate::str::contains(
"STELLAR_SECRET_KEY=SDIY6AQQ75WMD4W46EYB7O6UYMHOCGQHLAQGQTKHDX4J2DYQCHVCQYFD",
))
.success();
}

#[test]
fn env_single_concealed_key_returns_empty() {
let sandbox = TestEnv::default();
Expand All @@ -790,6 +807,21 @@ fn env_single_concealed_key_returns_empty() {
.success();
}

#[test]
fn env_single_is_returned_when_using_reveal() {
let sandbox = TestEnv::default();
sandbox
.new_assert_cmd("env")
.args(["STELLAR_SECRET_KEY", "--reveal"])
.env(
"STELLAR_SECRET_KEY",
"SDIY6AQQ75WMD4W46EYB7O6UYMHOCGQHLAQGQTKHDX4J2DYQCHVCQYFD",
)
.assert()
.stdout("SDIY6AQQ75WMD4W46EYB7O6UYMHOCGQHLAQGQTKHDX4J2DYQCHVCQYFD\n")
.success();
}

#[test]
fn env_does_not_display_sign_with_key() {
let sandbox = TestEnv::default();
Expand Down
34 changes: 28 additions & 6 deletions cmd/soroban-cli/src/commands/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ use crate::{
config::locator::{self},
env_vars,
print::Print,
utils::escape_control_characters,
};
use clap::Parser;
use shell_escape::escape;

#[allow(clippy::doc_markdown)]
#[derive(Debug, Parser)]
Expand All @@ -15,6 +17,11 @@ pub struct Cmd {
#[arg()]
pub name: Option<String>,

/// Whether to reveal the value of concealed env vars. By default, concealed env vars are
/// hidden behind a placeholder value.
#[arg(long)]
pub reveal: bool,
Comment thread
fnando marked this conversation as resolved.
Comment thread
fnando marked this conversation as resolved.

#[command(flatten)]
pub config_locator: locator::Args,
}
Expand All @@ -32,16 +39,20 @@ impl Cmd {
let supported = env_vars::prefixed("STELLAR");

for key in supported {
if let Some(v) = EnvVar::get(&key) {
if let Some(mut v) = EnvVar::get(&key) {
if self.reveal {
v.reveal();
}

Comment thread
fnando marked this conversation as resolved.
vars.push(v);
}
}
Comment thread
fnando marked this conversation as resolved.

// If a specific name is given, just print that one value
if let Some(name) = &self.name {
if env_vars::is_concealed(name) {
if let Some(v) = vars.iter().find(|v| &v.key == name) {
println!("{}", v.value);
if let Some(v) = vars.iter().find(|v| &v.key == name) {
if v.is_revealed() {
println!("{}", escape_control_characters(&v.value));
Comment thread
fnando marked this conversation as resolved.
}
}
Comment thread
fnando marked this conversation as resolved.

Expand Down Expand Up @@ -70,6 +81,7 @@ struct EnvVar {
key: String,
value: String,
source: String,
reveal: bool,
}

impl EnvVar {
Expand All @@ -84,15 +96,25 @@ impl EnvVar {
key: key.to_string(),
value,
source,
reveal: false,
});
}

None
}

fn reveal(&mut self) {
self.reveal = true;
}

fn is_revealed(&self) -> bool {
self.reveal || !env_vars::is_concealed(&self.key)
}

fn str(&self) -> String {
if env_vars::is_concealed(&self.key) {
format!("{}={}", self.key, self.value)
if self.is_revealed() {
let value = escape(escape_control_characters(&self.value).into());
Comment thread
fnando marked this conversation as resolved.
format!("{}={value}", self.key)
} else {
format!("# {}=<concealed>", self.key)
}
Expand Down
6 changes: 5 additions & 1 deletion cmd/soroban-cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,11 @@ pub enum Cmd {
/// Prints to stdout in a format that can be used as .env file. Environment
/// variables have precedence over defaults.
///
/// Pass a name to get the value of a single environment variable.
/// By default, secret values are concealed. To display them, use `--reveal`.
///
/// Pass a name to get the value of a single environment variable. Its value is printed without
/// shell quoting (control characters are neutralized), suitable for command substitution.
/// Concealed variables print nothing unless `--reveal` is passed.
///
/// If there are no environment variables in use, prints the defaults.
Env(env::Cmd),
Expand Down
10 changes: 4 additions & 6 deletions cmd/soroban-cli/src/env_vars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ pub fn unprefixed() -> Vec<&'static str> {
/// Unprefixed names of env vars that are safe to display in plain text.
const VISIBLE: &[&str] = &[
"ACCOUNT",
"ARCHIVE_URL",
"CONFIG_HOME",
"CONTRACT_ID",
"DATA_HOME",
Expand All @@ -41,21 +40,20 @@ const VISIBLE: &[&str] = &[
"NO_CACHE",
"NO_UPDATE_CHECK",
"OPERATION_SOURCE_ACCOUNT",
"RPC_URL",
"SEND",
"SIGN_WITH_LAB",
"SIGN_WITH_LEDGER",
];

/// Returns true if the key is one of the supported env vars that should be shown in `stellar env`.
/// Uses an allow list approach to avoid showing any env vars that are not explicitly supported,
/// even if they start with the expected prefix.
/// Returns true if the key should be concealed in `stellar env` output, i.e. it is not in the
/// allow list of vars that are safe to display. Using an allow list ensures unknown vars are
/// concealed by default, even if they start with the expected prefix.
pub fn is_concealed(key: &str) -> bool {
let name = key
.strip_prefix("STELLAR_")
.or_else(|| key.strip_prefix("SOROBAN_"))
.unwrap_or(key);
VISIBLE.contains(&name)
!VISIBLE.contains(&name)
}
Comment thread
fnando marked this conversation as resolved.

pub fn prefixed(key: &str) -> Vec<String> {
Expand Down
Loading