Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2f73c70
initial commit
hschu12 Feb 11, 2026
56c7cbb
made caching
hschu12 Feb 11, 2026
2e83412
finished provider notification
hschu12 Feb 16, 2026
62a400b
Merge branch 'master' into ProjectPolicy
hschu12 Feb 16, 2026
6c01d89
added policy cache for accountiong and orchestrator
hschu12 Feb 16, 2026
369ae1e
Added restriction names to api and restricted Downloads. Fixes #5310
hschu12 Feb 16, 2026
8cc7b3f
clear up failing entiries and added check for files and publicLins
hschu12 Feb 18, 2026
119fde2
Added additional policy checks. Fixes #5310, Fixes #5308, Fixes #5312…
hschu12 Feb 20, 2026
0b00ff0
merged master
hschu12 Mar 2, 2026
a694197
pre checkout. notifications to provider is being tested
hschu12 Mar 4, 2026
4e01018
Merge branch 'master' into ProjectPolicy
hschu12 Mar 6, 2026
a9cca04
missing import after merge of master and syncthing policy at core
hschu12 Mar 6, 2026
5564273
Fixes #5315
hschu12 Mar 11, 2026
db0ec82
missed comment
hschu12 Mar 11, 2026
7cfdb50
Fixes #5311
hschu12 Mar 13, 2026
bb4685e
Blocking on IP Restiction
hschu12 Mar 13, 2026
491b5b9
fixed missing updates on delete
hschu12 Mar 13, 2026
e9b07c4
Data Manager Role for Projects
hschu12 Mar 16, 2026
cce51ae
Merge branch 'master' of https://github.com/SDU-eScience/UCloud
hschu12 Mar 26, 2026
fbd690d
merged master
hschu12 Mar 26, 2026
08b51a1
compile error
hschu12 Mar 26, 2026
bcd72e8
Bump github.com/go-jose/go-jose/v4 from 4.1.3 to 4.1.4 in /core2
dependabot[bot] Apr 3, 2026
821e66c
Bump github.com/go-jose/go-jose/v4 in /provider-integration/im2
dependabot[bot] Apr 3, 2026
8e243ea
Bump vite from 7.3.1 to 7.3.2 in /frontend-web/webclient
dependabot[bot] Apr 6, 2026
1febb70
Merge pull request #5496 from SDU-eScience/dependabot/npm_and_yarn/fr…
DanThrane Apr 8, 2026
b86544f
Merge pull request #5495 from SDU-eScience/dependabot/go_modules/prov…
DanThrane Apr 8, 2026
48299c9
Merge pull request #5494 from SDU-eScience/dependabot/go_modules/core…
DanThrane Apr 8, 2026
2039de2
Bump lodash-es and mermaid in /frontend-web/webclient
dependabot[bot] Apr 8, 2026
ab99672
Merge pull request #5498 from SDU-eScience/dependabot/npm_and_yarn/fr…
DanThrane Apr 8, 2026
2cd7087
Merge branch 'master' of https://github.com/SDU-eScience/UCloud
hschu12 Apr 10, 2026
55652bb
Merge branch 'master' into ProjectPolicy
hschu12 Apr 10, 2026
06fbaae
cut and paste
hschu12 Apr 13, 2026
8107288
cut and paste
hschu12 Apr 16, 2026
93c0408
FE update
hschu12 Apr 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion core2/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ require (
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
github.com/go-jose/go-jose/v4 v4.1.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
Expand Down
4 changes: 2 additions & 2 deletions core2/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs=
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA=
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
Expand Down
3 changes: 3 additions & 0 deletions core2/pkg/accounting/00_module.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ func Init() {
initGrantsExport()
times["GrantsExport"] = t.Mark()

initPolicySubscriptions()
times["PolicySubscriptions"] = t.Mark()

coreutil.PrintStartupTimes("Accounting", times)

if util.DevelopmentModeEnabled() {
Expand Down
9 changes: 9 additions & 0 deletions core2/pkg/accounting/accounting.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ func initAccounting() {
go accountingProcessTasks()

accapi.RootAllocate.Handler(func(info rpc.RequestInfo, request fndapi.BulkRequest[accapi.RootAllocateRequest]) (fndapi.BulkResponse[fndapi.FindByStringId], *util.HttpError) {
if sourceIPisRestricted(info) {
return fndapi.BulkResponse[fndapi.FindByStringId]{}, util.HttpErr(http.StatusForbidden, "Client IP is not allowed by project")
}
var result []fndapi.FindByStringId
for _, reqItem := range request.Items {
id, err := RootAllocate(info.Actor, reqItem)
Expand All @@ -41,6 +44,9 @@ func initAccounting() {
})

accapi.UpdateAllocation.Handler(func(info rpc.RequestInfo, request fndapi.BulkRequest[accapi.UpdateAllocationRequest]) (util.Empty, *util.HttpError) {
if sourceIPisRestricted(info) {
return util.Empty{}, util.HttpErr(http.StatusForbidden, "Client IP is not allowed by project")
}
return UpdateAllocation(info.Actor, request.Items)
})

Expand All @@ -58,6 +64,9 @@ func initAccounting() {
})

accapi.WalletsBrowse.Handler(func(info rpc.RequestInfo, request accapi.WalletsBrowseRequest) (fndapi.PageV2[accapi.WalletV2], *util.HttpError) {
if sourceIPisRestricted(info) {
return fndapi.PageV2[accapi.WalletV2]{}, util.HttpErr(http.StatusForbidden, "Client IP is not allowed by project")
}
return WalletsBrowse(info.Actor, request), nil
})

Expand Down
15 changes: 15 additions & 0 deletions core2/pkg/accounting/grants.go
Original file line number Diff line number Diff line change
Expand Up @@ -2056,14 +2056,23 @@ func initGrants() {

if !grantGlobals.Testing.Enabled {
accapi.GrantsBrowse.Handler(func(info rpc.RequestInfo, request accapi.GrantsBrowseRequest) (fndapi.PageV2[accapi.GrantApplication], *util.HttpError) {
if sourceIPisRestricted(info) {
return fndapi.PageV2[accapi.GrantApplication]{}, util.HttpErr(http.StatusForbidden, "Client IP is not accepted by project")
}
return GrantsBrowse(info.Actor, request), nil
})

accapi.GrantsRetrieve.Handler(func(info rpc.RequestInfo, request fndapi.FindByStringId) (accapi.GrantApplication, *util.HttpError) {
if sourceIPisRestricted(info) {
return accapi.GrantApplication{}, util.HttpErr(http.StatusForbidden, "Client IP is not accepted by project")
}
return GrantsRetrieve(info.Actor, request.Id)
})

accapi.GrantsSubmitRevision.Handler(func(info rpc.RequestInfo, request accapi.GrantsSubmitRevisionRequest) (fndapi.FindByStringId, *util.HttpError) {
if sourceIPisRestricted(info) {
return fndapi.FindByStringId{}, util.HttpErr(http.StatusForbidden, "Client IP is not accepted by project")
}
id, err := GrantsSubmitRevision(info.Actor, request)
if err != nil {
return fndapi.FindByStringId{}, err
Expand All @@ -2086,6 +2095,9 @@ func initGrants() {
})

accapi.GrantsPostComment.Handler(func(info rpc.RequestInfo, request accapi.GrantsPostCommentRequest) (fndapi.FindByStringId, *util.HttpError) {
if sourceIPisRestricted(info) {
return fndapi.FindByStringId{}, util.HttpErr(http.StatusForbidden, "Client IP is not accepted by project")
}
id, err := GrantsPostComment(info.Actor, request)
if err != nil {
return fndapi.FindByStringId{}, err
Expand All @@ -2095,6 +2107,9 @@ func initGrants() {
})

accapi.GrantsDeleteComment.Handler(func(info rpc.RequestInfo, request accapi.GrantsDeleteCommentRequest) (util.Empty, *util.HttpError) {
if sourceIPisRestricted(info) {
return util.Empty{}, util.HttpErr(http.StatusForbidden, "Client IP is not accepted by project")
}
return util.Empty{}, GrantsDeleteComment(info.Actor, request)
})

Expand Down
7 changes: 7 additions & 0 deletions core2/pkg/accounting/grants_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package accounting

import (
"fmt"
"net/http"
"strings"
"time"

Expand All @@ -14,10 +15,16 @@ import (

func initGrantsExport() {
accapi.GrantsExport.Handler(func(info rpc.RequestInfo, request util.Empty) ([]accapi.GrantsExportResponse, *util.HttpError) {
if sourceIPisRestricted(info) {
return nil, util.HttpErr(http.StatusForbidden, "Client IP is not allowed by project")
}
return GrantsExportBrowse(info.Actor), nil
})

accapi.GrantsExportCsv.Handler(func(info rpc.RequestInfo, request util.Empty) (accapi.GrantsExportCsvResponse, *util.HttpError) {
if sourceIPisRestricted(info) {
return accapi.GrantsExportCsvResponse{}, util.HttpErr(http.StatusForbidden, "Client IP is not allowed by project")
}
csv := GrantsExportBrowseToCsv(GrantsExportBrowse(info.Actor))
return accapi.GrantsExportCsvResponse{
FileName: "grants.csv",
Expand Down
107 changes: 107 additions & 0 deletions core2/pkg/accounting/policy_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package accounting

import (
"context"
"net"
"sync"

"ucloud.dk/core/pkg/coreutil"
db "ucloud.dk/shared/pkg/database"
fndapi "ucloud.dk/shared/pkg/foundation"
"ucloud.dk/shared/pkg/log"
"ucloud.dk/shared/pkg/rpc"
"ucloud.dk/shared/pkg/util"
)

// policyCache is a mapping of projectId -> map[schemaName] -> PolicySpecification
var policyCache struct {
Mu sync.RWMutex
PoliciesByProject map[string]map[string]*fndapi.PolicySpecification
}

func initPolicySubscriptions() {

policyCache.Mu.Lock()
policyCache.PoliciesByProject = make(map[string]map[string]*fndapi.PolicySpecification)
policyCache.Mu.Unlock()

go func() {
policyUpdates := db.Listen(context.Background(), "policy_updates")
policyDeletes := db.Listen(context.Background(), "policy_deleted")

var projectId string
var policySpecifications map[string]*fndapi.PolicySpecification
var policiesOk bool

for {
select {
case projectId = <-policyUpdates:
db.NewTx0(func(tx *db.Transaction) {
policySpecifications, policiesOk = coreutil.PolicySpecificationsRetrieveFromDatabase(tx, projectId)
})
case projectId = <-policyDeletes:
db.NewTx0(func(tx *db.Transaction) {

policySpecifications, policiesOk = coreutil.PolicySpecificationsRetrieveFromDatabase(tx, projectId)
})
}

if policiesOk {
updatePolicyCacheForProject(projectId, policySpecifications)
}
}

}()
}

// policiesByProject returns mapping of [schema Name] => PolicySpecification. If no policy is cached for the project it
// will attempt to retrieve it from DB. This is also how it is populated.
func policiesByProject(projectId string) map[string]*fndapi.PolicySpecification {
projectPolicies := map[string]*fndapi.PolicySpecification{}
policyCache.Mu.Lock()
projectPolicies, ok := policyCache.PoliciesByProject[projectId]
if !ok {
log.Debug("No policies for project %v", projectId)
db.NewTx0(func(tx *db.Transaction) {
policySpecifications, policiesOk := coreutil.PolicySpecificationsRetrieveFromDatabase(tx, projectId)
if policiesOk {
policyCache.PoliciesByProject[projectId] = policySpecifications
} else {
log.Debug("No policies for project %v found in DB", projectId)
}
})
}
policyCache.Mu.Unlock()

return projectPolicies
}

func updatePolicyCacheForProject(projectId string, policySpecifications map[string]*fndapi.PolicySpecification) {
policyCache.Mu.Lock()
policyCache.PoliciesByProject[projectId] = policySpecifications
policyCache.Mu.Unlock()
}

func sourceIPisRestricted(info rpc.RequestInfo) bool {
if info.Actor.Project.Present {
sourceIpSpecs, hasSourceRestriction := policiesByProject(info.Actor.Project.String())[fndapi.RestrictSourceIPRange.String()]
if hasSourceRestriction {
isRestricted := true
for _, property := range sourceIpSpecs.Properties {
if property.Name == "allowedClientSubnets" {
allowedIps := property.Text
if allowedIps == "" {
break
}
_, subnet, _ := net.ParseCIDR(allowedIps)
ip := net.ParseIP(util.ClientIP(info.HttpRequest).String())
if subnet.Contains(ip) {
isRestricted = false
}
}
}
return isRestricted
}
}
return false
}
Loading