COOLJAPAN
← All posts

OxiGeo 0.2.1 Released — 342 Defects Found, 314 Fixed, and the Last C Dependency Is Gone

OxiGeo 0.2.1 is a production-hardening release: a multi-agent defect sweep found 342 bugs and fixed 314, including two CRITICAL silent-corruption decoders (JPEG2000, GRIB2) and a WFS-T fail-open security hole. A new axum gateway serving layer ships, and retiring oxigeo-kafka makes the workspace fully C-toolchain-free.

release oxigeo gdal geospatial pure-rust security

A defect sweep across a workspace is only as good as how many of its findings actually get fixed.

Today we released OxiGeo 0.2.1 — a production-hardening release built around a workspace-wide, multi-agent defect sweep across every crate. It surfaced 342 confirmed defects and turned 314 of them into real fixes across 38 crate lanes (~520 files). The remaining 79 weren’t swept under the rug either — each is left with a typed error (Unsupported* / NotImplemented / DecodingError) instead of silently wrong output.

No C. No C++. No Fortran. And as of 0.2.1, one dependency less than that promise used to cover: oxigeo-kafka — the workspace’s only crate that ever required a C toolchain — is retired for good, so cargo check --workspace --all-features no longer needs cmake or a system C compiler anywhere in the tree. OxiGeo still compiles to a single static binary (or WASM) and runs everywhere Rust runs.

Why 0.2.1 is a game changer

A “we found N bugs” release note is easy to write and easy to under-deliver on. Half-fixed findings, silently dropped edge cases, and defect counts with no fix count attached are common enough that the number alone doesn’t mean much:

OxiGeo 0.2.1 closes all of that out:

Technical Deep Dive: what the sweep actually touched

  1. Format drivers. GeoTIFF gets real planar-configuration (PlanarConfiguration=2) decoding, authoritative EPSG projected/geographic classification, and a working JPEG/WebP writer path. The Shapefile polygon reader now reconstructs multi-part polygons by ESRI ring winding (clockwise exterior / CCW hole) with containment-based hole assignment instead of merging rings from separate islands into one polygon. NetCDF-4 and HDF5 readers recurse into HDF5 sub-groups instead of silently dropping their variables, and the HDF5 writer’s chunking/compression/fill-value hints now go through a real chunked write path instead of being accepted and ignored.

  2. A new gateway serving layer. oxigeo-gateway’s Gateway::serve() used to accept TCP connections and do nothing with them. 0.2.1 replaces it with a real axum 0.8 HTTP service: GatewayServer / GatewayServerBuilder wire up GET /health, GET /gateway/metrics, POST /graphql (plus GraphiQL and a /graphql/ws subscription endpoint), a GET /ws WebSocket upgrade, and a load-balanced reverse-proxy fallback with real hyper-based streaming, HTTPS upstreams over Pure-Rust OxiTLS, and circuit-breaker-aware retries. The crate’s own test suite grew from 266 to 381 tests.

  3. Security and memory-safety hardening. Beyond the WFS-T fail-closed fix, header-driven allocation caps now bound NetCDF, HDF5, GRIB, and GeoTIFF parsing so a crafted header can’t trigger a multi-gigabyte allocation, and gateway load-balancer health checks issue genuine HTTP/1.1-over-TCP requests instead of always reporting backends healthy.

  4. Dependency and supply-chain hygiene. oxigeo-kafka (rdkafka-syscmake → librdkafka, 4,831 lines with zero in-workspace reverse dependents) is retired and its crates.io versions yanked; oxigeo-proj’s vestigial proj-sys C-bindings feature goes with it. A new deny.toml enforces the advisory/bans/license policy, cargo-machete removed genuinely-unused dependencies from 66 crates, and NOTICE / THIRD_PARTY.md ship for Apache-2.0 §4(d) attribution.

Getting Started

[dependencies]
oxigeo = "0.2"  # GeoTIFF + GeoJSON + Shapefile by default
use oxigeo::Dataset;

fn main() -> oxigeo::Result<()> {
    let dataset = Dataset::open("world.tif")?;
    println!("Format : {}", dataset.format());
    println!("Size   : {}x{}", dataset.width(), dataset.height());
    println!("CRS    : {}", dataset.crs().unwrap_or("unknown"));
    Ok(())
}

The new gateway serving layer is its own crate:

use oxigeo_gateway::{GatewayConfig, GatewayServer};
use oxigeo_gateway::loadbalancer::Backend;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let server = GatewayServer::builder(GatewayConfig::default())
        .with_backend(Backend::new("api".into(), "http://127.0.0.1:9000".into(), 1))
        .build()?;

    // Binds and serves until ctrl-c / SIGTERM (graceful shutdown).
    server.serve("0.0.0.0:8080").await?;
    Ok(())
}

What’s New in 0.2.1

Tips

This is the foundation

OxiGeo 0.2.1 leans on the same Pure Rust COOLJAPAN stack as every release before it: CRS transforms via OxiProj, HDF5/NetCDF read-write through oxih5 (now pinned to 0.2.2, with a scalar-attribute padding bug fixed upstream) and oxinetcdf, SQLite via oxisql-sqlite-compat (Limbo), TLS via OxiTLS, compression across the format drivers via the OxiArc family, ML tensor math via SciRS2-Core (bumped to 0.6.4 this cycle), and model export validated against OxiONNX. Every one of those is itself Pure Rust — which is how a 75-crate, ~784K-SLoC workspace ships a defect-hardening release without picking up a single new native dependency.

Repository: https://github.com/cool-japan/oxigeo

Star the repo if you’d rather your geospatial dependency tell you when a decode went wrong than hand you silently corrupted pixels. 342 findings, 314 fixes, and the last C dependency gone — that’s what a hardening release is supposed to look like.

The era of “it probably decoded right” is over. Pure Rust geospatial is here — fast, safe, and sovereign.

KitaSan at COOLJAPAN OÜ July 28, 2026

↑ Back to all posts