Skip to content

Improve validate.py: fake ID rejection, severity docs, and correct cel_expression+else handling - #8

Open
mraible wants to merge 9 commits into
eth0izzle:mainfrom
CrowdStrike:fix/validate-cel-else
Open

Improve validate.py: fake ID rejection, severity docs, and correct cel_expression+else handling#8
mraible wants to merge 9 commits into
eth0izzle:mainfrom
CrowdStrike:fix/validate-cel-else

Conversation

@mraible

@mraible mraible commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Two validation improvements, one documentation fix, and a correction to an earlier rule in this PR. Discovered through eval runs that generate workflows and judge them independently.

1. Correct cel_expression + else handling

An earlier commit in this PR added a rule rejecting cel_expression + else, based on the claim in cel-expressions.md that only FQL-style expression supports else. That claim is wrong. Fusion engineering confirmed that CEL conditions support both else and else_if, and the workflow engine's own translator test data uses exactly that combination. The YAML is a conversion of the workflow JSON (which the backend processes), and the else branch maps to an exclusive gateway's default flow.

The latest commit reverses that rule, so the validator no longer flags valid CEL workflows. It also corrects cel-expressions.md and yaml-schema.md to document the real CEL if / else-if / else syntax, and adds a regression test asserting the combination is accepted. Prefer cel_expression for new workflows; FQL-style expression is legacy.

2. Reject all-same-character action IDs

When the model skips action_search.py it sometimes writes all-zeros or all-f IDs that pass the hex format check but are fabricated. The error message directs the model to run action_search.py to get the real ID.

3. Document severity as numeric (1-5) in trigger-types.md

The EPP trigger section listed available fields but did not include Severity or document its type. The model inconsistently used string comparison (== 'Critical') vs numeric (>= 4) because it had to guess. Added the severity value table and correct/incorrect CEL examples.

Verification

  • pytest tests/: all passing, including a new regression test that cel_expression + else is accepted
  • pylint validate.py: 10.00/10

Reviewed and merged internally before being brought back here.

mraible added 5 commits May 19, 2026 10:25
…ion (#4)

* Add Fusion SOAR JSON structure reference from Charlotte team

Authoritative BPMN-based JSON schema doc covering the internal workflow
model: triggers, activities, flows, gateways, submodels (loops), CEL
extensions (cs.* functions), data references, custom variables, and
three complete examples. Updates SKILL.md to reference the new doc
when authoring workflows.

* Add local structural validation to validate.py

Adds a structural_check() step between pre-flight and API validation
that catches schema errors without needing API credentials. Validates:
action IDs are 32-char hex, actions have required id/name fields,
class-based actions include version_constraint, trigger type is valid,
next references resolve to defined labels, loop for.input matches a
trigger parameter, and data references have balanced brackets.

Also adds PyYAML to requirements.txt (needed for yaml.safe_load) and
11 new tests covering each validation rule (93 total, all passing).

* Bump dependencies to latest versions

crowdstrike-falconpy 1.6.1 → 1.6.2
pytest 9.0.2 → 9.0.3
PyYAML 6.0.2 → 6.0.3
* Fix README install instructions

- Replace generic SKILL-NAME placeholder with actual plugin name (fusion-workflows)
- Add CrowdStrike fork as primary install option with latest improvements
- Keep upstream (eth0izzle) as stable alternative
- Clarify that both repos provide the same plugin with two skills
- Update manual install to show both repo options

* Keep upstream repo URL, fix only the SKILL-NAME placeholder

Revert CrowdStrike fork references. The actual bug was the generic
SKILL-NAME placeholder, which is now replaced with the real plugin
name (fusion-workflows) and a note about the two skills it provides.

* Remove .git suffix from marketplace add command

The /plugin marketplace add command takes the bare repo URL without
the .git suffix. The git clone command in Manual Setup keeps it.
Real Fusion SOAR playbooks exported from the CrowdStrike Content Library
with real action IDs. The import logic detects non-global actions and
prompts users to configure integrations or substitute available actions.

Categories:
- threat-intel: VirusTotal domain/URL enrichment + Zscaler blocklist
- identity-response: brute force auto-resolution, phishing with ITP
- notifications: Slack messaging, endpoint containment with approval
- ngsiem: duplicate detection auto-close
- response-actions: 6 Palo Alto NGFW EDL/DAG playbooks
- tutorials: 6 Introduction to... concept playbooks

CrowdStrike-native action IDs are universal across all clouds.
Plugin actions (Slack, Zscaler, PAN NGFW) require the integration
installed from the CrowdStrike Store.
Two bugs in execute.py, both confirmed against live workflow executions:

- execute_workflow() assumed the execute endpoint returns resources as
  a list of dicts (resources[0].get('id')), but it returns bare
  execution-ID strings, crashing with 'str' object has no attribute 'get'.
  Now handles both shapes.
- poll_results() checked status in ('completed','failed','error'), but
  the execution-results API returns capitalized statuses
  (Succeeded/Failed/Canceled/NonRecoverable/ActionRequired per
  references/best-practices.md). A finished run never matched the terminal
  set, so polling always ran until timeout. Now matches the documented
  statuses case-insensitively.

Updated tests to use real API status casing and added coverage for the
bare-string execution ID.
CEL expressions do not support else syntax — only FQL expressions do. When a
model generates a condition with both cel_expression and else, the else branch
becomes unreachable, making the workflow functionally broken while still
importing cleanly. Add an explicit validation error to catch this early.
@mraible
mraible marked this pull request as draft June 12, 2026 15:07
mraible added 3 commits June 12, 2026 09:48
The initial check only covered top-level conditions. Workflows with conditions
nested inside loops (like the Okta session revocation workflow) were missed.
The model inconsistently uses string comparison ('Critical') vs numeric (>= 4)
because the trigger docs didn't specify the field type. Added the severity table
and correct/incorrect CEL examples so the model knows to use numeric comparison.
When the model skips action_search.py it sometimes writes all-zeros or all-f
IDs that pass the hex format check but are obviously fabricated. The error
message directs the model to run action_search.py to get the real ID.
@mraible mraible changed the title Validate that cel_expression conditions do not use else branching Improve validate.py: catch cel_expression+else, fake IDs, and document severity field Jun 12, 2026
@mraible

mraible commented Jun 12, 2026

Copy link
Copy Markdown
Contributor Author

@eth0izzle I made the same mistake with this PR as #7. I'm happy to help resolve conflicts if necessary.

FWIW, I will be on vacation from tonight - June 23rd and won't have access to my laptop until I'm back.

@mraible
mraible marked this pull request as ready for review June 12, 2026 17:24
The docs and validator asserted that only FQL-style `expression` supports
`else` branching and that `cel_expression` + `else` is invalid. This is wrong.
CEL conditions support both `else` and `else_if`, confirmed against the Fusion
workflow engine's own translator test data (cel_with_else_if.yaml/.json) and
by Tim Kuhlman (Principal Engineer, Fusion).

Changes:
- validate.py: remove the rule that rejected cel_expression + else (it would
  flag valid workflows as structural errors)
- cel-expressions.md, yaml-schema.md: replace the "only expression supports
  else" claim with the correct CEL if/else-if/else syntax, and note it maps to
  an exclusive gateway's default flow in the underlying JSON
- test_validate.py: add a regression test asserting cel_expression + else is
  accepted

Prefer cel_expression for new workflows; FQL-style expression is legacy.
@mraible mraible changed the title Improve validate.py: catch cel_expression+else, fake IDs, and document severity field Improve validate.py: fake ID rejection, severity docs, and correct cel_expression+else handling Jun 30, 2026
@mraible

mraible commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

Pushed a follow-up commit (7059010) that reverses the cel_expression + else rule this PR originally added.

After opening this, Fusion engineering confirmed CEL conditions do support else and else_if. The engine's own translator test data uses that combination, the YAML is just a conversion of the workflow JSON the backend processes, and the else branch maps to an exclusive gateway's default flow. So the original rule was based on a wrong assumption and would have flagged valid workflows.

The commit removes the rule, corrects cel-expressions.md and yaml-schema.md to show the real CEL if / else-if / else syntax, and adds a regression test that the combination is accepted. The PR's other changes (fake-ID rejection, severity docs) are unchanged. I left the original commits in place rather than force-pushing, so the trail is honest. Happy to squash if you'd prefer. Full context is in the updated description above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant