Weldr API: allow globing in distro image type deny list
Allow globing patterns in distro-specific image type deny list of Weldr API configuration. Extend unit tests to verify simple globing patterns. Update NEWS entry. Signed-off-by: Tomas Hozza <thozza@redhat.com>
This commit is contained in:
parent
a9b676e43e
commit
0a71054d86
3 changed files with 56 additions and 13 deletions
|
|
@ -1,9 +1,9 @@
|
||||||
# Weldr API: introduce the ablility to limit exposed Image Types by configuration
|
# Weldr API: introduce the ablility to limit exposed Image Types by configuration
|
||||||
|
|
||||||
Extend Weldr API to accept a map of distribution-specific lists of denied
|
Extend Weldr API to accept a map of distribution-specific lists of denied
|
||||||
image types, which should not be exposed via API. A special name `*` can be
|
image types, which should not be exposed via API. It is allowed to use
|
||||||
used to match any Distribution or any Image Type. This functionality is needed
|
globing patterns as Distribution and Image Type names. This functionality
|
||||||
to not expose image types which can't be successfully built outside
|
is needed to not expose image types which can't be successfully built outside
|
||||||
of Red Hat VPN.
|
of Red Hat VPN.
|
||||||
|
|
||||||
The list of denied Image Types is defined in `osbuild-composer` configuration,
|
The list of denied Image Types is defined in `osbuild-composer` configuration,
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/gobwas/glob"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/julienschmidt/httprouter"
|
"github.com/julienschmidt/httprouter"
|
||||||
|
|
||||||
|
|
@ -389,27 +390,40 @@ func (api *API) openImageFile(composeId uuid.UUID, compose store.Compose) (io.Re
|
||||||
// the distro-specific ImageType Denylist provided to the API from configuration.
|
// the distro-specific ImageType Denylist provided to the API from configuration.
|
||||||
// If the given ImageType is not allowed the method returns an `false`.
|
// If the given ImageType is not allowed the method returns an `false`.
|
||||||
// Otherwise `true` is returned.
|
// Otherwise `true` is returned.
|
||||||
func (api *API) isImageTypeAllowed(distroName, imageType string) bool {
|
func (api *API) isImageTypeAllowed(distroName, imageType string) (bool, error) {
|
||||||
anyImageType := "*"
|
|
||||||
anyDistro := "*"
|
|
||||||
|
|
||||||
for deniedDistro, deniedImgTypes := range api.distrosImageTypeDenylist {
|
for deniedDistro, deniedImgTypes := range api.distrosImageTypeDenylist {
|
||||||
if distroName == deniedDistro || deniedDistro == anyDistro {
|
deniedDistroPattern, err := glob.Compile(deniedDistro)
|
||||||
|
if err != nil {
|
||||||
|
// the bool return value here does not have any real meaning
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
if deniedDistroPattern.Match(distroName) {
|
||||||
for _, deniedImgType := range deniedImgTypes {
|
for _, deniedImgType := range deniedImgTypes {
|
||||||
if imageType == deniedImgType || deniedImgType == anyImageType {
|
deniedImageTypePattern, err := glob.Compile(deniedImgType)
|
||||||
return false
|
if err != nil {
|
||||||
|
// the bool return value here does not have any real meaning
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if deniedImageTypePattern.Match(imageType) {
|
||||||
|
return false, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getImageType returns the ImageType for the selected distro
|
// getImageType returns the ImageType for the selected distro
|
||||||
// This is necessary because different distros support different image types, and the image
|
// This is necessary because different distros support different image types, and the image
|
||||||
// type may have a different package set than other distros.
|
// type may have a different package set than other distros.
|
||||||
func (api *API) getImageType(distroName, imageType string) (distro.ImageType, error) {
|
func (api *API) getImageType(distroName, imageType string) (distro.ImageType, error) {
|
||||||
if !api.isImageTypeAllowed(distroName, imageType) {
|
imgAllowed, err := api.isImageTypeAllowed(distroName, imageType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while checking if image type is allowed: %v", err)
|
||||||
|
}
|
||||||
|
if !imgAllowed {
|
||||||
return nil, fmt.Errorf("image type %q for distro %q is denied by configuration", imageType, distroName)
|
return nil, fmt.Errorf("image type %q for distro %q is denied by configuration", imageType, distroName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2522,7 +2536,16 @@ func (api *API) composeTypesHandler(writer http.ResponseWriter, request *http.Re
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, format := range arch.ListImageTypes() {
|
for _, format := range arch.ListImageTypes() {
|
||||||
if !api.isImageTypeAllowed(distroName, format) {
|
imgAllowed, err := api.isImageTypeAllowed(distroName, format)
|
||||||
|
if err != nil {
|
||||||
|
errors := responseError{
|
||||||
|
ID: "InternalError",
|
||||||
|
Msg: fmt.Sprintf("Error while checking if image type is allowed: %v", err),
|
||||||
|
}
|
||||||
|
statusResponseError(writer, http.StatusInternalServerError, errors)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !imgAllowed {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
reply.Types = append(reply.Types, composeType{format, true})
|
reply.Types = append(reply.Types, composeType{format, true})
|
||||||
|
|
|
||||||
|
|
@ -1691,6 +1691,26 @@ func TestComposePOST_ImageTypeDenylist(t *testing.T) {
|
||||||
expectedComposeLocal,
|
expectedComposeLocal,
|
||||||
[]string{"build_id"},
|
[]string{"build_id"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"/api/v1/compose",
|
||||||
|
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageTypeName),
|
||||||
|
map[string][]string{fmt.Sprintf("%s*", test_distro.TestDistroName): {fmt.Sprintf("%s*", test_distro.TestImageTypeName)}},
|
||||||
|
http.StatusBadRequest,
|
||||||
|
fmt.Sprintf(`{"status":false,"errors":[{"id":"ComposeError","msg":"Failed to get compose type \"%[1]s\": image type \"%[1]s\" for distro \"%[2]s\" is denied by configuration"}]}`,
|
||||||
|
test_distro.TestImageTypeName, test_distro.TestDistro2Name),
|
||||||
|
expectedComposeLocal,
|
||||||
|
[]string{"build_id"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"/api/v1/compose",
|
||||||
|
fmt.Sprintf(`{"blueprint_name": "test","compose_type": "%s","branch": "master"}`, test_distro.TestImageType2Name),
|
||||||
|
map[string][]string{fmt.Sprintf("%s*", test_distro.TestDistroName): {fmt.Sprintf("%s*", test_distro.TestImageTypeName)}},
|
||||||
|
http.StatusBadRequest,
|
||||||
|
fmt.Sprintf(`{"status":false,"errors":[{"id":"ComposeError","msg":"Failed to get compose type \"%[1]s\": image type \"%[1]s\" for distro \"%[2]s\" is denied by configuration"}]}`,
|
||||||
|
test_distro.TestImageType2Name, test_distro.TestDistro2Name),
|
||||||
|
expectedComposeLocal,
|
||||||
|
[]string{"build_id"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
tempdir, err := ioutil.TempDir("", "weldr-tests-")
|
tempdir, err := ioutil.TempDir("", "weldr-tests-")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue