assertions-mate 0.2.0__tar.gz → 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- assertions_mate-0.4.0/.env +1 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/.gitignore +3 -1
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/PKG-INFO +7 -1
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/README.md +6 -0
- assertions_mate-0.4.0/Taskfile.yaml +46 -0
- assertions_mate-0.4.0/docs/explanation/architecture.md +66 -0
- assertions_mate-0.4.0/docs/explanation/compatibility-and-limitations.md +40 -0
- assertions_mate-0.4.0/docs/explanation/testing-and-reliability.md +32 -0
- assertions_mate-0.4.0/docs/how-to/add-cql2-polygon-area-function.md +57 -0
- assertions_mate-0.4.0/docs/how-to/author-cql2-json-encoding.md +46 -0
- assertions_mate-0.4.0/docs/how-to/combine-multiple-hints.md +57 -0
- assertions_mate-0.4.0/docs/how-to/create-reusable-rego-snippets.md +52 -0
- assertions_mate-0.4.0/docs/how-to/test-hints-with-pytest.md +27 -0
- assertions_mate-0.4.0/docs/how-to/troubleshoot-cwl-loader-errors.md +19 -0
- assertions_mate-0.4.0/docs/how-to/troubleshoot-rego-invalid-literal.md +32 -0
- assertions_mate-0.4.0/docs/how-to/use-packed-vs-single-cwl.md +28 -0
- assertions_mate-0.4.0/docs/how-to/validate-array-cardinality-jsonschema.md +48 -0
- assertions_mate-0.4.0/docs/how-to/validate-bbox-overlap-cql2.md +53 -0
- assertions_mate-0.4.0/docs/how-to/validate-conditional-required-rego.md +46 -0
- assertions_mate-0.4.0/docs/how-to/validate-cross-field-dependency-rego.md +46 -0
- assertions_mate-0.4.0/docs/how-to/validate-date-range-inputs.md +85 -0
- assertions_mate-0.4.0/docs/how-to/validate-datetime-input.md +83 -0
- assertions_mate-0.4.0/docs/how-to/validate-datetime-window-rego.md +64 -0
- assertions_mate-0.4.0/docs/how-to/validate-disjoint-geometries-cql2.md +38 -0
- assertions_mate-0.4.0/docs/how-to/validate-enum-jsonschema.md +45 -0
- assertions_mate-0.4.0/docs/how-to/validate-numeric-range-rego.md +48 -0
- assertions_mate-0.4.0/docs/how-to/validate-optional-input-rego.md +51 -0
- assertions_mate-0.4.0/docs/how-to/validate-point-in-polygon-cql2.md +43 -0
- assertions_mate-0.4.0/docs/how-to/validate-polygon-area-cql2.md +42 -0
- assertions_mate-0.4.0/docs/how-to/validate-polygon-intersects-aoi-cql2.md +38 -0
- assertions_mate-0.4.0/docs/how-to/validate-polygon-parameter.md +82 -0
- assertions_mate-0.4.0/docs/how-to/validate-required-property-rego.md +41 -0
- assertions_mate-0.4.0/docs/how-to/validate-uri-host-rego.md +57 -0
- assertions_mate-0.4.0/docs/how-to/validate-uri-input.md +78 -0
- assertions_mate-0.4.0/docs/index.md +44 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/docs/jsonschema.ipynb +10 -2
- assertions_mate-0.4.0/docs/pygeofilter.ipynb +3070 -0
- assertions_mate-0.4.0/docs/reference/cli.md +41 -0
- assertions_mate-0.4.0/docs/reference/errors.md +50 -0
- assertions_mate-0.4.0/docs/reference/hints.md +60 -0
- assertions_mate-0.4.0/docs/reference/hints_schema.html +226 -0
- assertions_mate-0.4.0/docs/reference/runtime-compatibility.md +53 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/docs/regopy.ipynb +39 -22
- assertions_mate-0.4.0/docs/tutorials/first-validated-workflow.md +93 -0
- assertions_mate-0.4.0/examples/array-cardinality-validation/inputs-invalid.yaml +1 -0
- assertions_mate-0.4.0/examples/array-cardinality-validation/inputs-valid.yaml +1 -0
- assertions_mate-0.4.0/examples/array-cardinality-validation/workflow.cwl +20 -0
- assertions_mate-0.4.0/examples/bbox-overlap-validation/inputs-invalid.yaml +2 -0
- assertions_mate-0.4.0/examples/bbox-overlap-validation/inputs-valid.yaml +2 -0
- assertions_mate-0.4.0/examples/bbox-overlap-validation/workflow.cwl +33 -0
- assertions_mate-0.4.0/examples/conditional-required-validation/inputs-invalid.yaml +2 -0
- assertions_mate-0.4.0/examples/conditional-required-validation/inputs-valid.yaml +9 -0
- assertions_mate-0.4.0/examples/conditional-required-validation/workflow.cwl +24 -0
- assertions_mate-0.4.0/examples/cql2-json-validation/inputs-invalid.yaml +1 -0
- assertions_mate-0.4.0/examples/cql2-json-validation/inputs-valid.yaml +1 -0
- assertions_mate-0.4.0/examples/cql2-json-validation/workflow.cwl +18 -0
- assertions_mate-0.4.0/examples/cross-field-dependency-validation/inputs-invalid.yaml +2 -0
- assertions_mate-0.4.0/examples/cross-field-dependency-validation/inputs-valid.yaml +2 -0
- assertions_mate-0.4.0/examples/cross-field-dependency-validation/workflow.cwl +24 -0
- assertions_mate-0.4.0/examples/date-range-validation/README.md +30 -0
- assertions_mate-0.4.0/examples/date-range-validation/inputs-invalid.yaml +4 -0
- assertions_mate-0.4.0/examples/date-range-validation/inputs-null.yaml +4 -0
- assertions_mate-0.4.0/examples/date-range-validation/inputs-valid.yaml +4 -0
- assertions_mate-0.4.0/examples/date-range-validation/workflow.cwl +79 -0
- assertions_mate-0.4.0/examples/datetime-validation/README.md +30 -0
- assertions_mate-0.4.0/examples/datetime-validation/inputs-invalid.yaml +2 -0
- assertions_mate-0.4.0/examples/datetime-validation/inputs-null.yaml +2 -0
- assertions_mate-0.4.0/examples/datetime-validation/inputs-valid.yaml +2 -0
- assertions_mate-0.4.0/examples/datetime-validation/workflow.cwl +46 -0
- assertions_mate-0.4.0/examples/datetime-window-validation/inputs-invalid.yaml +2 -0
- assertions_mate-0.4.0/examples/datetime-window-validation/inputs-valid.yaml +2 -0
- assertions_mate-0.4.0/examples/datetime-window-validation/workflow.cwl +35 -0
- assertions_mate-0.4.0/examples/disjoint-geometries-validation/inputs-invalid.yaml +16 -0
- assertions_mate-0.4.0/examples/disjoint-geometries-validation/inputs-valid.yaml +16 -0
- assertions_mate-0.4.0/examples/disjoint-geometries-validation/workflow.cwl +16 -0
- assertions_mate-0.4.0/examples/enum-validation/inputs-invalid.yaml +1 -0
- assertions_mate-0.4.0/examples/enum-validation/inputs-valid.yaml +1 -0
- assertions_mate-0.4.0/examples/enum-validation/workflow.cwl +17 -0
- assertions_mate-0.4.0/examples/multi-hint-validation/inputs-invalid.yaml +17 -0
- assertions_mate-0.4.0/examples/multi-hint-validation/inputs-valid.yaml +17 -0
- assertions_mate-0.4.0/examples/multi-hint-validation/workflow.cwl +36 -0
- assertions_mate-0.4.0/examples/numeric-range-validation/inputs-invalid.yaml +1 -0
- assertions_mate-0.4.0/examples/numeric-range-validation/inputs-valid.yaml +1 -0
- assertions_mate-0.4.0/examples/numeric-range-validation/workflow.cwl +26 -0
- assertions_mate-0.4.0/examples/optional-input-validation/inputs-invalid.yaml +1 -0
- assertions_mate-0.4.0/examples/optional-input-validation/inputs-valid.yaml +1 -0
- assertions_mate-0.4.0/examples/optional-input-validation/workflow.cwl +23 -0
- assertions_mate-0.4.0/examples/point-in-polygon-validation/README.md +23 -0
- assertions_mate-0.4.0/examples/point-in-polygon-validation/inputs-invalid.yaml +11 -0
- assertions_mate-0.4.0/examples/point-in-polygon-validation/inputs-valid.yaml +11 -0
- assertions_mate-0.4.0/examples/point-in-polygon-validation/workflow.cwl +23 -0
- assertions_mate-0.4.0/examples/polygon-intersects-validation/inputs-invalid.yaml +16 -0
- assertions_mate-0.4.0/examples/polygon-intersects-validation/inputs-valid.yaml +16 -0
- assertions_mate-0.4.0/examples/polygon-intersects-validation/workflow.cwl +16 -0
- assertions_mate-0.4.0/examples/polygon-validation/README.md +23 -0
- assertions_mate-0.4.0/examples/polygon-validation/inputs-invalid.yaml +4 -0
- assertions_mate-0.4.0/examples/polygon-validation/inputs-null.yaml +1 -0
- assertions_mate-0.4.0/examples/polygon-validation/inputs-valid.yaml +9 -0
- assertions_mate-0.4.0/examples/polygon-validation/workflow.cwl +27 -0
- assertions_mate-0.4.0/examples/pytest-validation/test_validators_example.py +20 -0
- assertions_mate-0.4.0/examples/required-property-validation/inputs-invalid.yaml +9 -0
- assertions_mate-0.4.0/examples/required-property-validation/inputs-valid.yaml +10 -0
- assertions_mate-0.4.0/examples/required-property-validation/workflow.cwl +19 -0
- assertions_mate-0.4.0/examples/reusable-rego-snippets/inputs-invalid.yaml +2 -0
- assertions_mate-0.4.0/examples/reusable-rego-snippets/inputs-valid.yaml +2 -0
- assertions_mate-0.4.0/examples/reusable-rego-snippets/workflow.cwl +32 -0
- assertions_mate-0.4.0/examples/uri-host-validation/inputs-invalid.yaml +1 -0
- assertions_mate-0.4.0/examples/uri-host-validation/inputs-valid.yaml +1 -0
- assertions_mate-0.4.0/examples/uri-host-validation/workflow.cwl +26 -0
- assertions_mate-0.4.0/examples/uri-validation/README.md +30 -0
- assertions_mate-0.4.0/examples/uri-validation/inputs-invalid.yaml +2 -0
- assertions_mate-0.4.0/examples/uri-validation/inputs-null.yaml +2 -0
- assertions_mate-0.4.0/examples/uri-validation/inputs-valid.yaml +2 -0
- assertions_mate-0.4.0/examples/uri-validation/workflow.cwl +46 -0
- assertions_mate-0.4.0/mkdocs.yaml +137 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/pyproject.toml +10 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/schemas/hints.yaml +16 -6
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/src/assertions_mate/__about__.py +1 -1
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/src/assertions_mate/__init__.py +4 -2
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/src/assertions_mate/cql2_validator.py +24 -19
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/src/assertions_mate/rego_validator.py +1 -1
- assertions_mate-0.4.0/tests/test_cql2_validator.py +86 -0
- assertions_mate-0.4.0/tests/test_howto_hints.py +83 -0
- assertions_mate-0.2.0/Taskfile.yaml +0 -32
- assertions_mate-0.2.0/docs/index.md +0 -9
- assertions_mate-0.2.0/docs/pygeofilter.ipynb +0 -191
- assertions_mate-0.2.0/mkdocs.yaml +0 -102
- assertions_mate-0.2.0/tests/test_cql2_validator.py +0 -51
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/.github/workflows/docs.yaml +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/.github/workflows/package.yaml +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/LICENSE +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/NOTICE +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/docs/diagrams/src/class.puml +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/docs/diagrams/src/flow.puml +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/docs/diagrams/src/overall.puml +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/docs/diagrams/src/sequence.puml +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/src/assertions_mate/cli.py +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/src/assertions_mate/error_models.py +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/src/assertions_mate/jsonschema_validator.py +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/tests/artifacts/request_body.yaml +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/tests/test_hints.py +0 -0
- {assertions_mate-0.2.0 → assertions_mate-0.4.0}/tests/test_jsonschema_validator.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
TASK_X_REMOTE_TASKFILES=1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: assertions-mate
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Project-URL: Documentation, https://github.com/Terradue/assertions-mate#README.md
|
|
5
5
|
Project-URL: Issues, https://github.com/Terradue/assertions-mate/issues
|
|
6
6
|
Project-URL: Source, https://github.com/Terradue/assertions-mate
|
|
@@ -42,6 +42,12 @@ It adds policy and rule checks on top of CWL typing by supporting:
|
|
|
42
42
|
|
|
43
43
|
Documentation site: https://terradue.github.io/assertions-mate/
|
|
44
44
|
|
|
45
|
+
Documentation follows the Diataxis framework:
|
|
46
|
+
- Tutorials: learning-oriented walkthroughs
|
|
47
|
+
- How-to guides: task-focused recipes
|
|
48
|
+
- Reference: technical contracts and interfaces
|
|
49
|
+
- Explanation: design rationale and concepts
|
|
50
|
+
|
|
45
51
|
## Why Use It
|
|
46
52
|
|
|
47
53
|
When a CWL workflow needs stricter runtime checks (business rules, policy constraints, geospatial conditions), `assertions-mate` lets you define them as workflow hints and evaluate them against an input payload before execution.
|
|
@@ -9,6 +9,12 @@ It adds policy and rule checks on top of CWL typing by supporting:
|
|
|
9
9
|
|
|
10
10
|
Documentation site: https://terradue.github.io/assertions-mate/
|
|
11
11
|
|
|
12
|
+
Documentation follows the Diataxis framework:
|
|
13
|
+
- Tutorials: learning-oriented walkthroughs
|
|
14
|
+
- How-to guides: task-focused recipes
|
|
15
|
+
- Reference: technical contracts and interfaces
|
|
16
|
+
- Explanation: design rationale and concepts
|
|
17
|
+
|
|
12
18
|
## Why Use It
|
|
13
19
|
|
|
14
20
|
When a CWL workflow needs stricter runtime checks (business rules, policy constraints, geospatial conditions), `assertions-mate` lets you define them as workflow hints and evaluate them against an input payload before execution.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Copyright 2026 Terradue
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
version: '3'
|
|
16
|
+
|
|
17
|
+
includes:
|
|
18
|
+
quality: https://raw.githubusercontent.com/Terradue/taskfile-utils/refs/heads/main/quality.yaml
|
|
19
|
+
|
|
20
|
+
tasks:
|
|
21
|
+
|
|
22
|
+
default:
|
|
23
|
+
cmds:
|
|
24
|
+
- task: quality:test
|
|
25
|
+
- task: quality:check
|
|
26
|
+
|
|
27
|
+
generate_schema_doc:
|
|
28
|
+
cmds:
|
|
29
|
+
- |
|
|
30
|
+
uv run \
|
|
31
|
+
--no-cache \
|
|
32
|
+
--no-project \
|
|
33
|
+
--with schema-salad \
|
|
34
|
+
schema-salad-doc \
|
|
35
|
+
--only 'http://oeap.github.io/schema#JSONSchemaHint' \
|
|
36
|
+
--only 'http://oeap.github.io/schema#RegoPolicyHint' \
|
|
37
|
+
--only 'http://oeap.github.io/schema#Cql2Query' \
|
|
38
|
+
--only 'http://oeap.github.io/schema#Cql2FilterHint' \
|
|
39
|
+
./schemas/hints.yaml > ./docs/reference/hints_schema.html
|
|
40
|
+
|
|
41
|
+
docs:serve:
|
|
42
|
+
desc: "Serve MkDocs site using hatch docs environment"
|
|
43
|
+
cmds:
|
|
44
|
+
- |
|
|
45
|
+
set -euo pipefail
|
|
46
|
+
HATCH_DATA_DIR="$PWD/.task/hatch" hatch run docs:serve
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Architecture and Design
|
|
2
|
+
|
|
3
|
+
`assertions-mate` is built around hint-driven validation for CWL workflows.
|
|
4
|
+
|
|
5
|
+
## Why Hints
|
|
6
|
+
|
|
7
|
+
CWL input typing can enforce structure, but many operational constraints are semantic:
|
|
8
|
+
- policy constraints
|
|
9
|
+
- domain rules
|
|
10
|
+
- geospatial relationships
|
|
11
|
+
|
|
12
|
+
Hints let these constraints travel with workflow definitions and be checked consistently before runtime.
|
|
13
|
+
|
|
14
|
+
## Validation Flow
|
|
15
|
+
|
|
16
|
+
1. Load CWL workflow document(s).
|
|
17
|
+
2. Read `workflow.hints`.
|
|
18
|
+
3. Map supported `eoap:*` hint classes to typed hint models.
|
|
19
|
+
4. Build validator objects from hints.
|
|
20
|
+
5. Run each validator against provided inputs.
|
|
21
|
+
6. Aggregate and log violations.
|
|
22
|
+
|
|
23
|
+
## Execution Semantics
|
|
24
|
+
|
|
25
|
+
`assertions-mate` follows a best-effort setup model:
|
|
26
|
+
|
|
27
|
+
- each hint is mapped and initialized independently
|
|
28
|
+
- setup failures for one hint do not prevent other hints from running
|
|
29
|
+
- validation output is therefore partial if one validator fails to initialize
|
|
30
|
+
|
|
31
|
+
This model favors operational continuity and progressive validation.
|
|
32
|
+
|
|
33
|
+
## Validator Model
|
|
34
|
+
|
|
35
|
+
Each hint type is responsible for producing a validator via `.validator()`.
|
|
36
|
+
|
|
37
|
+
This keeps:
|
|
38
|
+
- hint parsing and serialization concerns in hint models
|
|
39
|
+
- runtime validation behavior in validator classes
|
|
40
|
+
|
|
41
|
+
## Input Shape and Key Resolution
|
|
42
|
+
|
|
43
|
+
Validators operate on the loaded input mapping as-is.
|
|
44
|
+
|
|
45
|
+
Implications:
|
|
46
|
+
- input keys must match workflow input names exactly
|
|
47
|
+
- object wrappers such as `value` must be handled explicitly in rules (for example in Rego)
|
|
48
|
+
- inconsistent shape across workflows can produce false negatives if rules target the wrong path
|
|
49
|
+
|
|
50
|
+
## Supported Rule Languages
|
|
51
|
+
|
|
52
|
+
- JSON Schema: structural constraints over payload shape and values
|
|
53
|
+
- Rego: policy-oriented queries and rich rule composition
|
|
54
|
+
- CQL2: declarative predicate checks, including geospatial expressions
|
|
55
|
+
|
|
56
|
+
## Reliability Tradeoffs
|
|
57
|
+
|
|
58
|
+
- Strength: multi-validator execution can still produce useful checks when one hint fails setup.
|
|
59
|
+
- Tradeoff: setup errors and runtime backend constraints may reduce total coverage for a given run.
|
|
60
|
+
- Practical guidance: treat logs as part of the contract and monitor setup failures explicitly in CI.
|
|
61
|
+
|
|
62
|
+
## Known Gaps and Improvement Areas
|
|
63
|
+
|
|
64
|
+
- Runtime-specific parser differences can affect CWL load behavior and Rego syntax support.
|
|
65
|
+
- Some CQL2 features require explicit coercion helpers (`ensure_spatial`, `ensure_bbox`).
|
|
66
|
+
- Strict fail-fast exit semantics for reported violations are not yet guaranteed in all execution paths.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Compatibility and Limitations
|
|
2
|
+
|
|
3
|
+
This page explains where runtime behavior depends on parser and backend versions.
|
|
4
|
+
|
|
5
|
+
## Rego Runtime Coupling
|
|
6
|
+
|
|
7
|
+
Rego syntax support is runtime-dependent.
|
|
8
|
+
|
|
9
|
+
Stable pattern in current examples:
|
|
10
|
+
|
|
11
|
+
```rego
|
|
12
|
+
deny[msg] {
|
|
13
|
+
condition
|
|
14
|
+
msg := "..."
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Depending on runtime, newer syntax forms can fail with parser errors such as `Invalid literal`.
|
|
19
|
+
|
|
20
|
+
## CQL2 Backend Constraints
|
|
21
|
+
|
|
22
|
+
CQL2 spatial predicates operate reliably when payloads are coerced with helper functions:
|
|
23
|
+
|
|
24
|
+
- `ensure_spatial(...)` for GeoJSON geometry objects
|
|
25
|
+
|
|
26
|
+
Without coercion, backend exceptions can occur because predicates receive non-geometry objects.
|
|
27
|
+
|
|
28
|
+
## External CWL Type References
|
|
29
|
+
|
|
30
|
+
External schema refs (for example EOAP `#DateTime`, `#Polygon`) may require online resolution and parser compatibility.
|
|
31
|
+
|
|
32
|
+
Operational impact:
|
|
33
|
+
- local/offline environments may fail to resolve external refs
|
|
34
|
+
- integration tests should allow offline skip behavior
|
|
35
|
+
|
|
36
|
+
## JSON CQL2 From YAML
|
|
37
|
+
|
|
38
|
+
YAML-native scalar wrappers can affect CQL2 JSON evaluation if not normalized.
|
|
39
|
+
|
|
40
|
+
Current validator behavior includes normalization to builtin Python values before parsing CQL2 JSON, improving reliability.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Testing and Reliability
|
|
2
|
+
|
|
3
|
+
This project benefits from a split testing strategy.
|
|
4
|
+
|
|
5
|
+
## Unit Tests
|
|
6
|
+
|
|
7
|
+
Focus on deterministic behavior with local types and direct validator logic.
|
|
8
|
+
|
|
9
|
+
Examples:
|
|
10
|
+
- hint extraction and mapping tests
|
|
11
|
+
- CQL2 text/json predicate tests
|
|
12
|
+
- JSON schema validation tests
|
|
13
|
+
|
|
14
|
+
## Integration-Oriented Tests
|
|
15
|
+
|
|
16
|
+
Use real example workflows and external type references.
|
|
17
|
+
|
|
18
|
+
Because these can require network and parser compatibility, they should:
|
|
19
|
+
- skip when offline
|
|
20
|
+
- be isolated from core deterministic tests
|
|
21
|
+
|
|
22
|
+
## Reliability Patterns for CI
|
|
23
|
+
|
|
24
|
+
- treat hint setup errors as first-class signals
|
|
25
|
+
- include at least one valid and one invalid case per how-to example
|
|
26
|
+
- prefer stable syntax subsets for Rego and CQL2 in production pipelines
|
|
27
|
+
|
|
28
|
+
## Practical Guardrails
|
|
29
|
+
|
|
30
|
+
- keep payload key names aligned with workflow inputs
|
|
31
|
+
- document scalar vs wrapped object shapes (`value`) and test both where applicable
|
|
32
|
+
- reuse proven example expressions to avoid backend incompatibilities
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# How-to: Add `polygon_area(...)` to the CQL2 Evaluator
|
|
2
|
+
|
|
3
|
+
This guide shows how to extend `assertions-mate` so CQL2 rules can compare polygon area against a fixed threshold.
|
|
4
|
+
|
|
5
|
+
## Goal
|
|
6
|
+
|
|
7
|
+
Enable expressions like:
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
polygon_area(aoi) < 1000
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 1. Define the new function in a CQL2 hint
|
|
14
|
+
|
|
15
|
+
In your workflow hints, plug the suggested implementation:
|
|
16
|
+
|
|
17
|
+
```yaml
|
|
18
|
+
hints:
|
|
19
|
+
- class: eoap:Cql2FilterHint
|
|
20
|
+
custom_functions: |
|
|
21
|
+
from shapely import geometry
|
|
22
|
+
from typing import Any, List, Mapping, Union
|
|
23
|
+
|
|
24
|
+
def polygon_area(input: Union[Mapping[str, Any], List[Any]]):
|
|
25
|
+
"""Return area for a GeoJSON Polygon payload or raw coordinates list."""
|
|
26
|
+
if isinstance(input, dict):
|
|
27
|
+
geo_type = input.get("type")
|
|
28
|
+
coords = input.get("coordinates")
|
|
29
|
+
if geo_type != "Polygon" or not coords:
|
|
30
|
+
raise ValueError("Input must be a GeoJSON Polygon with coordinates")
|
|
31
|
+
geom = geometry.Polygon(coords[0])
|
|
32
|
+
return geom.area
|
|
33
|
+
|
|
34
|
+
if isinstance(input, list):
|
|
35
|
+
geom = geometry.Polygon(input[0] if input and isinstance(input[0], list) else input)
|
|
36
|
+
return geom.area
|
|
37
|
+
|
|
38
|
+
raise ValueError(f"Unsupported polygon input type: {type(input)}")
|
|
39
|
+
queries:
|
|
40
|
+
- id: aoi-area-limit
|
|
41
|
+
cql2: "polygon_area(aoi) < 1000"
|
|
42
|
+
message: "AOI area must be smaller than 1000"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 2. Validate with CLI
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
assertions-mate path/to/workflow.cwl --inputs path/to/inputs.yaml
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Notes on units
|
|
52
|
+
|
|
53
|
+
If AOI coordinates are lon/lat (EPSG:4326), `polygon_area` from Shapely returns degree-squared values, not square meters.
|
|
54
|
+
|
|
55
|
+
For metric thresholds, either:
|
|
56
|
+
- reproject geometry before computing area
|
|
57
|
+
- or compute geodesic area with a dedicated geodesic approach
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# How-to: Author CQL2 Rules in JSON Encoding
|
|
2
|
+
|
|
3
|
+
You can provide `cql2` as JSON, not only text.
|
|
4
|
+
|
|
5
|
+
## 1. Define the input
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
inputs:
|
|
9
|
+
mode:
|
|
10
|
+
type: string
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 2. Add CQL2 JSON rule
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
hints:
|
|
17
|
+
- class: eoap:Cql2FilterHint
|
|
18
|
+
queries:
|
|
19
|
+
- id: mode-is-strict
|
|
20
|
+
cql2:
|
|
21
|
+
op: "="
|
|
22
|
+
args:
|
|
23
|
+
- property: mode
|
|
24
|
+
- "strict"
|
|
25
|
+
message: "mode must be strict"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 3. Validate with sample values
|
|
29
|
+
|
|
30
|
+
Valid:
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
mode: "strict"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Run:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
assertions-mate workflow.cwl --inputs inputs-valid.yaml
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Ready-to-run example in this repository
|
|
43
|
+
|
|
44
|
+
- `examples/cql2-json-validation/workflow.cwl`
|
|
45
|
+
- `examples/cql2-json-validation/inputs-valid.yaml`
|
|
46
|
+
- `examples/cql2-json-validation/inputs-invalid.yaml`
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# How-to: Combine Multiple Hints in One Workflow
|
|
2
|
+
|
|
3
|
+
Use `JSONSchemaHint`, `RegoPolicyHint`, and `Cql2FilterHint` together to enforce structure, policy, and spatial predicates.
|
|
4
|
+
|
|
5
|
+
## 1. Define the inputs
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
inputs:
|
|
9
|
+
count:
|
|
10
|
+
type: int
|
|
11
|
+
aoi:
|
|
12
|
+
type: https://raw.githubusercontent.com/eoap/schemas/main/geojson.yaml#Polygon
|
|
13
|
+
candidate:
|
|
14
|
+
type: https://raw.githubusercontent.com/eoap/schemas/main/geojson.yaml#Polygon
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 2. Add multiple hints
|
|
18
|
+
|
|
19
|
+
```yaml
|
|
20
|
+
hints:
|
|
21
|
+
- class: eoap:JSONSchemaHint
|
|
22
|
+
json_schema:
|
|
23
|
+
type: object
|
|
24
|
+
required: [count, aoi, candidate]
|
|
25
|
+
properties:
|
|
26
|
+
count:
|
|
27
|
+
type: integer
|
|
28
|
+
minimum: 1
|
|
29
|
+
- class: eoap:RegoPolicyHint
|
|
30
|
+
module: |
|
|
31
|
+
package workflow
|
|
32
|
+
deny[msg] {
|
|
33
|
+
input["count"] > 10
|
|
34
|
+
msg := "count must be <= 10"
|
|
35
|
+
}
|
|
36
|
+
queries:
|
|
37
|
+
- data.workflow.deny[_]
|
|
38
|
+
- class: eoap:Cql2FilterHint
|
|
39
|
+
queries:
|
|
40
|
+
- id: spatial-check
|
|
41
|
+
cql2: "s_intersects(ensure_spatial(candidate), ensure_spatial(aoi))"
|
|
42
|
+
message: "candidate must intersect aoi"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 3. Validate with sample values
|
|
46
|
+
|
|
47
|
+
Run:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
assertions-mate workflow.cwl --inputs inputs-valid.yaml
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Ready-to-run example in this repository
|
|
54
|
+
|
|
55
|
+
- `examples/multi-hint-validation/workflow.cwl`
|
|
56
|
+
- `examples/multi-hint-validation/inputs-valid.yaml`
|
|
57
|
+
- `examples/multi-hint-validation/inputs-invalid.yaml`
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# How-to: Create Reusable Rego Snippets
|
|
2
|
+
|
|
3
|
+
Keep common checks reusable by copying a shared module block between workflows.
|
|
4
|
+
|
|
5
|
+
## 1. Define the inputs
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
inputs:
|
|
9
|
+
start-date:
|
|
10
|
+
type: string
|
|
11
|
+
end-date:
|
|
12
|
+
type: string
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 2. Add reusable Rego helper
|
|
16
|
+
|
|
17
|
+
```rego
|
|
18
|
+
package workflow
|
|
19
|
+
|
|
20
|
+
is_rfc3339_utc(s) {
|
|
21
|
+
regex.match("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$", s)
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Then reuse in multiple deny rules.
|
|
26
|
+
|
|
27
|
+
## 3. Add hint using the helper
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
hints:
|
|
31
|
+
- class: eoap:RegoPolicyHint
|
|
32
|
+
module: |
|
|
33
|
+
package workflow
|
|
34
|
+
|
|
35
|
+
is_rfc3339_utc(s) {
|
|
36
|
+
regex.match("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$", s)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
deny[msg] {
|
|
40
|
+
s := input["start-date"]
|
|
41
|
+
not is_rfc3339_utc(s)
|
|
42
|
+
msg := "start-date format is invalid"
|
|
43
|
+
}
|
|
44
|
+
queries:
|
|
45
|
+
- data.workflow.deny[_]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Ready-to-run example in this repository
|
|
49
|
+
|
|
50
|
+
- `examples/reusable-rego-snippets/workflow.cwl`
|
|
51
|
+
- `examples/reusable-rego-snippets/inputs-valid.yaml`
|
|
52
|
+
- `examples/reusable-rego-snippets/inputs-invalid.yaml`
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# How-to: Test Hints With pytest
|
|
2
|
+
|
|
3
|
+
Use direct validator classes in unit tests for quick feedback.
|
|
4
|
+
|
|
5
|
+
## 1. Create a validator test
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from assertions_mate import Cql2Query
|
|
9
|
+
from assertions_mate.cql2_validator import Cql2Validator
|
|
10
|
+
|
|
11
|
+
def test_rule_fails_when_count_not_positive():
|
|
12
|
+
validator = Cql2Validator(
|
|
13
|
+
queries=[Cql2Query(id="q", cql2="count > 0", message="count must be positive")]
|
|
14
|
+
)
|
|
15
|
+
result = validator.validate_inputs({"count": 0})
|
|
16
|
+
assert result is not None
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 2. Run the test
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
hatch run test:test-q examples/pytest-validation/test_validators_example.py
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Ready-to-run example in this repository
|
|
26
|
+
|
|
27
|
+
- `examples/pytest-validation/test_validators_example.py`
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# How-to: Troubleshoot CWL Loader Errors
|
|
2
|
+
|
|
3
|
+
When validation fails before hints execute, the CWL document may be rejected by `cwl_utils`.
|
|
4
|
+
|
|
5
|
+
## Common symptom
|
|
6
|
+
|
|
7
|
+
- `schema_salad.exceptions.ValidationException`
|
|
8
|
+
- messages around invalid `requirements` field shape
|
|
9
|
+
|
|
10
|
+
## Checklist
|
|
11
|
+
|
|
12
|
+
1. Start with a minimal single-workflow document (`class: Workflow`, `cwlVersion: v1.2`).
|
|
13
|
+
2. Add one input at a time and re-run.
|
|
14
|
+
3. If failures appear after adding `requirements`, temporarily remove that section to isolate parser compatibility.
|
|
15
|
+
4. Keep examples runnable first; reintroduce advanced schema refs after parser behavior is confirmed.
|
|
16
|
+
|
|
17
|
+
## Tip
|
|
18
|
+
|
|
19
|
+
Different environments can parse the same CWL differently depending on exact `cwl_utils` and schema-salad versions.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# How-to: Troubleshoot Rego "Invalid literal" Errors
|
|
2
|
+
|
|
3
|
+
If you see errors around `deny contains ... if { ... }`, your runtime is parsing classic Rego syntax.
|
|
4
|
+
|
|
5
|
+
## Symptoms
|
|
6
|
+
|
|
7
|
+
- `Invalid literal`
|
|
8
|
+
- `wellformed_error`
|
|
9
|
+
- validator setup fails for `RegoPolicyHint`
|
|
10
|
+
|
|
11
|
+
## Fix
|
|
12
|
+
|
|
13
|
+
Use classic syntax:
|
|
14
|
+
|
|
15
|
+
```rego
|
|
16
|
+
deny[msg] {
|
|
17
|
+
input["x"] == null
|
|
18
|
+
msg := "x is required"
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
instead of:
|
|
23
|
+
|
|
24
|
+
```rego
|
|
25
|
+
deny contains "x is required" if {
|
|
26
|
+
input["x"] == null
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Verify
|
|
31
|
+
|
|
32
|
+
Run your workflow and ensure `Setting up validator for RegoPolicyHint...` completes without parser errors.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# How-to: Use Packed CWL vs Single Workflow CWL
|
|
2
|
+
|
|
3
|
+
## Single workflow
|
|
4
|
+
|
|
5
|
+
Best for local examples and fast validation loops.
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
cwlVersion: v1.2
|
|
9
|
+
class: Workflow
|
|
10
|
+
id: my-workflow
|
|
11
|
+
...
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Packed workflow (`$graph`)
|
|
15
|
+
|
|
16
|
+
Useful when distributing multiple process definitions in one file.
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
cwlVersion: v1.2
|
|
20
|
+
$graph:
|
|
21
|
+
- class: Workflow
|
|
22
|
+
id: my-workflow
|
|
23
|
+
...
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Recommendation
|
|
27
|
+
|
|
28
|
+
Start with single-workflow CWL for validator docs/examples, then move to packed CWL once parser compatibility is confirmed in your target runtime.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# How-to: Validate Array Cardinality (JSON Schema)
|
|
2
|
+
|
|
3
|
+
Require `items` array length between 1 and 3.
|
|
4
|
+
|
|
5
|
+
## 1. Define the input
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
inputs:
|
|
9
|
+
items:
|
|
10
|
+
type: string[]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 2. Add JSON Schema hint
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
hints:
|
|
17
|
+
- class: eoap:JSONSchemaHint
|
|
18
|
+
json_schema:
|
|
19
|
+
type: object
|
|
20
|
+
required: [items]
|
|
21
|
+
properties:
|
|
22
|
+
items:
|
|
23
|
+
type: array
|
|
24
|
+
minItems: 1
|
|
25
|
+
maxItems: 3
|
|
26
|
+
items:
|
|
27
|
+
type: string
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 3. Validate with sample values
|
|
31
|
+
|
|
32
|
+
Valid:
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
items: ["a", "b"]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Run:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
assertions-mate workflow.cwl --inputs inputs-valid.yaml
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Ready-to-run example in this repository
|
|
45
|
+
|
|
46
|
+
- `examples/array-cardinality-validation/workflow.cwl`
|
|
47
|
+
- `examples/array-cardinality-validation/inputs-valid.yaml`
|
|
48
|
+
- `examples/array-cardinality-validation/inputs-invalid.yaml`
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# How-to: Validate BBOX Overlap (CQL2)
|
|
2
|
+
|
|
3
|
+
## 1. Define the inputs
|
|
4
|
+
|
|
5
|
+
```yaml
|
|
6
|
+
inputs:
|
|
7
|
+
bbox_1:
|
|
8
|
+
type: string
|
|
9
|
+
bbox_2:
|
|
10
|
+
type: string
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 2. Add CQL2 check
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
hints:
|
|
17
|
+
- class: eoap:Cql2FilterHint
|
|
18
|
+
custom_functions: |
|
|
19
|
+
from shapely import geometry
|
|
20
|
+
from typing import Any, List, Mapping, Union
|
|
21
|
+
|
|
22
|
+
def ensure_bbox(input: Union[Mapping[str, Any], List[float], str]):
|
|
23
|
+
value = []
|
|
24
|
+
|
|
25
|
+
if isinstance(input, dict):
|
|
26
|
+
value = input["bbox"]
|
|
27
|
+
if not value:
|
|
28
|
+
raise ValueError(f"Input {input} doesn't have a 'bbox' property")
|
|
29
|
+
elif isinstance(input, str):
|
|
30
|
+
value = [float(x) for x in str(input).split(",")]
|
|
31
|
+
else:
|
|
32
|
+
value = input
|
|
33
|
+
|
|
34
|
+
return geometry.box(*value)
|
|
35
|
+
queries:
|
|
36
|
+
- id: bbox-overlap
|
|
37
|
+
cql2: "s_intersects(ensure_bbox(bbox_1), ensure_bbox(bbox_2))"
|
|
38
|
+
message: "bbox_1 must overlap bbox_2"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## 3. Validate with sample values
|
|
42
|
+
|
|
43
|
+
Run:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
assertions-mate workflow.cwl --inputs inputs-valid.yaml
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Ready-to-run example in this repository
|
|
50
|
+
|
|
51
|
+
- `examples/bbox-overlap-validation/workflow.cwl`
|
|
52
|
+
- `examples/bbox-overlap-validation/inputs-valid.yaml`
|
|
53
|
+
- `examples/bbox-overlap-validation/inputs-invalid.yaml`
|