Documentation
¶
Overview ¶
Package resource provides the data layer for human-uploaded reference material (samples, playbooks, templates, references). Resources are scoped to global, persona, or user visibility and stored as blobs in S3 with metadata in PostgreSQL.
Index ¶
- Constants
- Variables
- func BuildS3Key(scope Scope, scopeID, resourceID, filename string) string
- func BuildURI(scheme string, scope Scope, scopeID, category, filename string) string
- func CanModifyResource(c Claims, r *Resource) bool
- func CanReadResource(c Claims, r *Resource) bool
- func CanWriteScope(c Claims, scope Scope, scopeID string) bool
- func GenerateID() (string, error)
- func SanitizeFilename(name string) (string, error)
- func ValidateCategory(cat string) error
- func ValidateDescription(desc string) error
- func ValidateDisplayName(name string) error
- func ValidateMIMEType(mt string) error
- func ValidateScope(scope Scope, scopeID string) error
- func ValidateTags(tags []string) error
- type Claims
- type ClaimsExtractor
- type Deps
- type Filter
- type Handler
- type ParsedURI
- type Resource
- type S3Client
- type Scope
- type ScopeFilter
- type Store
- type Update
Constants ¶
const ( MaxUploadBytes = 100 << 20 // 100 MB MaxDescriptionLen = 2000 MaxDisplayNameLen = 200 MaxTagsPerResource = 20 MaxTagLen = 50 MaxCategoryLen = 31 )
Validation limits.
const DefaultListLimit = 100
DefaultListLimit is used when no limit is specified in a list query.
const DefaultURIScheme = "mcp"
DefaultURIScheme is used when no scheme is configured.
const MaxMultipartMemory = 10 << 20
MaxMultipartMemory is the max memory for multipart form parsing (10 MB).
Variables ¶
var DeniedExtensions = map[string]bool{ ".exe": true, ".sh": true, ".bat": true, ".cmd": true, ".ps1": true, ".msi": true, ".com": true, ".scr": true, }
DeniedExtensions lists file extensions that are blocked for upload.
var DeniedMIMETypes = map[string]bool{ "application/x-executable": true, "application/x-msdos-program": true, "application/x-msdownload": true, "application/x-sh": true, "application/x-shellscript": true, "application/x-bat": true, "application/x-msi": true, }
DeniedMIMETypes lists MIME types that are blocked for upload.
Functions ¶
func BuildS3Key ¶
BuildS3Key constructs the S3 object key for a resource blob.
func CanModifyResource ¶
CanModifyResource checks whether the caller can update or delete a resource. The caller must be the original uploader OR have write permission for the scope.
func CanReadResource ¶
CanReadResource checks whether the caller can read a specific resource.
func CanWriteScope ¶
CanWriteScope checks whether the caller has write permission for the given scope.
func GenerateID ¶
GenerateID returns a cryptographically random 32-character hex string.
func SanitizeFilename ¶
SanitizeFilename normalizes a filename for storage: lowercase, no spaces, no path separators or shell metacharacters, preserves extension.
func ValidateCategory ¶
ValidateCategory checks that a category matches the required pattern.
func ValidateDescription ¶
ValidateDescription checks description length and content.
func ValidateDisplayName ¶
ValidateDisplayName checks display name length and content.
func ValidateMIMEType ¶
ValidateMIMEType checks that the MIME type is not on the deny list. The base type is extracted (e.g. "text/html" from "text/html; charset=utf-8") before checking the deny list.
func ValidateScope ¶
ValidateScope checks scope and scope_id consistency.
func ValidateTags ¶
ValidateTags checks tag count, length, and format.
Types ¶
type Claims ¶
type Claims struct {
Sub string // Keycloak subject (user ID)
Email string // user email
Personas []string // persona names the user belongs to
Roles []string // e.g., "admin", "platform-admin", "persona-admin:finance"
}
Claims represents the identity information needed for resource permission checks.
type ClaimsExtractor ¶
ClaimsExtractor extracts resource Claims from an HTTP request. Provided by the platform auth middleware.
type Deps ¶
type Deps struct {
Store Store
S3Client S3Client
S3Bucket string
URIScheme string // defaults to "mcp" if empty
}
Deps holds the dependencies for the resource HTTP handler.
type Filter ¶
type Filter struct {
Scopes []ScopeFilter // visibility scopes (derived from claims)
Category string // optional category filter
Tag string // optional tag filter
Query string // optional text search in display_name/description
Limit int
Offset int
}
Filter specifies criteria for listing resources.
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler provides HTTP endpoints for resource CRUD.
func NewHandler ¶
func NewHandler(deps Deps, extractFn ClaimsExtractor, authMiddle func(http.Handler) http.Handler) *Handler
NewHandler creates a resource handler with auth middleware.
type Resource ¶
type Resource struct {
ID string `json:"id"`
Scope Scope `json:"scope"`
ScopeID string `json:"scope_id,omitempty"` // persona name or user sub; empty for global
Category string `json:"category"`
Filename string `json:"filename"`
DisplayName string `json:"display_name"`
Description string `json:"description"`
MIMEType string `json:"mime_type"`
SizeBytes int64 `json:"size_bytes"`
S3Key string `json:"s3_key"`
URI string `json:"uri"`
Tags []string `json:"tags"`
UploaderSub string `json:"uploader_sub"`
UploaderEmail string `json:"uploader_email"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Resource represents a human-uploaded reference material entry.
type S3Client ¶
type S3Client interface {
PutObject(ctx context.Context, bucket, key string, data []byte, contentType string) error
GetObject(ctx context.Context, bucket, key string) (body []byte, contentType string, err error)
DeleteObject(ctx context.Context, bucket, key string) error
}
S3Client abstracts blob storage operations for resources.
type ScopeFilter ¶
ScopeFilter identifies a single scope+id pair for visibility filtering.
func VisibleScopes ¶
func VisibleScopes(c Claims) []ScopeFilter
VisibleScopes returns the set of (scope, scope_id) tuples the caller is allowed to see. Always derived from claims, never from request input.
type Store ¶
type Store interface {
Insert(ctx context.Context, r Resource) error
Get(ctx context.Context, id string) (*Resource, error)
GetByURI(ctx context.Context, uri string) (*Resource, error)
List(ctx context.Context, filter Filter) ([]Resource, int, error)
Update(ctx context.Context, id string, u Update) error
Delete(ctx context.Context, id string) error
}
Store persists and queries resource metadata.
func NewPostgresStore ¶
NewPostgresStore creates a resource store backed by PostgreSQL.