@@ -26,7 +26,7 @@ as fetchers and checks are loaded automatically by ``unittest``.
2626Evidence
2727~~~~~~~~
2828
29- Fetchers and checks manage evidence. We have defined three types of
29+ Fetchers and checks manage evidence. We have defined five types of
3030evidence (see :py:mod: `compliance.evidence `):
3131
3232* :py:class: `~compliance.evidence.RawEvidence `: Gathered by
@@ -37,6 +37,18 @@ evidence (see :py:mod:`compliance.evidence`):
3737 as binary by setting the ``binary_content=True `` keyword argument key/value
3838 pair when constructing a ``RawEvidence `` object.
3939
40+ * :py:class: `~compliance.evidence.DerivedEvidence `: Gathered/Generated by
41+ fetchers and used by checks as *input *. Derived evidence is useful for
42+ those cases when a fetcher needs other evidence to perform computations
43+ over data collected in order to generate a new evidence. This new
44+ evidence is considered `derived ` in the sense that its data is not the
45+ same as the source.
46+
47+ * :py:class: `~compliance.evidence.TmpEvidence `: Gathered by
48+ fetchers and used by checks as *input *. This type of evidence is similar to
49+ RawEvidence but it is never get pushed to the remote git repository. This is
50+ useful for evidence that contains passwords or credentials.
51+
4052* :py:class: `~compliance.evidence.ExternalEvidence `: Planted in the locker
4153 with `plant <https://github.com/ComplianceAsCode/auditree-plant >`_
4254 and used by checks as *input *. For example, a list of users in GitHub.
@@ -212,7 +224,8 @@ A few examples of what it is allowed:
212224
213225In any case, any modification of a new raw evidence **must ** be
214226approved and agreed by the reviewers. By default, do **not ** modify
215- the raw data.
227+ the raw data. If you need to, then you should consider using derived
228+ evidence.
216229
217230This is a list of modifications that are completely forbidden:
218231
@@ -230,11 +243,12 @@ we've provided some helpful decorators and context managers that validate
230243``ttl `` for you and if necessary write the evidence to the evidence locker for
231244you after it has been fetched.
232245
233- * ``store_raw_evidence `` decorator: Use this decorator on your fetcher method
234- when you know the full path and name of your raw evidence. The decorator
235- takes as an argument, the path to your raw evidence as a string.
246+ * ``store_raw_evidence `` and ``store_tmp_evidence `` decorators: Use one of
247+ these decorators on your fetcher method when you know the path and name of
248+ your raw or tmp evidence. The decorator takes as an argument, the path to
249+ your raw or tmp evidence as a string.
236250
237- `` @store_raw_evidence `` usage example::
251+ Usage example::
238252
239253 ...
240254 from compliance.evidence import store_raw_evidence
@@ -248,15 +262,16 @@ you after it has been fetched.
248262 # The decorator will write it to the evidence locker
249263 return json.dumps(foo_bar_data)
250264
251- * ``raw_evidence `` context manager: Use this context manager within your
252- fetcher method when your fetcher retrieves multiple, similar raw evidence
253- based on a dynamic set of configurable values. In other words the full name
254- and content of evidence is based on a configuration and not known prior
255- to execution of the fetcher logic. The context manager takes as arguments, a
256- locker object and the path to your raw evidence as a string. The context
257- manager yields the corresponding raw evidence object.
265+ * ``raw_evidence `` and ``tmp_evidence `` context managers: Use one of these
266+ context managers within your fetcher method when your fetcher retrieves
267+ multiple, similar raw or tmp evidence based on a dynamic set of configurable
268+ values. In other words the full name and content of evidence is based on a
269+ configuration and not known prior to execution of the fetcher logic. The
270+ context manager takes as arguments, a locker object and the path to your raw
271+ or tmp evidence as a string. The context manager yields the corresponding
272+ raw or tmp evidence object.
258273
259- `` with raw_evidence `` usage example::
274+ Usage example::
260275
261276 ...
262277 from compliance.evidence import raw_evidence
@@ -273,6 +288,109 @@ you after it has been fetched.
273288 # Upon exit it is written to the evidence locker
274289 evidence.set_content(json.dumps(foo_bar_data))
275290
291+ * ``store_derived_evidence `` decorator: Use this decorator on your fetcher
292+ method when you know the paths and names of your source evidences and
293+ the path and name of your target derived evidence. The decorator takes
294+ as arguments, a list of source evidence paths as strings and a target derived
295+ evidence path as a string. It also passes the source evidences to the
296+ decorated method in the form of method arguments.
297+
298+ Usage example::
299+
300+ ...
301+ from compliance.evidence import store_derived_evidence
302+ ...
303+ @store_derived_evidence(
304+ ['raw/foo/evidence_bar.json', 'raw/foo/evidence_baz.json'],
305+ 'foo/derived_bar_baz.json'
306+ )
307+ fetch_foo_bar_baz_derived_evidence(self, bar_evidence, baz_evidence):
308+ # Fetcher code only executes if evidence is stale
309+ # Construct your derived evidence
310+ derived_data = self._do_whatever(bar_evidence, baz_evidence)
311+ # Return the content as a string
312+ # The decorator will write it to the evidence locker
313+ return json.dumps(derived_data)
314+
315+ * ``derived_evidence `` context manager: Use this context manager within your
316+ fetcher method when your fetcher generates multiple, similar derived
317+ evidences based on a dynamic set of configurable values. In other words the
318+ name and content of the evidences are based on a configuration and not
319+ known prior to execution of the fetcher logic. The context manager takes as
320+ arguments, a locker object, source evidence paths and a target derived
321+ evidence path as a string. The source evidence paths can be in the form of a
322+ list of paths as strings, a dictionary of key/values pairs as strings where
323+ the key is an evidence short name and the value is the evidence path, or
324+ simply a single evidence path as a string. The context manager yields a
325+ dictionary containing the source and target evidences as the dictionary
326+ values. The source evidence key is its evidence path if a list of source
327+ paths were provided or its evidence short name if a dictionary of paths were
328+ provided or "source" if a single evidence path in the form of a string was
329+ provided. The target derived evidence key is always "derived".
330+
331+ Usage example (source list provided)::
332+
333+ ...
334+ from compliance.evidence import derived_evidence
335+ ...
336+ fetch_foo_bar_baz_derived_evidence(self):
337+ for system in systems:
338+ sources = ['raw/foo/evidence_bar.json', 'raw/foo/evidence_baz.json']
339+ target = 'foo/derived_bar_baz_{}.json'.format(system)
340+ with derived_evidence(self.locker, sources, target) as evidences:
341+ # None is returned if target evidence is not stale
342+ if evidences:
343+ # Construct your derived evidence
344+ derived_data = self._do_whatever(
345+ evidences['raw/foo/evidence_bar.json'],
346+ evidences['raw/foo/evidence_baz.json']
347+ )
348+ # Set the content as a string
349+ # Upon exit it is written to the evidence locker
350+ evidences['derived'].set_content(json.dumps(derived_data))
351+
352+ Usage example (source dictionary provided)::
353+
354+ ...
355+ from compliance.evidence import derived_evidence
356+ ...
357+ fetch_foo_bar_baz_derived_evidence(self):
358+ for system in systems:
359+ sources = {
360+ 'bar': 'raw/foo/evidence_bar.json',
361+ 'baz': 'raw/foo/evidence_baz.json'
362+ }
363+ target = 'foo/derived_bar_baz_{}.json'.format(system)
364+ with derived_evidence(self.locker, sources, target) as evidences:
365+ # None is returned if target evidence is not stale
366+ if evidences:
367+ # Construct your derived evidence
368+ derived_data = self._do_whatever(
369+ evidences['bar'],
370+ evidences['baz']
371+ )
372+ # Set the content as a string
373+ # Upon exit it is written to the evidence locker
374+ evidences['derived'].set_content(json.dumps(derived_data))
375+
376+ Usage example (source string provided)::
377+
378+ ...
379+ from compliance.evidence import derived_evidence
380+ ...
381+ fetch_foo_bar_derived_evidence(self):
382+ for system in systems:
383+ source = 'raw/foo/evidence_bar.json'
384+ target = 'foo/derived_bar_{}.json'.format(system)
385+ with derived_evidence(self.locker, source, target) as evidences:
386+ # None is returned if target evidence is not stale
387+ if evidences:
388+ # Construct your derived evidence
389+ derived_data = self._do_whatever(evidences['source'])
390+ # Set the content as a string
391+ # Upon exit it is written to the evidence locker
392+ evidences['derived'].set_content(json.dumps(derived_data))
393+
276394Evidence Dependency Chaining
277395============================
278396
@@ -355,22 +473,22 @@ we've provided some helpful decorators and context managers that validate
355473``ttl `` for you and will ``ERROR `` the check if evidence ``ttl `` has expired
356474prior to executing the check's logic.
357475
358- * ``with_raw_evidences ``, ``with_external_evidences `` decorators: Use these
359- decorators on your check method when you know the full path and name of
360- your raw or external evidence. Each decorator takes as arguments, the
361- paths to your raw or external evidence as strings or as evidence
362- ``LazyLoader `` named tuples. Evidence `` LazyLoader `` has ``path `` and
363- `` ev_class `` (evidence class) as attributes. If the requested evidence pass
364- TTL validation the evidence is then passed along to the decorated method in
365- the form of method arguments. Use an evidence ``LazyLoader `` when dealing
366- with sub-classed `` RawEvidence `` or ``ExternalEvidence ``, and you want the
367- evidence provided to the decorated method to be cast as that sub-classed
476+ * ``with_raw_evidences ``, ``with_derived_evidences ``, `` with_tmp_evidences ``,
477+ and `` with_external_evidences `` decorators: Use these decorators on your
478+ check method when you know the path and name of your raw, derived, tmp or
479+ external evidence. Each decorator takes as arguments, the paths to your evidence as strings or as evidence `` LazyLoader `` named tuples. Evidence
480+ ``LazyLoader `` has `` path `` and ``ev_class `` (evidence class) as attributes.
481+ If the requested evidence pass TTL validation the evidence is then passed
482+ along to the decorated method in the form of method arguments. Use an
483+ evidence ``LazyLoader `` when dealing with sub-classed `` RawEvidence ``,
484+ `` DerivedEvidence ``, `` TmpEvidence ``, or ``ExternalEvidence ``, and you want
485+ the evidence provided to the decorated method to be cast as that sub-classed
368486 evidence otherwise use a string path and the evidence will be provided as
369- either `` RawEvidence `` or `` ExternalEvidence `` . A ``LazyLoader `` named tuple
370- can be constructed by executing the ``lazy_load `` class method of any evidence
487+ the appropriate base evidence . A ``LazyLoader `` named tuple can be
488+ constructed by executing the ``lazy_load `` class method of any evidence
371489 class such as ``BarEvidence.lazy_load('foo/evidence_bar.json') ``.
372490
373- `` @with_*_evidences `` usage example::
491+ Usage example::
374492
375493 ...
376494 from compliance.evidence import with_raw_evidences
@@ -413,7 +531,7 @@ prior to executing the check's logic.
413531 the ``lazy_load `` class method of any evidence class such as
414532 ``BarEvidence.lazy_load('foo/evidence_bar.json') ``.
415533
416- `` with evidences `` (list provided) usage example ::
534+ Usage example (list provided)::
417535
418536 ...
419537 from compliance.evidence import evidences
@@ -436,7 +554,7 @@ prior to executing the check's logic.
436554 self.add_warnings('bar vs. baz', warnings)
437555 self.add_successes('bar vs. baz', successes)
438556
439- `` with evidences `` (dictionary provided) usage example ::
557+ Usage example (dictionary provided)::
440558
441559 ...
442560 from compliance.evidence import evidences
@@ -459,7 +577,7 @@ prior to executing the check's logic.
459577 self.add_warnings('bar vs. baz', warnings)
460578 self.add_successes('bar vs. baz', successes)
461579
462- `` with evidences `` (string path provided) usage example ::
580+ Usage example (string path provided)::
463581
464582 ...
465583 from compliance.evidence import evidences
@@ -475,7 +593,7 @@ prior to executing the check's logic.
475593 self.add_warnings('bar stuff', warnings)
476594 self.add_successes('bar stuff', successes)
477595
478- `` with evidences `` (``LazyLoader `` provided) usage example ::
596+ Usage example (``LazyLoader `` provided)::
479597
480598 ...
481599 from compliance.evidence import evidences
0 commit comments