mirror of
https://gitee.com/wanwujie/deer-flow
synced 2026-04-24 22:54:46 +08:00
fix(gateway): allow standard skill frontmatter metadata (#1103)
* fix(gateway): allow standard skill frontmatter metadata Accept standard optional frontmatter fields during .skill installs so external skills with version, author, or compatibility metadata do not fail validation. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * docs: sync skill installer metadata behavior Document the skill install allowlist so user-facing and backend contributor docs match the gateway validation contract. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * Apply suggestions from code review Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> Co-authored-by: Willem Jiang <willem.jiang@gmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -4,7 +4,9 @@ import re
|
||||
import shutil
|
||||
import tempfile
|
||||
import zipfile
|
||||
from collections.abc import Mapping
|
||||
from pathlib import Path
|
||||
from typing import cast
|
||||
|
||||
import yaml
|
||||
from fastapi import APIRouter, HTTPException
|
||||
@@ -57,7 +59,20 @@ class SkillInstallResponse(BaseModel):
|
||||
|
||||
|
||||
# Allowed properties in SKILL.md frontmatter
|
||||
ALLOWED_FRONTMATTER_PROPERTIES = {"name", "description", "license", "allowed-tools", "metadata"}
|
||||
ALLOWED_FRONTMATTER_PROPERTIES = {
|
||||
"name",
|
||||
"description",
|
||||
"license",
|
||||
"allowed-tools",
|
||||
"metadata",
|
||||
"compatibility",
|
||||
"version",
|
||||
"author",
|
||||
}
|
||||
|
||||
|
||||
def _safe_load_frontmatter(frontmatter_text: str) -> object:
|
||||
return cast(object, yaml.safe_load(frontmatter_text))
|
||||
|
||||
|
||||
def _validate_skill_frontmatter(skill_dir: Path) -> tuple[bool, str, str | None]:
|
||||
@@ -86,9 +101,11 @@ def _validate_skill_frontmatter(skill_dir: Path) -> tuple[bool, str, str | None]
|
||||
|
||||
# Parse YAML frontmatter
|
||||
try:
|
||||
frontmatter = yaml.safe_load(frontmatter_text)
|
||||
if not isinstance(frontmatter, dict):
|
||||
parsed_frontmatter = _safe_load_frontmatter(frontmatter_text)
|
||||
if not isinstance(parsed_frontmatter, Mapping):
|
||||
return False, "Frontmatter must be a YAML dictionary", None
|
||||
parsed_frontmatter = cast(Mapping[object, object], parsed_frontmatter)
|
||||
frontmatter: dict[str, object] = {str(key): value for key, value in parsed_frontmatter.items()}
|
||||
except yaml.YAMLError as e:
|
||||
return False, f"Invalid YAML in frontmatter: {e}", None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user