diff --git a/anchorecli/cli/utils.py b/anchorecli/cli/utils.py
index 34b107e..d520fb7 100644
--- a/anchorecli/cli/utils.py
+++ b/anchorecli/cli/utils.py
@@ -336,6 +336,8 @@ def format_output(config, op, params, payload):
                     obuf = obuf + t.get_string(sortby='Package')
                 elif params['query_type'] in ['manifest', 'dockerfile', 'docker_history']:
                     obuf = format_content_query(payload)
+                elif params['query_type'] in ['malware']:
+                    obuf = format_malware_scans(payload, params)
                 else:
                     try:
                         if payload['content']:
@@ -846,20 +848,13 @@ def format_output(config, op, params, payload):
         elif op in ['delete_system_service'] or re.match(".*_delete$", op) or re.match(".*_activate$", op) or re.match(".*_deactivate$", op) or re.match(".*_enable$", op) or re.match(".*_disable$", op):
             # NOTE this should always be the last in the if/elif conditional
             ret = 'Success'
-        elif op in ['analysis_archive_list']:
+        elif op in ['analysis_archive_list', 'archived_analysis']:
             header = ['Digest', 'Tags', 'Analyzed At', 'Archived At', 'Status', 'Archive Size Bytes']
             t = plain_column_table(header)
             for record in payload:
                 row = [str(record['imageDigest']), str(','.join([x['pullstring'] for x in record.get('image_detail', [])])), str(record['analyzed_at']), str(record['created_at']), str(record['status']), str(record['archive_size_bytes'])]
                 t.add_row(row)
             ret = t.get_string(sortby='Archived At', reversesort=True)+"\n"
-        elif op in ['archived_analysis']:
-            header = ['Digest', 'Tags', 'Analyzed At', 'Archived At', 'Status', 'Archive Size Bytes']
-            t = plain_column_table(header)
-            for record in payload:
-                row = [str(record['imageDigest']), str(','.join([x['pullstring'] for x in record.get('image_detail', [])])), str(record['analyzed_at']), str(record['created_at']), str(record['status']), str(record['archive_size_bytes'])]
-                t.add_row(row)
-            ret = t.get_string(sortby='Archived At', reversesort=True) + "\n"
         elif op in ['archive_analysis']:
             header = ['Image Digest', 'Archive Status', 'Details']
             t = plain_column_table(header)
@@ -907,6 +902,59 @@ def format_output(config, op, params, payload):
     return ret
 
 
+def format_malware_scans(payload, params):
+    """
+    Example response:
+    {
+        "content": [
+            {
+                "enabled": true,
+                "findings": [
+                    {
+                        "path": "/elf_payload1",
+                        "signature": "Unix.Trojan.MSShellcode-40"
+                    }
+                ],
+                "metadata": {
+                    "db_version": {
+                        "bytecode": "331",
+                        "daily": "25890",
+                        "main": "59"
+                    }
+                },
+                "name": "clamav"
+            }
+        ],
+        "content_type": "malware",
+        "imageDigest": "sha256:0eb874fcad5414762a2ca5b2496db5291aad7d3b737700d05e45af43bad3ce4d"
+    }
+
+    :param payload:
+    :param params:
+    :return:
+    """
+    obuf = ""
+
+    # Handle error
+    if 'query_type' not in params or not params['query_type']:
+        # payload will be a list with what is available as a query for the
+        # given image
+        for query in payload:
+            obuf += "%s: available\n" % query
+        return obuf + "\n"
+
+    if params['query_type'] in ['malware']:
+        header = ['Scanner', 'Matched Signature', 'Path']
+        t = plain_column_table(header)
+        for el in payload['content']:
+            scanner = el.get('name')
+            for row in [[scanner, x.get('signature', 'unknown'), x.get('path', 'unknown')] for x in el.get('findings', {})]:
+                t.add_row(row)
+        obuf = obuf + t.get_string(sortby='Path')
+
+    return obuf
+
+
 def format_vulnerabilities(payload, params):
     obuf = ""
     if 'query_type' not in params or not params['query_type']:

Malware scan output support in CLI
Add support for malware scan results in engine 0.8.0 responses

Simple table output:

|Scanner | Signature | Path
|------------|--------------|------|
clamav  | Sig1          | /usr/bin/something
clamav  | Sig2          | /usr/bin/somethingelse
scan2    | Shell.123  | /usr/bin/bash
diff --git a/tests/unit/cli/test_utils.py b/tests/unit/cli/test_utils.py
index 1839391..842e02f 100644
--- a/tests/unit/cli/test_utils.py
+++ b/tests/unit/cli/test_utils.py
@@ -1,6 +1,6 @@
 import pytest
 from anchorecli.cli import utils
-
+import prettytable
 
 class TestFormatErrorOutput:
 
@@ -151,3 +151,71 @@ class TestFormatContentQuery:
         payload = {'content': content}
         result = utils.format_content_query(payload)
         assert result == 'FROM centos7'
+
+
+class TestFormatContentMalware:
+
+    @pytest.mark.parametrize('content, expected', [({
+        "content": [
+            {
+                "enabled": True,
+                "findings": [
+                    {
+                        "path": "/elf_payload1",
+                        "signature": "Unix.Trojan.MSShellcode-40"
+                    }
+                ],
+                "metadata": {
+                    "db_version": {
+                        "bytecode": "331",
+                        "daily": "25890",
+                        "main": "59"
+                    }
+                },
+                "name": "clamav"
+            }
+        ],
+        "content_type": "malware",
+        "imageDigest": "sha256:0eb874fcad5414762a2ca5b2496db5291aad7d3b737700d05e45af43bad3ce4d"
+    }, [['clamav', "Unix.Trojan.MSShellcode-40", '/elf_payload1']]),
+    ({
+             "content": [
+                 {
+                     "enabled": True,
+                     "findings": [
+                         {
+                             "path": "/elf_payload1",
+                             "signature": "Unix.Trojan.MSShellcode-40"
+                         },
+                         {
+                             "path": "/some/dir/path/corrupted",
+                             "signature": "Unix.Trojan.MSShellcode-40"
+                         }
+
+                     ],
+                     "metadata": {
+                         "db_version": {
+                             "bytecode": "331",
+                             "daily": "25890",
+                             "main": "59"
+                         }
+                     },
+                     "name": "clamav"
+                 }
+             ],
+             "content_type": "malware",
+             "imageDigest": "sha256:0eb874fcad5414762a2ca5b2496db5291aad7d3b737700d05e45af43bad3ce4d"
+         }, [['clamav', "Unix.Trojan.MSShellcode-40", '/elf_payload1'], ['clamav', "Unix.Trojan.MSShellcode-40", '/some/dir/path/corrupted']]),
+    ({'content': []}, None)])
+    def test_scan_results(self, content, expected):
+        params = {'query_type': 'malware'}
+        result = utils.format_malware_scans(content, params)
+        assert result is not None
+        if expected:
+            t = utils.plain_column_table(['Scanner', 'Matched Signature', 'Path'])
+            for r in expected:
+                t.add_row(r)
+            assert result == t.get_string(sortby='Path')
+
+
+

pip install -e .
parse_log_pytest
requirements.txt
pytest tox
apt-get update apt-get install -y gcc
3.6
requirements.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
-e git+https://github.com/anchore/anchore-cli.git@62232d3079879960119ad43cb1b93da7f27ef396#egg=anchorecli
attrs==22.2.0
certifi==2021.5.30
chardet==3.0.4
Click==7.0
distlib==0.3.9
filelock==3.4.1
idna==2.10
importlib-metadata==4.8.3
importlib-resources==5.4.0
iniconfig==1.1.1
packaging==21.3
platformdirs==2.4.0
pluggy==1.0.0
prettytable==0.7.2
py==1.11.0
pyparsing==3.1.4
pytest==7.0.1
python-dateutil==2.8.1
PyYAML==5.3.1
requests==2.23.0
six==1.14.0
toml==0.10.2
tomli==1.2.3
tox==3.28.0
typing_extensions==4.1.1
urllib3==1.25.8
virtualenv==20.17.1
zipp==3.6.0

name: anchore-cli
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - attrs==22.2.0
      - chardet==3.0.4
      - click==7.0
      - distlib==0.3.9
      - filelock==3.4.1
      - idna==2.10
      - importlib-metadata==4.8.3
      - importlib-resources==5.4.0
      - iniconfig==1.1.1
      - packaging==21.3
      - platformdirs==2.4.0
      - pluggy==1.0.0
      - prettytable==0.7.2
      - py==1.11.0
      - pyparsing==3.1.4
      - pytest==7.0.1
      - python-dateutil==2.8.1
      - pyyaml==5.3.1
      - requests==2.23.0
      - six==1.14.0
      - toml==0.10.2
      - tomli==1.2.3
      - tox==3.28.0
      - typing-extensions==4.1.1
      - urllib3==1.25.8
      - virtualenv==20.17.1
      - zipp==3.6.0
prefix: /opt/conda/envs/anchore-cli

tests/unit/cli/test_utils.py::TestFormatContentMalware::test_scan_results[content0-expected0] tests/unit/cli/test_utils.py::TestFormatContentMalware::test_scan_results[content1-expected1] tests/unit/cli/test_utils.py::TestFormatContentMalware::test_scan_results[content2-None]
tests/unit/cli/test_utils.py::TestFormatErrorOutput::test_fails_on_invalid_json tests/unit/cli/test_utils.py::TestFormatErrorOutput::test_empty_json_fallsback tests/unit/cli/test_utils.py::TestFormatErrorOutput::test_httpcode_is_included tests/unit/cli/test_utils.py::TestFormatErrorOutput::test_message_is_included tests/unit/cli/test_utils.py::TestFormatErrorOutput::test_detail_is_included tests/unit/cli/test_utils.py::TestFormatErrorOutputJSONMode::test_loads_valid_json tests/unit/cli/test_utils.py::TestFormatErrorOutputJSONMode::test_builds_valid_json_on_failure tests/unit/cli/test_utils.py::TestFormatErrorOutputAccountDelete::test_invalid_account tests/unit/cli/test_utils.py::TestFormatErrorOutputAccountDelete::test_state_change_is_valid tests/unit/cli/test_utils.py::TestCreateHint::test_cannot_create_hint tests/unit/cli/test_utils.py::TestCreateHint::test_creates_hint tests/unit/cli/test_utils.py::TestCreateHint::test_cannot_create_hint_unquoted tests/unit/cli/test_utils.py::TestCreateHint::test_handles_non_strings[None] tests/unit/cli/test_utils.py::TestCreateHint::test_handles_non_strings[invalid_type1] tests/unit/cli/test_utils.py::TestCreateHint::test_handles_non_strings[invalid_type2] tests/unit/cli/test_utils.py::TestCreateHint::test_handles_non_strings[invalid_type3] tests/unit/cli/test_utils.py::TestCreateHint::test_handles_non_strings[1] tests/unit/cli/test_utils.py::TestCreateHint::test_handles_non_strings[True] tests/unit/cli/test_utils.py::TestCreateHint::test_handles_non_strings[False] tests/unit/cli/test_utils.py::TestFormatVulnerabilities::test_no_query_type tests/unit/cli/test_utils.py::TestFormatVulnerabilities::test_os_nonos_all_header tests/unit/cli/test_utils.py::TestFormatVulnerabilities::test_all tests/unit/cli/test_utils.py::TestFormatVulnerabilities::test_vulnerability_id_missing tests/unit/cli/test_utils.py::TestFormatContentQuery::test_no_content tests/unit/cli/test_utils.py::TestFormatContentQuery::test_content_defined_but_empty[content0] tests/unit/cli/test_utils.py::TestFormatContentQuery::test_content_defined_but_empty[] tests/unit/cli/test_utils.py::TestFormatContentQuery::test_content_defined_but_empty[None] tests/unit/cli/test_utils.py::TestFormatContentQuery::test_content_cannot_be_decoded tests/unit/cli/test_utils.py::TestFormatContentQuery::test_content_gets_decoded[RlJPTSBjZW50b3M30] tests/unit/cli/test_utils.py::TestFormatContentQuery::test_content_gets_decoded[RlJPTSBjZW50b3M31]
anchorecli/cli/utils.py
anchorecli/cli/utils.py