diff --git a/README.md b/README.md index 8344ce2..9ab0325 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ fireblocks-cli --help | `gen-keys` | ✅ | ✅ | Generate Fireblocks-compatible private key and CSR | Outputs to `.config/fireblocks-cli/keys/{name}.csr`, etc. | | `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 | +| `validate` | ✅ | ✅ | 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 | | `remove` | n/a | n/a | Remove a profile from the configuration | Deletes the corresponding section from `config.toml` | diff --git a/pyproject.toml b/pyproject.toml index 05c45ca..b07e9f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ [project] name = "fireblocks-cli" -version = "0.1.5" +version = "0.1.6" description = "An unofficial CLI for managing Fireblocks services." authors = [{ name = "Kamon Shohei", email = "cameong@stir.network" }] readme = "README.md" diff --git a/tests/test_configure_validate.py b/tests/test_configure_validate.py new file mode 100644 index 0000000..8d33d48 --- /dev/null +++ b/tests/test_configure_validate.py @@ -0,0 +1,89 @@ +# SPDX-FileCopyrightText: 2025 Ethersecurity Inc. +# +# SPDX-License-Identifier: MPL-2.0 +# Author: Shohei KAMON + +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): + """ + Set HOME to tmp path, and pre-create config dir. + """ + monkeypatch.setattr(Path, "home", lambda: tmp_path) + config_dir = tmp_path / ".config" / "fireblocks-cli" + config_dir.mkdir(parents=True, exist_ok=True) + return config_dir + + +def test_validate_with_valid_files(mock_home): + """ + Validate returns success (exit_code 0) when both config files are valid. + """ + config = mock_home / "config.toml" + credentials = mock_home / "credentials" + + config.write_text( + """ +[default] +api_id = "abc" +api_secret_key = { type = "file", value = "secret.key" } +""" + ) + + credentials.write_text( + """ +[creds] +api_id = "def" +api_secret_key = { type = "vault", value = "vaultpath" } +""" + ) + + result = runner.invoke(app, ["configure", "validate"]) + assert result.exit_code == 0 + assert "✅" in result.stdout + + +def test_validate_fails_on_invalid_config(mock_home): + """ + Should fail if config.toml is malformed. + """ + config = mock_home / "config.toml" + config.write_text("this is not toml") + + result = runner.invoke(app, ["configure", "validate"]) + assert result.exit_code == 1 + assert "❌" in result.stdout + + +def test_validate_fails_on_missing_keys(mock_home): + """ + Should fail if required keys are missing from profile. + """ + config = mock_home / "config.toml" + config.write_text( + """ +[default] +api_id = "only-id" +""" + ) + + result = runner.invoke(app, ["configure", "validate"]) + assert result.exit_code == 1 + assert "missing required keys" in result.stdout + + +def test_validate_skips_when_files_missing(tmp_path, monkeypatch): + """ + Should exit normally and skip when no config files exist. + """ + monkeypatch.setattr(Path, "home", lambda: tmp_path) + result = runner.invoke(app, ["configure", "validate"]) + assert result.exit_code == 0 + assert "not found. Skipping." in result.stdout