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
14 changes: 14 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

<!-- insertion marker -->

## [1.7.0](https://github.com/cortexapps/cli/releases/tag/1.7.0) - 2025-11-19

<small>[Compare with 1.6.0](https://github.com/cortexapps/cli/compare/1.6.0...1.7.0)</small>

## [1.6.0](https://github.com/cortexapps/cli/releases/tag/1.6.0) - 2025-11-14

<small>[Compare with 1.5.0](https://github.com/cortexapps/cli/compare/1.5.0...1.6.0)</small>

### 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

<small>[Compare with 1.4.0](https://github.com/cortexapps/cli/compare/1.4.0...1.5.0)</small>
Expand Down
4 changes: 4 additions & 0 deletions cortexapps_cli/commands/backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
8 changes: 6 additions & 2 deletions cortexapps_cli/cortex_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
40 changes: 40 additions & 0 deletions tests/test_backup.py
Original file line number Diff line number Diff line change
@@ -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"
4 changes: 2 additions & 2 deletions tests/test_config_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
1 change: 1 addition & 0 deletions tests/test_scim.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down