datoon 1.7.3__tar.gz → 1.7.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {datoon-1.7.3 → datoon-1.7.4}/CHANGELOG.md +7 -0
- {datoon-1.7.3 → datoon-1.7.4}/PKG-INFO +1 -1
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/_version.py +3 -3
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/xml.py +16 -1
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon.egg-info/PKG-INFO +1 -1
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon.egg-info/scm_version.json +2 -2
- {datoon-1.7.3 → datoon-1.7.4}/tests/unit/test_readers.py +20 -0
- {datoon-1.7.3 → datoon-1.7.4}/.agents/plugins/marketplace.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.claude-plugin/marketplace.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.claude-plugin/plugin.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.editorconfig +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.gitattributes +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/dependabot.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/workflows/package-installer-smoke.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/workflows/pages.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/workflows/pre-commit.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/workflows/publish-mcp.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/workflows/publish.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/workflows/release.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/workflows/tests.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/workflows/validate-artifacts.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.github/workflows/workflow-lint.yml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.gitignore +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.pre-commit-config.yaml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/.releaserc.yaml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/CLAUDE.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/CONTRIBUTING.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/INSTALL.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/LICENSE +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/MARKETPLACES.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/README.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/SECURITY.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/SKILL.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/assets/datoon-banner.svg +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/REPORT.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/agent_results.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/expected_answers.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/generate_payloads.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/payloads/1_large.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/payloads/1_medium.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/payloads/1_small.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/payloads/2_large.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/payloads/2_medium.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/payloads/2_small.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/payloads/3_large.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/payloads/3_medium.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/payloads/3_small.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/reports/1_large.report.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/reports/1_medium.report.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/reports/1_small.report.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/reports/2_large.report.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/reports/2_medium.report.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/reports/2_small.report.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/reports/3_large.report.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/reports/3_medium.report.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/reports/3_small.report.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/scored_agent_results.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/toon/1_large.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/toon/1_medium.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/toon/1_small.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/toon/2_large.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/toon/2_medium.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/toon/2_small.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/toon/3_large.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/toon/3_medium.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/agent_skill_eval/toon/3_small.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/payloads.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/results/.gitkeep +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/benchmarks/run.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/datoon/SKILL.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/datoon.skill +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/docs/.nojekyll +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/docs/app.js +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/docs/assets/datoon-banner.svg +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/docs/index.html +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/docs/styles.css +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/glama.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/install.sh +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/plugins/datoon/.codex-plugin/plugin.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/plugins/datoon/skills/datoon/SKILL.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/pyproject.toml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/scripts/ab_skill_benchmark.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/scripts/install.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/scripts/summarize_agent_skill_eval.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/scripts/validate_plugin_metadata.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/scripts/validate_skill_sync.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/server.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/setup.cfg +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/setup.sh +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/skills/datoon/README.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/skills/datoon/SKILL.md +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/smithery.yaml +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/__init__.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/analyzer.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/cli.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/converter.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/mcp_server.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/models.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/py.typed +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/__init__.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/_coerce.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/_tabular.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/columnar.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/csv.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/excel.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/jsonl.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/numbers.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon/readers/yaml.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon.egg-info/SOURCES.txt +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon.egg-info/dependency_links.txt +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon.egg-info/entry_points.txt +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon.egg-info/requires.txt +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon.egg-info/scm_file_list.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/src/datoon.egg-info/top_level.txt +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/fixtures/users.expected.toon +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/fixtures/users.json +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/integration/test_toon_cli_integration.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/unit/test_analyzer.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/unit/test_cli.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/unit/test_converter_policy.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/unit/test_installer.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/unit/test_mcp_server.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/unit/test_models.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/tests/unit/test_tabular_rows.py +0 -0
- {datoon-1.7.3 → datoon-1.7.4}/uv.lock +0 -0
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [1.7.4](https://github.com/andrii-su/datoon/compare/v1.7.3...v1.7.4) (2026-07-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **xml:** refuse DTD/DOCTYPE to block entity-expansion DoS ([#38](https://github.com/andrii-su/datoon/issues/38)) ([ef6a35e](https://github.com/andrii-su/datoon/commit/ef6a35e624176aab0a648794715c2d99411421d7))
|
|
7
|
+
|
|
1
8
|
## [1.7.3](https://github.com/andrii-su/datoon/compare/v1.7.2...v1.7.3) (2026-07-07)
|
|
2
9
|
|
|
3
10
|
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.7.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 7,
|
|
21
|
+
__version__ = version = '1.7.4'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 7, 4)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g9c1017702'
|
|
@@ -1,15 +1,30 @@
|
|
|
1
|
-
"""XML reader using stdlib xml.etree.ElementTree.
|
|
1
|
+
"""XML reader using stdlib xml.etree.ElementTree.
|
|
2
|
+
|
|
3
|
+
The stdlib parser rejects external entities but expands internal ones, so a DTD
|
|
4
|
+
can smuggle a billion-laughs DoS. datoon may process untrusted payloads, so DTDs
|
|
5
|
+
are refused outright. ``<!DOCTYPE`` is a fixed XML token (no internal
|
|
6
|
+
whitespace), so a literal scan reliably catches every declaration expat would
|
|
7
|
+
process.
|
|
8
|
+
"""
|
|
2
9
|
|
|
3
10
|
from __future__ import annotations
|
|
4
11
|
|
|
12
|
+
import re
|
|
5
13
|
import xml.etree.ElementTree as ET
|
|
6
14
|
from typing import Any
|
|
7
15
|
|
|
8
16
|
from datoon.readers._coerce import coerce_scalar as _coerce
|
|
9
17
|
|
|
18
|
+
_DOCTYPE_RE = re.compile(r"<!DOCTYPE", re.IGNORECASE)
|
|
19
|
+
|
|
10
20
|
|
|
11
21
|
def read_xml(text: str) -> list[dict[str, Any]]:
|
|
12
22
|
"""Parse XML into a list of row dicts from the dominant repeated child element."""
|
|
23
|
+
if _DOCTYPE_RE.search(text):
|
|
24
|
+
raise ValueError(
|
|
25
|
+
"XML with a DOCTYPE/DTD is not allowed (entity-expansion risk)."
|
|
26
|
+
)
|
|
27
|
+
|
|
13
28
|
try:
|
|
14
29
|
root = ET.fromstring(text)
|
|
15
30
|
except ET.ParseError as exc:
|
|
@@ -250,6 +250,26 @@ def test_read_xml_rejects_non_finite() -> None:
|
|
|
250
250
|
assert rows[1]["v"] == "nan"
|
|
251
251
|
|
|
252
252
|
|
|
253
|
+
def test_read_xml_rejects_dtd_billion_laughs() -> None:
|
|
254
|
+
# Internal entity expansion (billion laughs) is a DoS vector; DTDs are refused.
|
|
255
|
+
payload = (
|
|
256
|
+
'<!DOCTYPE lolz [<!ENTITY lol "lol">'
|
|
257
|
+
'<!ENTITY lol2 "&lol;&lol;&lol;">]>'
|
|
258
|
+
"<rows><r>&lol2;</r></rows>"
|
|
259
|
+
)
|
|
260
|
+
with pytest.raises(ValueError, match="DOCTYPE"):
|
|
261
|
+
read_xml(payload)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def test_read_xml_rejects_external_entity_dtd() -> None:
|
|
265
|
+
payload = (
|
|
266
|
+
'<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>'
|
|
267
|
+
"<rows><r>&xxe;</r></rows>"
|
|
268
|
+
)
|
|
269
|
+
with pytest.raises(ValueError, match="DOCTYPE"):
|
|
270
|
+
read_xml(payload)
|
|
271
|
+
|
|
272
|
+
|
|
253
273
|
def test_read_xml_invalid_raises() -> None:
|
|
254
274
|
with pytest.raises(ValueError, match="Invalid XML"):
|
|
255
275
|
read_xml("<not closed>")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|