Skip to content

release: v0.6.75 - #415

Merged
roncodes merged 31 commits into
mainfrom
release/v0.6.75
Oct 27, 2026
Merged

roncodes merged 31 commits into
mainfrom
release/v0.6.75

Conversation

@roncodes

@roncodes roncodes commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Release v0.6.75. Merging this PR into main tags v0.6.75 through the release workflow.

Included

All of these are merged into this branch:

Before merging

Upgrading

Related

The version files and RELEASE.md name v0.6.75 and now cover all of the above. Update RELEASE.md if anything else lands on this branch.

roncodes and others added 9 commits October 15, 2026 15:12
…y's routing engine

Order distance/time came from the straight-line 'calculate' provider because
DISTANCE_MATRIX_PROVIDER defaults to it and the routing setting is only read by
the console map. Resolve the provider from an explicit DISTANCE_MATRIX_PROVIDER,
then the company's routing engine when the server can call it (private OSRM
host, Google key), then 'calculate'. Fall back to the straight-line estimate
with a warning when a road provider fails instead of storing 0, cache road
results for 24h and stop caching empty ones.

Co-Authored-By: Claude <[email protected]>
… coordinates

- UpdateOrderRequest no longer applies creation's route requirements to a payload
  object: an update may send only entities (with entities_mode=replace), only a
  new dropoff, or an empty waypoints list.
- Place::createFromMixed treats an array as bare coordinates only when it has no
  address fields. A structured address sent with latitude/longitude keeps its
  street and uses those coordinates as its location, with no geocoding lookup.
  Previously the coordinates sent the place down the reverse-geocoding path,
  which discarded the street and stored a nearby address instead.
…currency, expiry and preview

- POST /v1/orders honours an Idempotency-Key header: repeats within a day return
  the first order (Idempotent-Replayed: true); a concurrent duplicate gets 409.
- scheduled_at and time windows sent with a UTC offset are stored as the same
  instant in the app timezone. The datetime cast used to drop the offset. The
  schedule endpoint's company-timezone input is now stored in UTC as well.
- Service quotes: the preliminary path read currency with has(), filtering by a
  boolean; it is now the currency code. Stored quotes get expired_at (default
  48h, fleetops.service_quotes.ttl_minutes). preview=1 prices without storing
  quote rows, for display-only callers such as storefront checkouts.
Tracking numbers are generated with the first three characters of the
company name as their prefix, so a company named "Al Noor" issues
numbers like "AL 7796486490AE". The lookup pattern added in #352 has no
space in its character class, so the public tracking page and
fleet-ops/lookup now answer "not found" for those numbers.

Allow a space only when it sits between two allowed characters. Leading,
trailing and repeated spaces, tabs, newlines, quotes and other symbols
are still refused, and the 100 character limit is unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…refix

generateTrackingNumber() takes the first three characters of the company
name as they are, so names such as "Al Noor" or "A&B Logistics" produce
numbers containing a space or "&", and names in non-Latin scripts produce
partial multibyte characters. Keep only A-Z and 0-9 from those three
characters and fall back to FLB when nothing is left.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
…ccount

Creating a driver, customer or contact looked up the login account by email
or phone across the whole instance and linked any managed account of the same
type to the new profile, adding it to the caller's organization. Any API key
holder could reveal another tenant's driver (name, email, phone came back in
the response) by guessing a phone number, attach that login to their own
organization, and then change its email, phone or password through the
profile update and credential endpoints.

- ProfileAccountManager only reuses an account that already belongs to the
  requesting organization (or belongs to none). Another organization's
  account is refused with the generic "already in use by another account"
  error, which reveals neither its details nor its type.
- Accounts already shared with another organization only take the name from
  profile updates, and driver/customer credential and login actions refuse
  them.
- POST /v1/drivers no longer creates drivers in whatever company the
  `company` parameter names: anything but the credential's own organization
  is refused like an unknown company.
…he locked replay

toStorageDateTime() parsed every value with Carbon::parse(), which throws on a
numeric string such as "1792605600". The datetime cast it replaces accepted Unix
timestamps, so form-encoded API clients that send one would have started
getting a 500. Numeric values now go through Carbon::createFromTimestamp().

Also covers the replay found after the lock is taken (a duplicate that finished
first), the one line codecov/patch flagged.
isUnowned() only looked at users.company_uuid and company_users, so an account
with neither but a live driver or contact profile in another organization (a
customer who signed up through a storefront, for example) could still be
adopted by any organization that knew its email or phone. It now also requires
that the account holds no profile anywhere.
@codecov

codecov Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (33032e5) to head (c1ee6e3).

Additional details and impacted files
@@             Coverage Diff              @@
##                main      #415    +/-   ##
============================================
  Coverage     100.00%   100.00%            
- Complexity     13596     13847   +251     
============================================
  Files            634       642     +8     
  Lines          49342     49865   +523     
============================================
+ Hits           49342     49865   +523     
Flag Coverage Δ
backend 100.00% <100.00%> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

roncodes and others added 16 commits October 23, 2026 11:44
Two parts of a generated number could carry a space or punctuation:

- The prefix took the first three characters of the company name, then
  dropped what was not a letter or digit, so "Al Noor Transport" gave AL and
  "A&B Logistics" gave AB. It now skips those characters first and takes the
  first three letters or digits (ALN, ABL), falling back to FLB.
- The suffix appended the region as given. The region falls back to the
  pickup's province or district when it has no country, and
  POST /v1/tracking-numbers accepts any string, so a pickup in "New York"
  issued ...NEW YORK. It now keeps only letters and digits, falling back to SG.

Numbers already issued keep working through the lookup change in this PR.
…-and-place-coordinates

fix(orders): allow partial payload edits and keep addresses sent with coordinates
…nt-linking

fix(security): never link a profile to another organization's login account
…-space

Allow single inner spaces in tracking number lookup (regression from #352)
…-idempotency

fix(orders,quotes): idempotent order creation, UTC scheduling, quote currency, expiry and preview
…-alphanumeric

fix(tracking): generate tracking numbers from letters and digits only
…by explicit opt-in

Add a Valhalla client (X-Api-Key) used for order distance/time and a Valhalla
tracking provider. The company's routing engine or the platform's Valhalla/
private OSRM server is used when configured; Google is never picked from
company settings. Add a switch to disable Google Routes tracking.

Co-Authored-By: Claude <[email protected]>
…ation exceptions

Admin -> Fleet-Ops -> Routing now controls which routing providers (Google,
Valhalla, OSRM, VROOM) organizations may use, the platform's default routing
and optimization engines, and per-organization exceptions. Google is off by
default. The policy is enforced for order distance, tracking intelligence,
organization settings, the orchestrator and the console's route engine and
optimization services. Valhalla reads the extension's admin and organization
settings before the environment. Rename the admin menu to Fleet-Ops.

Co-Authored-By: Claude <[email protected]>
…e map

Tracking no longer has its own provider and fallback settings: live ETAs,
remaining distance and route lines use the organization's routing engine, the
same one that measures the order, falling back to the straight-line estimate.
Add an admin server-side routing switch (road or straight-line), make
environment variables starting values for the admin policy only, and default
the optimization engine to the routing engine.

Co-Authored-By: Claude <[email protected]>
…k or the demo server

Default the routing engine to Valhalla and drop OSRM from the platform fallback
chain, so organizations without a configured engine get the straight-line
estimate rather than the public OSRM demo server. Order distance and the OSRM
tracking provider refuse the demo server even when OSRM is requested
explicitly. The console's route engine and routing-control fallbacks prefer
Valhalla, and leaflet-routing-control honours the provider policy.

Co-Authored-By: Claude <[email protected]>
…dress

Fleet-Ops reads the organization `valhalla` and `vroom` settings itself
(ValhallaClient for order distance and ETAs, VroomOrchestrationEngine
for allocation) and calls their api_host from the server. A user who
can edit routing settings could point it at loopback, private network
or cloud metadata addresses (SSRF), and values saved before the
extensions validated hosts still reach these calls.

- Support\Routing\HostPolicy: the same policy as the extensions'
  HostPolicy (fleetbase/valhalla#10, fleetbase/vroom#9). Only http(s)
  URLs without credentials whose host is, and resolves only to, public
  addresses (explicit IPv4/IPv6 blocklist).
- ValhallaClient::connection() drops an organization level whose host
  fails the policy, with its key, inside the 30 s connection cache.
- VroomOrchestrationEngine ignores the whole organization override
  (host, key, endpoint mode) when its host fails the policy.
- Self-hosted installs opt out with VALHALLA_ALLOW_PRIVATE_HOSTS
  (fleetops.valhalla.allow_private_hosts) and VROOM_ALLOW_PRIVATE_HOSTS
  (vroom.allow_private_hosts). System settings are not checked.
…n to Navigator without SMS

An organization turns it on in Settings > Navigator App > App Review. Reviewers sign in with +1 202 555 0144 (from the 555-01xx range reserved for fiction, never texted) and the organization's six-digit code, through core-api's App Review access: FleetOps registers the organization as the navigator type. The first sign-in adds an App Reviewer driver to that organization, which ad-hoc offers, nearest-driver assignment and the orchestrator leave out. The NAVIGATOR_* env review accounts still work. Requires core-api ^1.6.74.
roncodes and others added 6 commits October 25, 2026 10:34
feat(navigator): App Review access, so app store reviewers can sign in to Navigator without SMS
feat(routing): one routing engine for order distance, ETAs and the map; admin provider policy; Google off by default
fix(routing): never call an organization routing host on a private address
…rganization; admin page spacer

- OsrmConnection resolves the OSRM server like the Valhalla one: the
  organization's own (Fleet-Ops Settings -> Routing; must pass HostPolicy
  unless OSRM_ALLOW_PRIVATE_HOSTS), then the system setting (Admin ->
  Fleet-Ops -> Routing), then OSRM_HOST, then the public demo server, which
  only ever draws map routes.
- OSRM::forCompany() scopes calls to an organization; order distance,
  the OSRM tracking provider and RoutingEngineResolver::hasPrivateOsrmHost()
  use the organization's server.
- SettingController: admin-osrm-settings (admin; private hosts allowed,
  http(s) without credentials) and osrm-settings (routing-settings
  permissions; public hosts only), both 422 with the reason when refused.
  routing-settings returns osrm_host and osrm_host_source.
- Console: an OSRM Server panel in the admin routing page; an organization
  'Use my own OSRM server' panel when it routes or optimizes with OSRM; the
  osrm service, the OSRM route control (resolved per request) and the
  customer order preview call the resolved server; a 200px spacer at the
  bottom of the admin routing page.
- Tests: OSRM resolution, scoping, order distance and the four endpoints;
  the admin routing integration test and the osrm service unit test.

Co-Authored-By: Claude <[email protected]>
@roncodes
roncodes merged commit 811aa71 into main Oct 27, 2026
11 checks passed
@roncodes
roncodes deleted the release/v0.6.75 branch October 27, 2026 09:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants