Exemple #1
0
def test_cache_catches_last_found_secrets(client):
    """
    GIVEN an empty cache and an empty config matches-ignore section
    WHEN I run a scan with multiple secrets
    THEN cache last_found_secrets is updated with these secrets and saved
    """
    c = Commit()
    c._patch = _MULTIPLE_SECRETS
    config = Config()
    setattr(config, "matches_ignore", set())
    cache = Cache()
    cache.purge()
    assert cache.last_found_secrets == set()

    with my_vcr.use_cassette("multiple_secrets"):
        c.scan(
            client=client,
            cache=cache,
            matches_ignore=config.matches_ignore,
            all_policies=True,
            verbose=False,
        )
    assert config.matches_ignore == set()
    assert cache.last_found_secrets == FOUND_SECRETS
    cache.load_cache()
    assert cache.last_found_secrets == FOUND_SECRETS
Exemple #2
0
def test_cache_catches_last_found_secrets(client, isolated_fs):
    """
    GIVEN an empty cache and an empty config matches-ignore section
    WHEN I run a scan with multiple secrets
    THEN cache last_found_secrets is updated with these secrets and saved
    """
    c = Commit()
    c._patch = _MULTIPLE_SECRETS
    config = Config()
    setattr(config, "matches_ignore", [])
    cache = Cache()
    cache.purge()
    assert cache.last_found_secrets == list()

    with my_vcr.use_cassette("multiple_secrets"):
        c.scan(
            client=client,
            cache=cache,
            matches_ignore=config.matches_ignore,
            all_policies=True,
            verbose=False,
        )
    assert config.matches_ignore == list()

    cache_found_secrets = sorted(cache.last_found_secrets, key=compare_matches_ignore)
    found_secrets = sorted(FOUND_SECRETS, key=compare_matches_ignore)

    assert [found_secret["match"] for found_secret in cache_found_secrets] == [
        found_secret["match"] for found_secret in found_secrets
    ]
    ignore_last_found(config, cache)
    for ignore in config.matches_ignore:
        assert "test.txt" in ignore["name"]
    cache.load_cache()
def test_cache_catches_nothing(client):
    """
    GIVEN a cache of last found secrets same as config ignored-matches
    WHEN I run a scan (therefore finding no secret)
    THEN config matches is unchanged and cache is empty
    """
    c = Commit()
    c._patch = _MULTIPLE_SECRETS
    config = Config()
    config.matches_ignore = FOUND_SECRETS
    cache = Cache()
    cache.last_found_secrets = FOUND_SECRETS

    with my_vcr.use_cassette("multiple_secrets"):
        results = c.scan(
            client=client,
            cache=cache,
            matches_ignore=config.matches_ignore,
            all_policies=True,
            verbose=False,
        )

        assert results == []
        assert config.matches_ignore == FOUND_SECRETS
        assert cache.last_found_secrets == []
def test_scan_patch(client, cache, name, input_patch, expected):
    c = Commit()
    c._patch = input_patch

    with my_vcr.use_cassette(name):
        results = c.scan(
            client=client,
            cache=cache,
            matches_ignore={},
            all_policies=True,
            verbose=False,
        )
        for result in results:
            if result.scan.policy_breaks:
                assert len(
                    result.scan.policy_breaks[0].matches) == expected.matches
                if expected.first_match:
                    assert (result.scan.policy_breaks[0].matches[0].match ==
                            expected.first_match)
            else:
                assert result.scan.policy_breaks == []

            if expected.want:
                assert result.content == expected.want["content"]
                assert result.filename == expected.want["filename"]
                assert result.filemode == expected.want["filemode"]
Exemple #5
0
def test_cache_old_config_no_new_secret(client, isolated_fs):
    """
    GIVEN a cache of last found secrets same as config ignored-matches
          and config ignored-matches is a list of strings
    WHEN I run a scan (therefore finding no secret)
    THEN config matches is unchanged and cache is empty
    """
    c = Commit()
    c._patch = _MULTIPLE_SECRETS
    config = Config()
    config.matches_ignore = [d["match"] for d in FOUND_SECRETS]
    cache = Cache()
    cache.last_found_secrets = FOUND_SECRETS

    with my_vcr.use_cassette("multiple_secrets"):
        results = c.scan(
            client=client,
            cache=cache,
            matches_ignore=config.matches_ignore,
            all_policies=True,
            verbose=False,
        )

        assert results == []
        assert config.matches_ignore == [d["match"] for d in FOUND_SECRETS]
        assert cache.last_found_secrets == []
Exemple #6
0
def test_patch_separation_ignore():
    c = Commit()
    c._patch = PATCH_SEPARATION
    file_to_ignore = ".env"
    c.filter_set = {os.path.join(os.getcwd(), file_to_ignore)}
    files = list(c.get_files())

    assert len(files) == 3
    assert not (any(entry.filename == file_to_ignore for entry in files))
Exemple #7
0
def test_patch_separation():
    c = Commit()
    c._patch = PATCH_SEPARATION
    files = list(c.get_files())

    assert len(files) == 4

    assert c.info.author == "Testificate Jose"
    assert c.info.email == "*****@*****.**"
    assert c.info.date == "Fri Oct 18 13:20:00 2012 +0100"
Exemple #8
0
def test_patch_max_size():
    c = Commit()
    c._patch = """
diff --git a/tests/test_scannable.py b/.env
new file mode 100644
index 0000000..0000000
--- /dev/null
+++ b/.env
@@ -0,0 +1,112 @@
CHECK_ENVIRONMENT=true
    """
    c._patch += "a" * MAX_FILE_SIZE
    files = list(c.get_files())

    assert len(files) == 0
Exemple #9
0
def precommit_cmd(ctx: click.Context,
                  precommit_args: List[str]) -> int:  # pragma: no cover
    """
    scan as a pre-commit git hook.
    """
    config = ctx.obj["config"]
    output_handler = TextHandler(show_secrets=config.show_secrets,
                                 verbose=config.verbose,
                                 output=None)
    try:
        check_git_dir()
        results = Commit(filter_set=ctx.obj["filter_set"]).scan(
            client=ctx.obj["client"],
            cache=ctx.obj["cache"],
            matches_ignore=config.matches_ignore,
            all_policies=config.all_policies,
            verbose=config.verbose,
        )

        return output_handler.process_scan(
            ScanCollection(id="cached", type="pre-commit", results=results))[1]
    except click.exceptions.Abort:
        return 0
    except Exception as error:
        if config.verbose:
            traceback.print_exc()
        raise click.ClickException(str(error))
Exemple #10
0
def scan_commit(
    commit: Commit,
    client: GGClient,
    cache: Cache,
    verbose: bool,
    matches_ignore: Iterable[IgnoredMatch],
    all_policies: bool,
    mode_header: str,
    banlisted_detectors: Optional[Set[str]] = None,
) -> ScanCollection:  # pragma: no cover
    results = commit.scan(
        client=client,
        cache=cache,
        matches_ignore=matches_ignore,
        banlisted_detectors=banlisted_detectors,
        all_policies=all_policies,
        verbose=verbose,
    )

    return ScanCollection(
        commit.sha or "unknown",
        type="commit",
        results=results,
        optional_header=commit.optional_header,
        extra_info=commit.info._asdict(),
    )
def test_json_output(client, name, input_patch, expected, snapshot):
    c = Commit()
    c._patch = input_patch
    handler = JSONHandler(verbose=True, show_secrets=False)

    with my_vcr.use_cassette(name):
        results = c.scan(
            client=client, matches_ignore={}, all_policies=True, verbose=False
        )

        flat_results, exit_code = handler.process_scan(
            scan=ScanCollection(id="path", type="test", results=results), top=True
        )

        assert exit_code == expected
        json_flat_results = JSONScanCollectionSchema().dumps(flat_results)
        snapshot.assert_match(JSONScanCollectionSchema().loads(json_flat_results))
Exemple #12
0
def test_request_headers(scan_mock: Mock, client):
    c = Commit()
    c._patch = _SIMPLE_SECRET

    with Context(Command("bar"), info_name="bar") as ctx:
        ctx.parent = Context(Group("foo"), info_name="foo")
        c.scan(
            client=client,
            cache=Cache(),
            matches_ignore={},
            all_policies=True,
            verbose=False,
        )
    scan_mock.assert_called_with(
        ANY,
        {
            "GGShield-Version": __version__,
            "GGShield-Command-Path": "foo bar",
        },
    )
Exemple #13
0
def test_json_output(client, cache, name, input_patch, expected, snapshot):
    c = Commit()
    c._patch = input_patch
    handler = JSONOutputHandler(verbose=True, show_secrets=False)

    with my_vcr.use_cassette(name):
        results = c.scan(
            client=client,
            cache=cache,
            matches_ignore={},
            all_policies=True,
            verbose=False,
            banlisted_detectors=None,
        )

        scan = ScanCollection(id="path", type="test", results=results)
        json_flat_results = handler._process_scan_impl(scan)
        exit_code = OutputHandler._get_exit_code(scan)

        assert exit_code == expected
        snapshot.assert_match(
            JSONScanCollectionSchema().loads(json_flat_results))
Exemple #14
0
def scan_commit_range(
    client: GGClient,
    cache: Cache,
    commit_list: List[str],
    output_handler: OutputHandler,
    verbose: bool,
    exclusion_regexes: Set[re.Pattern],
    matches_ignore: Iterable[IgnoredMatch],
    all_policies: bool,
    scan_id: str,
    mode_header: str,
    banlisted_detectors: Optional[Set[str]] = None,
) -> int:  # pragma: no cover
    """
    Scan every commit in a range.

    :param client: Public Scanning API client
    :param commit_list: List of commits sha to scan
    :param verbose: Display successfull scan's message
    """
    return_code = 0
    with concurrent.futures.ThreadPoolExecutor(
            max_workers=min(CPU_COUNT, 4)) as executor:
        future_to_process = [
            executor.submit(
                scan_commit,
                Commit(sha, exclusion_regexes),
                client,
                cache,
                verbose,
                matches_ignore,
                all_policies,
                mode_header,
                banlisted_detectors,
            ) for sha in commit_list
        ]

        scans: List[ScanCollection] = []
        with click.progressbar(
                iterable=concurrent.futures.as_completed(future_to_process),
                length=len(future_to_process),
                label=format_text("Scanning Commits", STYLE["progress"]),
        ) as completed_futures:
            for future in completed_futures:
                scans.append(future.result())

        return_code = output_handler.process_scan(
            ScanCollection(id=scan_id, type="commit-range", scans=scans))
    return return_code
Exemple #15
0
def scan_commit_range(
    client: GGClient,
    cache: Cache,
    commit_list: List[str],
    output_handler: OutputHandler,
    verbose: bool,
    filter_set: Set[str],
    matches_ignore: Iterable[str],
    all_policies: bool,
    scan_id: str,
) -> int:  # pragma: no cover
    """
    Scan every commit in a range.

    :param client: Public Scanning API client
    :param commit_range: Range of commits to scan (A...B)
    :param verbose: Display successfull scan's message
    """
    return_code = 0
    with concurrent.futures.ThreadPoolExecutor(
            max_workers=min(CPU_COUNT, 4)) as executor:
        future_to_process = [
            executor.submit(
                scan_commit,
                Commit(sha, filter_set),
                client,
                cache,
                verbose,
                matches_ignore,
                all_policies,
            ) for sha in commit_list
        ]

        scans: List[ScanCollection] = []
        with click.progressbar(
                length=len(future_to_process),
                label=format_text("Scanning Commits", STYLE["progress"]),
        ) as bar:
            processed = 0
            for future in concurrent.futures.as_completed(future_to_process):
                scans.append(future.result())
                processed += 1
                bar.update(processed)

        return_code = output_handler.process_scan(
            ScanCollection(id=scan_id, type="commit-range", scans=scans))[1]
    return return_code
Exemple #16
0
def scan_commit(
    commit: Commit,
    client: GGClient,
    verbose: bool,
    matches_ignore: Iterable[str],
    all_policies: bool,
) -> ScanCollection:  # pragma: no cover
    results = commit.scan(
        client=client,
        matches_ignore=matches_ignore,
        all_policies=all_policies,
        verbose=verbose,
    )

    return ScanCollection(
        commit.sha or "unknown",
        type="commit",
        results=results,
        optional_header=commit.optional_header,
        extra_info=commit.info._asdict(),
    )
Exemple #17
0
def precommit_cmd(ctx: click.Context,
                  precommit_args: List[str]) -> int:  # pragma: no cover
    """
    scan as a pre-commit git hook.
    """
    config = ctx.obj["config"]
    output_handler = TextOutputHandler(show_secrets=config.show_secrets,
                                       verbose=config.verbose,
                                       output=None)
    try:
        check_git_dir()
        results = Commit(exclusion_regexes=ctx.obj["exclusion_regexes"]).scan(
            client=ctx.obj["client"],
            cache=ctx.obj["cache"],
            matches_ignore=config.matches_ignore,
            all_policies=config.all_policies,
            verbose=config.verbose,
            banlisted_detectors=config.banlisted_detectors,
        )

        return output_handler.process_scan(
            ScanCollection(id="cached", type="pre-commit", results=results))
    except Exception as error:
        return handle_exception(error, config.verbose)
Exemple #18
0
def test_get_filename():
    line = "a/test.txt b/test.txt"
    assert Commit().get_filename(line) == "test.txt"
Exemple #19
0
def test_get_filemode_delete():
    line = "deleted file mode 100644\n"
    assert Commit().get_filemode(line) == Filemode.DELETE
Exemple #20
0
def test_get_filemode_modify():
    line = "index 3d47bfe..ee93988 100644\n"
    assert Commit().get_filemode(line) == Filemode.MODIFY
Exemple #21
0
def test_get_filemode_new():
    line = "new file mode 100644\n"
    assert Commit().get_filemode(line) == Filemode.NEW
Exemple #22
0
def test_get_filemode_rename():
    line = "similarity index 99%\n"
    assert Commit().get_filemode(line) == Filemode.RENAME