Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
package accesspolicy
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/Tencent/WeKnora/internal/types"
|
|
)
|
|
|
|
// Snapshot is loaded from the active workspace on each authenticated request.
|
|
// An absent snapshot preserves native service behavior for background jobs.
|
|
type Snapshot struct {
|
|
Restricted bool
|
|
Permissions map[string]bool
|
|
Publications map[string]bool
|
|
Grants map[string]bool
|
|
Hidden map[string]bool
|
|
NoExport map[string]bool
|
|
}
|
|
|
|
func WithSnapshot(ctx context.Context, snapshot *Snapshot) context.Context {
|
|
return context.WithValue(ctx, types.AccessPolicySnapshotContextKey, snapshot)
|
|
}
|
|
func FromContext(ctx context.Context) *Snapshot {
|
|
value, _ := ctx.Value(types.AccessPolicySnapshotContextKey).(*Snapshot)
|
|
return value
|
|
}
|
|
func Allowed(ctx context.Context, permission string) bool {
|
|
s := FromContext(ctx)
|
|
return s == nil || !s.Restricted || s.Permissions[permission]
|
|
}
|
|
|
|
// WorkbenchActionPermission is shared by request and queued-job authorization.
|
|
func WorkbenchActionPermission(kind, action string) string {
|
|
if kind == "flows" {
|
|
return "flows.write"
|
|
}
|
|
if kind == "training-maps" {
|
|
return "content.maps"
|
|
}
|
|
if kind == "content-tasks" && (action == "accept" || action == "skip" || action == "review" || action == "review-settings" || action == "compose") {
|
|
return "content.review"
|
|
}
|
|
return "content.generate"
|
|
}
|
|
|
|
func Readable(ctx context.Context, kind, id string, owned, nativePublic bool) bool {
|
|
if Hidden(ctx, kind, id) {
|
|
return false
|
|
}
|
|
if owned {
|
|
return true
|
|
}
|
|
s := FromContext(ctx)
|
|
if s == nil {
|
|
return nativePublic
|
|
}
|
|
resource := kind + ":" + id
|
|
if global, managed := s.Publications[resource]; managed {
|
|
return global || s.Grants[resource]
|
|
}
|
|
return nativePublic || s.Grants[resource]
|
|
}
|
|
|
|
func SharedIDs(ctx context.Context, kind string) []string {
|
|
s := FromContext(ctx)
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
ids := map[string]bool{}
|
|
prefix := kind + ":"
|
|
for key, enabled := range s.Publications {
|
|
if enabled && len(key) > len(prefix) && key[:len(prefix)] == prefix {
|
|
ids[key[len(prefix):]] = true
|
|
}
|
|
}
|
|
for key, enabled := range s.Grants {
|
|
if enabled && len(key) > len(prefix) && key[:len(prefix)] == prefix {
|
|
ids[key[len(prefix):]] = true
|
|
}
|
|
}
|
|
out := make([]string, 0, len(ids))
|
|
for id := range ids {
|
|
if !s.Hidden[prefix+id] {
|
|
out = append(out, id)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func Hidden(ctx context.Context, kind, id string) bool {
|
|
s := FromContext(ctx)
|
|
return s != nil && s.Hidden[kind+":"+id]
|
|
}
|
|
|
|
func HiddenIDs(ctx context.Context, kind string) []string {
|
|
s := FromContext(ctx)
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
result := []string{}
|
|
prefix := kind + ":"
|
|
for key, hidden := range s.Hidden {
|
|
if hidden && len(key) > len(prefix) && key[:len(prefix)] == prefix {
|
|
result = append(result, key[len(prefix):])
|
|
}
|
|
}
|
|
return result
|
|
}
|