Add scoped identity listings and backend inventory
This commit is contained in:
@@ -94,10 +94,27 @@ type resourceNamespaces struct {
|
||||
}
|
||||
|
||||
type identityInventory interface {
|
||||
ListBackends(context.Context) ([]string, error)
|
||||
ListProfiles(context.Context) ([]string, error)
|
||||
ListPrompts(context.Context) ([]domain.PromptIdentity, error)
|
||||
}
|
||||
|
||||
// ListingFilterMode selects namespace membership for one identity listing.
|
||||
type ListingFilterMode uint8
|
||||
|
||||
const (
|
||||
ListingDefault ListingFilterMode = iota
|
||||
ListingNamed
|
||||
ListingUnqualified
|
||||
ListingAll
|
||||
)
|
||||
|
||||
// ListingFilter optionally overrides the namespace selected by an engine view.
|
||||
type ListingFilter struct {
|
||||
Mode ListingFilterMode
|
||||
Name string
|
||||
}
|
||||
|
||||
// New assembles an engine from facade-selected configuration and collaborators.
|
||||
func New(cfg Config, options Options) (*Engine, error) {
|
||||
defaultRetries, err := domain.ResolveTransientRetries(2, cfg.TransientRetries)
|
||||
@@ -231,12 +248,99 @@ func (e *Engine) InspectProfile(ctx context.Context, id string) (*domain.Profile
|
||||
return e.runner.InspectProfile(ctx, id)
|
||||
}
|
||||
|
||||
func (e *Engine) ListProfiles(ctx context.Context) ([]string, error) {
|
||||
return e.listing.ListProfiles(ctx)
|
||||
func (e *Engine) ListBackends(ctx context.Context, filters ...ListingFilter) ([]string, error) {
|
||||
return filterIdentityList(ctx, filters, e.namespaces.backend, e.listing.ListBackends)
|
||||
}
|
||||
|
||||
func (e *Engine) ListPrompts(ctx context.Context) ([]domain.PromptIdentity, error) {
|
||||
return e.listing.ListPrompts(ctx)
|
||||
func (e *Engine) ListProfiles(ctx context.Context, filters ...ListingFilter) ([]string, error) {
|
||||
return filterIdentityList(ctx, filters, e.namespaces.profile, e.listing.ListProfiles)
|
||||
}
|
||||
|
||||
func (e *Engine) ListPrompts(ctx context.Context, filters ...ListingFilter) ([]domain.PromptIdentity, error) {
|
||||
mode, namespace, err := resolveListingFilter(filters, e.namespaces.prompt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prompts, err := e.listing.ListPrompts(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var filtered []domain.PromptIdentity
|
||||
for _, prompt := range prompts {
|
||||
if matchesListingNamespace(prompt.ID, mode, namespace) {
|
||||
filtered = append(filtered, prompt)
|
||||
}
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
func filterIdentityList(
|
||||
ctx context.Context,
|
||||
filters []ListingFilter,
|
||||
scope string,
|
||||
list func(context.Context) ([]string, error),
|
||||
) ([]string, error) {
|
||||
mode, namespace, err := resolveListingFilter(filters, scope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ids, err := list(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var filtered []string
|
||||
for _, id := range ids {
|
||||
if matchesListingNamespace(id, mode, namespace) {
|
||||
filtered = append(filtered, id)
|
||||
}
|
||||
}
|
||||
if err := ctx.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return filtered, nil
|
||||
}
|
||||
|
||||
func resolveListingFilter(filters []ListingFilter, scope string) (ListingFilterMode, string, error) {
|
||||
if len(filters) > 1 {
|
||||
return 0, "", fmt.Errorf("%w: at most one listing filter is allowed", usecase.ErrInvalidRequest)
|
||||
}
|
||||
filter := ListingFilter{}
|
||||
if len(filters) == 1 {
|
||||
filter = filters[0]
|
||||
}
|
||||
switch filter.Mode {
|
||||
case ListingDefault:
|
||||
if scope == "" {
|
||||
return ListingAll, "", nil
|
||||
}
|
||||
return ListingNamed, scope, nil
|
||||
case ListingNamed:
|
||||
if !domain.IsValidResourceNamespace(filter.Name) {
|
||||
return 0, "", fmt.Errorf("%w: invalid listing namespace", usecase.ErrInvalidRequest)
|
||||
}
|
||||
return ListingNamed, filter.Name, nil
|
||||
case ListingUnqualified, ListingAll:
|
||||
return filter.Mode, "", nil
|
||||
default:
|
||||
return 0, "", fmt.Errorf("%w: unknown listing filter mode", usecase.ErrInvalidRequest)
|
||||
}
|
||||
}
|
||||
|
||||
func matchesListingNamespace(id string, mode ListingFilterMode, namespace string) bool {
|
||||
switch mode {
|
||||
case ListingNamed:
|
||||
idNamespace, _, qualified := strings.Cut(id, "/")
|
||||
return qualified && idNamespace == namespace
|
||||
case ListingUnqualified:
|
||||
return !strings.Contains(id, "/")
|
||||
case ListingAll:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
func (e *Engine) Prepare(ctx context.Context, request domain.RunRequest) (*domain.PreparedRun, error) {
|
||||
request, err := e.qualifyRunRequest(request)
|
||||
|
||||
Reference in New Issue
Block a user