linting
This commit is contained in:
47
api/gateway/aurora/.golangci.yml
Normal file
47
api/gateway/aurora/.golangci.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
version: "2"
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- bodyclose
|
||||
- canonicalheader
|
||||
- copyloopvar
|
||||
- durationcheck
|
||||
- errcheck
|
||||
- errchkjson
|
||||
- errname
|
||||
- errorlint
|
||||
- gosec
|
||||
- govet
|
||||
- ineffassign
|
||||
- nilerr
|
||||
- nilnesserr
|
||||
- nilnil
|
||||
- noctx
|
||||
- rowserrcheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- wastedassign
|
||||
disable:
|
||||
- depguard
|
||||
- exhaustruct
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gomoddirectives
|
||||
- wrapcheck
|
||||
- cyclop
|
||||
- dupl
|
||||
- funlen
|
||||
- gocognit
|
||||
- gocyclo
|
||||
- ireturn
|
||||
- lll
|
||||
- mnd
|
||||
- nestif
|
||||
- nlreturn
|
||||
- noinlineerr
|
||||
- paralleltest
|
||||
- tagliatelle
|
||||
- testpackage
|
||||
- varnamelen
|
||||
- wsl_v5
|
||||
@@ -87,7 +87,7 @@ func (g *gatewayClient) callContext(ctx context.Context, method string) (context
|
||||
}
|
||||
g.logger.Info("Aurora gateway client call timeout applied", fields...)
|
||||
}
|
||||
return context.WithTimeout(ctx, timeout)
|
||||
return context.WithTimeout(ctx, timeout) //nolint:gosec // cancel func is always invoked by call sites
|
||||
}
|
||||
|
||||
func (g *gatewayClient) CreateCardPayout(ctx context.Context, req *mntxv1.CardPayoutRequest) (*mntxv1.CardPayoutResponse, error) {
|
||||
|
||||
@@ -434,7 +434,7 @@ func buildGatewayLimits(cfg limitsConfig) *gatewayv1.Limits {
|
||||
if bucket == "" {
|
||||
continue
|
||||
}
|
||||
limits.VelocityLimit[bucket] = int32(value)
|
||||
limits.VelocityLimit[bucket] = int32(value) //nolint:gosec // velocity limits are validated config values
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ func buildGatewayLimits(cfg limitsConfig) *gatewayv1.Limits {
|
||||
MinAmount: strings.TrimSpace(override.MinAmount),
|
||||
MaxAmount: strings.TrimSpace(override.MaxAmount),
|
||||
MaxFee: strings.TrimSpace(override.MaxFee),
|
||||
MaxOps: int32(override.MaxOps),
|
||||
MaxOps: int32(override.MaxOps), //nolint:gosec // max ops is a validated config value
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -546,11 +546,12 @@ func (i *Imp) startHTTPCallbackServer(svc *auroraservice.Service, cfg callbackRu
|
||||
})
|
||||
|
||||
server := &http.Server{
|
||||
Addr: cfg.Address,
|
||||
Handler: router,
|
||||
Addr: cfg.Address,
|
||||
Handler: router,
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
}
|
||||
|
||||
ln, err := net.Listen("tcp", cfg.Address)
|
||||
ln, err := (&net.ListenConfig{}).Listen(context.Background(), "tcp", cfg.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func (s *cardPayoutStore) FindByIdempotencyKey(_ context.Context, key string) (*
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return nil, nil //nolint:nilnil // test store: payout not found by idempotency key
|
||||
}
|
||||
|
||||
func (s *cardPayoutStore) FindByOperationRef(_ context.Context, ref string) (*model.CardPayout, error) {
|
||||
@@ -64,7 +64,7 @@ func (s *cardPayoutStore) FindByOperationRef(_ context.Context, ref string) (*mo
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return nil, nil //nolint:nilnil // test store: payout not found by operation ref
|
||||
}
|
||||
|
||||
func (s *cardPayoutStore) FindByPaymentID(_ context.Context, id string) (*model.CardPayout, error) {
|
||||
@@ -75,7 +75,7 @@ func (s *cardPayoutStore) FindByPaymentID(_ context.Context, id string) (*model.
|
||||
return v, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return nil, nil //nolint:nilnil // test store: payout not found by payment id
|
||||
}
|
||||
|
||||
func (s *cardPayoutStore) Upsert(_ context.Context, record *model.CardPayout) error {
|
||||
|
||||
@@ -107,7 +107,7 @@ func findOperationRef(operationRef, payoutID string) string {
|
||||
|
||||
func (p *cardPayoutProcessor) findExistingPayoutState(ctx context.Context, state *model.CardPayout) (*model.CardPayout, error) {
|
||||
if p == nil || state == nil {
|
||||
return nil, nil
|
||||
return nil, nil //nolint:nilnil // nil processor/state means there is no existing payout state to load
|
||||
}
|
||||
if opRef := strings.TrimSpace(state.OperationRef); opRef != "" {
|
||||
existing, err := p.store.Payouts().FindByOperationRef(ctx, opRef)
|
||||
@@ -122,12 +122,12 @@ func (p *cardPayoutProcessor) findExistingPayoutState(ctx context.Context, state
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return nil, nil //nolint:nilnil // nil means no payout state exists for the operation reference
|
||||
}
|
||||
|
||||
func (p *cardPayoutProcessor) findAndMergePayoutState(ctx context.Context, state *model.CardPayout) (*model.CardPayout, error) {
|
||||
if p == nil || state == nil {
|
||||
return nil, nil
|
||||
return nil, nil //nolint:nilnil // nil processor/state means there is no existing payout state to merge
|
||||
}
|
||||
existing, err := p.findExistingPayoutState(ctx, state)
|
||||
if err != nil {
|
||||
@@ -862,7 +862,7 @@ func (p *cardPayoutProcessor) retryContext() (context.Context, context.CancelFun
|
||||
if timeout <= 0 {
|
||||
return ctx, func() {}
|
||||
}
|
||||
return context.WithTimeout(ctx, timeout)
|
||||
return context.WithTimeout(ctx, timeout) //nolint:gosec // cancel func is always invoked by caller
|
||||
}
|
||||
|
||||
func (p *cardPayoutProcessor) runCardPayoutRetry(req *mntxv1.CardPayoutRequest, attempt uint32, maxAttempts uint32) {
|
||||
@@ -1369,8 +1369,7 @@ func (p *cardPayoutProcessor) Tokenize(ctx context.Context, req *mntxv1.CardToke
|
||||
zap.String("customer_id", strings.TrimSpace(req.GetCustomerId())),
|
||||
)
|
||||
|
||||
cardInput, err := validateCardTokenizeRequest(req, p.config)
|
||||
if err != nil {
|
||||
if _, err := validateCardTokenizeRequest(req, p.config); err != nil {
|
||||
p.logger.Warn("Card tokenization validation failed",
|
||||
zap.String("request_id", req.GetRequestId()),
|
||||
zap.String("customer_id", req.GetCustomerId()),
|
||||
@@ -1379,14 +1378,15 @@ func (p *cardPayoutProcessor) Tokenize(ctx context.Context, req *mntxv1.CardToke
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var err error
|
||||
req = sanitizeCardTokenizeRequest(req)
|
||||
cardInput := extractTokenizeCard(req)
|
||||
|
||||
projectID, err := p.resolveProjectID(req.GetProjectId(), "request_id", req.GetRequestId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req = sanitizeCardTokenizeRequest(req)
|
||||
cardInput = extractTokenizeCard(req)
|
||||
|
||||
token := buildSimulatedCardToken(req.GetRequestId(), cardInput.pan)
|
||||
maskedPAN := provider.MaskPAN(cardInput.pan)
|
||||
p.rememberTokenPAN(token, cardInput.pan)
|
||||
@@ -1506,7 +1506,8 @@ func (p *cardPayoutProcessor) ProcessCallback(ctx context.Context, payload []byt
|
||||
}
|
||||
|
||||
retryScheduled := false
|
||||
if state.Status == model.PayoutStatusFailed || state.Status == model.PayoutStatusCancelled {
|
||||
switch state.Status {
|
||||
case model.PayoutStatusFailed, model.PayoutStatusCancelled:
|
||||
decision := p.retryPolicy.decideProviderFailure(state.ProviderCode)
|
||||
attemptsUsed := p.currentDispatchAttempt(operationRef)
|
||||
maxAttempts := p.maxDispatchAttempts()
|
||||
@@ -1553,7 +1554,7 @@ func (p *cardPayoutProcessor) ProcessCallback(ctx context.Context, payload []byt
|
||||
if !retryScheduled && strings.TrimSpace(state.FailureReason) == "" {
|
||||
state.FailureReason = payoutFailureReason(state.ProviderCode, state.ProviderMessage)
|
||||
}
|
||||
} else if state.Status == model.PayoutStatusSuccess {
|
||||
case model.PayoutStatusSuccess:
|
||||
state.FailureReason = ""
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,15 @@ func (s staticClock) Now() time.Time {
|
||||
return s.now
|
||||
}
|
||||
|
||||
func mustMarshalJSON(t *testing.T, value any) []byte {
|
||||
t.Helper()
|
||||
body, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
t.Fatalf("json marshal failed: %v", err)
|
||||
}
|
||||
return body
|
||||
}
|
||||
|
||||
type apiResponse struct {
|
||||
RequestID string `json:"request_id"`
|
||||
Status string `json:"status"`
|
||||
@@ -70,7 +79,7 @@ func TestCardPayoutProcessor_Submit_Success(t *testing.T) {
|
||||
Transport: roundTripperFunc(func(r *http.Request) (*http.Response, error) {
|
||||
resp := apiResponse{}
|
||||
resp.Operation.RequestID = "req-123"
|
||||
body, _ := json.Marshal(resp)
|
||||
body := mustMarshalJSON(t, resp)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewReader(body)),
|
||||
@@ -260,7 +269,7 @@ func TestCardPayoutProcessor_Submit_SameParentDifferentOperationsStoredSeparatel
|
||||
callN++
|
||||
resp := apiResponse{}
|
||||
resp.Operation.RequestID = fmt.Sprintf("req-%d", callN)
|
||||
body, _ := json.Marshal(resp)
|
||||
body := mustMarshalJSON(t, resp)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewReader(body)),
|
||||
@@ -350,7 +359,7 @@ func TestCardPayoutProcessor_StrictMode_BlocksSecondOperationUntilFirstFinalCall
|
||||
n := callN.Add(1)
|
||||
resp := apiResponse{}
|
||||
resp.Operation.RequestID = fmt.Sprintf("req-%d", n)
|
||||
body, _ := json.Marshal(resp)
|
||||
body := mustMarshalJSON(t, resp)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewReader(body)),
|
||||
@@ -544,7 +553,7 @@ func TestCardPayoutProcessor_Submit_RetriesProviderLimitDeclineUntilSuccess(t *t
|
||||
if n == 1 {
|
||||
resp.Code = providerCodeDeclineAmountOrFrequencyLimit
|
||||
resp.Message = "Decline due to amount or frequency limit"
|
||||
body, _ := json.Marshal(resp)
|
||||
body := mustMarshalJSON(t, resp)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusTooManyRequests,
|
||||
Body: io.NopCloser(bytes.NewReader(body)),
|
||||
@@ -552,7 +561,7 @@ func TestCardPayoutProcessor_Submit_RetriesProviderLimitDeclineUntilSuccess(t *t
|
||||
}, nil
|
||||
}
|
||||
resp.Operation.RequestID = "req-retry-success"
|
||||
body, _ := json.Marshal(resp)
|
||||
body := mustMarshalJSON(t, resp)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewReader(body)),
|
||||
@@ -617,7 +626,7 @@ func TestCardPayoutProcessor_Submit_RetriesProviderLimitDeclineThenFails(t *test
|
||||
Code: providerCodeDeclineAmountOrFrequencyLimit,
|
||||
Message: "Decline due to amount or frequency limit",
|
||||
}
|
||||
body, _ := json.Marshal(resp)
|
||||
body := mustMarshalJSON(t, resp)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusTooManyRequests,
|
||||
Body: io.NopCloser(bytes.NewReader(body)),
|
||||
@@ -689,7 +698,7 @@ func TestCardPayoutProcessor_ProcessCallback_RetryableDeclineSchedulesRetry(t *t
|
||||
} else {
|
||||
resp.Operation.RequestID = "req-after-callback-retry"
|
||||
}
|
||||
body, _ := json.Marshal(resp)
|
||||
body := mustMarshalJSON(t, resp)
|
||||
return &http.Response{
|
||||
StatusCode: http.StatusOK,
|
||||
Body: io.NopCloser(bytes.NewReader(body)),
|
||||
|
||||
@@ -40,8 +40,8 @@ func TestValidateCardTokenizeRequest_Expired(t *testing.T) {
|
||||
cfg := testProviderConfig()
|
||||
req := validCardTokenizeRequest()
|
||||
now := time.Now().UTC()
|
||||
req.CardExpMonth = uint32(now.Month())
|
||||
req.CardExpYear = uint32(now.Year() - 1)
|
||||
req.CardExpMonth = uint32(now.Month()) //nolint:gosec // month value is bounded by time.Time
|
||||
req.CardExpYear = uint32(now.Year() - 1) //nolint:gosec // test value intentionally uses previous year
|
||||
|
||||
_, err := validateCardTokenizeRequest(req, cfg)
|
||||
requireReason(t, err, "expired_card")
|
||||
|
||||
@@ -251,8 +251,8 @@ func buildCardPayoutRequestFromParams(reader params.Reader,
|
||||
AmountMinor: amountMinor,
|
||||
Currency: currency,
|
||||
CardPan: strings.TrimSpace(reader.String("card_pan")),
|
||||
CardExpYear: uint32(readerInt64(reader, "card_exp_year")),
|
||||
CardExpMonth: uint32(readerInt64(reader, "card_exp_month")),
|
||||
CardExpYear: uint32(readerInt64(reader, "card_exp_year")), //nolint:gosec // values are validated by request validators
|
||||
CardExpMonth: uint32(readerInt64(reader, "card_exp_month")), //nolint:gosec // values are validated by request validators
|
||||
CardHolder: strings.TrimSpace(reader.String("card_holder")),
|
||||
Metadata: metadataFromReader(reader),
|
||||
OperationRef: operationRef,
|
||||
|
||||
@@ -128,12 +128,13 @@ func (m *strictIsolatedPayoutExecutionMode) tryAcquire(operationRef string) (<-c
|
||||
return nil, false, errPayoutExecutionModeStopped
|
||||
}
|
||||
|
||||
switch owner := strings.TrimSpace(m.activeOperation); {
|
||||
case owner == "":
|
||||
owner := strings.TrimSpace(m.activeOperation)
|
||||
switch owner {
|
||||
case "":
|
||||
m.activeOperation = operationRef
|
||||
m.signalLocked()
|
||||
return nil, true, nil
|
||||
case owner == operationRef:
|
||||
case operationRef:
|
||||
return nil, true, nil
|
||||
default:
|
||||
return m.waitCh, false, nil
|
||||
|
||||
@@ -28,7 +28,6 @@ func TestPayoutFailurePolicy_DecideProviderFailure(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Helper()
|
||||
got := policy.decideProviderFailure(tc.code)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package gateway
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -238,6 +238,6 @@ func normalizeExpiryYear(year uint32) string {
|
||||
|
||||
func buildSimulatedCardToken(requestID, pan string) string {
|
||||
input := strings.TrimSpace(requestID) + "|" + normalizeCardNumber(pan)
|
||||
sum := sha1.Sum([]byte(input))
|
||||
sum := sha256.Sum256([]byte(input))
|
||||
return "aur_tok_" + hex.EncodeToString(sum[:8])
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ func (s *Service) startDiscoveryAnnouncer() {
|
||||
if strings.TrimSpace(announce.ID) == "" {
|
||||
announce.ID = discovery.StablePaymentGatewayID(discovery.RailCardPayout)
|
||||
}
|
||||
s.announcer = discovery.NewAnnouncer(s.logger, s.producer, string(mservice.MntxGateway), announce)
|
||||
s.announcer = discovery.NewAnnouncer(s.logger, s.producer, mservice.MntxGateway, announce)
|
||||
s.announcer.Start()
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ func requireReason(t *testing.T, err error, reason string) {
|
||||
if !errors.Is(err, merrors.ErrInvalidArg) {
|
||||
t.Fatalf("expected invalid argument error, got %v", err)
|
||||
}
|
||||
reasoned, ok := err.(payoutFailure)
|
||||
if !ok {
|
||||
var reasoned payoutFailure
|
||||
if !errors.As(err, &reasoned) {
|
||||
t.Fatalf("expected payout failure reason, got %T", err)
|
||||
}
|
||||
if reasoned.Reason() != reason {
|
||||
@@ -82,5 +82,5 @@ func validCardTokenizeRequest() *mntxv1.CardTokenizeRequest {
|
||||
|
||||
func futureExpiry() (uint32, uint32) {
|
||||
now := time.Now().UTC()
|
||||
return uint32(now.Month()), uint32(now.Year() + 1)
|
||||
return uint32(now.Month()), uint32(now.Year() + 1) //nolint:gosec // month/year values are bounded by time.Time
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ func (p *cardPayoutProcessor) updatePayoutStatus(ctx context.Context, state *mod
|
||||
return nil, emitErr
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
return struct{}{}, nil
|
||||
})
|
||||
if err != nil {
|
||||
p.logger.Warn("Failed to update transfer status", zap.Error(err), mzap.ObjRef("payout_ref", state.ID),
|
||||
|
||||
Reference in New Issue
Block a user