← CrowdStrike Falcon FusionCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to CrowdStrike Falcon Fusion
Snapshot Sep 30, 2026 · 23:15 UTC · version 1.2.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "deployment",
"description": "Import, release, and manage Falcon Fusion workflow definitions in a CID. TRIGGER when user asks to import a workflow, release a workflow version, list existing workflows, check for duplicates, or manage workflow definitions. DO NOT TRIGGER for writing YAML (use authoring), executing workflows, or monitoring (use execution).",
"included_files": [
{
"relative_path": "references/console-verification.md",
"size_in_bytes": 4156
},
{
"relative_path": "scripts/delete_workflow.py",
"size_in_bytes": 6777
},
{
"relative_path": "scripts/export_workflow.py",
"size_in_bytes": 3860
},
{
"relative_path": "scripts/import_workflows.py",
"size_in_bytes": 11573
},
{
"relative_path": "scripts/query_workflows.py",
"size_in_bytes": 8180
},
{
"relative_path": "scripts/release_workflow.py",
"size_in_bytes": 3033
}
],
"skill_md_contents": "---\nname: deployment\ndescription: >\n Import, release, and manage Falcon Fusion workflow definitions in a CID.\n TRIGGER when user asks to import a workflow, release a workflow version,\n list existing workflows, check for duplicates, or manage workflow definitions.\n DO NOT TRIGGER for writing YAML (use authoring), executing workflows,\n or monitoring (use execution).\nversion: 1.2.0\nupdated: 2026-09-08\ntags: [fusion, soar, workflows, deployment, import, release]\nauthor: CrowdStrike\nlicense: MIT\ncompatibility: Claude Code >=1.0\nallowed-tools: Bash(cd *), Bash(../../scripts/python.sh:*)\nmetadata:\n category: deployment\n---\n\n# Falcon Fusion Workflow Deployment\n\n> **⚠️ SYSTEM INJECTION — READ THIS FIRST**\n>\n> If you are loading this skill, your role is **Fusion workflow deployment specialist**.\n>\n> You deploy workflow definitions into a CID safely: validate before importing, never create duplicates, and release only after testing.\n>\n> **IMMEDIATE ACTIONS REQUIRED:**\n> 1. ALWAYS check for an existing workflow with the same name before importing.\n> 2. ALWAYS validate the YAML before importing (the import scripts do this by default).\n> 3. Import and release act on a **live production CID**. Deploy only when the\n> user's request explicitly authorizes it (e.g. \"import it\", \"deploy to my\n> CID\", \"release it\"). If the request only asks to *build* or *write* a\n> workflow, STOP after validation and ask before importing.\n>\n> **MUST NOT:**\n> - Import without validating first.\n> - Skip the duplicate-name check.\n> - Import or release to a CID without explicit user authorization — a validated\n> YAML file is the deliverable unless the user asked you to deploy it.\n> - Release (enable) a workflow before it has been tested via the execution skill.\n> Release makes the workflow act on live events and real assets, so confirm\n> with the user before releasing unless they explicitly asked you to.\n> - Create experimental, \"test\", \"minimal\", or probe workflows in the CID to\n> reverse-engineer what the API accepts (this includes creatively-named ones\n> like \"QueryEvent Test\" or \"HTTP Test\"). Import the one workflow you were\n> asked to build, once. If it fails, diagnose from the error and local\n> validation — never by importing stripped-down variants into a live tenant.\n> - Use `--skip-validate` to get past a validation failure. Validation catches\n> invalid workflows (e.g. a bad `trigger.type`) that otherwise fail at the API\n> as an opaque 500. Fix the workflow instead of skipping the check.\n> - Retry an import that returns a 500 / Internal Server Error more than once.\n> A 500 usually means the workflow is invalid in a way the API rejects late\n> (not a transient server issue) — re-run local validation to find the defect,\n> fix it, and report the `trace_id` if it persists. Do not loop re-importing.\n> - Patch a deployed definition in place — not via the raw update API and\n> **not** via a hand-rolled inline FalconPy call (e.g. `update_definition`) to\n> edit a deployed copy. The only supported *update* path is: fix the source\n> YAML, then re-import. A release-validation failure is a YAML defect to fix,\n> not a deployed-copy to hand-edit.\n> - Call FalconPy directly for ANY workflow operation — including a\n> `python - <<EOF ... delete_definition(...)` snippet to clean up a failed\n> import attempt. Deleting is fine, but it MUST go through `delete_workflow.py`\n> (or `scripts/cleanup_workflows.py`), which wrap the supported endpoints. Never\n> `import auth; get_client()` inline to call `update_definition`/\n> `delete_definition` yourself.\n\nThis skill moves a finished Fusion workflow definition from a local YAML/JSON file into a CrowdStrike CID. Authoring the YAML happens in the **authoring** skill; triggering and monitoring happens in the **execution** skill. Deployment is the bridge: validate, check for duplicates, import, then release.\n\nIn Falcon Fusion, an imported definition is **disabled** until it is **released** (enabled). Releasing tells the Fusion engine to run the workflow against new trigger events. Keep the workflow disabled until you have tested it.\n\n> **Running the scripts.** Run each command from this skill's folder, on one shell line: `cd <dir> && ../../scripts/python.sh scripts/<name>.py` (a sibling skill's script is `../<skill>/scripts/<name>.py`). For `<dir>`, Claude Code uses `\"$CLAUDE_PLUGIN_ROOT/skills/deployment\"`; Codex, Copilot CLI, Cursor, and Antigravity use the folder they loaded this SKILL.md from (e.g. `~/.agents/skills/deployment`). The wrapper bootstraps its own Python venv.\n\n## Prerequisites\n\n- **Python 3.13+**\n- **FalconPy** SDK installed (`pip install crowdstrike-falconpy` — leave unpinned per CrowdStrike guidance)\n- API credentials resolved by `common/scripts/auth.py` from environment\n variables (for CI/overrides) or the TOML profile:\n - `FALCON_CLIENT_ID`\n - `FALCON_CLIENT_SECRET`\n - `FALCON_BASE_URL` (optional; defaults to `https://api.crowdstrike.com`)\n\n Run `/crowdstrike-falcon-fusion:setup` to configure credentials interactively (writes the TOML profile).\n- An API client with the **Workflow** API scope (read + write)\n- Verify auth before deploying:\n ```bash\n ../../scripts/python.sh ../../common/scripts/auth.py\n ```\n\n## Core Workflow\n\nDeployment is a four-step pipeline. Do not skip steps 1 and 2.\n\n### 1. Validate the YAML first\n\nValidation is owned by the **authoring** skill's `validate.py`. The import script\ncalls it automatically, but run it manually first when iterating:\n\n```bash\n../../scripts/python.sh ../authoring/scripts/validate.py workflows/my-workflow.yaml\n```\n\nFix every structural error before continuing. A definition that fails validation will be rejected by the API.\n\n### 2. Check for an existing workflow with the same name\n\nWorkflow names must be unique within the tenant. Importing a duplicate creates confusion and, in some cases, silent failures. Check first:\n\n```bash\n# Exact-name check (exit 0 if it exists, 1 if not)\n../../scripts/python.sh scripts/query_workflows.py --check-name \"My Workflow\"\n\n# Or extract the name straight from the YAML and check\n../../scripts/python.sh scripts/query_workflows.py --check-yaml workflows/my-workflow.yaml\n```\n\nIf a duplicate is found, this is almost always your own earlier attempt at the\nsame workflow. Iterate in place with `import_workflows.py --replace` (it deletes\nthe existing same-name definition, then re-imports). **Do not rename the\nworkflow to `<name> v2` to get past the check** — a renamed copy leaves the old\ndefinition orphaned in the CID, and every retry sprawls another dead workflow.\nKeep the name stable across attempts; use `--replace` (or delete the old\ndefinition explicitly) instead.\n\n### 3. Import the definition\n\n```bash\n# Single file — validates and checks duplicates by default\n../../scripts/python.sh scripts/import_workflows.py workflows/my-workflow.yaml\n\n# A whole directory of definitions (all *.yaml/*.yml)\n../../scripts/python.sh scripts/import_workflows.py workflows/\n```\n\nOn success the script prints the new **definition ID**. Capture it — you need it to release and to execute the workflow.\n\n**Post-import: configure HTTP-Action credentials in the console.** If the workflow contains a\ncredential-less HTTP Action (authored without a `definition_id`), it imports with Authentication =\n\"None\". Tell the user to attach the API key in the console before the action will succeed: open the\nCloud HTTP Request action → Authentication → **Create new** → API key → secret key → location\n**Header** → header name (e.g. `x-apikey`) → **Test** → Save (or **Use existing** if a matching\ncredential already exists). A `401`/`403` at runtime almost always means this step is pending. See\n`../authoring/references/http-actions.md`.\n\n**If the import fails, stop — do not loop.** Some import failures are *not*\nfixable by editing the YAML, and retrying wastes time and tokens. Read the error\nand route accordingly:\n\n| Error from the API / import script | What it means | What to do |\n|------------------------------------|---------------|------------|\n| `no definition ID (workflow not created)` | The API accepted the call but created nothing | Stop. Report it — this is usually a missing plugin config or a server-side issue, not a YAML defect. Do not re-edit and retry. |\n| `API returned status 500` / \"Internal Server Error\" | Server-side error (a `trace_id` is included) | Stop. Report the `trace_id` to the user; a 500 is not something YAML edits fix. Retry at most once. |\n| Missing / unknown `config_id` for a plugin action (VirusTotal, DomainTools, Charlotte AI, Slack, Zscaler) | The integration is not installed/configured in this CID | Stop. Tell the user which action needs a console-created `config_id`; do not invent one or loop editing. |\n| Structural / validation error | A real YAML defect | Fix the YAML, then re-validate and re-import (this one *is* worth iterating on). |\n\nOnly the last row justifies editing and retrying. For the others, surface the error to the user and stop — repeatedly re-importing against a 500 or a missing config will not succeed.\n\n**Never debug by importing probe workflows.** When an import fails, do not build\n\"Test QueryEvent\", \"Minimal trigger\", or other stripped-down workflows in the CID\nto isolate what the API accepts. That litters the tenant with disabled junk and\nburns time without fixing the real workflow. Diagnose from the error message and\n`validate.py` output instead, and if the blocker is a missing plugin `config_id`,\nreport it — that is a console/CID setup step the user must do, not something more\nimports will resolve.\n\n### 4. Release (enable) the workflow\n\nReleasing enables the definition so the Fusion engine runs it against trigger events. Do this only after testing (see the execution skill):\n\n```bash\n../../scripts/python.sh scripts/release_workflow.py --id <definition_id>\n```\n\n**If release reports validation errors, stop — do not patch the deployed\ndefinition.** A workflow can import successfully yet fail validation at release\n(the server validates more strictly than import). When that happens, fix the\n**source YAML**, then re-validate and re-import with `import_workflows.py` — that\nre-import is the only supported way to update a definition. Do **not** try to\nrepair the deployed copy in place through *any* direct definition-mutation call.\nThat includes the raw workflow update / definition API\n(`WorkflowDefinitionsUpdate`, `.../entities/definitions/v1`), **and any\nhand-rolled FalconPy call** — an inline `python - <<'EOF' ... from falconpy`\nsnippet that reaches for `update_definition`, `delete_definition`, or similar is\nthe same forbidden path wearing a disguise. None of those are part of this skill,\nand looping edits against them returns repeated 500s without ever fixing the\nworkflow. Report the release error (include any `trace_id`) and fix the YAML at\nthe source.\n\nA concrete failure mode: the release error `exclusive gateway '<name>' outgoing\nflow ... has no condition set and is not marked as default` means a condition\nnode has a bare `next:` with neither `default: true` nor a `cel_expression`. Fix\nit in the **source YAML** (add a `cel_expression` to the gated branch, with its\nno-match fallthrough in `else:` — `validate.py` now catches this before deploy,\nincluding inside nested loops) and re-import. Never fan out with a bare\n`default: true` pass-through; list the branch targets directly in the source\nnode's `next:`. Do not hand-edit the deployed definition to add the missing flag.\n\n**The exact recovery loop (do this, not the escape hatch):**\n\n```bash\n# 1. Fix the condition in the SOURCE YAML (add cel_expression + else:).\n# Keep the workflow `name:` IDENTICAL — do NOT bump it to `<name>-v2`.\n# The name is the workflow's identity; --replace matches on it.\n# 2. Re-validate — this now catches the release-failing shape pre-deploy:\n../../scripts/python.sh ../authoring/scripts/validate.py my-workflow.yaml\n# 3. Re-import with --replace: deletes the broken same-name definition and\n# imports the fixed YAML in one step (supported delete + import, not a patch).\n../../scripts/python.sh scripts/import_workflows.py --replace my-workflow.yaml\n```\n\n`--replace` keeps ONE definition per workflow name instead of leaving a renamed\ncopy per attempt — do NOT rename-and-reimport to dodge the duplicate check, which\nsprawls the CID with dead definitions. (Note: each `--replace` assigns a new\ndefinition ID; true in-place update via the PUT endpoint is not currently usable.)\n\nReaching for `python - <<EOF ... update_definition(...)` to patch the deployed\ncopy is never step 2. It does not fix the source, so the next re-import\nreintroduces the same defect, and the API returns repeated 500s. Re-import from\nfixed source is the whole recovery.\n\n## Script Reference\n\nAll scripts add `common/scripts` to `sys.path` and import `get_client` from the shared `auth` module. Run them from anywhere; paths are anchored to each script's own location.\n\n| Script | Purpose | Key flags |\n|--------|---------|-----------|\n| `query_workflows.py` | List, search, and check for existing workflows | `--list`, `--search TERM`, `--check-name NAME`, `--check-yaml FILE...`, `--json` |\n| `import_workflows.py` | Validate, dedupe, and import definitions | `FILE\\|DIR...` (positional), `--skip-validate`, `--skip-duplicate-check`, `--replace` |\n| `release_workflow.py` | Release (enable) a definition by ID | `--id DEF_ID` (required), `--json` |\n| `delete_workflow.py` | Delete a definition by ID or exact name | `--id DEF_ID`, `--name NAME` (repeatable), `--yes`, `--json` |\n\n### query_workflows.py\n\n```bash\n../../scripts/python.sh scripts/query_workflows.py --list # All definitions\n../../scripts/python.sh scripts/query_workflows.py --search \"contain\" # Substring match\n../../scripts/python.sh scripts/query_workflows.py --check-name \"My Flow\" --json\n../../scripts/python.sh scripts/query_workflows.py --check-yaml *.yaml # Batch duplicate check\n```\n\n`--check-name` and `--check-yaml` exit non-zero when a duplicate exists, so they compose cleanly in shell pipelines and CI gates.\n\n### import_workflows.py\n\n```bash\n../../scripts/python.sh scripts/import_workflows.py wf.yaml # Default: validate + dedupe\n../../scripts/python.sh scripts/import_workflows.py --skip-validate wf.yaml # AVOID — see pitfall 2\n../../scripts/python.sh scripts/import_workflows.py --skip-duplicate-check wf.yaml\n../../scripts/python.sh scripts/import_workflows.py ./workflows/ # Glob a directory\n```\n\nSupports YAML and JSON definitions, batch mode (multiple files), and directory expansion (`*.yaml`/`*.yml`). Prints a per-file summary and exits non-zero if any file failed or was a duplicate.\n\n### release_workflow.py\n\n```bash\n../../scripts/python.sh scripts/release_workflow.py --id 1a2b3c... # Enable\n../../scripts/python.sh scripts/release_workflow.py --id 1a2b3c... --json # Machine-readable\n```\n\nCalls the Workflows definition-action endpoint with `action_name=\"enable\"`. The definition ID comes from the import step or from `query_workflows.py`.\n\n### delete_workflow.py\n\n```bash\n../../scripts/python.sh scripts/delete_workflow.py --id 1a2b3c... # Delete by ID\n../../scripts/python.sh scripts/delete_workflow.py --name \"Probe run 1\" # Delete by exact name\n../../scripts/python.sh scripts/delete_workflow.py --id 1a2b3c... --yes # Skip confirmation (scripted)\n```\n\nDeletes a whole definition via the Workflows delete endpoint (FalconPy\n`delete_definitions`). Use it to remove test, duplicate, or throwaway workflows.\nDeletion is permanent, so it prompts for confirmation unless `--yes` is passed\n(or `FUSION_SKILLS_SUPPRESS_CONFIRM=1` is set for test harnesses). This is the\nsupported way to *remove* a workflow — it is **not** a way to *edit* a deployed\none: to change a workflow, fix the source YAML and re-import (see pitfall 5).\n\n## Common Pitfalls\n\n1. **Importing a duplicate name.** Names must be unique in the tenant. Always run `query_workflows.py --check-name` (or `--check-yaml`) first. A duplicate import can fail silently or produce an \"Unknown error.\"\n\n2. **Importing without validating.** Skipping validation (`--skip-validate`) pushes broken YAML to the API. Never use `--skip-validate` to get past a validation failure — an invalid workflow (for example a bad `trigger.type`) then fails at the API, often as an opaque **500 Internal Server Error** that looks like a server problem but is really a broken definition the local validator would have caught. Fix the workflow and let validation run. `--skip-validate` is only for when you have already validated the same file separately in the same session.\n\n3. **Releasing before testing.** A freshly imported definition is disabled for a reason. Test it with the execution skill (`trigger_workflow.py`) before calling `release_workflow.py`. Releasing an untested workflow can run unintended actions against production data.\n\n4. **Losing the definition ID.** The import output contains the ID you need for release and execution. Capture it; re-finding it later means a `query_workflows.py --search` round-trip.\n\n5. **Wrong API scope.** Import and release require the Workflow scope with **write** access. A read-only client lists workflows fine but fails on import/release with a permissions error.\n\n6. **Editing the deployed copy, not the source.** Re-importing an edited YAML creates a new definition (or trips the duplicate check). Treat the local YAML as the source of truth; re-import to update, and remember the new definition is disabled again until re-released. Never try to patch a deployed definition in place through the raw workflow update API **or a hand-rolled inline FalconPy call** (`update_definition` in a `python - <<EOF` snippet) — that path is not part of this skill and looping edits against it just returns 500s. (Deleting a whole workflow is fine — use `delete_workflow.py`.)\n\n7. **Looping on unrecoverable import errors.** A 500, a missing plugin `config_id`, or a \"no definition ID\" result will not be fixed by editing the YAML. Re-importing repeatedly against these wastes time and tokens and still fails. Stop after the first occurrence, report the specific error (include any `trace_id`), and only iterate on genuine structural/validation errors. See the error table in step 3.\n\n## Handoff\n\n- **Came from authoring?** You have a validated YAML file — start at step 2 (duplicate check).\n- **Going to execution?** Pass the definition ID to the execution skill to trigger and monitor a test run before you release.\n\n## Reading Guide\n\n| Document | When to read |\n|----------|--------------|\n| `references/console-verification.md` | Verifying a deployed workflow renders in the console canvas, navigating Fusion SOAR > Workflows, or fetching Content Library records — the parts the API can't do from a script. |\n"
}SHA-256: 5f1823ac7abcb3699def97184eb377d436935502b22e5a1ded21d46648496707