0
0
mirror of https://github.com/go-gitea/gitea.git synced 2026-05-14 04:20:42 +02:00

Add label for private and internal package and fix composor package source permission check

This commit is contained in:
Lunny Xiao 2026-05-07 22:21:18 -07:00
parent 29676adfd3
commit 98869ce142
9 changed files with 103 additions and 12 deletions

View File

@ -9,7 +9,9 @@ import (
"time"
packages_model "code.gitea.io/gitea/models/packages"
access_model "code.gitea.io/gitea/models/perm/access"
composer_module "code.gitea.io/gitea/modules/packages/composer"
"code.gitea.io/gitea/services/context"
)
// ServiceIndexResponse contains registry endpoints
@ -91,7 +93,7 @@ type Source struct {
Reference string `json:"reference"`
}
func createPackageMetadataResponse(registryURL string, pds []*packages_model.PackageDescriptor) *PackageMetadataResponse {
func createPackageMetadataResponse(ctx *context.Context, registryURL string, pds []*packages_model.PackageDescriptor) (*PackageMetadataResponse, error) {
versions := make([]*PackageVersionMetadata, 0, len(pds))
for _, pd := range pds {
@ -116,10 +118,17 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
},
}
if pd.Repository != nil {
pkg.Source = Source{
URL: pd.Repository.HTMLURL(),
Type: "git",
Reference: pd.Version.Version,
permission, err := access_model.GetDoerRepoPermission(ctx, pd.Repository, ctx.Doer)
if err != nil {
return nil, err
}
if permission.HasAnyUnitAccess() {
pkg.Source = Source{
URL: pd.Repository.HTMLURL(),
Type: "git",
Reference: pd.Version.Version,
}
}
}
@ -131,5 +140,5 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
Packages: map[string][]*PackageVersionMetadata{
pds[0].Package.Name: versions,
},
}
}, nil
}

View File

@ -145,10 +145,15 @@ func PackageMetadata(ctx *context.Context) {
return
}
resp := createPackageMetadataResponse(
resp, err := createPackageMetadataResponse(
ctx,
setting.AppURL+"api/packages/"+ctx.Package.Owner.Name+"/composer",
pds,
)
if err != nil {
apiError(ctx, http.StatusInternalServerError, err)
return
}
ctx.JSON(http.StatusOK, resp)
}

View File

@ -10,7 +10,13 @@
{{template "user/overview/header" .}}
{{end}}
{{template "base/alert" .}}
<p><a href="{{.PackageDescriptor.PackageWebLink}}">{{.PackageDescriptor.Package.Name}}</a> / <strong>{{ctx.Locale.Tr "repo.settings"}}</strong></p>
<p>
<a href="{{.PackageDescriptor.PackageWebLink}}">{{.PackageDescriptor.Package.Name}}</a>
<span class="label-list">
{{template "package/shared/visibility_badge" dict "Package" .PackageDescriptor.Package "Owner" .PackageDescriptor.Owner}}
</span>
/ <strong>{{ctx.Locale.Tr "repo.settings"}}</strong>
</p>
<h4 class="ui top attached header">
{{ctx.Locale.Tr "packages.settings.link"}}
</h4>

View File

@ -18,7 +18,12 @@
{{range .VersionsToRemove}}
<tr>
<td>{{.Package.Type.Name}}</td>
<td>{{.Package.Name}}</td>
<td>
{{.Package.Name}}
<span class="label-list">
{{template "package/shared/visibility_badge" dict "Package" .Package "Owner" .Owner}}
</span>
</td>
<td><a href="{{.VersionWebLink}}">{{.Version.Version}}</a></td>
<td><a href="{{.Creator.HomeLink}}">{{.Creator.Name}}</a></td>
<td>{{FileSize .CalculateBlobSize}}</td>

View File

@ -21,7 +21,10 @@
<div class="item-main">
<div class="item-title">
<a href="{{.VersionWebLink}}">{{.Package.Name}}</a>
<span class="ui label">{{svg .Package.Type.SVGName 16}} {{.Package.Type.Name}}</span>
<span class="label-list">
{{template "package/shared/visibility_badge" dict "Package" .Package "Owner" .Owner}}
<span class="ui label">{{svg .Package.Type.SVGName 16}} {{.Package.Type.Name}}</span>
</span>
</div>
<div class="item-body">
{{$timeStr := DateUtils.TimeSince .Version.CreatedUnix}}

View File

@ -1,4 +1,10 @@
<p><a href="{{.PackageDescriptor.PackageWebLink}}">{{.PackageDescriptor.Package.Name}}</a> / <strong>{{ctx.Locale.Tr "packages.versions"}}</strong></p>
<p>
<a href="{{.PackageDescriptor.PackageWebLink}}">{{.PackageDescriptor.Package.Name}}</a>
<span class="label-list">
{{template "package/shared/visibility_badge" dict "Package" .PackageDescriptor.Package "Owner" .PackageDescriptor.Owner}}
</span>
/ <strong>{{ctx.Locale.Tr "packages.versions"}}</strong>
</p>
<form class="ui form ignore-dirty">
<div class="ui small fluid action input">
{{template "shared/search/input" dict "Value" .Query "Placeholder" (ctx.Locale.Tr "search.package_kind")}}

View File

@ -1,6 +1,11 @@
<div class="issue-title-header">
{{$packageVersionLink := print $.PackageDescriptor.PackageWebLink "/" (PathEscape .PackageDescriptor.Version.LowerVersion)}}
<h1>{{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}})</h1>
<div class="tw-flex tw-flex-wrap tw-items-center tw-gap-2">
<h1 class="tw-mb-0">{{.PackageDescriptor.Package.Name}} ({{.PackageDescriptor.Version.Version}})</h1>
<span class="label-list">
{{template "package/shared/visibility_badge" dict "Package" .PackageDescriptor.Package "Owner" .PackageDescriptor.Owner}}
</span>
</div>
<div>
{{$timeStr := DateUtils.TimeSince .PackageDescriptor.Version.CreatedUnix}}
{{if .HasRepositoryAccess}}

View File

@ -0,0 +1,7 @@
{{if .Package.IsInternal}}
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.private"}}</span>
{{else if .Owner.Visibility.IsPrivate}}
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.private"}}</span>
{{else if .Owner.Visibility.IsLimited}}
<span class="ui basic label">{{ctx.Locale.Tr "repo.desc.internal"}}</span>
{{end}}

View File

@ -27,6 +27,7 @@ func TestPackageComposer(t *testing.T) {
defer tests.PrepareTestEnv(t)()
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
otherUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5})
vendorName := "gitea"
projectName := "composer-package"
@ -243,5 +244,49 @@ func TestPackageComposer(t *testing.T) {
assert.Equal(t, repo1.HTMLURL(), pkgs[0].Source.URL)
assert.Equal(t, "git", pkgs[0].Source.Type)
assert.Equal(t, packageVersion, pkgs[0].Source.Reference)
// Private repository links remain visible to callers who can access the repository.
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
err = packages.SetRepositoryLink(t.Context(), userPkgs[0].ID, repo2.ID)
assert.NoError(t, err)
req = NewRequest(t, "GET", fmt.Sprintf("%s/p2/%s/%s.json", url, vendorName, projectName)).
AddBasicAuth(user.Name)
resp = MakeRequest(t, req, http.StatusOK)
result = DecodeJSON(t, resp, &composer.PackageMetadataResponse{})
pkgs = result.Packages[packageName]
assert.Len(t, pkgs, 1)
assert.Equal(t, repo2.HTMLURL(), pkgs[0].Source.URL)
assert.Equal(t, "git", pkgs[0].Source.Type)
assert.Equal(t, packageVersion, pkgs[0].Source.Reference)
// Callers without repository access still get the package metadata, but not the private source URL.
req = NewRequest(t, "GET", fmt.Sprintf("%s/p2/%s/%s.json", url, vendorName, projectName)).
AddBasicAuth(otherUser.Name)
resp = MakeRequest(t, req, http.StatusOK)
result = DecodeJSON(t, resp, &composer.PackageMetadataResponse{})
pkgs = result.Packages[packageName]
assert.Len(t, pkgs, 1)
assert.Empty(t, pkgs[0].Source.URL)
assert.Empty(t, pkgs[0].Source.Type)
assert.Empty(t, pkgs[0].Source.Reference)
})
t.Run("WebVisibilityBadge", func(t *testing.T) {
defer tests.PrintCurrentTest(t)()
listReq := NewRequest(t, "GET", fmt.Sprintf("/%s/-/packages", user.Name)).
AddBasicAuth(user.Name)
listResp := MakeRequest(t, listReq, http.StatusOK)
listDoc := NewHTMLParser(t, bytes.NewReader(listResp.Body.Bytes()))
assert.Equal(t, 0, listDoc.Find(".item-title .ui.basic.label").Length())
viewReq := NewRequest(t, "GET", fmt.Sprintf("/%s/-/packages/composer/%s/%s", user.Name, neturl.PathEscape(packageName), neturl.PathEscape(packageVersion))).
AddBasicAuth(user.Name)
viewResp := MakeRequest(t, viewReq, http.StatusOK)
viewDoc := NewHTMLParser(t, bytes.NewReader(viewResp.Body.Bytes()))
assert.Equal(t, 0, viewDoc.Find(".issue-title-header .ui.basic.label").Length())
})
}