Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 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
fbd690d
merged master
hschu12 Mar 26, 2026
08b51a1
compile error
hschu12 Mar 26, 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
b62b3e0
Merge branch 'master' into ProjectPolicy
hschu12 Apr 27, 2026
a0b23c7
relocated and titles now show
hschu12 Apr 27, 2026
6be7811
pre merge
hschu12 Apr 28, 2026
19fc47d
Simple FE to show current settings. Need to allow updating it
hschu12 Apr 30, 2026
89e3346
documentation for the service
hschu12 Jun 9, 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
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