Skip to content

Commit 3486454

Browse files
committed
Initial import of Falcon Fusion Skills
Six AI coding assistant skills for building CrowdStrike Falcon Fusion workflows, coordinated by a single orchestrator: workflows (the orchestrator), authoring, deployment, execution, lookup-files, and setup. What's included: - Live action discovery against the Falcon Workflows API, with a local cache (1-hour TTL, --clear-cache) - Structural validation against the Charlotte JSON schema (no credentials required), plus an optional server-side dry-run via the import API - 20 Content Library workflow examples, generated deterministically into readable YAML by a bundled converter and each verified to import cleanly, including a real parallel-enrichment playbook (AbuseIPDB) demonstrating fan-out and input gating - HTTP Action, Event Query (Inline.QueryEvent), Python Script (Inline.Python), and Charlotte AI LLM Completion action support - Correct Signal-trigger authoring: every Signal trigger carries the required event: field (the trigger category), discoverable via trigger_search.py --events - Parallel fan-out and per-indicator null-gating guidance so multi-indicator enrichment runs concurrently and only calls APIs for indicators that are present, rather than as a naive serial chain - Shared FalconPy authentication with multi-cloud TOML credential profiles and a guided setup skill (secret entered via the user's editor, never the chat) - 13 pattern-matchable use cases: some drawn from published CrowdStrike Tech Hub posts, others grounded directly in the bundled example workflows and the community Workflow Wednesday series (each cites its source and names the sub-skills it needs) - Cross-plugin advisory that redirects Foundry-app-shaped requests (UI, functions, collections, custom API integrations) to foundry-skills instead of authoring a broken workflow - Browser-based verification harness (verify-workflows.sh) that imports, releases, and confirms workflows against a live CID via Playwright, with passwordless-login handling - Hook scripts for intent routing and cross-plugin advisories to foundry-skills - Comprehensive unit tests (93% coverage, 90% gate), plus pylint 10/10, shellcheck, markdownlint, and structural validation — all enforced in CI Works with Claude Code, Codex, Gemini, and Copilot CLI as a plugin or as a standalone markdown reference. Builds on the MIT-licensed security-skills community project by Paul Price (eth0izzle).
1 parent 6cd1e05 commit 3486454

143 files changed

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

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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/
18+
working/

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