Skip to content

Commit e813700

Browse files
committed
Initial import of Falcon Fusion Skills
AI coding assistant skills for building CrowdStrike Falcon Fusion workflows. Six skills coordinated by an orchestrator: workflows (lifecycle routing), authoring (action discovery, YAML, validation), deployment (import, release), execution (trigger, monitor, debug), lookup-files (Next-Gen SIEM lookup management), and setup (credential configuration). Includes live action discovery against the Fusion API, structural validation against the Charlotte JSON schema, 19 Content Library workflow examples in YAML, HTTP Action / Event Query / Python Script action support, and hook scripts for intent routing and cross-plugin advisories. Works with Claude Code, Codex, Gemini, and Copilot as a plugin or as a tool-agnostic markdown reference. Builds on the MIT-licensed security-skills community project.
1 parent 6cd1e05 commit e813700

101 files changed

Lines changed: 17839 additions & 2 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude-plugin/marketplace.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "fusion-marketplace",
3+
"description": "AI coding assistant skills for building CrowdStrike Falcon Fusion workflows",
4+
"owner": {
5+
"name": "CrowdStrike"
6+
},
7+
"plugins": [
8+
{
9+
"name": "crowdstrike-falcon-fusion",
10+
"source": "./",
11+
"description": "CrowdStrike Falcon Fusion SOAR skills for authoring, deploying, and executing Fusion workflows. Includes live action discovery, YAML authoring with schema validation, workflow import and release, execution monitoring, and Falcon Next-Gen SIEM lookup files.",
12+
"version": "1.0.0",
13+
"author": {
14+
"name": "CrowdStrike"
15+
},
16+
"license": "MIT",
17+
"keywords": [
18+
"crowdstrike",
19+
"falcon",
20+
"fusion",
21+
"soar",
22+
"workflow",
23+
"automation",
24+
"security"
25+
]
26+
}
27+
]
28+
}

.claude-plugin/plugin.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "crowdstrike-falcon-fusion",
3+
"description": "CrowdStrike Falcon Fusion SOAR skills for authoring, deploying, and executing Fusion workflows. Includes live action discovery, YAML authoring with schema validation, workflow import and release, execution monitoring, and Falcon Next-Gen SIEM lookup files.",
4+
"version": "1.0.0",
5+
"author": {
6+
"name": "CrowdStrike"
7+
},
8+
"license": "MIT",
9+
"keywords": [
10+
"crowdstrike",
11+
"falcon",
12+
"fusion",
13+
"soar",
14+
"workflow",
15+
"automation",
16+
"security"
17+
]
18+
}

.github/copilot-instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
See [AGENTS.md](../AGENTS.md) for AI coding assistant instructions for this repository.

.github/dependabot.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
day: "monday"
8+
time: "14:00"
9+
timezone: "UTC"
10+
ignore:
11+
- dependency-name: "actions/checkout"
12+
versions: [">=6.0.3"]
13+
- dependency-name: "actions/setup-node"
14+
versions: [">=6.3.0"]
15+
- dependency-name: "actions/setup-python"
16+
versions: [">=6.3.0"]

.github/workflows/main.yml

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
name: Fusion Skills CI
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
push:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
shellcheck:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
17+
- name: Install ShellCheck
18+
run: command -v shellcheck || { sudo apt-get update -qq && sudo apt-get install -y -qq shellcheck; }
19+
- name: Run ShellCheck
20+
run: |
21+
shellcheck hooks/*.sh bin/*.sh
22+
shellcheck --severity=error *.sh
23+
24+
test-hooks:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
28+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
29+
with:
30+
python-version: "3.13"
31+
- name: Install dependencies
32+
run: |
33+
python -m venv .venv
34+
source .venv/bin/activate
35+
pip install --upgrade pip
36+
pip install pyyaml crowdstrike-falconpy
37+
- name: Run hook tests
38+
run: |
39+
source .venv/bin/activate
40+
./test-hooks.sh
41+
- name: Run structural validation
42+
run: |
43+
source .venv/bin/activate
44+
./test-validate.sh
45+
46+
pylint:
47+
runs-on: ubuntu-latest
48+
steps:
49+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
50+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
51+
with:
52+
python-version: "3.13"
53+
- name: Install dependencies
54+
run: |
55+
python -m venv .venv
56+
source .venv/bin/activate
57+
pip install --upgrade pip
58+
pip install pylint crowdstrike-falconpy pyyaml tomli
59+
- name: Run pylint (fail-under=10 enforced by .pylintrc)
60+
run: |
61+
source .venv/bin/activate
62+
pylint --rcfile=.pylintrc \
63+
common/scripts/*.py \
64+
skills/authoring/scripts/*.py \
65+
skills/deployment/scripts/*.py \
66+
skills/execution/scripts/*.py \
67+
skills/lookup-files/scripts/*.py \
68+
bin/*.py
69+
70+
validate:
71+
runs-on: ubuntu-latest
72+
steps:
73+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
74+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
75+
with:
76+
python-version: "3.13"
77+
- name: Install dependencies
78+
run: pip install pyyaml
79+
- name: Validate JSON files
80+
run: |
81+
for f in \
82+
hooks/hooks.json \
83+
.claude-plugin/plugin.json \
84+
.claude-plugin/marketplace.json \
85+
test-result-schema.json \
86+
verify-result-schema.json; do
87+
echo "Validating $f"
88+
python -m json.tool "$f" > /dev/null
89+
done
90+
- name: Validate SKILL.md frontmatter
91+
run: |
92+
fail=0
93+
for skill in skills/*/SKILL.md; do
94+
for field in name description version; do
95+
if ! head -20 "$skill" | grep -q "^${field}:"; then
96+
echo "FAIL: $skill missing '$field' in frontmatter"
97+
fail=1
98+
fi
99+
done
100+
done
101+
exit $fail
102+
- name: Validate skill size budgets
103+
run: |
104+
fail=0
105+
MAX_TOKENS=5500
106+
WARN_TOKENS=4500
107+
DESC_BUDGET=8000
108+
total_desc=0
109+
for skill in skills/*/SKILL.md; do
110+
words=$(wc -w < "$skill")
111+
tokens=$(( words * 4 / 3 ))
112+
if [ "$tokens" -gt "$MAX_TOKENS" ]; then
113+
echo "FAIL: $skill is ~${tokens} tokens (max $MAX_TOKENS)"
114+
fail=1
115+
elif [ "$tokens" -gt "$WARN_TOKENS" ]; then
116+
echo "WARN: $skill is ~${tokens} tokens (approaching $MAX_TOKENS limit)"
117+
else
118+
echo "OK: $skill ~${tokens} tokens"
119+
fi
120+
desc_len=$(python -c "
121+
import yaml
122+
with open('$skill') as f:
123+
parts = f.read().split('---')
124+
if len(parts) >= 3:
125+
fm = yaml.safe_load(parts[1])
126+
print(len(fm.get('description', '')))
127+
else:
128+
print(0)
129+
")
130+
total_desc=$(( total_desc + desc_len ))
131+
done
132+
echo "Total description chars: $total_desc / $DESC_BUDGET"
133+
if [ "$total_desc" -gt "$DESC_BUDGET" ]; then
134+
echo "FAIL: total description chars ($total_desc) exceeds budget ($DESC_BUDGET)"
135+
fail=1
136+
fi
137+
exit $fail
138+
- name: Validate hook scripts are executable
139+
run: |
140+
fail=0
141+
for script in hooks/*.sh; do
142+
[ -x "$script" ] || { echo "FAIL: $script is not executable"; fail=1; }
143+
done
144+
exit $fail
145+
- name: Validate Python scripts are syntactically valid
146+
run: |
147+
fail=0
148+
while IFS= read -r py; do
149+
if ! python -c "import ast, sys; ast.parse(open(sys.argv[1], encoding='utf-8').read())" "$py"; then
150+
echo "FAIL: $py has a syntax error"
151+
fail=1
152+
fi
153+
done < <(find . -name '*.py' -not -path '*/__pycache__/*' -not -path '*/.venv/*')
154+
exit $fail
155+
- name: Validate no PLACEHOLDER values in example workflows
156+
run: |
157+
fail=0
158+
while IFS= read -r wf; do
159+
if grep -qE 'PLACEHOLDER_[A-Z_]+' "$wf"; then
160+
echo "FAIL: $wf contains PLACEHOLDER_* values (action IDs must be resolved)"
161+
grep -nE 'PLACEHOLDER_[A-Z_]+' "$wf"
162+
fail=1
163+
fi
164+
done < <(find skills/authoring/examples -name '*.yaml' -o -name '*.yml')
165+
[ $fail -eq 0 ] && echo "No PLACEHOLDER_* values in example workflows"
166+
exit $fail
167+
- name: Validate version consistency
168+
run: |
169+
fail=0
170+
plugin_version=$(jq -r '.version' .claude-plugin/plugin.json)
171+
marketplace_version=$(jq -r '.plugins[0].version' .claude-plugin/marketplace.json)
172+
echo "plugin.json version: $plugin_version"
173+
echo "marketplace.json plugins[0].version: $marketplace_version"
174+
175+
# marketplace.json must match plugin.json
176+
if [ "$marketplace_version" != "$plugin_version" ]; then
177+
echo "FAIL: marketplace.json plugins[0].version '$marketplace_version' != plugin.json '$plugin_version'"
178+
fail=1
179+
fi
180+
181+
# All SKILL.md versions must match plugin.json
182+
for skill in skills/*/SKILL.md; do
183+
skill_version=$(sed -n 's/^version: *//p' "$skill")
184+
if [ "$skill_version" != "$plugin_version" ]; then
185+
echo "FAIL: $skill version '$skill_version' != plugin.json '$plugin_version'"
186+
fail=1
187+
fi
188+
done
189+
190+
# CHANGELOG must have an entry for this version
191+
if ! grep -q "## \[${plugin_version}\]" CHANGELOG.md; then
192+
echo "FAIL: CHANGELOG.md missing entry for version $plugin_version"
193+
fail=1
194+
fi
195+
196+
[ $fail -eq 0 ] && echo "All versions consistent: $plugin_version"
197+
exit $fail
198+
199+
markdownlint:
200+
runs-on: ubuntu-latest
201+
steps:
202+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
203+
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
204+
with:
205+
node-version: 22
206+
- name: Run markdownlint
207+
run: npx markdownlint-cli2 "**/*.md"

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Local action discovery cache (per-user, never shipped)
2+
.action_cache.json
3+
4+
# Python
5+
__pycache__/
6+
*.pyc
7+
8+
# Credentials
9+
.env
10+
11+
# IDE / local tools
12+
.idea/
13+
.playwright-mcp/

.markdownlint.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"MD007": false,
3+
"MD009": false,
4+
"MD012": false,
5+
"MD013": false,
6+
"MD022": false,
7+
"MD024": { "siblings_only": true },
8+
"MD028": false,
9+
"MD031": false,
10+
"MD032": false,
11+
"MD033": false,
12+
"MD034": false,
13+
"MD036": false,
14+
"MD040": false,
15+
"MD041": false,
16+
"MD045": false,
17+
"MD051": false,
18+
"MD059": false,
19+
"MD060": false
20+
}

0 commit comments

Comments
 (0)