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:
Tomas Hozza 2021-08-02 14:15:45 +02:00 committed by Ondřej Budai
parent a9b676e43e
commit 0a71054d86
3 changed files with 56 additions and 13 deletions

View file

@ -1,9 +1,9 @@
# 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
image types, which should not be exposed via API. A special name `*` can be
used to match any Distribution or any Image Type. This functionality is needed
to not expose image types which can't be successfully built outside
image types, which should not be exposed via API. It is allowed to use
globing patterns as Distribution and Image Type names. This functionality
is needed to not expose image types which can't be successfully built outside
of Red Hat VPN.
The list of denied Image Types is defined in `osbuild-composer` configuration,

View file

@ -24,6 +24,7 @@ import (
"time"
"github.com/BurntSushi/toml"
"github.com/gobwas/glob"
"github.com/google/uuid"
"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.
// If the given ImageType is not allowed the method returns an `false`.
// Otherwise `true` is returned.
func (api *API) isImageTypeAllowed(distroName, imageType string) bool {
anyImageType := "*"
anyDistro := "*"
func (api *API) isImageTypeAllowed(distroName, imageType string) (bool, error) {
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 {
if imageType == deniedImgType || deniedImgType == anyImageType {
return false
deniedImageTypePattern, err := glob.Compile(deniedImgType)
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
// This is necessary because different distros support different image types, and the image
// type may have a different package set than other distros.
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)
}
@ -2522,7 +2536,16 @@ func (api *API) composeTypesHandler(writer http.ResponseWriter, request *http.Re
}
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
}
reply.Types = append(reply.Types, composeType{format, true})

View file

@ -1691,6 +1691,26 @@ func TestComposePOST_ImageTypeDenylist(t *testing.T) {
expectedComposeLocal,
[]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-")