fix(skills): vendor the support files the vendored skills point at

The vendored SKILL.md files were byte-identical to upstream, but the
playbooks, templates and schemas they reference were left behind in the
original repos, so a loading skill pointed at a file that does not exist
anywhere in this repository.

Vendored 1:1 into each skill directory (so they survive
`cp -r skills/* ~/.hermes/skills/`):

- plays/ for api-security-review, code-review-security, sca-audit,
  secrets-scan, web-security-review (OWASP/secure-agent-playbook)
- templates/finding.md for the four OWASP skills that cite it
- schemas/finding.schema.json for cve-triage, patch-prioritization,
  dependency-scanning (UnitOneAI/SecuritySkills)
- docs/sarif-output.md, docs/fixer-policy.md and
  docs/normalized-json-output.md for dependency-scanning

Path fixes, the only edit to vendored text:
- the three UnitOneAI skills referenced ../../../schemas/ and ../../../docs/
  which assumed upstream's skills/<category>/<skill>/ depth; this repo is
  flat, so the links now resolve inside the skill directory
- safedeps told the agent to run <skill_dir>/../../check_deps.py while the
  script is vendored next to SKILL.md; corrected to <skill_dir>/check_deps.py
  and documented the script's exit codes (1 = finding, not a crash)
- NOTICE.md records the new files, the path edits, and the remaining known
  gaps (hermaguard's kensei-pipeline references, the ASVS dataset citations,
  and hermaguard being behind upstream)

Verified: every backticked path in every SKILL.md now resolves;
check_deps.py runs from the installed location and returns live OSV.dev
data ([email protected] -> 2 advisories); hermaguard's 46 tests still pass.
This commit is contained in:
Evandro Fonseca Junior committed 2026-09-14 07:40:21 -03:00
1 parent eba8bb1d94
commit bb3fe21766
20 files changed
+4156 -11

No files matched your search

@@ -0,0 +1,229 @@
# SARIF Output Mapping
SecuritySkills may emit SARIF-compatible JSON for tools that ingest Static
Analysis Results Interchange Format (SARIF) 2.1.0. SARIF output is an export
view of the normalized finding envelope documented in
[`docs/normalized-json-output.md`](normalized-json-output.md); it does not
replace the normalized JSON contract or change the required finding fields.
## Top-Level Shape
Use SARIF version `2.1.0` with the standard schema URI:
```json
{
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "SecuritySkills",
"semanticVersion": "1.0.0",
"rules": []
}
},
"results": []
}
]
}
```
Use one `run` per normalized envelope. `run.tool.driver.name` should identify
SecuritySkills or the executing agent. `run.tool.driver.semanticVersion` should
use the skill version when a single skill produced the run.
## Mapping
Map normalized fields to SARIF as follows:
| Normalized field | SARIF field |
|---|---|
| `run.id`, `run.timestamp`, `run.target`, `run.source_ref` | `runs[].properties.securityskills.run` |
| `skill.name`, `skill.version`, `skill.path`, `skill.frameworks` | `runs[].tool.driver.name`, `runs[].tool.driver.semanticVersion`, `runs[].properties.securityskills.skill` |
| `finding.id` | `results[].ruleId` and `results[].properties.securityskills.finding_id` |
| `finding.fingerprint` | `results[].partialFingerprints.securityskillsFingerprint` |
| `finding.title` | `tool.driver.rules[].shortDescription.text` |
| `finding.description` | `tool.driver.rules[].fullDescription.text` and `results[].message.text` |
| `finding.severity` | `results[].level` |
| `finding.status` | `results[].properties.securityskills.status` |
| `finding.cwe` | `tool.driver.rules[].relationships` when supported, and `properties.securityskills.cwe` |
| `finding.framework_refs` | `tool.driver.rules[].properties.securityskills.framework_refs` |
| `finding.evidence` | `results[].locations` plus `properties.securityskills.evidence` |
| `finding.references` | `tool.driver.rules[].helpUri` or `tool.driver.rules[].properties.securityskills.references` |
| `finding.remediations` | `tool.driver.rules[].help.text` and `properties.securityskills.remediations`, including each remediation's `test_strategy` |
## Severity
SARIF `level` has fewer values than the normalized contract. Use this mapping:
| Normalized severity | SARIF level |
|---|---|
| `critical` | `error` |
| `high` | `error` |
| `medium` | `warning` |
| `low` | `note` |
| `info` | `note` |
Keep the original severity in
`results[].properties.securityskills.severity` so downstream systems can
preserve the distinction between `critical` and `high`.
## Locations
For source, configuration, policy, or scan-result evidence with file locations,
populate `results[].locations[].physicalLocation`:
```json
{
"physicalLocation": {
"artifactLocation": {
"uri": "routes/users.js"
},
"region": {
"startLine": 42
}
},
"message": {
"text": "DELETE /users/:id checks authentication but not administrator role."
}
}
```
If the normalized evidence location does not contain a parseable file path and
line number, still emit a SARIF result and store the original location under
`properties.securityskills.evidence`. For cloud resources, identities, network
assets, logs, or documents, use the best stable asset identifier as
`artifactLocation.uri` only when it is meaningful to the SARIF consumer.
## Rules
Create one `tool.driver.rules[]` entry per distinct `ruleId`. A rule should
include:
- `id`: the normalized `finding.id`, or a stable detector ID when multiple
findings share the same detection rule.
- `shortDescription.text`: the finding title or detector title.
- `fullDescription.text`: the finding description.
- `help.text`: remediation guidance and test strategy summary.
- `properties.securityskills`: CWE IDs, framework references, normalized
severity, and any remediation metadata that does not fit native SARIF fields.
Do not invent CWE, framework, or control identifiers for SARIF. Reuse only the
values already present in the normalized finding.
## Minimal Example
```json
{
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "api-security",
"semanticVersion": "1.0.0",
"rules": [
{
"id": "API-SEC-001",
"shortDescription": {
"text": "Administrative endpoint lacks authorization check"
},
"fullDescription": {
"text": "The delete-user route accepts authenticated requests without verifying administrative privileges."
},
"help": {
"text": "Require an administrator role check before invoking deleteUser. Validate with integration tests for non-admin and admin delete flows."
},
"properties": {
"securityskills": {
"severity": "high",
"cwe": ["CWE-862"],
"framework_refs": [
{
"framework": "OWASP-API-Top-10-2023",
"control": "API5:2023",
"name": "Broken Function Level Authorization"
}
]
}
}
}
]
}
},
"results": [
{
"ruleId": "API-SEC-001",
"level": "error",
"message": {
"text": "Administrative endpoint lacks authorization check"
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "routes/users.js"
},
"region": {
"startLine": 42
}
},
"message": {
"text": "DELETE /users/:id checks authentication but not administrator role."
}
}
],
"partialFingerprints": {
"securityskillsFingerprint": "api-security:users-delete:missing-admin-auth"
},
"properties": {
"securityskills": {
"finding_id": "API-SEC-001",
"severity": "high",
"status": "open",
"remediations": [
{
"guidance": "Require an administrator role check before invoking deleteUser.",
"confidence": "high",
"blast_radius": "User administration routes only.",
"behavior_change_risk": "medium",
"test_strategy": {
"summary": "Proves non-admin users cannot delete accounts while admins still can.",
"recommended_tests": [
{
"name": "Reject non-admin delete",
"type": "integration",
"purpose": "Confirms the authorization bypass no longer succeeds.",
"command": "npm test -- users-authz.test.js",
"expected_result": "Non-admin DELETE returns 403 and admin DELETE succeeds."
}
]
}
}
]
}
}
}
],
"properties": {
"securityskills": {
"run": {
"id": "run-001",
"timestamp": "2026-06-16T12:00:00Z",
"target": "payments-api",
"source_ref": "abc1234"
},
"skill": {
"name": "api-security",
"version": "1.0.0",
"path": "skills/appsec/api-security/SKILL.md",
"frameworks": ["OWASP-API-Top-10-2023", "CWE"]
}
}
}
}
]
}
```