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

Release 3.3.0 to main #525

Merged
merged 11 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 0 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ SDP_UI_BASE_URL=http://stellar.local:3000
DATABASE_URL="postgres://postgres@localhost:5432/sdp_mtn?sslmode=disable"

LOG_LEVEL=info
EC256_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ3HNphPAEKHvtRjsl5Kjwc9tTMqS\n2pmYNybrLsxZ6cuQvg2yiEoXZixP2cJ77csHClXC6cb1wQp/BNGDvGKoPg==\n-----END PUBLIC KEY-----"
EC256_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgdo6o+tdFkF94B7z8\nnoybH6/zO3PryLLjLbj54/zOi4WhRANCAAQncc2mE8AQoe+1GOyXkqPBz21MypLa\nmZg3JusuzFnpy5C+DbKIShdmLE/ZwnvtywcKVcLpxvXBCn8E0YO8Yqg+\n-----END PRIVATE KEY-----"
EMAIL_SENDER_TYPE=DRY_RUN
SMS_SENDER_TYPE=DRY_RUN
Expand Down
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,27 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/).

## Unreleased
## [3.3.0](https://github.com/stellar/stellar-disbursement-platform-backend/releases/tag/3.3.0) ([diff](https://github.com/stellar/stellar-disbursement-platform-backend/compare/3.2.0...3.3.0))

Release of the Stellar Disbursement Platform `v3.3.0`. This release adds support to Circle's Transfers API, as an
alternative to the Payouts API. It also adds audit functionality for the `receivers` table to track changes.

> [!WARNING]
> This version is compatible with the [stellar/stellar-disbursement-platform-frontend] version `3.3.0`.

### Added

- Audit functionality for the `receivers` table to track changes. [#520](https://github.com/stellar/stellar-disbursement-platform-backend/pull/520)
- Support for Circle API type `TRANSFERS`, and allow users to choose between `TRANSFERS` and `PAYOUTS` through the `CIRCLE_API_TYPE` environment variable. It defaults to `TRANSFERS`. [#522](https://github.com/stellar/stellar-disbursement-platform-backend/pull/522)

### Changed

- Refactor MFA and reCAPTCHA handling for better modularity in preparation for API-only usage. [#499](https://github.com/stellar/stellar-disbursement-platform-backend/pull/499)

### Removed

- Removed `EC256_PUBLIC_KEY` environment variable as it can be derived from the `EC256_PRIVATE_KEY` [#511](https://github.com/stellar/stellar-disbursement-platform-backend/pull/511)
- Removed `nginx.ingress.kubernetes.io/server-snippet` annotation from SDP and AP ingress resources. [#510](https://github.com/stellar/stellar-disbursement-platform-backend/pull/510)

## [3.2.0](https://github.com/stellar/stellar-disbursement-platform-backend/releases/tag/3.2.0) ([diff](https://github.com/stellar/stellar-disbursement-platform-backend/compare/3.1.0...3.2.0))

Expand Down
19 changes: 11 additions & 8 deletions cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ func (s *ServerService) GetSchedulerJobRegistrars(
Models: models,
DistAccountResolver: serveOpts.SubmitterEngine.DistributionAccountResolver,
CircleService: serveOpts.CircleService,
CircleAPIType: serveOpts.CircleAPIType,
}),
scheduler.WithStellarPaymentToSubmitterJobOption(jobs.StellarPaymentToSubmitterJobOptions{
JobIntervalSeconds: schedulerOptions.PaymentJobIntervalSeconds,
Expand Down Expand Up @@ -202,6 +203,7 @@ func (s *ServerService) SetupConsumers(ctx context.Context, o SetupConsumersOpti
MtnDBConnectionPool: o.ServeOpts.MtnDBConnectionPool,
DistAccountResolver: o.ServeOpts.SubmitterEngine.DistributionAccountResolver,
CircleService: o.ServeOpts.CircleService,
CircleAPIType: o.ServeOpts.CircleAPIType,
}),
)
if err != nil {
Expand Down Expand Up @@ -240,14 +242,6 @@ func (c *ServeCommand) Command(serverService ServerServiceInterface, monitorServ
ConfigKey: &serveOpts.InstanceName,
Required: true,
},
{
Name: "ec256-public-key",
Usage: "The EC256 Public Key used to validate the token signature. This EC key needs to be at least as strong as prime256v1 (P-256).",
OptType: types.String,
CustomSetValue: cmdUtils.SetConfigOptionEC256PublicKey,
ConfigKey: &serveOpts.EC256PublicKey,
Required: true,
},
{
Name: "ec256-private-key",
Usage: "The EC256 Private Key used to sign the authentication token. This EC key needs to be at least as strong as prime256v1 (P-256).",
Expand Down Expand Up @@ -371,6 +365,15 @@ func (c *ServeCommand) Command(serverService ServerServiceInterface, monitorServ
ConfigKey: &serveOpts.SingleTenantMode,
FlagDefault: false,
},
{
Name: "circle-api-type",
Usage: `The Circle API type. Options: ["TRANSFERS", "PAYOUTS"]. `,
OptType: types.String,
ConfigKey: &serveOpts.CircleAPIType,
Required: true,
CustomSetValue: cmdUtils.SetConfigOptionCircleAPIType,
FlagDefault: string(circle.APITypeTransfers),
},
}

// crash tracker options
Expand Down
3 changes: 1 addition & 2 deletions cmd/serve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ func Test_serve(t *testing.T) {
MonitorService: mMonitorService,
AdminDBConnectionPool: dbConnectionPool,
MtnDBConnectionPool: dbConnectionPool,
EC256PublicKey: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER88h7AiQyVDysRTxKvBB6CaiO/kS\ncvGyimApUE/12gFhNTRf37SE19CSCllKxstnVFOpLLWB7Qu5OJ0Wvcz3hg==\n-----END PUBLIC KEY-----",
EC256PrivateKey: "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgIqI1MzMZIw2pQDLx\nJn0+FcNT/hNjwtn2TW43710JKZqhRANCAARHzyHsCJDJUPKxFPEq8EHoJqI7+RJy\n8bKKYClQT/XaAWE1NF/ftITX0JIKWUrGy2dUU6kstYHtC7k4nRa9zPeG\n-----END PRIVATE KEY-----",
CorsAllowedOrigins: []string{"*"},
SEP24JWTSecret: "jwt_secret_1234567890",
Expand All @@ -178,6 +177,7 @@ func Test_serve(t *testing.T) {
MaxInvitationResendAttempts: 3,
DistAccEncryptionPassphrase: distributionAccPrivKey,
CircleService: mCircleService,
CircleAPIType: circle.APITypeTransfers,
}
serveOpts.AnchorPlatformAPIService, err = anchorplatform.NewAnchorPlatformAPIService(httpclient.DefaultClient(), serveOpts.AnchorPlatformBasePlatformURL, serveOpts.AnchorPlatformOutgoingJWTSecret)
require.NoError(t, err)
Expand Down Expand Up @@ -291,7 +291,6 @@ func Test_serve(t *testing.T) {
require.True(t, serveCmdFound, "serve command not found")

t.Setenv("DATABASE_URL", dbt.DSN)
t.Setenv("EC256_PUBLIC_KEY", serveOpts.EC256PublicKey)
t.Setenv("EC256_PRIVATE_KEY", serveOpts.EC256PrivateKey)
t.Setenv("SEP24_JWT_SECRET", serveOpts.SEP24JWTSecret)
t.Setenv("SEP10_SIGNING_PUBLIC_KEY", serveOpts.Sep10SigningPublicKey)
Expand Down
34 changes: 13 additions & 21 deletions cmd/utils/custom_set_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/stellar/go/support/config"
"github.com/stellar/go/support/log"

"github.com/stellar/stellar-disbursement-platform-backend/internal/circle"
"github.com/stellar/stellar-disbursement-platform-backend/internal/crashtracker"
"github.com/stellar/stellar-disbursement-platform-backend/internal/data"
"github.com/stellar/stellar-disbursement-platform-backend/internal/events"
Expand All @@ -20,6 +21,18 @@ import (
"github.com/stellar/stellar-disbursement-platform-backend/internal/utils"
)

func SetConfigOptionCircleAPIType(co *config.ConfigOption) error {
apiType := viper.GetString(co.Name)

circleAPIType, err := circle.ParseAPIType(apiType)
if err != nil {
return fmt.Errorf("couldn't parse circle API type in %s: %w", co.Name, err)
}

*(co.ConfigKey.(*circle.APIType)) = circleAPIType
return nil
}

func SetConfigOptionMessengerType(co *config.ConfigOption) error {
senderType := viper.GetString(co.Name)

Expand Down Expand Up @@ -81,27 +94,6 @@ func SetConfigOptionLogLevel(co *config.ConfigOption) error {
return nil
}

// SetConfigOptionEC256PublicKey parses the config option incoming value and validates if it is a valid EC256PublicKey.
func SetConfigOptionEC256PublicKey(co *config.ConfigOption) error {
key, ok := co.ConfigKey.(*string)
if !ok {
return fmt.Errorf("not a valid EC256PublicKey in %s: the expected type for this config key is a string, but got a %T instead", co.Name, co.ConfigKey)
}

publicKey := viper.GetString(co.Name)

// We must remove the literal \n in case of the config options being set this way
publicKey = strings.Replace(publicKey, `\n`, "\n", -1)

_, err := utils.ParseStrongECPublicKey(publicKey)
if err != nil {
return fmt.Errorf("parsing EC256PublicKey in %s: %w", co.Name, err)
}

*key = publicKey
return nil
}

// SetConfigOptionEC256PrivateKey parses the config option incoming value and validates if it is a valid EC256PrivateKey.
func SetConfigOptionEC256PrivateKey(co *config.ConfigOption) error {
key, ok := co.ConfigKey.(*string)
Expand Down
108 changes: 52 additions & 56 deletions cmd/utils/custom_set_value_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/stellar/stellar-disbursement-platform-backend/internal/circle"
"github.com/stellar/stellar-disbursement-platform-backend/internal/crashtracker"
"github.com/stellar/stellar-disbursement-platform-backend/internal/data"
"github.com/stellar/stellar-disbursement-platform-backend/internal/events"
Expand Down Expand Up @@ -278,62 +279,6 @@ func Test_SetConfigOptionCrashTrackerType(t *testing.T) {
}
}

func Test_SetConfigOptionEC256PublicKey(t *testing.T) {
opts := struct{ ec256PublicKey string }{}

co := config.ConfigOption{
Name: "ec256-public-key",
OptType: types.String,
CustomSetValue: SetConfigOptionEC256PublicKey,
ConfigKey: &opts.ec256PublicKey,
}

expectedPublicKey := `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER88h7AiQyVDysRTxKvBB6CaiO/kS
cvGyimApUE/12gFhNTRf37SE19CSCllKxstnVFOpLLWB7Qu5OJ0Wvcz3hg==
-----END PUBLIC KEY-----`

testCases := []customSetterTestCase[string]{
{
name: "returns an error if the value is not a PEM string",
args: []string{"--ec256-public-key", "not-a-pem-string"},
wantErrContains: "parsing EC256PublicKey in ec256-public-key: failed to decode PEM block containing public key",
},
{
name: "returns an error if the value is not a x509 string",
args: []string{"--ec256-public-key", "-----BEGIN MY STRING-----\nYWJjZA==\n-----END MY STRING-----"},
wantErrContains: "parsing EC256PublicKey in ec256-public-key: failed to parse EC public key",
},
{
name: "returns an error if the value is not a ECDSA public key",
args: []string{"--ec256-public-key", "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyNPqmozv8a2PnXHIkV+F\nmWMFy2YhOFzX12yzjjWkJ3rI9QSEomz4Unkwc6oYrnKEDYlnAgCiCqL2zPr5qNkX\nk5MPU87/wLgEqp7uAk0GkJZfrhJIYZ5AuG9+o69BNeQDEi7F3YdMJj9bvs2Ou1FN\n1zG/8HV969rJ/63fzWsqlNon1j4H5mJ0YbmVh/QLcYPmv7feFZGEj4OSZ4u+eJsw\nat5NPyhMgo6uB/goNS3fEY29UNvXoSIN3hnK3WSxQ79Rjn4V4so7ehxzCVPjnm/G\nFFTgY0hGBobmnxbjI08hEZmYKosjan4YqydGETjKR3UlhBx9y/eqqgL+opNJ8vJs\n2QIDAQAB\n-----END PUBLIC KEY-----"},
wantErrContains: "parsing EC256PublicKey in ec256-public-key: not a valid elliptic curve public key",
},
{
name: "🎉 handles EC256 public key through the CLI flag",
args: []string{"--ec256-public-key", expectedPublicKey},
wantResult: expectedPublicKey,
},
{
name: "🎉 handles EC256 public key through the ENV vars",
envValue: expectedPublicKey,
wantResult: expectedPublicKey,
},
{
name: "🎉 handles EC256 public key through the ENV vars & inline line-breaks",
envValue: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER88h7AiQyVDysRTxKvBB6CaiO/kS\ncvGyimApUE/12gFhNTRf37SE19CSCllKxstnVFOpLLWB7Qu5OJ0Wvcz3hg==\n-----END PUBLIC KEY-----",
wantResult: expectedPublicKey,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
opts.ec256PublicKey = ""
customSetterTester[string](t, tc, co)
})
}
}

func Test_SetConfigOptionEC256PrivateKey(t *testing.T) {
opts := struct{ ec256PrivateKey string }{}

Expand Down Expand Up @@ -767,3 +712,54 @@ func Test_SetRegistrationContactType(t *testing.T) {
})
}
}

func Test_SetConfigOptionCircleAPIType(t *testing.T) {
opts := struct{ circleAPIType circle.APIType }{}

co := config.ConfigOption{
Name: "circle-api-type",
OptType: types.String,
CustomSetValue: SetConfigOptionCircleAPIType,
ConfigKey: &opts.circleAPIType,
}

testCases := []customSetterTestCase[circle.APIType]{
{
name: "returns an error if the API type is empty",
args: []string{},
wantErrContains: `couldn't parse circle API type in circle-api-type: invalid Circle API type "", must be one of [PAYOUTS TRANSFERS]`,
},
{
name: "returns an error if the API type is invalid",
args: []string{"--circle-api-type", "test"},
wantErrContains: `couldn't parse circle API type in circle-api-type: invalid Circle API type "TEST", must be one of [PAYOUTS TRANSFERS]`,
},
{
name: "🎉 handles API type PAYOUTS (through CLI args)",
args: []string{"--circle-api-type", "PaYoUtS"},
wantResult: circle.APITypePayouts,
},
{
name: "🎉 handles API type PAYOUTS (through ENV vars)",
envValue: "PAYOUTS",
wantResult: circle.APITypePayouts,
},
{
name: "🎉 handles API type TRANSFERS (through CLI args)",
args: []string{"--circle-api-type", "TrAnSfErS"},
wantResult: circle.APITypeTransfers,
},
{
name: "🎉 handles API type TRANSFERS (through ENV vars)",
envValue: "TRANSFERS",
wantResult: circle.APITypeTransfers,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
opts.circleAPIType = ""
customSetterTester[circle.APIType](t, tc, co)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Add auditing to receiver_verifications

-- +migrate Up
SELECT 1 FROM create_audit_table('receivers');

-- +migrate Down
SELECT 1 FROM drop_audit_table('receivers');
1 change: 0 additions & 1 deletion dev/docker-compose-sdp-anchor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ services:
EMAIL_SENDER_TYPE: DRY_RUN
SMS_SENDER_TYPE: DRY_RUN
NETWORK_PASSPHRASE: "Test SDF Network ; September 2015"
EC256_PUBLIC_KEY: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ3HNphPAEKHvtRjsl5Kjwc9tTMqS\n2pmYNybrLsxZ6cuQvg2yiEoXZixP2cJ77csHClXC6cb1wQp/BNGDvGKoPg==\n-----END PUBLIC KEY-----"
SEP10_SIGNING_PUBLIC_KEY: ${SEP10_SIGNING_PUBLIC_KEY}
ANCHOR_PLATFORM_BASE_SEP_URL: http://localhost:8080
ANCHOR_PLATFORM_BASE_PLATFORM_URL: http://anchor-platform:8085
Expand Down
4 changes: 2 additions & 2 deletions helmchart/sdp/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
apiVersion: v2
name: stellar-disbursement-platform
description: A Helm chart for the Stellar Disbursement Platform Backend (A.K.A. `sdp`)
version: "3.1.0"
appVersion: "3.2.0"
version: "3.3.0"
appVersion: "3.3.0"
type: application
maintainers:
- name: Stellar Development Foundation
Expand Down
Loading