387b640249
Fix pre-existing lint, typecheck, and security failures that were
blocking the PR from passing CI:
- Fix E501 line-too-long in session_service.py (remove erroneous
"sha256:" string prefix from dict comprehension on line 268)
- Fix W293 trailing whitespace in tool.py line 249
- Fix typecheck error in session_service.py: data.get("checksum")
can return None, remove invalid string concatenation
- Fix typecheck error in schema.py: add explicit dict[str, Any]
type annotation for wrapper variable to resolve str|None issue
- Fix vulture false positive: add "destination" Protocol parameter
to vulture_whitelist.py
- Fix @tdd_issue/@tdd_issue_1472 tag placement in skill_schema.feature
(remove blank line between tags and scenario)
- Add @tdd_issue/@tdd_issue_1472 tags to all new wrapper key scenarios
- Add Robot integration test for spec-compliant skill: wrapper YAML
373 lines
18 KiB
Gherkin
373 lines
18 KiB
Gherkin
Feature: Skill YAML schema validation
|
|
As a CleverAgents user
|
|
I want to define skills via YAML configuration files
|
|
So that I can create validated, reusable tool collections
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# Valid schema scenarios
|
|
# ────────────────────────────────────────────────────────────
|
|
|
|
Scenario: Load a minimal valid skill YAML (name only)
|
|
Given a skill YAML string with only the name field
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config name should be "local/empty-skill"
|
|
|
|
Scenario: Load a skill YAML with tool references
|
|
Given a skill YAML string with tool references
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config name should be "local/file-reader"
|
|
And the skill config should have 3 tools
|
|
|
|
Scenario: Load a skill YAML with all sections populated
|
|
Given a skill YAML string with all sections populated
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config name should be "local/full-skill"
|
|
And the skill config description should be "A fully populated skill"
|
|
And the skill config should have 2 tools
|
|
And the skill config should have 1 inline tools
|
|
And the skill config should have 1 includes
|
|
And the skill config should have 1 mcp servers
|
|
And the skill config should have 1 agent skill folders
|
|
|
|
Scenario: Load the single-tool example YAML
|
|
Given the skill YAML file "examples/skills/single-tool.yaml"
|
|
When I validate the skill schema from file
|
|
Then the skill schema validation should succeed
|
|
|
|
Scenario: Load the composed example YAML
|
|
Given the skill YAML file "examples/skills/composed.yaml"
|
|
When I validate the skill schema from file
|
|
Then the skill schema validation should succeed
|
|
|
|
Scenario: Load the inline-tool example YAML
|
|
Given the skill YAML file "examples/skills/inline-tool.yaml"
|
|
When I validate the skill schema from file
|
|
Then the skill schema validation should succeed
|
|
|
|
Scenario: Load the validation-only example YAML
|
|
Given the skill YAML file "examples/skills/validation-only.yaml"
|
|
When I validate the skill schema from file
|
|
Then the skill schema validation should succeed
|
|
|
|
Scenario: Load the mcp-backed example YAML
|
|
Given the skill YAML file "examples/skills/mcp-backed.yaml"
|
|
When I validate the skill schema from file
|
|
Then the skill schema validation should succeed
|
|
|
|
Scenario: Optional fields have correct defaults when omitted
|
|
Given a skill YAML string with only the name field
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config tools list should be empty
|
|
And the skill config inline_tools list should be empty
|
|
And the skill config includes list should be empty
|
|
And the skill config mcp_servers list should be empty
|
|
And the skill config agent_skill_folders list should be empty
|
|
|
|
Scenario: Tool reference with override fields
|
|
Given a skill YAML string with tool overrides
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And skill tool 0 name should be "builtin/shell_execute"
|
|
And skill tool 0 description should be "Execute commands in sandbox"
|
|
And skill tool 0 writes should be true
|
|
And skill tool 0 checkpointable should be false
|
|
|
|
Scenario: Inline tool with all fields
|
|
Given a skill YAML string with a full inline tool
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And skill inline tool 0 name should be "run_migrations"
|
|
And skill inline tool 0 source should be "custom"
|
|
And skill inline tool 0 writes should be true
|
|
And skill inline tool 0 checkpointable should be true
|
|
|
|
Scenario: MCP server with stdio transport
|
|
Given a skill YAML string with a stdio MCP server
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And skill mcp server 0 name should be "github"
|
|
And skill mcp server 0 transport should be "stdio"
|
|
And skill mcp server 0 command should be "npx"
|
|
|
|
Scenario: MCP server with SSE transport
|
|
Given a skill YAML string with an SSE MCP server
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And skill mcp server 0 transport should be "sse"
|
|
And skill mcp server 0 url should be "https://mcp.example.com/sse"
|
|
|
|
Scenario: MCP server with tool filter
|
|
Given a skill YAML string with MCP tool filter
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And skill mcp server 0 tool filter include should have 2 items
|
|
And skill mcp server 0 tool filter exclude should have 1 items
|
|
|
|
Scenario: Agent skill folder entries
|
|
Given a skill YAML string with agent skill folders
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config should have 2 agent skill folders
|
|
And skill agent folder 0 path should be "./skills/deploy"
|
|
And skill agent folder 1 name should be "code-review"
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# Invalid schema scenarios
|
|
# ────────────────────────────────────────────────────────────
|
|
|
|
Scenario: Missing name field produces a clear error
|
|
Given a skill YAML string missing the name field
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "name"
|
|
|
|
Scenario: Invalid namespaced name without slash
|
|
Given a skill YAML string with name "invalid-name-no-slash"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Accept skill with server-qualified name
|
|
Given a skill YAML string with name "dev:freemo/custom-skill"
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
|
|
Scenario: Accept skill with server-qualified name using cleverthis server
|
|
Given a skill YAML string with name "cleverthis:local/my-skill"
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
|
|
Scenario: Reject skill with server-qualified name but multiple slashes
|
|
Given a skill YAML string with name "dev:namespace/sub/skill"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Invalid namespaced name with special characters
|
|
Given a skill YAML string with name "local/bad name!!"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Uppercase namespace is rejected by SkillConfigSchema
|
|
Given a skill YAML string with name "MyOrg/my-skill"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Uppercase name part is rejected by SkillConfigSchema
|
|
Given a skill YAML string with name "myorg/MySkill"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Fully uppercase namespaced name is rejected by SkillConfigSchema
|
|
Given a skill YAML string with name "MyOrg/MySkill"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Uppercase tool reference name is rejected by SkillToolRefSchema
|
|
Given a skill YAML string with an invalid tool ref name "MyOrg/MyTool"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Uppercase include name is rejected by SkillIncludeSchema
|
|
Given a skill YAML string with an invalid include name "MyOrg/MySkill"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Invalid tool reference name
|
|
Given a skill YAML string with an invalid tool ref name "no-slash-tool"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Inline tool missing source field
|
|
Given a skill YAML string with an inline tool missing source
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "source"
|
|
|
|
Scenario: Inline tool missing code field
|
|
Given a skill YAML string with an inline tool missing code
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "code"
|
|
|
|
Scenario: Inline tool with invalid source value
|
|
Given a skill YAML string with an inline tool source "plugin"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "custom"
|
|
|
|
Scenario: Invalid include name
|
|
Given a skill YAML string with an invalid include name "bad-include"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "namespace/name"
|
|
|
|
Scenario: Invalid MCP transport value
|
|
Given a skill YAML string with MCP transport "grpc"
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "transport"
|
|
|
|
Scenario: MCP server missing transport field
|
|
Given a skill YAML string with MCP server missing transport
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "transport"
|
|
|
|
Scenario: Agent skill folder missing path
|
|
Given a skill YAML string with agent folder missing path
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "path"
|
|
|
|
Scenario: Extra unknown field is rejected
|
|
Given a skill YAML string with an unknown top-level field
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "extra"
|
|
|
|
Scenario: None YAML string raises ValueError
|
|
Given a None skill YAML string
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "None"
|
|
|
|
Scenario: Empty YAML string raises ValueError
|
|
Given an empty skill YAML string
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "empty"
|
|
|
|
Scenario: YAML that is a list instead of a mapping
|
|
Given a skill YAML string that is a list
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "mapping"
|
|
|
|
Scenario: None file path raises ValueError
|
|
Given a None skill YAML file path
|
|
When I validate the skill schema from file expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "None"
|
|
|
|
Scenario: Non-existent file raises FileNotFoundError
|
|
Given the skill YAML file "examples/skills/nonexistent.yaml"
|
|
When I validate the skill schema from file expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "not found"
|
|
|
|
Scenario: Directory path raises ValueError
|
|
Given the skill YAML directory path "examples/skills"
|
|
When I validate the skill schema from file expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "not a file"
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# Key normalization scenarios
|
|
# ────────────────────────────────────────────────────────────
|
|
|
|
Scenario: camelCase keys are normalized to snake_case
|
|
Given a skill YAML string with camelCase keys
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config should have 1 inline tools
|
|
And the skill config should have 1 mcp servers
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# Environment variable interpolation
|
|
# ────────────────────────────────────────────────────────────
|
|
|
|
Scenario: Environment variable interpolation in YAML values
|
|
Given the environment variable "TEST_MCP_CMD" is set to "npx"
|
|
And a skill YAML string using env var "${TEST_MCP_CMD}" for mcp command
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And skill mcp server 0 command should be "npx"
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# Round-trip serialization
|
|
# ────────────────────────────────────────────────────────────
|
|
|
|
Scenario: Schema model serializes to dict correctly
|
|
Given a skill YAML string with all sections populated
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config model_dump should contain key "name"
|
|
And the skill config model_dump should contain key "tools"
|
|
And the skill config model_dump should contain key "inline_tools"
|
|
And the skill config model_dump should contain key "includes"
|
|
And the skill config model_dump should contain key "mcp_servers"
|
|
And the skill config model_dump should contain key "agent_skill_folders"
|
|
|
|
|
|
# ────────────────────────────────────────────────────────────
|
|
# skill: wrapper key scenarios
|
|
# ────────────────────────────────────────────────────────────
|
|
@tdd_issue
|
|
@tdd_issue_1472
|
|
Scenario: Load spec-compliant YAML with skill: wrapper key
|
|
Given a spec-compliant skill YAML with skill: wrapper key
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config name should be "local/wrapped-skill"
|
|
And the skill config should have 1 tools
|
|
|
|
@tdd_issue
|
|
@tdd_issue_1472
|
|
Scenario: Load spec-compliant YAML with cleveragents: header and skill: wrapper
|
|
Given a spec-compliant skill YAML with cleveragents: header and skill: wrapper
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config name should be "local/wrapped-with-meta"
|
|
|
|
@tdd_issue
|
|
@tdd_issue_1472
|
|
Scenario: skill: wrapper key with None value raises ValueError
|
|
Given a skill YAML with skill: wrapper key with None value
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "empty"
|
|
|
|
@tdd_issue
|
|
@tdd_issue_1472
|
|
Scenario: skill: wrapper key with non-dict value raises ValueError
|
|
Given a skill YAML with skill: wrapper key and string value
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "mapping"
|
|
|
|
@tdd_issue
|
|
@tdd_issue_1472
|
|
Scenario: skill: wrapper key with list value raises ValueError
|
|
Given a skill YAML with skill: wrapper key and list value
|
|
When I validate the skill schema expecting failure
|
|
Then the skill schema validation should fail
|
|
And the skill schema error should mention "mapping"
|
|
|
|
@tdd_issue
|
|
@tdd_issue_1472
|
|
Scenario: Flat YAML without wrapper key still works (backward compatibility)
|
|
Given a skill YAML string with only the name field
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config name should be "local/empty-skill"
|
|
|
|
@tdd_issue
|
|
@tdd_issue_1472
|
|
Scenario: cleveragents: header alone (flat format with metadata, no skill: wrapper)
|
|
Given a skill YAML with cleveragents: header and flat format
|
|
When I validate the skill schema
|
|
Then the skill schema validation should succeed
|
|
And the skill config name should be "local/flat-with-meta"
|