generated from cisagov/ScubaGear
-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add config file support for existing parameters (#413)
* Add pyyaml to requirements * Add basic config file support * Update Parameters.md with config file parameter * Expand help string for config parameter * Create Config.md file * Update README.md with link to config file docs * Document config file support * Remove note about config not supporting aliases * Correct link syntax * minor grammatical tweak * Add navigation section * Reformat notes to make clear not part of any one example * Pylint corrections * Refactor ScubaConfig glass into ScubaArgumentParser * linter tweaks * Correct return type hint * Clarify list parameters * Pin pylint version
- Loading branch information
Showing
10 changed files
with
156 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
|
||
# Usage: Config File | ||
All ScubaGoggles [parameters](/docs/usage/Parameters.md) can be placed into a configuration file in order to made execution easier. The path of the file is specified by the `--config` parameter, and its contents are expected as YAML. | ||
|
||
> [!NOTE] | ||
> If a parameter is specified both on the command-line and in a configuration file, the command-line parameter has precedence over the config file. | ||
## Sample Configuration Files | ||
[Sample config files](/sample-config-files) are available in the repo and are discussed below. | ||
|
||
### Basic Usage | ||
The [basic use](/sample-config-files/basic_config.yaml) example config file specifies the `outpath`, `baselines`, and `quiet` parameters. | ||
|
||
ScubaGoggles can be invokes with this config file: | ||
``` | ||
scubagoggles gws --config basic_config.yaml | ||
``` | ||
|
||
It can also be invoked while overriding the `baselines` parameter. | ||
``` | ||
scubagoggles gws --config basic_config.yaml -b gmail chat | ||
``` | ||
|
||
## Navigation | ||
- Continue to [Usage: Examples](/docs/usage/Examples.md) | ||
- Return to [Documentation Home](/README.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,3 +6,4 @@ dnspython==2.6.1 | |
pandas==2.2.0 | ||
tqdm==4.66.5 | ||
requests==2.32.3 | ||
pyyaml==6.0.2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# YAML basic configuration file with examples of how to specify various types | ||
# of parameters. | ||
|
||
# Example specifying a string parameter | ||
outputpath: example_output | ||
|
||
# Example specifying a list parameter | ||
# Note that list parameter values must be formatted as a list (i.e., with | ||
# brackets) in the config file, even if only one value is specified. For | ||
# example, "baselines: [gmail]" is correct but "baselines: gmail" is not. | ||
baselines: [gmail, calendar, groups, chat, drive, meet, sites, commoncontrols] | ||
|
||
# Example specifying a boolean paramter | ||
quiet: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
""" | ||
Class for parsing the config file and command-line arguments. | ||
""" | ||
|
||
import argparse | ||
import yaml | ||
|
||
class ScubaArgumentParser: | ||
""" | ||
Class for parsing the config file and command-line arguments. | ||
""" | ||
|
||
# Create a mapping of the long form of parameters to their short aliases | ||
_param_to_alias = { | ||
"baselines": "b", | ||
"outputpath": "o", | ||
"credentials": "c" | ||
} | ||
|
||
def __init__(self, parser): | ||
self.parser = parser | ||
|
||
def parse_args(self) -> argparse.Namespace: | ||
""" | ||
Parse the arguments without loading config file. | ||
""" | ||
return self.parser.parse_args() | ||
|
||
def parse_args_with_config(self) -> argparse.Namespace: | ||
""" | ||
Parse the arguments and the config file, if provided, resolving any | ||
differences between the two. | ||
""" | ||
args = self.parse_args() | ||
|
||
# Create a mapping of the short param aliases to the long form | ||
alias_to_param = { | ||
value: key for key, value in self._param_to_alias.items() | ||
} | ||
|
||
# Get the args explicitly specified on the command-line so we know | ||
# what should override the config file | ||
cli_args = self._get_explicit_cli_args(args) | ||
|
||
# If a config file is not specified, just return the args unchanged. | ||
if args.config is not None: | ||
with open(args.config, 'r', encoding="utf-8") as f: | ||
config = yaml.safe_load(f) | ||
config_params = list(config) | ||
for param in config_params: | ||
# If the short form of a param was provided in the config, | ||
# translate it to the long form | ||
if param in alias_to_param: | ||
config[alias_to_param[param]] = config[param] | ||
param = alias_to_param[param] | ||
# If the param was specified in the command-line, the | ||
# command-line arg takes precedence | ||
if param in cli_args: | ||
continue | ||
vars(args)[param] = config[param] | ||
# Return the args (argparse.Namespace) as a dictionary | ||
return args | ||
|
||
@classmethod | ||
def _get_explicit_cli_args(cls, args : argparse.Namespace) -> dict: | ||
""" | ||
Return the list of arguments that were explicitly specified on the | ||
command-line. | ||
""" | ||
# Build a secondary parser, configure the secondary parser to | ||
# suppress the default values so the secondary parser will only | ||
# contain the values explicitly specified on the command-line. | ||
aux_parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS) | ||
for arg, val in vars(args).items(): | ||
dests = [f"--{arg}"] | ||
# If the arg has a short form alias, add the short form as well | ||
if arg in cls._param_to_alias: | ||
dests.append(f"-{cls._param_to_alias[arg]}") | ||
# If the arg is a boolean, need to specify the store action | ||
# otherwise the boolean args will cause an error | ||
if isinstance(val, bool): | ||
aux_parser.add_argument(*dests, action="store_false") | ||
else: | ||
aux_parser.add_argument(*dests) | ||
cli_args, _ = aux_parser.parse_known_args() | ||
return cli_args |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters