scanner-cli 0.1.0rc4__py3-none-any.whl → 0.1.0rc6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: scanner-cli
3
- Version: 0.1.0rc4
3
+ Version: 0.1.0rc6
4
4
  Summary: Python command-line interface for Scanner API
5
5
  Author: Scanner, Inc.
6
6
  Author-email: support@scanner.dev
@@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3.10
10
10
  Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Requires-Dist: click (>=8.1.7,<9.0.0)
13
- Requires-Dist: scanner-client (==0.1.0rc5)
13
+ Requires-Dist: scanner-client (>=0.1.0rc5,<0.2.0)
14
14
  Description-Content-Type: text/markdown
15
15
 
16
16
  # scanner-cli
@@ -26,40 +26,40 @@ pip install scanner-cli
26
26
  ```
27
27
 
28
28
  You will need to provide the API URL of your Scanner instance and an API key. Go
29
- to *Settings > API Keys* to find your API URL and API key.
29
+ to **Settings > API Keys** to find your API URL and API key.
30
30
 
31
31
  You can either set these values as environment variables:
32
32
 
33
33
  ```
34
- export SCANNER_API_URL=<your API URL>
35
- export SCANNER_API_KEY=<your API key>
34
+ export SCANNER_API_URL=<Scanner API URL>
35
+ export SCANNER_API_KEY=<Scanner API key>
36
36
  ```
37
37
 
38
38
  or provide them as arguments to the CLI:
39
39
 
40
40
  ```
41
- scanner-cli <command> --api-url=<your API url> --api-key=<your API key>
41
+ scanner-cli <command> --api-url=<Scanner API URL> --api-key=<Scanner API key>
42
42
  ```
43
43
 
44
- ### Commands
44
+ ## Commands
45
45
 
46
46
  Available commands are
47
47
  - `run-tests` - run tests on detection rules as code
48
48
  - `validate` - validate detection rules as code
49
49
 
50
- To validate or run tests on files
50
+ To validate or run tests on files:
51
51
 
52
52
  ```
53
- scanner-cli <command> -f detections/src/errors.yaml -f detections/src/unauthorized_logins.yaml
53
+ scanner-cli <command> -f detections/errors.yaml -f detections/unauthorized_logins.yaml
54
54
  ```
55
55
 
56
- To validate or run tests on directories
56
+ To validate or run tests on directories:
57
57
 
58
58
  ```
59
- scanner-cli <command> -d detections/src
59
+ scanner-cli <command> -d detections
60
60
  ```
61
61
 
62
- This will validate or run tests on all YAML files in the directory that have the correct schema header.
62
+ This will only validate or run tests on YAML files with the correct schema header.
63
63
 
64
64
  A file or directory must be provided. Multiple files and/or directories can be provided.
65
65
 
@@ -0,0 +1,6 @@
1
+ src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ src/cli.py,sha256=EPfmwoCBiSUKGBReXF5PENDFTWKb-eIAWZkiSNwmogY,5035
3
+ scanner_cli-0.1.0rc6.dist-info/METADATA,sha256=sGfEtgjuEFr833V-j6lVAn7LRDCmYKDHi8_uY6932ak,1607
4
+ scanner_cli-0.1.0rc6.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
5
+ scanner_cli-0.1.0rc6.dist-info/entry_points.txt,sha256=vqXMrIG6N6pY66bNf0y-gbUxbU8v5dXvuL3mV832Fh8,43
6
+ scanner_cli-0.1.0rc6.dist-info/RECORD,,
src/cli.py CHANGED
@@ -1,5 +1,6 @@
1
1
  """ Contains code for Python CLI """
2
2
 
3
+ import glob
3
4
  import os
4
5
  from typing import Any, Callable
5
6
 
@@ -33,6 +34,14 @@ _CLICK_OPTIONS = [
33
34
  help="Directory to validate. Only .yml or .yaml files with the correct schema header will be validated.",
34
35
  multiple=True,
35
36
  ),
37
+ click.option(
38
+ "-r",
39
+ "recursive",
40
+ is_flag=True,
41
+ show_default=True,
42
+ default=False,
43
+ help="Recursively search directory for valid YAML files.",
44
+ ),
36
45
  ]
37
46
 
38
47
 
@@ -51,7 +60,7 @@ def _is_valid_file(file_path: str) -> bool:
51
60
  return False
52
61
 
53
62
 
54
- def _get_valid_files_in_directory(directory: str) -> list[str]:
63
+ def _get_valid_files_in_directory(directory: str, recursive: bool) -> list[str]:
55
64
  if not os.path.exists(directory):
56
65
  raise click.exceptions.ClickException(
57
66
  message=(
@@ -59,14 +68,14 @@ def _get_valid_files_in_directory(directory: str) -> list[str]:
59
68
  )
60
69
  )
61
70
 
62
- return [f"{directory}/{f}" for f in os.listdir(directory) if _is_valid_file(f"{directory}/{f}")]
71
+ return [f for f in glob.iglob(f"{directory}/**", recursive=recursive) if _is_valid_file(f)]
63
72
 
64
73
 
65
- def _get_valid_files(file_paths: str, directories: str) -> list[str]:
74
+ def _get_valid_files(file_paths: str, directories: str, recursive: bool) -> list[str]:
66
75
  files = [f for f in file_paths if _is_valid_file(f)]
67
76
 
68
77
  for d in directories:
69
- files.extend(_get_valid_files_in_directory(d))
78
+ files.extend(_get_valid_files_in_directory(d, recursive))
70
79
 
71
80
  return files
72
81
 
@@ -101,50 +110,59 @@ def cli():
101
110
 
102
111
  @cli.command()
103
112
  @_click_options
104
- def validate(api_url: str, api_key: str, file_paths: str, directories: str):
113
+ def validate(api_url: str, api_key: str, file_paths: str, directories: str, recursive: bool):
105
114
  """ Validate detection rules """
106
115
  _validate_shared_options(api_url, api_key, file_paths, directories)
107
116
 
108
117
  scanner_client = Scanner(api_url, api_key)
109
118
 
110
- files = _get_valid_files(file_paths, directories)
119
+ files = _get_valid_files(file_paths, directories, recursive)
111
120
  click.echo(f'Validating {len(files)} {"file" if len(files) == 1 else "files"}')
112
121
 
113
122
  for file in files:
114
- result = scanner_client.detection_rule_yaml.validate(file)
123
+ try:
124
+ result = scanner_client.detection_rule_yaml.validate(file)
125
+
126
+ if result.is_valid:
127
+ click.echo(f"{file}: " + click.style("Valid", fg="green"))
128
+ else:
129
+ click.echo(f"{file}: " + click.style(f"{result.error}", fg="red"))
130
+ except Exception as e:
131
+ click.echo(f"{file}: " + click.style(e, fg="red"))
115
132
 
116
- if result.is_valid:
117
- click.echo(f"{file}: " + click.style("Valid", fg="green"))
118
- else:
119
- click.echo(f"{file}: " + click.style(f"{result.error}", fg="red"))
120
133
 
121
134
 
122
135
  @cli.command()
123
136
  @_click_options
124
- def run_tests(api_url: str, api_key: str, file_paths: str, directories: str):
137
+ def run_tests(api_url: str, api_key: str, file_paths: str, directories: str, recursive: bool):
125
138
  """ Run detection rule tests """
126
139
  _validate_shared_options(api_url, api_key, file_paths, directories)
127
140
 
128
141
  scanner_client = Scanner(api_url, api_key)
129
142
 
130
- files = _get_valid_files(file_paths, directories)
143
+ files = _get_valid_files(file_paths, directories, recursive)
131
144
  click.echo(f'Running tests on {len(files)} {"file" if len(files) == 1 else "files"}')
132
145
 
133
146
  for file in files:
134
- response = scanner_client.detection_rule_yaml.run_tests(file)
135
- results = response.results.to_dict()
136
-
137
- click.secho(f"{file}", bold=True)
138
- if len(results) == 0:
139
- click.secho("No tests found", fg="yellow")
140
- else:
141
- for name, status in response.results.to_dict().items():
142
- if status == "Passed":
143
- click.echo(f"{name}: " + click.style("Passed", fg="green"))
144
- else:
145
- click.echo(f"{name}: " + click.style("Failed", fg="red"))
146
-
147
- click.echo("")
147
+ try:
148
+ response = scanner_client.detection_rule_yaml.run_tests(file)
149
+ results = response.results.to_dict()
150
+
151
+ click.secho(f"{file}", bold=True)
152
+ if len(results) == 0:
153
+ click.secho("No tests found", fg="yellow")
154
+ else:
155
+ for name, status in response.results.to_dict().items():
156
+ if status == "Passed":
157
+ click.echo(f"{name}: " + click.style("Passed", fg="green"))
158
+ else:
159
+ click.echo(f"{name}: " + click.style("Failed", fg="red"))
160
+
161
+ click.echo("")
162
+ except Exception as e:
163
+ click.secho(f"{file}", bold=True)
164
+ click.secho(e, fg="red")
165
+ click.echo("")
148
166
 
149
167
 
150
168
  if __name__ == "__main__":
@@ -1,6 +0,0 @@
1
- src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- src/cli.py,sha256=Hv5WA0LfmqgkT-9BRqcyUz2h8uTPEeeLkiPl3iy7saw,4398
3
- scanner_cli-0.1.0rc4.dist-info/METADATA,sha256=ScPgaZo7ZYQV5Mecdf-eHthhbRtwHyGKJU9Gwk3-WYY,1618
4
- scanner_cli-0.1.0rc4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
5
- scanner_cli-0.1.0rc4.dist-info/entry_points.txt,sha256=vqXMrIG6N6pY66bNf0y-gbUxbU8v5dXvuL3mV832Fh8,43
6
- scanner_cli-0.1.0rc4.dist-info/RECORD,,