mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 09:01:31 +00:00
feat: answer ECR DescribeRegistry with the caller's registry and an empty replication configuration (#1182)
This commit is contained in:
@@ -17,13 +17,13 @@ tags:
|
||||
|
||||
## Overview
|
||||
|
||||
The platform serves **391 operations** across the AWS APIs below. Every page names the operations its service implements from the pinned model, generated from the dispatch tables on each build rather than written by hand.
|
||||
The platform serves **392 operations** across the AWS APIs below. Every page names the operations its service implements from the pinned model, generated from the dispatch tables on each build rather than written by hand.
|
||||
|
||||
| Service | Operations |
|
||||
|---|---:|
|
||||
| [ACM](/coverage/acm) | 9 |
|
||||
| [EC2](/coverage/ec2) | 127 |
|
||||
| [ECR](/coverage/ecr) | 22 |
|
||||
| [ECR](/coverage/ecr) | 23 |
|
||||
| [ECS](/coverage/ecs) | 31 |
|
||||
| [EKS](/coverage/eks) | 27 |
|
||||
| [ELBv2](/coverage/elbv2) | 36 |
|
||||
@@ -31,4 +31,4 @@ The platform serves **391 operations** across the AWS APIs below. Every page nam
|
||||
| [RDS](/coverage/rds) | 27 |
|
||||
| [S3](/coverage/s3) | 26 |
|
||||
| [STS](/coverage/sts) | 5 |
|
||||
| **Total** | **391** |
|
||||
| **Total** | **392** |
|
||||
|
||||
@@ -1983,6 +1983,7 @@
|
||||
"DeleteRepository",
|
||||
"DeleteRepositoryPolicy",
|
||||
"DescribeImages",
|
||||
"DescribeRegistry",
|
||||
"DescribeRepositories",
|
||||
"GetAuthorizationToken",
|
||||
"GetLifecyclePolicy",
|
||||
@@ -2002,7 +2003,6 @@
|
||||
"stubbed": [
|
||||
"BatchCheckLayerAvailability",
|
||||
"CompleteLayerUpload",
|
||||
"DescribeRegistry",
|
||||
"GetDownloadUrlForLayer",
|
||||
"GetRegistryPolicy",
|
||||
"InitiateLayerUpload",
|
||||
|
||||
@@ -18,7 +18,7 @@ tags:
|
||||
|
||||
## Overview
|
||||
|
||||
Spinifex implements **22 operations** in the ECR `2015-09-21` API model.
|
||||
Spinifex implements **23 operations** in the ECR `2015-09-21` API model.
|
||||
|
||||
### Two endpoints, one registry
|
||||
|
||||
@@ -26,7 +26,7 @@ Repository metadata is served over the AWS API on the gateway endpoint. Image da
|
||||
|
||||
The split explains the stubs below. The layer-transfer operations — `BatchCheckLayerAvailability`, `InitiateLayerUpload`, `UploadLayerPart`, `CompleteLayerUpload` and `GetDownloadUrlForLayer` — are registered stubs because the `/v2/` endpoint carries that traffic instead. A client using `docker` or any OCI-compatible tool never calls them.
|
||||
|
||||
Registry replication is a stub for the same kind of reason: a deployment is a single registry, with no cross-region peer to replicate to.
|
||||
Registry replication is a stub for the same kind of reason: a deployment is a single registry, with no cross-region peer to replicate to. `DescribeRegistry` reports this as a replication configuration with no rules.
|
||||
|
||||
### Operations
|
||||
|
||||
@@ -39,6 +39,7 @@ Registry replication is a stub for the same kind of reason: a deployment is a si
|
||||
| `DeleteRepository` |
|
||||
| `DeleteRepositoryPolicy` |
|
||||
| `DescribeImages` |
|
||||
| `DescribeRegistry` |
|
||||
| `DescribeRepositories` |
|
||||
| `GetAuthorizationToken` |
|
||||
| `GetLifecyclePolicy` |
|
||||
|
||||
@@ -4,4 +4,4 @@ Repository metadata is served over the AWS API on the gateway endpoint. Image da
|
||||
|
||||
The split explains the stubs below. The layer-transfer operations — `BatchCheckLayerAvailability`, `InitiateLayerUpload`, `UploadLayerPart`, `CompleteLayerUpload` and `GetDownloadUrlForLayer` — are registered stubs because the `/v2/` endpoint carries that traffic instead. A client using `docker` or any OCI-compatible tool never calls them.
|
||||
|
||||
Registry replication is a stub for the same kind of reason: a deployment is a single registry, with no cross-region peer to replicate to.
|
||||
Registry replication is a stub for the same kind of reason: a deployment is a single registry, with no cross-region peer to replicate to. `DescribeRegistry` reports this as a replication configuration with no rules.
|
||||
|
||||
@@ -762,7 +762,7 @@ spot-price: On owned hardware there is no spot-to-on-demand price differential,
|
||||
|
||||
## ecr
|
||||
|
||||
`2015-09-21` — 22 of 58 modelled operations implemented (37.9%), 11 stubbed, 0 not applicable, 3 registered outside the pinned model.
|
||||
`2015-09-21` — 23 of 58 modelled operations implemented (39.7%), 10 stubbed, 0 not applicable, 3 registered outside the pinned model.
|
||||
|
||||
### Not implemented
|
||||
|
||||
@@ -793,7 +793,6 @@ spot-price: On owned hardware there is no spot-to-on-demand price differential,
|
||||
|
||||
- `BatchCheckLayerAvailability`
|
||||
- `CompleteLayerUpload`
|
||||
- `DescribeRegistry`
|
||||
- `GetDownloadUrlForLayer`
|
||||
- `GetRegistryPolicy`
|
||||
- `InitiateLayerUpload`
|
||||
|
||||
@@ -79,7 +79,7 @@ var Actions = map[string]Handler{
|
||||
"DeleteRepositoryPolicy": DeleteRepositoryPolicy,
|
||||
"GetRegistryPolicy": NotImplemented,
|
||||
"PutRegistryPolicy": NotImplemented,
|
||||
"DescribeRegistry": NotImplemented,
|
||||
"DescribeRegistry": DescribeRegistry,
|
||||
|
||||
// Image scanning is unsupported (no scanner backend), except that
|
||||
// PutImageScanningConfiguration accepts the scanOnPush=false no-op rather
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package gateway_ecrapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ecr"
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
// DescribeRegistry reports the caller's registry. A deployment has no
|
||||
// replication, so the configuration is always present with an empty rules
|
||||
// list, which is what AWS returns for an account with none configured.
|
||||
func DescribeRegistry(_ context.Context, _ *nats.Conn, accountID string, body []byte) (any, error) {
|
||||
if len(body) > 0 {
|
||||
var req struct{}
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
return nil, MalformedBodyError()
|
||||
}
|
||||
}
|
||||
return &ecr.DescribeRegistryOutput{
|
||||
RegistryId: aws.String(accountID),
|
||||
ReplicationConfiguration: &ecr.ReplicationConfiguration{
|
||||
Rules: []*ecr.ReplicationRule{},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package gateway_ecrapi_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/mulgadc/spinifex/spinifex/awserrors"
|
||||
gateway_ecrapi "github.com/mulgadc/spinifex/spinifex/gateway/ecrapi"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// describeRegistryWire runs the dispatched DescribeRegistry handler and
|
||||
// serialises its output the way the gateway does, returning the decoded body.
|
||||
func describeRegistryWire(t *testing.T, accountID string, body []byte) map[string]any {
|
||||
t.Helper()
|
||||
out, err := gateway_ecrapi.Actions["DescribeRegistry"](context.Background(), nil, accountID, body)
|
||||
require.NoError(t, err)
|
||||
w := httptest.NewRecorder()
|
||||
gateway_ecrapi.WriteJSONResponse(w, out)
|
||||
var decoded map[string]any
|
||||
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &decoded))
|
||||
return decoded
|
||||
}
|
||||
|
||||
// AWS answers an account with no replication with the configuration present
|
||||
// and an empty rules list, not with the configuration omitted.
|
||||
func TestDescribeRegistry_CallerAccountAndEmptyReplication(t *testing.T) {
|
||||
for _, body := range []string{"", "{}", "null"} {
|
||||
t.Run("body="+body, func(t *testing.T) {
|
||||
decoded := describeRegistryWire(t, "123456789012", []byte(body))
|
||||
assert.Equal(t, map[string]any{
|
||||
"registryId": "123456789012",
|
||||
"replicationConfiguration": map[string]any{"rules": []any{}},
|
||||
}, decoded)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDescribeRegistry_ScopedToCaller(t *testing.T) {
|
||||
a := describeRegistryWire(t, "111111111111", nil)
|
||||
b := describeRegistryWire(t, "222222222222", nil)
|
||||
assert.Equal(t, "111111111111", a["registryId"])
|
||||
assert.Equal(t, "222222222222", b["registryId"])
|
||||
}
|
||||
|
||||
func TestDescribeRegistry_MalformedBody(t *testing.T) {
|
||||
for _, body := range []string{"{", "[]", `"x"`} {
|
||||
t.Run(body, func(t *testing.T) {
|
||||
out, err := gateway_ecrapi.DescribeRegistry(context.Background(), nil, "123456789012", []byte(body))
|
||||
assert.Nil(t, out)
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, awserrors.ValidErrorCodeFromError(gateway_ecrapi.MalformedBodyError()),
|
||||
awserrors.ValidErrorCodeFromError(err))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDescribeRegistry_NotStubbed(t *testing.T) {
|
||||
assert.NotContains(t, gateway_ecrapi.StubbedActionNames(), "DescribeRegistry")
|
||||
}
|
||||
Reference in New Issue
Block a user