Reserve Promptkit catalog profile names
This commit is contained in:
@@ -72,6 +72,10 @@ manifest, layout, profile ownership, inheritance, and secret-safety rules
|
|||||||
before returning raw catalog sources. Internal engine assembly uses those validated
|
before returning raw catalog sources. Internal engine assembly uses those validated
|
||||||
catalogs as the maintained lowest-precedence profile source.
|
catalogs as the maintained lowest-precedence profile source.
|
||||||
|
|
||||||
|
Normalized external catalog profile IDs with the exact `promptkit-` prefix are
|
||||||
|
rejected at this adapter boundary. That reservation applies only to imported
|
||||||
|
catalogs; configured consumer sources retain the ordinary profile-ID rules.
|
||||||
|
|
||||||
The overlay repository consults the next repository only when the
|
The overlay repository consults the next repository only when the
|
||||||
higher-precedence repository reports that a profile is absent. A reliably
|
higher-precedence repository reports that a profile is absent. A reliably
|
||||||
selected malformed profile stops fallback, while an unrelated malformed file
|
selected malformed profile stops fallback, while an unrelated malformed file
|
||||||
|
|||||||
@@ -128,6 +128,8 @@ checkouts, workspaces, or replacements.
|
|||||||
|
|
||||||
## Stage 3: Enforce The External Catalog Namespace
|
## Stage 3: Enforce The External Catalog Namespace
|
||||||
|
|
||||||
|
**Completed:** 2026-09-22
|
||||||
|
|
||||||
Repository: Promptkit. Keep current v1 dependencies during this stage;
|
Repository: Promptkit. Keep current v1 dependencies during this stage;
|
||||||
dependency adoption remains atomic in Stage 5.
|
dependency adoption remains atomic in Stage 5.
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ func Load(sources ...Source) (Set, error) {
|
|||||||
}
|
}
|
||||||
resolvingRepository := profile.NewResolvingRepository(repository)
|
resolvingRepository := profile.NewResolvingRepository(repository)
|
||||||
for _, entry := range metadata {
|
for _, entry := range metadata {
|
||||||
|
if strings.HasPrefix(entry.ID, "promptkit-") {
|
||||||
|
return Set{}, fmt.Errorf("catalog %s: %s uses the reserved promptkit- profile ID prefix", source.Name, entry.Path)
|
||||||
|
}
|
||||||
if profileIDs[entry.ID] {
|
if profileIDs[entry.ID] {
|
||||||
return Set{}, fmt.Errorf("catalog %s: %s duplicates an earlier profile ID", source.Name, entry.Path)
|
return Set{}, fmt.Errorf("catalog %s: %s duplicates an earlier profile ID", source.Name, entry.Path)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,6 +193,39 @@ func TestLoadRejectsInvalidCatalogProfiles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadReservesPromptkitProfilePrefixForCatalogs(t *testing.T) {
|
||||||
|
tests := map[string]struct {
|
||||||
|
profileID string
|
||||||
|
wantError bool
|
||||||
|
}{
|
||||||
|
"maintained name": {
|
||||||
|
profileID: "promptkit-openrouter-standard",
|
||||||
|
wantError: true,
|
||||||
|
},
|
||||||
|
"other reserved name": {
|
||||||
|
profileID: "promptkit-example",
|
||||||
|
wantError: true,
|
||||||
|
},
|
||||||
|
"ordinary name": {
|
||||||
|
profileID: "ordinary-profile",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, test := range tests {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
fsys := validCatalogFS("one")
|
||||||
|
fsys["catalog/profiles/one-profile.yml"].Data = []byte(validProfile(test.profileID, "one"))
|
||||||
|
|
||||||
|
_, err := Load(testSource("one", fsys))
|
||||||
|
if (err != nil) != test.wantError {
|
||||||
|
t.Fatalf("Load() error = %v, want error %t", err, test.wantError)
|
||||||
|
}
|
||||||
|
if err != nil && !strings.Contains(err.Error(), "catalog one: one-profile.yml") {
|
||||||
|
t.Fatalf("Load() error = %v, want catalog source and path context", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadRejectsCrossCatalogConflicts(t *testing.T) {
|
func TestLoadRejectsCrossCatalogConflicts(t *testing.T) {
|
||||||
t.Run("duplicate backend", func(t *testing.T) {
|
t.Run("duplicate backend", func(t *testing.T) {
|
||||||
second := catalogFS("one", map[string]string{
|
second := catalogFS("one", map[string]string{
|
||||||
|
|||||||
Reference in New Issue
Block a user