Skip to content

Commit 22e892b

Browse files
authored
Remove the need of a --creds-path (#153)
If --creds-path is not provided it will not default to `~/.credentials` any more. Instead, it will assume that env vars want to be used and it will try so. Also, the documentation has been updated to reflect this and provide a way to use 1Password CLI as a credentials loader.
1 parent 830597d commit 22e892b

File tree

9 files changed

+80
-110
lines changed

9 files changed

+80
-110
lines changed

CHANGES.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
# [1.24.1](https://github.com/ComplianceAsCode/auditree-framework/releases/tag/v1.24.1)
1+
# [1.25.0](https://github.com/ComplianceAsCode/auditree-framework/releases/tag/v1.25.0)
22

3+
- [ADDED] Documentation on how to use it with 1Password CLI.
4+
- [CHANGED] "--creds-path" does not default to "~/.credentials".
35
- [FIXED] Number of errors/warnings shown correctly for single checks.
46

57
# [1.24.0](https://github.com/ComplianceAsCode/auditree-framework/releases/tag/v1.24.0)

compliance/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@
1313
# limitations under the License.
1414
"""Compliance automation package."""
1515

16-
__version__ = "1.24.1"
16+
__version__ = "1.25.0"

compliance/config.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,9 @@ def __init__(self):
6868
@property
6969
def creds(self):
7070
"""Credentials used for locker management and running fetchers."""
71-
if self.creds_path is None:
72-
raise ValueError("Path to credentials file not provided")
73-
74-
if self._creds is None:
75-
self._creds = Config(self.creds_path)
71+
if not self._creds:
72+
path = None if self.creds_path is None else str(self.creds_path)
73+
self._creds = Config(path)
7674
return self._creds
7775

7876
@property

compliance/runners.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,15 @@ def get_test_candidates(self, suite):
9191
yield test
9292

9393
def _load_compliance_config(self):
94-
creds_path = Path(self.opts.creds_path).expanduser()
95-
if not creds_path.is_file():
96-
raise ValueError(f"{creds_path} file does not exist.")
9794
self.config = get_config()
98-
self.config.creds_path = str(creds_path)
95+
creds_path = None
96+
if self.opts.creds_path is not None:
97+
creds_path = Path(self.opts.creds_path).expanduser()
98+
if not creds_path.is_file():
99+
raise ValueError(
100+
f"Invalid path to credentials file '{str(creds_path)}'"
101+
)
102+
self.config.creds_path = creds_path
99103
self.config.load(self.opts.compliance_config)
100104

101105
def _init_dirs(self):

compliance/scripts/compliance_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def _init_arguments(self):
8383
"Defaults to %(default)s."
8484
),
8585
metavar="/path/to/creds.ini",
86-
default="~/.credentials",
86+
default=None,
8787
)
8888
notify_options = [k for k in get_notifiers().keys() if k != "stdout"]
8989
self.add_argument(

compliance/utils/credentials.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ def __init__(self, cfg_file="~/.credentials"):
3636
:param cfg_file: The path to the RawConfigParser compatible config file
3737
"""
3838
self._cfg = RawConfigParser()
39-
self._cfg.read(str(Path(cfg_file).expanduser()))
4039
self._cfg_file = cfg_file
40+
if cfg_file is not None:
41+
self._cfg.read(str(Path(cfg_file).expanduser()))
4142

4243
def __getitem__(self, section):
4344
"""
@@ -60,13 +61,16 @@ def _getattr_wrapper(t, attr):
6061
try:
6162
return t.__getattribute__(attr)
6263
except AttributeError as exc:
63-
exc.args = (
64-
(
64+
if self._cfg_file:
65+
msg = (
6566
f'Unable to locate attribute "{attr}" '
6667
f'in section "{type(t).__name__}" '
6768
f'at config file "{self._cfg_file}"'
68-
),
69-
)
69+
)
70+
else:
71+
env_var_name = f"{type(t).__name__}_{attr}".upper()
72+
msg = f"Unable to find the env var: {env_var_name}"
73+
exc.args = (msg,)
7074
raise exc
7175

7276
env_vars = [k for k in environ.keys() if k.startswith(f"{section.upper()}_")]

doc-source/design-principles.rst

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -750,9 +750,51 @@ levels:
750750
Credentials
751751
~~~~~~~~~~~
752752

753-
If you want to configure your credentials locally, the framework
754-
will look for a credentials file at ``~/.credentials`` by default. This
755-
file should be similar to this:
753+
There are 2 ways for providing credentials:
756754

757-
.. include:: credentials-example.cfg
758-
:literal:
755+
1. *Local file*: if you want to configure your credentials in a local file,
756+
you will have to provide the the framework using ``--creds-path`` option.
757+
This file should be similar to this:
758+
759+
.. include:: credentials-example.cfg
760+
:literal:
761+
762+
1. *Environment variables*: each section and field of the local file can be
763+
rendered as an environment variable.
764+
For instance, suppose your code requires ``creds['github'].token`` or ``creds['slack'].webhook``.
765+
You just need to export:
766+
767+
* ``GITHUB_TOKEN = XXX``
768+
769+
* ``MY_SERVICE_API_KEY = YYY``
770+
771+
This is equivalent to the credentials file::
772+
773+
[github]
774+
token=XXX
775+
776+
[my_service]
777+
api_key=YYY
778+
779+
Creds with ``.env`` files and 1Password
780+
+++++++++++++++++++++++++++++++++++++++
781+
782+
Combining the method based on passing env vars to Auditree and `1Password CLI <https://developer.1password.com/docs/cli/>`_,
783+
it is possible to grab the secrets from 1Password and inject them into Auditree.
784+
Here it is how to do it:
785+
786+
1. Create the following alias::
787+
788+
alias compliance="op run --env-file .env -- compliance"
789+
790+
1. In your fetchers/checks project, create an ``.env`` file with the following schema::
791+
792+
<SECTION>_<ATTRIBUTE>="op://<VAULT>/<ITEM>/<FIELD>"
793+
794+
For example::
795+
796+
GITHUB_TOKEN="op://Private/github/token"
797+
MY_SERVICE_ORG="the-org-id"
798+
MY_SERVICE_API_KEY="op://Shared/my_service/api_key"
799+
800+
1. Now running ``compliance`` will pull credentials from 1Password vaults.

doc-source/notifiers.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ You can also use a Slack app token (recommended if you need to post
134134
messages to private channels)::
135135

136136
[slack]
137-
slack=XXX
137+
token=XXX
138+
139+
Note that you can do the same thing using env vars ``SLACK_WEBHOOK`` and ``SLACK_TOKEN``.
138140

139141
In case you need private channels as part of the list, you have to
140142
specify the channel ID::

doc-source/running-on-travis.rst

Lines changed: 5 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -57,104 +57,22 @@ This is a typical `.travis.yml` file:
5757
- "3.7"
5858
install:
5959
- pip install -r requirements.txt
60-
- ./travis/gen-credentials.py > ~/.credentials
6160
script:
6261
- make clean
6362
- ./travis/run.sh
64-
after_script:
65-
- rm ~/.credentials
6663
6764
Basically, this will firstly install the dependencies through
6865
``pip install -r requirements.txt`` and then generate the credentials file from
6966
using Travis environment variables.
7067

71-
Credentials generation
72-
~~~~~~~~~~~~~~~~~~~~~~
68+
Credentials
69+
~~~~~~~~~~~
7370

74-
This is an implementation you might want to use for your project of
75-
``gen-credentials.py``:
71+
The recommended way to use credentials in a CI job is to export them as environment variables.
72+
Auditree will automatically parsed the environment variables available to the process and make them available to the fetchers if they follow a specific structure.
7673

77-
.. code-block:: python
74+
For more information on how to do this, have a look to the :ref:`credentials` section.
7875

79-
#!/usr/bin/env python
80-
# -*- coding:utf-8; mode:python -*-
81-
82-
'''This script generates a config file suitable to be used by
83-
`utilitarian.credentials.Config` from envvars. This is useful for
84-
Travis CI that allows to deploy credentials safely using envvars.
85-
86-
Any new supported credential must be added to SUPPORTED_SECTIONS which
87-
includes a list of sections of `Config` supported by the script. For
88-
example, adding 'github' will make the script to generate
89-
`github.username` from GITHUB_USERNAME and `github.password` from
90-
GITHUB_PASSWORD, if both envvars are defined.
91-
'''
92-
93-
import os
94-
import sys
95-
import ConfigParser
96-
97-
98-
SUPPORTED_SECTIONS = ['github', 'slack']
99-
100-
101-
def main():
102-
matched_keys = filter(
103-
lambda k: any([k.lower().startswith(x) for x in SUPPORTED_SECTIONS]),
104-
os.environ.keys()
105-
)
106-
if not matched_keys:
107-
return 0
108-
109-
cfg_parser = ConfigParser.ConfigParser()
110-
for k in matched_keys:
111-
# split the section name and option from this env var (max()
112-
# to ensure the longest match)
113-
section = max(
114-
[s for s in SUPPORTED_SECTIONS if k.lower().startswith(s)],
115-
key=len
116-
)
117-
option = k.split(section.upper())[1][1:].lower()
118-
119-
# add to the config
120-
if not cfg_parser.has_section(section):
121-
cfg_parser.add_section(section)
122-
cfg_parser.set(section, option, os.environ[k])
123-
124-
cfg_parser.write(sys.stdout)
125-
126-
return 0
127-
128-
129-
if __name__ == '__main__':
130-
exit(main())
131-
132-
So, for instance, using the previous script you will be able to create
133-
the credentials required for ``github`` and ``slack`` by
134-
defining the following environment variables in Travis:
135-
136-
* ``GITHUB_TOKEN = XXX``
137-
138-
* ``SLACK_WEBHOOK = YYY``
139-
140-
Using those variables, ``./travis/gen-credentials.py >
141-
~/.credentials`` will generate::
142-
143-
[github]
144-
token=XXX
145-
146-
[slack]
147-
webhook=YYY
148-
149-
This method has a few limitation:
150-
151-
* Do not use ``$`` as part of the value of any variable as they will
152-
be evaluated by bash.
153-
154-
* You will need to add a new service into the
155-
``SUPPORTED_SECTIONS``. This is actually good since a manual
156-
addition requires a code change (so new credentials are
157-
tracked).
15876

15977
``travis/run.sh``
16078
~~~~~~~~~~~~~~~~~

0 commit comments

Comments
 (0)