diff --git a/pkg/signatory/signatory.go b/pkg/signatory/signatory.go index fd2df89a..6ace9de5 100644 --- a/pkg/signatory/signatory.go +++ b/pkg/signatory/signatory.go @@ -713,6 +713,30 @@ func checkRequestKind(allowedKinds []string) error { func checkOperationKind(allowedKinds []string) error { avilKinds := append(proto.ListGenericOperations(), proto.ListPseudoOperations()...) for _, kind := range allowedKinds { + // Handle ballot sub-kinds (ballot:yay, ballot:nay, ballot:pass) + if strings.Contains(kind, ":") { + parts := strings.SplitN(kind, ":", 2) + base := parts[0] + subKind := parts[1] + + // Only ballot operations support sub-kind syntax + if base != "ballot" { + return fmt.Errorf("invalid operation kind `%s` in `allow.generic` list", kind) + } + + // Validate the ballot sub-kind + validBallotKinds := []string{"yay", "nay", "pass"} + if !slices.Contains(validBallotKinds, subKind) { + return fmt.Errorf("invalid operation kind `%s` in `allow.generic` list", kind) + } + + // Ensure base "ballot" is in the valid operations list + if !slices.Contains(avilKinds, base) { + return fmt.Errorf("invalid operation kind `%s` in `allow.generic` list", kind) + } + continue + } + if !slices.Contains(avilKinds, kind) { return fmt.Errorf("invalid operation kind `%s` in `allow.generic` list", kind) } diff --git a/pkg/signatory/signatory_test.go b/pkg/signatory/signatory_test.go index 1b78f000..0e056e93 100644 --- a/pkg/signatory/signatory_test.go +++ b/pkg/signatory/signatory_test.go @@ -817,6 +817,28 @@ func TestOperationKindCheck(t *testing.T) { "ballot", }, }, + { + name: "ballot:yay accepted", + ops: []string{"ballot:yay"}, + }, + { + name: "ballot:nay accepted", + ops: []string{"ballot:nay"}, + }, + { + name: "ballot:pass accepted", + ops: []string{"ballot:pass"}, + }, + { + name: "ballot:invalid rejected", + ops: []string{"ballot:invalid"}, + wantErr: "invalid operation kind `ballot:invalid` in `allow.generic` list", + }, + { + name: "transaction:foo rejected", + ops: []string{"transaction:foo"}, + wantErr: "invalid operation kind `transaction:foo` in `allow.generic` list", + }, } invalidOps := []string{"attestation", "attestation_with_dal", "preattestation"}