Skip to content

Commit b7e5561

Browse files
meganwolf0soltyshbrandtkeller
authored
docs: 0008 validation refactor adr (#881)
* docs: 0008 adr * Update adr/0008-validation-refactor.md Co-authored-by: Maciej Szulik <[email protected]> * docs: updated adr * docs: updated adr to proposed --------- Co-authored-by: Maciej Szulik <[email protected]> Co-authored-by: Brandt Keller <[email protected]>
1 parent 5cb7313 commit b7e5561

File tree

1 file changed

+90
-0
lines changed

1 file changed

+90
-0
lines changed

adr/0008-validation-refactor.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# 8. Validation Refactor
2+
3+
Date: 2025-01-16
4+
5+
## Status
6+
7+
Proposed
8+
9+
## Context
10+
11+
Execution of the Lula Validation Engine (i.e., the underlying functionality that performs evidence collection from a system of interest and evaluation of that against some policy) is tightly coupled to the OSCAL format. This is dis-advantageous for a few reasons:
12+
* Other data formats that wrap Lula Validations (e.g., Assessment Plans or a future Lula-custom aggregated validation format) are not supported. At minimum the OSCAL Assessment Plan should be a supported input to correctly instantiate the [OSCAL e2e model flow](https://pages.nist.gov/OSCAL/resources/concepts/layer/assessment/assessment-results/).
13+
* The current package structure does not allow for core functionality of Lula to be easily reused or extended. For example, a Kubernetes controller may want to use some Lula features in business logic, but not couple to the OSCAL format.
14+
15+
## Decision
16+
17+
To alleviate the rigidity of the current design, parts of the Lula library will need to be refactored, resulting in breaking changes, but ideally creating an implementation that is more modular, reusable, and generally not dependent on the data structure for Component Definitions and Assessment Results.
18+
19+
The primary outcome of this will be exposed functionality that can be thought of in following categories:
20+
21+
* Validation and Requirement collection from source - Encapsulates extracting Lula Validations and associated Requirements from the given source and loading the validations and requirements into the `ValidationStore` and `RequirementStore`, respectively.
22+
* Execution of validations - Running the Validation Engine against `ValidationStore` validations
23+
* Reporting on results - Outputting the results of the validation (i.e., the policy results) in the context of the requirements, as determined by the desired output format
24+
25+
## Consequences
26+
27+
Currently the validation logic exists in `src/pkg/common`, much of this logic will be refactored into `src/pkg/validation`. New interfaces will be introduced to support the decoupled validaiton logic.
28+
29+
The following interfaces are proposed:
30+
31+
```go
32+
// A Validation Producer interface defines the requirements, how to meet them, and associated validations
33+
type ValidationProducer interface {
34+
// Populate populates the validation store with the validations from the producer
35+
// and adds the defined requirements to the requirement store
36+
Populate(validationStore *ValidationStore, requirementStore *RequirementStore) error
37+
}
38+
39+
// Requirement is an interface that defines the requirements for validation
40+
// These are specific to the provider and contain custom logic that evaluate the "satisfaction" of the
41+
// validation against said requirement.
42+
type Requirement interface {
43+
// ID returns the unique requirement ID
44+
ID() string
45+
46+
// Description returns a requirement description
47+
Description() string
48+
49+
// EvaluateSuccess determines if the requirement is satisfied (true) and returns a message
50+
// describing the criteria evaluation
51+
EvaluateSuccess() (bool, string)
52+
53+
// GetValidations returns the validations associated with the requirement
54+
GetValidations() []*types.LulaValidation
55+
}
56+
57+
// ResultConsumer is the interface that must be implemented by any consumer of the requirements
58+
// It is responsible for evaluating the results and generating the output speific to the consumer.
59+
type ResultConsumer interface {
60+
// The GenerateResults method should take the requirements, as specified by the producer,
61+
// and generate the results in the consumer-specific custom format
62+
GenerateResults(store *RequirementStore) error
63+
}
64+
```
65+
66+
The `ValidationStore` would be redefined to be non-specific to a Component Definition/Back-Matter data storage, but instead be a more generic store of the validations:
67+
68+
```go
69+
// Contains the store for the validations and their results, once executed
70+
type ValidationStore struct {
71+
validationMap map[string]*types.LulaValidation
72+
}
73+
```
74+
75+
The purpose of the `ValidationStore` is to provide the anchor point to store the validations and execute them, using the Lula-specific validation engine, which operates on the `LulaValidation` objects.
76+
77+
The `RequirementStore` is a separate entity used to store the requirements, are different from the validations:
78+
79+
```go
80+
// Contains the store for the requirements
81+
type RequirementStore struct {
82+
requirementMap map[string]Requirement
83+
}
84+
```
85+
86+
The purpose of the `RequirementStore` is to simplify the consumer's evaluation of the requirements.
87+
88+
### Example Implementation
89+
90+
An example implementation of the above interfaces is on the `test-lib-refactor` branch of the lula repo. Specifically, this explores implementing a Component Definition as a `ValidationProducer` and the Assessment Results as a `ResultConsumer`. As well as re-defining the `ValidationStore` and `RequirementStore` to be a more generic stores of validations and requirements. Each of these have sample methods laid out, but this is subject to change as the refactor progresses.

0 commit comments

Comments
 (0)