Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(*): add gosec #94

Merged
merged 14 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ jobs:
run-unit-tests: true
run-integration-tests: true
run-lint: true
run-gosec: true
gosec-args: "-exclude-generated -exclude-dir=e2etest -exclude-dir=testutil ./..."
install-dependencies-command: |
sudo apt-get update
sudo apt-get install -y libzmq3-dev
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jobs:
run-unit-tests: true
run-integration-tests: true
run-lint: true
run-gosec: true
gosec-args: "-exclude-generated -exclude-dir=e2etest -exclude-dir=testutil ./..."
install-dependencies-command: |
sudo apt-get update
sudo apt-get install -y libzmq3-dev
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## Unreleased

* [#94](https://github.com/babylonlabs-io/vigilante/pull/94) adds gosec and fixes gosec issues

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty line


## v0.15.0

* [#90](https://github.com/babylonlabs-io/vigilante/pull/90) upgrade babylon to v0.15.0
Expand Down
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ proto-gen:
.PHONY: proto-gen


###############################################################################
### Gosec ###
###############################################################################

gosec-local: ## Run local security checks
gosec -exclude-generated -exclude-dir=$(CURDIR)/testutil -exclude-dir=$(CURDIR)/e2etest $(CURDIR)/...

.PHONY: gosec-local

###############################################################################
### Release ###
###############################################################################
Expand Down
16 changes: 12 additions & 4 deletions btcclient/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ func (c *Client) GetBestBlock() (uint32, error) {
return 0, err
}

if height < 0 || height > int64(^uint32(0)) {
RafilxTenfen marked this conversation as resolved.
Show resolved Hide resolved
panic(fmt.Errorf("height (%d) is out of uint32 range", height)) //software bug, panic
}

return uint32(height), nil
}

Expand All @@ -34,7 +38,11 @@ func (c *Client) GetBlockByHash(blockHash *chainhash.Hash) (*types.IndexedBlock,
}

btcTxs := types.GetWrappedTxs(mBlock)
return types.NewIndexedBlock(int32(blockInfo.Height), &mBlock.Header, btcTxs), mBlock, nil
height := blockInfo.Height
if height < 0 || height > int64(^uint32(0)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems a bit overkill and removing this check and running make gosec-local does not errors 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure? Because it does for me:
image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will clean cache and try again

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeap, for me it doesn't appear the error

$~ make gosec-local

Results:


Summary:
  Gosec  : 2.20.0
  Files  : 90
  Lines  : 10303
  Nosec  : 5
  Issues : 0

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you do any other configuration?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, I was on a "dev" version. Fixed, thanks @RafilxTenfen

Copy link
Member Author

@Lazar955 Lazar955 Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah now the CI fails, so seems that we do need it, as our CI used the latest version. I'll be reverting this code then. And you should upgrade to latest version of gosec (2.21.4).

Summary:
  Gosec  : dev
  Files  : 90
  Lines  : 10287
  Nosec  : 5
  Issues : 2

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

 curl -sfL https://raw.githubusercontent.com/securego/gosec/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.21.4

And try again @RafilxTenfen

panic(fmt.Errorf("height (%d) is out of uint32 range", height)) //software bug, panic
}
return types.NewIndexedBlock(uint32(height), &mBlock.Header, btcTxs), mBlock, nil
}

// GetBlockByHeight returns a block with the given height
Expand All @@ -51,7 +59,7 @@ func (c *Client) GetBlockByHeight(height uint32) (*types.IndexedBlock, *wire.Msg

btcTxs := types.GetWrappedTxs(mBlock)

return types.NewIndexedBlock(int32(height), &mBlock.Header, btcTxs), mBlock, nil
return types.NewIndexedBlock(height, &mBlock.Header, btcTxs), mBlock, nil
}

func (c *Client) getBestBlockHashWithRetry() (*chainhash.Hash, error) {
Expand Down Expand Up @@ -153,7 +161,7 @@ func (c *Client) getBlockVerboseWithRetry(hash *chainhash.Hash) (*btcjson.GetBlo
// getChainBlocks returns a chain of indexed blocks from the block at baseHeight to the tipBlock
// note: the caller needs to ensure that tipBlock is on the blockchain
func (c *Client) getChainBlocks(baseHeight uint32, tipBlock *types.IndexedBlock) ([]*types.IndexedBlock, error) {
tipHeight := uint32(tipBlock.Height)
tipHeight := tipBlock.Height
if tipHeight < baseHeight {
return nil, fmt.Errorf("the tip block height %v is less than the base height %v", tipHeight, baseHeight)
}
Expand Down Expand Up @@ -201,7 +209,7 @@ func (c *Client) FindTailBlocksByHeight(baseHeight uint32) ([]*types.IndexedBloc
return nil, err
}

if baseHeight > uint32(tipIb.Height) {
if baseHeight > tipIb.Height {
return nil, fmt.Errorf("invalid base height %d, should not be higher than tip block %d", baseHeight, tipIb.Height)
}

Expand Down
4 changes: 4 additions & 0 deletions btcstaking-tracker/atomicslasher/routines.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package atomicslasher

import (
"fmt"
"time"

bstypes "github.com/babylonlabs-io/babylon/x/btcstaking/types"
Expand Down Expand Up @@ -58,6 +59,9 @@ func (as *AtomicSlasher) slashingTxTracker() {
return
}
// record BTC tip
if blockEpoch.Height < 0 {
panic(fmt.Errorf("received negative block height: %d", blockEpoch.Height))
}
as.btcTipHeight.Store(uint32(blockEpoch.Height))
as.logger.Debug("Received new best btc block", zap.Int32("height", blockEpoch.Height))
// get full BTC block
Expand Down
10 changes: 10 additions & 0 deletions btcstaking-tracker/btcslasher/slasher_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package btcslasher
import (
"encoding/hex"
"fmt"
"math"
"strings"

"github.com/avast/retry-go/v4"
Expand Down Expand Up @@ -213,6 +214,10 @@ func BuildUnbondingSlashingTxWithWitness(
return nil, fmt.Errorf("failed to convert covenant pks to BTC pks: %v", err)
}

if d.UnbondingTime > uint32(^uint16(0)) {
panic(fmt.Errorf("unbondingTime (%d) exceeds maximum for uint16", d.UnbondingTime))
}

// get unbonding info
unbondingInfo, err := btcstaking.BuildUnbondingInfo(
d.BtcPk.MustToBTCPK(),
Expand Down Expand Up @@ -316,7 +321,12 @@ func BuildSlashingTxWithWitness(
return nil, fmt.Errorf("failed to convert covenant pks to BTC pks: %v", err)
}

if d.TotalSat > math.MaxInt64 {
panic(fmt.Errorf("TotalSat %d exceeds int64 range", d.TotalSat))
}

// get staking info
// #nosec G115 -- performed the conversion check above
stakingInfo, err := btcstaking.BuildStakingInfo(
d.BtcPk.MustToBTCPK(),
fpBtcPkList,
Expand Down
12 changes: 9 additions & 3 deletions btcstaking-tracker/stakingeventwatcher/stakingeventwatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ func (sew *StakingEventWatcher) Start() error {
// we registered for notifications with `nil` so we should receive best block immediately
select {
case block := <-blockEventNotifier.Epochs:
if block.Height < 0 {
panic(fmt.Errorf("received negative block height: %d", block.Height))
}
sew.currentBestBlockHeight.Store(uint32(block.Height))
case <-sew.quit:
startErr = errors.New("watcher quit before finishing start")
Expand Down Expand Up @@ -158,6 +161,9 @@ func (sew *StakingEventWatcher) handleNewBlocks(blockNotifier *notifier.BlockEpo
if !ok {
return
}
if block.Height < 0 {
panic(fmt.Errorf("received negative block height: %d", block.Height))
}
sew.currentBestBlockHeight.Store(uint32(block.Height))
sew.logger.Debugf("Received new best btc block: %d", block.Height)
case <-sew.quit:
Expand All @@ -183,7 +189,7 @@ func (sew *StakingEventWatcher) checkBabylonDelegations(status btcstakingtypes.B
addDel(delegation)
}

if len(delegations) < int(sew.cfg.NewDelegationsBatchSize) {
if uint64(len(delegations)) < sew.cfg.NewDelegationsBatchSize {
// we received fewer delegations than we asked for; it means went through all of them
return nil
}
Expand Down Expand Up @@ -451,7 +457,7 @@ func (sew *StakingEventWatcher) buildSpendingTxProof(spendingTx *wire.MsgTx) (*b
}

btcTxs := types.GetWrappedTxs(details.Block)
ib := types.NewIndexedBlock(int32(details.BlockHeight), &details.Block.Header, btcTxs)
ib := types.NewIndexedBlock(details.BlockHeight, &details.Block.Header, btcTxs)

proof, err := ib.GenSPVProof(int(details.TxIndex))
if err != nil {
Expand Down Expand Up @@ -596,7 +602,7 @@ func (sew *StakingEventWatcher) checkBtcForStakingTx() error {
}

btcTxs := types.GetWrappedTxs(details.Block)
ib := types.NewIndexedBlock(int32(details.BlockHeight), &details.Block.Header, btcTxs)
ib := types.NewIndexedBlock(details.BlockHeight, &details.Block.Header, btcTxs)

proof, err := ib.GenSPVProof(int(details.TxIndex))
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions config/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ type MonitorConfig struct {
// Max number of BTC blocks in the buffer
BtcBlockBufferSize uint64 `mapstructure:"btc-block-buffer-size"`
// Max number of BTC blocks in the cache
BtcCacheSize uint64 `mapstructure:"btc-cache-size"`
BtcCacheSize uint32 `mapstructure:"btc-cache-size"`
// Intervals between each liveness check in seconds
LivenessCheckIntervalSeconds uint64 `mapstructure:"liveness-check-interval-seconds"`
// Max lasting BTC heights that a checkpoint is not reported before an alarm is sent
MaxLiveBtcHeights uint64 `mapstructure:"max-live-btc-heights"`
// the confirmation depth to consider a BTC block as confirmed
BtcConfirmationDepth uint64 `mapstructure:"btc-confirmation-depth"`
BtcConfirmationDepth uint32 `mapstructure:"btc-confirmation-depth"`
// whether to enable liveness checker
EnableLivenessChecker bool `mapstructure:"enable-liveness-checker"`
// DatabaseConfig stores lates epoch and height used for faster bootstrap
Expand Down
2 changes: 1 addition & 1 deletion config/reporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const (
// ReporterConfig defines configuration for the reporter.
type ReporterConfig struct {
NetParams string `mapstructure:"netparams"` // should be mainnet|testnet|simnet|signet
BTCCacheSize uint64 `mapstructure:"btc_cache_size"` // size of the BTC cache
BTCCacheSize uint32 `mapstructure:"btc_cache_size"` // size of the BTC cache
MaxHeadersInMsg uint32 `mapstructure:"max_headers_in_msg"` // maximum number of headers in a MsgInsertHeaders message
}

Expand Down
6 changes: 5 additions & 1 deletion config/submitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type SubmitterConfig struct {
// ResubmitFeeMultiplier is used to multiply the estimated bumped fee in resubmission
ResubmitFeeMultiplier float64 `mapstructure:"resubmit-fee-multiplier"`
// PollingIntervalSeconds defines the intervals (in seconds) between each polling of Babylon checkpoints
PollingIntervalSeconds uint `mapstructure:"polling-interval-seconds"`
PollingIntervalSeconds int64 `mapstructure:"polling-interval-seconds"`
// ResendIntervalSeconds defines the time (in seconds) which the submitter awaits
// before resubmitting checkpoints to BTC
ResendIntervalSeconds uint `mapstructure:"resend-interval-seconds"`
Expand All @@ -39,6 +39,10 @@ func (cfg *SubmitterConfig) Validate() error {
return errors.New("invalid resubmit-fee-multiplier, should not be less than 1")
}

if cfg.PollingIntervalSeconds < 0 {
return errors.New("invalid polling-interval-seconds, should not be less than 0")
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if cfg.PollingIntervalSeconds < 0 {
return errors.New("invalid polling-interval-seconds, should not be less than 0")
}
if cfg.PollingIntervalSeconds <= 0 {
return errors.New("invalid polling-interval-seconds, should be positive")
}


return nil
}

Expand Down
12 changes: 10 additions & 2 deletions metrics/prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package metrics

import (
"net/http"
_ "net/http/pprof"
_ "net/http/pprof" // #nosec G108 we want this
"regexp"
"time"

"github.com/babylonlabs-io/vigilante/config"
"github.com/prometheus/client_golang/prometheus"
Expand Down Expand Up @@ -37,5 +38,12 @@ func start(addr string, reg *prometheus.Registry) {
}
log := metricsLogger.With(zap.String("module", "metrics")).Sugar()
log.Infof("Successfully started Prometheus metrics server at %s", addr)
log.Fatal(http.ListenAndServe(addr, nil))
srv := &http.Server{
Addr: addr,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
if err := srv.ListenAndServe(); err != nil {
log.Fatalf("Failed to start metrics server: %v", err)
}
}
19 changes: 16 additions & 3 deletions monitor/btcscanner/block_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package btcscanner
import (
"errors"
"fmt"
"math"

"github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/chainntnfs"
Expand All @@ -17,10 +18,13 @@ func (bs *BtcScanner) bootstrapAndBlockEventHandler() {
var blockEpoch *chainntnfs.BlockEpoch
bestKnownBlock := bs.unconfirmedBlockCache.Tip()
if bestKnownBlock != nil {
if bestKnownBlock.Height > math.MaxInt32 {
panic(fmt.Errorf("block height exceeds int32 range: %d", bestKnownBlock.Height))
}
hash := bestKnownBlock.BlockHash()
blockEpoch = &chainntnfs.BlockEpoch{
Hash: &hash,
Height: bestKnownBlock.Height,
Height: int32(bestKnownBlock.Height),
BlockHeader: bestKnownBlock.Header,
}
}
Expand All @@ -43,7 +47,11 @@ func (bs *BtcScanner) bootstrapAndBlockEventHandler() {
return // channel closed
}

if err := bs.handleNewBlock(epoch.Height, epoch.BlockHeader); err != nil {
if epoch.Height < 0 {
panic(fmt.Errorf("received negative epoch height: %d", epoch.Height)) // software bug, panic
}

if err := bs.handleNewBlock(uint32(epoch.Height), epoch.BlockHeader); err != nil {
bs.logger.Warnf("failed to handle block at height %d: %s, "+
"need to restart the bootstrapping process", epoch.Height, err.Error())
bs.Bootstrap()
Expand All @@ -54,7 +62,7 @@ func (bs *BtcScanner) bootstrapAndBlockEventHandler() {

// handleNewBlock handles blocks from the BTC client
// if new confirmed blocks are found, send them through the channel
func (bs *BtcScanner) handleNewBlock(height int32, header *wire.BlockHeader) error {
func (bs *BtcScanner) handleNewBlock(height uint32, header *wire.BlockHeader) error {
// get cache tip
cacheTip := bs.unconfirmedBlockCache.Tip()
if cacheTip == nil {
Expand Down Expand Up @@ -91,7 +99,12 @@ func (bs *BtcScanner) handleNewBlock(height int32, header *wire.BlockHeader) err
// otherwise, add the block to the cache
bs.unconfirmedBlockCache.Add(ib)

if bs.unconfirmedBlockCache.Size() > math.MaxInt32 {
panic(fmt.Errorf("unconfirmedBlockCache exceeds uint32"))
}

// still unconfirmed
// #nosec G115 -- performed the conversion check above
if uint32(bs.unconfirmedBlockCache.Size()) <= bs.k {
return nil
}
Expand Down
8 changes: 4 additions & 4 deletions monitor/btcscanner/btc_scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func New(
logger: parentLogger.With(zap.String("module", "btcscanner")).Sugar(),
btcClient: btcClient,
btcNotifier: btcNotifier,
k: uint32(monitorCfg.BtcConfirmationDepth),
k: monitorCfg.BtcConfirmationDepth,
ckptCache: ckptCache,
unconfirmedBlockCache: unconfirmedBlockCache,
confirmedBlocksChan: confirmedBlocksChan,
Expand Down Expand Up @@ -143,9 +143,9 @@ func (bs *BtcScanner) Bootstrap() {
)

if bs.confirmedTipBlock != nil {
firstUnconfirmedHeight = uint32(bs.confirmedTipBlock.Height + 1)
firstUnconfirmedHeight = bs.confirmedTipBlock.Height + 1
} else {
firstUnconfirmedHeight = uint32(bs.GetBaseHeight())
firstUnconfirmedHeight = bs.GetBaseHeight()
}

bs.logger.Infof("the bootstrapping starts at %d", firstUnconfirmedHeight)
Expand Down Expand Up @@ -251,7 +251,7 @@ func (bs *BtcScanner) matchAndPop() (*types.CheckpointRecord, error) {

return &types.CheckpointRecord{
RawCheckpoint: rawCheckpoint,
FirstSeenBtcHeight: uint32(ckptSegments.Segments[0].AssocBlock.Height),
FirstSeenBtcHeight: ckptSegments.Segments[0].AssocBlock.Height,
}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion monitor/btcscanner/btc_scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func FuzzBootStrap(f *testing.F) {
Return(chainIndexedBlocks[i], nil, nil).AnyTimes()
}

cache, err := types.NewBTCCache(numBlocks)
cache, err := types.NewBTCCache(uint32(numBlocks))
require.NoError(t, err)
var btcScanner btcscanner.BtcScanner
btcScanner.SetBtcClient(mockBtcClient)
Expand Down
7 changes: 6 additions & 1 deletion monitor/liveness_checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package monitor

import (
"fmt"
"math"
"time"

"github.com/pkg/errors"
Expand All @@ -12,6 +13,10 @@ import (
)

func (m *Monitor) runLivenessChecker() {
if m.Cfg.LivenessCheckIntervalSeconds > uint64(math.MaxInt64/time.Second) {
panic(fmt.Errorf("LivenessCheckIntervalSeconds %d exceeds int64 range when converted to time.Duration", m.Cfg.LivenessCheckIntervalSeconds))
}
// #nosec G115 -- performed the conversion check above
ticker := time.NewTicker(time.Duration(m.Cfg.LivenessCheckIntervalSeconds) * time.Second)

m.logger.Infof("liveness checker is started, checking liveness every %d seconds", m.Cfg.LivenessCheckIntervalSeconds)
Expand Down Expand Up @@ -89,7 +94,7 @@ func (m *Monitor) CheckLiveness(cr *types.CheckpointRecord) error {
return fmt.Errorf("the gap %d between two BTC heights should not be negative", gap)
}

if gap > int(m.Cfg.MaxLiveBtcHeights) {
if uint64(gap) > m.Cfg.MaxLiveBtcHeights {
return fmt.Errorf("%w: the gap BTC height is %d, larger than the threshold %d", types.ErrLivenessAttack, gap, m.Cfg.MaxLiveBtcHeights)
}

Expand Down
Loading
Loading