Skip to content

Commit

Permalink
Set up server-level configuration for OpenSanctions provider.
Browse files Browse the repository at this point in the history
  • Loading branch information
apognu committed Jan 29, 2025
1 parent e55c0da commit 354b6db
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 14 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ CONVOY_API_URL=
CONVOY_API_KEY=
CONVOY_PROJECT_ID=

<<<<<<< HEAD
#
# TUNING
#
Expand Down
5 changes: 5 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ func RunServer() error {
ProjectID: utils.GetEnv("CONVOY_PROJECT_ID", ""),
RateLimit: utils.GetEnv("CONVOY_RATE_LIMIT", 50),
}
openSanctionsConfig := infra.InitializeOpenSanctions(
utils.GetEnv("OPENSANCTIONS_API_HOST", ""),
utils.GetEnv("OPENSANCTIONS_API_KEY", ""),
)

seedOrgConfig := models.SeedOrgConfiguration{
CreateGlobalAdminEmail: utils.GetEnv("CREATE_GLOBAL_ADMIN_EMAIL", ""),
Expand Down Expand Up @@ -133,6 +137,7 @@ func RunServer() error {
infra.InitializeConvoyRessources(convoyConfiguration),
convoyConfiguration.RateLimit,
),
repositories.WithOpenSanctions(openSanctionsConfig),
repositories.WithClientDbConfig(clientDbConfig),
repositories.WithTracerProvider(telemetryRessources.TracerProvider),
)
Expand Down
35 changes: 35 additions & 0 deletions infra/opensanctions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package infra

const (
OPEN_SANCTIONS_API_HOST = "https://api.opensanctions.org"
)

type OpenSanctions struct {
host string
// TODO: this is only for SaaS OpenSanctions API, we may need to abstract
// over authentication to at least offer Basic and Bearer for self-hosted.
apiKey string
}

func InitializeOpenSanctions(host, apiKey string) OpenSanctions {
return OpenSanctions{
host: host,
apiKey: apiKey,
}
}

func (os OpenSanctions) IsSelfHosted() bool {
return len(os.host) > 0
}

func (os OpenSanctions) Host() string {
if os.IsSelfHosted() {
return os.host
}

return OPEN_SANCTIONS_API_HOST
}

func (os OpenSanctions) ApiKey() string {
return os.apiKey
}
3 changes: 1 addition & 2 deletions repositories/httpmodels/http_opensanctions_result.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ type HTTPOpenSanctionsResult struct {
Total struct {
Value int `json:"value"`
} `json:"total"`
Limit int `json:"limit"`
Results []struct {
Id string `json:"id"`
Schema string `json:"schema"`
Expand All @@ -30,7 +29,7 @@ func AdaptOpenSanctionsResult(result HTTPOpenSanctionsResult) (models.SanctionCh
matches := make(map[string]models.SanctionCheckResultMatch)

for _, resp := range result.Responses {
if resp.Total.Value != resp.Limit {
if resp.Total.Value > len(resp.Results) {
partial = true
}

Expand Down
25 changes: 16 additions & 9 deletions repositories/opensanctions_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,19 @@ import (
"encoding/json"
"fmt"
"net/http"
"net/url"

"github.com/checkmarble/marble-backend/infra"
"github.com/checkmarble/marble-backend/models"
"github.com/checkmarble/marble-backend/repositories/httpmodels"
"github.com/checkmarble/marble-backend/utils"
"github.com/cockroachdb/errors"
"github.com/google/uuid"
)

const (
// TODO: Pull this as server configuration
DEV_YENTE_URL = "http://app.yente.orb.local"
)

type OpenSanctionsRepository struct{}
type OpenSanctionsRepository struct {
opensanctions infra.OpenSanctions
}

type openSanctionsRequest struct {
Queries map[string]openSanctionsRequestQuery `json:"queries"`
Expand Down Expand Up @@ -62,7 +61,7 @@ func (repo OpenSanctionsRepository) Search(ctx context.Context, cfg models.Sanct
return httpmodels.AdaptOpenSanctionsResult(matches)
}

func (OpenSanctionsRepository) searchRequest(ctx context.Context, query models.OpenSanctionsQuery) (*http.Request, error) {
func (repo OpenSanctionsRepository) searchRequest(ctx context.Context, query models.OpenSanctionsQuery) (*http.Request, error) {
q := openSanctionsRequest{
Queries: make(map[string]openSanctionsRequestQuery, len(query.Queries)),
}
Expand All @@ -80,8 +79,16 @@ func (OpenSanctionsRepository) searchRequest(ctx context.Context, query models.O
return nil, errors.Wrap(err, "could not parse OpenSanctions response")
}

url := fmt.Sprintf("%s/match/sanctions", DEV_YENTE_URL)
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, &body)
requestUrl := fmt.Sprintf("%s/match/sanctions", repo.opensanctions.Host())

if len(repo.opensanctions.ApiKey()) > 0 {
qs := url.Values{}
qs.Set("api_key", repo.opensanctions.ApiKey())

requestUrl = fmt.Sprintf("%s?%s", requestUrl, qs.Encode())
}

req, err := http.NewRequestWithContext(ctx, http.MethodPost, requestUrl, &body)

return req, err
}
11 changes: 11 additions & 0 deletions repositories/repositories.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type options struct {
clientDbConfig map[string]infra.ClientDbConfig
convoyClientProvider ConvoyClientProvider
convoyRateLimit int
openSanctions infra.OpenSanctions
riverClient *river.Client[pgx.Tx]
tp trace.TracerProvider
}
Expand Down Expand Up @@ -50,6 +51,12 @@ func WithConvoyClientProvider(convoyResources ConvoyClientProvider, convoyRateLi
}
}

func WithOpenSanctions(openSanctionsConfig infra.OpenSanctions) Option {
return func(o *options) {
o.openSanctions = openSanctionsConfig
}
}

func WithRiverClient(client *river.Client[pgx.Tx]) Option {
return func(o *options) {
o.riverClient = client
Expand Down Expand Up @@ -84,6 +91,7 @@ type Repositories struct {
CustomListRepository CustomListRepository
UploadLogRepository UploadLogRepository
MarbleAnalyticsRepository MarbleAnalyticsRepository
OpenSanctionsRepository OpenSanctionsRepository
TransferCheckEnrichmentRepository *TransferCheckEnrichmentRepository
TaskQueueRepository TaskQueueRepository
ScenarioTestrunRepository ScenarioTestRunRepository
Expand Down Expand Up @@ -131,6 +139,9 @@ func NewRepositories(
MarbleAnalyticsRepository: MarbleAnalyticsRepository{
metabase: options.metabase,
},
OpenSanctionsRepository: OpenSanctionsRepository{
opensanctions: options.openSanctions,
},
TransferCheckEnrichmentRepository: NewTransferCheckEnrichmentRepository(
blobRepository,
options.transfercheckEnrichmentBucket,
Expand Down
3 changes: 2 additions & 1 deletion usecases/evaluate_scenario/evaluate_scenario.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ func processScenarioIteration(ctx context.Context, params ScenarioEvaluationPara

if iteration.SanctionCheckConfig != nil {
query := models.OpenSanctionsQuery{Queries: models.OpenSanctionCheckFilter{
// TODO: take this from the context and the scenario configuration
"name": []string{"obama"},
}}

Expand All @@ -137,7 +138,7 @@ func processScenarioIteration(ctx context.Context, params ScenarioEvaluationPara
return models.ScenarioExecution{}, errors.Wrap(err, "could not perform sanction check")
}

logger.Debug("SANCTION CHECK: found", "matches", result.Count)
logger.Debug("SANCTION CHECK: found", "matches", result.Count, "partial", result.Partial)
}

// Compute outcome from score
Expand Down
3 changes: 1 addition & 2 deletions usecases/usecases_with_creds.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package usecases

import (
"github.com/checkmarble/marble-backend/models"
"github.com/checkmarble/marble-backend/repositories"
"github.com/checkmarble/marble-backend/usecases/decision_phantom"
"github.com/checkmarble/marble-backend/usecases/decision_workflows"
"github.com/checkmarble/marble-backend/usecases/inboxes"
Expand Down Expand Up @@ -120,7 +119,7 @@ func (usecases *UsecasesWithCreds) NewDecisionUsecase() DecisionUsecase {

func (usecases *UsecasesWithCreds) NewSanctionCheckUsecase() SanctionCheckUsecase {
return SanctionCheckUsecase{
openSanctionsProvider: repositories.OpenSanctionsRepository{},
openSanctionsProvider: usecases.Repositories.OpenSanctionsRepository,
repository: &usecases.Repositories.MarbleDbRepository,
}
}
Expand Down

0 comments on commit 354b6db

Please sign in to comment.