refactor: drop the legacy handlers_ecr import alias

Import domains/ecr under its package name, or as ecrdomain where the
file also imports the AWS SDK ecr package, matching acmdomain. Also fix
a stale daemon file reference in the integration ECR daemon comment.
This commit is contained in:
joshsiv-mulga
2026-10-09 12:17:01 +10:00
parent 5292bd22c9
commit c3c8e28f86
30 changed files with 189 additions and 189 deletions
+1 -1
View File
@@ -393,7 +393,7 @@ These residuals were recorded by individual slices and must be resolved once the
- `domains/dns`: imports `runtime/compute/vm` (domain-to-runtime), `domains/network/reconcile` for the reconcile lock and `bootstrap/config` for node configuration.
- ACM: the IAM AES-GCM helper import (ACM relocation residual).
- `runtime/roles/awsgw`: the quota reconcile loop belongs to `domains/admission/quota`, and the EKS token-verify responder belongs with STS or EKS identity.
- ECR control-plane registration: `awsapi.Deps.NATS` is a raw `*nats.Conn`, not a narrow capability. Every NATS-backed `Handler` passes it to `handlers_ecr.NewNATSMetaStore`, which calls `natsmsg.NATSRequest`, so narrowing it means changing the exported `Handler` type, every handler and the meta store; it must not be broadened further meanwhile.
- ECR control-plane registration: `awsapi.Deps.NATS` is a raw `*nats.Conn`, not a narrow capability. Every NATS-backed `Handler` passes it to `domains/ecr.NewNATSMetaStore`, which calls `natsmsg.NATSRequest`, so narrowing it means changing the exported `Handler` type, every handler and the meta store; it must not be broadened further meanwhile.
- ACM control-plane registration: `domains/acm/awsapi.Deps.NATS` (`registration.go`) is likewise a raw `*nats.Conn` carried by every `Handler`, for the same reason; it must not be broadened further meanwhile.
- `cmd/aws-model-coverage` imports `ingress/aws/dispatch`, `domains/ecr/awsapi`, `domains/acm/awsapi` and `gateway` to read ECR's and ACM's declared inventories. It is a non-serving tool and the only named exception to the ADR-0002 composition invariant; it must not construct a registration.
- Ingress pipeline (ADR-0002 phase 4): the request-audit record, the trace action enricher, the throttle key functions and the gateway request-context keys stay in `gateway` until the auth/IAM and request-context boundary is designed. SigV4 authentication writes the audit record and context keys from four places, so moving them now would export exactly the setters ADR-0002 says must not be exported solely to make a directory move possible.
+25 -25
View File
@@ -62,7 +62,7 @@ import (
ec2tags "github.com/mulgadc/spinifex/spinifex/domains/ec2/tags"
ec2volume "github.com/mulgadc/spinifex/spinifex/domains/ec2/volume"
ec2vpc "github.com/mulgadc/spinifex/spinifex/domains/ec2/vpc"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/network/external"
"github.com/mulgadc/spinifex/spinifex/domains/network/external/dhcp"
"github.com/mulgadc/spinifex/spinifex/domains/network/external/exonet"
@@ -180,7 +180,7 @@ type Daemon struct {
ochreVectorService ochrevector.VectorService
ochreAppliance *ochrevector.Appliance
ochreBackupService *ochrevector.BackupService
ecrMetaService *handlers_ecr.MetaServiceImpl
ecrMetaService *ecr.MetaServiceImpl
routeTableService *ec2routetable.RouteTableServiceImpl
natGatewayService *ec2natgw.NatGatewayServiceImpl
externalIPAM *ec2vpc.ExternalIPAM
@@ -1242,28 +1242,28 @@ func (d *Daemon) subscribeAll() error {
// JetStream KV metadata; blob/manifest bytes never traverse these subjects.
if d.ecrMetaService != nil {
subs = append(subs,
natsSub{handlers_ecr.SubjectRepoCreate, handleNATSRequest(d.node, d.ecrMetaService.RepoCreate), "spinifex-workers"},
natsSub{handlers_ecr.SubjectRepoDescribe, handleNATSRequest(d.node, d.ecrMetaService.RepoDescribe), "spinifex-workers"},
natsSub{handlers_ecr.SubjectRepoList, handleNATSRequest(d.node, d.ecrMetaService.RepoList), "spinifex-workers"},
natsSub{handlers_ecr.SubjectRepoDelete, handleNATSRequest(d.node, d.ecrMetaService.RepoDelete), "spinifex-workers"},
natsSub{handlers_ecr.SubjectPolicyPut, handleNATSRequest(d.node, d.ecrMetaService.PolicyPut), "spinifex-workers"},
natsSub{handlers_ecr.SubjectPolicyGet, handleNATSRequest(d.node, d.ecrMetaService.PolicyGet), "spinifex-workers"},
natsSub{handlers_ecr.SubjectPolicyDelete, handleNATSRequest(d.node, d.ecrMetaService.PolicyDelete), "spinifex-workers"},
natsSub{handlers_ecr.SubjectLifecyclePut, handleNATSRequest(d.node, d.ecrMetaService.LifecyclePut), "spinifex-workers"},
natsSub{handlers_ecr.SubjectLifecycleGet, handleNATSRequest(d.node, d.ecrMetaService.LifecycleGet), "spinifex-workers"},
natsSub{handlers_ecr.SubjectLifecycleDelete, handleNATSRequest(d.node, d.ecrMetaService.LifecycleDelete), "spinifex-workers"},
natsSub{handlers_ecr.SubjectTagPut, handleNATSRequest(d.node, d.ecrMetaService.TagPut), "spinifex-workers"},
natsSub{handlers_ecr.SubjectTagGet, handleNATSRequest(d.node, d.ecrMetaService.TagGet), "spinifex-workers"},
natsSub{handlers_ecr.SubjectTagList, handleNATSRequest(d.node, d.ecrMetaService.TagList), "spinifex-workers"},
natsSub{handlers_ecr.SubjectTagDelete, handleNATSRequest(d.node, d.ecrMetaService.TagDelete), "spinifex-workers"},
natsSub{handlers_ecr.SubjectManifestPut, handleNATSRequest(d.node, d.ecrMetaService.ManifestPut), "spinifex-workers"},
natsSub{handlers_ecr.SubjectManifestDescribe, handleNATSRequest(d.node, d.ecrMetaService.ManifestDescribe), "spinifex-workers"},
natsSub{handlers_ecr.SubjectManifestList, handleNATSRequest(d.node, d.ecrMetaService.ManifestList), "spinifex-workers"},
natsSub{handlers_ecr.SubjectManifestDelete, handleNATSRequest(d.node, d.ecrMetaService.ManifestDelete), "spinifex-workers"},
natsSub{handlers_ecr.SubjectUploadCreate, handleNATSRequest(d.node, d.ecrMetaService.UploadCreate), "spinifex-workers"},
natsSub{handlers_ecr.SubjectUploadGet, handleNATSRequest(d.node, d.ecrMetaService.UploadGet), "spinifex-workers"},
natsSub{handlers_ecr.SubjectUploadUpdate, handleNATSRequest(d.node, d.ecrMetaService.UploadUpdate), "spinifex-workers"},
natsSub{handlers_ecr.SubjectUploadDelete, handleNATSRequest(d.node, d.ecrMetaService.UploadDelete), "spinifex-workers"},
natsSub{ecr.SubjectRepoCreate, handleNATSRequest(d.node, d.ecrMetaService.RepoCreate), "spinifex-workers"},
natsSub{ecr.SubjectRepoDescribe, handleNATSRequest(d.node, d.ecrMetaService.RepoDescribe), "spinifex-workers"},
natsSub{ecr.SubjectRepoList, handleNATSRequest(d.node, d.ecrMetaService.RepoList), "spinifex-workers"},
natsSub{ecr.SubjectRepoDelete, handleNATSRequest(d.node, d.ecrMetaService.RepoDelete), "spinifex-workers"},
natsSub{ecr.SubjectPolicyPut, handleNATSRequest(d.node, d.ecrMetaService.PolicyPut), "spinifex-workers"},
natsSub{ecr.SubjectPolicyGet, handleNATSRequest(d.node, d.ecrMetaService.PolicyGet), "spinifex-workers"},
natsSub{ecr.SubjectPolicyDelete, handleNATSRequest(d.node, d.ecrMetaService.PolicyDelete), "spinifex-workers"},
natsSub{ecr.SubjectLifecyclePut, handleNATSRequest(d.node, d.ecrMetaService.LifecyclePut), "spinifex-workers"},
natsSub{ecr.SubjectLifecycleGet, handleNATSRequest(d.node, d.ecrMetaService.LifecycleGet), "spinifex-workers"},
natsSub{ecr.SubjectLifecycleDelete, handleNATSRequest(d.node, d.ecrMetaService.LifecycleDelete), "spinifex-workers"},
natsSub{ecr.SubjectTagPut, handleNATSRequest(d.node, d.ecrMetaService.TagPut), "spinifex-workers"},
natsSub{ecr.SubjectTagGet, handleNATSRequest(d.node, d.ecrMetaService.TagGet), "spinifex-workers"},
natsSub{ecr.SubjectTagList, handleNATSRequest(d.node, d.ecrMetaService.TagList), "spinifex-workers"},
natsSub{ecr.SubjectTagDelete, handleNATSRequest(d.node, d.ecrMetaService.TagDelete), "spinifex-workers"},
natsSub{ecr.SubjectManifestPut, handleNATSRequest(d.node, d.ecrMetaService.ManifestPut), "spinifex-workers"},
natsSub{ecr.SubjectManifestDescribe, handleNATSRequest(d.node, d.ecrMetaService.ManifestDescribe), "spinifex-workers"},
natsSub{ecr.SubjectManifestList, handleNATSRequest(d.node, d.ecrMetaService.ManifestList), "spinifex-workers"},
natsSub{ecr.SubjectManifestDelete, handleNATSRequest(d.node, d.ecrMetaService.ManifestDelete), "spinifex-workers"},
natsSub{ecr.SubjectUploadCreate, handleNATSRequest(d.node, d.ecrMetaService.UploadCreate), "spinifex-workers"},
natsSub{ecr.SubjectUploadGet, handleNATSRequest(d.node, d.ecrMetaService.UploadGet), "spinifex-workers"},
natsSub{ecr.SubjectUploadUpdate, handleNATSRequest(d.node, d.ecrMetaService.UploadUpdate), "spinifex-workers"},
natsSub{ecr.SubjectUploadDelete, handleNATSRequest(d.node, d.ecrMetaService.UploadDelete), "spinifex-workers"},
)
}
@@ -2203,7 +2203,7 @@ func (d *Daemon) startCluster() error {
if js, jsErr := jetstream.New(d.natsConn); jsErr != nil {
slog.Warn("ECR metadata service disabled: JetStream unavailable", "err", jsErr)
} else {
d.ecrMetaService = handlers_ecr.NewKVMetaService(js)
d.ecrMetaService = ecr.NewKVMetaService(js)
}
if err := d.eksService.SpawnRegisteredReconcilers(); err != nil {
@@ -9,7 +9,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
)
@@ -68,12 +68,12 @@ func CreateRepository(ctx context.Context, store RepositoryStore, endpoint Repos
if _, err := store.GetRepo(ctx, accountID, req.RepositoryName); err == nil {
return nil, RepositoryAlreadyExistsError(accountID, req.RepositoryName)
} else if !errors.Is(err, handlers_ecr.ErrNotFound) {
} else if !errors.Is(err, ecrdomain.ErrNotFound) {
slog.ErrorContext(ctx, "ECR CreateRepository: get repository failed", "repository", req.RepositoryName, "err", err)
return nil, errors.New(awserrors.ErrorServerInternal)
}
meta := handlers_ecr.RepoMeta{
meta := ecrdomain.RepoMeta{
Name: req.RepositoryName,
CreatedAt: time.Now().UTC(),
ImageTagMutability: mutability,
@@ -113,17 +113,17 @@ func tagMapFromInput(in []*ecr.Tag) (map[string]string, error) {
// customer-managed key material is implemented.
func normalizeEncryptionType(cfg *encryptionConfigurationInput) (string, error) {
if cfg == nil || cfg.EncryptionType == "" {
return handlers_ecr.EncryptionTypeAES256, nil
return ecrdomain.EncryptionTypeAES256, nil
}
switch cfg.EncryptionType {
case handlers_ecr.EncryptionTypeAES256:
case ecrdomain.EncryptionTypeAES256:
return cfg.EncryptionType, nil
case handlers_ecr.EncryptionTypeKMS:
case ecrdomain.EncryptionTypeKMS:
return "", awserrors.Errorf(awserrors.ErrorECRInvalidParameter,
"encryptionType KMS is not supported: no customer-managed key is used, and repositories are already encrypted at rest under a server-managed AES-256 key")
default:
return "", EnumValueError("encryptionConfiguration.encryptionType",
handlers_ecr.EncryptionTypeAES256, "KMS_DSSE", handlers_ecr.EncryptionTypeKMS)
ecrdomain.EncryptionTypeAES256, "KMS_DSSE", ecrdomain.EncryptionTypeKMS)
}
}
@@ -133,8 +133,8 @@ func normalizeEncryptionType(cfg *encryptionConfigurationInput) (string, error)
func normalizeTagMutability(value string) (string, error) {
switch value {
case "":
return handlers_ecr.TagMutabilityMutable, nil
case handlers_ecr.TagMutabilityMutable, handlers_ecr.TagMutabilityImmutable:
return ecrdomain.TagMutabilityMutable, nil
case ecrdomain.TagMutabilityMutable, ecrdomain.TagMutabilityImmutable:
return value, nil
default:
return "", EnumValueError("imageTagMutability", ImageTagMutabilityValues...)
@@ -4,7 +4,7 @@ import (
"context"
"testing"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -12,7 +12,7 @@ import (
func TestCreateRepository_PersistsConfiguredMetadata(t *testing.T) {
nc := newRepositoryActionTestConn(t)
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecr.NewNATSMetaStore(nc)
body := []byte(`{"repositoryName":"team/app","imageTagMutability":"IMMUTABLE","tags":[{"Key":"environment","Value":"test"}],"imageScanningConfiguration":{"scanOnPush":true}}`)
out, err := CreateRepository(context.Background(), store, repositoryActionEndpoint(), repositoryActionTestAccount, body)
@@ -24,14 +24,14 @@ func TestCreateRepository_PersistsConfiguredMetadata(t *testing.T) {
meta, err := store.GetRepo(context.Background(), repositoryActionTestAccount, "team/app")
require.NoError(t, err)
assert.Equal(t, handlers_ecr.TagMutabilityImmutable, meta.ImageTagMutability)
assert.Equal(t, ecr.TagMutabilityImmutable, meta.ImageTagMutability)
assert.Equal(t, map[string]string{"environment": "test"}, meta.Tags)
assert.True(t, meta.ScanOnPush)
}
func TestCreateRepository_RejectsInvalidRequestsAndDuplicates(t *testing.T) {
nc := newRepositoryActionTestConn(t)
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecr.NewNATSMetaStore(nc)
_, err := CreateRepository(context.Background(), store, repositoryActionEndpoint(), repositoryActionTestAccount, []byte(`{"repositoryName":"team/app"}`))
require.NoError(t, err)
@@ -7,7 +7,7 @@ import (
"log/slog"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
)
@@ -40,7 +40,7 @@ func DeleteRepository(ctx context.Context, store RepositoryStore, endpoint Repos
meta, err := store.GetRepo(ctx, accountID, req.RepositoryName)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return nil, RepositoryNotFoundError(accountID, req.RepositoryName)
}
slog.ErrorContext(ctx, "ECR DeleteRepository: get repository failed", "repository", req.RepositoryName, "err", err)
@@ -59,7 +59,7 @@ func DeleteRepository(ctx context.Context, store RepositoryStore, endpoint Repos
}
if err := store.DeleteRepo(ctx, accountID, req.RepositoryName); err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return nil, RepositoryNotFoundError(accountID, req.RepositoryName)
}
slog.ErrorContext(ctx, "ECR DeleteRepository: delete repository failed", "repository", req.RepositoryName, "err", err)
@@ -6,7 +6,7 @@ import (
"testing"
"time"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -14,7 +14,7 @@ import (
func TestDeleteRepository_RemovesEmptyRepository(t *testing.T) {
nc := newRepositoryActionTestConn(t)
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecr.NewNATSMetaStore(nc)
seedRepositoryForAction(t, nc, "team/app")
out, err := DeleteRepository(context.Background(), store, repositoryActionEndpoint(), repositoryActionTestAccount, []byte(`{"repositoryName":"team/app"}`))
@@ -23,14 +23,14 @@ func TestDeleteRepository_RemovesEmptyRepository(t *testing.T) {
assert.Equal(t, "team/app", *out.Repository.RepositoryName)
_, err = store.GetRepo(context.Background(), repositoryActionTestAccount, "team/app")
require.ErrorIs(t, err, handlers_ecr.ErrNotFound)
require.ErrorIs(t, err, ecr.ErrNotFound)
}
func TestDeleteRepository_ProtectsNonEmptyRepositoryUnlessForced(t *testing.T) {
nc := newRepositoryActionTestConn(t)
seedRepositoryForAction(t, nc, "team/app")
store := handlers_ecr.NewNATSMetaStore(nc)
require.NoError(t, store.PutManifestMeta(context.Background(), repositoryActionTestAccount, "team/app", handlers_ecr.ManifestMeta{
store := ecr.NewNATSMetaStore(nc)
require.NoError(t, store.PutManifestMeta(context.Background(), repositoryActionTestAccount, "team/app", ecr.ManifestMeta{
Digest: "sha256:" + strings.Repeat("a", 64), MediaType: "application/json", Size: 7, PushedAt: time.Now(),
}))
@@ -45,7 +45,7 @@ func TestDeleteRepository_ProtectsNonEmptyRepositoryUnlessForced(t *testing.T) {
func TestDeleteRepository_ValidatesRequest(t *testing.T) {
nc := newRepositoryActionTestConn(t)
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecr.NewNATSMetaStore(nc)
cases := []struct {
name string
body string
@@ -7,7 +7,7 @@ import (
"log/slog"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
)
@@ -54,7 +54,7 @@ func DescribeRepositories(ctx context.Context, store RepositoryStore, endpoint R
for _, name := range names {
meta, err := store.GetRepo(ctx, accountID, name)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return nil, RepositoryNotFoundError(accountID, name)
}
slog.ErrorContext(ctx, "ECR DescribeRepositories: get repository failed", "repository", name, "err", err)
@@ -4,7 +4,7 @@ import (
"context"
"testing"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -12,7 +12,7 @@ import (
func TestDescribeRepositories_ListsAccountScoped(t *testing.T) {
nc := newRepositoryActionTestConn(t)
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecr.NewNATSMetaStore(nc)
seedRepositoryForAction(t, nc, "team/app")
seedRepositoryForAction(t, nc, "team/web")
@@ -32,7 +32,7 @@ func TestDescribeRepositories_ListsAccountScoped(t *testing.T) {
func TestDescribeRepositories_ValidatesRequestAndRepository(t *testing.T) {
nc := newRepositoryActionTestConn(t)
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecr.NewNATSMetaStore(nc)
seedRepositoryForAction(t, nc, "team/app")
cases := []struct {
+2 -2
View File
@@ -5,7 +5,7 @@ import (
"errors"
"log/slog"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrregistry "github.com/mulgadc/spinifex/spinifex/domains/ecr/registry"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
)
@@ -56,7 +56,7 @@ func listImageRecords(ctx context.Context, catalog ImageCatalog, accountID, repo
return nil, errors.New(awserrors.ErrorServerInternal)
}
records, err := catalog.ListImages(ctx, accountID, repository)
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecr.ErrNotFound) {
return nil, RepositoryNotFoundError(accountID, repository)
}
if err != nil {
+3 -3
View File
@@ -7,7 +7,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/nats-io/nats.go"
)
@@ -47,10 +47,10 @@ func PutImageScanningConfiguration(ctx context.Context, nc *nats.Conn, accountID
return nil, errors.New(awserrors.ErrorOperationNotSupported)
}
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecrdomain.NewNATSMetaStore(nc)
meta, err := store.GetRepo(ctx, accountID, req.RepositoryName)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return nil, RepositoryNotFoundError(accountID, req.RepositoryName)
}
return nil, err
@@ -8,7 +8,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
)
@@ -23,7 +23,7 @@ type LifecyclePolicyStore interface {
type LifecyclePreview struct {
RepositoryName string
LifecyclePolicyText string
Expiries []handlers_ecr.LifecycleExpiry
Expiries []ecrdomain.LifecycleExpiry
}
// lifecyclePreviewRequest is the camelCase AWS JSON 1.1 input shared by the
@@ -55,7 +55,7 @@ func EvaluateLifecyclePreview(ctx context.Context, policies LifecyclePolicyStore
if policyText == "" {
stored, err := policies.GetLifecyclePolicy(ctx, accountID, req.RepositoryName)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return LifecyclePreview{}, LifecyclePolicyNotFoundError(accountID, req.RepositoryName)
}
return LifecyclePreview{}, err
@@ -67,14 +67,14 @@ func EvaluateLifecyclePreview(ctx context.Context, policies LifecyclePolicyStore
if err != nil {
return LifecyclePreview{}, err
}
images := make([]handlers_ecr.LifecycleImage, 0, len(records))
images := make([]ecrdomain.LifecycleImage, 0, len(records))
for _, record := range records {
images = append(images, handlers_ecr.LifecycleImage{
images = append(images, ecrdomain.LifecycleImage{
Digest: record.Digest, Tags: record.Tags, PushedAt: record.PushedAt,
})
}
expiries, err := handlers_ecr.EvaluateLifecyclePolicy([]byte(policyText), images, time.Now().UTC())
expiries, err := ecrdomain.EvaluateLifecyclePolicy([]byte(policyText), images, time.Now().UTC())
if err != nil {
return LifecyclePreview{}, InvalidLifecyclePolicyError()
}
@@ -7,7 +7,7 @@ import (
"time"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrregistry "github.com/mulgadc/spinifex/spinifex/domains/ecr/registry"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/stretchr/testify/assert"
@@ -68,8 +68,8 @@ func TestEvaluateLifecyclePreview_MapsPolicyAndRepositoryFailures(t *testing.T)
body string
code string
}{
{"missing policy", fakeLifecyclePolicyStore{err: handlers_ecr.ErrNotFound}, fakeImageCatalog{}, `{"repositoryName":"team/app"}`, awserrors.ErrorLifecyclePolicyNotFound},
{"missing repository", fakeLifecyclePolicyStore{}, fakeImageCatalog{err: handlers_ecr.ErrNotFound}, `{"repositoryName":"team/app","lifecyclePolicyText":"{}"}`, awserrors.ErrorRepositoryNotFound},
{"missing policy", fakeLifecyclePolicyStore{err: ecrdomain.ErrNotFound}, fakeImageCatalog{}, `{"repositoryName":"team/app"}`, awserrors.ErrorLifecyclePolicyNotFound},
{"missing repository", fakeLifecyclePolicyStore{}, fakeImageCatalog{err: ecrdomain.ErrNotFound}, `{"repositoryName":"team/app","lifecyclePolicyText":"{}"}`, awserrors.ErrorRepositoryNotFound},
{"invalid policy", fakeLifecyclePolicyStore{}, fakeImageCatalog{}, `{"repositoryName":"team/app","lifecyclePolicyText":"not-json"}`, awserrors.ErrorECRInvalidParameter},
}
for _, tc := range cases {
@@ -9,7 +9,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/nats-io/nats.go"
)
@@ -39,7 +39,7 @@ func compactPolicyText(text []byte) string {
// resolveLifecycleRepo parses + validates the request, enforces the registryId
// cross-account guard, and confirms the repository exists.
func resolveLifecycleRepo(ctx context.Context, nc *nats.Conn, accountID string, body []byte) (lifecyclePolicyRequest, *handlers_ecr.NATSMetaStore, error) {
func resolveLifecycleRepo(ctx context.Context, nc *nats.Conn, accountID string, body []byte) (lifecyclePolicyRequest, *ecrdomain.NATSMetaStore, error) {
var req lifecyclePolicyRequest
if len(body) > 0 {
if err := json.Unmarshal(body, &req); err != nil {
@@ -53,9 +53,9 @@ func resolveLifecycleRepo(ctx context.Context, nc *nats.Conn, accountID string,
return req, nil, errors.New(awserrors.ErrorAccessDenied)
}
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecrdomain.NewNATSMetaStore(nc)
if _, err := store.GetRepo(ctx, accountID, req.RepositoryName); err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return req, nil, RepositoryNotFoundError(accountID, req.RepositoryName)
}
return req, nil, err
@@ -71,7 +71,7 @@ func PutLifecyclePolicy(ctx context.Context, nc *nats.Conn, accountID string, bo
if err != nil {
return nil, err
}
if _, err := handlers_ecr.ParseLifecyclePolicy([]byte(req.LifecyclePolicyText)); err != nil {
if _, err := ecrdomain.ParseLifecyclePolicy([]byte(req.LifecyclePolicyText)); err != nil {
return nil, InvalidLifecyclePolicyError()
}
policy := compactPolicyText([]byte(req.LifecyclePolicyText))
@@ -94,7 +94,7 @@ func GetLifecyclePolicy(ctx context.Context, nc *nats.Conn, accountID string, bo
}
policy, err := store.GetLifecyclePolicy(ctx, accountID, req.RepositoryName)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return nil, LifecyclePolicyNotFoundError(accountID, req.RepositoryName)
}
return nil, err
@@ -116,7 +116,7 @@ func DeleteLifecyclePolicy(ctx context.Context, nc *nats.Conn, accountID string,
}
policy, err := store.DeleteLifecyclePolicy(ctx, accountID, req.RepositoryName)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return nil, LifecyclePolicyNotFoundError(accountID, req.RepositoryName)
}
return nil, err
@@ -8,7 +8,7 @@ import (
"github.com/aws/aws-sdk-go/service/ecr"
"github.com/mulgadc/spinifex/internal/testkit"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
@@ -23,12 +23,12 @@ func newLifecycleTestConn(t *testing.T) *nats.Conn {
t.Helper()
_, nc, _ := testutil.StartTestJetStream(t)
js := testutil.NewJetStream(t, nc)
svc := handlers_ecr.NewKVMetaService(js)
serveMeta(t, nc, handlers_ecr.SubjectRepoCreate, svc.RepoCreate)
serveMeta(t, nc, handlers_ecr.SubjectRepoDescribe, svc.RepoDescribe)
serveMeta(t, nc, handlers_ecr.SubjectLifecyclePut, svc.LifecyclePut)
serveMeta(t, nc, handlers_ecr.SubjectLifecycleGet, svc.LifecycleGet)
serveMeta(t, nc, handlers_ecr.SubjectLifecycleDelete, svc.LifecycleDelete)
svc := ecrdomain.NewKVMetaService(js)
serveMeta(t, nc, ecrdomain.SubjectRepoCreate, svc.RepoCreate)
serveMeta(t, nc, ecrdomain.SubjectRepoDescribe, svc.RepoDescribe)
serveMeta(t, nc, ecrdomain.SubjectLifecyclePut, svc.LifecyclePut)
serveMeta(t, nc, ecrdomain.SubjectLifecycleGet, svc.LifecycleGet)
serveMeta(t, nc, ecrdomain.SubjectLifecycleDelete, svc.LifecycleDelete)
return nc
}
@@ -5,7 +5,7 @@ import (
"errors"
"testing"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrregistry "github.com/mulgadc/spinifex/spinifex/domains/ecr/registry"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/stretchr/testify/assert"
@@ -52,7 +52,7 @@ func TestListImages_ValidatesRequestAndCatalogFailure(t *testing.T) {
{"malformed", fakeImageCatalog{}, `{`, awserrors.ErrorECRInvalidParameter},
{"missing repository name", fakeImageCatalog{}, `{}`, awserrors.ErrorECRInvalidParameter},
{"cross account", fakeImageCatalog{}, `{"repositoryName":"team/app","registryId":"999999999999"}`, awserrors.ErrorAccessDenied},
{"repository missing", fakeImageCatalog{err: handlers_ecr.ErrNotFound}, `{"repositoryName":"team/app"}`, awserrors.ErrorRepositoryNotFound},
{"repository missing", fakeImageCatalog{err: ecr.ErrNotFound}, `{"repositoryName":"team/app"}`, awserrors.ErrorRepositoryNotFound},
{"backend failure", fakeImageCatalog{err: errors.New("unavailable")}, `{"repositoryName":"team/app"}`, awserrors.ErrorServerInternal},
}
for _, tc := range cases {
@@ -11,7 +11,7 @@ import (
"github.com/mulgadc/bluebottle/pkg/iampolicy"
"github.com/mulgadc/bluebottle/pkg/sigv4"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrauth "github.com/mulgadc/spinifex/spinifex/domains/ecr/auth"
ecrregistry "github.com/mulgadc/spinifex/spinifex/domains/ecr/registry"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
@@ -66,9 +66,9 @@ func (b *backend) GetLifecyclePolicy(_ context.Context, _, repo string) ([]byte,
return nil, errFakeBackend
}
func (b *backend) GetRepo(_ context.Context, _, repo string) (handlers_ecr.RepoMeta, error) {
func (b *backend) GetRepo(_ context.Context, _, repo string) (ecr.RepoMeta, error) {
b.use(repo)
return handlers_ecr.RepoMeta{}, errFakeBackend
return ecr.RepoMeta{}, errFakeBackend
}
func (b *backend) ListRepos(context.Context, string) ([]string, error) {
@@ -76,7 +76,7 @@ func (b *backend) ListRepos(context.Context, string) ([]string, error) {
return nil, errFakeBackend
}
func (b *backend) PutRepo(_ context.Context, _ string, meta handlers_ecr.RepoMeta) error {
func (b *backend) PutRepo(_ context.Context, _ string, meta ecr.RepoMeta) error {
b.use(meta.Name)
return errFakeBackend
}
@@ -9,7 +9,7 @@ import (
"time"
"github.com/mulgadc/spinifex/internal/testkit"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/require"
)
@@ -25,13 +25,13 @@ func newRepositoryActionTestConn(t *testing.T) *nats.Conn {
t.Helper()
_, nc, _ := testutil.StartTestJetStream(t)
js := testutil.NewJetStream(t, nc)
svc := handlers_ecr.NewKVMetaService(js)
serveRepositoryActionMeta(t, nc, handlers_ecr.SubjectRepoCreate, svc.RepoCreate)
serveRepositoryActionMeta(t, nc, handlers_ecr.SubjectRepoDescribe, svc.RepoDescribe)
serveRepositoryActionMeta(t, nc, handlers_ecr.SubjectRepoDelete, svc.RepoDelete)
serveRepositoryActionMeta(t, nc, handlers_ecr.SubjectRepoList, svc.RepoList)
serveRepositoryActionMeta(t, nc, handlers_ecr.SubjectManifestPut, svc.ManifestPut)
serveRepositoryActionMeta(t, nc, handlers_ecr.SubjectManifestList, svc.ManifestList)
svc := ecr.NewKVMetaService(js)
serveRepositoryActionMeta(t, nc, ecr.SubjectRepoCreate, svc.RepoCreate)
serveRepositoryActionMeta(t, nc, ecr.SubjectRepoDescribe, svc.RepoDescribe)
serveRepositoryActionMeta(t, nc, ecr.SubjectRepoDelete, svc.RepoDelete)
serveRepositoryActionMeta(t, nc, ecr.SubjectRepoList, svc.RepoList)
serveRepositoryActionMeta(t, nc, ecr.SubjectManifestPut, svc.ManifestPut)
serveRepositoryActionMeta(t, nc, ecr.SubjectManifestList, svc.ManifestList)
return nc
}
@@ -58,8 +58,8 @@ func serveRepositoryActionMeta[I any, O any](t *testing.T, nc *nats.Conn, subjec
func seedRepositoryForAction(t *testing.T, nc *nats.Conn, name string) {
t.Helper()
store := handlers_ecr.NewNATSMetaStore(nc)
require.NoError(t, store.PutRepo(context.Background(), repositoryActionTestAccount, handlers_ecr.RepoMeta{
store := ecr.NewNATSMetaStore(nc)
require.NoError(t, store.PutRepo(context.Background(), repositoryActionTestAccount, ecr.RepoMeta{
Name: name, CreatedAt: time.Now(),
}))
}
@@ -5,7 +5,7 @@ import (
"errors"
"slices"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
)
@@ -14,9 +14,9 @@ import (
// operations: this control-plane surface needs only repository records and
// their manifest inventory.
type RepositoryStore interface {
GetRepo(ctx context.Context, accountID, repo string) (handlers_ecr.RepoMeta, error)
GetRepo(ctx context.Context, accountID, repo string) (ecr.RepoMeta, error)
ListRepos(ctx context.Context, accountID string) ([]string, error)
PutRepo(ctx context.Context, accountID string, meta handlers_ecr.RepoMeta) error
PutRepo(ctx context.Context, accountID string, meta ecr.RepoMeta) error
ListManifests(ctx context.Context, accountID, repo string) ([]string, error)
DeleteRepo(ctx context.Context, accountID, repo string) error
}
@@ -7,7 +7,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/nats-io/nats.go"
)
@@ -24,7 +24,7 @@ type repoPolicyRequest struct {
// resolvePolicyRepo parses and validates the request, enforces the registryId
// cross-account guard, and confirms the repository exists. It returns the parsed
// request and the NATS-backed MetaStore for the follow-on policy operation.
func resolvePolicyRepo(ctx context.Context, nc *nats.Conn, accountID string, body []byte) (repoPolicyRequest, *handlers_ecr.NATSMetaStore, error) {
func resolvePolicyRepo(ctx context.Context, nc *nats.Conn, accountID string, body []byte) (repoPolicyRequest, *ecrdomain.NATSMetaStore, error) {
var req repoPolicyRequest
if len(body) > 0 {
if err := json.Unmarshal(body, &req); err != nil {
@@ -40,9 +40,9 @@ func resolvePolicyRepo(ctx context.Context, nc *nats.Conn, accountID string, bod
return req, nil, errors.New(awserrors.ErrorAccessDenied)
}
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecrdomain.NewNATSMetaStore(nc)
if _, err := store.GetRepo(ctx, accountID, req.RepositoryName); err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return req, nil, RepositoryNotFoundError(accountID, req.RepositoryName)
}
return req, nil, err
@@ -83,7 +83,7 @@ func GetRepositoryPolicy(ctx context.Context, nc *nats.Conn, accountID string, b
}
policy, err := store.GetRepoPolicy(ctx, accountID, req.RepositoryName)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return nil, RepositoryPolicyNotFoundError(accountID, req.RepositoryName)
}
return nil, err
@@ -104,7 +104,7 @@ func DeleteRepositoryPolicy(ctx context.Context, nc *nats.Conn, accountID string
}
policy, err := store.DeleteRepoPolicy(ctx, accountID, req.RepositoryName)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return nil, RepositoryPolicyNotFoundError(accountID, req.RepositoryName)
}
return nil, err
@@ -10,7 +10,7 @@ import (
"github.com/aws/aws-sdk-go/service/ecr"
"github.com/mulgadc/spinifex/internal/testkit"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
@@ -47,19 +47,19 @@ func newPolicyTestConn(t *testing.T) *nats.Conn {
t.Helper()
_, nc, _ := testutil.StartTestJetStream(t)
js := testutil.NewJetStream(t, nc)
svc := handlers_ecr.NewKVMetaService(js)
serveMeta(t, nc, handlers_ecr.SubjectRepoCreate, svc.RepoCreate)
serveMeta(t, nc, handlers_ecr.SubjectRepoDescribe, svc.RepoDescribe)
serveMeta(t, nc, handlers_ecr.SubjectPolicyPut, svc.PolicyPut)
serveMeta(t, nc, handlers_ecr.SubjectPolicyGet, svc.PolicyGet)
serveMeta(t, nc, handlers_ecr.SubjectPolicyDelete, svc.PolicyDelete)
svc := ecrdomain.NewKVMetaService(js)
serveMeta(t, nc, ecrdomain.SubjectRepoCreate, svc.RepoCreate)
serveMeta(t, nc, ecrdomain.SubjectRepoDescribe, svc.RepoDescribe)
serveMeta(t, nc, ecrdomain.SubjectPolicyPut, svc.PolicyPut)
serveMeta(t, nc, ecrdomain.SubjectPolicyGet, svc.PolicyGet)
serveMeta(t, nc, ecrdomain.SubjectPolicyDelete, svc.PolicyDelete)
return nc
}
func seedRepo(t *testing.T, nc *nats.Conn, repo string) {
t.Helper()
store := handlers_ecr.NewNATSMetaStore(nc)
require.NoError(t, store.PutRepo(context.Background(), policyTestAccount, handlers_ecr.RepoMeta{Name: repo, CreatedAt: time.Now()}))
store := ecrdomain.NewNATSMetaStore(nc)
require.NoError(t, store.PutRepo(context.Background(), policyTestAccount, ecrdomain.RepoMeta{Name: repo, CreatedAt: time.Now()}))
}
func TestRepositoryPolicy_Lifecycle(t *testing.T) {
@@ -8,7 +8,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/nats-io/nats.go"
)
@@ -35,17 +35,17 @@ func PutImageTagMutability(ctx context.Context, nc *nats.Conn, accountID string,
return nil, errors.New(awserrors.ErrorAccessDenied)
}
switch req.ImageTagMutability {
case handlers_ecr.TagMutabilityMutable, handlers_ecr.TagMutabilityImmutable:
case ecrdomain.TagMutabilityMutable, ecrdomain.TagMutabilityImmutable:
case "":
return nil, RequiredParameterError("imageTagMutability")
default:
return nil, EnumValueError("imageTagMutability", ImageTagMutabilityValues...)
}
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecrdomain.NewNATSMetaStore(nc)
meta, err := store.GetRepo(ctx, accountID, req.RepositoryName)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
if errors.Is(err, ecrdomain.ErrNotFound) {
return nil, RepositoryNotFoundError(accountID, req.RepositoryName)
}
slog.ErrorContext(ctx, "ECR PutImageTagMutability: get repository failed", "repository", req.RepositoryName, "err", err)
@@ -5,7 +5,7 @@ import (
"testing"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -22,9 +22,9 @@ func TestPutImageTagMutability_UpdatesRepository(t *testing.T) {
require.True(t, ok)
assert.Equal(t, "IMMUTABLE", *response.ImageTagMutability)
meta, err := handlers_ecr.NewNATSMetaStore(nc).GetRepo(context.Background(), repositoryActionTestAccount, "team/app")
meta, err := ecrdomain.NewNATSMetaStore(nc).GetRepo(context.Background(), repositoryActionTestAccount, "team/app")
require.NoError(t, err)
assert.Equal(t, handlers_ecr.TagMutabilityImmutable, meta.ImageTagMutability)
assert.Equal(t, ecrdomain.TagMutabilityImmutable, meta.ImageTagMutability)
}
func TestPutImageTagMutability_ValidatesRequest(t *testing.T) {
+8 -8
View File
@@ -9,7 +9,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/nats-io/nats.go"
)
@@ -35,21 +35,21 @@ type listTagsForResourceRequest struct {
// resolveTaggedRepo parses resourceArn and confirms the repository it names
// exists in the caller account, returning the repo name, its current meta,
// and the NATS-backed MetaStore for a follow-on read-modify-write.
func resolveTaggedRepo(ctx context.Context, nc *nats.Conn, accountID, resourceArn string) (string, handlers_ecr.RepoMeta, *handlers_ecr.NATSMetaStore, error) {
func resolveTaggedRepo(ctx context.Context, nc *nats.Conn, accountID, resourceArn string) (string, ecrdomain.RepoMeta, *ecrdomain.NATSMetaStore, error) {
if resourceArn == "" {
return "", handlers_ecr.RepoMeta{}, nil, invalidResourceARNError()
return "", ecrdomain.RepoMeta{}, nil, invalidResourceARNError()
}
name, err := RepositoryNameFromResourceARN(resourceArn)
if err != nil {
return "", handlers_ecr.RepoMeta{}, nil, err
return "", ecrdomain.RepoMeta{}, nil, err
}
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecrdomain.NewNATSMetaStore(nc)
meta, err := store.GetRepo(ctx, accountID, name)
if err != nil {
if errors.Is(err, handlers_ecr.ErrNotFound) {
return "", handlers_ecr.RepoMeta{}, nil, RepositoryNotFoundError(accountID, name)
if errors.Is(err, ecrdomain.ErrNotFound) {
return "", ecrdomain.RepoMeta{}, nil, RepositoryNotFoundError(accountID, name)
}
return "", handlers_ecr.RepoMeta{}, nil, err
return "", ecrdomain.RepoMeta{}, nil, err
}
return name, meta, store, nil
}
+3 -3
View File
@@ -6,7 +6,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
)
@@ -25,8 +25,8 @@ func ValidateRepositoryName(name string) error {
return ConstraintError("repositoryName", fmt.Sprintf("must have length greater than or equal to %d", minRepositoryNameLength))
case len(name) > maxRepositoryNameLength:
return ConstraintError("repositoryName", fmt.Sprintf("must have length less than or equal to %d", maxRepositoryNameLength))
case handlers_ecr.ValidateRepoName(name) != nil:
return ConstraintError("repositoryName", "must satisfy regular expression '"+handlers_ecr.RepoNamePattern+"'")
case ecrdomain.ValidateRepoName(name) != nil:
return ConstraintError("repositoryName", "must satisfy regular expression '"+ecrdomain.RepoNamePattern+"'")
}
return nil
}
@@ -19,7 +19,7 @@ import (
"github.com/go-chi/chi/v5"
"github.com/mulgadc/bluebottle/pkg/sigv4"
"github.com/mulgadc/spinifex/internal/testkit"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
awsapi "github.com/mulgadc/spinifex/spinifex/domains/ecr/awsapi"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/mulgadc/spinifex/spinifex/foundation/telemetry"
@@ -333,9 +333,9 @@ type recordingRepoStore struct {
calls int
}
func (s *recordingRepoStore) GetRepo(context.Context, string, string) (handlers_ecr.RepoMeta, error) {
func (s *recordingRepoStore) GetRepo(context.Context, string, string) (ecr.RepoMeta, error) {
s.calls++
return handlers_ecr.RepoMeta{}, errors.New("recordingRepoStore: unexpected call")
return ecr.RepoMeta{}, errors.New("recordingRepoStore: unexpected call")
}
func (s *recordingRepoStore) ListRepos(context.Context, string) ([]string, error) {
@@ -343,7 +343,7 @@ func (s *recordingRepoStore) ListRepos(context.Context, string) ([]string, error
return nil, errors.New("recordingRepoStore: unexpected call")
}
func (s *recordingRepoStore) PutRepo(context.Context, string, handlers_ecr.RepoMeta) error {
func (s *recordingRepoStore) PutRepo(context.Context, string, ecr.RepoMeta) error {
s.calls++
return errors.New("recordingRepoStore: unexpected call")
}
@@ -10,7 +10,7 @@ import (
"time"
"github.com/mulgadc/spinifex/internal/testkit"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
awsapi "github.com/mulgadc/spinifex/spinifex/domains/ecr/awsapi"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
"github.com/nats-io/nats.go"
@@ -24,16 +24,16 @@ func newRepoLifecycleGateway(t *testing.T) (*GatewayConfig, *nats.Conn) {
t.Helper()
_, nc, _ := testutil.StartTestJetStream(t)
js := testutil.NewJetStream(t, nc)
svc := handlers_ecr.NewKVMetaService(js)
serveECRMeta(t, nc, handlers_ecr.SubjectRepoCreate, svc.RepoCreate)
serveECRMeta(t, nc, handlers_ecr.SubjectRepoDescribe, svc.RepoDescribe)
serveECRMeta(t, nc, handlers_ecr.SubjectRepoDelete, svc.RepoDelete)
serveECRMeta(t, nc, handlers_ecr.SubjectManifestPut, svc.ManifestPut)
serveECRMeta(t, nc, handlers_ecr.SubjectManifestList, svc.ManifestList)
svc := ecr.NewKVMetaService(js)
serveECRMeta(t, nc, ecr.SubjectRepoCreate, svc.RepoCreate)
serveECRMeta(t, nc, ecr.SubjectRepoDescribe, svc.RepoDescribe)
serveECRMeta(t, nc, ecr.SubjectRepoDelete, svc.RepoDelete)
serveECRMeta(t, nc, ecr.SubjectManifestPut, svc.ManifestPut)
serveECRMeta(t, nc, ecr.SubjectManifestList, svc.ManifestList)
gw := withECR(&GatewayConfig{
NATSConn: nc, Region: ecrTestRegion, InternalSuffix: ecrTestSuffix, DisableLogging: true,
IAMService: allowAllIAMService(),
}, awsapi.Deps{Repository: awsapi.NewRepositoryActionService(handlers_ecr.NewNATSMetaStore(nc), awsapi.RepositoryEndpoint{
}, awsapi.Deps{Repository: awsapi.NewRepositoryActionService(ecr.NewNATSMetaStore(nc), awsapi.RepositoryEndpoint{
Region: ecrTestRegion, ServicesDomain: ecrTestSuffix,
})})
return gw, nc
@@ -99,7 +99,7 @@ func TestCreateRepository_Tags(t *testing.T) {
_, err := createRepo(t, gw, `{"repositoryName":"team/tagged","tags":[{"Key":"env","Value":"prod"},{"Key":"team","Value":""}]}`)
require.NoError(t, err)
meta, err := handlers_ecr.NewNATSMetaStore(nc).GetRepo(context.Background(), ecrTestAccount, "team/tagged")
meta, err := ecr.NewNATSMetaStore(nc).GetRepo(context.Background(), ecrTestAccount, "team/tagged")
require.NoError(t, err)
assert.Equal(t, map[string]string{"env": "prod", "team": ""}, meta.Tags)
@@ -107,7 +107,7 @@ func TestCreateRepository_Tags(t *testing.T) {
// one written before tags were accepted here.
_, err = createRepo(t, gw, `{"repositoryName":"team/untagged"}`)
require.NoError(t, err)
meta, err = handlers_ecr.NewNATSMetaStore(nc).GetRepo(context.Background(), ecrTestAccount, "team/untagged")
meta, err = ecr.NewNATSMetaStore(nc).GetRepo(context.Background(), ecrTestAccount, "team/untagged")
require.NoError(t, err)
assert.Nil(t, meta.Tags)
@@ -258,8 +258,8 @@ func TestDeleteRepository_NotEmpty(t *testing.T) {
require.NoError(t, err)
// Seed an image (manifest) so the repo is non-empty.
store := handlers_ecr.NewNATSMetaStore(nc)
require.NoError(t, store.PutManifestMeta(context.Background(), ecrTestAccount, "team/app", handlers_ecr.ManifestMeta{
store := ecr.NewNATSMetaStore(nc)
require.NoError(t, store.PutManifestMeta(context.Background(), ecrTestAccount, "team/app", ecr.ManifestMeta{
Digest: "sha256:" + strings.Repeat("a", 64), MediaType: "application/json", Size: 7, PushedAt: time.Now(),
}))
@@ -11,7 +11,7 @@ import (
"time"
"github.com/mulgadc/spinifex/internal/testkit"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
awsapi "github.com/mulgadc/spinifex/spinifex/domains/ecr/awsapi"
"github.com/nats-io/nats.go"
"github.com/stretchr/testify/assert"
@@ -45,14 +45,14 @@ func newDescribeReposGateway(t *testing.T, repos ...string) *GatewayConfig {
t.Helper()
_, nc, _ := testutil.StartTestJetStream(t)
js := testutil.NewJetStream(t, nc)
svc := handlers_ecr.NewKVMetaService(js)
serveECRMeta(t, nc, handlers_ecr.SubjectRepoCreate, svc.RepoCreate)
serveECRMeta(t, nc, handlers_ecr.SubjectRepoDescribe, svc.RepoDescribe)
serveECRMeta(t, nc, handlers_ecr.SubjectRepoList, svc.RepoList)
svc := ecr.NewKVMetaService(js)
serveECRMeta(t, nc, ecr.SubjectRepoCreate, svc.RepoCreate)
serveECRMeta(t, nc, ecr.SubjectRepoDescribe, svc.RepoDescribe)
serveECRMeta(t, nc, ecr.SubjectRepoList, svc.RepoList)
store := handlers_ecr.NewNATSMetaStore(nc)
store := ecr.NewNATSMetaStore(nc)
for _, r := range repos {
require.NoError(t, store.PutRepo(context.Background(), ecrTestAccount, handlers_ecr.RepoMeta{Name: r, CreatedAt: time.Now()}))
require.NoError(t, store.PutRepo(context.Background(), ecrTestAccount, ecr.RepoMeta{Name: r, CreatedAt: time.Now()}))
}
return withECR(&GatewayConfig{
NATSConn: nc, Region: ecrTestRegion, InternalSuffix: ecrTestSuffix, DisableLogging: true,
+3 -3
View File
@@ -11,7 +11,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ecr"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
awsapi "github.com/mulgadc/spinifex/spinifex/domains/ecr/awsapi"
ecrregistry "github.com/mulgadc/spinifex/spinifex/domains/ecr/registry"
"github.com/mulgadc/spinifex/spinifex/foundation/aws/errors"
@@ -24,7 +24,7 @@ import (
// object store + memory meta) and its composed ECR JSON image-action service.
func newImageGateway(t *testing.T) *GatewayConfig {
t.Helper()
meta := handlers_ecr.NewMemoryMetaStore()
meta := ecrdomain.NewMemoryMetaStore()
reg := ecrregistry.NewRegistry(objectstore.NewMemoryObjectStore(), meta, ecrTestAccount)
return withECR(&GatewayConfig{
ECRRegistry: reg,
@@ -39,7 +39,7 @@ func newImageGateway(t *testing.T) *GatewayConfig {
// which require an existing repository — accept writes. Idempotent.
func seedGatewayRepo(t *testing.T, gw *GatewayConfig, repo string) {
t.Helper()
require.NoError(t, gw.ECRRegistry.Meta.PutRepo(context.Background(), ecrTestAccount, handlers_ecr.RepoMeta{Name: repo}))
require.NoError(t, gw.ECRRegistry.Meta.PutRepo(context.Background(), ecrTestAccount, ecrdomain.RepoMeta{Name: repo}))
}
// seedTaggedImage stores a layerless manifest under repo:tag, returning its
+28 -28
View File
@@ -5,16 +5,16 @@ package integration
import (
"testing"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/mulgadc/spinifex/spinifex/domains/ecr"
"github.com/nats-io/nats.go"
)
// StartECRDaemonLite subscribes a real handlers_ecr.MetaServiceImpl (the same
// production service the live daemon runs, see daemon/daemon_handlers_ecr.go)
// StartECRDaemonLite subscribes a real ecr.MetaServiceImpl (the same
// production service the live daemon runs, see daemon/daemon.go)
// to every ecr.* NATS subject the gateway's ECR control-plane handlers and
// ECRRegistry.Meta dial for metadata — repos, policies, lifecycle policies,
// tags, manifest records, and in-progress upload state. It is memory-backed
// (handlers_ecr.NewMemoryMetaStore) rather than JetStream-KV-backed, matching
// (ecr.NewMemoryMetaStore) rather than JetStream-KV-backed, matching
// DaemonLite's in-scope resources.
//
// Blob and manifest bytes never travel these subjects (ECRRegistry.Store
@@ -25,39 +25,39 @@ import (
// GetAuthorizationToken: StartGateway wires ECRRegistry.Meta as a NATS client
// with no responder until this runs, so an early call times out after 30s
// rather than failing fast.
func StartECRDaemonLite(t *testing.T, gw *Gateway) *handlers_ecr.MetaServiceImpl {
func StartECRDaemonLite(t *testing.T, gw *Gateway) *ecr.MetaServiceImpl {
t.Helper()
svc := handlers_ecr.NewMetaServiceImpl(handlers_ecr.NewMemoryMetaStore())
svc := ecr.NewMetaServiceImpl(ecr.NewMemoryMetaStore())
nc := gw.NATSConn
sub(t, nc, handlers_ecr.SubjectRepoCreate, func(m *nats.Msg) { dispatch(m, svc.RepoCreate) })
sub(t, nc, handlers_ecr.SubjectRepoDescribe, func(m *nats.Msg) { dispatch(m, svc.RepoDescribe) })
sub(t, nc, handlers_ecr.SubjectRepoList, func(m *nats.Msg) { dispatch(m, svc.RepoList) })
sub(t, nc, handlers_ecr.SubjectRepoDelete, func(m *nats.Msg) { dispatch(m, svc.RepoDelete) })
sub(t, nc, ecr.SubjectRepoCreate, func(m *nats.Msg) { dispatch(m, svc.RepoCreate) })
sub(t, nc, ecr.SubjectRepoDescribe, func(m *nats.Msg) { dispatch(m, svc.RepoDescribe) })
sub(t, nc, ecr.SubjectRepoList, func(m *nats.Msg) { dispatch(m, svc.RepoList) })
sub(t, nc, ecr.SubjectRepoDelete, func(m *nats.Msg) { dispatch(m, svc.RepoDelete) })
sub(t, nc, handlers_ecr.SubjectPolicyPut, func(m *nats.Msg) { dispatch(m, svc.PolicyPut) })
sub(t, nc, handlers_ecr.SubjectPolicyGet, func(m *nats.Msg) { dispatch(m, svc.PolicyGet) })
sub(t, nc, handlers_ecr.SubjectPolicyDelete, func(m *nats.Msg) { dispatch(m, svc.PolicyDelete) })
sub(t, nc, ecr.SubjectPolicyPut, func(m *nats.Msg) { dispatch(m, svc.PolicyPut) })
sub(t, nc, ecr.SubjectPolicyGet, func(m *nats.Msg) { dispatch(m, svc.PolicyGet) })
sub(t, nc, ecr.SubjectPolicyDelete, func(m *nats.Msg) { dispatch(m, svc.PolicyDelete) })
sub(t, nc, handlers_ecr.SubjectLifecyclePut, func(m *nats.Msg) { dispatch(m, svc.LifecyclePut) })
sub(t, nc, handlers_ecr.SubjectLifecycleGet, func(m *nats.Msg) { dispatch(m, svc.LifecycleGet) })
sub(t, nc, handlers_ecr.SubjectLifecycleDelete, func(m *nats.Msg) { dispatch(m, svc.LifecycleDelete) })
sub(t, nc, ecr.SubjectLifecyclePut, func(m *nats.Msg) { dispatch(m, svc.LifecyclePut) })
sub(t, nc, ecr.SubjectLifecycleGet, func(m *nats.Msg) { dispatch(m, svc.LifecycleGet) })
sub(t, nc, ecr.SubjectLifecycleDelete, func(m *nats.Msg) { dispatch(m, svc.LifecycleDelete) })
sub(t, nc, handlers_ecr.SubjectTagPut, func(m *nats.Msg) { dispatch(m, svc.TagPut) })
sub(t, nc, handlers_ecr.SubjectTagGet, func(m *nats.Msg) { dispatch(m, svc.TagGet) })
sub(t, nc, handlers_ecr.SubjectTagList, func(m *nats.Msg) { dispatch(m, svc.TagList) })
sub(t, nc, handlers_ecr.SubjectTagDelete, func(m *nats.Msg) { dispatch(m, svc.TagDelete) })
sub(t, nc, ecr.SubjectTagPut, func(m *nats.Msg) { dispatch(m, svc.TagPut) })
sub(t, nc, ecr.SubjectTagGet, func(m *nats.Msg) { dispatch(m, svc.TagGet) })
sub(t, nc, ecr.SubjectTagList, func(m *nats.Msg) { dispatch(m, svc.TagList) })
sub(t, nc, ecr.SubjectTagDelete, func(m *nats.Msg) { dispatch(m, svc.TagDelete) })
sub(t, nc, handlers_ecr.SubjectManifestPut, func(m *nats.Msg) { dispatch(m, svc.ManifestPut) })
sub(t, nc, handlers_ecr.SubjectManifestDescribe, func(m *nats.Msg) { dispatch(m, svc.ManifestDescribe) })
sub(t, nc, handlers_ecr.SubjectManifestList, func(m *nats.Msg) { dispatch(m, svc.ManifestList) })
sub(t, nc, handlers_ecr.SubjectManifestDelete, func(m *nats.Msg) { dispatch(m, svc.ManifestDelete) })
sub(t, nc, ecr.SubjectManifestPut, func(m *nats.Msg) { dispatch(m, svc.ManifestPut) })
sub(t, nc, ecr.SubjectManifestDescribe, func(m *nats.Msg) { dispatch(m, svc.ManifestDescribe) })
sub(t, nc, ecr.SubjectManifestList, func(m *nats.Msg) { dispatch(m, svc.ManifestList) })
sub(t, nc, ecr.SubjectManifestDelete, func(m *nats.Msg) { dispatch(m, svc.ManifestDelete) })
sub(t, nc, handlers_ecr.SubjectUploadCreate, func(m *nats.Msg) { dispatch(m, svc.UploadCreate) })
sub(t, nc, handlers_ecr.SubjectUploadGet, func(m *nats.Msg) { dispatch(m, svc.UploadGet) })
sub(t, nc, handlers_ecr.SubjectUploadUpdate, func(m *nats.Msg) { dispatch(m, svc.UploadUpdate) })
sub(t, nc, handlers_ecr.SubjectUploadDelete, func(m *nats.Msg) { dispatch(m, svc.UploadDelete) })
sub(t, nc, ecr.SubjectUploadCreate, func(m *nats.Msg) { dispatch(m, svc.UploadCreate) })
sub(t, nc, ecr.SubjectUploadGet, func(m *nats.Msg) { dispatch(m, svc.UploadGet) })
sub(t, nc, ecr.SubjectUploadUpdate, func(m *nats.Msg) { dispatch(m, svc.UploadUpdate) })
sub(t, nc, ecr.SubjectUploadDelete, func(m *nats.Msg) { dispatch(m, svc.UploadDelete) })
return svc
}
+2 -2
View File
@@ -35,7 +35,7 @@ import (
"github.com/aws/aws-sdk-go/service/sts"
clusterv1 "github.com/mulgadc/spinifex/contracts/cluster/v1"
acmawsapi "github.com/mulgadc/spinifex/spinifex/domains/acm/awsapi"
handlers_ecr "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrdomain "github.com/mulgadc/spinifex/spinifex/domains/ecr"
ecrauth "github.com/mulgadc/spinifex/spinifex/domains/ecr/auth"
awsapi "github.com/mulgadc/spinifex/spinifex/domains/ecr/awsapi"
ecrregistry "github.com/mulgadc/spinifex/spinifex/domains/ecr/registry"
@@ -169,7 +169,7 @@ func startGateway(t *testing.T, collector *conformanceCollector, opts ...Option)
// ECR's control plane is composed as the awsgw role composes it, sharing
// the OCI registry, meta store and token issuer the /v2 data plane uses.
ecrMeta := handlers_ecr.NewNATSMetaStore(nc)
ecrMeta := ecrdomain.NewNATSMetaStore(nc)
ecrRegistry := ecrregistry.NewRegistry(objectstore.NewMemoryObjectStore(), ecrMeta, awsidentifiers.GlobalAccountID)
ecrIssuer := ecrauth.NewIssuer(signingKey, testECRAudience)
ecrEndpoint := awsapi.RepositoryEndpoint{Region: testRegion, ServicesDomain: testECRServicesDomain}