Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a3614ec
ci: point the Postman contract at the v0.7.53 release
roncodes Aug 7, 2026
5fed04b
ci: unpin the contract workflow now that it tracks latest
roncodes Aug 8, 2026
faf20a3
fix(customers): default a Place location so signup with a place works
roncodes Aug 8, 2026
68a8eb1
fix(drivers): close verify-code authentication bypass
roncodes Aug 8, 2026
9b4ebba
feat(customers): add a non-production verification-code bypass
roncodes Aug 8, 2026
7ec2b0e
fix(api): answer 404 instead of 500 for an unknown onboard organization
roncodes Aug 8, 2026
5e979bd
fix(api): return 422 instead of 500 on duplicate part SKU and fuel tr…
roncodes Aug 8, 2026
8990a73
v0.6.60
roncodes Aug 10, 2026
1838ab2
ci: run the server, ember and Postman workflows on dev-v* release bra…
roncodes Aug 10, 2026
a0de4f9
test(customers): realign the CreateCustomerRequest source assertion
roncodes Aug 10, 2026
2b8d0be
test(drivers): give the auth-flow harness a container that answers en…
roncodes Aug 10, 2026
73f0761
test(requests): cover the duplicate-key messages and provider fallback
roncodes Aug 10, 2026
ec47bda
test(drivers): extend the environment() container swap to the interna…
roncodes Aug 10, 2026
d0be554
Merge pull request #288 from fleetbase/ci/postman-contract-v0.7.53
roncodes Aug 10, 2026
1c7085b
test(navigator): cover the real errorResponse seam
roncodes Aug 10, 2026
56d5c5b
Merge pull request #290 from fleetbase/feature/onboard-driver-setting…
roncodes Aug 10, 2026
983668d
Merge pull request #291 from fleetbase/feature/fix-duplicate-key-500s…
roncodes Aug 10, 2026
728a93d
Merge pull request #292 from fleetbase/fix/driver-verify-code-bypass
roncodes Aug 10, 2026
6a43d21
Merge pull request #293 from fleetbase/fix/customer-place-location-de…
roncodes Aug 10, 2026
6092b24
Merge pull request #294 from fleetbase/feat/customer-verification-byp…
roncodes Aug 10, 2026
6f3b4b0
ci(postman): test this branch's API code, not the published package
roncodes Aug 10, 2026
8b1f4e4
Merge pull request #296 from fleetbase/ci/contract-overlay-branch-source
roncodes Aug 10, 2026
2ce6b76
fix(auth): scope the verification bypass to designated review accounts
roncodes Aug 10, 2026
4a95266
test(auth): align the bypass contracts with the review-account policy
roncodes Aug 10, 2026
2b98ef4
fix(maintenance): restore vehicle schedule workflows
roncodes Aug 10, 2026
119bc88
fix(sensors): default last_position so a sensor can be created at all
roncodes Aug 10, 2026
c0c0a9d
fix(api): register-device was unreachable on both driver routes
roncodes Aug 11, 2026
8c099a5
fix(api): fuel reports could not be created without a location or upd…
roncodes Aug 11, 2026
c499bce
fix(api): geofence driver history asked for a uuid the API never issues
roncodes Aug 12, 2026
efc10a7
ci(contract): run the API contract once per commit
roncodes Aug 12, 2026
2100cee
Revert "ci(contract): run the API contract once per commit"
roncodes Aug 12, 2026
dcbf13d
test(geofence): cover the real driver lookup
roncodes Aug 12, 2026
2130c86
fix(api): publish the QR code's content in debug, and stop /from-qr 5…
roncodes Aug 12, 2026
8d301d1
test: restore 100% coverage on the QR and geofence changes
roncodes Aug 12, 2026
1e2e2ae
docs(release): write the v0.6.60 release notes
roncodes Aug 17, 2026
b9fef65
Merge branch 'main' into dev-v0.6.60
roncodes Aug 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ember.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ name: Ember.js CI

on:
push:
branches: [ main ]
branches: [ main, 'dev-v*' ]
tags:
- 'v*'
pull_request:
branches: [ main ]
branches: [ main, 'dev-v*' ]

env:
NODE_VERSION: 22.x
Expand Down
21 changes: 16 additions & 5 deletions .github/workflows/postman.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,33 @@ name: API Contract (Postman)
# collection against the live API. Delegates to the reusable workflow in
# fleetbase/fleetbase. Requires org secrets POSTMAN_API_KEY + _GITHUB_AUTH_TOKEN
# (inherited); no-ops until POSTMAN_API_KEY is set.
# TODO: change @dev-v0.7.53 to @main once that branch is merged.
#
# Deliberately unpinned. The reusable workflow defaults to booting fleetbase/fleetbase@main
# against fleetbase/fleetbase-api:latest, so every release is picked up automatically and
# there is no ref here to remember to bump. Each run records the image digest it actually
# resolved in its job summary, so a result stays traceable. To reproduce an older run:
#
# with:
# fleetbase-ref: v0.7.53
# api-image: fleetbase/fleetbase-api:v0.7.53

on:
push:
branches: [main]
branches: [main, 'dev-v*']
pull_request:
branches: [main]
branches: [main, 'dev-v*']
workflow_dispatch:

permissions:
contents: read

jobs:
contract:
uses: fleetbase/fleetbase/.github/workflows/api-contract.yml@dev-v0.7.53
uses: fleetbase/fleetbase/.github/workflows/api-contract.yml@main
with:
collections: "Fleetbase API"
build-from-source: false
# Without this the run tests the version of fleetbase/fleetops-api baked into the
# published image, not the branch under review. The workflow checks this
# repository out at the commit under test and swaps it into the container.
overlay-package: fleetbase/fleetops-api
secrets: inherit
4 changes: 2 additions & 2 deletions .github/workflows/server.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ name: PHP CI

on:
push:
branches: [ main ]
branches: [ main, 'dev-v*' ]
tags:
- 'v*'
pull_request:
branches: [ main ]
branches: [ main, 'dev-v*' ]

jobs:
build:
Expand Down
31 changes: 26 additions & 5 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
> v0.6.59 ~ "RELEASE_NOTES_PLACEHOLDER — replace this line with the release title"
> v0.6.60 ~ "Closes an authentication bypass, and clears a run of API 500s"

---
## Highlights
A security fix and a broad sweep of public API defects surfaced by running the official Postman collection against a live stack. Several endpoints answered `500` where a `404` or `422` belonged, and a few were unreachable entirely.

RELEASE_NOTES_PLACEHOLDER
---
## Security
- **Closed a verify-code authentication bypass in the driver flow.** Please upgrade.
- The non-production verification-code bypass is now scoped to explicitly designated review accounts, so a bypass code alone is not enough — the identity has to be on the allowlist too.

---
## Bug Fixes
- **Driver `register-device` was unreachable on both driver routes.** Laravel never injects a class-typed parameter that declares a default, so the injected request was always null.
- **Geofence driver history asked for a UUID the API never issues.** It now resolves the driver by the public id callers actually hold.
- **`/from-qr` returned a 500**, and the QR code's content is now published in debug mode so the flow can be exercised.
- **Fuel reports could not be created without a location**, and could not be updated.
- **A sensor could not be created at all** — `last_position` had no default.
- **Customer signup with a place failed** — the Place location now defaults.
- Unknown onboard organization answers `404` instead of `500`.
- Duplicate part SKU and fuel transaction answer `422` instead of `500`.
- Restored the vehicle maintenance schedule workflows.

Describe what changed in this release. The first line above must name the version
being released, and both placeholder markers must be gone, or the release workflow
refuses to tag.
---
## Testing
- Coverage restored to 100% across the QR, geofence, driver auth, customer request and navigator changes.

---
## Continuous Integration
- The server, Ember and Postman workflows now run on `dev-v*` release branches.
- The contract run tests this branch's API code rather than the published package.

---
## Need help?
Expand Down
4 changes: 2 additions & 2 deletions addon/components/vehicle/details/schedules.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
<div class="flex flex-col items-center justify-center py-10 text-gray-400 dark:text-gray-600">
<FaIcon @icon="calendar-alt" @size="2x" class="mb-3" />
<p class="text-sm">No maintenance schedules for this vehicle.</p>
<Button @text="Add Schedule" @icon="plus" @size="xs" @type="primary" class="mt-3" @onClick={{fn this.maintenanceScheduleActions.modal.create (hash subject=@vehicle)}} />
<Button @text="Add Schedule" @icon="plus" @size="xs" @type="primary" class="mt-3" @onClick={{this.createSchedule}} />
</div>
{{/if}}
{{/if}}
</div>
</div>
8 changes: 7 additions & 1 deletion addon/components/vehicle/details/schedules.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { task } from 'ember-concurrency';

export default class VehicleDetailsSchedulesComponent extends Component {
@service maintenanceScheduleActions;
@service notifications;
@service store;
@service vehicleActions;
@tracked schedules = [];

get resourceId() {
Expand All @@ -22,11 +24,15 @@ export default class VehicleDetailsSchedulesComponent extends Component {
try {
this.schedules = yield this.store.query('maintenance-schedule', {
subject_uuid: this.resourceId,
subject_type: 'vehicle',
subject_type: 'fleet-ops:vehicle',
sort: '-created_at',
});
} catch (err) {
this.notifications.serverError(err);
}
}

@action createSchedule() {
return this.vehicleActions.scheduleMaintenance(this.args.vehicle, {}, { refresh: false, callback: () => this.loadSchedules.perform() });
}
}
11 changes: 10 additions & 1 deletion addon/controllers/maintenance/schedules/index/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,21 @@ export default class MaintenanceSchedulesIndexEditController extends Controller
this.overlay?.close();
yield this.hostRouter.refresh();
yield this.hostRouter.transitionTo('console.fleet-ops.maintenance.schedules.index.details', schedule);
this.notifications.success(this.intl.t('common.resource-updated-success', { resource: this.intl.t('resource.maintenance-schedule') }));
this.notifyUpdateSuccess(schedule);
} catch (err) {
this.notifications.serverError(err);
}
}

notifyUpdateSuccess(schedule) {
this.notifications.success(
this.intl.t('common.resource-updated-success', {
resource: this.intl.t('resource.maintenance-schedule'),
resourceName: schedule.name,
})
);
}

@action cancel() {
return this.hostRouter.transitionTo('console.fleet-ops.maintenance.schedules.index');
}
Expand Down
6 changes: 4 additions & 2 deletions addon/services/vehicle-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,10 @@ export default class VehicleActionsService extends ResourceActionService {
},
};

@action scheduleMaintenance(vehicle) {
this.maintenanceScheduleActions.modal.create({ subject: vehicle });
@action async scheduleMaintenance(vehicle, options = {}, saveOptions = {}) {
vehicle = await this.resolveVehicleResource(vehicle);

return this.maintenanceScheduleActions.modal.create({ subject: vehicle }, options, saveOptions);
}

@action createWorkOrder(vehicle) {
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fleetbase/fleetops-api",
"version": "0.6.59",
"version": "0.6.60",
"description": "Fleet & Transport Management Extension for Fleetbase",
"keywords": [
"fleetbase-extension",
Expand Down
2 changes: 1 addition & 1 deletion extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Fleet-Ops",
"version": "0.6.59",
"version": "0.6.60",
"description": "Fleet & Transport Management Extension for Fleetbase",
"repository": "https://github.com/fleetbase/fleetops",
"license": "AGPL-3.0-or-later",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@fleetbase/fleetops-engine",
"version": "0.6.59",
"version": "0.6.60",
"description": "Fleet & Transport Management Extension for Fleetbase",
"fleetbase": {
"route": "fleet-ops"
Expand Down
44 changes: 44 additions & 0 deletions server/config/fleetops.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,54 @@
|--------------------------------------------------------------------------
*/
'navigator' => [
/*
| App store reviewers cannot receive our SMS, so a fixed verification code has
| to keep working for them — including in production, which is where a review
| build is tested. Blocking the bypass outside production made review
| impossible; restricting it to named accounts makes it safe instead.
|
| Both values are required, and neither has a default. The code alone is not
| sufficient: it is only accepted for an identity listed in review_accounts, so
| a leaked code cannot be used to authenticate as an arbitrary driver.
|
| NAVIGATOR_BYPASS_VERIFICATION_CODE=<a secret, rotated code>
| NAVIGATOR_REVIEW_ACCOUNTS=+15555550100,apple-review@example.com
*/
'bypass_verification_code' => env('SMS_AUTH_BYPASS_CODE', env('NAVIGATOR_BYPASS_VERIFICATION_CODE')),
'review_accounts' => array_values(array_filter(array_map(
'trim',
explode(',', (string) env('NAVIGATOR_REVIEW_ACCOUNTS', ''))
))),
'app_identifier' => env('NAVIGATOR_APP_IDENTIFIER', 'io.fleetbase.navigator'),
],

/*
|--------------------------------------------------------------------------
| Customers
|--------------------------------------------------------------------------
|
| Testing-only verification-code bypass for the customer auth flows
| (POST /v1/customers, /customers/verify-code, /customers/reset-password).
| Intended for local development and staging QA, where signing up means
| waiting on a real email or paying for a real SMS.
|
| MUST be left unset in production. It is ignored outright when the app
| environment is `production`, and when unset no bypass is possible.
|
| Deliberately NOT wired to SMS_AUTH_BYPASS_CODE: that variable already
| gates operator console login and driver login, and reusing it here would
| make one leaked value unlock three different privilege tiers.
|
*/
'customers' => [
'verification_bypass_code' => env('FLEETOPS_CUSTOMER_VERIFICATION_BYPASS_CODE'),
// Identities the bypass code is accepted for. See the note on navigator below.
'review_accounts' => array_values(array_filter(array_map(
'trim',
explode(',', (string) env('FLEETOPS_CUSTOMER_REVIEW_ACCOUNTS', ''))
))),
],

/*
|--------------------------------------------------------------------------
| API Events
Expand Down
2 changes: 1 addition & 1 deletion server/config/geocoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
'providers' => [
Chain::class => [
GoogleMaps::class => [
config('services.google_maps.locale', env('GOOGLE_MAPS_LOCALE', 'us')),
config('services.google_maps.locale', env('GOOGLE_MAPS_LOCALE', 'en')),
config('services.google_maps.api_key', env('GOOGLE_MAPS_API_KEY')),
]
],
Expand Down
Loading
Loading