Skip to content

Commit 6edf7f2

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 6edf7f2

119 files changed

Lines changed: 22170 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: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
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+
pytest:
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 -r requirements-test.txt
59+
- name: Run unit tests
60+
run: |
61+
source .venv/bin/activate
62+
pytest tests/ -v \
63+
--cov=common/scripts \
64+
--cov=skills/authoring/scripts \
65+
--cov=skills/deployment/scripts \
66+
--cov=skills/execution/scripts \
67+
--cov=skills/lookup-files/scripts \
68+
--cov=bin \
69+
--cov-report=term-missing \
70+
--cov-fail-under=90
71+
72+
pylint:
73+
runs-on: ubuntu-latest
74+
steps:
75+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
76+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
77+
with:
78+
python-version: "3.13"
79+
- name: Install dependencies
80+
run: |
81+
python -m venv .venv
82+
source .venv/bin/activate
83+
pip install --upgrade pip
84+
pip install pylint crowdstrike-falconpy pyyaml tomli
85+
- name: Run pylint (fail-under=10 enforced by .pylintrc)
86+
run: |
87+
source .venv/bin/activate
88+
pylint --rcfile=.pylintrc \
89+
common/scripts/*.py \
90+
skills/authoring/scripts/*.py \
91+
skills/deployment/scripts/*.py \
92+
skills/execution/scripts/*.py \
93+
skills/lookup-files/scripts/*.py \
94+
bin/*.py
95+
96+
validate:
97+
runs-on: ubuntu-latest
98+
steps:
99+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
100+
- name: Validate JSON files
101+
run: |
102+
for f in \
103+
hooks/hooks.json \
104+
.claude-plugin/plugin.json \
105+
.claude-plugin/marketplace.json \
106+
test-result-schema.json \
107+
verify-result-schema.json; do
108+
echo "Validating $f"
109+
python -m json.tool "$f" > /dev/null
110+
done
111+
- name: Validate SKILL.md frontmatter
112+
run: |
113+
fail=0
114+
for skill in skills/*/SKILL.md; do
115+
for field in name description version; do
116+
if ! head -20 "$skill" | grep -q "^${field}:"; then
117+
echo "FAIL: $skill missing '$field' in frontmatter"
118+
fail=1
119+
fi
120+
done
121+
done
122+
exit $fail
123+
- name: Validate skill size budgets
124+
run: |
125+
fail=0
126+
total_desc_chars=0
127+
max_tokens=5500
128+
129+
for skill in skills/*/SKILL.md; do
130+
name=$(basename "$(dirname "$skill")")
131+
chars=$(wc -c < "$skill")
132+
approx_tokens=$((chars / 4))
133+
pct=$((approx_tokens * 100 / max_tokens))
134+
135+
if [ "$approx_tokens" -gt "$max_tokens" ]; then
136+
echo "FAIL: $name ~${approx_tokens} tokens (${pct}% of ${max_tokens} limit)"
137+
fail=1
138+
elif [ "$approx_tokens" -gt 4500 ]; then
139+
echo "WARN: $name ~${approx_tokens} tokens (${pct}% of ${max_tokens} limit)"
140+
fi
141+
142+
desc=$(sed -n 's/^description: *//p' "$skill")
143+
desc_len=${#desc}
144+
total_desc_chars=$((total_desc_chars + desc_len))
145+
146+
if [ "$desc_len" -gt 1536 ]; then
147+
echo "FAIL: $name description ${desc_len} chars (max 1536)"
148+
fail=1
149+
fi
150+
done
151+
152+
desc_budget=8000
153+
desc_pct=$((total_desc_chars * 100 / desc_budget))
154+
echo ""
155+
echo "Description budget: ${total_desc_chars} / ~${desc_budget} chars (${desc_pct}%) — 1% of 200k context at ~4 chars/token"
156+
exit $fail
157+
- name: Validate hook scripts are executable
158+
run: |
159+
fail=0
160+
for script in hooks/*.sh; do
161+
[ -x "$script" ] || { echo "FAIL: $script is not executable"; fail=1; }
162+
done
163+
exit $fail
164+
- name: Validate Python scripts are syntactically valid
165+
run: |
166+
fail=0
167+
while IFS= read -r py; do
168+
if ! python -c "import ast, sys; ast.parse(open(sys.argv[1], encoding='utf-8').read())" "$py"; then
169+
echo "FAIL: $py has a syntax error"
170+
fail=1
171+
fi
172+
done < <(find . -name '*.py' -not -path '*/__pycache__/*' -not -path '*/.venv/*')
173+
exit $fail
174+
- name: Validate no PLACEHOLDER values in example workflows
175+
run: |
176+
fail=0
177+
while IFS= read -r wf; do
178+
if grep -qE 'PLACEHOLDER_[A-Z_]+' "$wf"; then
179+
echo "FAIL: $wf contains PLACEHOLDER_* values (action IDs must be resolved)"
180+
grep -nE 'PLACEHOLDER_[A-Z_]+' "$wf"
181+
fail=1
182+
fi
183+
done < <(find skills/authoring/examples -name '*.yaml' -o -name '*.yml')
184+
[ $fail -eq 0 ] && echo "No PLACEHOLDER_* values in example workflows"
185+
exit $fail
186+
- name: Validate version consistency
187+
run: |
188+
fail=0
189+
plugin_version=$(jq -r '.version' .claude-plugin/plugin.json)
190+
marketplace_version=$(jq -r '.plugins[0].version' .claude-plugin/marketplace.json)
191+
echo "plugin.json version: $plugin_version"
192+
echo "marketplace.json plugins[0].version: $marketplace_version"
193+
194+
# marketplace.json must match plugin.json
195+
if [ "$marketplace_version" != "$plugin_version" ]; then
196+
echo "FAIL: marketplace.json plugins[0].version '$marketplace_version' != plugin.json '$plugin_version'"
197+
fail=1
198+
fi
199+
200+
# All SKILL.md versions must match plugin.json
201+
for skill in skills/*/SKILL.md; do
202+
skill_version=$(sed -n 's/^version: *//p' "$skill")
203+
if [ "$skill_version" != "$plugin_version" ]; then
204+
echo "FAIL: $skill version '$skill_version' != plugin.json '$plugin_version'"
205+
fail=1
206+
fi
207+
done
208+
209+
# CHANGELOG must have an entry for this version
210+
if ! grep -q "## \[${plugin_version}\]" CHANGELOG.md; then
211+
echo "FAIL: CHANGELOG.md missing entry for version $plugin_version"
212+
fail=1
213+
fi
214+
215+
# README badge must match
216+
if ! grep -q "version-${plugin_version}-blue" README.md; then
217+
echo "FAIL: README.md badge doesn't match version $plugin_version"
218+
fail=1
219+
fi
220+
221+
[ $fail -eq 0 ] && echo "All versions consistent: $plugin_version"
222+
exit $fail
223+
224+
markdownlint:
225+
runs-on: ubuntu-latest
226+
steps:
227+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
228+
- uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
229+
with:
230+
node-version: 22
231+
- name: Run markdownlint
232+
run: npx markdownlint-cli2 "**/*.md"

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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/
14+
15+
# Coverage
16+
.coverage
17+
htmlcov/

.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)