Skip to content

Release v1.6.65 - #279

Merged
roncodes merged 19 commits into
mainfrom
release/v1.6.65
Sep 28, 2026
Merged

roncodes merged 19 commits into
mainfrom
release/v1.6.65

Conversation

@roncodes

Copy link
Copy Markdown
Member

Release branch for v1.6.65, cut from main.

What it carries

2FA

IAM

Notifications and devices

Merge order

The PRs now target release/v1.6.65. Merge #272 before #277 and #274 before #275, since each pair is stacked. #275 and #278 both touch CompanyController, so whichever goes second may need a rebase.

Behaviour changes

  • Needs the console changes in fleetbase/fleetbase (fix/2fa-login-hardening, #685 and #686). With an older console, users with 2FA can't sign in and self-service password changes fail.
  • Reports, API keys, webhooks, events and logs now require their IAM/developer permissions. Fleet-Ops' report screens follow in fix(permissions): enforce Fleet-Ops permissions across the API and console fleetops#345.
  • New migration (nullable user_devices columns) and a new dependency, pragmarx/google2fa.

composer.json is bumped to 1.6.65 and RELEASE.md names v1.6.65.

🤖 Generated with Claude Code

- two-fa/check no longer starts a session from the identity alone, which let
  the emailed/SMS code stand in for the password and revealed which accounts
  have 2FA on. It now always answers {twoFaSession: null, isTwoFaEnabled: false}
  so older consoles fall through to auth/login, which already starts the
  session after the password check. createTwoFaSessionIfEnabled is deprecated.
- Store 2FA sessions with a 600 second TTL. EX was being given an absolute
  timestamp, so sessions lived for decades.
- Invalidate a 2FA session after 5 wrong codes, counted per session so
  resending a code does not reset the count, and compare codes with
  hash_equals.
- Generate verification codes with random_int instead of mt_rand.
Without an explicit android.priority, Android held order pushes while the
device was in deep Doze and delivered them only when the phone was
unlocked or charged.

Closes #268

(cherry picked from commit 5bd2ba9232c4f7fced8d502f07ab0906418d3368)
…ompany

NotificationRegistry::notify() read company settings from the session, but
it is called from queued listeners and console commands, which have no
session. Settings -> Notifications was therefore ignored whenever the queue
ran in its own worker. notifyUsingDefinitionName() read the global
notification_settings key, which the console never writes.

Both now take the company from the notification parameters (a company, or a
model with a company_uuid) and fall back to the session. Adds
Setting::lookupForCompany() for looking up a company setting without a
session.

Closes #262

(cherry picked from commit 9c24673e7677c53d8d6adf01eb6b5ae98c40fb2c)
…s set a password

POST users/set-password, validate-password and change-password had no
SkipAuthorizationCheck, so the generic check required `iam create user`.
Invited non-admin users could not set their first password (#263), and
non-admins could not change their own password.

Password endpoints now follow an AWS-style model:

- set-password needs no IAM permission, but works only once, within 24h
  of accepting an invite (a server-side allowance set by
  acceptCompanyInvite). It used to accept a new password at any time
  without the current one.
- change-password requires the current password in the same request,
  and is allowed for admins and Administrators, when the organization
  allows users to change their own password (new setting, default on),
  or with the `iam change-password` permission (already seeded, never
  enforced until now).
- validate-password and change-password are throttled per user.
- New GET users/password-policy and GET/POST companies/auth-settings.
- Password and auth-setting changes are written to the `auth` activity log.

Closes #263

(cherry picked from commit 58ab1578513c0473bf4ff0df5bd16c9e3e32b6c4)
Add optional app_identifier, environment and last_seen_at columns to
user_devices so push senders can pick the credentials of the app a token
was registered from and the APNs environment that issued it, instead of
guessing. All columns are nullable and guarded, and callers that do not
set them keep working.
Adds authenticator apps (TOTP, RFC 6238) as a 2FA method, next to email
and SMS. Works with Google Authenticator, Authy, 1Password and similar
apps.

- Setup: POST users/two-fa/authenticator/setup (current password) returns
  a secret, an otpauth:// URL and a QR code. confirm checks a code from
  the app, makes it the user's 2FA method and returns 8 one-time recovery
  codes. disable and recovery-codes also need the current password.
- Sign-in: when the method is authenticator_app, two-fa/validate sends
  nothing and returns method "authenticator_app". two-fa/verify accepts a
  code from the app (one time step either side, each code usable once) or
  a recovery code. Wrong codes count towards the existing 5-attempt
  lockout. two-fa/resend sends a code by email (SMS without an email) as
  a fallback.
- Storage: the secret is encrypted with the app key; recovery codes are
  stored as keyed SHA-256 hashes. Neither is ever returned again or logged.
- Enable, disable, recovery code use, successful sign-ins and lockouts are
  written to the `auth` activity log.
- saveTwoFactorSettings refuses authenticator_app until an app is set up.
- New Fleetbase\Support\Barcode helper, which owns milon/barcode. QR codes
  are drawn as a compact SVG on a white background with a quiet zone, so
  they scan on dark themes too.
- New dependencies: pragmarx/google2fa ^8.0 and milon/barcode ^10.0
  (already installed everywhere through Fleet-Ops).
- Tests: the shared test container now provides a recording activity
  logger and a test encrypter.

Closes #163
- Organization settings: any member could update the company, including
  owner_uuid (take ownership) and billing/lifecycle fields, and change the
  organization 2FA policy. Updates and the 2FA policy now require the owner,
  the Administrator role or a system admin; owner, Stripe ids, plan, status,
  trial and type are ignored for non-admin updates (ownership keeps its
  transfer endpoint).
- System-wide 2FA policy save is restricted to system admins.
- Admin platform metrics are restricted to system admins; IAM and developer
  metrics require iam list user / developers list api-key.
- Reports resolved to the "fleetbase" service, so no permission ever matched
  and every report endpoint was open. ReportController now uses the iam
  service, and direct query execution/export/download require iam
  execute/export report.
- API credentials, webhooks, API events and request logs resolved to
  resource names (api-credential, webhook-endpoint, ...) that no permission
  uses, leaving them unguarded. Controllers can now declare
  $permissionResource, used by Auth when resolving permissions; these map to
  the Developers schema resources (api-key, webhook, event, log).
- Auth::cannotUnlessAdmin() for explicit checks outside AuthorizationGuard.
fix(2fa): start two-factor sessions only after the password is checked
feat(2fa): sign in with an authenticator app, with recovery codes
fix(notifications): resolve notification settings from the notified company
fix(iam): enforce the change-password permission and let invited users set a password
fix(push): send FCM order notifications with android high priority
feat: record app and APNs environment on user devices
fix(iam): close authorization gaps in core controllers
@codecov

codecov Bot commented Sep 28, 2026

Copy link
Copy Markdown

Codecov Report

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

Additional details and impacted files
@@             Coverage Diff              @@
##                main      #279    +/-   ##
============================================
  Coverage     100.00%   100.00%            
- Complexity      7499      7676   +177     
============================================
  Files            430       433     +3     
  Lines          24488     25009   +521     
============================================
+ Hits           24488     25009   +521     
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.

@roncodes
roncodes merged commit b82d921 into main Sep 28, 2026
7 checks passed
@roncodes
roncodes deleted the release/v1.6.65 branch September 28, 2026 09:49
@roncodes roncodes mentioned this pull request Sep 28, 2026
6 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment