mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
fix(verifier): tolerate out-of-range override indices
A single stale index from V8 aborted the entire override map, so any valid entries alongside it were dropped and verification ran on stale extractor values. V8 and goja register from the same bundle so a mismatch is unusual but recoverable. Skip out-of-range entries instead of erroring, and return the skipped count so the runner logs the mismatch without losing valid overrides.
This commit is contained in:
1 parent
3b204b75dc
commit
d77f89aeb1
3 files changed
+39
-17
No files matched your search
@@ -138,8 +138,13 @@ func Run(ctx context.Context, options Options) (Summary, error) {
|
||||
}); err != nil {
|
||||
return summary, fmt.Errorf("step %d push: %w", stepIndex, err)
|
||||
}
|
||||
if err := options.Verifier.OverrideExtractorValues(v8Overrides); err != nil {
|
||||
logger.Warn("v8 override apply failed", "step", stepIndex, "err", err)
|
||||
skipped, overrideErr := options.Verifier.OverrideExtractorValues(v8Overrides)
|
||||
if overrideErr != nil {
|
||||
logger.Warn("v8 override apply failed", "step", stepIndex, "err", overrideErr)
|
||||
}
|
||||
if skipped > 0 {
|
||||
logger.Warn("v8 override skipped out-of-range entries",
|
||||
"step", stepIndex, "skipped", skipped, "have", len(v8Overrides))
|
||||
}
|
||||
|
||||
screen := ""
|
||||
|
||||
@@ -540,7 +540,7 @@ func TestOverrideExtractorValues_PreservesPrevious(t *testing.T) {
|
||||
if err := verifier.PushSnapshot(SnapshotInput{Snapshots: Snapshots{"ledger.balance": json.RawMessage(`100`)}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := verifier.OverrideExtractorValues(map[int]json.RawMessage{1: json.RawMessage(`777`)}); err != nil {
|
||||
if _, err := verifier.OverrideExtractorValues(map[int]json.RawMessage{1: json.RawMessage(`777`)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
balance := verifier.runtime.GlobalObject().Get("balance").ToObject(verifier.runtime)
|
||||
@@ -564,10 +564,10 @@ func TestOverrideExtractorValues_NilIsNoop(t *testing.T) {
|
||||
if err := verifier.PushSnapshot(SnapshotInput{Snapshots: Snapshots{"ledger.balance": json.RawMessage(`42`)}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := verifier.OverrideExtractorValues(nil); err != nil {
|
||||
if _, err := verifier.OverrideExtractorValues(nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := verifier.OverrideExtractorValues(map[int]json.RawMessage{}); err != nil {
|
||||
if _, err := verifier.OverrideExtractorValues(map[int]json.RawMessage{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
balance := verifier.runtime.GlobalObject().Get("balance").ToObject(verifier.runtime)
|
||||
@@ -576,14 +576,24 @@ func TestOverrideExtractorValues_NilIsNoop(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverrideExtractorValues_UnknownIndexErrors(t *testing.T) {
|
||||
func TestOverrideExtractorValues_UnknownIndexSkipped(t *testing.T) {
|
||||
verifier := newVerifier(t)
|
||||
mustLoad(t, verifier, helloSpec)
|
||||
if err := verifier.PushSnapshot(SnapshotInput{}); err != nil {
|
||||
if err := verifier.PushSnapshot(SnapshotInput{Snapshots: Snapshots{"ledger.balance": json.RawMessage(`42`)}}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := verifier.OverrideExtractorValues(map[int]json.RawMessage{99: json.RawMessage(`1`)})
|
||||
if err == nil || !strings.Contains(err.Error(), "out of range") {
|
||||
t.Errorf("expected out-of-range error, got %v", err)
|
||||
skipped, err := verifier.OverrideExtractorValues(map[int]json.RawMessage{
|
||||
1: json.RawMessage(`777`),
|
||||
99: json.RawMessage(`1`),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if skipped != 1 {
|
||||
t.Errorf("expected 1 skipped entry, got %d", skipped)
|
||||
}
|
||||
balance := verifier.runtime.GlobalObject().Get("balance").ToObject(verifier.runtime)
|
||||
if balance.Get("current").ToInteger() != 777 {
|
||||
t.Errorf("valid override should still apply alongside skipped one, got current=%v", balance.Get("current"))
|
||||
}
|
||||
}
|
||||
@@ -246,21 +246,28 @@ func (v *Verifier) PushSnapshot(input SnapshotInput) error {
|
||||
// state.ax shim. Passing a nil/empty map is a no-op so the mobile path can
|
||||
// call this unconditionally. The override must run *after* PushSnapshot
|
||||
// (which advanced `previous`) and *before* EvaluateProperties.
|
||||
func (v *Verifier) OverrideExtractorValues(overrides map[int]json.RawMessage) error {
|
||||
//
|
||||
// Out-of-range indices are tolerated (skipped) rather than fatal: V8 and goja
|
||||
// register extractors from the same spec bundle so counts should always
|
||||
// match, but a stale or partial override map should not block valid overrides
|
||||
// from applying. The number of skipped entries is reported so the caller can
|
||||
// surface a mismatch.
|
||||
func (v *Verifier) OverrideExtractorValues(overrides map[int]json.RawMessage) (skipped int, err error) {
|
||||
if len(overrides) == 0 {
|
||||
return nil
|
||||
return 0, nil
|
||||
}
|
||||
for index, raw := range overrides {
|
||||
if index < 0 || index >= len(v.extractors) {
|
||||
return fmt.Errorf("extractor override index %d out of range (have %d)", index, len(v.extractors))
|
||||
skipped++
|
||||
continue
|
||||
}
|
||||
value, err := jsonToJSValue(v.runtime, raw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("extractor override %d: %w", index, err)
|
||||
value, conversionErr := jsonToJSValue(v.runtime, raw)
|
||||
if conversionErr != nil {
|
||||
return skipped, fmt.Errorf("extractor override %d: %w", index, conversionErr)
|
||||
}
|
||||
_ = v.extractors[index].handle.Set("current", value)
|
||||
}
|
||||
return nil
|
||||
return skipped, nil
|
||||
}
|
||||
|
||||
// SnapshotInput bundles everything a step feeds into the verifier. Fields
|
||||
|
||||
Reference in new issue
Block a user