diff --git a/HISTORY.md b/HISTORY.md
index 238d819..28f2e86 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -6,6 +6,20 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
+
+## [1.7.0](https://github.com/cortexapps/cli/releases/tag/1.7.0) - 2025-11-19
+
+[Compare with 1.6.0](https://github.com/cortexapps/cli/compare/1.6.0...1.7.0)
+
+## [1.6.0](https://github.com/cortexapps/cli/releases/tag/1.6.0) - 2025-11-14
+
+[Compare with 1.5.0](https://github.com/cortexapps/cli/compare/1.5.0...1.6.0)
+
+### Bug Fixes
+
+- remove rate limiter initialization log message (#169) #patch ([015107a](https://github.com/cortexapps/cli/commit/015107aca15d5a4cf4eb746834bcbb7dac607e1d) by Jeff Schnitter).
+
+
## [1.5.0](https://github.com/cortexapps/cli/releases/tag/1.5.0) - 2025-11-13
[Compare with 1.4.0](https://github.com/cortexapps/cli/compare/1.4.0...1.5.0)
diff --git a/cortexapps_cli/commands/backup.py b/cortexapps_cli/commands/backup.py
index 0b39592..2c4fe9d 100644
--- a/cortexapps_cli/commands/backup.py
+++ b/cortexapps_cli/commands/backup.py
@@ -698,3 +698,7 @@ def import_tenant(
print(f"cortex scorecards create -f \"{file_path}\"")
elif import_type == "workflows":
print(f"cortex workflows create -f \"{file_path}\"")
+
+ # Exit with non-zero code if any imports failed
+ if total_failed > 0:
+ raise typer.Exit(1)
diff --git a/cortexapps_cli/cortex_client.py b/cortexapps_cli/cortex_client.py
index 9692efd..abc014f 100644
--- a/cortexapps_cli/cortex_client.py
+++ b/cortexapps_cli/cortex_client.py
@@ -156,8 +156,12 @@ def request(self, method, endpoint, params={}, headers={}, data=None, raw_body=F
print(error_str)
raise typer.Exit(code=1)
except json.JSONDecodeError:
- # if we can't parse the error message, just raise the HTTP error
- response.raise_for_status()
+ # if we can't parse the error message, print a clean error and exit
+ status = response.status_code
+ reason = response.reason or 'Unknown error'
+ error_str = f'[red][bold]HTTP Error {status}[/bold][/red]: {reason}'
+ print(error_str)
+ raise typer.Exit(code=1)
if raw_response:
return response
diff --git a/tests/test_backup.py b/tests/test_backup.py
new file mode 100644
index 0000000..be9c138
--- /dev/null
+++ b/tests/test_backup.py
@@ -0,0 +1,40 @@
+from tests.helpers.utils import *
+import os
+import tempfile
+
+def test_backup_import_invalid_api_key(monkeypatch):
+ """
+ Test that backup import exits with non-zero return code when API calls fail.
+ """
+ monkeypatch.setenv("CORTEX_API_KEY", "invalidKey")
+
+ # Create a temp directory with a catalog subdirectory and a simple yaml file
+ with tempfile.TemporaryDirectory() as tmpdir:
+ catalog_dir = os.path.join(tmpdir, "catalog")
+ os.makedirs(catalog_dir)
+
+ # Create a minimal catalog entity file
+ entity_file = os.path.join(catalog_dir, "test-entity.yaml")
+ with open(entity_file, "w") as f:
+ f.write("""
+info:
+ x-cortex-tag: test-entity
+ title: Test Entity
+ x-cortex-type: service
+""")
+
+ result = cli(["backup", "import", "-d", tmpdir], return_type=ReturnType.RAW)
+ assert result.exit_code != 0, f"backup import should exit with non-zero code on failure, got exit_code={result.exit_code}"
+
+
+def test_backup_export_invalid_api_key(monkeypatch):
+ """
+ Test that backup export exits with non-zero return code and clean error message when API calls fail.
+ """
+ monkeypatch.setenv("CORTEX_API_KEY", "invalidKey")
+
+ with tempfile.TemporaryDirectory() as tmpdir:
+ result = cli(["backup", "export", "-d", tmpdir], return_type=ReturnType.RAW)
+ assert result.exit_code != 0, f"backup export should exit with non-zero code on failure, got exit_code={result.exit_code}"
+ assert "HTTP Error 401" in result.stdout, "Should show HTTP 401 error message"
+ assert "Traceback" not in result.stdout, "Should not show Python traceback"
diff --git a/tests/test_config_file.py b/tests/test_config_file.py
index f37cc81..1f86c97 100644
--- a/tests/test_config_file.py
+++ b/tests/test_config_file.py
@@ -31,12 +31,12 @@ def test_config_file_bad_api_key(monkeypatch, tmp_path):
monkeypatch.setattr('sys.stdin', io.StringIO('y'))
f = tmp_path / "test-config-bad-api-key.txt"
response = cli(["-c", str(f), "-k", "invalidApiKey", "scorecards", "list"], return_type=ReturnType.RAW)
- assert "401 Client Error: Unauthorized" in str(response), "should get Unauthorized error"
+ assert "HTTP Error 401" in response.stdout, "should get Unauthorized error"
def test_environment_variable_invalid_key(monkeypatch):
monkeypatch.setenv("CORTEX_API_KEY", "invalidKey")
response = cli(["scorecards", "list"], return_type=ReturnType.RAW)
- assert "401 Client Error: Unauthorized" in str(response), "should get Unauthorized error"
+ assert "HTTP Error 401" in response.stdout, "should get Unauthorized error"
def test_config_file_bad_url(monkeypatch, tmp_path):
monkeypatch.delenv("CORTEX_BASE_URL")
diff --git a/tests/test_scim.py b/tests/test_scim.py
index 3215747..ed5bda7 100644
--- a/tests/test_scim.py
+++ b/tests/test_scim.py
@@ -2,6 +2,7 @@
from urllib.error import HTTPError
import pytest
+@pytest.mark.skip(reason="Disabled until CET-23082 is resolved.")
def test():
response = cli(["scim", "list"], ReturnType.STDOUT)