mirror of
https://github.com/iflytek/skillhub.git
synced 2026-08-27 11:14:59 +00:00
Merge pull request #526 from iflytek/feature/add-agentguard-skill
feat(bootstrap): add agentguard builtin skill
This commit is contained in:
commit
05e1968563
5 changed files with 75 additions and 16 deletions
|
|
@ -50,6 +50,7 @@ public class BuiltinSkillInitializer {
|
|||
|
||||
private static final Logger log = LoggerFactory.getLogger(BuiltinSkillInitializer.class);
|
||||
private static final Set<String> SYSTEM_PUBLISHER_ROLES = Set.of("SUPER_ADMIN");
|
||||
private static final boolean CONFIRM_BUILTIN_PUBLISH_WARNINGS = true;
|
||||
|
||||
private final BuiltinSkillProperties properties;
|
||||
private final BuiltinSkillManifestLoader manifestLoader;
|
||||
|
|
@ -243,7 +244,7 @@ public class BuiltinSkillInitializer {
|
|||
SYSTEM_PUBLISHER_ID,
|
||||
SkillVisibility.PUBLIC,
|
||||
SYSTEM_PUBLISHER_ROLES,
|
||||
false
|
||||
CONFIRM_BUILTIN_PUBLISH_WARNINGS
|
||||
);
|
||||
log.info("Published built-in skill slug={} version={} to @{}",
|
||||
item.slug(), item.version(), GLOBAL_NAMESPACE);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@
|
|||
"slug": "skillhub-hello",
|
||||
"version": "1.0.0",
|
||||
"url": "https://bjcdn.openstorage.cn/aicontest/2026-06-11/f8a59af3-30d4-4031-80f6-ebff74b05195.zip"
|
||||
},
|
||||
{
|
||||
"slug": "agentguard",
|
||||
"version": "1.1",
|
||||
"url": "https://bjcdn.openstorage.cn/aicontest/2026-06-12/9d063bc7-223a-4762-adeb-305c268aa29e.zip"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.iflytek.skillhub.bootstrap;
|
|||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.never;
|
||||
|
|
@ -106,7 +107,7 @@ class BuiltinSkillInitializerTest {
|
|||
runInitializer();
|
||||
|
||||
verify(manifestLoader, never()).load();
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -116,7 +117,7 @@ class BuiltinSkillInitializerTest {
|
|||
runInitializer();
|
||||
|
||||
verify(manifestLoader, never()).load();
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -144,7 +145,7 @@ class BuiltinSkillInitializerTest {
|
|||
|
||||
verify(namespaceMemberRepository, never()).save(any());
|
||||
verify(downloader, never()).download(any());
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -162,7 +163,7 @@ class BuiltinSkillInitializerTest {
|
|||
runInitializer();
|
||||
|
||||
verify(downloader, never()).download(any());
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -180,7 +181,7 @@ class BuiltinSkillInitializerTest {
|
|||
runInitializer();
|
||||
|
||||
verify(downloader, never()).download(any());
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -192,7 +193,7 @@ class BuiltinSkillInitializerTest {
|
|||
runInitializer();
|
||||
|
||||
verify(downloader, never()).download(any());
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -206,7 +207,7 @@ class BuiltinSkillInitializerTest {
|
|||
runInitializer();
|
||||
|
||||
verify(downloader).download(URI.create(ITEM.url()));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -222,7 +223,7 @@ class BuiltinSkillInitializerTest {
|
|||
runInitializer();
|
||||
|
||||
verify(downloader, never()).download(any());
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
assertThat(output).doesNotContain("Failed to synchronize built-in skill slug=skillhub-hello");
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +233,7 @@ class BuiltinSkillInitializerTest {
|
|||
|
||||
runInitializer();
|
||||
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -241,7 +242,7 @@ class BuiltinSkillInitializerTest {
|
|||
|
||||
runInitializer();
|
||||
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), eq(false));
|
||||
verify(skillPublishService, never()).publishFromEntries(any(), any(), any(), any(), any(), anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -259,7 +260,7 @@ class BuiltinSkillInitializerTest {
|
|||
eq(PUBLISHER),
|
||||
eq(SkillVisibility.PUBLIC),
|
||||
eq(Set.of("SUPER_ADMIN")),
|
||||
eq(false)
|
||||
eq(true)
|
||||
);
|
||||
assertThat(entriesCaptor.getValue()).isEqualTo(entries);
|
||||
}
|
||||
|
|
@ -297,7 +298,7 @@ class BuiltinSkillInitializerTest {
|
|||
.thenReturn(List.of())
|
||||
.thenReturn(List.of(builtinSkill));
|
||||
when(skillPublishService.publishFromEntries(
|
||||
eq(GLOBAL), any(), eq(PUBLISHER), eq(SkillVisibility.PUBLIC), eq(Set.of("SUPER_ADMIN")), eq(false)))
|
||||
eq(GLOBAL), any(), eq(PUBLISHER), eq(SkillVisibility.PUBLIC), eq(Set.of("SUPER_ADMIN")), eq(true)))
|
||||
.thenThrow(new DomainBadRequestException("error.skill.version.exists", "1.0.0"));
|
||||
when(skillVersionRepository.findBySkillIdAndVersion(100L, "1.0.0")).thenReturn(Optional.of(published));
|
||||
when(skillFileRepository.findByVersionId(200L)).thenReturn(skillFilesFor(entries, 200L));
|
||||
|
|
@ -305,7 +306,7 @@ class BuiltinSkillInitializerTest {
|
|||
runInitializer();
|
||||
|
||||
verify(skillPublishService).publishFromEntries(
|
||||
eq(GLOBAL), any(), eq(PUBLISHER), eq(SkillVisibility.PUBLIC), eq(Set.of("SUPER_ADMIN")), eq(false));
|
||||
eq(GLOBAL), any(), eq(PUBLISHER), eq(SkillVisibility.PUBLIC), eq(Set.of("SUPER_ADMIN")), eq(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -318,7 +319,7 @@ class BuiltinSkillInitializerTest {
|
|||
.thenReturn(List.of())
|
||||
.thenReturn(List.of(builtinSkill));
|
||||
when(skillPublishService.publishFromEntries(
|
||||
eq(GLOBAL), any(), eq(PUBLISHER), eq(SkillVisibility.PUBLIC), eq(Set.of("SUPER_ADMIN")), eq(false)))
|
||||
eq(GLOBAL), any(), eq(PUBLISHER), eq(SkillVisibility.PUBLIC), eq(Set.of("SUPER_ADMIN")), eq(true)))
|
||||
.thenThrow(new DomainBadRequestException("error.skill.version.exists", "1.0.0"));
|
||||
when(skillVersionRepository.findBySkillIdAndVersion(100L, "1.0.0")).thenReturn(Optional.of(published));
|
||||
when(skillFileRepository.findByVersionId(200L)).thenReturn(List.of(
|
||||
|
|
@ -329,7 +330,7 @@ class BuiltinSkillInitializerTest {
|
|||
|
||||
verify(skillFileRepository).findByVersionId(200L);
|
||||
verify(skillPublishService).publishFromEntries(
|
||||
eq(GLOBAL), any(), eq(PUBLISHER), eq(SkillVisibility.PUBLIC), eq(Set.of("SUPER_ADMIN")), eq(false));
|
||||
eq(GLOBAL), any(), eq(PUBLISHER), eq(SkillVisibility.PUBLIC), eq(Set.of("SUPER_ADMIN")), eq(true));
|
||||
assertThat(output).contains("Failed to publish built-in skill slug=skillhub-hello version=1.0.0");
|
||||
assertThat(output).doesNotContain("was published concurrently, skipping");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ public class SkillMetadataParser {
|
|||
String name = extractRequiredField(frontmatter, "name");
|
||||
String description = extractRequiredField(frontmatter, "description");
|
||||
String version = extractOptionalField(frontmatter, "version");
|
||||
if (version == null) {
|
||||
version = extractNestedOptionalField(frontmatter, "metadata", "version");
|
||||
}
|
||||
|
||||
return new SkillMetadata(name, description, version, body, frontmatter);
|
||||
}
|
||||
|
|
@ -122,4 +125,13 @@ public class SkillMetadataParser {
|
|||
Object value = frontmatter.get(fieldName);
|
||||
return value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
private String extractNestedOptionalField(Map<String, Object> frontmatter, String objectFieldName, String fieldName) {
|
||||
Object nestedValue = frontmatter.get(objectFieldName);
|
||||
if (!(nestedValue instanceof Map<?, ?> nestedMap)) {
|
||||
return null;
|
||||
}
|
||||
Object value = nestedMap.get(fieldName);
|
||||
return value == null ? null : value.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,6 +123,46 @@ class SkillMetadataParserTest {
|
|||
assertNull(metadata.version());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUsesMetadataVersionWhenTopLevelVersionIsMissing() {
|
||||
String content = """
|
||||
---
|
||||
name: agentguard
|
||||
description: Agent security guard
|
||||
metadata:
|
||||
author: GoPlusSecurity
|
||||
version: "1.1"
|
||||
---
|
||||
Body
|
||||
""";
|
||||
|
||||
SkillMetadata metadata = parser.parse(content);
|
||||
|
||||
assertEquals("agentguard", metadata.name());
|
||||
assertEquals("Agent security guard", metadata.description());
|
||||
assertEquals("1.1", metadata.version());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTopLevelVersionTakesPrecedenceOverMetadataVersion() {
|
||||
String content = """
|
||||
---
|
||||
name: versioned-skill
|
||||
description: Prefer top-level version
|
||||
version: 2.0.0
|
||||
metadata:
|
||||
version: "1.1"
|
||||
---
|
||||
Body
|
||||
""";
|
||||
|
||||
SkillMetadata metadata = parser.parse(content);
|
||||
|
||||
assertEquals("versioned-skill", metadata.name());
|
||||
assertEquals("Prefer top-level version", metadata.description());
|
||||
assertEquals("2.0.0", metadata.version());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFallsBackToLooseFrontmatterParsingWhenYamlSyntaxIsNotStrict() {
|
||||
String content = """
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue