Skip to content

Commit

Permalink
Dropping support for --json and --compact and adding support for --ou…
Browse files Browse the repository at this point in the history
…tput-format (#266)

* Dropping support for --json and --compact and adding support for --output-format

* Addressing review comments

Co-authored-by: Joey Wilhelm <tarkatronic@gmail.com>
  • Loading branch information
mayuriesha and tarkatronic authored Nov 5, 2021
1 parent c2b50cd commit e319a51
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 28 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Features:
thanks to @dclayton-godaddy for showing the way.
* [#244](https://github.com/godaddy/tartufo/pull/244) - Drops support for
`--fetch/--no-fetch` option for local scans
* [#253](https://github.com/godaddy/tartufo/issues/253) - Drops support for `--json` and `--compact`
and consolidates the two options into one `---output-format json/compact/text`
* [#259](https://github.com/godaddy/tartufo/pull/259) - Adds a new
`--scan-filenames/--no-scan-filenames` flag which allows users to enable or disable file name scanning.
* [#254](https://github.com/godaddy/tartufo/pull/260) - Changes the default value of
Expand Down
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,13 @@ Usage: tartufo [OPTIONS] COMMAND [ARGS]...
commit hook.

Options:
--json / --no-json Output in JSON format.
--rules FILENAME Path(s) to regex rules json list file(s).
--default-regexes / --no-default-regexes
Whether to include the default regex list
when configuring search patterns. Only
applicable if --rules is also specified.
[default: True]

--compact / --no-compact Enable reduced output. [default: False]
--entropy / --no-entropy Enable entropy checks. [default: True]
--regex / --no-regex Enable high signal regexes checks.
[default: False]
Expand Down Expand Up @@ -122,6 +120,12 @@ Options:
with keeping the results of individual runs
of tartufo separated.

-of, --output-format TEXT Specify the format in which the output needs
to be generated `--output-format json/compact/text`.
Either `json`, `compact` or `text` can be specified.
If not provided (default) the output will be generated
in `text` format.

--git-rules-repo TEXT A file path, or git URL, pointing to a git
repository containing regex rules to be used
for scanning. By default, all .json files
Expand Down
2 changes: 1 addition & 1 deletion docs/source/examplecleanup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ More on this later!)
.. code-block:: console
# Run Tartufo on your repo and create a list of high entropy items to remove:
tartufo --regex --json scan-local-repo ${GITHUBREPO} | \
tartufo --regex --output-format json scan-local-repo ${GITHUBREPO} | \
jq -r '.found_issues[].matched_string' | \
sort -u > remove.txt
Expand Down
24 changes: 16 additions & 8 deletions tartufo/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ def get_command(self, ctx: click.Context, cmd_name: str) -> Optional[click.Comma
name="tartufo",
context_settings=dict(help_option_names=["-h", "--help"]),
)
@click.option("--json/--no-json", help="Output in JSON format.", is_flag=True)
@click.option(
"--rules",
multiple=True,
Expand All @@ -60,13 +59,6 @@ def get_command(self, ctx: click.Context, cmd_name: str) -> Optional[click.Comma
help="Whether to include the default regex list when configuring"
" search patterns. Only applicable if --rules is also specified.",
)
@click.option(
"--compact/--no-compact",
is_flag=True,
default=False,
show_default=True,
help="Enable reduced output.",
)
@click.option(
"--entropy/--no-entropy",
is_flag=True,
Expand Down Expand Up @@ -129,6 +121,22 @@ def get_command(self, ctx: click.Context, cmd_name: str) -> Optional[click.Comma
are excluded unless effectively excluded via the --include-path-patterns
option.""",
)
@click.option(
"-of",
"--output-format",
type=click.Choice(
[
types.OutputFormat.Json.value,
types.OutputFormat.Compact.value,
types.OutputFormat.Text.value,
]
),
default="text",
help="""Specify the format in which the output needs to be generated
`--output-format json/compact/text`. Either `json`, `compact` or `text`
can be specified. If not provided (default) the output will be generated
in `text` format.""",
)
@click.option(
"-xe",
"--exclude-entropy-patterns",
Expand Down
12 changes: 8 additions & 4 deletions tartufo/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
@dataclass
class GlobalOptions:
__slots__ = (
"json",
"rules",
"default_regexes",
"entropy",
Expand All @@ -26,11 +25,10 @@ class GlobalOptions:
"verbose",
"quiet",
"log_timestamps",
"compact",
"output_format",
"b64_entropy_score",
"hex_entropy_score",
)
json: bool
rules: Tuple[TextIO, ...]
default_regexes: bool
entropy: bool
Expand All @@ -49,7 +47,7 @@ class GlobalOptions:
verbose: int
quiet: bool
log_timestamps: bool
compact: bool
output_format: Optional[str]
b64_entropy_score: float
hex_entropy_score: float

Expand Down Expand Up @@ -97,6 +95,12 @@ class LogLevel(enum.IntEnum):
DEBUG = 3


class OutputFormat(enum.Enum):
Text = "text" # pylint: disable=invalid-name
Json = "json" # pylint: disable=invalid-name
Compact = "compact" # pylint: disable=invalid-name


class TartufoException(Exception):
"""Base class for all package exceptions"""

Expand Down
9 changes: 5 additions & 4 deletions tartufo/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def echo_result(
"""

now = datetime.now().isoformat("T", "microseconds")
if options.json:
if options.output_format == types.OutputFormat.Json.value:
output = {
"scan_time": now,
"project_path": repo_path,
Expand All @@ -97,11 +97,12 @@ def echo_result(
click.echo(f'{static_part[:-1]}, "found_issues": [', nl=False)
delimiter = ""
for issue in scanner.scan():
live_part = json.dumps(issue.as_dict(compact=options.compact))
compact = options.output_format == types.OutputFormat.Compact.value
live_part = json.dumps(issue.as_dict(compact=compact))
click.echo(f"{delimiter}{live_part}", nl=False)
delimiter = ", "
click.echo("]}")
elif options.compact:
elif options.output_format == types.OutputFormat.Compact.value:
for issue in scanner.scan():
click.echo(
f"[{issue.issue_type.value}] {issue.chunk.file_path}: {issue.matched_string} "
Expand Down Expand Up @@ -261,5 +262,5 @@ def process_issues(
echo_result(options, scan, repo_path, output_dir)
if output_dir:
write_outputs(scan.issues, output_dir)
if not options.json:
if options.output_format != types.OutputFormat.Json.value:
click.echo(f"Results have been saved in {output_dir}")
20 changes: 18 additions & 2 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,15 @@ def test_output_dir_is_not_called_out_when_outputting_json(
runner = CliRunner()
with runner.isolated_filesystem():
result = runner.invoke(
cli.main, ["--output-dir", "./foo", "--json", "scan-local-repo", "."]
cli.main,
[
"--output-dir",
"./foo",
"--output-format",
"json",
"scan-local-repo",
".",
],
)
# All other outputs are mocked, so this is ensuring that the
# "Results have been saved in ..." message is not output.
Expand All @@ -175,7 +183,15 @@ def test_output_dir_is_created_if_it_does_not_exist(
runner = CliRunner()
with runner.isolated_filesystem():
runner.invoke(
cli.main, ["--output-dir", "./foo", "--json", "scan-local-repo", "."]
cli.main,
[
"--output-dir",
"./foo",
"--output-format",
"json",
"scan-local-repo",
".",
],
)
self.assertTrue(Path("./foo").exists())

Expand Down
16 changes: 9 additions & 7 deletions tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ class OutputTests(unittest.TestCase):
@mock.patch("tartufo.scanner.ScannerBase")
@mock.patch("tartufo.util.click")
def test_echo_result_echos_all_when_not_json(self, mock_click, mock_scanner):
options = generate_options(GlobalOptions, json=False, verbose=0)
options = generate_options(GlobalOptions, verbose=0)
mock_scanner.exclude_signatures = []
mock_scanner.scan.return_value = (1, 2, 3, 4)
util.echo_result(options, mock_scanner, "", "")
Expand All @@ -128,7 +128,7 @@ def test_echo_result_echos_all_when_not_json(self, mock_click, mock_scanner):
@mock.patch("tartufo.scanner.ScannerBase")
@mock.patch("tartufo.util.click")
def test_echo_result_outputs_compact_format(self, mock_click, mock_scanner):
options = generate_options(GlobalOptions, json=False, verbose=0, compact=True)
options = generate_options(GlobalOptions, verbose=0, output_format="compact")
issue1 = scanner.Issue(
types.IssueType.Entropy, "foo", types.Chunk("fullfoobar", "/what/foo", {})
)
Expand Down Expand Up @@ -157,7 +157,7 @@ def test_echo_result_echos_message_when_clean(
self, mock_time, mock_click, mock_scanner
):
mock_time.now.return_value.isoformat.return_value = "now:now:now"
options = generate_options(GlobalOptions, json=False, quiet=False, verbose=0)
options = generate_options(GlobalOptions, quiet=False, verbose=0)
mock_scanner.exclude_signatures = []
mock_scanner.issue_count = 0
mock_scanner.issues = []
Expand All @@ -183,7 +183,6 @@ def test_echo_result_echos_exclusions_verbose(
]
options = generate_options(
GlobalOptions,
json=False,
quiet=False,
verbose=1,
exclude_signatures=exclude_signatures,
Expand Down Expand Up @@ -212,7 +211,7 @@ def test_echo_result_echos_exclusions_verbose(
@mock.patch("tartufo.scanner.ScannerBase")
@mock.patch("tartufo.util.click")
def test_echo_result_echos_no_message_when_quiet(self, mock_click, mock_scanner):
options = generate_options(GlobalOptions, json=False, quiet=True, verbose=0)
options = generate_options(GlobalOptions, quiet=True, verbose=0)
mock_scanner.issues = []
mock_scanner.exclude_signatures = []
util.echo_result(options, mock_scanner, "", "")
Expand All @@ -235,7 +234,10 @@ def test_echo_result_outputs_proper_json_when_requested(
mock_scanner.scan.return_value = (issue_1, issue_2)
mock_scanner.excluded_paths = []
options = generate_options(
GlobalOptions, json=True, exclude_signatures=[], exclude_entropy_patterns=[]
GlobalOptions,
output_format=types.OutputFormat.Json.value,
exclude_signatures=[],
exclude_entropy_patterns=[],
)

# We're generating JSON piecemeal, so if we want to be safe we'll recover
Expand Down Expand Up @@ -302,7 +304,7 @@ def test_echo_result_outputs_proper_json_when_requested_pathtype(
]
options = generate_options(
GlobalOptions,
json=True,
output_format=types.OutputFormat.Json.value,
exclude_signatures=exclude_signatures,
exclude_entropy_patterns=exclude_entropy_patterns,
)
Expand Down

0 comments on commit e319a51

Please sign in to comment.