From 14e4c7d3d81517639a42339bdc8e215e22ed4189 Mon Sep 17 00:00:00 2001 From: "Zhdanovich, Dzmitry" Date: Wed, 14 Oct 2026 20:52:29 +0200 Subject: [PATCH] Allow Artifactory S3 redirect for configured registry Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../handlers/egress_allowlist_defaults.yaml | 5 ++++ internal/handlers/egress_allowlist_test.go | 2 ++ .../handlers/egress_dynamic_hosts_test.go | 26 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/internal/handlers/egress_allowlist_defaults.yaml b/internal/handlers/egress_allowlist_defaults.yaml index 408646b..28701c7 100644 --- a/internal/handlers/egress_allowlist_defaults.yaml +++ b/internal/handlers/egress_allowlist_defaults.yaml @@ -171,6 +171,11 @@ shared_registry_domains: # the credential (e.g. the private ECR layer bucket, which interpolates the # region) stay in registryRedirectHosts in Go. registry_redirect_derivations: + # Wolters Kluwer's configured Artifactory npm registry redirects artifact + # downloads to its S3 storage bucket. + - credential_host: artifactory.wolterskluwer.io + derived: + - jfrog-platform.s3.eu-west-1.amazonaws.com # packagecloud.io redirects downloads to one CloudFront distribution it owns. - credential_host: packagecloud.io derived: diff --git a/internal/handlers/egress_allowlist_test.go b/internal/handlers/egress_allowlist_test.go index 9dd86ce..7789623 100644 --- a/internal/handlers/egress_allowlist_test.go +++ b/internal/handlers/egress_allowlist_test.go @@ -563,6 +563,8 @@ func TestEgressAllowlist_JFrogS3BucketsAllowedButSharedS3Blocked(t *testing.T) { "https://attacker-bucket.s3.amazonaws.com/loot", "https://s3.amazonaws.com/attacker-bucket/loot", "https://s3-us-west-2.amazonaws.com/attacker-bucket/loot", + // The Artifactory redirect bucket is only allowed for matching registry credentials. + "https://jfrog-platform.s3.eu-west-1.amazonaws.com/artifactory/artifact", } { resp := egressResult(t, h, blocked) if assert.NotNil(t, resp, "shared S3 host must be blocked: "+blocked) { diff --git a/internal/handlers/egress_dynamic_hosts_test.go b/internal/handlers/egress_dynamic_hosts_test.go index 5c12a2b..46d45e3 100644 --- a/internal/handlers/egress_dynamic_hosts_test.go +++ b/internal/handlers/egress_dynamic_hosts_test.go @@ -208,6 +208,32 @@ func TestRegistryRedirectHosts_PackagecloudCDNNotAllowedWithoutCredential(t *tes "download CDN must not be allowed for a job with no packagecloud credential") } +func TestRegistryRedirectHosts_WoltersKluwerArtifactoryS3Derived(t *testing.T) { + registry := "https://artifactory.wolterskluwer.io/artifactory/api/npm/group-npm/" + artifact := "https://jfrog-platform.s3.eu-west-1.amazonaws.com/artifactory/c6/c6af054e3732c361e9ad8c44070f909666b5616f" + h := newEgressHandlerWithCreds(config.Credentials{ + {"type": "npm_registry", "registry": registry}, + }) + + assert.Nil(t, egressResult(t, h, registry), "the configured Artifactory registry must be allowed") + assert.Nil(t, egressResult(t, h, artifact), + "the S3 artifact host must be allowed for the matching Artifactory credential") + + for _, blocked := range []string{ + "https://evil.jfrog-platform.s3.eu-west-1.amazonaws.com/artifact", + "https://jfrog-platform.s3.us-east-1.amazonaws.com/artifact", + } { + assert.NotNil(t, egressResult(t, h, blocked), + "only the exact derived S3 host must be allowed: "+blocked) + } + + otherRegistry := newEgressHandlerWithCreds(config.Credentials{ + {"type": "npm_registry", "registry": "https://registry.npmjs.org"}, + }) + assert.NotNil(t, egressResult(t, otherRegistry, artifact), + "the S3 artifact host must remain blocked without the matching registry credential") +} + func TestRegistryRedirectHosts_GemfuryStorageDerived(t *testing.T) { // Gemfury endpoints redirect downloads to one Gemfury-owned bucket, // reachable on both its dualstack and plain accelerate endpoints.