From ad96c3aaa2bf3188561b19eee7be62abd357332f Mon Sep 17 00:00:00 2001 From: Sascha Brawer Date: Thu, 10 Sep 2026 17:17:54 +0200 Subject: [PATCH] chore: rename crate and binary osm-diffs -> osmdiffs Completes the repo move: the crate, the binary artifact, and every name derived from them now match github.com/brawer/osmdiffs. - `Cargo.toml` package name -> `osmdiffs`; `Cargo.lock` regenerated; `osm_diffs::` -> `osmdiffs::` in `src/main.rs`. Log `target` fields are now `osmdiffs::...` (reflected in the Hetzner `pipeline.log` fixture and `docs/LOGGING.md`). - `Containerfile`: build WORKDIR `/usr/osmdiffs`, binary copied to `/app/osmdiffs`, `ENTRYPOINT ["/app/osmdiffs"]`. - Tests: `cargo_bin!("osmdiffs")`, `cargo test -p osmdiffs`. - Provenance BOM: tool component `name` and every `bom-ref` (`tool-osmdiffs`, `formula-osmdiffs-build`, ...) plus test assertions. - SBOM scripts: `osmdiffs_bin.cdx.json`, the `osmdiffs:sbom:devBuild` property, and comments. - Hetzner / macOS test tooling, per the "everything, consistently" choice: systemd unit names (`osmdiffs-run`, `osmdiffs-monitor`), the local podman image tag and VM label key (`osmdiffs-test`), `REMOTE_DIR` `/root/osmdiffs`, binary paths. - Docs and stray comments. Left unchanged: - The frozen UUIDv5 seed URLs in `provenance.rs` / `datapackage.rs` (still `alltheplaces/osm-diffs`, as before -- the constants must not be regenerated). - The local dev checkout path in the gitignored `.claude/settings.local.json`. `cargo test --locked`, `cargo clippy --locked`, `cargo fmt`, and the Hetzner pytest suite all pass. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01ADxF1ZE2j9Ki51fiJQQLVo --- .github/workflows/pr-title-lint.yml | 2 +- Cargo.lock | 22 +++--- Cargo.toml | 2 +- Containerfile | 12 ++-- deny.toml | 2 +- docs/CONTRIBUTING.md | 4 +- docs/LOGGING.md | 4 +- docs/PRODUCTION.md | 4 +- docs/README.md | 4 +- docs/RELEASING.md | 4 +- docs/SUPPLY_CHAIN_SECURITY.md | 14 ++-- docs/TECHNICAL_DESIGN.md | 2 +- scripts/README.md | 2 +- scripts/cut-release.sh | 2 +- scripts/sbom/README.md | 8 +-- scripts/sbom/generate-sbom.sh | 8 +-- scripts/sbom/merge.jq | 4 +- scripts/sbom/pipeline.jq | 10 +-- scripts/sbom/tippecanoe-binary.jq | 4 +- scripts/test-branch-on-macos/README.md | 14 ++-- scripts/test-branch-on-macos/monitor.sh | 8 +-- scripts/test-branch-on-macos/test_macos.py | 2 +- scripts/test-on-hetzner/README.md | 12 ++-- scripts/test-on-hetzner/cloud_test.py | 26 +++---- scripts/test-on-hetzner/remote/build.sh | 4 +- .../remote/extract-binaries.sh | 14 ++-- scripts/test-on-hetzner/remote/pull.sh | 4 +- .../test-on-hetzner/test_data/pipeline.log | 68 +++++++++---------- .../test-on-hetzner/tests/test_cloud_test.py | 18 ++--- .../test-on-hetzner/tests/test_validate.py | 4 +- src/main.rs | 2 +- src/pipeline/datapackage.rs | 2 +- src/pipeline/memstats.rs | 4 +- src/pipeline/provenance.rs | 44 ++++++------ src/pipeline/upload.rs | 2 +- tests/integration_test.rs | 14 ++-- 36 files changed, 179 insertions(+), 177 deletions(-) diff --git a/.github/workflows/pr-title-lint.yml b/.github/workflows/pr-title-lint.yml index 15a22fd9..bbbff15c 100644 --- a/.github/workflows/pr-title-lint.yml +++ b/.github/workflows/pr-title-lint.yml @@ -36,7 +36,7 @@ jobs: # adds a label, never removes one, so a title edit won't strip a label a # human applied for an unrelated reason (e.g. good first issue). # - # Note: "!" here means the PR breaks osm-diffs' OUTPUT SCHEMA + # Note: "!" here means the PR breaks osmdiffs' OUTPUT SCHEMA # (conflated.parquet), not that it breaks some public API -- see # docs/CONTRIBUTING.md and docs/RELEASING.md's "Choosing the version # number". It's a hint for scripts/cut-release.sh, not a substitute for the diff --git a/Cargo.lock b/Cargo.lock index a9c1e4af..c19c6187 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1959,7 +1959,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] -name = "osm-diffs" +name = "osm_pbf_iter" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1998ded392212fad69f25e7510fc34d095f585fc5e67282b99f2a4f993cbcfe6" +dependencies = [ + "libdeflater", + "protobuf_iter", +] + +[[package]] +name = "osmdiffs" version = "0.8.3" dependencies = [ "anyhow", @@ -2010,16 +2020,6 @@ dependencies = [ "wkt", ] -[[package]] -name = "osm_pbf_iter" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1998ded392212fad69f25e7510fc34d095f585fc5e67282b99f2a4f993cbcfe6" -dependencies = [ - "libdeflater", - "protobuf_iter", -] - [[package]] name = "parquet" version = "59.2.0" diff --git a/Cargo.toml b/Cargo.toml index 8b72a15c..456f17df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "osm-diffs" +name = "osmdiffs" version = "0.8.3" edition = "2024" license = "MIT" diff --git a/Containerfile b/Containerfile index 10ac5e6c..12844951 100644 --- a/Containerfile +++ b/Containerfile @@ -81,10 +81,10 @@ RUN for bin in tippecanoe tile-join; do \ # ---------------------------------------------------------------------------- -# Stage 1.3: Build and test osm-diffs binary +# Stage 1.3: Build and test osmdiffs binary # ---------------------------------------------------------------------------- -WORKDIR /usr/osm-diffs +WORKDIR /usr/osmdiffs COPY Cargo.toml Cargo.lock build.rs rust-toolchain.toml . COPY scripts/sbom scripts/sbom @@ -99,7 +99,7 @@ RUN cargo test --release --locked # Stage 1.4: Generate the SBOM for the container # ---------------------------------------------------------------------------- # -# Runs after both binaries (tippecanoe and osm-diffs) have been built, so a +# Runs after both binaries (tippecanoe and osmdiffs) have been built, so a # single script invocation can see the facts about both of them. RUN sh scripts/sbom/generate-sbom.sh /artifacts/sbom.cdx.json @@ -119,12 +119,12 @@ COPY --from=builder /usr/local/bin/tippecanoe /usr/local/bin/tippecanoe COPY --from=builder /usr/local/bin/tile-join /usr/local/bin/tile-join COPY --from=builder --chown=1000:1000 \ - /usr/osm-diffs/target/release/osm-diffs \ - /app/osm-diffs + /usr/osmdiffs/target/release/osmdiffs \ + /app/osmdiffs USER 1000 -ENTRYPOINT ["/app/osm-diffs"] +ENTRYPOINT ["/app/osmdiffs"] LABEL \ org.opencontainers.image.authors="Sascha Brawer " \ diff --git a/deny.toml b/deny.toml index 98a398f1..bece6f4b 100644 --- a/deny.toml +++ b/deny.toml @@ -21,7 +21,7 @@ ignore = [ # XML attribute/namespace handling. Both only matter for untrusted input; # `s3` uses quick-xml solely to parse XML *responses from the S3 endpoint # we're uploading to*, not attacker-controlled input, so this isn't - # exploitable in how osm-diffs uses it. Fix is upstream in `s3`, not + # exploitable in how osmdiffs uses it. Fix is upstream in `s3`, not # something we can patch here (no git/path deps -- see docs/CONTRIBUTING.md # on why): https://github.com/lvillis/s3-rs/pull/15 bumps it to >=0.41.0. # Re-run `cargo deny check advisories` after that merges and a new `s3` diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index b5d2293c..fc378e2b 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing -Thanks for taking a look at `osm-diffs`! 👋 Contributions, questions, +Thanks for taking a look at `osmdiffs`! 👋 Contributions, questions, and bug reports are all welcome — this project is still early, so there’s no such thing as too small a [Pull Request (PR)](https://docs.github.com/en/pull-requests/get-started/about-pull-requests). @@ -60,7 +60,7 @@ categorized release notes — so getting the type right saves the maintainer a manual labeling step, it’s not just a style nit. **The `!` marker is special here.** Normally it means “breaks the public -API.” `osm-diffs` doesn’t have one client code links against — what it +API.” `osmdiffs` doesn’t have one client code links against — what it has is an **output schema** (`conflated.parquet`), and that’s what matters to everyone downstream. So on this project, `!` means *this PR breaks the output schema*, per the rules in diff --git a/docs/LOGGING.md b/docs/LOGGING.md index a0bb3c6c..fd474080 100644 --- a/docs/LOGGING.md +++ b/docs/LOGGING.md @@ -1,6 +1,6 @@ # Logging -`osm-diffs run` writes `pipeline.log` to its `--workdir`, one JSON +`osmdiffs run` writes `pipeline.log` to its `--workdir`, one JSON object per line ([JSON Lines](https://jsonlines.org/)) — machine-readable rather than free-form text, so a log can be grepped, `jq`’d, or loaded into whatever analysis tool you like without first @@ -9,7 +9,7 @@ Every record has: - `timestamp` — RFC 3339, UTC. - `level` — `INFO`, `WARN`, `ERROR`, … -- `target` — which module logged it (e.g. `osm_diffs::pipeline::conflate`). +- `target` — which module logged it (e.g. `osmdiffs::pipeline::conflate`). - `message` — the human-readable text. - `fields` — present only on records that attach structured data (numbers, an id, …) instead of just interpolating it into the diff --git a/docs/PRODUCTION.md b/docs/PRODUCTION.md index 6aaccda4..bae2cdbb 100644 --- a/docs/PRODUCTION.md +++ b/docs/PRODUCTION.md @@ -1,6 +1,6 @@ -# Running `osm-diffs` in production +# Running `osmdiffs` in production -`osm-diffs` doesn’t run anywhere permanent yet — see +`osmdiffs` doesn’t run anywhere permanent yet — see [`TECHNICAL_DESIGN.md`](TECHNICAL_DESIGN.md)’s “Status” section. This document isn’t a description of an existing deployment; it’s the operational knowledge gathered from testing on Hetzner Cloud diff --git a/docs/README.md b/docs/README.md index 0298a52d..9c6e5889 100644 --- a/docs/README.md +++ b/docs/README.md @@ -17,9 +17,9 @@ Want to work on the pipeline itself, or run it somewhere? Start here. - [`TESTING.md`](TESTING.md) — how this project’s tests are organized, what CI enforces, and how to try a change on real hardware before it lands. -- [`LOGGING.md`](LOGGING.md) — the JSON log format `osm-diffs run` +- [`LOGGING.md`](LOGGING.md) — the JSON log format `osmdiffs run` writes, and where weekly-run logs end up archived in S3. -- [`RELEASING.md`](RELEASING.md) — how to cut a release of `osm-diffs`. +- [`RELEASING.md`](RELEASING.md) — how to cut a release of `osmdiffs`. - [`PRODUCTION.md`](PRODUCTION.md) — operational knowledge for running a released container somewhere real: hardware sizing, required configuration, serving the outputs over a CDN, what to monitor. diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 5fb382b2..273a89ff 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -1,7 +1,7 @@ # Cutting a release This document is the practical how-to for cutting a release of -`osm-diffs`. For the concepts behind *why* the process looks like this +`osmdiffs`. For the concepts behind *why* the process looks like this (SBOM, attestations, immutable releases, ...), see [`SUPPLY_CHAIN_SECURITY.md`](SUPPLY_CHAIN_SECURITY.md). @@ -27,7 +27,7 @@ the pipeline’s **output schema** — not by how much code changed. This is a different question than what [SemVer](https://semver.org/) usually answers. Programmers normally think of SemVer in terms of API compatibility for code that *links against* a library. Nobody links -against `osm-diffs`: +against `osmdiffs`: downstream clients only ever consume the *data* it produces. So the question to ask isn’t “did the code change in a breaking way,” it’s “does this change what a client reading our output has to handle differently”: diff --git a/docs/SUPPLY_CHAIN_SECURITY.md b/docs/SUPPLY_CHAIN_SECURITY.md index 73247f03..17d6e1b7 100644 --- a/docs/SUPPLY_CHAIN_SECURITY.md +++ b/docs/SUPPLY_CHAIN_SECURITY.md @@ -6,7 +6,7 @@ process itself. This document explains the security practices we use around ours (see [`RELEASING.md`](RELEASING.md) for the actual, repo-specific steps). It’s written for someone who can code but hasn’t necessarily done release engineering before. None of it is original to -`osm-diffs` — everything here is standard practice, just explained in +`osmdiffs` — everything here is standard practice, just explained in one place. ## Containers @@ -18,7 +18,7 @@ virtual machine, since it shares the host’s kernel instead of running its own, while still keeping what’s inside isolated from everything else on that host. -We publish `osm-diffs` as an [OCI image](https://opencontainers.org/) — +We publish `osmdiffs` as an [OCI image](https://opencontainers.org/) — the open, vendor-neutral standard most container tooling implements today — to a [container registry](https://www.redhat.com/en/topics/cloud-native-apps/what-is-a-container-registry) @@ -31,7 +31,7 @@ a plain-text file listing the build steps, one instruction per line. ## Minimal containers `Containerfile` builds in two stages, and only the second one ships: -`FROM scratch`, containing nothing but the `osm-diffs` and `tippecanoe` +`FROM scratch`, containing nothing but the `osmdiffs` and `tippecanoe` binaries. The whole build toolchain (Rust, a C compiler, `apk`, `git`, ...) stays behind in the discarded first stage. Both binaries are statically linked against [musl](https://en.wikipedia.org/wiki/Musl), @@ -64,7 +64,7 @@ for your machine. Because we ship `FROM scratch` (see “Minimal containers” above), there’s no `/etc/ssl` in the final image either — no OS-provided CA trust store to fall back on for verifying a TLS server’s certificate. -Rather than adding one, `osm-diffs` embeds Mozilla’s own CA root +Rather than adding one, `osmdiffs` embeds Mozilla’s own CA root bundle directly into the binary at compile time, via the [`webpki-roots`](https://github.com/rustls/webpki-roots) crate (see `main.rs`’s `build_client()`) — the same trust store @@ -91,7 +91,7 @@ library X?” without rebuilding the software or reading its source. ## SBOM and CBOM Our SBOM describes the container image we publish: the Rust dependency -graph of the `osm-diffs` binary, the statically linked `tippecanoe` +graph of the `osmdiffs` binary, the statically linked `tippecanoe` binary and its libraries, build-environment details, and licenses. Alongside it, our SBOM includes a small @@ -175,7 +175,7 @@ image* was built by our workflow from our source (provenance), and ## Is this overkill for a project like this? -Fair question. `osm-diffs` is open source, processes only public data, +Fair question. `osmdiffs` is open source, processes only public data, and handles no secrets — our actual threat model is modest compared to a service handling user data or credentials. So no, this isn’t strictly *necessary* the way it would be for many other projects. @@ -205,7 +205,7 @@ requirement, for example under the US and the EU [Cyber Resilience Act](https://en.wikipedia.org/wiki/Cyber_Resilience_Act). -None of that raises `osm-diffs`’s own threat model much — and +None of that raises `osmdiffs`’s own threat model much — and honestly, everything in this document is overkill for what a project like this actually needs. We set it up anyway to make a different point: this level of rigor doesn’t require a large company’s diff --git a/docs/TECHNICAL_DESIGN.md b/docs/TECHNICAL_DESIGN.md index d58399d9..f7a556ea 100644 --- a/docs/TECHNICAL_DESIGN.md +++ b/docs/TECHNICAL_DESIGN.md @@ -1,4 +1,4 @@ -# Technical design: `osm-diffs` +# Technical design: `osmdiffs` Status: Work in Progress — see [“Status”](#status) at the end of this document for what’s still ahead. diff --git a/scripts/README.md b/scripts/README.md index 14c10144..3347b2d6 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -39,7 +39,7 @@ process these fit into. ## Testing development branches -Unrelated to how `osm-diffs` actually ships to production — this is for +Unrelated to how `osmdiffs` actually ships to production — this is for ad hoc validation of a branch before it lands. - [`test-on-hetzner/`](test-on-hetzner/README.md): spins diff --git a/scripts/cut-release.sh b/scripts/cut-release.sh index 56b4ce0f..456bd09b 100755 --- a/scripts/cut-release.sh +++ b/scripts/cut-release.sh @@ -99,7 +99,7 @@ fi # ── scan for Conventional-Commits breaking markers since the last release ─── # This is a hint, not a rule: choosing the version is still your call (see # "Choosing the version number" in docs/RELEASING.md). Reminder, since it's -# easy to reach for the usual meaning by reflex: on osm-diffs, "!" flags a +# easy to reach for the usual meaning by reflex: on osmdiffs, "!" flags a # commit that breaks the OUTPUT SCHEMA (conflated.parquet), not one that # breaks some public API -- see docs/CONTRIBUTING.md. LAST_TAG="$(git describe --tags --abbrev=0 2>/dev/null || true)" diff --git a/scripts/sbom/README.md b/scripts/sbom/README.md index c6d7896b..48673538 100644 --- a/scripts/sbom/README.md +++ b/scripts/sbom/README.md @@ -2,7 +2,7 @@ This directory holds the scripts that generate the Software Bill of Materials (SBOM) — including a small Cryptographic Bill of Materials, -CBOM — for the `osm-diffs` container image. See +CBOM — for the `osmdiffs` container image. See [`../../docs/SUPPLY_CHAIN_SECURITY.md`](../../docs/SUPPLY_CHAIN_SECURITY.md) for what an SBOM/CBOM actually is and why we publish one; this document only covers how it’s implemented here. @@ -36,13 +36,13 @@ Linux version, compiler versions, library versions, ...) using standard tools such as `apk`, `sed`, `awk` and `grep`. It then: 1. Runs `cargo cyclonedx` to get the Rust dependency graph for the - `osm-diffs` binary, in CycloneDX 1.5 format (the newest that + `osmdiffs` binary, in CycloneDX 1.5 format (the newest that `cargo cyclonedx` currently supports). 2. Pipes that through [`pipeline.jq`](pipeline.jq), which upgrades it to CycloneDX 1.7 and enriches it with build-environment metadata, supplier/license info, the CBOM facts (a `cryptographic-asset` component for TLS 1.3, plus `crypto:tls:*`/`crypto:catrust:*` - custom properties on the `osm-diffs` component — see that file’s own + custom properties on the `osmdiffs` component — see that file’s own comments for why a curated CA root bundle isn’t a good fit for CycloneDX’s `certificate` cryptographic-asset type), and the vendored “data” components (`id-tagging-schema`, @@ -83,7 +83,7 @@ Some of the facts it normally reads via Alpine’s `apk` (the exact musl, sqlite and zlib versions statically linked into `tippecanoe`, the Alpine version itself) aren’t available outside of that build environment. In that case, the script inserts placeholder values, prints a warning, and -marks the SBOM as `osm-diffs:sbom:devBuild` in its metadata properties. +marks the SBOM as `osmdiffs:sbom:devBuild` in its metadata properties. Such an SBOM is useful for checking structural or semantic validity (e.g. with `cyclonedx-cli validate`), but must not be treated as an accurate description of a production build. diff --git a/scripts/sbom/generate-sbom.sh b/scripts/sbom/generate-sbom.sh index f4d8bb41..f1943f0e 100755 --- a/scripts/sbom/generate-sbom.sh +++ b/scripts/sbom/generate-sbom.sh @@ -4,7 +4,7 @@ # SPDX-License-Identifier: MIT # # Generate the CycloneDX Software Bill of Materials (SBOM) for the -# osm-diffs container image: one single file, describing the osm-diffs +# osmdiffs container image: one single file, describing the osmdiffs # binary (with its Rust dependency graph) and the two statically # linked tippecanoe-project binaries that ship alongside it, tippecanoe # and tile-join. @@ -24,7 +24,7 @@ # printed. Such a placeholder-filled SBOM is fine for checking structural # or semantic validity, but MUST NOT be treated as an accurate SBOM for a # production build; the output is marked as such in its own metadata -# (metadata.properties: "osm-diffs:sbom:devBuild"). +# (metadata.properties: "osmdiffs:sbom:devBuild"). # # Note on the image digest: this script does not, and cannot, know the # digest of the container image it is building -- that digest only @@ -126,11 +126,11 @@ else exit 1 fi -# ── build the osm-diffs (pipeline) SBOM fragment ───────────────────────────── +# ── build the osmdiffs (pipeline) SBOM fragment ───────────────────────────── # cargo cyclonedx always writes next to Cargo.toml, named after the binary # target; move it into our workdir once it's done so it can't be mistaken # for a second, independently meaningful SBOM file. -RAW_PIPELINE="${PROJECT_ROOT}/osm-diffs_bin.cdx.json" +RAW_PIPELINE="${PROJECT_ROOT}/osmdiffs_bin.cdx.json" rm -f "$RAW_PIPELINE" # clean up any leftover file from a previous failed run cargo cyclonedx \ diff --git a/scripts/sbom/merge.jq b/scripts/sbom/merge.jq index a075cd71..99b2d678 100644 --- a/scripts/sbom/merge.jq +++ b/scripts/sbom/merge.jq @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT # # Assemble the final, single SBOM for the container image out of the -# osm-diffs (pipeline), tippecanoe, and tile-join component fragments. +# osmdiffs (pipeline), tippecanoe, and tile-join component fragments. # # Invoked as `jq -n -f merge.jq` (no stdin input; all three fragments # are read via --slurpfile). @@ -20,7 +20,7 @@ # serial SBOM serial number (a "urn:uuid:..." string) # image container image name, e.g. "brawer/osmdiffs" # timestamp build timestamp, RFC 3339 -# pipeline (--slurpfile) the enriched osm-diffs SBOM fragment, as +# pipeline (--slurpfile) the enriched osmdiffs SBOM fragment, as # produced by pipeline.jq # tippecanoe (--slurpfile) the tippecanoe SBOM fragment, as produced # by tippecanoe.jq diff --git a/scripts/sbom/pipeline.jq b/scripts/sbom/pipeline.jq index 01bcbf52..8b7f76ec 100644 --- a/scripts/sbom/pipeline.jq +++ b/scripts/sbom/pipeline.jq @@ -2,13 +2,13 @@ # SPDX-License-Identifier: MIT # # Enrich the raw CycloneDX SBOM produced by `cargo cyclonedx` for the -# osm-diffs binary: fix up the dependency graph, attach build-environment +# osmdiffs binary: fix up the dependency graph, attach build-environment # and supplier metadata, and add the vendored "data" components (and the # Cryptographic Bill of Materials entries) that cargo-cyclonedx cannot see # on its own. # # Input (stdin): the raw CycloneDX 1.5 document from `cargo cyclonedx`. -# Output: a CycloneDX 1.7 document, still describing only the osm-diffs +# Output: a CycloneDX 1.7 document, still describing only the osmdiffs # application (not the final container -- that's assembled by merge.jq). # # Arguments (all required, passed with --arg): @@ -42,8 +42,8 @@ def add_supplier: . end; -# Patch bom-ref of main application to read "osm-diffs-1.2.3" -# instead of "path+file:///Users/sascha/src/osm-diffs#osm-diffs". +# Patch bom-ref of main application to read "osmdiffs-1.2.3" +# instead of "path+file:///Users/sascha/src/osm-diffs#osmdiffs". .metadata.component."bom-ref" as $orig_root_ref | ( .metadata.component.name + "-" + .metadata.component.version ) as $root_ref | .metadata.component."bom-ref" = $root_ref | @@ -273,7 +273,7 @@ else . end | if $DEV_BUILD == "true" then .metadata.properties = ((.metadata.properties // []) + [{ - name: "osm-diffs:sbom:devBuild", + name: "osmdiffs:sbom:devBuild", value: "true" }]) else diff --git a/scripts/sbom/tippecanoe-binary.jq b/scripts/sbom/tippecanoe-binary.jq index 2db99ebc..a97a11a1 100644 --- a/scripts/sbom/tippecanoe-binary.jq +++ b/scripts/sbom/tippecanoe-binary.jq @@ -3,7 +3,7 @@ # # Build a CycloneDX 1.7 SBOM fragment for one statically compiled # binary from the felt/tippecanoe build that we ship alongside -# osm-diffs in the OCI container image -- tippecanoe itself, or its +# osmdiffs in the OCI container image -- tippecanoe itself, or its # sibling tile-join (used by pipeline::tiles::join_tiles to merge # conflated.pmtiles' overview and detail passes; see # pipeline::conflated_tiles' module doc comment for why that split @@ -79,7 +79,7 @@ def alpine_supplier: {name: "Alpine Linux", url: ["https://alpinelinux.org"]}; }] }, properties: (if $DEV_BUILD == "true" then - [{name: "osm-diffs:sbom:devBuild", value: "true"}] + [{name: "osmdiffs:sbom:devBuild", value: "true"}] else [] end) diff --git a/scripts/test-branch-on-macos/README.md b/scripts/test-branch-on-macos/README.md index 9836d970..f304b825 100644 --- a/scripts/test-branch-on-macos/README.md +++ b/scripts/test-branch-on-macos/README.md @@ -17,18 +17,18 @@ hardware actually matters. ## Usage ```console -$ ./test_macos.py run --workdir /tmp/osm-diffs-workdir +$ ./test_macos.py run --workdir /tmp/osmdiffs-workdir + cargo build --release ... -Starting monitor -> /tmp/osm-diffs-workdir/macos_monitor.log -+ .../target/release/osm-diffs run --workdir /tmp/osm-diffs-workdir +Starting monitor -> /tmp/osmdiffs-workdir/macos_monitor.log ++ .../target/release/osmdiffs run --workdir /tmp/osmdiffs-workdir ... -pipeline.log: /tmp/osm-diffs-workdir/pipeline.log -monitor log: /tmp/osm-diffs-workdir/macos_monitor.log +pipeline.log: /tmp/osmdiffs-workdir/pipeline.log +monitor log: /tmp/osmdiffs-workdir/macos_monitor.log ``` -- `--skip-build` reuses the existing `target/release/osm-diffs` as-is, +- `--skip-build` reuses the existing `target/release/osmdiffs` as-is, for re-running against the same binary without waiting on a rebuild. - `--clean` clears the workdir first but keeps `planet-latest.osm.pbf`/ its metadata sidecar, so re-running doesn't re-download the ~94GB @@ -43,7 +43,7 @@ separate stop step to remember. ## Why the monitor re-resolves the PID every iteration An earlier, ad hoc version of this script (used during the PR 665 -experiment) resolved `osm-diffs`'s PID once at the top and never again. +experiment) resolved `osmdiffs`'s PID once at the top and never again. When the process wasn't running yet at that exact moment -- or restarted during the run -- every subsequent `ps -p` call just failed with "Invalid process id" for the rest of the run, silently producing a diff --git a/scripts/test-branch-on-macos/monitor.sh b/scripts/test-branch-on-macos/monitor.sh index 643cb94d..d50b73fb 100755 --- a/scripts/test-branch-on-macos/monitor.sh +++ b/scripts/test-branch-on-macos/monitor.sh @@ -1,11 +1,11 @@ #!/usr/bin/env bash -# Monitors vm_stat and osm-diffs's own RSS, appending a log entry every +# Monitors vm_stat and osmdiffs's own RSS, appending a log entry every # 5 seconds, UTC-timestamped to match pipeline.log. Started/stopped by # test_macos.py, not meant to be run standalone (though nothing stops # you from doing that too). # # Resolves the PID fresh every iteration, not once at the top: a -# one-shot PID goes stale as soon as osm-diffs isn't running yet when +# one-shot PID goes stale as soon as osmdiffs isn't running yet when # this starts (or has restarted since) -- every subsequent `ps -p` call # would then just fail with "Invalid process id" for the rest of the # run, exactly what happened to an earlier ad hoc version of this @@ -14,11 +14,11 @@ set -uo pipefail while true; do printf '=== %s UTC ===\n' "$(date -u +"%Y-%m-%d %H:%M:%S")" - pid=$(pgrep -f 'osm-diffs run' | head -1) + pid=$(pgrep -f 'osmdiffs run' | head -1) if [ -n "$pid" ]; then ps -o pid,%cpu,%mem,rss,vsz -p "$pid" else - echo "osm-diffs run: not currently running" + echo "osmdiffs run: not currently running" fi vm_stat sleep 5 diff --git a/scripts/test-branch-on-macos/test_macos.py b/scripts/test-branch-on-macos/test_macos.py index 5c9369e4..dcef7380 100755 --- a/scripts/test-branch-on-macos/test_macos.py +++ b/scripts/test-branch-on-macos/test_macos.py @@ -26,7 +26,7 @@ SCRIPT_DIR = Path(__file__).resolve().parent REPO_ROOT = SCRIPT_DIR.parent.parent -BINARY = REPO_ROOT / "target" / "release" / "osm-diffs" +BINARY = REPO_ROOT / "target" / "release" / "osmdiffs" PLANET_FILES = ("planet-latest.osm.pbf", "planet-latest.osm.pbf.meta.json") diff --git a/scripts/test-on-hetzner/README.md b/scripts/test-on-hetzner/README.md index 1a47d49c..3fd6edc8 100644 --- a/scripts/test-on-hetzner/README.md +++ b/scripts/test-on-hetzner/README.md @@ -1,6 +1,6 @@ # Testing on cloud machines -Two small tools: `cloud_test.py` runs the full `osm-diffs` pipeline on +Two small tools: `cloud_test.py` runs the full `osmdiffs` pipeline on real Hetzner Cloud hardware, without repeating the manual VM setup by hand each time -- create a VM, either build a development branch's `Containerfile` natively on it or pull an already-built image (e.g. a @@ -28,7 +28,7 @@ the results carefully -- it just removes the repetitive, error-prone parts of getting there. **Not a general-purpose deployment tool.** This has nothing to do with -how `osm-diffs` actually gets deployed to production (see +how `osmdiffs` actually gets deployed to production (see `../../docs/RELEASING.md` for that) -- it only exists to make ad hoc experiments on cloud hardware repeatable. @@ -112,7 +112,7 @@ restart a run with a clean workdir without tearing down the VM | `up` | Create the server + volume, deploy, start the pipeline. | | `create` | Server + a formatted, attached, automounted data volume. Also collects `sysinfo` and runs `fio` once, automatically. Prints the exact `destroy` command needed to remove what it just created. | | `deploy` | `--branch NAME`: clone/update the given branch on an existing server and build it via the project's `Containerfile`, natively (see below for why that matters). `--image REF`: pull an already-built image instead (e.g. `ghcr.io/brawer/osmdiffs:v1.2.3`) -- either way, binaries get extracted the same way, so bare-mode `start` works unchanged regardless of which path was used. | -| `start` | Launch `osm-diffs run` and the vmstat/disk monitor, both detached via `systemd-run`. `--clean` clears the workdir first but keeps `planet-latest.osm.pbf`/its metadata sidecar, so re-running doesn't re-download the ~94GB planet file. `--containerized --mem-limit SIZE --cpu-limit N` runs `podman run` against the image `deploy` produced instead of the bare extracted binary, for real cgroup accounting -- see below. | +| `start` | Launch `osmdiffs run` and the vmstat/disk monitor, both detached via `systemd-run`. `--clean` clears the workdir first but keeps `planet-latest.osm.pbf`/its metadata sidecar, so re-running doesn't re-download the ~94GB planet file. `--containerized --mem-limit SIZE --cpu-limit N` runs `podman run` against the image `deploy` produced instead of the bare extracted binary, for real cgroup accounting -- see below. | | `status` | `systemctl status` for the run, plus `df` and the last few `pipeline.log` lines. | | `fio` | Random-read benchmark of the attached volume (the same command used by hand throughout the PR 665 experiment -- see `#667`). Re-runnable anytime, e.g. to check whether a result was a one-off blip. | | `sysinfo` | OS/kernel version, CPU model, memory, swap, disk layout, cgroup limits -- environment facts that turned out to matter for interpreting results but aren't anything this tool controls. | @@ -172,7 +172,7 @@ $ ./cloud_test.py up --name reg1 --ssh-key my-key \ `INTERNAL_S3_*`) at this one bucket. Omit it and the container just doesn't upload anywhere, same as the pipeline's own `*_S3_ENDPOINT`-unset behavior. -- `--run-id ID` is passed straight through as `osm-diffs run --run_id +- `--run-id ID` is passed straight through as `osmdiffs run --run_id ID`, embedded into the output's provenance BOM. Recommended: keep all of this pointed at a Hetzner project (and S3 @@ -184,7 +184,7 @@ something always goes wrong during testing. ```console $ ./cloud_test.py validate \ - --bucket-name osm-diffs-container-test-1 --bucket-region fsn1 \ + --bucket-name osmdiffs-container-test-1 --bucket-region fsn1 \ --pipeline-log logs/reg1/pipeline.log \ --mem-limit 4g --expect-pipeline-version 0.8.0 --min-atp-features 100000 ``` @@ -307,7 +307,7 @@ to attach/detach. There's no separate state file tracking which instances exist -- `list`/`destroy` query Hetzner directly (servers/volumes tagged with the -`osm-diffs-test` label), and `workdir_for()` re-derives the mounted +`osmdiffs-test` label), and `workdir_for()` re-derives the mounted volume's path from `hcloud volume describe` each time rather than caching it. Nothing here can drift out of sync with what Hetzner actually has, at the cost of an extra API round-trip per command -- diff --git a/scripts/test-on-hetzner/cloud_test.py b/scripts/test-on-hetzner/cloud_test.py index d8607e9e..3a4ca6c9 100755 --- a/scripts/test-on-hetzner/cloud_test.py +++ b/scripts/test-on-hetzner/cloud_test.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Spins up a Hetzner Cloud VM and runs the full osm-diffs pipeline on it +"""Spins up a Hetzner Cloud VM and runs the full osmdiffs pipeline on it -- either built from a given git branch or pulled as an already-built image (e.g. a released `ghcr.io` container) -- so testing on real cloud hardware doesn't mean re-deriving the VM setup dance by hand each time. @@ -36,8 +36,8 @@ DEFAULT_TYPE = "cpx32" DEFAULT_VOLUME_SIZE = 400 DEFAULT_REPO = "https://github.com/brawer/osmdiffs.git" -LABEL_KEY = "osm-diffs-test" -REMOTE_DIR = "/root/osm-diffs" +LABEL_KEY = "osmdiffs-test" +REMOTE_DIR = "/root/osmdiffs" SCRIPT_DIR = Path(__file__).resolve().parent LOGS_DIR = SCRIPT_DIR / "logs" PRICING_URL = "https://api.hetzner.cloud/v1/pricing" @@ -294,7 +294,7 @@ def cmd_deploy(args): ip = server_ip(args.name) ssh_cmd(ip, f"mkdir -p {REMOTE_DIR}") # Both the build and pull paths end by extracting binaries out of the - # locally tagged osm-diffs-test image, via the shared script. + # locally tagged osmdiffs-test image, via the shared script. scp_to(ip, SCRIPT_DIR / "remote" / "extract-binaries.sh", f"{REMOTE_DIR}/extract-binaries.sh") ssh_cmd(ip, f"chmod +x {REMOTE_DIR}/extract-binaries.sh") @@ -306,7 +306,7 @@ def cmd_deploy(args): else: scp_to(ip, SCRIPT_DIR / "remote" / "build.sh", f"{REMOTE_DIR}/build.sh") ssh_cmd(ip, f"chmod +x {REMOTE_DIR}/build.sh") - remote_checkout = f"{REMOTE_DIR}/osm-diffs-src" + remote_checkout = f"{REMOTE_DIR}/osmdiffs-src" ssh_cmd( ip, f"{REMOTE_DIR}/build.sh {shlex.quote(args.repo)} " @@ -345,7 +345,7 @@ def cmd_start(args): # free, without needing a terminal multiplexer at all. ssh_cmd( ip, - "systemd-run --unit=osm-diffs-monitor --collect " + "systemd-run --unit=osmdiffs-monitor --collect " f"--working-directory={REMOTE_DIR} --setenv=WORKDIR={workdir} -- " f"/bin/bash {REMOTE_DIR}/monitor.sh", ) @@ -353,11 +353,11 @@ def cmd_start(args): if containerized: run_command = containerized_run_command(args, ip, workdir) else: - run_command = f"/usr/local/bin/osm-diffs run --workdir {shlex.quote(workdir)}" + run_command = f"/usr/local/bin/osmdiffs run --workdir {shlex.quote(workdir)}" ssh_cmd( ip, - "systemd-run --unit=osm-diffs-run --collect " + "systemd-run --unit=osmdiffs-run --collect " # Debian's systemd defaults new units to the same 1024 # soft-limit open-file cap an interactive shell gets -- # switching to systemd-run does NOT fix the EMFILE crash a @@ -440,14 +440,14 @@ def containerized_run_command(args, ip, workdir): "podman run --rm --read-only " f"--memory={shlex.quote(args.mem_limit)} --cpus={shlex.quote(args.cpu_limit)} " f"-v {shlex.quote(workdir)}:/workdir {env_flag}" - f"osm-diffs-test run --workdir /workdir{run_id_flag}" + f"osmdiffs-test run --workdir /workdir{run_id_flag}" ) def cmd_status(args): ip = server_ip(args.name) workdir = workdir_for(args.name) - ssh_cmd(ip, "systemctl status osm-diffs-run --no-pager -l || true") + ssh_cmd(ip, "systemctl status osmdiffs-run --no-pager -l || true") ssh_cmd(ip, f"df -h {shlex.quote(workdir)}") ssh_cmd(ip, f"tail -5 {shlex.quote(workdir)}/pipeline.log 2>/dev/null || true") @@ -476,7 +476,7 @@ def cmd_logs(args): def cmd_stop(args): ip = server_ip(args.name) - ssh_cmd(ip, "systemctl stop osm-diffs-run osm-diffs-monitor || true") + ssh_cmd(ip, "systemctl stop osmdiffs-run osmdiffs-monitor || true") def fetch_pricing(): @@ -654,7 +654,7 @@ def cmd_validate(args): def cmd_list(args): servers = hcloud_json(["server", "list", "-l", f"{LABEL_KEY}=true"]) if not servers: - print("No osm-diffs-test instances running.") + print("No osmdiffs-test instances running.") for s in servers: labels = s.get("labels", {}) branch = labels.get(f"{LABEL_KEY}-branch", "?").replace("--", "/") @@ -843,7 +843,7 @@ def add_containerized(p): ) p_validate.set_defaults(func=cmd_validate) - p_list = sub.add_parser("list", help="list all osm-diffs-test instances") + p_list = sub.add_parser("list", help="list all osmdiffs-test instances") p_list.add_argument( "--bucket-region", help="also list S3 test buckets in this Hetzner Object Storage region" ) diff --git a/scripts/test-on-hetzner/remote/build.sh b/scripts/test-on-hetzner/remote/build.sh index ad977eeb..2863f929 100755 --- a/scripts/test-on-hetzner/remote/build.sh +++ b/scripts/test-on-hetzner/remote/build.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Pushed to the remote VM and run there by `cloud_test.py deploy`. Clones -# (or updates) the given branch and builds osm-diffs + tippecanoe via the +# (or updates) the given branch and builds osmdiffs + tippecanoe via the # project's own Containerfile -- natively, no QEMU emulation. Building # this same Containerfile locally on an Apple Silicon dev machine forces # --platform linux/amd64, which is slow enough (~2 hours, including one @@ -25,7 +25,7 @@ else fi cd "$dir" -podman build -t osm-diffs-test \ +podman build -t osmdiffs-test \ --build-arg BUILD_TIMESTAMP="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ -f Containerfile . diff --git a/scripts/test-on-hetzner/remote/extract-binaries.sh b/scripts/test-on-hetzner/remote/extract-binaries.sh index 50871d3b..ee426086 100755 --- a/scripts/test-on-hetzner/remote/extract-binaries.sh +++ b/scripts/test-on-hetzner/remote/extract-binaries.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Extracts /app/osm-diffs, /usr/local/bin/tippecanoe, and -# /usr/local/bin/tile-join out of the locally tagged osm-diffs-test +# Extracts /app/osmdiffs, /usr/local/bin/tippecanoe, and +# /usr/local/bin/tile-join out of the locally tagged osmdiffs-test # image into /usr/local/bin -- shared by build.sh (after building from # source) and pull.sh (after pulling an already-built image), so # bare-mode `start` works the same either way. @@ -9,16 +9,16 @@ set -euo pipefail # Remove any leftover "extract" container from a previous deploy first -- # podman create fails with "name already in use" otherwise. podman rm -f extract >/dev/null 2>&1 || true -podman create --name extract osm-diffs-test -# All three go to /usr/local/bin, not somewhere repo-relative: osm-diffs +podman create --name extract osmdiffs-test +# All three go to /usr/local/bin, not somewhere repo-relative: osmdiffs # invokes tippecanoe and tile-join via `Command::new(...)`, a bare PATH # lookup with no hardcoded location (src/pipeline/tiles.rs), so both # specifically must resolve on PATH for any branch that reaches # render_tiles/join_tiles. -podman cp extract:/app/osm-diffs /usr/local/bin/osm-diffs +podman cp extract:/app/osmdiffs /usr/local/bin/osmdiffs podman cp extract:/usr/local/bin/tippecanoe /usr/local/bin/tippecanoe podman cp extract:/usr/local/bin/tile-join /usr/local/bin/tile-join podman rm -f extract >/dev/null -chmod +x /usr/local/bin/osm-diffs /usr/local/bin/tippecanoe /usr/local/bin/tile-join -/usr/local/bin/osm-diffs --version +chmod +x /usr/local/bin/osmdiffs /usr/local/bin/tippecanoe /usr/local/bin/tile-join +/usr/local/bin/osmdiffs --version diff --git a/scripts/test-on-hetzner/remote/pull.sh b/scripts/test-on-hetzner/remote/pull.sh index c534804c..8680d071 100755 --- a/scripts/test-on-hetzner/remote/pull.sh +++ b/scripts/test-on-hetzner/remote/pull.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # Pushed to the remote VM and run there by `cloud_test.py deploy --image`. -# Pulls an already-built image -- e.g. a released osm-diffs container +# Pulls an already-built image -- e.g. a released osmdiffs container # from ghcr.io -- instead of building one from source, then extracts # binaries the same way build.sh does after a local build, via the # shared extract-binaries.sh, so bare-mode `start` works unchanged @@ -17,6 +17,6 @@ podman pull "$image" # extract-binaries.sh (and containerized `start`) both expect this fixed # local name, regardless of what registry/tag the image actually came # from -- same convention build.sh already uses for a locally built image. -podman tag "$image" osm-diffs-test +podman tag "$image" osmdiffs-test "$(dirname "$0")/extract-binaries.sh" diff --git a/scripts/test-on-hetzner/test_data/pipeline.log b/scripts/test-on-hetzner/test_data/pipeline.log index 85e88ab6..87972a8f 100644 --- a/scripts/test-on-hetzner/test_data/pipeline.log +++ b/scripts/test-on-hetzner/test_data/pipeline.log @@ -1,34 +1,34 @@ -{"level":"INFO","message":"pipeline starting up, version=v0.6.10","target":"osm_diffs::logging","timestamp":"2026-08-14T00:20:13.415103813Z"} -{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osm_diffs::atp","timestamp":"2026-08-14T00:20:13.525825392Z"} -{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osm_diffs::atp","timestamp":"2026-08-14T00:20:13.525876328Z"} -{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osm_diffs::atp","timestamp":"2026-08-14T00:20:13.525885683Z"} -{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osm_diffs::atp","timestamp":"2026-08-14T00:20:13.525893946Z"} -{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osm_diffs::atp","timestamp":"2026-08-14T00:20:13.525901647Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":3198976,"rss_bytes":9265152,"rss_file_bytes":6066176,"rss_peak_bytes":9265152,"rss_shmem_bytes":0,"step":"import_atp"},"level":"INFO","message":"import_atp: start","target":"osm_diffs::pipeline","timestamp":"2026-08-14T00:20:13.416185221Z"} -{"fields":{"end_time":"2026-08-11T21:11:13Z","run_id":"2026-08-08-13-32-19","size_bytes":2627885079,"spiders":4867,"total_lines":40242906},"level":"INFO","message":"fetched AllThePlaces dump","target":"osm_diffs::atp","timestamp":"2026-08-14T00:21:29.822279200Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":245.580147419,"phase":"end","rss_anon_bytes":11976704,"rss_bytes":26083328,"rss_file_bytes":14106624,"rss_peak_bytes":811192320,"rss_shmem_bytes":0,"step":"import_atp"},"level":"INFO","message":"import_atp: end","target":"osm_diffs::pipeline","timestamp":"2026-08-14T00:24:18.996240040Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":11976704,"rss_bytes":26083328,"rss_file_bytes":14106624,"rss_peak_bytes":811192320,"rss_shmem_bytes":0,"step":"build_coverage"},"level":"INFO","message":"build_coverage: start","target":"osm_diffs::pipeline","timestamp":"2026-08-14T00:24:18.996331247Z"} -{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osm_diffs::geometry","timestamp":"2026-08-14T00:24:19.417806433Z"} -{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osm_diffs::geometry","timestamp":"2026-08-14T00:24:19.594082487Z"} -{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osm_diffs::geometry","timestamp":"2026-08-14T00:24:19.621817789Z"} -{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osm_diffs::geometry","timestamp":"2026-08-14T00:24:19.669221549Z"} -{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osm_diffs::geometry","timestamp":"2026-08-14T00:24:19.878242477Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":494.985524166,"phase":"end","rss_anon_bytes":12582912,"rss_bytes":27262976,"rss_file_bytes":14680064,"rss_peak_bytes":847249408,"rss_shmem_bytes":0,"step":"build_coverage"},"level":"INFO","message":"build_coverage: end","target":"osm_diffs::pipeline","timestamp":"2026-08-14T00:32:33.981890235Z"} -{"fields":{"step":"build_coverage"},"level":"ERROR","message":"build_coverage failed: I/O operation failed: No file descriptors available (os error 24): No file descriptors available (os error 24)","target":"osm_diffs::pipeline","timestamp":"2026-08-14T00:32:33.981922003Z"} -{"level":"INFO","message":"pipeline starting up, version=v0.6.10","target":"osm_diffs::logging","timestamp":"2026-08-14T02:10:01.927000739Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":3198976,"rss_bytes":9265152,"rss_file_bytes":6066176,"rss_peak_bytes":9265152,"rss_shmem_bytes":0,"step":"import_atp"},"level":"INFO","message":"import_atp: start","target":"osm_diffs::pipeline","timestamp":"2026-08-14T02:10:01.927600739Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":0.00028535,"phase":"end","rss_anon_bytes":3198976,"rss_bytes":9265152,"rss_file_bytes":6066176,"rss_peak_bytes":9265152,"rss_shmem_bytes":0,"step":"import_atp"},"level":"INFO","message":"import_atp: end","target":"osm_diffs::pipeline","timestamp":"2026-08-14T02:10:01.928240884Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":3198976,"rss_bytes":9265152,"rss_file_bytes":6066176,"rss_peak_bytes":9265152,"rss_shmem_bytes":0,"step":"build_coverage"},"level":"INFO","message":"build_coverage: start","target":"osm_diffs::pipeline","timestamp":"2026-08-14T02:10:01.928343328Z"} -{"level":"INFO","message":"build_spatial_coverage finished, built \"/mnt/HC_Volume_106613191/workdir/coverage\"","target":"osm_diffs::coverage::writer","timestamp":"2026-08-14T03:16:24.947748077Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":3983.020624965,"phase":"end","rss_anon_bytes":13000000,"rss_bytes":27500000,"rss_file_bytes":15000000,"rss_peak_bytes":900000000,"rss_shmem_bytes":0,"step":"build_coverage"},"level":"INFO","message":"build_coverage: end","target":"osm_diffs::pipeline","timestamp":"2026-08-14T03:16:24.949063896Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":13000000,"rss_bytes":27500000,"rss_file_bytes":15000000,"rss_peak_bytes":900000000,"rss_shmem_bytes":0,"step":"import_osm"},"level":"INFO","message":"import_osm: start","target":"osm_diffs::pipeline","timestamp":"2026-08-14T03:16:24.949206101Z"} -{"fields":{"replication_timestamp":"2026-08-10T00:00:00Z","sha256":"1c3b456bbf66e853d83316593c9c73763753326115ac831fe006906b50f119db","source":"http://www.openstreetmap.org/api/0.6","writing_program":"planet-dump-ng 1.2.4"},"level":"INFO","message":"opened OpenStreetMap planet file","target":"osm_diffs::pipeline::osm","timestamp":"2026-08-14T03:48:09.411557950Z"} -{"level":"WARN","message":"could not build geometry for way/116707169","target":"osm_diffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:26:22.761218419Z"} -{"level":"WARN","message":"could not build geometry for way/116707190","target":"osm_diffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:26:22.768503504Z"} -{"level":"WARN","message":"could not build geometry for way/116707213","target":"osm_diffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:26:22.768551015Z"} -{"level":"WARN","message":"could not build geometry for way/305575606","target":"osm_diffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:52:50.538185778Z"} -{"level":"WARN","message":"could not build geometry for way/305538101","target":"osm_diffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:52:51.164032395Z"} -{"level":"WARN","message":"could not build geometry for way/305538120","target":"osm_diffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:52:51.169281566Z"} -{"fields":{"bytes":2629556368,"elapsed_seconds":1630.716088696,"feature_count":163030988,"path":"/mnt/HC_Volume_106613209/workdir/osm-features.index.pass2.tmp"},"level":"INFO","message":"OsmFeatureIndex::create: pass 1 → pass 2 spool file","target":"osm_diffs::tables::feature_index","timestamp":"2026-08-14T05:23:19.217161284Z"} -{"fields":{"feature_count":163030988,"features_bytes":17906765191,"inverted_index_bytes":2629556432,"inverted_index_entries":164347273,"pass1_seconds":1630.716088696,"pass2_seconds":59.565436453,"total_seconds":1690.281538389},"level":"INFO","message":"OsmFeatureIndex::create: done","target":"osm_diffs::tables::feature_index","timestamp":"2026-08-14T05:24:18.782046497Z"} -{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":7433.5,"phase":"end","rss_anon_bytes":14000000,"rss_bytes":29000000,"rss_file_bytes":18000000000,"rss_peak_bytes":18500000000,"rss_shmem_bytes":0,"step":"import_osm"},"level":"INFO","message":"import_osm: end","target":"osm_diffs::pipeline","timestamp":"2026-08-14T05:24:18.783000000Z"} +{"level":"INFO","message":"pipeline starting up, version=v0.6.10","target":"osmdiffs::logging","timestamp":"2026-08-14T00:20:13.415103813Z"} +{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osmdiffs::atp","timestamp":"2026-08-14T00:20:13.525825392Z"} +{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osmdiffs::atp","timestamp":"2026-08-14T00:20:13.525876328Z"} +{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osmdiffs::atp","timestamp":"2026-08-14T00:20:13.525885683Z"} +{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osmdiffs::atp","timestamp":"2026-08-14T00:20:13.525893946Z"} +{"level":"WARN","message":"Skipping AllThePlaces run entry: missing 'output_url'","target":"osmdiffs::atp","timestamp":"2026-08-14T00:20:13.525901647Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":3198976,"rss_bytes":9265152,"rss_file_bytes":6066176,"rss_peak_bytes":9265152,"rss_shmem_bytes":0,"step":"import_atp"},"level":"INFO","message":"import_atp: start","target":"osmdiffs::pipeline","timestamp":"2026-08-14T00:20:13.416185221Z"} +{"fields":{"end_time":"2026-08-11T21:11:13Z","run_id":"2026-08-08-13-32-19","size_bytes":2627885079,"spiders":4867,"total_lines":40242906},"level":"INFO","message":"fetched AllThePlaces dump","target":"osmdiffs::atp","timestamp":"2026-08-14T00:21:29.822279200Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":245.580147419,"phase":"end","rss_anon_bytes":11976704,"rss_bytes":26083328,"rss_file_bytes":14106624,"rss_peak_bytes":811192320,"rss_shmem_bytes":0,"step":"import_atp"},"level":"INFO","message":"import_atp: end","target":"osmdiffs::pipeline","timestamp":"2026-08-14T00:24:18.996240040Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":11976704,"rss_bytes":26083328,"rss_file_bytes":14106624,"rss_peak_bytes":811192320,"rss_shmem_bytes":0,"step":"build_coverage"},"level":"INFO","message":"build_coverage: start","target":"osmdiffs::pipeline","timestamp":"2026-08-14T00:24:18.996331247Z"} +{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osmdiffs::geometry","timestamp":"2026-08-14T00:24:19.417806433Z"} +{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osmdiffs::geometry","timestamp":"2026-08-14T00:24:19.594082487Z"} +{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osmdiffs::geometry","timestamp":"2026-08-14T00:24:19.621817789Z"} +{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osmdiffs::geometry","timestamp":"2026-08-14T00:24:19.669221549Z"} +{"level":"WARN","message":"polygon had no winding order. Results are undefined.","target":"osmdiffs::geometry","timestamp":"2026-08-14T00:24:19.878242477Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":494.985524166,"phase":"end","rss_anon_bytes":12582912,"rss_bytes":27262976,"rss_file_bytes":14680064,"rss_peak_bytes":847249408,"rss_shmem_bytes":0,"step":"build_coverage"},"level":"INFO","message":"build_coverage: end","target":"osmdiffs::pipeline","timestamp":"2026-08-14T00:32:33.981890235Z"} +{"fields":{"step":"build_coverage"},"level":"ERROR","message":"build_coverage failed: I/O operation failed: No file descriptors available (os error 24): No file descriptors available (os error 24)","target":"osmdiffs::pipeline","timestamp":"2026-08-14T00:32:33.981922003Z"} +{"level":"INFO","message":"pipeline starting up, version=v0.6.10","target":"osmdiffs::logging","timestamp":"2026-08-14T02:10:01.927000739Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":3198976,"rss_bytes":9265152,"rss_file_bytes":6066176,"rss_peak_bytes":9265152,"rss_shmem_bytes":0,"step":"import_atp"},"level":"INFO","message":"import_atp: start","target":"osmdiffs::pipeline","timestamp":"2026-08-14T02:10:01.927600739Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":0.00028535,"phase":"end","rss_anon_bytes":3198976,"rss_bytes":9265152,"rss_file_bytes":6066176,"rss_peak_bytes":9265152,"rss_shmem_bytes":0,"step":"import_atp"},"level":"INFO","message":"import_atp: end","target":"osmdiffs::pipeline","timestamp":"2026-08-14T02:10:01.928240884Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":3198976,"rss_bytes":9265152,"rss_file_bytes":6066176,"rss_peak_bytes":9265152,"rss_shmem_bytes":0,"step":"build_coverage"},"level":"INFO","message":"build_coverage: start","target":"osmdiffs::pipeline","timestamp":"2026-08-14T02:10:01.928343328Z"} +{"level":"INFO","message":"build_spatial_coverage finished, built \"/mnt/HC_Volume_106613191/workdir/coverage\"","target":"osmdiffs::coverage::writer","timestamp":"2026-08-14T03:16:24.947748077Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":3983.020624965,"phase":"end","rss_anon_bytes":13000000,"rss_bytes":27500000,"rss_file_bytes":15000000,"rss_peak_bytes":900000000,"rss_shmem_bytes":0,"step":"build_coverage"},"level":"INFO","message":"build_coverage: end","target":"osmdiffs::pipeline","timestamp":"2026-08-14T03:16:24.949063896Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":null,"phase":"start","rss_anon_bytes":13000000,"rss_bytes":27500000,"rss_file_bytes":15000000,"rss_peak_bytes":900000000,"rss_shmem_bytes":0,"step":"import_osm"},"level":"INFO","message":"import_osm: start","target":"osmdiffs::pipeline","timestamp":"2026-08-14T03:16:24.949206101Z"} +{"fields":{"replication_timestamp":"2026-08-10T00:00:00Z","sha256":"1c3b456bbf66e853d83316593c9c73763753326115ac831fe006906b50f119db","source":"http://www.openstreetmap.org/api/0.6","writing_program":"planet-dump-ng 1.2.4"},"level":"INFO","message":"opened OpenStreetMap planet file","target":"osmdiffs::pipeline::osm","timestamp":"2026-08-14T03:48:09.411557950Z"} +{"level":"WARN","message":"could not build geometry for way/116707169","target":"osmdiffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:26:22.761218419Z"} +{"level":"WARN","message":"could not build geometry for way/116707190","target":"osmdiffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:26:22.768503504Z"} +{"level":"WARN","message":"could not build geometry for way/116707213","target":"osmdiffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:26:22.768551015Z"} +{"level":"WARN","message":"could not build geometry for way/305575606","target":"osmdiffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:52:50.538185778Z"} +{"level":"WARN","message":"could not build geometry for way/305538101","target":"osmdiffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:52:51.164032395Z"} +{"level":"WARN","message":"could not build geometry for way/305538120","target":"osmdiffs::pipeline::osm::assemble","timestamp":"2026-08-14T05:52:51.169281566Z"} +{"fields":{"bytes":2629556368,"elapsed_seconds":1630.716088696,"feature_count":163030988,"path":"/mnt/HC_Volume_106613209/workdir/osm-features.index.pass2.tmp"},"level":"INFO","message":"OsmFeatureIndex::create: pass 1 → pass 2 spool file","target":"osmdiffs::tables::feature_index","timestamp":"2026-08-14T05:23:19.217161284Z"} +{"fields":{"feature_count":163030988,"features_bytes":17906765191,"inverted_index_bytes":2629556432,"inverted_index_entries":164347273,"pass1_seconds":1630.716088696,"pass2_seconds":59.565436453,"total_seconds":1690.281538389},"level":"INFO","message":"OsmFeatureIndex::create: done","target":"osmdiffs::tables::feature_index","timestamp":"2026-08-14T05:24:18.782046497Z"} +{"fields":{"cgroup_current_bytes":null,"cgroup_max_bytes":null,"cgroup_peak_bytes":null,"elapsed_seconds":7433.5,"phase":"end","rss_anon_bytes":14000000,"rss_bytes":29000000,"rss_file_bytes":18000000000,"rss_peak_bytes":18500000000,"rss_shmem_bytes":0,"step":"import_osm"},"level":"INFO","message":"import_osm: end","target":"osmdiffs::pipeline","timestamp":"2026-08-14T05:24:18.783000000Z"} diff --git a/scripts/test-on-hetzner/tests/test_cloud_test.py b/scripts/test-on-hetzner/tests/test_cloud_test.py index a7bda5af..bb8ea3a9 100644 --- a/scripts/test-on-hetzner/tests/test_cloud_test.py +++ b/scripts/test-on-hetzner/tests/test_cloud_test.py @@ -26,22 +26,22 @@ def test_label_flags_sanitizes_branch_slash(): flags = ct.label_flags("myname", branch="feature/foo") assert flags == [ "--label", - "osm-diffs-test=true", + "osmdiffs-test=true", "--label", - "osm-diffs-test-owner=myname", + "osmdiffs-test-owner=myname", "--label", - "osm-diffs-test-branch=feature--foo", + "osmdiffs-test-branch=feature--foo", ] def test_label_flags_sanitizes_image_slash_and_colon(): flags = ct.label_flags("myname", image="ghcr.io/brawer/osmdiffs:v1.2.3") - assert flags[-1] == "osm-diffs-test-image=ghcr.io--brawer--osmdiffs--v1.2.3" + assert flags[-1] == "osmdiffs-test-image=ghcr.io--brawer--osmdiffs--v1.2.3" def test_label_flags_no_branch_or_image(): flags = ct.label_flags("myname") - assert flags == ["--label", "osm-diffs-test=true", "--label", "osm-diffs-test-owner=myname"] + assert flags == ["--label", "osmdiffs-test=true", "--label", "osmdiffs-test-owner=myname"] # ── s3_credentials / s3_endpoint / s3_client ───────────────────────── @@ -145,7 +145,7 @@ def test_containerized_run_command_basic_flags(monkeypatch): assert "--memory=4g" in cmd assert "--cpus=2" in cmd assert "-v /workdir:/workdir" in cmd - assert "osm-diffs-test run --workdir /workdir" in cmd + assert "osmdiffs-test run --workdir /workdir" in cmd assert "--run_id" not in cmd @@ -204,7 +204,7 @@ def fake_scp(ip, local, remote): cmd = ct.containerized_run_command(args, "1.2.3.4", "/workdir") - assert "--env-file /root/osm-diffs/s3.env" in cmd + assert "--env-file /root/osmdiffs/s3.env" in cmd env_content = scp_files["s3.env"] # Both destinations, pointed at the one ephemeral test bucket. for prefix in ("PUBLIC_S3", "INTERNAL_S3"): @@ -400,14 +400,14 @@ def test_cmd_list_skips_buckets_without_bucket_region(monkeypatch, capsys): def test_cmd_list_lists_buckets_with_bucket_region(monkeypatch, capsys): mock_client = MagicMock() mock_client.list_buckets.return_value = { - "Buckets": [{"Name": "osm-diffs-container-test-1", "CreationDate": datetime(2026, 1, 1, tzinfo=UTC)}] + "Buckets": [{"Name": "osmdiffs-container-test-1", "CreationDate": datetime(2026, 1, 1, tzinfo=UTC)}] } monkeypatch.setattr(ct, "hcloud_json", lambda args: []) monkeypatch.setattr(ct, "s3_client", lambda region: mock_client) ct.cmd_list(Args(bucket_region="fsn1")) - assert "osm-diffs-container-test-1" in capsys.readouterr().out + assert "osmdiffs-container-test-1" in capsys.readouterr().out # ── cmd_create prints the teardown command ──────────────────────────── diff --git a/scripts/test-on-hetzner/tests/test_validate.py b/scripts/test-on-hetzner/tests/test_validate.py index 0364e8f0..771dae93 100644 --- a/scripts/test-on-hetzner/tests/test_validate.py +++ b/scripts/test-on-hetzner/tests/test_validate.py @@ -283,7 +283,7 @@ def test_check_cgroup_signal_fails_when_conflate_end_missing(): "dmesg_text,expected", [ ("kernel: some unrelated line\n", True), - ("kernel: Out of memory: Killed process 123 (osm-diffs)\n", False), + ("kernel: Out of memory: Killed process 123 (osmdiffs)\n", False), ], ) def test_check_no_oom(dmesg_text, expected): @@ -348,7 +348,7 @@ def test_run_hard_checks_skips_parquet_checks_when_output_is_missing(tmp_path): records = [ {"level": "INFO", "message": "conflate: start", "fields": {"step": "conflate", "phase": "start"}}, ] - dmesg_text = "Memory cgroup out of memory: Killed process 2699 (osm-diffs)" + dmesg_text = "Memory cgroup out of memory: Killed process 2699 (osmdiffs)" results = v.run_hard_checks( con, url, records, dmesg_text=dmesg_text, mem_limit="4g", expect_pipeline_version=None, min_atp_features=None ) diff --git a/src/main.rs b/src/main.rs index fbbff216..5f85eb0b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,7 +42,7 @@ fn main() -> Result<()> { match &args.command { Some(Commands::Run { workdir, run_id }) => { let client = build_client(); - osm_diffs::run_pipeline(&client, workdir, run_id) + osmdiffs::run_pipeline(&client, workdir, run_id) } None => Err(anyhow!("no subcommand given")), } diff --git a/src/pipeline/datapackage.rs b/src/pipeline/datapackage.rs index 50776af5..b54080e1 100644 --- a/src/pipeline/datapackage.rs +++ b/src/pipeline/datapackage.rs @@ -251,7 +251,7 @@ mod tests { /// The full serialized manifest, pinned to a committed fixture so any /// change to its shape shows up in review. Regenerate with - /// `UPDATE_GOLDEN=1 cargo test -p osm-diffs datapackage`. + /// `UPDATE_GOLDEN=1 cargo test -p osmdiffs datapackage`. #[test] fn matches_golden() -> Result<()> { let workdir = TempDir::new()?; diff --git a/src/pipeline/memstats.rs b/src/pipeline/memstats.rs index 8aca8e4e..d397321e 100644 --- a/src/pipeline/memstats.rs +++ b/src/pipeline/memstats.rs @@ -249,7 +249,7 @@ mod linux { #[test] fn test_parse_proc_status() { let content = "\ -Name:\tosm-diffs +Name:\tosmdiffs State:\tR (running) VmPeak:\t 2000000 kB VmSize:\t 1900000 kB @@ -273,7 +273,7 @@ Threads:\t8 #[test] fn test_parse_proc_status_missing_fields() { - let stats = parse_proc_status("Name:\tosm-diffs\nState:\tR (running)\n"); + let stats = parse_proc_status("Name:\tosmdiffs\nState:\tR (running)\n"); assert_eq!(stats, MemStats::default()); } diff --git a/src/pipeline/provenance.rs b/src/pipeline/provenance.rs index dfa37a3d..fb6139ea 100644 --- a/src/pipeline/provenance.rs +++ b/src/pipeline/provenance.rs @@ -219,11 +219,12 @@ const SERIAL_NAMESPACE: Uuid = Uuid::from_bytes([ /// rather than a fresh random v4 UUID per run, which made every BOM /// (and, with it, `conflated.parquet`) non-reproducible. fn deterministic_serial_number(atp: &AtpMetadata, osm: &OsmMetadata) -> Result { - let atp_sha = atp.sha256.as_deref().context( - "AllThePlaces metadata has no sha256 (workdir from an older osm-diffs version?)", - )?; + let atp_sha = atp + .sha256 + .as_deref() + .context("AllThePlaces metadata has no sha256 (workdir from an older osmdiffs version?)")?; let osm_sha = osm.sha256.as_deref().context( - "OpenStreetMap metadata has no sha256 (workdir from an older osm-diffs version?)", + "OpenStreetMap metadata has no sha256 (workdir from an older osmdiffs version?)", )?; Ok( Uuid::new_v5(&SERIAL_NAMESPACE, format!("{atp_sha}:{osm_sha}").as_bytes()) @@ -232,14 +233,14 @@ fn deterministic_serial_number(atp: &AtpMetadata, osm: &OsmMetadata) -> Result Value { let version = env!("CARGO_PKG_VERSION"); json!({ - "bom-ref": "tool-osm-diffs", + "bom-ref": "tool-osmdiffs", "type": "application", - "name": "osm-diffs", + "name": "osmdiffs", "version": version, "purl": format!("pkg:github/brawer/osmdiffs@{version}"), "externalReferences": [ @@ -250,7 +251,7 @@ fn tool_component() -> Value { } /// `conflated.parquet` itself -- the data file this BOM is embedded -/// into, described as data (not as the `osm-diffs` tool that built it, +/// into, described as data (not as the `osmdiffs` tool that built it, /// which is `tool_component()` instead). /// /// `output` (`Some` only for the standalone sidecar BOM) adds the @@ -297,9 +298,10 @@ fn atp_component(atp: &AtpMetadata) -> Result { // workdir left over from before this field existed -- matches how // AtpMetadata's other fields are already treated: don't build a BOM // from data we don't actually trust. - let sha256 = atp.sha256.as_deref().context( - "AllThePlaces metadata has no sha256 (workdir from an older osm-diffs version?)", - )?; + let sha256 = atp + .sha256 + .as_deref() + .context("AllThePlaces metadata has no sha256 (workdir from an older osmdiffs version?)")?; Ok(json!({ "bom-ref": "alltheplaces.zip", "type": "data", @@ -333,7 +335,7 @@ fn osm_component(osm: &OsmMetadata) -> Result { // workdir left over from before this field existed -- matches how // atp_component treats AtpMetadata::sha256. let sha256 = osm.sha256.as_deref().context( - "OpenStreetMap metadata has no sha256 (workdir from an older osm-diffs version?)", + "OpenStreetMap metadata has no sha256 (workdir from an older osmdiffs version?)", )?; Ok(json!({ // Reference PLANET_PBF_FILENAME rather than a literal, so this @@ -362,11 +364,11 @@ fn osm_component(osm: &OsmMetadata) -> Result { /// which inputs to produce which output. fn formulation(pipeline_run_id: &str, time_start: &str, time_end: &str) -> Value { json!({ - "bom-ref": "formula-osm-diffs-build", + "bom-ref": "formula-osmdiffs-build", "workflows": [{ - "bom-ref": "workflow-osm-diffs-build", + "bom-ref": "workflow-osmdiffs-build", "uid": pipeline_run_id, - "name": "osm-diffs conflation", + "name": "osmdiffs conflation", "taskTypes": ["build"], // This pipeline runs as a weekly batch job (see // docs/SUPPLY_CHAIN_SECURITY.md), not on manual/ad-hoc @@ -374,13 +376,13 @@ fn formulation(pipeline_run_id: &str, time_start: &str, time_end: &str) -> Value // "uid" too: one trigger firing is one pipeline run here, // so there's no separate identifier worth inventing. "trigger": { - "bom-ref": "trigger-osm-diffs-schedule", + "bom-ref": "trigger-osmdiffs-schedule", "uid": pipeline_run_id, "type": "scheduled", }, "timeStart": time_start, "timeEnd": time_end, - "resourceReferences": [{"ref": "tool-osm-diffs"}], + "resourceReferences": [{"ref": "tool-osmdiffs"}], "inputs": [ {"resource": {"ref": "alltheplaces.zip"}}, {"resource": {"ref": pipeline::PLANET_PBF_FILENAME}}, @@ -454,9 +456,9 @@ mod tests { assert_eq!(bom["metadata"]["supplier"]["name"], "Sascha Brawer"); let tool = &bom["metadata"]["tools"]["components"][0]; - assert_eq!(tool["bom-ref"], "tool-osm-diffs"); + assert_eq!(tool["bom-ref"], "tool-osmdiffs"); assert_eq!(tool["type"], "application"); - assert_eq!(tool["name"], "osm-diffs"); + assert_eq!(tool["name"], "osmdiffs"); assert_eq!(tool["version"], env!("CARGO_PKG_VERSION")); assert_eq!( tool["purl"], @@ -557,7 +559,7 @@ mod tests { // Every bom-ref the formulation refers to must actually exist. let known_refs = [ - "tool-osm-diffs", + "tool-osmdiffs", "conflated.parquet", "alltheplaces.zip", pipeline::PLANET_PBF_FILENAME, @@ -570,7 +572,7 @@ mod tests { // span -- the workflow's own `uid` is the only run-specific field. assert_eq!(workflow["timeStart"], "2026-03-04T15:16:17Z"); assert_eq!(workflow["timeEnd"], bom["metadata"]["timestamp"]); - assert_eq!(workflow["resourceReferences"][0]["ref"], "tool-osm-diffs"); + assert_eq!(workflow["resourceReferences"][0]["ref"], "tool-osmdiffs"); for input in workflow["inputs"].as_array().expect("inputs") { let r = input["resource"]["ref"].as_str().expect("ref"); assert!(known_refs.contains(&r), "unknown bom-ref {r}"); diff --git a/src/pipeline/upload.rs b/src/pipeline/upload.rs index 7065916c..b1582835 100644 --- a/src/pipeline/upload.rs +++ b/src/pipeline/upload.rs @@ -139,7 +139,7 @@ impl Bucket { /// environment and reused for every upload to it in a pipeline run. /// /// All five come from environment variables, none of them CLI flags -/// (`osm-diffs run --help` won't mention them) -- they're ambient +/// (`osmdiffs run --help` won't mention them) -- they're ambient /// deployment config, the kind you'd set once for wherever this runs on /// a schedule, not something to pass per invocation. For prefix /// `PUBLIC_S3` (likewise `INTERNAL_S3`): diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 04664dc4..3608ffc4 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use tempfile::TempDir; /// Sets up a workdir with the fixture inputs symlinked in (so the -/// pipeline uses them instead of fetching), runs `osm-diffs run` to +/// pipeline uses them instead of fetching), runs `osmdiffs run` to /// completion, and returns the workdir. fn run_pipeline_on_fixtures(extra_args: &[&str]) -> Result { use std::os::unix::fs::symlink; @@ -37,7 +37,7 @@ fn run_pipeline_on_fixtures(extra_args: &[&str]) -> Result { workdir.path().join("planet-latest.osm.pbf.meta.json"), )?; - Command::new(cargo_bin!("osm-diffs")) + Command::new(cargo_bin!("osmdiffs")) .arg("run") .arg("--workdir") .arg(workdir.path()) @@ -185,7 +185,7 @@ fn test_workdir_run_id_guard() -> Result<()> { let workdir = run_pipeline_on_fixtures(&["--run_id", "run-A"])?; // Same run id, same workdir: a restart -- succeeds (steps are cached). - Command::new(cargo_bin!("osm-diffs")) + Command::new(cargo_bin!("osmdiffs")) .arg("run") .arg("--workdir") .arg(workdir.path()) @@ -194,7 +194,7 @@ fn test_workdir_run_id_guard() -> Result<()> { .success(); // Different run id, same workdir: refused. - Command::new(cargo_bin!("osm-diffs")) + Command::new(cargo_bin!("osmdiffs")) .arg("run") .arg("--workdir") .arg(workdir.path()) @@ -642,7 +642,7 @@ fn assert_conflated_tile_layers(workdir: &Path) -> Result<()> { #[test] fn test_no_subcommand() { - Command::new(cargo_bin!("osm-diffs")) + Command::new(cargo_bin!("osmdiffs")) .assert() .failure() .stderr(predicates::str::contains("no subcommand given")); @@ -652,7 +652,7 @@ fn test_no_subcommand() { fn test_version_flag() { // Asserts against CARGO_PKG_VERSION (rather than a hardcoded string) so // this doesn't need updating every time cut-release.sh bumps the version. - Command::new(cargo_bin!("osm-diffs")) + Command::new(cargo_bin!("osmdiffs")) .arg("--version") .assert() .success() @@ -661,7 +661,7 @@ fn test_version_flag() { #[test] fn test_help_flag() { - Command::new(cargo_bin!("osm-diffs")) + Command::new(cargo_bin!("osmdiffs")) .arg("--help") .assert() .success()