Remove semver compatible flag and change pypi to an array of test cases (#21708) (#21729)

Backport (#21708)

This addresses #21707 and adds a second package test case for a
non-semver compatible version (this might be overkill though since you
could also edit the old package version to have an epoch in front and
see the error, this just seemed more flexible for the future).

Co-authored-by: KN4CK3R <admin@oldschoolhack.me>
This commit is contained in:
Wayne Starr 2022-11-09 09:02:21 -06:00 committed by GitHub
parent 995ae06a6e
commit 3c07ed0911
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 7 deletions

View File

@ -28,7 +28,7 @@ func TestPackagePyPI(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
packageName := "test-package" packageName := "test-package"
packageVersion := "1.0.1+r1234" packageVersion := "1!1.0.1+r1234"
packageAuthor := "KN4CK3R" packageAuthor := "KN4CK3R"
packageDescription := "Test Description" packageDescription := "Test Description"
@ -71,7 +71,7 @@ func TestPackagePyPI(t *testing.T) {
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0]) pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, pd.SemVer) assert.Nil(t, pd.SemVer)
assert.IsType(t, &pypi.Metadata{}, pd.Metadata) assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
assert.Equal(t, packageName, pd.Package.Name) assert.Equal(t, packageName, pd.Package.Name)
assert.Equal(t, packageVersion, pd.Version.Version) assert.Equal(t, packageVersion, pd.Version.Version)
@ -99,7 +99,7 @@ func TestPackagePyPI(t *testing.T) {
pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0]) pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0])
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, pd.SemVer) assert.Nil(t, pd.SemVer)
assert.IsType(t, &pypi.Metadata{}, pd.Metadata) assert.IsType(t, &pypi.Metadata{}, pd.Metadata)
assert.Equal(t, packageName, pd.Package.Name) assert.Equal(t, packageName, pd.Package.Name)
assert.Equal(t, packageVersion, pd.Version.Version) assert.Equal(t, packageVersion, pd.Version.Version)

View File

@ -22,9 +22,9 @@ import (
packages_service "code.gitea.io/gitea/services/packages" packages_service "code.gitea.io/gitea/services/packages"
) )
// https://www.python.org/dev/peps/pep-0503/#normalized-names // https://peps.python.org/pep-0426/#name
var normalizer = strings.NewReplacer(".", "-", "_", "-") var normalizer = strings.NewReplacer(".", "-", "_", "-")
var nameMatcher = regexp.MustCompile(`\A[a-zA-Z0-9\.\-_]+\z`) var nameMatcher = regexp.MustCompile(`\A(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\.\-_]*[a-zA-Z0-9])\z`)
// https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions // https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
var versionMatcher = regexp.MustCompile(`\Av?` + var versionMatcher = regexp.MustCompile(`\Av?` +
@ -130,7 +130,7 @@ func UploadPackageFile(ctx *context.Context) {
packageName := normalizer.Replace(ctx.Req.FormValue("name")) packageName := normalizer.Replace(ctx.Req.FormValue("name"))
packageVersion := ctx.Req.FormValue("version") packageVersion := ctx.Req.FormValue("version")
if !nameMatcher.MatchString(packageName) || !versionMatcher.MatchString(packageVersion) { if !isValidNameAndVersion(packageName, packageVersion) {
apiError(ctx, http.StatusBadRequest, "invalid name or version") apiError(ctx, http.StatusBadRequest, "invalid name or version")
return return
} }
@ -148,7 +148,7 @@ func UploadPackageFile(ctx *context.Context) {
Name: packageName, Name: packageName,
Version: packageVersion, Version: packageVersion,
}, },
SemverCompatible: true, SemverCompatible: false,
Creator: ctx.Doer, Creator: ctx.Doer,
Metadata: &pypi_module.Metadata{ Metadata: &pypi_module.Metadata{
Author: ctx.Req.FormValue("author"), Author: ctx.Req.FormValue("author"),
@ -179,3 +179,7 @@ func UploadPackageFile(ctx *context.Context) {
ctx.Status(http.StatusCreated) ctx.Status(http.StatusCreated)
} }
func isValidNameAndVersion(packageName, packageVersion string) bool {
return nameMatcher.MatchString(packageName) && versionMatcher.MatchString(packageVersion)
}

View File

@ -0,0 +1,39 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package pypi
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsValidNameAndVersion(t *testing.T) {
// The test cases below were created from the following Python PEPs:
// https://peps.python.org/pep-0426/#name
// https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
// Valid Cases
assert.True(t, isValidNameAndVersion("A", "1.0.1"))
assert.True(t, isValidNameAndVersion("Test.Name.1234", "1.0.1"))
assert.True(t, isValidNameAndVersion("test_name", "1.0.1"))
assert.True(t, isValidNameAndVersion("test-name", "1.0.1"))
assert.True(t, isValidNameAndVersion("test-name", "v1.0.1"))
assert.True(t, isValidNameAndVersion("test-name", "2012.4"))
assert.True(t, isValidNameAndVersion("test-name", "1.0.1-alpha"))
assert.True(t, isValidNameAndVersion("test-name", "1.0.1a1"))
assert.True(t, isValidNameAndVersion("test-name", "1.0b2.r345.dev456"))
assert.True(t, isValidNameAndVersion("test-name", "1!1.0.1"))
assert.True(t, isValidNameAndVersion("test-name", "1.0.1+local.1"))
// Invalid Cases
assert.False(t, isValidNameAndVersion(".test-name", "1.0.1"))
assert.False(t, isValidNameAndVersion("test!name", "1.0.1"))
assert.False(t, isValidNameAndVersion("-test-name", "1.0.1"))
assert.False(t, isValidNameAndVersion("test-name-", "1.0.1"))
assert.False(t, isValidNameAndVersion("test-name", "a1.0.1"))
assert.False(t, isValidNameAndVersion("test-name", "1.0.1aa"))
assert.False(t, isValidNameAndVersion("test-name", "1.0.0-alpha.beta"))
}