Files
Anthropic-Cybersecurity-Skills/.github/workflows/update-index.yml
T
Mahipal d56fc0a7f9 Fix index.json generator to parse folded YAML descriptions
The generator's `^description:\s*(.+)$` regex captured the block-scalar
indicator (">-") instead of the wrapped text, corrupting 43 descriptions in
index.json. Parse `>`/`|` block scalars properly and regenerate (0 broken).
Also refresh the count-update comment examples 754 -> 817.
2026-08-02 10:47:14 -07:00

137 lines
5.8 KiB
YAML

name: Update marketplace index
on:
push:
branches: [main]
paths:
- 'skills/**'
- '.github/workflows/update-index.yml'
workflow_dispatch:
jobs:
update-index:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Regenerate index.json
run: |
python3 << 'EOF'
import os, json, re
from datetime import datetime, timezone
skills_dir = "skills"
skills = []
for skill_name in sorted(os.listdir(skills_dir)):
skill_md = os.path.join(skills_dir, skill_name, "SKILL.md")
if not os.path.isfile(skill_md):
continue
with open(skill_md, "r", encoding="utf-8") as f:
content = f.read()
fm_match = re.match(r"^---\n(.*?)\n---", content, re.DOTALL)
description = ""
if fm_match:
fm = fm_match.group(1)
dm = re.search(r"^description:[ \t]*(.*)$", fm, re.MULTILINE)
if dm:
first = dm.group(1).strip()
if first[:1] in (">", "|"):
# YAML block scalar: gather the following more-indented lines
buf = []
for ln in fm[dm.end():].split("\n"):
if ln.strip() == "":
buf.append("")
elif re.match(r"^[ \t]+\S", ln):
buf.append(ln.strip())
else:
break
if first.startswith(">"): # folded: blank line = break, else join w/ space
paras, cur = [], []
for b in buf:
if b == "":
if cur: paras.append(" ".join(cur)); cur = []
else:
cur.append(b)
if cur: paras.append(" ".join(cur))
description = " ".join(paras).strip()
else: # literal
description = " ".join(b for b in buf if b).strip()
else:
description = first.strip('"').strip("'")
skills.append({
"name": skill_name,
"description": description,
"domain": "cybersecurity",
"path": f"skills/{skill_name}"
})
index = {
"version": "1.1.0",
"generated_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"repository": "https://github.com/mukul975/Anthropic-Cybersecurity-Skills",
"domain": "cybersecurity",
"total_skills": len(skills),
"skills": skills
}
with open("index.json", "w", encoding="utf-8") as f:
json.dump(index, f, separators=(',', ':'))
print(f"Updated index.json: {len(skills)} skills")
EOF
- name: Sync skill count into README and marketplace
run: |
python3 << 'EOF'
import os, re, json
# Authoritative count: directories under skills/ that contain a SKILL.md
# and are not .bak backups (matches index.json generation above).
count = 0
for name in os.listdir("skills"):
if name.endswith(".bak"):
continue
if os.path.isfile(os.path.join("skills", name, "SKILL.md")):
count += 1
print(f"Authoritative skill count: {count}")
# README.md — replace the skills badge and every "<NNN> ... skills" phrase.
with open("README.md", encoding="utf-8") as f:
readme = f.read()
readme = re.sub(r"(badge/skills-)\d+", rf"\g<1>{count}", readme)
# "817 production-grade", "817 structured", "817 skills", "all 817 skills",
# "Scans 817 skill", "contains **817 skills**", BibTeX "{817 structured"
readme = re.sub(r"\b\d+(?=\s+production-grade cybersecurity skills)", str(count), readme)
readme = re.sub(r"\b\d+(?=\s+structured cybersecurity skills)", str(count), readme)
readme = re.sub(r"(all\s+)\d+(?=\s+skills)", rf"\g<1>{count}", readme)
readme = re.sub(r"(Scans\s+)\d+(?=\s+skill\b)", rf"\g<1>{count}", readme)
readme = re.sub(r"(contains\s+\*\*)\d+(?=\s+skills\*\*)", rf"\g<1>{count}", readme)
readme = re.sub(r"(\{)\d+(?=\s+structured cybersecurity skills)", rf"\g<1>{count}", readme)
with open("README.md", "w", encoding="utf-8") as f:
f.write(readme)
# marketplace.json + plugin.json — patch "<NNN> cybersecurity skills" in descriptions.
for path in (".claude-plugin/marketplace.json", ".claude-plugin/plugin.json"):
with open(path, encoding="utf-8") as f:
data = f.read()
data = re.sub(r"\b\d+(?=\s+cybersecurity skills)", str(count), data)
json.loads(data) # fail loudly if the regex broke JSON
with open(path, "w", encoding="utf-8") as f:
f.write(data)
print("Synced skill count into README.md, marketplace.json, plugin.json")
EOF
- name: Commit updated index and skill count
run: |
git config user.name "mukul975"
git config user.email "mukuljangra5@gmail.com"
git add index.json README.md .claude-plugin/marketplace.json .claude-plugin/plugin.json
git diff --staged --quiet || git commit -m "chore: auto-update index.json and skill count"
git push