def parse_sensitivity_values(args):
    """
    When configuring which plugins to run, the user is able to either
    specify a configuration file (with --config-file), or select individual
    values (e.g. --base64-limit).

    This function handles parsing the values from these various places,
    and returning them as a SensitivityValues namedtuple.

    Order Precedence:
        1. Values specified in config file.
        2. Values specified inline. (eg. `--hex-limit 6`)
        3. Default values for CLI arguments (specified in ParserBuilder)

    :param args: parsed arguments from parse_args.
    :return: SensitivityValues
    """
    default_plugins = {}
    if args.config_file:
        data = open_config_file(args.config_file[0]).get('default', {})
        default_plugins = data.get('plugins', {})

    return SensitivityValues(
        base64_limit=default_plugins.get('Base64HighEntropyString') or
        args.plugins.get('Base64HighEntropyString', {}).get('base64_limit', [])[0],
        hex_limit=default_plugins.get('HexHighEntropyString') or
        args.plugins.get('HexHighEntropyString', {}).get('hex_limit', [])[0],
        private_key_detector=default_plugins.get('PrivateKeyDetector') or
        'PrivateKeyDetector' in args.plugins,
    )
Esempio n. 2
0
def mock_tracked_repo(cls=BaseTrackedRepo, **kwargs):
    """Returns a mock TrackedRepo for testing"""

    defaults = {
        'sha':
        'does_not_matter',
        'repo':
        '[email protected]:pre-commit/pre-commit-hooks.git',
        'cron':
        '* * 4 * *',
        'repo_config':
        RepoConfig(
            base_tmp_dir='foo/bar',
            baseline='.secrets.baseline',
            exclude_regex='',
        ),
        'plugin_sensitivity':
        SensitivityValues(
            base64_limit=4.5,
            hex_limit=3,
        )
    }

    defaults.update(kwargs)

    with mock.patch(
            'detect_secrets_server.repos.base_tracked_repo.os.path.isdir'
    ) as m:
        m.return_value = True
        return cls(**defaults)
    def test_initialize_repos_from_repo_yaml_no_tracked_repos(self, mock_data):
        mock_data.return_value = {'nothing': 'important'}

        assert initialize_repos_from_repo_yaml(
            'will_be_mocked',
            SensitivityValues(),
            self._mock_repo_config(),
        ) == []
Esempio n. 4
0
    def test_initialize_plugins_failed_instantiation(self):
        with mock.patch(
                'detect_secrets.plugins.HexHighEntropyString.__init__',
                side_effect=TypeError,
        ):
            output = initialize(SensitivityValues(hex_limit=3, ), )

        assert len(output) == 0
    def test_initialize_repos_from_repo_yaml_success(self, mock_data,
                                                     mock_subprocess):
        def _create_mock_tracked_repo_repr(**kwargs):
            defaults = {
                'sha': 'does_not_matter',
                'repo': 'does_not_matter',
            }

            defaults.update(kwargs)

            return defaults

        mock_data.return_value = {
            'tracked': [
                _create_mock_tracked_repo_repr(
                    # Test that it can also be overriden here.
                    plugins={
                        'Base64HighEntropyString': 2,
                    },
                    baseline_file='is_included',
                ),
                _create_mock_tracked_repo_repr(
                    # Test local repo
                    is_local_repo=True, ),
                _create_mock_tracked_repo_repr(
                    # Test S3 remote repo
                    s3_backed=True, ),
                _create_mock_tracked_repo_repr(
                    # Test S3 local repo
                    is_local_repo=True,
                    s3_backed=True,
                ),
            ]
        }

        with mock.patch.object(S3TrackedRepo, '_initialize_s3_client'):
            output = initialize_repos_from_repo_yaml(
                'will_be_mocked',
                SensitivityValues(
                    base64_limit=1,
                    hex_limit=2,
                ), self._mock_repo_config(),
                S3Config(
                    s3_creds_file='filename',
                    bucket_name='bucket',
                    prefix='prefix',
                ))

        assert isinstance(output[0], BaseTrackedRepo)
        assert isinstance(output[1], LocalTrackedRepo)
        assert isinstance(output[2], S3TrackedRepo)
        assert isinstance(output[3], S3LocalTrackedRepo)

        assert output[0].plugin_config.base64_limit == 2
        assert output[0].baseline_file == 'is_included'
        assert output[1].plugin_config.base64_limit == 1
Esempio n. 6
0
    def test_success(self):
        plugins = SensitivityValues(
            base64_limit=4.5,
            hex_limit=3,
        )

        output = initialize(plugins)
        assert isinstance(output[0], Base64HighEntropyString)
        assert output[0].entropy_limit == 4.5
        assert isinstance(output[1], HexHighEntropyString)
        assert output[1].entropy_limit == 3
    def _modify_tracked_file_contents(cls, data):
        """For better representation, we use namedtuples. However, these do not directly
        correlate to file dumps (which `save` does, using `__dict__`. Therefore, we may
        need to modify these values, before loading them into the class constructor.

        :type data: dict
        :param data: pretty much the layout of __dict__
        :return: dict
        """
        # Need to change plugins to type SensitivityValues
        data['plugin_sensitivity'] = SensitivityValues(**data['plugins'])

        return data
Esempio n. 8
0
    def test_aliases(self):
        """For better usability, we can also use aliases when initializing
        the SensitivityValues object.
        """
        plugins = SensitivityValues(
            Base64HighEntropyString=2,

            # Non aliases should take precedence over aliases.
            HexHighEntropyString=1,
            hex_limit=1.5,
        )

        output = initialize(plugins)
        assert isinstance(output[0], Base64HighEntropyString)
        assert output[0].entropy_limit == 2
        assert isinstance(output[1], HexHighEntropyString)
        assert output[1].entropy_limit == 1.5
Esempio n. 9
0
    def test_no_sensitivity_value_necessary_plugin(self):
        plugins = SensitivityValues(PrivateKeyDetector=True)

        output = initialize(plugins)
        assert len(output) == 1
        assert isinstance(output[0], PrivateKeyDetector)
Esempio n. 10
0
    def test_false_disables_plugin(self):
        output = initialize(SensitivityValues(PrivateKeyDetector=False))

        assert len(output) == 0
def initialize_repos_from_repo_yaml(
    repo_yaml,
    plugin_sensitivity,
    repo_config,
    s3_config=None
):
    """For expected yaml file format, see `repos.yaml.sample`

    :type repo_yaml: string
    :param repo_yaml: filename of config file to read and parse

    :type plugin_sensitivity: SensitivityValues

    :type repo_config: RepoConfig

    :type s3_config: S3Config

    :return: list of TrackedRepos
    :raises: IOError
    """
    data = open_config_file(repo_yaml)

    output = []
    if data.get('tracked') is None:
        return output

    for entry in data['tracked']:
        sensitivity = plugin_sensitivity
        if entry.get('plugins'):
            # Merge plugin sensitivities
            plugin_dict = plugin_sensitivity._asdict()

            # Use SensitivityValues constructor to convert values
            entry_sensitivity = SensitivityValues(**entry['plugins'])
            plugin_dict.update(entry_sensitivity._asdict())

            sensitivity = SensitivityValues(**plugin_dict)

        entry['plugin_sensitivity'] = sensitivity

        config = repo_config
        if 'baseline_file' in entry:
            config = RepoConfig(
                base_tmp_dir=repo_config.base_tmp_dir,
                exclude_regex=repo_config.exclude_regex,
                baseline=entry['baseline_file'],
            )

        entry['repo_config'] = config

        if entry.get('s3_backed') and s3_config is None:
            CustomLogObj.getLogger().error(
                (
                    'Unable to load s3 config for %s. Make sure to specify '
                    '--s3-config-file for s3_backed repos!'
                ),
                entry.get('repo'),
            )
            continue
        entry['s3_config'] = s3_config

        # After setting up all arguments, create respective object.
        repo = tracked_repo_factory(
            entry.get('is_local_repo', False),
            entry.get('s3_backed', False),
        )
        output.append(repo(**entry))

    return output