resource

package
v1.55.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 11, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

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

View Source
const (
	MaxUploadBytes     = 100 << 20 // 100 MB
	MaxDescriptionLen  = 2000
	MaxDisplayNameLen  = 200
	MaxTagsPerResource = 20
	MaxTagLen          = 50
	MaxCategoryLen     = 31
)

Validation limits.

View Source
const DefaultListLimit = 100

DefaultListLimit is used when no limit is specified in a list query.

View Source
const DefaultURIScheme = "mcp"

DefaultURIScheme is used when no scheme is configured.

View Source
const MaxMultipartMemory = 10 << 20

MaxMultipartMemory is the max memory for multipart form parsing (10 MB).

Variables

View Source
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.

View Source
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

func BuildS3Key(scope Scope, scopeID, resourceID, filename string) string

BuildS3Key constructs the S3 object key for a resource blob.

func BuildURI

func BuildURI(scheme string, scope Scope, scopeID, category, filename string) string

BuildURI constructs the canonical resource URI from its components.

func CanModifyResource

func CanModifyResource(c Claims, r *Resource) bool

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

func CanReadResource(c Claims, r *Resource) bool

CanReadResource checks whether the caller can read a specific resource.

func CanWriteScope

func CanWriteScope(c Claims, scope Scope, scopeID string) bool

CanWriteScope checks whether the caller has write permission for the given scope.

func GenerateID

func GenerateID() (string, error)

GenerateID returns a cryptographically random 32-character hex string.

func SanitizeFilename

func SanitizeFilename(name string) (string, error)

SanitizeFilename normalizes a filename for storage: lowercase, no spaces, no path separators or shell metacharacters, preserves extension.

func ValidateCategory

func ValidateCategory(cat string) error

ValidateCategory checks that a category matches the required pattern.

func ValidateDescription

func ValidateDescription(desc string) error

ValidateDescription checks description length and content.

func ValidateDisplayName

func ValidateDisplayName(name string) error

ValidateDisplayName checks display name length and content.

func ValidateMIMEType

func ValidateMIMEType(mt string) error

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

func ValidateScope(scope Scope, scopeID string) error

ValidateScope checks scope and scope_id consistency.

func ValidateTags

func ValidateTags(tags []string) error

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

type ClaimsExtractor func(r *http.Request) (*Claims, error)

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.

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.

type ParsedURI

type ParsedURI struct {
	Scope   Scope
	ScopeID string
	Path    string
}

ParsedURI holds the components extracted from a resource URI.

func ParseURI

func ParseURI(scheme, uri string) (ParsedURI, error)

ParseURI extracts scope, scopeID, and path from a resource URI. Returns an error if the URI does not match the expected format.

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 Scope

type Scope string

Scope defines the visibility level of a resource.

const (
	// ScopeGlobal is visible to every authenticated user.
	ScopeGlobal Scope = "global"
	// ScopePersona is visible to users operating under the named persona.
	ScopePersona Scope = "persona"
	// ScopeUser is visible only to the owning user.
	ScopeUser Scope = "user"
)

type ScopeFilter

type ScopeFilter struct {
	Scope   Scope
	ScopeID string // empty for global
}

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

func NewPostgresStore(db *sql.DB) Store

NewPostgresStore creates a resource store backed by PostgreSQL.

type Update

type Update struct {
	DisplayName *string  `json:"display_name,omitempty"`
	Description *string  `json:"description,omitempty"`
	Tags        []string `json:"tags,omitempty"`
	Category    *string  `json:"category,omitempty"`
}

Update holds mutable fields for a PATCH operation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL