From a860b3e101293e8f398d34813a97ecc30f9dfdf8 Mon Sep 17 00:00:00 2001 From: Aiden Scandella Date: Fri, 29 Nov 2024 11:18:21 -0800 Subject: [PATCH 01/13] WIP --- models/auth/access_token_scope.go | 17 +++++++++++++++-- models/auth/access_token_scope_test.go | 6 +++--- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/models/auth/access_token_scope.go b/models/auth/access_token_scope.go index 897ff3fc9ee3d..c0d6ef140ff3d 100644 --- a/models/auth/access_token_scope.go +++ b/models/auth/access_token_scope.go @@ -23,6 +23,7 @@ const ( AccessTokenScopeCategoryIssue AccessTokenScopeCategoryRepository AccessTokenScopeCategoryUser + AccessTokenScopeCategoryCommitStatus ) // AllAccessTokenScopeCategories contains all access token scope categories @@ -36,6 +37,7 @@ var AllAccessTokenScopeCategories = []AccessTokenScopeCategory{ AccessTokenScopeCategoryIssue, AccessTokenScopeCategoryRepository, AccessTokenScopeCategoryUser, + AccessTokenScopeCategoryCommitStatus, } // AccessTokenScopeLevel represents the access levels without a given scope category @@ -81,6 +83,9 @@ const ( AccessTokenScopeReadUser AccessTokenScope = "read:user" AccessTokenScopeWriteUser AccessTokenScope = "write:user" + + AccessTokenScopeReadCommitStatus AccessTokenScope = "read:commitstatus" + AccessTokenScopeWriteCommitStatus AccessTokenScope = "write:commitstatus" ) // accessTokenScopeBitmap represents a bitmap of access token scopes. @@ -92,7 +97,7 @@ const ( accessTokenScopeAllBits accessTokenScopeBitmap = accessTokenScopeWriteActivityPubBits | accessTokenScopeWriteAdminBits | accessTokenScopeWriteMiscBits | accessTokenScopeWriteNotificationBits | accessTokenScopeWriteOrganizationBits | accessTokenScopeWritePackageBits | accessTokenScopeWriteIssueBits | - accessTokenScopeWriteRepositoryBits | accessTokenScopeWriteUserBits + accessTokenScopeWriteRepositoryBits | accessTokenScopeWriteUserBits | accessTokenScopeWriteCommitStatusBits accessTokenScopePublicOnlyBits accessTokenScopeBitmap = 1 << iota @@ -123,6 +128,9 @@ const ( accessTokenScopeReadUserBits accessTokenScopeBitmap = 1 << iota accessTokenScopeWriteUserBits accessTokenScopeBitmap = 1< 64 scopes, // refactoring the whole implementation in this file (and only this file) is needed. @@ -141,6 +149,7 @@ var allAccessTokenScopes = []AccessTokenScope{ AccessTokenScopeWriteIssue, AccessTokenScopeReadIssue, AccessTokenScopeWriteRepository, AccessTokenScopeReadRepository, AccessTokenScopeWriteUser, AccessTokenScopeReadUser, + AccessTokenScopeWriteCommitStatus, AccessTokenScopeReadCommitStatus, } // allAccessTokenScopeBits contains all access token scopes. @@ -165,6 +174,8 @@ var allAccessTokenScopeBits = map[AccessTokenScope]accessTokenScopeBitmap{ AccessTokenScopeWriteRepository: accessTokenScopeWriteRepositoryBits, AccessTokenScopeReadUser: accessTokenScopeReadUserBits, AccessTokenScopeWriteUser: accessTokenScopeWriteUserBits, + AccessTokenScopeReadCommitStatus: accessTokenScopeReadCommitStatusBits, + AccessTokenScopeWriteCommitStatus: accessTokenScopeWriteCommitStatusBits, } // readAccessTokenScopes maps a scope category to the read permission scope @@ -179,6 +190,7 @@ var accessTokenScopes = map[AccessTokenScopeLevel]map[AccessTokenScopeCategory]A AccessTokenScopeCategoryIssue: AccessTokenScopeReadIssue, AccessTokenScopeCategoryRepository: AccessTokenScopeReadRepository, AccessTokenScopeCategoryUser: AccessTokenScopeReadUser, + AccessTokenScopeCategoryCommitStatus: AccessTokenScopeReadCommitStatus, }, Write: { AccessTokenScopeCategoryActivityPub: AccessTokenScopeWriteActivityPub, @@ -190,6 +202,7 @@ var accessTokenScopes = map[AccessTokenScopeLevel]map[AccessTokenScopeCategory]A AccessTokenScopeCategoryIssue: AccessTokenScopeWriteIssue, AccessTokenScopeCategoryRepository: AccessTokenScopeWriteRepository, AccessTokenScopeCategoryUser: AccessTokenScopeWriteUser, + AccessTokenScopeCategoryCommitStatus: AccessTokenScopeWriteCommitStatus, }, } @@ -359,7 +372,7 @@ func (bitmap accessTokenScopeBitmap) toScope() AccessTokenScope { scope := AccessTokenScope(strings.Join(scopes, ",")) scope = AccessTokenScope(strings.ReplaceAll( string(scope), - "write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user", + "write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user,write:commitstatus", "all", )) return scope diff --git a/models/auth/access_token_scope_test.go b/models/auth/access_token_scope_test.go index a6097e45d7f59..531e29b6f2795 100644 --- a/models/auth/access_token_scope_test.go +++ b/models/auth/access_token_scope_test.go @@ -21,11 +21,11 @@ func TestAccessTokenScope_Normalize(t *testing.T) { {"", "", nil}, {"write:misc,write:notification,read:package,write:notification,public-only", "public-only,write:misc,write:notification,read:package", nil}, {"all", "all", nil}, - {"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user", "all", nil}, - {"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user,public-only", "public-only,all", nil}, + {"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user,write:commitstatus", "all", nil}, + {"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user,write:commitstatus,public-only", "public-only,all", nil}, } - for _, scope := range []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user"} { + for _, scope := range []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user", "commitstatus"} { tests = append(tests, scopeTestNormalize{AccessTokenScope(fmt.Sprintf("read:%s", scope)), AccessTokenScope(fmt.Sprintf("read:%s", scope)), nil}, scopeTestNormalize{AccessTokenScope(fmt.Sprintf("write:%s", scope)), AccessTokenScope(fmt.Sprintf("write:%s", scope)), nil}, From 14f6e4cad0495d346fd0bcdfd04cc04839054602 Mon Sep 17 00:00:00 2001 From: Aiden Scandella Date: Fri, 29 Nov 2024 11:28:10 -0800 Subject: [PATCH 02/13] start on API perms --- routers/api/v1/api.go | 28 ++++++++++++++++++++++++++-- services/context/api.go | 12 ++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index f28ee980e1043..e164e607c1314 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -432,6 +432,18 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { } } +// reqRepoCommitStatusWriter user should have a permission to write to commit +// statuses, or write to a repo, or be a site admin +func reqRepoCommitStatusWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + // TODO + if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { + ctx.Error(http.StatusForbidden, "reqRepoCommitStatusWriter", "user should have a permission to write to a repo") + return + } + } +} + // reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin func reqRepoBranchWriter(ctx *context.APIContext) { options, ok := web.GetForm(ctx).(api.FileOptionInterface) @@ -451,6 +463,18 @@ func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { } } +// reqRepoReader user should have specific commit status read permission, or +// repo read permission, or be a repo admin or a site admin +func reqRepoCommitStatusReader(unitType unit.Type) func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + // TODO + if !ctx.Repo.CanRead(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { + ctx.Error(http.StatusForbidden, "reqRepoCommitStatusReader", "user should have specific read permission or be a repo admin or a site admin") + return + } + } +} + // reqAnyRepoReader user should have any permission to read repository or permissions of site admin func reqAnyRepoReader() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { @@ -1323,8 +1347,8 @@ func Routes() *web.Router { }, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo()) m.Group("/statuses", func() { m.Combo("/{sha}").Get(repo.GetCommitStatuses). - Post(reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus) - }, reqRepoReader(unit.TypeCode)) + Post(reqToken(), reqRepoCommitStatusWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus) + }, reqRepoCommitStatusReader(unit.TypeCode)) m.Group("/commits", func() { m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits) m.Group("/{ref}", func() { diff --git a/services/context/api.go b/services/context/api.go index b45e80a329789..be8e7161e41be 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -388,3 +388,15 @@ func (ctx *APIContext) IsUserRepoWriter(unitTypes []unit.Type) bool { return false } + +// IsUserRepoWriter returns true if current user has write commit status privilege in current repo +func (ctx *APIContext) IsUserCommitStatusWriter(unitTypes []unit.Type) bool { + for _, unitType := range unitTypes { + // TODO + if ctx.Repo.CanWrite(unitType) { + return true + } + } + + return false +} From ab6c80a133dee780a554de886d5d04ddc17f9f34 Mon Sep 17 00:00:00 2001 From: Aiden Scandella Date: Fri, 29 Nov 2024 13:58:20 -0800 Subject: [PATCH 03/13] add to token creation UI --- web_src/js/components/ScopedAccessTokenSelector.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/web_src/js/components/ScopedAccessTokenSelector.vue b/web_src/js/components/ScopedAccessTokenSelector.vue index 63214d0bf5164..e0535a6564792 100644 --- a/web_src/js/components/ScopedAccessTokenSelector.vue +++ b/web_src/js/components/ScopedAccessTokenSelector.vue @@ -23,6 +23,7 @@ const categories = computed(() => { 'organization', 'package', 'repository', + 'commitstatus', 'user'); return categories; }); From 35f68afdf6254204dcba8add698fa6ceb577b710 Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Fri, 29 Aug 2025 21:31:52 +0000 Subject: [PATCH 04/13] Fix errors now what? --- routers/api/v1/api.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index c2ff7d7b450fa..d83da479811da 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -459,22 +459,23 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { // statuses, or write to a repo, or be a site admin func reqRepoCommitStatusWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { return func(ctx *context.APIContext) { - // TODO + // TODO(not7cd) if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { - ctx.Error(http.StatusForbidden, "reqRepoCommitStatusWriter", "user should have a permission to write to a repo") + ctx.APIError(http.StatusForbidden, "user should have a permission to write to a repo") return } } } -// reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin -func reqRepoBranchWriter(ctx *context.APIContext) { - options, ok := web.GetForm(ctx).(api.FileOptionInterface) - if !ok || (!ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, options.Branch()) && !ctx.IsUserSiteAdmin()) { - ctx.Error(http.StatusForbidden, "reqRepoBranchWriter", "user should have a permission to write to this branch") - return - } -} +// TODO(not7cd): do I need this? +// // reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin +// func reqRepoBranchWriter(ctx *context.APIContext) { +// options, ok := web.GetForm(ctx).(api.FileOptionInterface) +// if !ok || (!ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, options.Branch()) && !ctx.IsUserSiteAdmin()) { +// ctx.APIError(http.StatusForbidden, "user should have a permission to write to this branch") +// return +// } +// } // reqRepoReader user should have specific read permission or be a repo admin or a site admin func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { @@ -490,9 +491,9 @@ func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { // repo read permission, or be a repo admin or a site admin func reqRepoCommitStatusReader(unitType unit.Type) func(ctx *context.APIContext) { return func(ctx *context.APIContext) { - // TODO + // TODO(not7cd) if !ctx.Repo.CanRead(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { - ctx.Error(http.StatusForbidden, "reqRepoCommitStatusReader", "user should have specific read permission or be a repo admin or a site admin") + ctx.APIError(http.StatusForbidden, "user should have specific read permission or be a repo admin or a site admin") return } } From 7c5cc63dc61f96ab94eb188e9103f9d1b5d8a493 Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sat, 30 Aug 2025 11:49:03 +0000 Subject: [PATCH 05/13] Add UnitCommitStatus --- models/unit/unit.go | 16 ++++++++++++++++ routers/api/v1/api.go | 38 ++------------------------------------ services/context/api.go | 12 ------------ 3 files changed, 18 insertions(+), 48 deletions(-) diff --git a/models/unit/unit.go b/models/unit/unit.go index c0560678ca9aa..89740c791ce97 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -33,6 +33,7 @@ const ( TypeProjects // 8 Projects TypePackages // 9 Packages TypeActions // 10 Actions + TypeCommitStatus // 11 Commit Status // FIXME: TEAM-UNIT-PERMISSION: the team unit "admin" permission's design is not right, when a new unit is added in the future, // admin team won't inherit the correct admin permission for the new unit, need to have a complete fix before adding any new unit. @@ -65,6 +66,7 @@ var ( TypeProjects, TypePackages, TypeActions, + TypeCommitStatus, } // DefaultRepoUnits contains the default unit types @@ -77,8 +79,10 @@ var ( TypeProjects, TypePackages, TypeActions, + TypeCommitStatus, } + // TODO(not7cd): Defaults that need TypeCommitStatus // ForkRepoUnits contains the default unit types for forks DefaultForkRepoUnits = []Type{ TypeCode, @@ -237,6 +241,7 @@ func (u Unit) MaxPerm() perm.AccessMode { } // Enumerate all the units +// TODO(not7cd): Add TypeCommitStatus var ( UnitCode = Unit{ TypeCode, @@ -328,6 +333,16 @@ var ( perm.AccessModeOwner, } + // TODO(not7cd): Just copied this + UnitCommitStatus = Unit{ + TypeCommitStatus, + "repo.commitstatus", + "/statuses", + "commitstatus.unit.desc", + 8, + perm.AccessModeOwner, + } + // Units contains all the units Units = map[Type]Unit{ TypeCode: UnitCode, @@ -340,6 +355,7 @@ var ( TypeProjects: UnitProjects, TypePackages: UnitPackages, TypeActions: UnitActions, + TypeCommitStatus: UnitCommitStatus, } ) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index d83da479811da..8255065d1ce96 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -455,28 +455,6 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { } } -// reqRepoCommitStatusWriter user should have a permission to write to commit -// statuses, or write to a repo, or be a site admin -func reqRepoCommitStatusWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { - return func(ctx *context.APIContext) { - // TODO(not7cd) - if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { - ctx.APIError(http.StatusForbidden, "user should have a permission to write to a repo") - return - } - } -} - -// TODO(not7cd): do I need this? -// // reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin -// func reqRepoBranchWriter(ctx *context.APIContext) { -// options, ok := web.GetForm(ctx).(api.FileOptionInterface) -// if !ok || (!ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, options.Branch()) && !ctx.IsUserSiteAdmin()) { -// ctx.APIError(http.StatusForbidden, "user should have a permission to write to this branch") -// return -// } -// } - // reqRepoReader user should have specific read permission or be a repo admin or a site admin func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { return func(ctx *context.APIContext) { @@ -487,18 +465,6 @@ func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { } } -// reqRepoReader user should have specific commit status read permission, or -// repo read permission, or be a repo admin or a site admin -func reqRepoCommitStatusReader(unitType unit.Type) func(ctx *context.APIContext) { - return func(ctx *context.APIContext) { - // TODO(not7cd) - if !ctx.Repo.CanRead(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { - ctx.APIError(http.StatusForbidden, "user should have specific read permission or be a repo admin or a site admin") - return - } - } -} - // reqAnyRepoReader user should have any permission to read repository or permissions of site admin func reqAnyRepoReader() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { @@ -1433,8 +1399,8 @@ func Routes() *web.Router { }, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo()) m.Group("/statuses", func() { m.Combo("/{sha}").Get(repo.GetCommitStatuses). - Post(reqToken(), reqRepoCommitStatusWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus) - }, reqRepoCommitStatusReader(unit.TypeCode)) + Post(reqToken(), reqRepoWriter(unit.TypeCommitStatus), bind(api.CreateStatusOption{}), repo.NewCommitStatus) + }, reqRepoWriter(unit.TypeCommitStatus)) m.Group("/commits", func() { m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits) m.Group("/{ref}", func() { diff --git a/services/context/api.go b/services/context/api.go index cc8e4f65ca50a..ab50a360f48b6 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -367,15 +367,3 @@ func (ctx *APIContext) IsUserRepoAdmin() bool { func (ctx *APIContext) IsUserRepoWriter(unitTypes []unit.Type) bool { return slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite) } - -// IsUserRepoWriter returns true if current user has write commit status privilege in current repo -func (ctx *APIContext) IsUserCommitStatusWriter(unitTypes []unit.Type) bool { - for _, unitType := range unitTypes { - // TODO - if ctx.Repo.CanWrite(unitType) { - return true - } - } - - return false -} From d9e9f8878df59b0b35ae91c814630b57d315f83c Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sat, 30 Aug 2025 13:13:22 +0000 Subject: [PATCH 06/13] Revert "Add UnitCommitStatus" This reverts commit 7c5cc63dc61f96ab94eb188e9103f9d1b5d8a493. --- models/unit/unit.go | 16 ---------------- routers/api/v1/api.go | 38 ++++++++++++++++++++++++++++++++++++-- services/context/api.go | 12 ++++++++++++ 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/models/unit/unit.go b/models/unit/unit.go index 89740c791ce97..c0560678ca9aa 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -33,7 +33,6 @@ const ( TypeProjects // 8 Projects TypePackages // 9 Packages TypeActions // 10 Actions - TypeCommitStatus // 11 Commit Status // FIXME: TEAM-UNIT-PERMISSION: the team unit "admin" permission's design is not right, when a new unit is added in the future, // admin team won't inherit the correct admin permission for the new unit, need to have a complete fix before adding any new unit. @@ -66,7 +65,6 @@ var ( TypeProjects, TypePackages, TypeActions, - TypeCommitStatus, } // DefaultRepoUnits contains the default unit types @@ -79,10 +77,8 @@ var ( TypeProjects, TypePackages, TypeActions, - TypeCommitStatus, } - // TODO(not7cd): Defaults that need TypeCommitStatus // ForkRepoUnits contains the default unit types for forks DefaultForkRepoUnits = []Type{ TypeCode, @@ -241,7 +237,6 @@ func (u Unit) MaxPerm() perm.AccessMode { } // Enumerate all the units -// TODO(not7cd): Add TypeCommitStatus var ( UnitCode = Unit{ TypeCode, @@ -333,16 +328,6 @@ var ( perm.AccessModeOwner, } - // TODO(not7cd): Just copied this - UnitCommitStatus = Unit{ - TypeCommitStatus, - "repo.commitstatus", - "/statuses", - "commitstatus.unit.desc", - 8, - perm.AccessModeOwner, - } - // Units contains all the units Units = map[Type]Unit{ TypeCode: UnitCode, @@ -355,7 +340,6 @@ var ( TypeProjects: UnitProjects, TypePackages: UnitPackages, TypeActions: UnitActions, - TypeCommitStatus: UnitCommitStatus, } ) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 8255065d1ce96..d83da479811da 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -455,6 +455,28 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { } } +// reqRepoCommitStatusWriter user should have a permission to write to commit +// statuses, or write to a repo, or be a site admin +func reqRepoCommitStatusWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + // TODO(not7cd) + if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { + ctx.APIError(http.StatusForbidden, "user should have a permission to write to a repo") + return + } + } +} + +// TODO(not7cd): do I need this? +// // reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin +// func reqRepoBranchWriter(ctx *context.APIContext) { +// options, ok := web.GetForm(ctx).(api.FileOptionInterface) +// if !ok || (!ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, options.Branch()) && !ctx.IsUserSiteAdmin()) { +// ctx.APIError(http.StatusForbidden, "user should have a permission to write to this branch") +// return +// } +// } + // reqRepoReader user should have specific read permission or be a repo admin or a site admin func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { return func(ctx *context.APIContext) { @@ -465,6 +487,18 @@ func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { } } +// reqRepoReader user should have specific commit status read permission, or +// repo read permission, or be a repo admin or a site admin +func reqRepoCommitStatusReader(unitType unit.Type) func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + // TODO(not7cd) + if !ctx.Repo.CanRead(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { + ctx.APIError(http.StatusForbidden, "user should have specific read permission or be a repo admin or a site admin") + return + } + } +} + // reqAnyRepoReader user should have any permission to read repository or permissions of site admin func reqAnyRepoReader() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { @@ -1399,8 +1433,8 @@ func Routes() *web.Router { }, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo()) m.Group("/statuses", func() { m.Combo("/{sha}").Get(repo.GetCommitStatuses). - Post(reqToken(), reqRepoWriter(unit.TypeCommitStatus), bind(api.CreateStatusOption{}), repo.NewCommitStatus) - }, reqRepoWriter(unit.TypeCommitStatus)) + Post(reqToken(), reqRepoCommitStatusWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus) + }, reqRepoCommitStatusReader(unit.TypeCode)) m.Group("/commits", func() { m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits) m.Group("/{ref}", func() { diff --git a/services/context/api.go b/services/context/api.go index ab50a360f48b6..cc8e4f65ca50a 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -367,3 +367,15 @@ func (ctx *APIContext) IsUserRepoAdmin() bool { func (ctx *APIContext) IsUserRepoWriter(unitTypes []unit.Type) bool { return slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite) } + +// IsUserRepoWriter returns true if current user has write commit status privilege in current repo +func (ctx *APIContext) IsUserCommitStatusWriter(unitTypes []unit.Type) bool { + for _, unitType := range unitTypes { + // TODO + if ctx.Repo.CanWrite(unitType) { + return true + } + } + + return false +} From f49e20dec386413b781867f19d59f7444816f9fa Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sat, 30 Aug 2025 13:17:14 +0000 Subject: [PATCH 07/13] Lets start with token --- routers/api/v1/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index d83da479811da..c211e34d0a4df 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1433,8 +1433,8 @@ func Routes() *web.Router { }, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo()) m.Group("/statuses", func() { m.Combo("/{sha}").Get(repo.GetCommitStatuses). - Post(reqToken(), reqRepoCommitStatusWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus) - }, reqRepoCommitStatusReader(unit.TypeCode)) + Post(reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryCommitStatus), bind(api.CreateStatusOption{}), repo.NewCommitStatus) + }) m.Group("/commits", func() { m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits) m.Group("/{ref}", func() { From bb65a90cab56c7dbb37e70b9a3fe85c705d94a09 Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sat, 30 Aug 2025 14:08:06 +0000 Subject: [PATCH 08/13] This kinda works, but not really --- routers/api/v1/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index c211e34d0a4df..885a166c01a44 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1433,7 +1433,7 @@ func Routes() *web.Router { }, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo()) m.Group("/statuses", func() { m.Combo("/{sha}").Get(repo.GetCommitStatuses). - Post(reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryCommitStatus), bind(api.CreateStatusOption{}), repo.NewCommitStatus) + Post(reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryCommitStatus, auth_model.AccessTokenScopeCategoryRepository), bind(api.CreateStatusOption{}), repo.NewCommitStatus) }) m.Group("/commits", func() { m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits) From f02a372c65566d9964f82da25e044c2e07c2a7df Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sat, 30 Aug 2025 14:13:36 +0000 Subject: [PATCH 09/13] remove unused --- services/context/api.go | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/services/context/api.go b/services/context/api.go index cc8e4f65ca50a..ab50a360f48b6 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -367,15 +367,3 @@ func (ctx *APIContext) IsUserRepoAdmin() bool { func (ctx *APIContext) IsUserRepoWriter(unitTypes []unit.Type) bool { return slices.ContainsFunc(unitTypes, ctx.Repo.CanWrite) } - -// IsUserRepoWriter returns true if current user has write commit status privilege in current repo -func (ctx *APIContext) IsUserCommitStatusWriter(unitTypes []unit.Type) bool { - for _, unitType := range unitTypes { - // TODO - if ctx.Repo.CanWrite(unitType) { - return true - } - } - - return false -} From a399a5ac3fa73e97c2ef938300555527cf3f72e7 Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sat, 30 Aug 2025 14:23:20 +0000 Subject: [PATCH 10/13] remove unused in routers/api/v1/api.go --- routers/api/v1/api.go | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 885a166c01a44..958ccad8a2248 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -455,28 +455,6 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { } } -// reqRepoCommitStatusWriter user should have a permission to write to commit -// statuses, or write to a repo, or be a site admin -func reqRepoCommitStatusWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) { - return func(ctx *context.APIContext) { - // TODO(not7cd) - if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { - ctx.APIError(http.StatusForbidden, "user should have a permission to write to a repo") - return - } - } -} - -// TODO(not7cd): do I need this? -// // reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin -// func reqRepoBranchWriter(ctx *context.APIContext) { -// options, ok := web.GetForm(ctx).(api.FileOptionInterface) -// if !ok || (!ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, options.Branch()) && !ctx.IsUserSiteAdmin()) { -// ctx.APIError(http.StatusForbidden, "user should have a permission to write to this branch") -// return -// } -// } - // reqRepoReader user should have specific read permission or be a repo admin or a site admin func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { return func(ctx *context.APIContext) { @@ -487,18 +465,6 @@ func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) { } } -// reqRepoReader user should have specific commit status read permission, or -// repo read permission, or be a repo admin or a site admin -func reqRepoCommitStatusReader(unitType unit.Type) func(ctx *context.APIContext) { - return func(ctx *context.APIContext) { - // TODO(not7cd) - if !ctx.Repo.CanRead(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() { - ctx.APIError(http.StatusForbidden, "user should have specific read permission or be a repo admin or a site admin") - return - } - } -} - // reqAnyRepoReader user should have any permission to read repository or permissions of site admin func reqAnyRepoReader() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { From ee83b0dba766de11127c5bbe293a122bfcdaf0c0 Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sat, 30 Aug 2025 22:16:30 +0000 Subject: [PATCH 11/13] fix test --- models/auth/access_token_scope_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/auth/access_token_scope_test.go b/models/auth/access_token_scope_test.go index b0117a6e1ea5c..b753da3e712cb 100644 --- a/models/auth/access_token_scope_test.go +++ b/models/auth/access_token_scope_test.go @@ -17,7 +17,7 @@ type scopeTestNormalize struct { } func TestAccessTokenScope_Normalize(t *testing.T) { - assert.Equal(t, []string{"activitypub", "admin", "issue", "misc", "notification", "organization", "package", "repository", "user", "commitstatus"}, GetAccessTokenCategories()) + assert.Equal(t, []string{"activitypub", "admin", "commitstatus", "issue", "misc", "notification", "organization", "package", "repository", "user"}, GetAccessTokenCategories()) tests := []scopeTestNormalize{ {"", "", nil}, {"write:misc,write:notification,read:package,write:notification,public-only", "public-only,write:misc,write:notification,read:package", nil}, From 1103ccacb1eea80fb401a84b989d741dfd5dbe37 Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sun, 31 Aug 2025 10:10:03 +0000 Subject: [PATCH 12/13] bring back unit check --- routers/api/v1/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 958ccad8a2248..3ec23ad052884 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1399,8 +1399,8 @@ func Routes() *web.Router { }, mustAllowPulls, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo()) m.Group("/statuses", func() { m.Combo("/{sha}").Get(repo.GetCommitStatuses). - Post(reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryCommitStatus, auth_model.AccessTokenScopeCategoryRepository), bind(api.CreateStatusOption{}), repo.NewCommitStatus) - }) + Post(reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryCommitStatus), reqRepoWriter(unit.TypeCode), bind(api.CreateStatusOption{}), repo.NewCommitStatus) + }, reqRepoReader(unit.TypeCode)) m.Group("/commits", func() { m.Get("", context.ReferencesGitRepo(), repo.GetAllCommits) m.Group("/{ref}", func() { From 4e2530c3bb41aff42d0008add7521768bc38557b Mon Sep 17 00:00:00 2001 From: Norbert Szulc Date: Sun, 31 Aug 2025 10:13:50 +0000 Subject: [PATCH 13/13] commit status contained within --- models/auth/access_token_scope.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/models/auth/access_token_scope.go b/models/auth/access_token_scope.go index 7086779458253..37beb3e8ad981 100644 --- a/models/auth/access_token_scope.go +++ b/models/auth/access_token_scope.go @@ -123,8 +123,8 @@ const ( accessTokenScopeReadIssueBits accessTokenScopeBitmap = 1 << iota accessTokenScopeWriteIssueBits accessTokenScopeBitmap = 1<