mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07:10 +00:00
fix(verifier): don't crash on throwing JS predicates (#21)
* fix(verifier): don't crash on throwing JS predicates formulaThunk used to panic whenever goja returned an error from a predicate callable, and nothing on the LTL -> runner path recovered, so a malformed spec (e.g. a property whose body throws or touches an undefined field) would kill the verifier process. Latch the first error on formulaState, return false so LTL marks the property violated, and expose PredicateError(name) that walks the property's formula-spec tree and surfaces the latched cause. * fix(runner): log predicate errors alongside violations For each violated property, surface the verifier's latched predicate error via logger.Warn so operators can distinguish a genuine false verdict from a malformed spec. Add a runner-level test asserting that a throwing predicate no longer crashes the run and that the error message appears in the log.
This commit is contained in:
5 files changed
+113
-2
No files matched your search
@@ -302,12 +302,46 @@ func (v *Verifier) formulaThunk(index int) func() bool {
|
||||
formula := v.formulas[index]
|
||||
result, err := formula.predicate(goja.Undefined())
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("predicate panic: %w", err))
|
||||
if formula.err == nil {
|
||||
formula.err = err
|
||||
}
|
||||
return false
|
||||
}
|
||||
return result.ToBoolean()
|
||||
}
|
||||
}
|
||||
|
||||
// PredicateError returns the first goja error raised by any thunk in the
|
||||
// named property's formula tree, or nil if none fired. Callers typically
|
||||
// consult this after EvaluateProperties reports a violation to distinguish
|
||||
// a genuine predicate-false verdict from a malformed spec.
|
||||
func (v *Verifier) PredicateError(name string) error {
|
||||
rootIndex, ok := v.properties[name]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return v.firstThunkError(rootIndex)
|
||||
}
|
||||
|
||||
func (v *Verifier) firstThunkError(index int) error {
|
||||
if index < 0 || index >= len(v.formulaSpecs) {
|
||||
return nil
|
||||
}
|
||||
spec := v.formulaSpecs[index]
|
||||
switch spec.kind {
|
||||
case specKindThunk:
|
||||
return v.formulas[spec.predicateIndex].err
|
||||
case specKindImplies, specKindOr, specKindAnd:
|
||||
if err := v.firstThunkError(spec.childA); err != nil {
|
||||
return err
|
||||
}
|
||||
return v.firstThunkError(spec.childB)
|
||||
case specKindNow, specKindNext, specKindEventually, specKindNot, specKindAlways:
|
||||
return v.firstThunkError(spec.childA)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *Verifier) resolveGenerator(generator goja.Value) (Action, error) {
|
||||
object := generator.ToObject(v.runtime)
|
||||
if object == nil {
|
||||
|
||||
Reference in new issue
Block a user