From dcbd2eded121bd84e714abd4998d50626a6a5140 Mon Sep 17 00:00:00 2001 From: timothyF95 Date: Mon, 15 Jun 2026 15:27:48 +0100 Subject: [PATCH] Simplify --- internal/settings/multisig_validation.go | 29 +++++++ internal/settings/multisig_validation_test.go | 84 +++++++++++++++++++ internal/settings/workflow_settings.go | 7 ++ 3 files changed, 120 insertions(+) create mode 100644 internal/settings/multisig_validation.go create mode 100644 internal/settings/multisig_validation_test.go diff --git a/internal/settings/multisig_validation.go b/internal/settings/multisig_validation.go new file mode 100644 index 00000000..cb700609 --- /dev/null +++ b/internal/settings/multisig_validation.go @@ -0,0 +1,29 @@ +package settings + +import ( + "fmt" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// IsMultisigMode reports whether multisig transaction mode is active via --unsigned or --changeset. +func IsMultisigMode(v *viper.Viper) bool { + return v.GetBool(Flags.RawTxFlag.Name) || + v.GetBool(Flags.Changeset.Name) +} + +// ValidateMultisigCompatibility rejects incompatible multisig, private registry, and browser secrets auth combinations. +// resolvedRegistry may be nil during initial settings load; the private-registry check is skipped until resolved. +func ValidateMultisigCompatibility(v *viper.Viper, cmd *cobra.Command, resolvedRegistry ResolvedRegistry) error { + if !IsMultisigMode(v) { + return nil + } + if f := cmd.Flags().Lookup("secrets-auth"); f != nil && f.Value.String() == "browser" { + return fmt.Errorf("browser secrets auth cannot be combined with multisig secrets operations; remove --unsigned/--changeset or use --secrets-auth=onchain") + } + if resolvedRegistry != nil && resolvedRegistry.Type() == RegistryTypeOffChain { + return fmt.Errorf("multisig operations (--unsigned or --changeset) are not supported with private registry; remove the flag or use an on-chain deployment-registry") + } + return nil +} diff --git a/internal/settings/multisig_validation_test.go b/internal/settings/multisig_validation_test.go new file mode 100644 index 00000000..dfcbcf9d --- /dev/null +++ b/internal/settings/multisig_validation_test.go @@ -0,0 +1,84 @@ +package settings + +import ( + "testing" + + "github.com/spf13/cobra" + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIsMultisigMode(t *testing.T) { + t.Run("unsigned", func(t *testing.T) { + v := viper.New() + v.Set(Flags.RawTxFlag.Name, true) + assert.True(t, IsMultisigMode(v)) + }) + + t.Run("changeset", func(t *testing.T) { + v := viper.New() + v.Set(Flags.Changeset.Name, true) + assert.True(t, IsMultisigMode(v)) + }) + + t.Run("neither flag", func(t *testing.T) { + v := viper.New() + assert.False(t, IsMultisigMode(v)) + }) +} + +func secretsCmd(secretsAuth string) *cobra.Command { + cmd := &cobra.Command{Use: "create"} + cmd.Flags().String("secrets-auth", secretsAuth, "auth mode") + return cmd +} + +func workflowCmd() *cobra.Command { + return &cobra.Command{Use: "deploy"} +} + +func TestValidateMultisigCompatibility(t *testing.T) { + offChain := NewOffChainRegistry("42", "test-don") + onChain := NewOnChainRegistry("mainnet", "0xabc", "ethereum-mainnet", "test-don", "") + + tests := []struct { + name string + unsigned bool + changeset bool + cmd *cobra.Command + resolvedRegistry ResolvedRegistry + wantErr bool + errMsg string + }{ + {"not multisig secrets onchain off-chain", false, false, secretsCmd("onchain"), offChain, false, ""}, + {"not multisig secrets browser off-chain", false, false, secretsCmd("browser"), offChain, false, ""}, + {"unsigned secrets onchain on-chain", true, false, secretsCmd("onchain"), onChain, false, ""}, + {"unsigned secrets onchain nil registry", true, false, secretsCmd("onchain"), nil, false, ""}, + {"changeset secrets browser off-chain", false, true, secretsCmd("browser"), offChain, true, "browser secrets auth cannot be combined with multisig"}, + {"unsigned secrets browser on-chain", true, false, secretsCmd("browser"), onChain, true, "browser secrets auth cannot be combined with multisig"}, + {"unsigned secrets onchain off-chain", true, false, secretsCmd("onchain"), offChain, true, "not supported with private registry"}, + {"changeset workflow off-chain", false, true, workflowCmd(), offChain, true, "not supported with private registry"}, + {"unsigned workflow on-chain", true, false, workflowCmd(), onChain, false, ""}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + v := viper.New() + if tt.unsigned { + v.Set(Flags.RawTxFlag.Name, true) + } + if tt.changeset { + v.Set(Flags.Changeset.Name, true) + } + + err := ValidateMultisigCompatibility(v, tt.cmd, tt.resolvedRegistry) + if tt.wantErr { + require.Error(t, err) + require.Contains(t, err.Error(), tt.errMsg) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/internal/settings/workflow_settings.go b/internal/settings/workflow_settings.go index 17aba9c4..271c851c 100644 --- a/internal/settings/workflow_settings.go +++ b/internal/settings/workflow_settings.go @@ -167,6 +167,10 @@ func loadWorkflowSettings(logger *zerolog.Logger, v *viper.Viper, cmd *cobra.Com return WorkflowSettings{}, errors.Wrap(err, "for target "+target) } + if err := ValidateMultisigCompatibility(v, cmd, nil); err != nil { + return WorkflowSettings{}, err + } + // This is required because some commands still read values directly out of viper // TODO: Remove this function once all access to settings no longer uses viper // DEVSVCS-1561 @@ -187,6 +191,9 @@ func FinalizeWorkflowOwner( resolved ResolvedRegistry, derivedWorkflowOwner string, ) error { + if err := ValidateMultisigCompatibility(v, cmd, resolved); err != nil { + return err + } if ShouldSkipGetOwner(cmd) { return nil }