//go:build integration && legacy // +build integration,legacy package integration_test import ( "context" "crypto/tls" "math/big" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" "github.com/fraktal/mev-beta/internal/logger" "github.com/fraktal/mev-beta/pkg/security" ) const ( testEncryptionKey = "integrationlegacyencryptionkey0123456789" ) func newSecurityManagerForTest(t *testing.T) (*security.SecurityManager, func()) { t.Helper() // Create local RPC stub that always succeeds rpcServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") _, _ = w.Write([]byte(`{"jsonrpc":"2.0","id":"sm-1","result":"0x1"}`)) })) // Use repo-local temp directory to satisfy production validation rules keyDir, err := os.MkdirTemp(".", "sec-harness-") require.NoError(t, err) t.Cleanup(func() { _ = os.RemoveAll(keyDir) }) // Ensure logs directory exists to avoid cluttering stdout in parallel runs require.NoError(t, os.MkdirAll("logs", 0o755)) t.Setenv("MEV_BOT_ENCRYPTION_KEY", testEncryptionKey) cfg := &security.SecurityConfig{ KeyStoreDir: keyDir, EncryptionEnabled: true, TransactionRPS: 25, RPCRPS: 25, MaxBurstSize: 5, FailureThreshold: 3, RecoveryTimeout: 2 * time.Second, TLSMinVersion: tls.VersionTLS12, TLSCipherSuites: []uint16{ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, }, EmergencyStopFile: filepath.Join(keyDir, "emergency.stop"), MaxGasPrice: "50000000000", // 50 gwei LogLevel: "error", RPCURL: rpcServer.URL, } manager, err := security.NewSecurityManager(cfg) require.NoError(t, err) cleanup := func() { rpcServer.Close() // Trigger emergency stop to halt background activity gracefully _ = manager.TriggerEmergencyStop("test cleanup") } return manager, cleanup } func TestLegacySecurityManagerEndToEnd(t *testing.T) { manager, cleanup := newSecurityManagerForTest(t) defer cleanup() recipient := common.HexToAddress("0x8a753747A1Fa494EC906cE90E9f37563A8AF630e") params := &security.TransactionParams{ To: &recipient, Value: big.NewInt(1_000_000_000_000_000), // 0.001 ETH Gas: 21000, GasPrice: big.NewInt(1_000_000_000), // 1 gwei Nonce: 0, } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() // Validate transaction under normal operation require.NoError(t, manager.ValidateTransaction(ctx, params)) // Perform secure RPC call against stub server result, err := manager.SecureRPCCall(ctx, "eth_chainId", []interface{}{}) require.NoError(t, err) require.Equal(t, "0x1", result) // Trigger emergency stop and confirm transactions are blocked require.NoError(t, manager.TriggerEmergencyStop("integration harness assertion")) err = manager.ValidateTransaction(ctx, params) require.Error(t, err) require.Contains(t, err.Error(), "emergency mode") } func TestLegacyChainIDValidatorIntegration(t *testing.T) { t.Setenv("MEV_BOT_ENCRYPTION_KEY", testEncryptionKey) keystoreDir, err := os.MkdirTemp(".", "km-harness-") require.NoError(t, err) defer os.RemoveAll(keystoreDir) logger := logger.New("error", "text", "") cfg := &security.KeyManagerConfig{ KeyDir: keystoreDir, KeystorePath: keystoreDir, EncryptionKey: testEncryptionKey, BackupEnabled: false, MaxFailedAttempts: 5, LockoutDuration: time.Minute, MaxSigningRate: 20, SessionTimeout: time.Minute, EnableRateLimiting: false, } chainID := big.NewInt(42161) keyManager, err := security.NewKeyManagerWithChainID(cfg, logger, chainID) require.NoError(t, err) defer keyManager.Shutdown() privateKey, err := keyManager.GetActivePrivateKey() require.NoError(t, err) fromAddr := crypto.PubkeyToAddress(privateKey.PublicKey) toAddr := common.HexToAddress("0xC36442b4a4522E871399CD717aBDD847Ab11FE88") tx := types.NewTransaction( 0, toAddr, big.NewInt(0), 21000, big.NewInt(1_500_000_000), // 1.5 gwei nil, ) request := &security.SigningRequest{ Transaction: tx, ChainID: chainID, From: fromAddr, Purpose: "integration test", UrgencyLevel: 1, } result, err := keyManager.SignTransaction(request) require.NoError(t, err) require.NotNil(t, result.SignedTx) validator := security.NewChainIDValidator(logger, chainID) validation := validator.ValidateChainID(result.SignedTx, fromAddr, nil) require.True(t, validation.Valid) require.Equal(t, "NONE", validation.ReplayRisk) // Sign a transaction with an incorrect chain ID manually and ensure validator catches it privateKeyMismatch, err := keyManager.GetActivePrivateKey() require.NoError(t, err) mismatchTx := types.NewTransaction( 1, toAddr, big.NewInt(0), 21000, big.NewInt(1_500_000_000), nil, ) wrongSigner := types.NewEIP155Signer(big.NewInt(1)) mismatchedSignedTx, err := types.SignTx(mismatchTx, wrongSigner, privateKeyMismatch) require.NoError(t, err) mismatchResult := validator.ValidateChainID(mismatchedSignedTx, fromAddr, nil) require.False(t, mismatchResult.Valid) require.Greater(t, len(mismatchResult.Errors), 0) }