Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ on:
jobs:
build:

runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
Expand Down
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
1.12.0
-----
- Add command aliases with dashes (e.g., analyze-by-list) while maintaining backward compatibility with underscore versions

1.11.2
-----
- Upgrade intezer-SDK to 1.21.4
Expand Down
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,17 @@ For complete documentation please run `intezer-analyze analyze --help`
Send a text file with list of hashes

### Usage
`intezer-analyze analyze_by_list PATH`
`intezer-analyze analyze-by-list PATH`

### Parameters
PATH: Path to txt file.

### Example
Send txt file with hashes for analysis:

$ intezer-analyze analyze_by_list ~/files/hashes.txt
$ intezer-analyze analyze-by-list ~/files/hashes.txt

For complete documentation please run `intezer-analyze analyze_by_list --help`
For complete documentation please run `intezer-analyze analyze-by-list --help`

## Index
Send a file or a directory for indexing
Expand Down Expand Up @@ -89,7 +89,7 @@ For complete documentation please run `intezer-analyze index --help`
Send a text file with list of hashes to index

### Usage
`intezer-analyze index_by_list PATH --index-as=INDEX [FAMILY_NAME]`
`intezer-analyze index-by-list PATH --index-as=INDEX [FAMILY_NAME]`

### Parameters
PATH: Path to txt file
Expand All @@ -101,50 +101,50 @@ FAMILY_NAME: The family name (optional)
### Example
Send a file with hashes and verdict for indexing:

$ intezer-analyze index_by_list ~/files/hashes.txt --index-as=malicious family_name
$ intezer-analyze index-by-list ~/files/hashes.txt --index-as=malicious family_name

For complete documentation please run `intezer-analyze index --help`
For complete documentation please run `intezer-analyze index-by-list --help`

## Upload offline endpoint scan
Upload an offline scan created by running the Intezer Endpoint Scanner with '-o' flag

### Usage
`intezer-analyze upload_endpoint_scan OFFLINE_SCAN_DIRECTORY`
`intezer-analyze upload-endpoint-scan OFFLINE_SCAN_DIRECTORY`

### Parameters
OFFLINE_SCAN_DIRECTORY: Path to directory with offline endpoint scan results

### Examples:
Upload a directory with offline endpoint scan results:

$ intezer-analyze upload_endpoint_scan /home/user/offline_scans/scan_MYPC_2019-01-01_00-00-00
$ intezer-analyze upload-endpoint-scan /home/user/offline_scans/scan_MYPC_2019-01-01_00-00-00

For complete documentation plrase run `intezer-analyze upload_endpoint_scan --help`
For complete documentation please run `intezer-analyze upload-endpoint-scan --help`

## Upload multiple offline endpoint scans
Upload multiple offline scans created by running the Intezer Endpoint Scanner with '-o' flag

### Usage
`intezer-analyze upload_endpoint_scans_in_directory OFFLINE_SCANS_ROOT_DIRECTORY`
`intezer-analyze upload-endpoint-scans-in-directory OFFLINE_SCANS_ROOT_DIRECTORY`

### Parameters
OFFLINE_SCANS_ROOT_DIRECTORY: Path to root directory containing offline endpoint scan results

### Examples:
Upload a directory with offline endpoint scan results:

$ intezer-analyze upload_endpoint_scans /home/user/offline_scans
$ intezer-analyze upload-endpoint-scans-in-directory /home/user/offline_scans

For complete documentation please run `intezer-analyze upload_endpoint_scans_in_directory --help`
For complete documentation please run `intezer-analyze upload-endpoint-scans-in-directory --help`

## Upload all subdirectories with .eml files to analyze
Upload a directory with .eml files

### Parameter
UPLOAD_EMAILS_IN_DIRECTORY: Path to root directory containing the .eml fiels
UPLOAD_EMAILS_IN_DIRECTORY: Path to root directory containing the .eml files

### Examples:
$ intezer-analyze upload_emails_in_directory /path/to/emails_root_directory
$ intezer-analyze upload-emails-in-directory /path/to/emails_root_directory

# Troubleshooting
The cli produce a log file named `intezer-analyze-cli.log` in the current working directory.
Expand Down
2 changes: 1 addition & 1 deletion intezer_analyze_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '1.11.3'
__version__ = '1.12.0'
51 changes: 32 additions & 19 deletions intezer_analyze_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@
logger = logging.getLogger('intezer_cli')


class AliasedGroup(click.Group):
def get_command(self, ctx, cmd_name):
rv = click.Group.get_command(self, ctx, cmd_name)
if rv is not None:
return rv
matches = [x for x in self.list_commands(ctx)
if x.replace('-', '_') == cmd_name.replace('-', '_')]
if not matches:
return None
elif len(matches) == 1:
return click.Group.get_command(self, ctx, matches[0])
ctx.fail(f"Too many matches: {', '.join(sorted(matches))}")

def resolve_command(self, ctx, args):
# always return the full command name
_, cmd, args = super().resolve_command(ctx, args)
return cmd.name, cmd, args


def create_global_api():
try:
api_key = key_store.get_stored_api_key()
Expand All @@ -41,7 +60,7 @@ def create_global_api():
raise click.Abort()


@click.group(context_settings=dict(help_option_names=['-h', '--help'], max_content_width=120),
@click.group(cls=AliasedGroup, context_settings=dict(help_option_names=['-h', '--help'], max_content_width=120),
help=f'Intezer Labs Ltd. Intezer Analyze CLI {__version__}')
def main_cli():
pass
Expand Down Expand Up @@ -135,7 +154,7 @@ def analyze(path: str,
f'and attach the log file in {utilities.log_file_path}')


@main_cli.command('analyze_by_list', short_help='Send a text file with list of hashes')
@main_cli.command('analyze-by-list', short_help='Send a text file with list of hashes')
@click.argument('path', type=click.Path(exists=True, dir_okay=False))
def analyze_by_list(path):
""" Send a text file with hashes for analysis in Intezer Analyze.
Expand All @@ -146,7 +165,7 @@ def analyze_by_list(path):
\b
Examples:
Send txt file with hashes for analysis:
$ intezer-analyze analyze_by_list ~/files/hashes.txt
$ intezer-analyze analyze-by-list ~/files/hashes.txt
"""
try:
create_global_api()
Expand All @@ -159,8 +178,7 @@ def analyze_by_list(path):
click.echo('Unexpected error occurred, please contact us at support@intezer.com '
f'and attach the log file in {utilities.log_file_path}')


@main_cli.command('index_by_list', short_help='Send a text file with list of hashes, verdict, family name if malicious')
@main_cli.command('index-by-list', short_help='Send a text file with list of hashes, verdict, family name if malicious')
@click.argument('path', type=click.Path(exists=True, dir_okay=False))
@click.option('--index-as', type=click.Choice(['malicious', 'trusted'], case_sensitive=True))
@click.argument('family_name', required=False, type=click.STRING, default=None)
Expand All @@ -173,7 +191,7 @@ def index_by_list(path: str, index_as: str, family_name: str):

\b
Examples:
$ intezer-analyze index_by_list ~/files/hashes.txt malicious family_name
$ intezer-analyze index-by-list ~/files/hashes.txt malicious family_name
\b
"""
try:
Expand All @@ -193,7 +211,6 @@ def index_by_list(path: str, index_as: str, family_name: str):
click.echo('Unexpected error occurred, please contact us at support@intezer.com '
f'and attach the log file in {utilities.log_file_path}')


@main_cli.command('index', short_help='index a file or a directory')
@click.argument('path', type=click.Path(exists=True))
@click.option('--index-as', type=click.Choice(['malicious', 'trusted'], case_sensitive=True))
Expand Down Expand Up @@ -239,7 +256,7 @@ def index(path: str, index_as: str, family_name: str, ignore_directory_count_lim
f'and attach the log file in {utilities.log_file_path}')


@main_cli.command('upload_endpoint_scan', short_help='upload a directory with offline endpoint scan results')
@main_cli.command('upload-endpoint-scan', short_help='upload a directory with offline endpoint scan results')
@click.argument('offline_scan_directory', type=click.Path(exists=True))
@click.option('--force', is_flag=True, default=False, help='Upload scan even if it was already uploaded')
@click.option('--max-concurrent', default=0, type=int, help='Maximum number of concurrent uploads.')
Expand All @@ -253,7 +270,7 @@ def upload_endpoint_scan(offline_scan_directory: str, force: bool, max_concurren
Examples:
upload a directory with offline endpoint scan results:

$ intezer-analyze upload_endpoint_scan /path/to/endpoint_scan_results
$ intezer-analyze upload-endpoint-scan /path/to/endpoint_scan_results
"""
try:
create_global_api()
Expand All @@ -267,9 +284,8 @@ def upload_endpoint_scan(offline_scan_directory: str, force: bool, max_concurren
click.echo('Unexpected error occurred, please contact us at support@intezer.com '
f'and attach the log file in {utilities.log_file_path}')


@main_cli.command('upload_endpoint_scans_in_directory',
short_help='upload all subdirectories with offline endpoint scan results')
@main_cli.command('upload-endpoint-scans-in-directory',
short_help='upload all subdirectories with offline endpoint scan results')
@click.argument('offline_scans_root_directory', type=click.Path(exists=True))
@click.option('--force', is_flag=True, default=False, help='Upload scans even if they were already uploaded')
@click.option('--max-concurrent', default=0, type=int, help='Maximum number of concurrent uploads.')
Expand All @@ -283,7 +299,7 @@ def upload_endpoint_scans_in_directory(offline_scans_root_directory: str, force:
Examples:
upload a directory with offline endpoint scan results:

$ intezer-analyze upload_endpoint_scans_in_directory /path/to/endpoint_scan_results_root
$ intezer-analyze upload-endpoint-scans-in-directory /path/to/endpoint_scan_results_root
"""
try:
create_global_api()
Expand All @@ -297,9 +313,8 @@ def upload_endpoint_scans_in_directory(offline_scans_root_directory: str, force:
click.echo('Unexpected error occurred, please contact us at support@intezer.com '
f'and attach the log file in {utilities.log_file_path}')


@main_cli.command('upload_emails_in_directory',
short_help='upload all subdirectories with .emal files')
@main_cli.command('upload-emails-in-directory',
short_help='upload all subdirectories with .emal files')
@click.argument('emails_root_directory', type=click.Path(exists=True, file_okay=False, dir_okay=True))
@click.option('--ignore-directory-count-limit',
is_flag=True,
Expand All @@ -314,7 +329,7 @@ def upload_emails_in_directory(emails_root_directory: str, ignore_directory_coun
Examples:
upload a directory with .eml files:

$ intezer-analyze upload_emails_in_directory /path/to/emails_root_directory
$ intezer-analyze upload-emails-in-directory /path/to/emails_root_directory
"""
try:
create_global_api()
Expand All @@ -327,11 +342,9 @@ def upload_emails_in_directory(emails_root_directory: str, ignore_directory_coun
click.echo('Unexpected error occurred, please contact us at support@intezer.com '
f'and attach the log file in {utilities.log_file_path}')


if __name__ == '__main__':
try:
main_cli()

except Exception as e:
logger.exception(f'Unexpected error occurred {e}')
click.echo('Unexpected error occurred')
4 changes: 2 additions & 2 deletions tests/unit/cli_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ def test_index_by_txt_file_command_wrong_index(self):

# Assert
self.assertEqual(result.exit_code, 2, result.exception)
self.assertTrue(b'Usage: main-cli index_by_list [OPTIONS] PATH [FAMILY_NAME]' in result.stdout_bytes)
self.assertTrue(b'Try \'main-cli index_by_list -h\' for help.' in result.stdout_bytes)
self.assertTrue(b'Usage: main-cli index-by-list [OPTIONS] PATH [FAMILY_NAME]' in result.stdout_bytes)
self.assertTrue(b'Try \'main-cli index-by-list -h\' for help.' in result.stdout_bytes)
self.assertTrue(b'Error: Invalid value for \'--index-as\': invalid choice: wrong_index_name. '
b'(choose from malicious, trusted)' in result.stdout_bytes)