Support in-segment wildcards in ACL patterns (test*, test-*).
`*` was not escaped before being converted to `[^/]*`, so patterns like `test*` compiled to a broken regex. Escape `*` and `?` so partial segment wildcards match as documented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
89c6cbb5ad
commit
c7dad0ed0c
4 files changed
+9
-4
No files matched your search
@@ -96,6 +96,8 @@ ACL 패턴 예:
|
|||||||
- `demo/app` — 정확한 저장소
|
- `demo/app` — 정확한 저장소
|
||||||
- `demo/*` — 한 단계 하위
|
- `demo/*` — 한 단계 하위
|
||||||
- `team/**` — 하위 전체
|
- `team/**` — 하위 전체
|
||||||
|
- `test*`, `test-*` — 해당 접두사로 시작하는 최상위 저장소 (`/`는 넘지 않음)
|
||||||
|
- `team/app-*` — 세그먼트 안 부분 와일드카드
|
||||||
- `*` — 모든 저장소
|
- `*` — 모든 저장소
|
||||||
|
|
||||||
## 이미지 삭제
|
## 이미지 삭제
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ const aclPatterns = [
|
|||||||
{ pattern: 'demo/app', description: '정확한 저장소' },
|
{ pattern: 'demo/app', description: '정확한 저장소' },
|
||||||
{ pattern: 'demo/*', description: 'demo 아래 한 단계' },
|
{ pattern: 'demo/*', description: 'demo 아래 한 단계' },
|
||||||
{ pattern: 'team/**', description: 'team 아래 전체' },
|
{ pattern: 'team/**', description: 'team 아래 전체' },
|
||||||
|
{ pattern: 'test*', description: 'test로 시작하는 최상위 저장소 (test, test-app 등)' },
|
||||||
|
{ pattern: 'team/app-*', description: 'team 아래 app-로 시작하는 저장소' },
|
||||||
{ pattern: '*', description: '모든 저장소' },
|
{ pattern: '*', description: '모든 저장소' },
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
@@ -162,7 +162,7 @@
|
|||||||
<Input
|
<Input
|
||||||
v-model="acl.repository"
|
v-model="acl.repository"
|
||||||
class="font-mono"
|
class="font-mono"
|
||||||
placeholder="예: demo/* 또는 library/nginx"
|
placeholder="예: demo/*, test-*, library/nginx"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<Button variant="ghost" size="icon" type="button" @click="form.acls.splice(idx, 1)">
|
<Button variant="ghost" size="icon" type="button" @click="form.acls.splice(idx, 1)">
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* Glob-like repository matching:
|
* Glob-like repository matching:
|
||||||
* - exact match
|
* - exact match
|
||||||
* - `*` matches a single path segment (no `/`)
|
* - `*` matches within a single path segment (no `/`), so `test*`,
|
||||||
* - `**` matches any remaining path
|
* `test-*` and `team/app-*` work as prefix/suffix wildcards
|
||||||
|
* - `**` as a whole segment matches any remaining path
|
||||||
*/
|
*/
|
||||||
export function matchRepository(pattern: string, repository: string): boolean {
|
export function matchRepository(pattern: string, repository: string): boolean {
|
||||||
if (pattern === '*' || pattern === '**') return true
|
if (pattern === '*' || pattern === '**') return true
|
||||||
if (pattern === repository) return true
|
if (pattern === repository) return true
|
||||||
|
|
||||||
const escapeRegex = (s: string) => s.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
const escapeRegex = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||||
const regexSource = pattern
|
const regexSource = pattern
|
||||||
.split('/')
|
.split('/')
|
||||||
.map((segment) => {
|
.map((segment) => {
|
||||||
|
|||||||
Reference in new issue
Block a user