From b6cc51d369e995ccfcb90bac367f830c41027ef4 Mon Sep 17 00:00:00 2001 From: James Hewitt Date: Sun, 10 Apr 2022 18:04:31 +0100 Subject: [PATCH] Switch config format to be easier to understand Use a multiple choice instead of trying to keep it to booleans Signed-off-by: James Hewitt --- configuration/configuration.go | 42 ++++++++++++----- configuration/configuration_test.go | 37 +++++---------- docs/configuration.md | 70 ++++++++++++++++++++--------- registry/handlers/app.go | 12 ++--- 4 files changed, 101 insertions(+), 60 deletions(-) diff --git a/configuration/configuration.go b/configuration/configuration.go index 648302e6b..1dcd7c87b 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -680,6 +680,8 @@ type Validation struct { Disabled bool `yaml:"disabled,omitempty"` // Manifests configures manifest validation. Manifests ValidationManifests `yaml:"manifests,omitempty"` + // ImageIndexes configures validation of image indexes + ImageIndexes ValidationImageIndexes `yaml:"imageindexes,omitempty"` } type ValidationManifests struct { @@ -692,18 +694,38 @@ type ValidationManifests struct { // that URLs in pushed manifests must not match. Deny []string `yaml:"deny,omitempty"` } `yaml:"urls,omitempty"` - // ImageIndex configures validation of image indexes - ImageIndex ValidationManifestsImageIndex `yaml:"imageindex,omitempty"` } -type ValidationManifestsImageIndex struct { - Images struct { - // Exist validates that images referenced by indexes exist in the registry - // before the image index is accepted. - Exist *bool `yaml:"exist"` - // Platforms filters the set of platforms to validate for image existence. - Platforms []Platform `yaml:"platforms,omitempty"` - } `yaml:"images,omitempty"` +type ValidationImageIndexes struct { + // PlatformsExist configures the validation applies to the platform images included in an image index + PlatformsExist PlatformsExist `yaml:"platformsexist"` + // SelectedPlatforms filters the set of platforms to validate for image existence. + SelectedPlatforms []Platform `yaml:"selectedplatforms,omitempty"` +} + +// PlatformsExist configures the validation applies to the platform images included in an image index +// This can be all, none, or selected +type PlatformsExist string + +// UnmarshalYAML implements the yaml.Umarshaler interface +// Unmarshals a string into a PlatformsExist option, lowercasing the string and validating that it represents a +// valid option +func (platformsexist *PlatformsExist) UnmarshalYAML(unmarshal func(interface{}) error) error { + var platformsExistString string + err := unmarshal(&platformsExistString) + if err != nil { + return err + } + + platformsExistString = strings.ToLower(platformsExistString) + switch platformsExistString { + case "all", "none", "selected": + default: + return fmt.Errorf("invalid platformsexist option %s Must be one of [all, none, selected]", platformsExistString) + } + + *platformsexist = PlatformsExist(platformsExistString) + return nil } // Parse parses an input configuration yaml document into a Configuration struct diff --git a/configuration/configuration_test.go b/configuration/configuration_test.go index cce48c4eb..b62a80519 100644 --- a/configuration/configuration_test.go +++ b/configuration/configuration_test.go @@ -16,9 +16,6 @@ import ( // Hook up gocheck into the "go test" runner func Test(t *testing.T) { check.TestingT(t) } -// falseaddr is a boolean false to reference -var falseaddr = false - // configStruct is a canonical example configuration, which should map to configYamlV0_1 var configStruct = Configuration{ Version: "0.1", @@ -169,15 +166,8 @@ var configStruct = Configuration{ WriteTimeout: time.Millisecond * 10, }, Validation: Validation{ - Manifests: ValidationManifests{ - ImageIndex: ValidationManifestsImageIndex{ - Images: struct { - Exist *bool `yaml:"exist"` - Platforms []Platform `yaml:"platforms,omitempty"` - }{ - Exist: &falseaddr, - }, - }, + ImageIndexes: ValidationImageIndexes{ + PlatformsExist: "none", }, }, } @@ -237,10 +227,8 @@ redis: readtimeout: 10ms writetimeout: 10ms validation: - manifests: - imageindex: - images: - exist: false + imageindexes: + platformsexist: none ` // inmemoryConfigYamlV0_1 is a Version 0.1 yaml document specifying an inmemory @@ -271,10 +259,8 @@ http: headers: X-Content-Type-Options: [nosniff] validation: - manifests: - imageindex: - images: - exist: false + imageindexes: + platformsexist: none ` type ConfigSuite struct { @@ -367,7 +353,7 @@ func (suite *ConfigSuite) TestParseIncomplete(c *check.C) { IdleTimeout time.Duration `yaml:"idletimeout,omitempty"` } `yaml:"pool,omitempty"` }{} - suite.expectedConfig.Validation.Manifests.ImageIndex.Images.Exist = nil + suite.expectedConfig.Validation.ImageIndexes.PlatformsExist = "" // Note: this also tests that REGISTRY_STORAGE and // REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY can be used together @@ -662,11 +648,12 @@ func copyConfig(config Configuration) *Configuration { } configCopy.Redis = config.Redis - + configCopy.Validation = Validation{ - Enabled: config.Validation.Enabled, - Disabled: config.Validation.Disabled, - Manifests: config.Validation.Manifests, + Enabled: config.Validation.Enabled, + Disabled: config.Validation.Disabled, + Manifests: config.Validation.Manifests, + ImageIndexes: config.Validation.ImageIndexes, } return configCopy diff --git a/docs/configuration.md b/docs/configuration.md index ad353419c..5e7e9d3c6 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1247,16 +1247,16 @@ features. Each subsection defines such a feature with configurable behavior. ## `validation` -```none +```yaml validation: - manifests: - urls: - allow: - - ^https?://([^/]+\.)*example\.com/ - deny: - - ^https?://www\.example\.com/ + disabled: false ``` +Use these settings to configure what validation the registry performs on content. + +Validation is performed when content is uploaded to the registry. Changing these +settings will not validate content that has already been accepting into the registry. + ### `disabled` The `disabled` flag disables the other options in the `validation` @@ -1269,6 +1269,16 @@ Use the `manifests` subsection to configure validation of manifests. If #### `urls` +```yaml +validation: + manifests: + urls: + allow: + - ^https?://([^/]+\.)*example\.com/ + deny: + - ^https?://www\.example\.com/ +``` + The `allow` and `deny` options are each a list of [regular expressions](https://pkg.go.dev/regexp/syntax) that restrict the URLs in pushed manifests. @@ -1282,27 +1292,47 @@ one of the `allow` regular expressions **and** one of the following holds: 2. `deny` is set but no URLs within the manifest match any of the `deny` regular expressions. -#### `imageindex` +### `imageindexes` -##### `images` +validation: + imageindexes: + platformsexist: [All|None|Selected] + selectedplatforms: + - os: linux + architecture: amd64 -Set `exist` to false to disable validation that images exist when an image -index manifest is uploaded. +Use these settings to configure what validation the registry performs on image +index manifests uploaded to the registry. -Set `platforms` to configure the set of platforms to validate the existence of. -If a platform is included in this list and in the images contained within an index, -the registry will validate that it exists in the registry. The registry will not -validate the existence of other platform images in the index. +#### `platformsexist` -This parameter does not validate that the platforms are included in the index, -if an image index is missing one or more platform images from this array it may -still be accepted by the registry. +Set `platformexist` to `all` (the default) to validate all platform images exist. +The registry will validate that the images referenced by the index exist in the +registry before accepting the image index. + +Set `platformsexist` to `none` to disable all validation that images exist when an +image index manifest is uploaded. This allows image lists to be uploaded to the +registry without their associated images. + +Set `platformsexist` to `selected` to selectively validate the existence of platforms +within image index manifests. + +#### `selectedplatforms` + +When `platformsexist` is set to `selected`, set `selectedplatforms` to an array of +platforms to validate. If a platform is included in this the array and in the images +contained within an index, the registry will validate that the platform specific image +exists in the registry before accepting the index. The registry will not validate the +existence of platform specific images in the index that do not appear in the +`selectedplatforms` array. + +This parameter does not validate that the configured platforms are included in every +index. If an image index does not include one of the platform specific images configured +in the `selectedplatforms` array, it may still be accepted by the registry. Each platform is a map with two keys, `os` and `architecture`, as defined in the [OCI Image Index specification](https://github.com/opencontainers/image-spec/blob/main/image-index.md#image-index-property-descriptions). -If `platforms` is an empty array, all images in the index must exist. - ## Example: Development configuration You can use this simple example for local development: diff --git a/registry/handlers/app.go b/registry/handlers/app.go index fd2e18125..ccbc2c483 100644 --- a/registry/handlers/app.go +++ b/registry/handlers/app.go @@ -258,13 +258,15 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App { options = append(options, storage.ManifestURLsDenyRegexp(re)) } } - // If unset, default to true - if config.Validation.Manifests.ImageIndex.Images.Exist == nil || - *config.Validation.Manifests.ImageIndex.Images.Exist { + // Any option except "none" enables the validation + if config.Validation.ImageIndexes.PlatformsExist != "none" { options = append(options, storage.EnableValidateImageIndexImagesExist) } - for _, platform := range config.Validation.Manifests.ImageIndex.Images.Platforms { - options = append(options, storage.AddValidateImageIndexImagesExistPlatform(platform.Architecture, platform.OS)) + // If we are verifying selected image platforms, add those platforms to the options + if config.Validation.ImageIndexes.PlatformsExist == "selected" { + for _, platform := range config.Validation.ImageIndexes.SelectedPlatforms { + options = append(options, storage.AddValidateImageIndexImagesExistPlatform(platform.Architecture, platform.OS)) + } } }