Compose brings up registry:3 plus a Prisma/SQLite Nuxt app for docker login, ACL management, and image browsing with shadcn-vue. Co-authored-by: Cursor <cursoragent@cursor.com>
42 lines
1.2 KiB
TypeScript
42 lines
1.2 KiB
TypeScript
/**
|
|
* Glob-like repository matching:
|
|
* - exact match
|
|
* - `*` matches a single path segment (no `/`)
|
|
* - `**` matches any remaining path
|
|
*/
|
|
export function matchRepository(pattern: string, repository: string): boolean {
|
|
if (pattern === '*' || pattern === '**') return true
|
|
if (pattern === repository) return true
|
|
|
|
const escapeRegex = (s: string) => s.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
const regexSource = pattern
|
|
.split('/')
|
|
.map((segment) => {
|
|
if (segment === '**') return '(.+)'
|
|
if (segment === '*') return '([^/]+)'
|
|
return escapeRegex(segment).replace(/\\\*/g, '[^/]*')
|
|
})
|
|
.join('/')
|
|
|
|
return new RegExp(`^${regexSource}$`).test(repository)
|
|
}
|
|
|
|
export type Action = 'pull' | 'push' | 'delete' | '*'
|
|
|
|
export function actionsFromAcl(acl: {
|
|
canPull: boolean
|
|
canPush: boolean
|
|
canDelete: boolean
|
|
}): Action[] {
|
|
const actions: Action[] = []
|
|
if (acl.canPull) actions.push('pull')
|
|
if (acl.canPush) actions.push('push')
|
|
if (acl.canDelete) actions.push('delete')
|
|
return actions
|
|
}
|
|
|
|
export function intersectActions(requested: string[], allowed: string[]): string[] {
|
|
if (allowed.includes('*')) return requested
|
|
return requested.filter((a) => allowed.includes(a) || (a === '*' && allowed.length > 0))
|
|
}
|