Summary
Dependabot fails to authenticate with Amazon ECR Public (public.ecr.aws) when configured
as a docker_registry private registry. The proxy sends Authorization: Basic, but ECR
Public only accepts Authorization: Bearer and responds with HTTP 400 (not 401) for
any Basic auth request (not on the /token endpoint):
{"errors":[{"code":"DENIED","message":"Your Authorization Token is invalid."}]}
Because the response is 400 and not 401, TokenTransport.isTokenDemand() never
triggers, so the token exchange flow is never attempted. (Ref: https://github.com/stackrox/docker-registry-client/blob/main/registry/tokentransport.go#L141)
Not being able to authenticate on public.ecr.aws causes 429 ratelimit errors during dependabot execution.
Root Cause
In internal/handlers/docker_registry.go, the ecrRe regex only matches private ECR
hostnames (\d+.dkr.ecr.*\.amazonaws\.com). public.ecr.aws does not match, so it falls
through to the generic BasicTransport path:
// line 26 — public.ecr.aws does NOT match this
ecrRe = regexp.MustCompile(`\A\d+.dkr.ecr.([a-z0-9-]+)\.amazonaws\.com\z`)
// line 121-136 — public.ecr.aws ends up here
transport := ®istry.BasicTransport{
Transport: ®istry.TokenTransport{...},
URL: fmt.Sprintf("https://%s", cred.registry),
Username: cred.getUsername(), // e.g. "AWS"
Password: cred.getPassword(), // e.g. <jwt>
}
BasicTransport.RoundTrip unconditionally adds Authorization: Basic base64("AWS:")
to every request (it only skips auth if both username and password are empty strings).
ECR Public's behaviour differs from private ECR:
- Private ECR (.dkr.ecr..amazonaws.com) — returns 401 on wrong auth →
TokenTransport kicks in → works
- ECR Public (public.ecr.aws) — returns 400 on any Basic auth → transport chain
never retries → broken
Expected / Required Auth Flow for ECR Public
Per the ECR Public authentication docs,
the correct auth for public.ecr.aws registry endpoints is:
Authorization: Bearer <base64("AWS:")>
where the token is obtained from ecr-public:GetAuthorizationToken (us-east-1 only).
Suggested Fix
Extend getECRCredentials to also handle public.ecr.aws as a special case and then call
helpers.SetBearerAuthorization instead of helpers.SetBasicAuthorization:
Environment
- Registry: public.ecr.aws (Amazon ECR Public)
- Configured via GitHub org private registry API as docker_registry type
Summary
Dependabot fails to authenticate with Amazon ECR Public (
public.ecr.aws) when configuredas a
docker_registryprivate registry. The proxy sendsAuthorization: Basic, but ECRPublic only accepts
Authorization: Bearerand responds with HTTP 400 (not 401) forany Basic auth request (not on the /token endpoint):
{"errors":[{"code":"DENIED","message":"Your Authorization Token is invalid."}]}Because the response is
400and not401,TokenTransport.isTokenDemand()nevertriggers, so the token exchange flow is never attempted. (Ref: https://github.com/stackrox/docker-registry-client/blob/main/registry/tokentransport.go#L141)
Not being able to authenticate on public.ecr.aws causes 429 ratelimit errors during dependabot execution.
Root Cause
In
internal/handlers/docker_registry.go, theecrReregex only matches private ECRhostnames (
\d+.dkr.ecr.*\.amazonaws\.com).public.ecr.awsdoes not match, so it fallsthrough to the generic
BasicTransportpath:BasicTransport.RoundTrip unconditionally adds Authorization: Basic base64("AWS:")
to every request (it only skips auth if both username and password are empty strings).
ECR Public's behaviour differs from private ECR:
TokenTransport kicks in → works
never retries → broken
Expected / Required Auth Flow for ECR Public
Per the ECR Public authentication docs,
the correct auth for public.ecr.aws registry endpoints is:
Authorization: Bearer <base64("AWS:")>
where the token is obtained from ecr-public:GetAuthorizationToken (us-east-1 only).
Suggested Fix
Extend getECRCredentials to also handle public.ecr.aws as a special case and then call
helpers.SetBearerAuthorization instead of helpers.SetBasicAuthorization:
Environment