diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7c6d800..d494cd0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,11 +1,14 @@ name: Publish on: + workflow_dispatch: push: branches: - main paths: - 'cortexapps_cli/**' + - 'pyproject.toml' + - 'poetry.lock' env: CORTEX_API_KEY: ${{ secrets.CORTEX_API_KEY_PRODUCTION }} diff --git a/HISTORY.md b/HISTORY.md index 16f151c..9f889ec 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -6,6 +6,27 @@ 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.19.0](https://github.com/cortexapps/cli/releases/tag/1.19.0) - 2026-06-01 + +[Compare with 1.18.0](https://github.com/cortexapps/cli/compare/1.18.0...1.19.0) + +### Bug Fixes + +- resolve Python 3.14 crash from builtin list shadowing in custom_events ([95e3f79](https://github.com/cortexapps/cli/commit/95e3f7960fc02ab6299cd765bafe39946f8fa847) by Jeff Schnitter). + +## [1.18.0](https://github.com/cortexapps/cli/releases/tag/1.18.0) - 2026-06-01 + +[Compare with 1.17.0](https://github.com/cortexapps/cli/compare/1.17.0...1.18.0) + +### Features + +- add Python 3.14 support and update CI to test on 3.14 by default ([90c5654](https://github.com/cortexapps/cli/commit/90c56540c3034cb29212cbd1c06eb7a8eb4073b0) by Jeff Schnitter). + +### Bug Fixes + +- pin safety<3.8.0 to fix broken poetry audit in CI ([f706a6c](https://github.com/cortexapps/cli/commit/f706a6c0bb384f689eab7dbc14d1b0602cc62db2) by Jeff Schnitter). +- update idna to 3.17 to address CVE bypass (Dependabot #22) ([cb60c3c](https://github.com/cortexapps/cli/commit/cb60c3cbaf281b4b80e25e0d328209d300366d50) by Jeff Schnitter). + ## [1.17.0](https://github.com/cortexapps/cli/releases/tag/1.17.0) - 2026-05-20 [Compare with 1.16.0](https://github.com/cortexapps/cli/compare/1.16.0...1.17.0) diff --git a/cortexapps_cli/__init__.py b/cortexapps_cli/__init__.py index e69de29..8b13789 100644 --- a/cortexapps_cli/__init__.py +++ b/cortexapps_cli/__init__.py @@ -0,0 +1 @@ + diff --git a/cortexapps_cli/commands/custom_events.py b/cortexapps_cli/commands/custom_events.py index 9c9b969..f170341 100644 --- a/cortexapps_cli/commands/custom_events.py +++ b/cortexapps_cli/commands/custom_events.py @@ -1,6 +1,7 @@ from collections import defaultdict from datetime import datetime import json +from typing import List, Optional from rich import print_json import typer from typing_extensions import Annotated @@ -32,7 +33,7 @@ def _parse_key_value(values): def update_by_uuid( ctx: typer.Context, file_input: Annotated[typer.FileText, typer.Option("--file", "-f", help=" File containing custom event; can be passed as stdin with -, example: -f-")] = None, - custom_data: list[str] | None = typer.Option(None, "--custom", "-c", callback=_parse_key_value, help="List of optional custom metadata key=value pairs (only if file input not provided."), + custom_data: Optional[List[str]] = typer.Option(None, "--custom", "-c", callback=_parse_key_value, help="List of optional custom metadata key=value pairs (only if file input not provided."), description: str = typer.Option(None, "--description", "-d", help="The description of the custom data key (only if file input not provided)."), title: str = typer.Option(None, "--title", "-ti", help="The title of the custome event (only if file input not provided)."), tag: str = typer.Option(..., "--tag", "-t", help="The tag (x-cortex-tag) or unique, auto-generated identifier for the entity."), @@ -81,7 +82,7 @@ def update_by_uuid( def create( ctx: typer.Context, file_input: Annotated[typer.FileText, typer.Option("--file", "-f", help=" File containing custom event; can be passed as stdin with -, example: -f-")] = None, - custom_data: list[str] | None = typer.Option(None, "--custom", "-c", callback=_parse_key_value, help="List of optional custom metadata key=value pairs (only if file input not provided."), + custom_data: Optional[List[str]] = typer.Option(None, "--custom", "-c", callback=_parse_key_value, help="List of optional custom metadata key=value pairs (only if file input not provided."), description: str = typer.Option(None, "--description", "-d", help="The description of the custom data key (only if file input not provided)."), title: str = typer.Option(None, "--title", "-ti", help="The title of the custome event (only if file input not provided)."), tag: str = typer.Option(..., "--tag", "-t", help="The tag (x-cortex-tag) or unique, auto-generated identifier for the entity."), diff --git a/cortexapps_cli/commands/entity_types.py b/cortexapps_cli/commands/entity_types.py index af758c9..a2cb510 100644 --- a/cortexapps_cli/commands/entity_types.py +++ b/cortexapps_cli/commands/entity_types.py @@ -114,7 +114,6 @@ def update( def get( ctx: typer.Context, entity_type: str = typer.Option(..., "--type", "-t", help="The entity type"), - _print: CommandOptions._print = True, ): """ Retrieve entity type @@ -123,7 +122,4 @@ def get( client = ctx.obj["client"] r = client.get("api/v1/catalog/definitions/" + entity_type) - if _print: - print_json(data=r) - else: - return r + print_json(data=r) diff --git a/data/import/scorecards/cli-test-draft-scorecard.yaml b/data/import/scorecards/cli-test-draft-scorecard.yaml index 72f4e86..6705743 100644 --- a/data/import/scorecards/cli-test-draft-scorecard.yaml +++ b/data/import/scorecards/cli-test-draft-scorecard.yaml @@ -15,5 +15,5 @@ rules: weight: 1 level: You Made It filter: - query: entity_descriptor.info.`x-cortex-tag` = "cli-test-service" + query: entity.tag() == "cli-test-service" category: SERVICE diff --git a/poetry.lock b/poetry.lock index 30525da..736b113 100644 --- a/poetry.lock +++ b/poetry.lock @@ -922,7 +922,7 @@ version = "4.14.1" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" -groups = ["playwright"] +groups = ["main", "playwright"] files = [ {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"}, {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, @@ -949,4 +949,4 @@ zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [metadata] lock-version = "2.1" python-versions = "^3.11" -content-hash = "656108a410372cb006af2e0f3a6ae97ae5050e1dc014f75b92df32dde6665513" +content-hash = "1d38560a601329ebf7335f055ebbb9629a94868da642e24d8bcb40dde535acd0" diff --git a/pyproject.toml b/pyproject.toml index 0c75bc5..e0de63c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,6 +21,7 @@ requests = "^2.33.0" pyyaml = ">= 6.0.1, < 7" urllib3 = ">= 2.7.0" typer = ">=0.15,<1.0" +typing_extensions = ">=3.7.4.3" [tool.poetry.scripts] cortex = "cortexapps_cli.cli:app" diff --git a/tests/test_cortex_client.py b/tests/test_cortex_client.py new file mode 100644 index 0000000..6812f3a --- /dev/null +++ b/tests/test_cortex_client.py @@ -0,0 +1,233 @@ +import io +import logging +import pytest +import responses +import typer + +from cortexapps_cli.cortex_client import CortexClient + +BASE_URL = "https://api.test.example.com" + + +def make_client(): + return CortexClient( + api_key="test-key", + tenant="default", + numeric_level=logging.WARNING, + base_url=BASE_URL, + rate_limit=60000, + ) + + +# --------------------------------------------------------------------------- +# Task 6: Error handling paths (Lines 77-78, 162-173, 182-188) +# --------------------------------------------------------------------------- + +def test_version_fallback_when_package_not_found(): + from unittest.mock import patch + import importlib.metadata + with patch("importlib.metadata.version", side_effect=importlib.metadata.PackageNotFoundError): + client = CortexClient( + api_key="test-key", + tenant="default", + numeric_level=logging.WARNING, + base_url=BASE_URL, + rate_limit=60000, + ) + assert client.version == "unknown" + + +@responses.activate +def test_request_error_with_violations(): + client = make_client() + responses.add( + responses.GET, + f"{BASE_URL}/api/v1/test", + json={ + "violations": [ + { + "title": "Bad Field", + "description": "Field is invalid", + "violationType": "CONSTRAINT", + "pointer": "/field", + }, + { + "title": "Missing Field", + "description": "Required field missing", + }, + ] + }, + status=400, + ) + with pytest.raises(typer.Exit): + client.get("api/v1/test") + + +@responses.activate +def test_request_error_with_violations_minimal_fields(): + client = make_client() + responses.add( + responses.GET, + f"{BASE_URL}/api/v1/test", + json={ + "violations": [ + {} + ] + }, + status=400, + ) + with pytest.raises(typer.Exit): + client.get("api/v1/test") + + +@responses.activate +def test_request_error_non_json_response(): + client = make_client() + responses.add( + responses.GET, + f"{BASE_URL}/api/v1/test", + body="502 Bad Gateway", + status=502, + content_type="text/html", + ) + with pytest.raises(typer.Exit): + client.get("api/v1/test") + + +# --------------------------------------------------------------------------- +# Task 7: Response fallbacks and read_file (Lines 198-201, 310) +# --------------------------------------------------------------------------- + +@responses.activate +def test_request_ok_non_json_returns_text(): + client = make_client() + responses.add( + responses.GET, + f"{BASE_URL}/api/v1/test", + body="plain text response", + status=200, + content_type="text/plain", + ) + result = client.get("api/v1/test") + assert result == "plain text response" + + +def test_read_file(): + client = make_client() + f = io.StringIO("file contents") + assert client.read_file(f) == "file contents" + + +# --------------------------------------------------------------------------- +# Task 8: `fetch` edge cases (Lines 229, 238-240, 250) +# --------------------------------------------------------------------------- + +@responses.activate +def test_fetch_non_dict_non_list_response_breaks(): + client = make_client() + responses.add( + responses.GET, + f"{BASE_URL}/api/v1/test", + body="not json at all", + status=200, + content_type="text/plain", + ) + result = client.fetch("api/v1/test") + # When response is not dict/list, fetch breaks immediately with data_key still None. + # The return statement at line 252-257 creates {"total": 0, "page": 0, "totalPages": 0, None: []} + assert result["total"] == 0 + assert result["page"] == 0 + assert result["totalPages"] == 0 + assert None in result + assert result[None] == [] + + +@responses.activate +def test_fetch_list_response_pagination(): + client = make_client() + # First page returns items + responses.add( + responses.GET, + f"{BASE_URL}/api/v1/test", + json=[{"id": 1}, {"id": 2}], + status=200, + ) + # Second page returns empty list (signals end) + responses.add( + responses.GET, + f"{BASE_URL}/api/v1/test", + json=[], + status=200, + ) + result = client.fetch("api/v1/test") + assert result == [{"id": 1}, {"id": 2}] + + +# --------------------------------------------------------------------------- +# Task 9: Entity helper methods with team type +# (Lines 270, 274-280, 283-289, 292-298, 301-307) +# --------------------------------------------------------------------------- + +@responses.activate +def test_get_entity_team_type(): + client = make_client() + responses.add(responses.GET, f"{BASE_URL}/api/v1/teams/my-team", json={"tag": "my-team"}, status=200) + result = client.get_entity("my-team", entity_type="team") + assert result["tag"] == "my-team" + assert "/teams/" in responses.calls[0].request.url + + +@responses.activate +def test_get_entity_catalog_type(): + client = make_client() + responses.add(responses.GET, f"{BASE_URL}/api/v1/catalog/my-service", json={"tag": "my-service"}, status=200) + result = client.get_entity("my-service", entity_type="service") + assert "/catalog/" in responses.calls[0].request.url + + +@responses.activate +def test_delete_entity_team_type(): + client = make_client() + responses.add(responses.DELETE, f"{BASE_URL}/api/v1/teams/my-team", json={}, status=200) + client.delete_entity("my-team", entity_type="teams") + assert "/teams/" in responses.calls[0].request.url + + +@responses.activate +def test_delete_entity_catalog_type(): + client = make_client() + responses.add(responses.DELETE, f"{BASE_URL}/api/v1/catalog/my-service", json={}, status=200) + client.delete_entity("my-service", entity_type="service") + assert "/catalog/" in responses.calls[0].request.url + + +@responses.activate +def test_archive_entity_team_type(): + client = make_client() + responses.add(responses.PUT, f"{BASE_URL}/api/v1/teams/my-team/archive", json={}, status=200) + client.archive_entity("my-team", entity_type="team") + assert "/teams/" in responses.calls[0].request.url + + +@responses.activate +def test_archive_entity_catalog_type(): + client = make_client() + responses.add(responses.PUT, f"{BASE_URL}/api/v1/catalog/my-service/archive", json={}, status=200) + client.archive_entity("my-service", entity_type="service") + assert "/catalog/" in responses.calls[0].request.url + + +@responses.activate +def test_unarchive_entity_team_type(): + client = make_client() + responses.add(responses.PUT, f"{BASE_URL}/api/v1/teams/my-team/unarchive", json={}, status=200) + client.unarchive_entity("my-team", entity_type="team") + assert "/teams/" in responses.calls[0].request.url + + +@responses.activate +def test_unarchive_entity_catalog_type(): + client = make_client() + responses.add(responses.PUT, f"{BASE_URL}/api/v1/catalog/my-service/unarchive", json={}, status=200) + client.unarchive_entity("my-service", entity_type="service") + assert "/catalog/" in responses.calls[0].request.url diff --git a/tests/test_entity_types.py b/tests/test_entity_types.py index c5b59fd..a778614 100644 --- a/tests/test_entity_types.py +++ b/tests/test_entity_types.py @@ -16,6 +16,9 @@ def test_resource_definitions(capsys): response = cli(["entity-types", "get", "-t", "cli-test"]) assert response.get('iconTag') == "Cortex-builtin::Basketball", "iconTag should be set to Cortex-builtin::Basketball" + # Verify default columns are set when using --table output + cli(["entity-types", "list", "--table"], return_type=ReturnType.STDOUT) + cli(["entity-types", "update", "-t", "cli-test", "-f", "data/run-time/entity-type-update.json"]) diff --git a/tests/test_integrations_apiiro.py b/tests/test_integrations_apiiro.py index 91d148f..82270e8 100644 --- a/tests/test_integrations_apiiro.py +++ b/tests/test_integrations_apiiro.py @@ -57,3 +57,16 @@ def test_integrations_apiiro_validate(): def test_integrations_apiiro_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/apiiro/configuration/validate", json={}, status=200) cli(["integrations", "apiiro", "validate-all"]) + +@responses.activate +def test_integrations_apiiro_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "apiiro", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_apiiro_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/apiiro/configurations", json={}, status=200) + cli(["integrations", "apiiro", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_argocd.py b/tests/test_integrations_argocd.py index 511f9ad..f24fd41 100644 --- a/tests/test_integrations_argocd.py +++ b/tests/test_integrations_argocd.py @@ -57,3 +57,16 @@ def test_integrations_argocd_validate(): def test_integrations_argocd_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/argocd/configuration/validate", json={}, status=200) cli(["integrations", "argocd", "validate-all"]) + +@responses.activate +def test_integrations_argocd_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "argocd", "add", "-a", "test", "-h", "host", "-u", "user", "-p", "pass", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_argocd_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/argocd/configurations", json={}, status=200) + cli(["integrations", "argocd", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_azure_active_directory.py b/tests/test_integrations_azure_active_directory.py index 24e8c00..3a1b9d5 100644 --- a/tests/test_integrations_azure_active_directory.py +++ b/tests/test_integrations_azure_active_directory.py @@ -29,6 +29,28 @@ def test_integrations_azure_active_directory_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/active-directory/configuration/validate", json={}, status=200) cli(["integrations", "azure-active-directory", "validate"]) +@responses.activate +def test_integrations_azure_active_directory_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/active-directory/configuration", json={}, status=200) + cli(["integrations", "azure-active-directory", "add", "--client-id", "foo", "--client-secret", "bar", "--tenant-id", "baz"]) + +@responses.activate +def test_integrations_azure_active_directory_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "azure-active-directory", "add", "-f", str(f), "--client-id", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_azure_active_directory_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/active-directory/configuration", json={}, status=200) + cli(["integrations", "azure-active-directory", "update", "--client-id", "foo"]) + +@responses.activate +def test_integrations_azure_active_directory_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "azure-active-directory", "update", "-f", str(f), "--client-id", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_azure_active_directory_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/active-directory/configurations", json={}, status=200) diff --git a/tests/test_integrations_azure_devops.py b/tests/test_integrations_azure_devops.py index 484b49c..fd75ddd 100644 --- a/tests/test_integrations_azure_devops.py +++ b/tests/test_integrations_azure_devops.py @@ -57,3 +57,16 @@ def test_integrations_azure_devops_validate(): def test_integrations_azure_devops_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/azure-devops/configuration/validate", json={}, status=200) cli(["integrations", "azure-devops", "validate-all"]) + +@responses.activate +def test_integrations_azure_devops_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "azure-devops", "add", "-a", "test", "-h", "host", "-o", "org", "-p", "pat", "-u", "user", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_azure_devops_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/azure-devops/configurations", json={}, status=200) + cli(["integrations", "azure-devops", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_bamboohr.py b/tests/test_integrations_bamboohr.py index d04291f..faa4bac 100644 --- a/tests/test_integrations_bamboohr.py +++ b/tests/test_integrations_bamboohr.py @@ -29,6 +29,28 @@ def test_integrations_bamboohr_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/bamboohr/configuration/validate", json={}, status=200) cli(["integrations", "bamboohr", "validate"]) +@responses.activate +def test_integrations_bamboohr_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/bamboohr/configuration", json={}, status=200) + cli(["integrations", "bamboohr", "add", "--api-token", "foo", "--subdomain", "bar"]) + +@responses.activate +def test_integrations_bamboohr_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "bamboohr", "add", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_bamboohr_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/bamboohr/configuration", json={}, status=200) + cli(["integrations", "bamboohr", "update", "--api-token", "foo"]) + +@responses.activate +def test_integrations_bamboohr_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "bamboohr", "update", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_bamboohr_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/bamboohr/configurations", json={}, status=200) diff --git a/tests/test_integrations_bitbucket.py b/tests/test_integrations_bitbucket.py index c014858..593a89e 100644 --- a/tests/test_integrations_bitbucket.py +++ b/tests/test_integrations_bitbucket.py @@ -58,3 +58,17 @@ def test_integrations_bitbucket_validate(): def test_integrations_bitbucket_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/bitbucket/configuration/validate", json={}, status=200) cli(["integrations", "bitbucket", "validate-all"]) + +@responses.activate +def test_integrations_bitbucket_add_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"alias": "test", "appPassword": "pw", "username": "user"}') + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/bitbucket/configuration", json={}, status=200) + cli(["integrations", "bitbucket", "add", "-f", str(f)]) + +@responses.activate +def test_integrations_bitbucket_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/bitbucket/configurations", json={}, status=200) + cli(["integrations", "bitbucket", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_bugsnag.py b/tests/test_integrations_bugsnag.py index 5c753ef..4d579ab 100644 --- a/tests/test_integrations_bugsnag.py +++ b/tests/test_integrations_bugsnag.py @@ -29,6 +29,28 @@ def test_integrations_bugsnag_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/bugsnag/configuration/validate", json={}, status=200) cli(["integrations", "bugsnag", "validate"]) +@responses.activate +def test_integrations_bugsnag_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/bugsnag/configuration", json={}, status=200) + cli(["integrations", "bugsnag", "add", "--auth-token", "foo", "--organization-id", "bar"]) + +@responses.activate +def test_integrations_bugsnag_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "bugsnag", "add", "-f", str(f), "--auth-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_bugsnag_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/bugsnag/configuration", json={}, status=200) + cli(["integrations", "bugsnag", "update", "--auth-token", "foo"]) + +@responses.activate +def test_integrations_bugsnag_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "bugsnag", "update", "-f", str(f), "--auth-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_bugsnag_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/bugsnag/configurations", json={}, status=200) diff --git a/tests/test_integrations_buildkite.py b/tests/test_integrations_buildkite.py index 1d97c5c..40f07be 100644 --- a/tests/test_integrations_buildkite.py +++ b/tests/test_integrations_buildkite.py @@ -29,6 +29,28 @@ def test_integrations_buildkite_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/buildkite/configuration/validate", json={}, status=200) cli(["integrations", "buildkite", "validate"]) +@responses.activate +def test_integrations_buildkite_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/buildkite/configuration", json={}, status=200) + cli(["integrations", "buildkite", "add", "--api-token", "foo", "--organization-slug", "bar"]) + +@responses.activate +def test_integrations_buildkite_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "buildkite", "add", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_buildkite_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/buildkite/configuration", json={}, status=200) + cli(["integrations", "buildkite", "update", "--api-token", "foo"]) + +@responses.activate +def test_integrations_buildkite_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "buildkite", "update", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_buildkite_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/buildkite/configurations", json={}, status=200) diff --git a/tests/test_integrations_checkmarx_sast.py b/tests/test_integrations_checkmarx_sast.py index a86ad18..ba752db 100644 --- a/tests/test_integrations_checkmarx_sast.py +++ b/tests/test_integrations_checkmarx_sast.py @@ -29,6 +29,28 @@ def test_integrations_checkmarx_sast_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/checkmarx/sast/configuration/validate", json={}, status=200) cli(["integrations", "checkmarx-sast", "validate"]) +@responses.activate +def test_integrations_checkmarx_sast_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/checkmarx/sast/configuration", json={}, status=200) + cli(["integrations", "checkmarx-sast", "add", "--username", "foo", "--password", "bar"]) + +@responses.activate +def test_integrations_checkmarx_sast_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "checkmarx-sast", "add", "-f", str(f), "--username", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_checkmarx_sast_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/checkmarx/sast/configuration", json={}, status=200) + cli(["integrations", "checkmarx-sast", "update", "--username", "foo"]) + +@responses.activate +def test_integrations_checkmarx_sast_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "checkmarx-sast", "update", "-f", str(f), "--username", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_checkmarx_sast_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/checkmarx/sast/configurations", json={}, status=200) diff --git a/tests/test_integrations_circleci.py b/tests/test_integrations_circleci.py index e738404..ca43299 100644 --- a/tests/test_integrations_circleci.py +++ b/tests/test_integrations_circleci.py @@ -57,3 +57,16 @@ def test_integrations_circle_ci_validate(): def test_integrations_circle_ci_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/circleci/configuration/validate", json={}, status=200) cli(["integrations", "circleci", "validate-all"]) + +@responses.activate +def test_integrations_circleci_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "circleci", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_circleci_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/circleci/configurations", json={}, status=200) + cli(["integrations", "circleci", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_clickup.py b/tests/test_integrations_clickup.py index 8318c90..78365ef 100644 --- a/tests/test_integrations_clickup.py +++ b/tests/test_integrations_clickup.py @@ -29,6 +29,28 @@ def test_integrations_clickup_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/clickup/configuration/validate", json={}, status=200) cli(["integrations", "clickup", "validate"]) +@responses.activate +def test_integrations_clickup_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/clickup/configuration", json={}, status=200) + cli(["integrations", "clickup", "add", "--personal-api-token", "foo"]) + +@responses.activate +def test_integrations_clickup_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "clickup", "add", "-f", str(f), "--personal-api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_clickup_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/clickup/configuration", json={}, status=200) + cli(["integrations", "clickup", "update", "--personal-api-token", "foo"]) + +@responses.activate +def test_integrations_clickup_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "clickup", "update", "-f", str(f), "--personal-api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_clickup_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/clickup/configurations", json={}, status=200) diff --git a/tests/test_integrations_codecov.py b/tests/test_integrations_codecov.py index 4eb06a5..10666c6 100644 --- a/tests/test_integrations_codecov.py +++ b/tests/test_integrations_codecov.py @@ -29,6 +29,28 @@ def test_integrations_codecov_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/codecov/configuration/validate", json={}, status=200) cli(["integrations", "codecov", "validate"]) +@responses.activate +def test_integrations_codecov_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/codecov/configuration", json={}, status=200) + cli(["integrations", "codecov", "add", "--api-token", "foo"]) + +@responses.activate +def test_integrations_codecov_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "codecov", "add", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_codecov_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/codecov/configuration", json={}, status=200) + cli(["integrations", "codecov", "update", "--api-token", "foo"]) + +@responses.activate +def test_integrations_codecov_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "codecov", "update", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_codecov_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/codecov/configurations", json={}, status=200) diff --git a/tests/test_integrations_coralogix.py b/tests/test_integrations_coralogix.py index 52bcd53..5cc994f 100644 --- a/tests/test_integrations_coralogix.py +++ b/tests/test_integrations_coralogix.py @@ -57,3 +57,16 @@ def test_integrations_coralogix_validate(): def test_integrations_coralogix_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/coralogix/configuration/validate", json={}, status=200) cli(["integrations", "coralogix", "validate-all"]) + +@responses.activate +def test_integrations_coralogix_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "coralogix", "add", "-a", "test", "--api-key", "key", "-r", "US1", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_coralogix_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/coralogix/configurations", json={}, status=200) + cli(["integrations", "coralogix", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_datadog.py b/tests/test_integrations_datadog.py index bae6289..dd82d3f 100644 --- a/tests/test_integrations_datadog.py +++ b/tests/test_integrations_datadog.py @@ -57,3 +57,16 @@ def test_integrations_datadog_validate(): def test_integrations_datadog_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/datadog/configuration/validate", json={}, status=200) cli(["integrations", "datadog", "validate-all"]) + +@responses.activate +def test_integrations_datadog_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "datadog", "add", "-a", "test", "--api-key", "key", "-r", "US1", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_datadog_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/datadog/configurations", json={}, status=200) + cli(["integrations", "datadog", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_dynatrace.py b/tests/test_integrations_dynatrace.py index 5201cea..02f3985 100644 --- a/tests/test_integrations_dynatrace.py +++ b/tests/test_integrations_dynatrace.py @@ -29,6 +29,28 @@ def test_integrations_dynatrace_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/dynatrace/configuration/validate", json={}, status=200) cli(["integrations", "dynatrace", "validate"]) +@responses.activate +def test_integrations_dynatrace_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/dynatrace/configuration", json={}, status=200) + cli(["integrations", "dynatrace", "add", "--api-key", "foo", "--domain", "bar"]) + +@responses.activate +def test_integrations_dynatrace_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "dynatrace", "add", "-f", str(f), "--api-key", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_dynatrace_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/dynatrace/configuration", json={}, status=200) + cli(["integrations", "dynatrace", "update", "--api-key", "foo"]) + +@responses.activate +def test_integrations_dynatrace_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "dynatrace", "update", "-f", str(f), "--api-key", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_dynatrace_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/dynatrace/configurations", json={}, status=200) diff --git a/tests/test_integrations_firehydrant.py b/tests/test_integrations_firehydrant.py index 3597a57..47f0f0b 100644 --- a/tests/test_integrations_firehydrant.py +++ b/tests/test_integrations_firehydrant.py @@ -29,6 +29,28 @@ def test_integrations_firehydrant_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/firehydrant/configuration/validate", json={}, status=200) cli(["integrations", "firehydrant", "validate"]) +@responses.activate +def test_integrations_firehydrant_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/firehydrant/configuration", json={}, status=200) + cli(["integrations", "firehydrant", "add", "--api-token", "foo"]) + +@responses.activate +def test_integrations_firehydrant_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "firehydrant", "add", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_firehydrant_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/firehydrant/configuration", json={}, status=200) + cli(["integrations", "firehydrant", "update", "--api-token", "foo"]) + +@responses.activate +def test_integrations_firehydrant_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "firehydrant", "update", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_firehydrant_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/firehydrant/configurations", json={}, status=200) diff --git a/tests/test_integrations_github.py b/tests/test_integrations_github.py index fb4c091..69e8125 100644 --- a/tests/test_integrations_github.py +++ b/tests/test_integrations_github.py @@ -24,7 +24,7 @@ def test_integrations_github_delete_all(): @responses.activate def test_integrations_github_get(): - responses.add(responses.GET, os.getenv("CORTEX_BASE_URL") + "/api/v1/github/configuration/app/test", json={}, status=200) + responses.add(responses.GET, os.getenv("CORTEX_BASE_URL") + "/api/v1/github/configurations/app/test", json={}, status=200) cli(["integrations", "github", "get", "-a", "test"]) @responses.activate @@ -65,9 +65,21 @@ def test_integrations_github_update_personal(): @responses.activate def test_integrations_github_get_personal(): responses.add(responses.GET, os.getenv("CORTEX_BASE_URL") + "/api/v1/github/configurations/personal/test", json={}, status=200) - cli(["integrations", "github", "get", "-a", "test"]) + cli(["integrations", "github", "get-personal", "-a", "test"]) @responses.activate def test_integrations_github_delete_personal(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/github/configurations/personal/test", status=200) cli(["integrations", "github", "delete-personal", "-a", "test"]) + +@responses.activate +def test_integrations_github_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "github", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_github_add_personal_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "github", "add-personal", "-a", "test", "--access-token", "token", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 diff --git a/tests/test_integrations_gitlab.py b/tests/test_integrations_gitlab.py index 8ff6e01..e0aca41 100644 --- a/tests/test_integrations_gitlab.py +++ b/tests/test_integrations_gitlab.py @@ -57,3 +57,16 @@ def test_integrations_gitlab_validate(): def test_integrations_gitlab_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/gitlab/configuration/validate", json={}, status=200) cli(["integrations", "gitlab", "validate-all"]) + +@responses.activate +def test_integrations_gitlab_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "gitlab", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_gitlab_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/gitlab/configurations", json={}, status=200) + cli(["integrations", "gitlab", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_incidentio.py b/tests/test_integrations_incidentio.py index 325c26d..c253b1c 100644 --- a/tests/test_integrations_incidentio.py +++ b/tests/test_integrations_incidentio.py @@ -57,3 +57,16 @@ def test_integrations_incidentio_validate(): def test_integrations_incidentio_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/incidentio/configuration/validate", json={}, status=200) cli(["integrations", "incidentio", "validate-all"]) + +@responses.activate +def test_integrations_incidentio_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "incidentio", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_incidentio_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/incidentio/configurations", json={}, status=200) + cli(["integrations", "incidentio", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_instana.py b/tests/test_integrations_instana.py index d03471d..f0fafbc 100644 --- a/tests/test_integrations_instana.py +++ b/tests/test_integrations_instana.py @@ -29,6 +29,28 @@ def test_integrations_instana_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/instana/configuration/validate", json={}, status=200) cli(["integrations", "instana", "validate"]) +@responses.activate +def test_integrations_instana_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/instana/configuration", json={}, status=200) + cli(["integrations", "instana", "add", "--api-token", "foo", "--endpoint", "bar"]) + +@responses.activate +def test_integrations_instana_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "instana", "add", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_instana_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/instana/configuration", json={}, status=200) + cli(["integrations", "instana", "update", "--api-token", "foo"]) + +@responses.activate +def test_integrations_instana_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "instana", "update", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_instana_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/instana/configurations", json={}, status=200) diff --git a/tests/test_integrations_jenkins.py b/tests/test_integrations_jenkins.py index dd92cad..7c5ebc1 100644 --- a/tests/test_integrations_jenkins.py +++ b/tests/test_integrations_jenkins.py @@ -57,3 +57,16 @@ def test_integrations_jenkins_validate(): def test_integrations_jenkins_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/jenkins/configuration/validate", json={}, status=200) cli(["integrations", "jenkins", "validate-all"]) + +@responses.activate +def test_integrations_jenkins_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "jenkins", "add", "-a", "test", "--api-key", "key", "-h", "host", "-u", "user", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_jenkins_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/jenkins/configurations", json={}, status=200) + cli(["integrations", "jenkins", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_jira.py b/tests/test_integrations_jira.py index fd10595..d3508e0 100644 --- a/tests/test_integrations_jira.py +++ b/tests/test_integrations_jira.py @@ -58,3 +58,17 @@ def test_integrations_jira_validate(): def test_integrations_jira_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/jira/configuration/validate", json={}, status=200) cli(["integrations", "jira", "validate-all"]) + +@responses.activate +def test_integrations_jira_add_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"alias": "test", "email": "test@test.com", "host": "jira.test.com", "apiToken": "token"}') + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/jira/configuration", json={}, status=200) + cli(["integrations", "jira", "add", "-f", str(f)]) + +@responses.activate +def test_integrations_jira_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/jira/configurations", json={}, status=200) + cli(["integrations", "jira", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_launchdarkly.py b/tests/test_integrations_launchdarkly.py index 5657d87..a63544a 100644 --- a/tests/test_integrations_launchdarkly.py +++ b/tests/test_integrations_launchdarkly.py @@ -57,3 +57,16 @@ def test_integrations_launchdarkly_validate(): def test_integrations_launchdarkly_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/launchdarkly/configuration/validate", json={}, status=200) cli(["integrations", "launchdarkly", "validate-all"]) + +@responses.activate +def test_integrations_launchdarkly_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "launchdarkly", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_launchdarkly_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/launchdarkly/configurations", json={}, status=200) + cli(["integrations", "launchdarkly", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_mend_sast.py b/tests/test_integrations_mend_sast.py index 0087ea8..5d76895 100644 --- a/tests/test_integrations_mend_sast.py +++ b/tests/test_integrations_mend_sast.py @@ -29,6 +29,28 @@ def test_integrations_mend_sast_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/mend/sast/configuration/validate", json={}, status=200) cli(["integrations", "mend-sast", "validate"]) +@responses.activate +def test_integrations_mend_sast_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/mend/sast/configuration", json={}, status=200) + cli(["integrations", "mend-sast", "add", "--api-key", "foo"]) + +@responses.activate +def test_integrations_mend_sast_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "mend-sast", "add", "-f", str(f), "--api-key", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_mend_sast_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/mend/sast/configuration", json={}, status=200) + cli(["integrations", "mend-sast", "update", "--api-key", "foo"]) + +@responses.activate +def test_integrations_mend_sast_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "mend-sast", "update", "-f", str(f), "--api-key", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_mend_sast_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/mend/sast/configurations", json={}, status=200) diff --git a/tests/test_integrations_mend_sca.py b/tests/test_integrations_mend_sca.py index 44f1e0e..cb1c9ab 100644 --- a/tests/test_integrations_mend_sca.py +++ b/tests/test_integrations_mend_sca.py @@ -29,6 +29,28 @@ def test_integrations_mend_sca_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/mend/sca/configuration/validate", json={}, status=200) cli(["integrations", "mend-sca", "validate"]) +@responses.activate +def test_integrations_mend_sca_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/mend/sca/configuration", json={}, status=200) + cli(["integrations", "mend-sca", "add", "--org-key", "foo", "--user-key", "bar"]) + +@responses.activate +def test_integrations_mend_sca_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "mend-sca", "add", "-f", str(f), "--org-key", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_mend_sca_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/mend/sca/configuration", json={}, status=200) + cli(["integrations", "mend-sca", "update", "--org-key", "foo"]) + +@responses.activate +def test_integrations_mend_sca_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "mend-sca", "update", "-f", str(f), "--org-key", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_mend_sca_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/mend/sca/configurations", json={}, status=200) diff --git a/tests/test_integrations_newrelic.py b/tests/test_integrations_newrelic.py index 0af6040..0f702d3 100644 --- a/tests/test_integrations_newrelic.py +++ b/tests/test_integrations_newrelic.py @@ -86,3 +86,17 @@ def test_integrations_newrelic_validate(): def test_integrations_newrelic_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/newrelic/configuration/validate", json={}, status=200) cli(["integrations", "newrelic", "validate-all"]) + +@responses.activate +def test_integrations_newrelic_add_file_with_flags_error(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"alias": "test"}') + result = cli(["integrations", "newrelic", "add", "-a", "test", "--account-id", "123", "--personal-key", "NRAK-key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_newrelic_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/newrelic/configurations", json={}, status=200) + cli(["integrations", "newrelic", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_okta.py b/tests/test_integrations_okta.py index 2633233..d6ef0ec 100644 --- a/tests/test_integrations_okta.py +++ b/tests/test_integrations_okta.py @@ -29,6 +29,28 @@ def test_integrations_okta_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/okta/configuration/validate", json={}, status=200) cli(["integrations", "okta", "validate"]) +@responses.activate +def test_integrations_okta_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/okta/configuration", json={}, status=200) + cli(["integrations", "okta", "add", "--api-token", "foo", "--domain", "bar"]) + +@responses.activate +def test_integrations_okta_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "okta", "add", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_okta_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/okta/configuration", json={}, status=200) + cli(["integrations", "okta", "update", "--api-token", "foo"]) + +@responses.activate +def test_integrations_okta_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "okta", "update", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_okta_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/okta/configurations", json={}, status=200) diff --git a/tests/test_integrations_opsgenie.py b/tests/test_integrations_opsgenie.py index 9165c50..234618e 100644 --- a/tests/test_integrations_opsgenie.py +++ b/tests/test_integrations_opsgenie.py @@ -29,6 +29,28 @@ def test_integrations_opsgenie_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/opsgenie/configuration/validate", json={}, status=200) cli(["integrations", "opsgenie", "validate"]) +@responses.activate +def test_integrations_opsgenie_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/opsgenie/configuration", json={}, status=200) + cli(["integrations", "opsgenie", "add", "--api-token", "foo", "--subdomain", "bar"]) + +@responses.activate +def test_integrations_opsgenie_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "opsgenie", "add", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_opsgenie_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/opsgenie/configuration", json={}, status=200) + cli(["integrations", "opsgenie", "update", "--api-token", "foo"]) + +@responses.activate +def test_integrations_opsgenie_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "opsgenie", "update", "-f", str(f), "--api-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_opsgenie_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/opsgenie/configurations", json={}, status=200) diff --git a/tests/test_integrations_pagerduty.py b/tests/test_integrations_pagerduty.py index 7c5271d..4a5caf2 100644 --- a/tests/test_integrations_pagerduty.py +++ b/tests/test_integrations_pagerduty.py @@ -57,3 +57,16 @@ def test_integrations_circle_ci_validate(): def test_integrations_circle_ci_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/pagerduty/configuration/validate", json={}, status=200) cli(["integrations", "pagerduty", "validate-all"]) + +@responses.activate +def test_integrations_pagerduty_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "pagerduty", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_pagerduty_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/pagerduty/configurations", json={}, status=200) + cli(["integrations", "pagerduty", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_prometheus.py b/tests/test_integrations_prometheus.py index 3061d24..3b6e7e9 100644 --- a/tests/test_integrations_prometheus.py +++ b/tests/test_integrations_prometheus.py @@ -57,3 +57,16 @@ def test_integrations_prometheus_validate(): def test_integrations_prometheus_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/prometheus/configuration/validate", json={}, status=200) cli(["integrations", "prometheus", "validate-all"]) + +@responses.activate +def test_integrations_prometheus_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "prometheus", "add", "-a", "test", "-h", "host", "--username", "user", "--password", "pass", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_prometheus_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/prometheus/configurations", json={}, status=200) + cli(["integrations", "prometheus", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_rollbar.py b/tests/test_integrations_rollbar.py index 9e06ac6..e392a9a 100644 --- a/tests/test_integrations_rollbar.py +++ b/tests/test_integrations_rollbar.py @@ -29,6 +29,28 @@ def test_integrations_rollbar_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/rollbar/configuration/validate", json={}, status=200) cli(["integrations", "rollbar", "validate"]) +@responses.activate +def test_integrations_rollbar_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/rollbar/configuration", json={}, status=200) + cli(["integrations", "rollbar", "add", "--access-token", "foo", "--organization-slug", "bar"]) + +@responses.activate +def test_integrations_rollbar_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "rollbar", "add", "-f", str(f), "--access-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_rollbar_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/rollbar/configuration", json={}, status=200) + cli(["integrations", "rollbar", "update", "--access-token", "foo"]) + +@responses.activate +def test_integrations_rollbar_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "rollbar", "update", "-f", str(f), "--access-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_rollbar_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/rollbar/configurations", json={}, status=200) diff --git a/tests/test_integrations_rootly.py b/tests/test_integrations_rootly.py index 5cf8f5a..cb870a1 100644 --- a/tests/test_integrations_rootly.py +++ b/tests/test_integrations_rootly.py @@ -57,3 +57,16 @@ def test_integrations_rootly_validate(): def test_integrations_rootly_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/rootly/configuration/validate", json={}, status=200) cli(["integrations", "rootly", "validate-all"]) + +@responses.activate +def test_integrations_rootly_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "rootly", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_rootly_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/rootly/configurations", json={}, status=200) + cli(["integrations", "rootly", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_semgrep.py b/tests/test_integrations_semgrep.py index bd49158..723091f 100644 --- a/tests/test_integrations_semgrep.py +++ b/tests/test_integrations_semgrep.py @@ -57,3 +57,16 @@ def test_integrations_semgrep_validate(): def test_integrations_semgrep_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/semgrep/configuration/validate", json={}, status=200) cli(["integrations", "semgrep", "validate-all"]) + +@responses.activate +def test_integrations_semgrep_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "semgrep", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_semgrep_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/semgrep/configurations", json={}, status=200) + cli(["integrations", "semgrep", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_sentry.py b/tests/test_integrations_sentry.py index d9e0fb1..6591e1f 100644 --- a/tests/test_integrations_sentry.py +++ b/tests/test_integrations_sentry.py @@ -29,6 +29,28 @@ def test_integrations_sentry_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/sentry/configuration/validate", json={}, status=200) cli(["integrations", "sentry", "validate"]) +@responses.activate +def test_integrations_sentry_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/sentry/configuration", json={}, status=200) + cli(["integrations", "sentry", "add", "--auth-token", "foo", "--organization-slug", "bar"]) + +@responses.activate +def test_integrations_sentry_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "sentry", "add", "-f", str(f), "--auth-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_sentry_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/sentry/configuration", json={}, status=200) + cli(["integrations", "sentry", "update", "--auth-token", "foo"]) + +@responses.activate +def test_integrations_sentry_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "sentry", "update", "-f", str(f), "--auth-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_sentry_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/sentry/configurations", json={}, status=200) diff --git a/tests/test_integrations_servicenow.py b/tests/test_integrations_servicenow.py index bf94756..08d470c 100644 --- a/tests/test_integrations_servicenow.py +++ b/tests/test_integrations_servicenow.py @@ -29,6 +29,28 @@ def test_integrations_servicenow_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/servicenow/configuration/validate", json={}, status=200) cli(["integrations", "servicenow", "validate"]) +@responses.activate +def test_integrations_servicenow_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/servicenow/configuration", json={}, status=200) + cli(["integrations", "servicenow", "add", "--instance-name", "foo", "--password", "bar", "--username", "baz"]) + +@responses.activate +def test_integrations_servicenow_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "servicenow", "add", "-f", str(f), "--instance-name", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_servicenow_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/servicenow/configuration", json={}, status=200) + cli(["integrations", "servicenow", "update", "--instance-name", "foo"]) + +@responses.activate +def test_integrations_servicenow_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "servicenow", "update", "-f", str(f), "--instance-name", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_servicenow_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/servicenow/configurations", json={}, status=200) diff --git a/tests/test_integrations_servicenow_cloud_observability.py b/tests/test_integrations_servicenow_cloud_observability.py index 59f9b1b..3ad899a 100644 --- a/tests/test_integrations_servicenow_cloud_observability.py +++ b/tests/test_integrations_servicenow_cloud_observability.py @@ -29,6 +29,28 @@ def test_integrations_servicenow_cloud_observability_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/lightstep/configuration/validate", json={}, status=200) cli(["integrations", "servicenow-cloud-observability", "validate"]) +@responses.activate +def test_integrations_servicenow_cloud_observability_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/lightstep/configuration", json={}, status=200) + cli(["integrations", "servicenow-cloud-observability", "add", "--auth-token", "foo", "--organization-id", "bar", "--project-id", "baz"]) + +@responses.activate +def test_integrations_servicenow_cloud_observability_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "servicenow-cloud-observability", "add", "-f", str(f), "--auth-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_servicenow_cloud_observability_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/lightstep/configuration", json={}, status=200) + cli(["integrations", "servicenow-cloud-observability", "update", "--auth-token", "foo"]) + +@responses.activate +def test_integrations_servicenow_cloud_observability_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "servicenow-cloud-observability", "update", "-f", str(f), "--auth-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_servicenow_cloud_observability_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/lightstep/configurations", json={}, status=200) diff --git a/tests/test_integrations_snyk.py b/tests/test_integrations_snyk.py index 9eeff7d..ad8240f 100644 --- a/tests/test_integrations_snyk.py +++ b/tests/test_integrations_snyk.py @@ -29,6 +29,28 @@ def test_integrations_snyk_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/snyk/configuration/validate", json={}, status=200) cli(["integrations", "snyk", "validate"]) +@responses.activate +def test_integrations_snyk_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/snyk/configuration", json={}, status=200) + cli(["integrations", "snyk", "add", "--auth-token", "foo", "--region", "USA"]) + +@responses.activate +def test_integrations_snyk_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "snyk", "add", "-f", str(f), "--auth-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_snyk_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/snyk/configuration", json={}, status=200) + cli(["integrations", "snyk", "update", "--auth-token", "foo"]) + +@responses.activate +def test_integrations_snyk_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "snyk", "update", "-f", str(f), "--auth-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_snyk_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/snyk/configurations", json={}, status=200) diff --git a/tests/test_integrations_sonarqube.py b/tests/test_integrations_sonarqube.py index 9195582..dafd6d4 100644 --- a/tests/test_integrations_sonarqube.py +++ b/tests/test_integrations_sonarqube.py @@ -78,3 +78,17 @@ def test_integrations_sonarqube_validate(): def test_integrations_sonarqube_validate_all(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/sonarqube/configuration/validate", json={}, status=200) cli(["integrations", "sonarqube", "validate-all"]) + +@responses.activate +def test_integrations_sonarqube_add_file_with_flags_error(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"alias": "test"}') + result = cli(["integrations", "sonarqube", "add", "-a", "test", "--api-key", "key", "-f", str(f)], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_sonarqube_add_multiple_valid(tmp_path): + f = tmp_path / "valid.json" + f.write_text('{"configurations": []}') + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/sonarqube/configurations", json={}, status=200) + cli(["integrations", "sonarqube", "add-multiple", "-f", str(f)]) diff --git a/tests/test_integrations_splunk_observability_cloud.py b/tests/test_integrations_splunk_observability_cloud.py index 8260a72..c9972c8 100644 --- a/tests/test_integrations_splunk_observability_cloud.py +++ b/tests/test_integrations_splunk_observability_cloud.py @@ -29,6 +29,28 @@ def test_integrations_splunk_observability_cloud_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/signalfx/configuration/validate", json={}, status=200) cli(["integrations", "splunk-observability-cloud", "validate"]) +@responses.activate +def test_integrations_splunk_observability_cloud_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/signalfx/configuration", json={}, status=200) + cli(["integrations", "splunk-observability-cloud", "add", "--access-token", "foo", "--realm", "bar"]) + +@responses.activate +def test_integrations_splunk_observability_cloud_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "splunk-observability-cloud", "add", "-f", str(f), "--access-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_splunk_observability_cloud_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/signalfx/configuration", json={}, status=200) + cli(["integrations", "splunk-observability-cloud", "update", "--access-token", "foo"]) + +@responses.activate +def test_integrations_splunk_observability_cloud_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "splunk-observability-cloud", "update", "-f", str(f), "--access-token", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_splunk_observability_cloud_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/signalfx/configurations", json={}, status=200) diff --git a/tests/test_integrations_splunk_on_call.py b/tests/test_integrations_splunk_on_call.py index 2a421c1..2d6bd86 100644 --- a/tests/test_integrations_splunk_on_call.py +++ b/tests/test_integrations_splunk_on_call.py @@ -29,6 +29,28 @@ def test_integrations_splunk_on_call_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/victorops/configuration/validate", json={}, status=200) cli(["integrations", "splunk-on-call", "validate"]) +@responses.activate +def test_integrations_splunk_on_call_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/victorops/configuration", json={}, status=200) + cli(["integrations", "splunk-on-call", "add", "--api-id", "foo", "--api-key", "bar", "--organization", "baz"]) + +@responses.activate +def test_integrations_splunk_on_call_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "splunk-on-call", "add", "-f", str(f), "--api-id", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_splunk_on_call_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/victorops/configuration", json={}, status=200) + cli(["integrations", "splunk-on-call", "update", "--api-id", "foo"]) + +@responses.activate +def test_integrations_splunk_on_call_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "splunk-on-call", "update", "-f", str(f), "--api-id", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_splunk_on_call_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/victorops/configurations", json={}, status=200) diff --git a/tests/test_integrations_sumologic.py b/tests/test_integrations_sumologic.py index 2f7db9c..7ef3f4a 100644 --- a/tests/test_integrations_sumologic.py +++ b/tests/test_integrations_sumologic.py @@ -29,6 +29,28 @@ def test_integrations_sumologic_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/sumologic/configuration/validate", json={}, status=200) cli(["integrations", "sumo-logic", "validate"]) +@responses.activate +def test_integrations_sumologic_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/sumologic/configuration", json={}, status=200) + cli(["integrations", "sumo-logic", "add", "--access-id", "foo", "--access-key", "bar", "--deployment", "baz"]) + +@responses.activate +def test_integrations_sumologic_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "sumo-logic", "add", "-f", str(f), "--access-id", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_sumologic_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/sumologic/configuration", json={}, status=200) + cli(["integrations", "sumo-logic", "update", "--access-id", "foo"]) + +@responses.activate +def test_integrations_sumologic_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "sumo-logic", "update", "-f", str(f), "--access-id", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_sumologic_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/sumologic/configurations", json={}, status=200) diff --git a/tests/test_integrations_veracode.py b/tests/test_integrations_veracode.py index 8b5a731..b1379c4 100644 --- a/tests/test_integrations_veracode.py +++ b/tests/test_integrations_veracode.py @@ -29,6 +29,28 @@ def test_integrations_veracode_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/veracode/configuration/validate", json={}, status=200) cli(["integrations", "veracode", "validate"]) +@responses.activate +def test_integrations_veracode_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/veracode/configuration", json={}, status=200) + cli(["integrations", "veracode", "add", "--api-key", "foo", "--key-id", "bar", "--region", "baz"]) + +@responses.activate +def test_integrations_veracode_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "veracode", "add", "-f", str(f), "--api-key", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_veracode_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/veracode/configuration", json={}, status=200) + cli(["integrations", "veracode", "update", "--api-key", "foo"]) + +@responses.activate +def test_integrations_veracode_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "veracode", "update", "-f", str(f), "--api-key", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_veracode_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/veracode/configurations", json={}, status=200) diff --git a/tests/test_integrations_wiz.py b/tests/test_integrations_wiz.py index 886568b..25bb4f1 100644 --- a/tests/test_integrations_wiz.py +++ b/tests/test_integrations_wiz.py @@ -29,6 +29,28 @@ def test_integrations_wiz_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/wiz/configuration/validate", json={}, status=200) cli(["integrations", "wiz", "validate"]) +@responses.activate +def test_integrations_wiz_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/wiz/configuration", json={}, status=200) + cli(["integrations", "wiz", "add", "--client-id", "foo", "--client-secret", "bar", "--data-center", "baz", "--identity-provider", "qux"]) + +@responses.activate +def test_integrations_wiz_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "wiz", "add", "-f", str(f), "--client-id", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_wiz_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/wiz/configuration", json={}, status=200) + cli(["integrations", "wiz", "update", "--client-id", "foo"]) + +@responses.activate +def test_integrations_wiz_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "wiz", "update", "-f", str(f), "--client-id", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_wiz_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/wiz/configurations", json={}, status=200) diff --git a/tests/test_integrations_workday.py b/tests/test_integrations_workday.py index c9957ee..5025c79 100644 --- a/tests/test_integrations_workday.py +++ b/tests/test_integrations_workday.py @@ -29,6 +29,28 @@ def test_integrations_workday_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/workday/configuration/validate", json={}, status=200) cli(["integrations", "workday", "validate"]) +@responses.activate +def test_integrations_workday_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/workday/configuration", json={}, status=200) + cli(["integrations", "workday", "add", "--username", "foo", "--password", "bar", "--ownership-report-url", "baz"]) + +@responses.activate +def test_integrations_workday_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "workday", "add", "-f", str(f), "--username", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_workday_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/workday/configuration", json={}, status=200) + cli(["integrations", "workday", "update", "--username", "foo"]) + +@responses.activate +def test_integrations_workday_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "workday", "update", "-f", str(f), "--username", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_workday_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/workday/configurations", json={}, status=200) diff --git a/tests/test_integrations_xmatters.py b/tests/test_integrations_xmatters.py index 12e23a5..ceee629 100644 --- a/tests/test_integrations_xmatters.py +++ b/tests/test_integrations_xmatters.py @@ -29,6 +29,28 @@ def test_integrations_xmatters_validate(): responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/xmatters/configuration/validate", json={}, status=200) cli(["integrations", "xmatters", "validate"]) +@responses.activate +def test_integrations_xmatters_add_with_flags(): + responses.add(responses.POST, os.getenv("CORTEX_BASE_URL") + "/api/v1/xmatters/configuration", json={}, status=200) + cli(["integrations", "xmatters", "add", "--organization-slug", "foo", "--password", "bar", "--username", "baz"]) + +@responses.activate +def test_integrations_xmatters_add_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "xmatters", "add", "-f", str(f), "--organization-slug", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + +@responses.activate +def test_integrations_xmatters_update_with_flags(): + responses.add(responses.PUT, os.getenv("CORTEX_BASE_URL") + "/api/v1/xmatters/configuration", json={}, status=200) + cli(["integrations", "xmatters", "update", "--organization-slug", "foo"]) + +@responses.activate +def test_integrations_xmatters_update_file_with_flags_error(tmp_path): + f = _dummy_file(tmp_path) + result = cli(["integrations", "xmatters", "update", "-f", str(f), "--organization-slug", "foo"], return_type=ReturnType.RAW) + assert result.exit_code != 0 + @responses.activate def test_integrations_xmatters_delete(): responses.add(responses.DELETE, os.getenv("CORTEX_BASE_URL") + "/api/v1/xmatters/configurations", json={}, status=200) diff --git a/tests/test_scim.py b/tests/test_scim.py index ed5bda7..354cba6 100644 --- a/tests/test_scim.py +++ b/tests/test_scim.py @@ -2,7 +2,7 @@ from urllib.error import HTTPError import pytest -@pytest.mark.skip(reason="Disabled until CET-23082 is resolved.") +#@pytest.mark.skip(reason="Disabled until CET-23082 is resolved.") def test(): response = cli(["scim", "list"], ReturnType.STDOUT) diff --git a/tests/test_secrets.py b/tests/test_secrets.py index 6145c21..18fd56f 100644 --- a/tests/test_secrets.py +++ b/tests/test_secrets.py @@ -34,6 +34,13 @@ def test(): response = cli(["secrets", "get", "-t", "cli_test_secret"]) assert response['name'] == 'Updated CLI Test Secret', "Should have updated name" + # Verify table output with default columns + cli(["secrets", "list", "--table"], return_type=ReturnType.STDOUT) + + # Verify list with explicit page + response = cli(["secrets", "list", "-p", "0"]) + assert 'secrets' in response, "Should return secrets with explicit page" + # Delete the secret cli(["secrets", "delete", "-t", "cli_test_secret"]) diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 0000000..0becd9d --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,224 @@ +import pytest +import typer +from unittest.mock import MagicMock +from cortexapps_cli.utils import ( + guess_data_key, + get_value_at_path, + matches_filters, + humanize_value, + print_output, + print_output_with_context, +) + + +# Task 1: guess_data_key edge cases (Lines 25, 31, 34, 38) + +def test_guess_data_key_list_returns_empty_string(): + assert guess_data_key([1, 2, 3]) == '' + + +def test_guess_data_key_dict_no_list_raises(): + with pytest.raises(ValueError, match="does not contain a list"): + guess_data_key({"key": "value"}) + + +def test_guess_data_key_dict_multiple_lists_raises(): + with pytest.raises(ValueError, match="contains multiple lists"): + guess_data_key({"a": [1], "b": [2]}) + + +def test_guess_data_key_non_list_non_dict_raises(): + with pytest.raises(ValueError, match="is not a list or dict"): + guess_data_key("a string") + + +# Task 2: get_value_at_path edge cases (Lines 58-62, 64-65) + +def test_get_value_at_path_list_index(): + data = {"items": [{"name": "first"}, {"name": "second"}]} + assert get_value_at_path(data, "items.1.name") == "second" + + +def test_get_value_at_path_non_dict_non_list_returns_none(): + data = {"key": 42} + assert get_value_at_path(data, "key.nested") is None + + +def test_get_value_at_path_invalid_list_index_returns_none(): + data = {"items": [1, 2]} + assert get_value_at_path(data, "items.abc") is None + + +def test_get_value_at_path_index_out_of_range_returns_none(): + data = {"items": [1]} + assert get_value_at_path(data, "items.99") is None + + +# Task 3: matches_filters and humanize_value (Lines 80-87, 102, 104) + +def test_matches_filters_matching(): + data = {"name": "foo", "status": "active"} + assert matches_filters(data, ["name=foo"]) is True + + +def test_matches_filters_no_match(): + data = {"name": "foo"} + assert matches_filters(data, ["name=bar"]) is False + + +def test_matches_filters_missing_key(): + data = {"name": "foo"} + assert matches_filters(data, ["missing=.*"]) is False + + +def test_matches_filters_multiple_all_match(): + data = {"name": "foo", "status": "active"} + assert matches_filters(data, ["name=foo", "status=active"]) is True + + +def test_matches_filters_multiple_one_fails(): + data = {"name": "foo", "status": "active"} + assert matches_filters(data, ["name=foo", "status=inactive"]) is False + + +def test_humanize_value_list(): + assert humanize_value(["a", "b", "c"]) == "a, b, c" + + +def test_humanize_value_dict(): + result = humanize_value({"key": "val"}) + assert '"key": "val"' in result + + +def test_humanize_value_none(): + assert humanize_value(None) == "" + + +def test_humanize_value_string(): + assert humanize_value("hello") == "hello" + + +# Task 4: print_output table/csv/sort/filter paths + +def test_print_output_none_format_defaults_to_json(capsys): + print_output({"key": "val"}, output_format=None) + out = capsys.readouterr().out + assert "key" in out + + +def test_print_output_invalid_format_raises(): + with pytest.raises(ValueError, match="Invalid output format"): + print_output({}, output_format="xml") + + +def test_print_output_json_with_columns_raises(): + with pytest.raises(typer.BadParameter, match="Columns can only be specified"): + print_output({"items": [{"a": 1}]}, columns=["a"], output_format="json") + + +def test_print_output_json_with_filters_raises(): + with pytest.raises(typer.BadParameter, match="Filters can only be specified"): + print_output({"items": [{"a": 1}]}, filters=["a=1"], output_format="json") + + +def test_print_output_table_no_columns_raises(): + with pytest.raises(typer.BadParameter, match="Columns must be specified"): + print_output({"items": [{"a": 1}]}, output_format="table") + + +def test_print_output_table_shorthand_column(capsys): + data = {"items": [{"name": "foo"}, {"name": "bar"}]} + print_output(data, columns=["name"], output_format="table") + out = capsys.readouterr().out + assert "foo" in out + assert "bar" in out + + +def test_print_output_table_invalid_column_format_raises(): + data = {"items": [{"a": 1}]} + with pytest.raises(typer.BadParameter, match="Columns must be in the format"): + print_output(data, columns=["!!!invalid"], output_format="table") + + +def test_print_output_table_with_filters(capsys): + data = {"items": [{"name": "foo", "status": "active"}, {"name": "bar", "status": "inactive"}]} + print_output(data, columns=["Name=name"], filters=["status=active"], output_format="table") + out = capsys.readouterr().out + assert "foo" in out + assert "bar" not in out + + +def test_print_output_table_invalid_filter_raises(): + data = {"items": [{"a": 1}]} + with pytest.raises(typer.BadParameter, match="Filters must be in the format"): + print_output(data, columns=["a"], filters=["!!!"], output_format="table") + + +def test_print_output_table_sort_asc(capsys): + data = {"items": [{"name": "b"}, {"name": "a"}]} + print_output(data, columns=["name"], sort=["name:asc"], output_format="table") + out = capsys.readouterr().out + assert out.index("a") < out.index("b") + + +def test_print_output_table_sort_desc(capsys): + data = {"items": [{"name": "zebra"}, {"name": "apple"}]} + print_output(data, columns=["name"], sort=["name:desc"], output_format="table") + out = capsys.readouterr().out + assert out.index("zebra") < out.index("apple") + + +def test_print_output_table_invalid_sort_raises(): + data = {"items": [{"a": 1}]} + with pytest.raises(typer.BadParameter, match="Sort must be in the format"): + print_output(data, columns=["a"], sort=["bad_sort"], output_format="table") + + +def test_print_output_csv(capsys): + data = {"items": [{"name": "foo"}, {"name": "bar"}]} + print_output(data, columns=["Name=name"], output_format="csv") + out = capsys.readouterr().out + lines = out.strip().split("\n") + assert lines[0] == "Name" + assert lines[1] == "foo" + assert lines[2] == "bar" + + +def test_print_output_csv_no_headers(capsys): + data = {"items": [{"name": "foo"}]} + print_output(data, columns=["Name=name"], output_format="csv", no_headers=True) + out = capsys.readouterr().out + lines = out.strip().split("\n") + assert lines[0] == "foo" + assert "Name" not in out + + +# Task 5: print_output_with_context (Lines 195, 199) + +def test_print_output_with_context_table_and_csv_raises(): + ctx = MagicMock() + ctx.params = { + "columns": ["name"], + "filters": None, + "sort": None, + "table_output": True, + "csv_output": True, + "no_headers": False, + } + with pytest.raises(typer.BadParameter, match="Only one of --table and --csv"): + print_output_with_context(ctx, {"items": [{"name": "foo"}]}) + + +def test_print_output_with_context_csv(capsys): + ctx = MagicMock() + ctx.params = { + "columns": ["Name=name"], + "filters": None, + "sort": None, + "table_output": False, + "csv_output": True, + "no_headers": False, + } + print_output_with_context(ctx, {"items": [{"name": "foo"}]}) + out = capsys.readouterr().out + assert "foo" in out