Skip to content
Merged
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ fireblocks-cli --help
|-------------------|-------------|--------------|----------------------------------------------------------------|-----------------------------------------------------------------------|
| `init` | ✅ | ✅ | Initialize the default configuration files | Creates `~/.config/fireblocks-cli/config.toml` and `~/.config/fireblocks-cli/keys/` |
| `gen-keys` | ✅ | ✅ | Generate Fireblocks-compatible private key and CSR | Outputs to `.config/fireblocks-cli/keys/{name}.csr`, etc. |
| `list` | n/a | n/a | List all configured profiles | Displays `[profile]` sections from `config.toml` |
| `list` | ✅ | ✅ | List all configured profiles | Displays `[profile]` sections from `config.toml` |
| `edit` | ✅ | ✅ | Open the config file in your default `$EDITOR` | Falls back to `vi` or `nano` if `$EDITOR` is not set |
| `validate` | ✅ | n/a | Validate the structure and contents of the config file | Checks for invalid or missing keys and values |
| `add` | n/a | n/a | Append a new profile to the configuration file | Will add to the bottom of the file without auto-formatting |
Expand Down
7 changes: 6 additions & 1 deletion REUSE.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
version = 1
# SPDX-FileCopyrightText: 2025 Ethersecurity Inc.
#
# SPDX-License-Identifier: MPL-2.0
# Author: Shohei KAMON <cameong@stir.network>

version = 5
[reuse]
license = "MPL-2.0"
copyright = "Ethersecurity"
Expand Down
45 changes: 45 additions & 0 deletions fireblocks_cli/commands/configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,48 @@ def edit():
except Exception as e:
typer.secho(f"❌ Validation failed: {e}", fg=typer.colors.RED)
raise typer.Exit(code=1)


@configure_app.command("list")
def list_profiles():
"""
List available profiles from config.toml and credentials (if present).
Profiles in credentials override those in config.toml.
"""
import toml
from fireblocks_cli.config import get_config_file, get_credentials_file

config_path = get_config_file()
credentials_path = get_credentials_file()

combined_data = {}

# Step 1: load config.toml
if config_path.exists():
try:
config_data = toml.load(config_path)
combined_data.update(config_data)
except Exception as e:
typer.secho(f"❌ Failed to parse config.toml: {e}", fg=typer.colors.RED)
raise typer.Exit(code=1)

# Step 2: override with credentials if it exists
if credentials_path.exists():
try:
credentials_data = toml.load(credentials_path)
combined_data.update(credentials_data) # override same keys
except Exception as e:
typer.secho(f" Failed to parse credentials: {e}", fg=typer.colors.RED)
raise typer.Exit(code=1)

if not combined_data:
typer.echo("⚠️ No profiles found in config.toml or credentials.")
return

typer.echo("📜 Available Profiles:\n")
for name, values in combined_data.items():
api_id = values.get("api_id", "<missing>")
secret_type = values.get("api_secret_key", {}).get("type", "<unknown>")
typer.echo(
f"🔹 [{name}]\n api_id: {api_id}\n secret_type: {secret_type}\n"
)
5 changes: 5 additions & 0 deletions poetry.lock.license

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

78 changes: 78 additions & 0 deletions tests/test_configure_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# SPDX-FileCopyrightText: 2025 Ethersecurity Inc.
#
# SPDX-License-Identifier: MPL-2.0
# Author: Shohei KAMON <cameong@stir.network>

import pytest
from pathlib import Path
from typer.testing import CliRunner
from fireblocks_cli.main import app

runner = CliRunner()


@pytest.fixture
def mock_home(tmp_path, monkeypatch):
"""
Redirect HOME to a temporary directory to isolate config paths.
Creates both config.toml and credentials.
"""
monkeypatch.setattr(Path, "home", lambda: tmp_path)

config_dir = tmp_path / ".config" / "fireblocks-cli"
config_dir.mkdir(parents=True, exist_ok=True)

config_toml = config_dir / "config.toml"
credentials = config_dir / "credentials"

# Write config.toml with default profile (should be overridden)
config_toml.write_text(
"""
[default]
api_id = "from-config"
api_secret_key = { type = "file", value = "config.key" }

[only_in_config]
api_id = "config-only"
api_secret_key = { type = "file", value = "config.key" }
"""
)

# Write credentials with default profile (should override) and another unique one
credentials.write_text(
"""
[default]
api_id = "from-credentials"
api_secret_key = { type = "vault", value = "vault.key" }

[only_in_credentials]
api_id = "credentials-only"
api_secret_key = { type = "vault", value = "vault.key" }
"""
)

return config_toml, credentials


def test_configure_list_merges_profiles(mock_home):
"""
Test that `configure list` merges config.toml and credentials,
and credentials override config values when profile names match.
"""
result = runner.invoke(app, ["configure", "list"])
output = result.stdout

assert result.exit_code == 0

# default should come from credentials (vault)
assert "[default]" in output
assert "api_id: from-credentials" in output
assert "secret_type: vault" in output

# config-only profile should still appear
assert "[only_in_config]" in output
assert "api_id: config-only" in output

# credentials-only profile should also appear
assert "[only_in_credentials]" in output
assert "api_id: credentials-only" in output