Releases: Hebbian-Robotics/hflow
Release list
v0.2.4
Security
GHSA-57x4-5jwm-2xg8 (#271): curate(..., constrained=True) interpolated caller SQL into a COPY statement, so a tenant could smuggle a second statement past the sandbox and run arbitrary DDL/DML on the connection. curate() now parses with extract_statements and refuses anything that is not exactly one SELECT.
Severity is Low. hflow serve, the only tenant-SQL surface shipped here, was never affected: its curation routes have always applied the same one-SELECT rule before any interpolation. Reaching the vulnerable path meant calling curate() directly from an integration without that guard. Even then the lockdown held everywhere it mattered, since constrained connections materialize the catalog in memory before the constraints land, so file access, ATTACH, extension loading, and the catalog's own files all stayed refused. What an attacker gained was arbitrary statements against a throwaway in-memory copy of data they were already permitted to query, on a connection closed at the end of the call.
Reported by @Raghav7-tech, who also wrote the fix.
Upgrade if you call curate(..., constrained=True) or open_catalog_connection(..., constrained=True) with SQL you did not write.
Note this narrows what curate() accepts: PIVOT is now refused, because DuckDB expands it into a CREATE plus a SELECT. DESCRIBE and SUMMARIZE now pass where they were previously parser errors.
Added
- First-class LeRobot v3 dataset import:
hflow.import_lerobot_datasetandhflow import lerobot. - DuckDB catalog UI.
- First-class model evaluation evidence.
- EgoSuite hand evaluation example, with natural sampling (#262, #270).
hflow servewarns when it binds past loopback, since the server authenticates nobody (#269).camera_frame_statsreports<topic>/decode_deficit_pct: messages that arrived but did not decode, separate from the existing rate-based deficit.camera_frame_statsversion 1 to 2 (#265).
Fixed
- LeRobot converter output decodes in full; B-frames disabled (#251).
doctorchunk purity proxy checks the provenance group map (#252), and per-group chunk time order is enforced (#256).- Egocentric contact-sheet enrichment resolves its camera explicitly (#253).
- Hand-count evaluation schema constrains its value set (#258).
VideoEpisodeSpecrefuses bools and non-finite numbers, matching its sibling validator (#277).- Both evaluation examples refuse missing and malformed summaries with exit 2 instead of a traceback (#272, #290).
Tests
- Module boundaries are enforced mechanically:
hflow.testingmay not reach the canonical writer, and nothing undersrc/hflow/may importhflow_serverat module scope (#263). - Malformed H.264 input guards, and the snapshot export symlink and null-
episode_idrefusals, are pinned (#282, #283). - Five workspace and catalog refusal cases (#249).
Full changelog: v0.2.3...v0.2.4
HFlow 0.2.3
The transform now repairs one thing it used to refuse: a foxglove.CompressedVideo stream missing its access-unit delimiters is fixed by inserting them, with no re-encode, so the slice data is untouched and conforming messages stay byte-identical. Standard recordings that could not be canonicalized before now can be.
Beyond that this is a hardening release. Roughly a dozen entry points that accepted values they should never have accepted now refuse them at the boundary, with a message naming the field: TransformConfig (bool and out-of-range crf, non-finite gop_seconds), Threshold (infinite and bool values, plus a large-int OverflowError), contact_sheet (tile_width and bool sizing arguments), SyntheticEpisodeSpec, data-root parsing (an empty root silently meant the current directory), and batch planning.
The LeRobot converter reads any Dataset v3 repository from its own metadata instead of PushT constants, converting every selected camera, and python -m hflow works alongside the console script.
TRANSFORM_BEHAVIOR_VERSION moved from 5 to 7. Canonical output for video episodes can differ from 0.2.2, so pipeline_version and episode_id change and a re-ingest rewrites those episodes rather than reusing them. State-only episodes are unaffected.
The new refusals are a behaviour change. A pipeline passing a value the list above now rejects will raise where it previously ran. Every one of them was accepting something meaningless, but the failure is at construction rather than later.
What's Changed
- refuse empty and whitespace-only measurement keys before the wide-view pivot by @ayam04 in #185
- feat(transform): insert missing H.264 access-unit delimiters by @WilliamK112 in #184
- test(storage): cover bucket create-if-absent races by @WilliamK112 in #186
- fix(app): unify local source identities by @WilliamK112 in #187
- cli: describe runtime subcommands in help output by @wuisabel-gif in #188
- test(cli): cover stale pipeline app errors by @WilliamK112 in #192
- cli: describe dataset, export, and serve commands by @wuisabel-gif in #194
- docs: add environment-variable reference by @omnilink-tech in #196
- feat(runtime): plan outstanding stages in the Airflow lane by @chiruu12 in #195
- refactor(checks): camera_frame_stats owns its key set (#182) by @Sagar-024 in #197
- refactor(checks): the remaining five defaults own their key set (#182) by @Sagar-024 in #198
- fix(video-measurements): refuse bool and wrong types in settings dataclasses by @afonsojanu in #201
- docs: document input MCAP converter contract by @tunglambk in #202
- fix: validate batch planning inputs by @anisayakmitra-in in #207
- test(video-measurements): cover the range and value refusals by @afonsojanu in #208
- docs(benchmarks): measure chunk floor on manipulation data by @sylvesterkaczmarek in #210
- docs: add contract docstrings for exported API names (#60) by @NiranjanKumar001 in #211
- refactor(runtime): parse the conf flag where mode is parsed by @chiruu12 in #212
- fix: avoid replanning camera-less media by @tunglambk in #213
- fix(video-measurements): keep empty freeze totals float by @tunglambk in #216
- refactor(transform): type pass-through video messages by @WilliamK112 in #217
- fix(contact-sheet): escape apostrophes for drawtext by @tunglambk in #218
- fix: validate transform config numeric settings by @anisayakmitra-in in #224
- fix(testing): refuse invalid SyntheticEpisodeSpec in synthesize_episode by @Soham-47 in #226
- fix(ffmpeg): validate contact sheet sizing arguments by @Iamnotphage in #227
- test(checks): stop pinning a libm-dependent content digest by @chiruu12 in #228
- feat(lerobot): generalize converter to LeRobot Dataset v3 metadata (#189) by @ayam04 in #230
- fix(checks): remove dead type check in trajectory_metrics and document conditional key by @NiranjanKumar001 in #231
- fix(steps): reject non-finite and boolean threshold values by @victorwon2001 in #232
- refactor(app): type step and transform kinds by @Iamnotphage in #233
- Docs: docstrings for
CanonicalMcapWriterpublic methods an by @Mr-Neutr0n in #235 - docs: document doctor finding codes by @victorwon2001 in #236
- fix(storage): refuse empty local paths and bucketless URLs (#238) by @mohit-bhandari45 in #242
- fix(cli): add main.py to enable python -m hflow execution by @tarun1790 in #243
- Sharpen video-measurement boundary guard to catch all hflow import forms by @mohit-bhandari45 in #244
- Add swappable Build AI evaluation example by @kstonekuan in #248
New Contributors
- @wuisabel-gif made their first contribution in #188
- @omnilink-tech made their first contribution in #196
- @afonsojanu made their first contribution in #201
- @tunglambk made their first contribution in #202
- @anisayakmitra-in made their first contribution in #207
- @sylvesterkaczmarek made their first contribution in #210
- @NiranjanKumar001 made their first contribution in #211
- @Soham-47 made their first contribution in #226
- @Iamnotphage made their first contribution in #227
- @victorwon2001 made their first contribution in #232
- @Mr-Neutr0n made their first contribution in #235
- @mohit-bhandari45 made their first contribution in #242
- @tarun1790 made their first contribution in #243
Full Changelog: v0.2.2...v0.2.3
HFlow 0.2.2
HFlow now uses explicit, author-declared versions for checks, enrichments, and derived channels. Every registration must pass version=, and authors bump it when results are no longer comparable. HFlow no longer fingerprints Python functions, so the version contract is portable across SDK languages.
This is an intentional pre-1.0 breaking change. Existing pipelines must add explicit versions before upgrading.
What's Changed
- fix: Reject inverted or negative interval bounds on append by @VedantMadane in #174
- Cache frame_stats per video to fix doubled decode cost by @Sagar-024 in #175
- fix: refuse non-finite catalog measurements by @sharonyao1127 in #176
- docs: describe benchmark report as published and fix stale claims by @tasodoufu in #179
- fix(catalog): report a crashed critical check as unverified by @chiruu12 in #180
- fix(checks): skip defaults whose keys the pipeline already emitted (#177) by @Sagar-024 in #178
- fix(dataset): select only ok episodes by default by @chiruu12 in #183
New Contributors
- @VedantMadane made their first contribution in #174
- @sharonyao1127 made their first contribution in #176
Full Changelog: v0.2.1...v0.2.2
HFlow 0.2.1
HFlow 0.2.1 makes the current pre-v1 workflow available as an installable release.
Highlights:
- Add opinionated project defaults through
hflow.toml, automatic built-in checks, dataset manifests, and planned re-ingest. - Export portable dataset snapshots as standard Parquet tables with optional copied media for tools such as Renumics Spotlight and FiftyOne.
- Expand deterministic quality checks and declarative gates, including opt-in motion and MediaPipe hand-presence checks.
- Improve catalog provenance, curation diagnostics and dry runs, staged execution, runtime validation, and error reporting.
- Add reproducible stress and LeRobot PushT examples.
This is a pre-v1 release. Stored-data compatibility remains explicit and versioned; review the repository documentation when upgrading.
Full changelog: v0.2.0...v0.2.1
HFlow 0.2.0
First community release of HFlow by Hebbian Robotics.
Highlights:
- Build physical-AI data pipelines from plain Python transforms, checks, labels, and enrichments.
- Process episodes locally with no scheduler, or render an Airflow 3 runtime for durable batch execution.
- Write canonical MCAP episodes with provenance and curate Parquet catalogs with DuckDB SQL.
- Use local, S3, GCS, or Azure data roots.
This is a pre-v1 release. The Hebbian Robotics project begins at 0.2.0; the older PyPI 0.1.x files belong to the unrelated project that previously held the package name.