@@ -350,6 +350,40 @@ func (c importingContractCapability) CapabilityContracts() map[string]Capability
350350 }
351351}
352352
353+ type argMutationContractCapability struct {
354+ invokeCount * int
355+ }
356+
357+ func (c argMutationContractCapability ) Bind (binding CapabilityBinding ) (map [string ]Value , error ) {
358+ return map [string ]Value {
359+ "cap" : NewObject (map [string ]Value {
360+ "install" : NewBuiltin ("cap.install" , func (exec * Execution , receiver Value , args []Value , kwargs map [string ]Value , block Value ) (Value , error ) {
361+ if len (args ) != 1 || (args [0 ].Kind () != KindHash && args [0 ].Kind () != KindObject ) {
362+ return NewNil (), fmt .Errorf ("cap.install expects target hash" )
363+ }
364+ args [0 ].Hash ()["call" ] = NewBuiltin ("cap.call" , func (exec * Execution , receiver Value , args []Value , kwargs map [string ]Value , block Value ) (Value , error ) {
365+ * c .invokeCount = * c .invokeCount + 1
366+ return NewString ("ok" ), nil
367+ })
368+ return NewString ("installed" ), nil
369+ }),
370+ }),
371+ }, nil
372+ }
373+
374+ func (c argMutationContractCapability ) CapabilityContracts () map [string ]CapabilityMethodContract {
375+ return map [string ]CapabilityMethodContract {
376+ "cap.call" : {
377+ ValidateArgs : func (args []Value , kwargs map [string ]Value , block Value ) error {
378+ if len (args ) != 1 || args [0 ].Kind () != KindInt {
379+ return fmt .Errorf ("cap.call expects int" )
380+ }
381+ return nil
382+ },
383+ },
384+ }
385+ }
386+
353387func TestCapabilityContractRejectsInvalidArguments (t * testing.T ) {
354388 engine := MustNewEngine (Config {})
355389 script , err := engine .Compile (`def run()
@@ -641,3 +675,31 @@ end`)
641675 t .Fatalf ("unexpected result: %#v" , result )
642676 }
643677}
678+
679+ func TestCapabilityContractsBindAfterArgumentMutation (t * testing.T ) {
680+ engine := MustNewEngine (Config {})
681+ script , err := engine .Compile (`def run()
682+ target = {}
683+ cap.install(target)
684+ target.call("bad")
685+ end` )
686+ if err != nil {
687+ t .Fatalf ("compile failed: %v" , err )
688+ }
689+
690+ invocations := 0
691+ _ , err = script .Call (context .Background (), "run" , nil , CallOptions {
692+ Capabilities : []CapabilityAdapter {
693+ argMutationContractCapability {invokeCount : & invocations },
694+ },
695+ })
696+ if err == nil {
697+ t .Fatalf ("expected argument-mutation contract validation error" )
698+ }
699+ if got := err .Error (); ! strings .Contains (got , "cap.call expects int" ) {
700+ t .Fatalf ("unexpected error: %s" , got )
701+ }
702+ if invocations != 0 {
703+ t .Fatalf ("argument mutation capability should not execute when contract fails" )
704+ }
705+ }
0 commit comments