Skip to content

Commit

Permalink
Add support for overriding validation severity
Browse files Browse the repository at this point in the history
severityOverride cannot set an event to SUPPRESSED. Use suppressions
for that. It cannot lower the severity of an event, only elevate. This
prevents a backdoor for disabling built-in validation or ignoring
ERROR events.

Closes #856
  • Loading branch information
mtdowling committed Jul 28, 2023
1 parent 8db9d56 commit 98bdf6f
Show file tree
Hide file tree
Showing 28 changed files with 717 additions and 297 deletions.
53 changes: 52 additions & 1 deletion docs/source-2.0/spec/model-validation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ following properties:
- Description
* - id
- ``string``
- **Required**. The validation event ID to suppress.
- **Required**. The hierarchical validation event ID to suppress.
* - namespace
- ``string``
- **Required**. The validation event is only suppressed if it matches the
Expand Down Expand Up @@ -315,6 +315,57 @@ specific. Further, a suppression ID of "ABC" does not match an event ID of
- No


------------------
Severity overrides
------------------

The ``severityOverrides`` metadata property is used to elevate the severity
of validation events. This property contains an array of severity override
objects that support the following properties:

.. list-table::
:header-rows: 1
:widths: 20 20 60

* - Property
- Type
- Description
* - id
- ``string``
- **Required**. The hierarchical validation event ID to elevate.
* - namespace
- ``string``
- **Required**. The validation event is only elevated if it matches the
supplied namespace. A value of ``*`` can be provided to match any namespace.
* - severity
- ``string``
- Defines the :ref:`severity <severity-definition>` to elevate matching
events to. This value can only be set to ``WARNING`` or ``DANGER``.

The following example elevates the events of ``SomeValidator`` to ``DANGER``
in any namespace, and ``OtherValidator`` is elevated to ``WARNING`` but only
for events emitted for shapes in the ``smithy.example`` namespace:

.. code-block:: smithy
$version: "2"
metadata severityOverrides = [
{
namespace: "*"
id: "SomeValidator"
severity: "DANGER"
}
{
namespace: "smithy.example"
id: "OtherValidator"
severity: "WARNING"
}
]
namespace smithy.example
-------------------
Built-in validators
-------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -580,15 +580,18 @@ public ValidatedResult<Model> assemble() {
}

if (disableValidation) {
List<ValidationEventDecorator> decorators = validatorFactory.loadDecorators();
return new ValidatedResult<>(transformed, ModelValidator.decorateEvents(decorators, events));
}

try {
return validate(transformed, events);
} catch (SourceException e) {
events.add(ValidationEvent.fromSourceException(e));
ValidationEventDecorator decorator = ValidationEventDecorator.compose(validatorFactory.loadDecorators());
for (int idx = 0; idx < events.size(); idx++) {
events.set(idx, decorator.decorate(events.get(idx)));
}
return new ValidatedResult<>(transformed, events);
} else {
try {
return validate(transformed, events);
} catch (SourceException e) {
events.add(ValidationEvent.fromSourceException(e));
return new ValidatedResult<>(transformed, events);
}
}
}

Expand All @@ -599,22 +602,22 @@ private void addMetadataToProcessor(Map<String, Node> metadataMap, LoadOperation
}

private ValidatedResult<Model> returnOnlyErrors(Model model, List<ValidationEvent> events) {
List<ValidationEventDecorator> decorators = validatorFactory.loadDecorators();
ValidationEventDecorator decorator = ValidationEventDecorator.compose(validatorFactory.loadDecorators());
return new ValidatedResult<>(model, events.stream()
.filter(event -> event.getSeverity() == Severity.ERROR)
.map(event -> ModelValidator.decorateEvent(decorators, event))
.map(decorator::decorate)
.collect(Collectors.toList()));
}

private ValidatedResult<Model> validate(Model model, List<ValidationEvent> events) {
// Validate the model based on the explicit validators and model metadata.
// Note the ModelValidator handles emitting events to the validationEventListener.
List<ValidationEvent> mergedEvents = new ModelValidator()
List<ValidationEvent> mergedEvents = ModelValidator.builder()
.validators(validators)
.validatorFactory(validatorFactory)
.eventListener(validationEventListener)
.includeEvents(events)
.createValidator()
.build()
.validate(model);

return new ValidatedResult<>(model, mergedEvents);
Expand Down
Loading

0 comments on commit 98bdf6f

Please sign in to comment.