feat(verifier): refuse a bundle built against a different action encoding

ActionWireContract names the encoding wireAction decodes and must equal the one
the bundled runtime entry declares. An absent declaration is a mismatch, not a
default: it is the package that shipped the zero-distance scroll. A bundle that
installs no picker generates no actions and is exempt.
This commit is contained in:
pj committed 2026-08-22 21:04:23 +05:30
1 parent 912ad71804
commit 81713fa183
3 files changed
+192

No files matched your search

+28
View File
@@ -150,6 +150,10 @@ func (v *Verifier) Load(source string) error {
return fmt.Errorf("run spec: %w", err)
}
if err := v.checkActionEncoding(); err != nil {
return err
}
propertiesValue := v.runtime.GlobalObject().Get("properties")
if propertiesValue != nil && !goja.IsUndefined(propertiesValue) && !goja.IsNull(propertiesValue) {
propertiesObject := propertiesValue.ToObject(v.runtime)
@@ -210,6 +214,30 @@ func (v *Verifier) Load(source string) error {
return nil
}
// checkActionEncoding fails the load when the bundle's action encoding is not
// the one this binary decodes. A bundle that installs the picker and declares
// nothing is an @sanderling/spec older than the declaration, which is the
// pairing that has to be caught: an absent declaration is a mismatch, never a
// default. A bundle with no picker (a raw-JS fixture, the bundle-check tool)
// generates no actions at all, so it has no encoding to disagree about.
//
// chrome.Driver.InstallBundle applies this same rule to the web host.
func (v *Verifier) checkActionEncoding() error {
picker := v.runtime.GlobalObject().Get("__sanderlingNextAction__")
if picker == nil || goja.IsUndefined(picker) || goja.IsNull(picker) {
return nil
}
declared := ""
if value := v.runtime.GlobalObject().Get(actionEncodingGlobal); value != nil &&
!goja.IsUndefined(value) && !goja.IsNull(value) {
declared = value.String()
}
if declared == ActionWireContract {
return nil
}
return ActionEncodingError(declared)
}
// buildFormula walks the formula-spec registry and produces a Go ltl.Formula
// tree rooted at the given spec index.
//