Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(common): json schema linting for common validation(s) #473

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0d121c6
feat(validation): add initiall validation json schema
mike-winberry Jun 10, 2024
5036817
feat(common): create schema folder in common with schema functionalit…
mike-winberry Jun 10, 2024
638ccd5
feat(schema): add the validate method to run validation given a schem…
mike-winberry Jun 12, 2024
d712ce8
feat(schema): schema tests passing, still need to fix other repo vali…
mike-winberry Jun 13, 2024
eb55325
fix(schema): fix missing top level field not properly returning top l…
mike-winberry Jun 13, 2024
ab71941
Merge branch 'main' into 364-check-if-lula-validation-is-malformed-an…
mike-winberry Jun 13, 2024
42b07e6
chore(tests): fix validations used by tests, TODO: replace remote lin…
mike-winberry Jun 14, 2024
4fa91ff
Merge branch 'main' into 364-check-if-lula-validation-is-malformed-an…
mike-winberry Jun 17, 2024
593fead
Merge branch 'main' into 364-check-if-lula-validation-is-malformed-an…
mike-winberry Jul 1, 2024
be391fe
feat(schemas): worked more defined schema for domain
mike-winberry Jul 2, 2024
071e958
feat(schemas): fix validation schema and test files relating
mike-winberry Jul 2, 2024
4893bd4
fix(validation): while the documentation says name required if field …
mike-winberry Jul 2, 2024
dfba495
feat(schemas): validation schema provider and domain specs linked to …
mike-winberry Jul 3, 2024
b6a4e87
feat(schemas): add back in the resource-rule constraints
mike-winberry Jul 4, 2024
0b84a92
fix(adr): revert validation-artifact-format
mike-winberry Jul 4, 2024
eca12a0
fix(schemas): resource-rule no longer flags name as required when fie…
mike-winberry Jul 4, 2024
1b608bf
Merge branch 'main' into 364-check-if-lula-validation-is-malformed-an…
mike-winberry Jul 4, 2024
a0f768d
test(compose_test): uncomment remote validations and test case
mike-winberry Jul 4, 2024
a41673d
fix(component_test): uncomment test case
mike-winberry Jul 4, 2024
205b855
docs: fix missing optional comment in kubernetes-domain.md
mike-winberry Jul 4, 2024
154cb28
fix(validation-composition): reintroduced remote components to compon…
mike-winberry Jul 4, 2024
566f870
test(unit): fix composition compoent-definition-local-and-remote to h…
mike-winberry Jul 4, 2024
7567ad1
docs(common): add annotation about schema linting to UnmarshalYaml func
mike-winberry Jul 4, 2024
ff32ef8
refactor(schemas): removed the duplicative ExtractErrors method in fa…
mike-winberry Jul 4, 2024
2fbd52f
docs(reference): update the Validation reference readme
mike-winberry Jul 4, 2024
6c2364a
fix(schemas): validation schema fixed create-resources, semver, and k…
mike-winberry Jul 4, 2024
984a33a
docs: update reference/README.md
mike-winberry Jul 4, 2024
1b01f65
chore: remove lula.schema.json
mike-winberry Jul 10, 2024
b0914c2
feat(lint): add composition to lint that can be disabled using the -c…
mike-winberry Jul 10, 2024
bb076aa
chore(docs): add schema-updates.md
mike-winberry Jul 10, 2024
500574f
Merge branch 'main' into 364-check-if-lula-validation-is-malformed-an…
mike-winberry Jul 10, 2024
45a7579
refactor(cmd): rm composition from tools lint
mike-winberry Jul 11, 2024
04e2399
feat(cmd): add dev validate command.
mike-winberry Jul 11, 2024
96a4a31
Merge branch 'main' into 364-check-if-lula-validation-is-malformed-an…
mike-winberry Jul 11, 2024
dc0b8ad
Merge branch 'main' into 364-check-if-lula-validation-is-malformed-an…
brandtkeller Jul 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ Relates to #
## Checklist before merging

- [ ] Test, docs, adr added or updated as needed
- [ ] [Schema Updates](https://github.com/defenseunicorns/lula/blob/main/docs/community-and-contribution/schema-updates.md) applied
- [ ] [Contributor Guide Steps](https://github.com/defenseunicorns/lula/blob/main/CONTRIBUTING.md) followed
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ CLI_VERSION ?= $(if $(shell git describe --tags),$(shell git describe --tags),"u

# Go CLI options
PKG := ./...
UNIT_PKG := $(shell go list ./... | grep -v 'e2e')
TAGS :=
TESTS := .
TESTFLAGS := -race -v
Expand Down Expand Up @@ -63,6 +64,10 @@ $(BINDIR)/$(BINNAME): $(SRC)
test:
go clean -testcache && go test $(GOFLAGS) -run $(TESTS) $(PKG) $(TESTFLAGS)

.PHONY: test-unit
test-unit: # Run tests excluding those in the e2e folder.
go clean -testcache && go test $(GOFLAGS) -run $(TESTS) $(UNIT_PKG) $(TESTFLAGS)

.PHONY: test-e2e
test-e2e:
cd src/test/e2e && go clean -testcache && go test $(GOFLAGS) -run $(TESTS) $(PKG) $(TESTFLAGS)
Expand All @@ -74,4 +79,3 @@ test-cmd:
.PHONY: install
install: ## Install binary to $INSTALL_PATH.
@install "$(BINDIR)/$(BINNAME)" "$(INSTALL_PATH)/$(BINNAME)"

30 changes: 30 additions & 0 deletions docs/cli-commands/dev/lint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Lint Command

The `lula dev lint` command is used to validate validation files against the schema. It can validate both local files and URLs.

## Usage

```bash
lula dev lint -f <input-files> [-r <result-file>]
```

## Options

- `-f, --input-files`: The paths to the validation files (comma-separated).
- `-r, --result-file`: The path to the result file. If not specified, the validation results will be printed to the console.

## Examples

To lint existing validation files:
```bash
lula dev lint -f ./validation-file1.yaml,./validation-file2.yaml,https://example.com/validation-file3.yaml
```

To specify a result file:
```bash
lula dev lint -f ./validation-file1.yaml,./validation-file2.yaml -r validation-results.json
```

## Notes

The validation results will be written to the specified result file. If there is at least one validation result that is not valid, the command will exit with a fatal error listing the files that failed linting.
4 changes: 2 additions & 2 deletions docs/cli-commands/tools/compose.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Compose Command

The `compose` command is used to compose an OSCAL component definition. It is used to compose remote validations within a component definition in order to resolve any references for portability.
The `lula tools compose` command is used to compose an OSCAL component definition. It is used to compose remote validations within a component definition in order to resolve any references for portability.

## Usage

Expand All @@ -11,7 +11,7 @@ lula tools compose -f <input-file> -o <output-file>
## Options

- `-f, --input-file`: The path to the target OSCAL component definition.
- `-o, --output-file`: The path to the output file. If not specified, the output file will be the original filename with `-composed` appended.
- `-o, --output-file`: The path to the output file. If not specified, the output file will be the original filename with `-composed` appended (ie. `oscal-component.yaml` will be composed to `oscal-component-composed.yaml`).

## Examples

Expand Down
32 changes: 32 additions & 0 deletions docs/cli-commands/tools/lint.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Lint Command

The `lula tools lint` command is used to validate OSCAL files against the OSCAL schema. It can validate both composed and non-composed OSCAL models.
> **Note**: the `lint` command does not compose the OSCAL model.
> If you want to validate a composed OSCAL model, you should use the [`lula tools compose`](../compose/README.md) command first.

## Usage

```bash
lula tools lint -f <input-files> [-r <result-file>]
```

## Options

- `-f, --input-files`: The paths to the tar get OSCAL files (comma-separated).
- `-r, --result-file`: The path to the result file. If not specified, the validation results will be printed to the console.

## Examples

To lint existing OSCAL files:
```bash
lula tools lint -f ./oscal-component1.yaml,./oscal-component2.yaml
```

To specify a result file:
```bash
lula tools lint -f ./oscal-component1.yaml,./oscal-component2.yaml -r validation-results.json
```

## Notes

If no input files are specified, an error will be returned. The validation results will be written to the specified result file. If no result file is specified, the validation results will be printed to the console. If there is at least one validation result that is not valid, the command will exit with a fatal error listing the files that failed linting.
3 changes: 3 additions & 0 deletions docs/community-and-contribution/schema-updates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Schema Updates

Any changes type changes effecting one of the schemas in `src/pkg/common/schemas` should be reflected in the relevant `types.go` file and vice versa. This will ensure that the schema is kept in sync with the Go type definitions.
97 changes: 96 additions & 1 deletion docs/reference/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,96 @@
# Validation Reference
# Validation Reference

### Validation Struct

The `Validation` struct is a data structure used for ingesting validation data. It contains the following fields:

- `LulaVersion` (string): Optional field to maintain backward compatibility.
- `Metadata` (*Metadata): Optional metadata containing the name and UUID of the validation.
- `Provider` (*Provider): Required field specifying the provider and its corresponding specification.
- `Domain` (*Domain): Required field specifying the domain and its corresponding specification.

#### Metadata Struct

The `Metadata` struct contains the following fields:

- `Name` (string): Optional short description to use in the output of validations.
- `UUID` (string): Optional UUID of the validation.

#### Domain Struct

The `Domain` struct contains the following fields:

- `Type` (string): Required field specifying the type of domain (enum: `kubernetes`, `api`).
- `KubernetesSpec` (*KubernetesSpec): Optional specification for a Kubernetes domain, required if type is `kubernetes`.
- `ApiSpec` (*ApiSpec): Optional specification for an API domain, required if type is `api`.

#### Provider Struct

The `Provider` struct contains the following fields:

- `Type` (string): Required field specifying the type of provider (enum: `opa`, `kyverno`).
- `OpaSpec` (*OpaSpec): Optional specification for an OPA provider.
- `KyvernoSpec` (*KyvernoSpec): Optional specification for a Kyverno provider.

### Example YAML Document

The following is an example of a YAML document for a validation artifact:
```yaml
lula-version: ">=v0.2.0"
metadata:
name: Validate pods with label foo=bar
uuid: 123e4567-e89b-12d3-a456-426655440000
domain:
type: kubernetes
kubernetes-spec:
resources:
- name: podsvt
resource-rule:
version: v1
resource: pods
namespaces: [validation-test]
provider:
type: opa
opa-spec:
rego: |
package validate

import future.keywords.every

validate {
every pod in input.podsvt {
podLabel := pod.metadata.labels.foo
podLabel == "bar"
}
}
```
## Linting
Linting is done by Lula when a `Validation` object is converted to a `LulaValidation` for evaluation.

The `common.Validation.Lint` method is a convenience method to lint a `Validation` object. It performs the following step:

1. **Marshalling**: The method marshals the `Validation` object into a YAML byte array using the `common.Validation.MarshalYaml` function.
2. **Linting**: The method runs linting against the marshalled `Validation` object. This is done using the `schemas.Validate` function, which ensures that the YAML data conforms to the expected [schema](../../src/pkg/common/schemas/validation.json).

___
The `schemas.Validate` function is responsible for validating the provided data against a specified JSON schema using [github.com/santhosh-tekuri/jsonschema/v5](https://github.com/santhosh-tekuri/jsonschema). The process involves the following steps:

1. **Coercion to JSON Map**: The provided data, which can be either an interface or a byte array, is coerced into a JSON map using the `model.CoerceToJsonMap` function.
2. **Schema Retrieval**: The function retrieves the JSON schema specified by the `schema` parameter using the `GetSchema` function.
3. **Schema Compilation**: The retrieved schema is compiled into a format that can be used for validation using the `jsonschema.CompileString` function.
4. **Validation**: The coerced JSON map is validated against the compiled schema. If the validation fails, the function extracts the specific errors and returns them as a formatted string.

## VS Code intellisense:
1. Ensure that the [YAML (Red Hat)](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) extension is installed.
2. Add the following to your settings.json:
```json
"yaml.schemas": {
"${PATH_TO_LULA}/lula/src/pkg/common/schemas/validation.json": "*validation*.yaml"
},
```


> **Note:**
> - `${PATH_TO_LULA}` should be replaced with your path.
> - `*validation*.yaml` may be changed to match your project's validation file naming conventions.
> - can also be limited to project or workspace settings if desired
4 changes: 2 additions & 2 deletions docs/reference/domains/kubernetes-domain.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ domain:
- name: podsvt # Required - Identifier to be read by the policy
resource-rule: # Required - resource selection criteria, at least one resource rule is required
name: # Optional - Used to retrieve a specific resource in a single namespace
group: # Required - empty or "" for core group
group: # Optional - empty or "" for core group
version: v1 # Required - Version of resource
resource: pods # Required - Resource type (API-recognized type, not Kind)
namespaces: [validation-test] # Required - Namespaces to validate the above resources in. Empty or "" for all namespace pr non-namespaced resources
namespaces: [validation-test] # Optional - Namespaces to validate the above resources in. Empty or "" for all namespace pr non-namespaced resources
field: # Optional - Field to grab in a resource if it is in an unusable type, e.g., string json data. Must specify named resource to use.
jsonpath: # Required - Jsonpath specifier of where to find the field from the top level object
type: # Optional - Accepts "json" or "yaml". Default is "json".
Expand Down
Loading