Skip to content

fix: remove lxml transitive dep by upgrading pytest-splunk-addon-ui-smartx to 7.0.0 - #2090

Merged
kkedziak-splunk merged 16 commits into
developfrom
chore/test-lxml-removal-smartx
Aug 18, 2026
Merged

kkedziak-splunk merged 16 commits into
developfrom
chore/test-lxml-removal-smartx

Conversation

@kkedziak-splunk

@kkedziak-splunk kkedziak-splunk commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Removes `pytest-splunk-addon-ui-smartx` and `pytest-splunk-addon` from poetry dev deps (avoids urllib3/certifi conflict in the dep tree)
  • Adds `tests/ui/requirements.txt` pinning `pytest-splunk-addon-ui-smartx==7.0.0` — the major release that drops the `lxml` dependency (VULN-85394) and constrains support to Python 3.10–3.13
  • Installs UI deps via `poetry run pip install -r tests/ui/requirements.txt` in the `test-ui` CI job
  • Bumps `test-ui` Python 3.9 → 3.10 (required by smartx 7.0.0)
  • Registers `pytest_splunk_addon_ui_smartx.splunk` via `pytest_plugins` in `tests/ui/conftest.py` (smartx 7.0.0 no longer pulls in `pytest-splunk-addon` which previously auto-registered the `--splunk-*` CLI args)
  • Fixes `tests/unit/commands/test_publish.py` to scope the `open` mock to the publish module, avoiding a Python 3.9.25 regression where `mimetypes` lazy-init clashes with `@patch("builtins.open", ...)`

Motivation

`lxml` (VULN-85394) cannot be upgraded to 6.x in-tree — it is a transitive dependency pulled in by `pytest-splunk-addon-ui-smartx`. The smartx 7.0.0 release removes it entirely. This PR adopts that release and verifies all UI tests pass cleanly.

Test plan

  • `test-ui` passes across all 30 groups × 3 Splunk versions (9.4.10, 10.0.5, 10.2.2)
  • `test-unit` passes across all 6 Python versions (3.9–3.14)
  • `test-smoke` passes across all 6 Python versions
  • `pre-commit`, `build`, `splunk-appinspect` all pass

🤖 Generated with Claude Code

…3.10

- Remove pytest-splunk-addon-ui-smartx and pytest-splunk-addon from
  poetry dev deps to avoid urllib3/certifi conflicts across the dep tree
- Add tests/ui/requirements.txt pointing to the unreleased smartx branch
  (user/kkedziak/drop-eol-python-versions) which drops lxml
- Install UI deps via `poetry run pip` in the test-ui CI job
- Bump test-ui Python from 3.9 to 3.10 (required by new smartx)

Co-Authored-By: Claude <noreply@anthropic.com>
kkedziak-splunk and others added 3 commits August 17, 2026 12:58
kkedziak-splunk and others added 5 commits August 17, 2026 13:26
… mock_open

Python 3.9.25 changed mimetypes to call open() lazily in a way that
collides with builtins.open mocking, causing TypeError in the runner.
Patch the module-level open instead so mimetypes is unaffected.

Co-Authored-By: Claude <noreply@anthropic.com>
…ranch

The new smartx branch (drop-eol-python-versions) no longer depends on
pytest-splunk-addon; instead it ships its own splunk.py with the
--splunk-type/--splunk-host/etc. argument registration. That module must
be explicitly activated via pytest_plugins in the consumer's conftest.
Suppress E402 for conftest.py since pytest_plugins must precede imports.

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes in upstream smartx branch user/kkedziak/drop-eol-python-versions:
- Replace removed find_element_by_css_selector() with find_element(By.CSS_SELECTOR, ...)
  in table.py for Selenium >=4.x compatibility

Co-Authored-By: Claude <noreply@anthropic.com>
@pull-request-size pull-request-size Bot added size/M and removed size/S labels Aug 18, 2026
@kkedziak-splunk
kkedziak-splunk marked this pull request as ready for review August 18, 2026 07:40
@kkedziak-splunk
kkedziak-splunk requested review from a team as code owners August 18, 2026 07:40
@kkedziak-splunk
kkedziak-splunk marked this pull request as draft August 18, 2026 08:37
renovate Bot and others added 4 commits August 18, 2026 10:38
This PR contains the following updates:

| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [js-yaml](https://redirect.github.com/nodeca/js-yaml) | [`4.3.0` →
`4.3.1`](https://renovatebot.com/diffs/npm/js-yaml/4.3.0/4.3.1) |
![age](https://developer.mend.io/api/mc/badges/age/npm/js-yaml/4.3.1?slim=true)
|
![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/js-yaml/4.3.0/4.3.1?slim=true)
|

---

### JS-YAML: Quadratic CPU consumption in !!omap resolution (3.x and
4.x) — CVE-2026-59870 fix not backported

[GHSA-5p4m-2wfm-xmqj](https://redirect.github.com/advisories/GHSA-5p4m-2wfm-xmqj)

<details>
<summary>More information</summary>

#### Details
##### Quadratic CPU consumption in `!!omap` resolution (js-yaml 3.x and
4.x)

##### Summary

`resolveYamlOmap()` enforces key uniqueness for `!!omap` sequences with
a linear
scan (`objectKeys.indexOf(...)`) inside the per-element loop, making
resolution
**O(n²)** in the number of entries. A modestly sized YAML document
therefore
consumes disproportionate CPU inside `yaml.load()`, giving a denial of
service
against any consumer that parses untrusted YAML.

`!!omap` is registered in the **default schema**
(`lib/schema/default.js` → `require('../type/omap')`), so a plain
`yaml.load(untrustedInput)` with no options is affected — no custom
schema or
non-default configuration is required.

**This is the same weakness as CVE-2026-59870 / GHSA-724g-mxrg-4qvm**,
which was
fixed in the 5.x line in 5.2.1. That fix was never backported: both
currently
maintained legacy lines still carry the original implementation.

##### Affected versions

| Line | Latest tested | Status |
|---|---|---|
| 3.x | **3.15.0** | Affected — `objectKeys.indexOf(pairKey)` at
`lib/type/omap.js:29` |
| 4.x | **4.3.0** | Affected — `objectKeys.indexOf(pairKey)` at
`lib/type/omap.js:30` |
| 5.x | 5.2.2 | **Not affected** — fixed in 5.2.1 (uses a `Set`) |

Both figures are the newest release of each line at the time of writing,
so
this is not a "you are on an old version" issue.

##### Details

`lib/type/omap.js` (js-yaml 4.3.0):

```js
if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey)
else return false
```

`objectKeys` grows by one element per entry, and
`Array.prototype.indexOf` is a
linear scan, so resolving an `n`-entry `!!omap` performs roughly
`1 + 2 + … + n` comparisons — quadratic in `n`. The work happens
synchronously
inside `yaml.load()`, blocking the event loop for its whole duration.

The 5.x line already solves exactly this by tracking seen keys in a
`Set`
(`src/tag/sequence/omap.ts`):

```ts
if (carrier.seen.has(key)) return 'duplicate key in ordered map'
carrier.seen.add(key)
```

##### Proof of concept

```js
// poc.js  —  node poc.js
const yaml = require('js-yaml');
const doc = n => '!!omap\n' + Array.from({length: n}, (_, i) => `- k${i}: ${i}`).join('\n') + '\n';

for (const n of [10000, 20000, 40000, 80000]) {
  const d = doc(n), t = Date.now();
  yaml.load(d);                      // default schema, no options
  console.log(`n=${n} bytes=${d.length} load=${Date.now() - t}ms`);
}
```

##### Measured (node v20.20.2, default heap, no flags)

**js-yaml 4.3.0**

```
n=10000  bytes=137787   load=54ms
n=20000  bytes=297787   load=169ms
n=40000  bytes=617787   load=646ms
n=80000  bytes=1257787  load=2607ms
```

**js-yaml 3.15.0**

```
n=10000  bytes=137787   load=53ms
n=20000  bytes=297787   load=166ms
n=40000  bytes=617787   load=641ms
n=80000  bytes=1257787  load=2567ms
```

Runtime grows by a factor of ~4 for each doubling of `n`, which is the
signature of O(n²) (linear growth would be ~2×).

Scaling further: a **2.48 MB** document with 150,000 entries blocked
`yaml.load()` for **10.8 seconds**.

##### Impact

Any service that parses attacker-influenced YAML with js-yaml 3.x or 4.x
can be
stalled with a small input. Because the loop is synchronous, a single
request
blocks the Node.js event loop and stalls every other request in the
process —
so the amplification is per-process, not just per-request.

Suggested severity: consistent with **CVE-2026-59870** (the same
weakness in
5.x), i.e. Availability-only impact, network attack vector, no
privileges or
user interaction required.

##### Suggested fix

Mirror the 5.x fix — replace the linear scan with a `Set`:

```js
// lib/type/omap.js
const seen = new Set()
// ...
if (seen.has(pairKey)) return false
seen.add(pairKey)
```

This preserves the existing duplicate-key rejection semantics exactly
while
making resolution O(n). A `maxOmapLength`-style cap would also work, but
the
`Set` matches what 5.x already ships and requires no new option.

##### References

- CVE-2026-59870 / GHSA-724g-mxrg-4qvm — same weakness in 5.0.0–5.2.0,
fixed in 5.2.1
- `lib/type/omap.js` (3.x, 4.x) — the affected resolver
- `lib/schema/default.js` — registers `!!omap` in the default schema

##### Discovery

Found by an automated static-analysis and executed-proof-of-concept
scanner run
against js-yaml 4.2.0, then manually verified against 3.15.0 and 4.3.0
by
executing the proof of concept above. All timings in this report were
measured
on the **current** releases of each line, not on the version originally
scanned.

#### Severity
- CVSS Score: 7.5 / 10 (High)
- Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H`

#### References
-
[https://github.com/nodeca/js-yaml/security/advisories/GHSA-5p4m-2wfm-xmqj](https://redirect.github.com/nodeca/js-yaml/security/advisories/GHSA-5p4m-2wfm-xmqj)
-
[https://github.com/advisories/GHSA-5p4m-2wfm-xmqj](https://redirect.github.com/advisories/GHSA-5p4m-2wfm-xmqj)

This data is provided by the [GitHub Advisory
Database](https://redirect.github.com/advisories/GHSA-5p4m-2wfm-xmqj)
([CC-BY
4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)).
</details>

---

### Release Notes

<details>
<summary>nodeca/js-yaml (js-yaml)</summary>

###
[`v4.3.1`](https://redirect.github.com/nodeca/js-yaml/compare/4.3.0...4.3.1)

[Compare
Source](https://redirect.github.com/nodeca/js-yaml/compare/4.3.0...4.3.1)

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these
updates again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/splunk/addonfactory-ucc-generator).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4yNC4wIiwidXBkYXRlZEluVmVyIjoiNDQuMjkuNSIsInRhcmdldEJyYW5jaCI6ImRldmVsb3AiLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Replaces git branch reference with the official PyPI release that drops
the lxml dependency (VULN-85394).

Co-Authored-By: Claude <noreply@anthropic.com>
@pull-request-size pull-request-size Bot added size/S and removed size/M labels Aug 18, 2026
@kkedziak-splunk
kkedziak-splunk marked this pull request as ready for review August 18, 2026 09:28
kkedziak-splunk and others added 2 commits August 18, 2026 16:05
Major release that drops Python 3.9 support (EOL) and constrains
compatibility to Python 3.10–3.13.

Co-Authored-By: Claude <noreply@anthropic.com>
@kkedziak-splunk kkedziak-splunk changed the title chore: move UI test deps to requirements.txt, test lxml removal from smartx fix: remove lxml transitive dep by upgrading pytest-splunk-addon-ui-smartx to 7.0.0 Aug 18, 2026
@kkedziak-splunk
kkedziak-splunk merged commit 63f52bb into develop Aug 18, 2026
@kkedziak-splunk
kkedziak-splunk deleted the chore/test-lxml-removal-smartx branch August 18, 2026 14:35
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 18, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants