elastic / elastic/integrations

[bug-hunter] CrowdStrike identity assessment stream can stall after low remainingPoints

Open
#19,029 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Handlebars
Stars
333
Forks
647
Avg merge
3d 4h
Merged PRs (30d)
209

Description

## Impact
The CrowdStrike `identity_protection_assessment` stream can stop ingesting assessment events and never recover after one low-point response. Affected users silently stop receiving new identity assessment data.

## Reproduction Steps
1. From repository root, run this new minimal failing test:

```python
# repro_identity_assessment_stall.py
state = {
'worklist': ['d1', 'd2'],
'next': 0,
'last_remaining': 50,
'min_remaining_points': 100,
}

def step(s):
s = dict(s)
# Mirrors packages/crowdstrike/.../cel.yml.hbs logic.
if not ('worklist' in s and len(s['worklist']) > 0):
s.update({'worklist': ['new-domain'], 'next': 0, 'last_remaining': 500000})
if ('worklist' not in s) or len(s['worklist']) == 0:
return s
if int(s.get('next', 0)) >= len(s['worklist']):
out = dict(s); out.update({'events': [], 'want_more': False})
out.pop('worklist', None); out.pop('next', None); out.pop('last_remaining', None)
return out
if ('last_remaining' in s) and int(s['last_remaining']) < int(s['min_remaining_points']):
out = dict(s); out.update({'events': [], 'want_more': False})
return out
return dict(s, events=[{'ok': True}], next=int(s['next']) + 1, want_more=int(s['next']) + 1 < len(s['worklist']))

s1 = step(state)
s2 = step(s1)
# Expected recovery path: throttled state should be reset so next tick can re-fetch domains.
assert 'worklist' not in s2, f"BUG: stale worklist persists and stream stalls: {s2}"
```

2. Execute:

```bash
python repro_identity_assessment_stall.py
```

## Expected vs Actual
**Expected:** After throttling (`remainingPoints < min_remaining_points`), stream state is reset so a later tick can re-run domains discovery and resume ingestion.

**Actual:** `worklist`, `next`, and `last_remaining` persist unchanged; each subsequent tick re-enters the same throttled branch and emits no events forever.

Observed output:

```text
Traceback (most recent call last):
File "repro_identity_assessment_stall.py", line 30, in
assert 'worklist' not in s2, f"BUG: stale worklist persists and stream stalls: {s2}"
AssertionError: BUG: stale worklist persists and stream stalls: {'worklist': ['d1', 'd2'], 'next': 0, 'last_remaining': 50, 'min_remaining_points': 100, 'events': [], 'want_more': False}
```

## Failing Test
```python
state = {
'worklist': ['d1', 'd2'],
'next': 0,
'last_remaining': 50,
'min_remaining_points': 100,
}

def step(s):
s = dict(s)
if not ('worklist' in s and len(s['worklist']) > 0):
s.update({'worklist': ['new-domain'], 'next': 0, 'last_remaining': 500000})
if ('worklist' not in s) or len(s['worklist']) == 0:
return s
if int(s.get('next', 0)) >= len(s['worklist']):
out = dict(s); out.update({'events': [], 'want_more': False})
out.pop('worklist', None); out.pop('next', None); out.pop('last_remaining', None)
return out
if ('last_remaining' in s) and int(s['last_remaining']) < int(s['min_remaining_points']):
out = dict(s); out.update({'events': [], 'want_more': False})
return out
return dict(s, events=[{'ok': True}], next=int(s['next']) + 1, want_more=int(s['next']) + 1 < len(s['worklist']))

s1 = step(state)
s2 = step(s1)
assert 'worklist' not in s2, f"BUG: stale worklist persists and stream stalls: {s2}"
```

## Evidence
- `packages/crowdstrike/data_stream/identity_protection_assessment/agent/stream/cel.yml.hbs:43-46` skips the domains request whenever `state.worklist` exists.
- `packages/crowdstrike/data_stream/identity_protection_assessment/agent/stream/cel.yml.hbs:135-141` handles low remaining points by setting `events`/`want_more` but does **not** drop `worklist`, `next`, or `last_remaining`.
- `packages/crowdstrike/data_stream/identity_protection_assessment/agent/stream/cel.yml.hbs:126-141` then repeats the same branch on the next run, creating a stable no-progress state.

> [!NOTE]
>
> 🔒 Integrity filter blocked 1 item
>
> The following item were blocked because they don't meet the GitHub integrity level.
>
> - [#17846](https://github.com/elastic/integrations/issues/17846) `search_issues`: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
>
> To allow these resources, lower `min-integrity` in your GitHub frontmatter:
>
> ```yaml
> tools:
> github:
> min-integrity: approved # merged | approved | unapproved | none
> ```
>
>

---
[What is this?](https://ela.st/github-ai-tools) | [From workflow: Bug Hunter](https://github.com/elastic/integrations/actions/runs/25915826626)

Give us feedback! React with 🚀 if perfect, 👍 if helpful, 👎 if not.
> - [x] expires on May 22, 2026, 11:49 AM UTC

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.