7 Commits

Author SHA1 Message Date
mukul975 673da1f3b0 Fix validator: register hardware-firmware-security subdomain, skip .bak dirs
- Add hardware-firmware-security as a canonical subdomain (folding in the
  firmware-analysis/firmware-security aliases). The 4 new hardware/firmware
  skills failed validation because the subdomain was not in the allowed set.
- Skip skills/*.bak/ backup directories in --all mode; they have no SKILL.md
  and were producing 21 false failures.
- Result: validate-skill.py --all now reports 817/817 passing, exit 0.
2026-06-26 16:37:35 +02:00
mukul975 1f5cb12ac0 chore: auto-update index.json and skill count 2026-06-26 14:06:13 +00:00
Mahipal f3a472b105 Merge pull request #85 from nyxst4ck/nyxst4ck/auto-quote-pip-extras-20260621-091605
docs: quote pip extras install examples
2026-06-26 16:06:02 +02:00
Mahipal 4e165f9a8d Merge pull request #87 from ioxoi/fix/validator-and-disclaimers
Fix validator nested-name misparse (94 false fails), unify with CI, add authorized-use banner
2026-06-26 16:05:40 +02:00
mukul975 768ca51c8d chore: bump plugin version to v1.3.0 2026-06-22 17:11:46 +00:00
Homan Ansari 5f5edbb30b Fix validator nested-name misparse, unify with CI, add authorized-use banner
Issues found in review:

1. tools/validate-skill.py: parse_frontmatter operated on the stripped line, so
   an indented nested `name:` (under framework-mapping lists, e.g.
   `name: 'Create Fake Materials: Fake Website'`) clobbered the skill's
   top-level `name`. That produced 94 spurious "invalid kebab-case name"
   failures out of 762. Now indented (non-list) key lines are ignored, so only
   top-level keys define frontmatter fields. Result: 762/762 pass.

2. Two divergent validators: the CI workflow had its own weaker inline parser
   (no subdomain/tag/description checks) requiring a different field set than
   tools/validate-skill.py. CI now delegates to tools/validate-skill.py --all
   (single source of truth); REQUIRED_FIELDS aligned to include
   version/author/license. The duplicate-name and stats steps are unchanged.

3. README: added an explicit authorized-&-lawful-use disclaimer next to the
   existing "not affiliated with Anthropic" note, since the library ships
   offensive/dual-use techniques.

No skill content changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:09:19 +02:00
nyxst4ck 40869a8c1c docs: quote pip extras install examples 2026-06-21 09:16:20 -03:00
7 changed files with 33 additions and 61 deletions
+2 -2
View File
@@ -6,14 +6,14 @@
}, },
"metadata": { "metadata": {
"description": "817 cybersecurity skills for AI agents mapped to 6 frameworks: MITRE ATT&CK, NIST CSF 2.0, MITRE ATLAS, D3FEND, NIST AI RMF, and the MITRE Fight Fraud Framework (F3).", "description": "817 cybersecurity skills for AI agents mapped to 6 frameworks: MITRE ATT&CK, NIST CSF 2.0, MITRE ATLAS, D3FEND, NIST AI RMF, and the MITRE Fight Fraud Framework (F3).",
"version": "1.2.0" "version": "1.3.0"
}, },
"plugins": [ "plugins": [
{ {
"name": "cybersecurity-skills", "name": "cybersecurity-skills",
"source": "./", "source": "./",
"description": "817 cybersecurity skills covering web security, pentesting, DFIR, threat intelligence, cloud security, malware analysis, and more. Mapped to 6 frameworks.", "description": "817 cybersecurity skills covering web security, pentesting, DFIR, threat intelligence, cloud security, malware analysis, and more. Mapped to 6 frameworks.",
"version": "1.2.0", "version": "1.3.0",
"author": { "author": {
"name": "mukul975" "name": "mukul975"
}, },
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"name": "cybersecurity-skills", "name": "cybersecurity-skills",
"description": "817 cybersecurity skills covering web security, pentesting, DFIR, threat intelligence, cloud security, malware analysis, and more.", "description": "817 cybersecurity skills covering web security, pentesting, DFIR, threat intelligence, cloud security, malware analysis, and more.",
"version": "1.2.0" "version": "1.3.0"
} }
+5 -51
View File
@@ -15,57 +15,11 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Validate SKILL.md frontmatter with Python # Single source of truth: tools/validate-skill.py validates required
run: | # frontmatter fields, kebab-case name, description length, subdomain, and
python3 << 'EOF' # tag count. (Previously this step duplicated a weaker inline parser.)
import os - name: Validate SKILL.md frontmatter
import re run: python3 tools/validate-skill.py --all
import sys
REQUIRED_FIELDS = ['name', 'description', 'domain', 'subdomain', 'tags', 'version', 'author', 'license']
errors = []
checked = 0
for root, dirs, files in os.walk('skills'):
for file in files:
if file == 'SKILL.md':
path = os.path.join(root, file)
checked += 1
with open(path, 'r', encoding='utf-8') as f:
content = f.read()
# Check frontmatter exists
fm_match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
if not fm_match:
errors.append(f"{path}: Missing YAML frontmatter")
continue
fm = fm_match.group(1)
# Check required fields
for field in REQUIRED_FIELDS:
if not re.search(rf'^{field}:', fm, re.MULTILINE):
errors.append(f"{path}: Missing required field '{field}'")
# Check name format (kebab-case)
name_match = re.search(r'^name:\s*(.+)$', fm, re.MULTILINE)
if name_match:
name = name_match.group(1).strip().strip('"')
if not re.match(r'^[a-z0-9-]+$', name):
errors.append(f"{path}: Name '{name}' must be kebab-case")
if len(name) > 64:
errors.append(f"{path}: Name '{name}' exceeds 64 characters")
print(f"Checked {checked} SKILL.md files")
if errors:
print(f"\n{len(errors)} validation error(s):")
for e in errors:
print(f" ❌ {e}")
sys.exit(1)
else:
print(f"✅ All {checked} skills valid")
EOF
- name: Check for duplicate skill names - name: Check for duplicate skill names
run: | run: |
+2
View File
@@ -33,6 +33,8 @@
--- ---
> ⚠️ **Community Project** — This is an independent, community-created project. Not affiliated with Anthropic PBC. > ⚠️ **Community Project** — This is an independent, community-created project. Not affiliated with Anthropic PBC.
>
> 🔐 **Authorized & lawful use only.** This library includes offensive and dual-use techniques (e.g. red-team C2, phishing simulation, exploitation) intended for **authorized penetration testing, security research, defense, and education**. Only use them against systems you own or have **explicit written permission** to test, and comply with all applicable laws and rules of engagement. You are solely responsible for how you use these skills. See [SECURITY.md](SECURITY.md) and [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
## Give any AI agent the security skills of a senior analyst ## Give any AI agent the security skills of a senior analyst
+1 -1
View File
File diff suppressed because one or more lines are too long
@@ -12,7 +12,7 @@
## Installation ## Installation
```bash ```bash
pip install in-toto securesystemslib[crypto] pip install in-toto 'securesystemslib[crypto]'
``` ```
## CLI Commands ## CLI Commands
+19 -3
View File
@@ -10,7 +10,10 @@ import re
import sys import sys
import glob import glob
REQUIRED_FIELDS = ["name", "description", "domain", "subdomain", "tags"] # Kept in sync with the CI workflow (.github/workflows/validate-skills.yml),
# which now delegates to this script so there is a single source of truth.
REQUIRED_FIELDS = ["name", "description", "domain", "subdomain", "tags",
"version", "author", "license"]
# Canonical subdomain → set of accepted aliases (including canonical itself). # Canonical subdomain → set of accepted aliases (including canonical itself).
# When a skill uses an alias, the validator accepts it but the canonical form # When a skill uses an alias, the validator accepts it but the canonical form
@@ -50,7 +53,7 @@ _SUBDOMAIN_ALIASES = {
"blockchain-security": {"blockchain-security"}, "blockchain-security": {"blockchain-security"},
"data-protection": {"data-protection"}, "data-protection": {"data-protection"},
"deception-technology": {"deception-technology"}, "deception-technology": {"deception-technology"},
"firmware-analysis": {"firmware-analysis", "firmware-security"}, "hardware-firmware-security": {"hardware-firmware-security", "firmware-analysis", "firmware-security"},
"privacy-compliance": {"privacy-compliance"}, "privacy-compliance": {"privacy-compliance"},
"purple-team": {"purple-team"}, "purple-team": {"purple-team"},
"supply-chain-security": {"supply-chain-security"}, "supply-chain-security": {"supply-chain-security"},
@@ -132,6 +135,14 @@ def parse_frontmatter(text):
data[current_key] = list(list_values) # copy so future mutations don't leak data[current_key] = list(list_values) # copy so future mutations don't leak
continue continue
# Only TOP-LEVEL keys (column 0) define frontmatter fields. An indented
# ``key: value`` line belongs to a nested structure (e.g. a framework
# mapping object that has its own ``name:``/``id:``) and must NOT be
# treated as a top-level field — otherwise a nested ``name:`` clobbers
# the skill's real ``name``.
if line[:1].isspace():
continue
# Handle inline list: tags: [a, b, c] # Handle inline list: tags: [a, b, c]
m = re.match(r"^(\w[\w_-]*):\s*\[(.+)\]\s*$", stripped) m = re.match(r"^(\w[\w_-]*):\s*\[(.+)\]\s*$", stripped)
if m: if m:
@@ -252,7 +263,12 @@ def main():
sys.exit(1) sys.exit(1)
if sys.argv[1] == "--all": if sys.argv[1] == "--all":
skill_dirs = sorted(glob.glob("skills/*/")) # Skip .bak backup directories — they are stale copies without a SKILL.md.
# glob may return OS-native separators, so normalize before checking.
skill_dirs = sorted(
d for d in glob.glob("skills/*/")
if not d.rstrip("/\\").endswith(".bak")
)
if not skill_dirs: if not skill_dirs:
print("ERROR: No skill directories found. Run from the repository root.") print("ERROR: No skill directories found. Run from the repository root.")
sys.exit(1) sys.exit(1)