Skip to content

v1.6.74 - #322

Merged
roncodes merged 25 commits into
mainfrom
release/v1.6.74
Oct 27, 2026
Merged

roncodes merged 25 commits into
mainfrom
release/v1.6.74

Conversation

@roncodes

@roncodes roncodes commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Summary

The v1.6.74 release branch: bumps composer.json to 1.6.74 and replaces RELEASE.md. Merged into it:

Companion PRs

Upgrade Steps

  • php artisan migrate
  • To use Sign in with Fleetbase, give every API instance the same signing key pair:
    • run php artisan oauth-server:keys, or
    • run php artisan oauth-server:keys --show and set OAUTH_SERVER_PRIVATE_KEY / OAUTH_SERVER_PUBLIC_KEY.
  • Set OAUTH_SERVER_ISSUER if the public API URL differs from APP_URL. On Cloud it's https://api.fleetbase.io.

Test plan

  • EndpointWebhookSigningTest and ResourceLifecycleWebhookListenerTest pass locally on PHP 8.4.
  • FileControllerTest, FileResolverServiceTest and FileModelTest pass locally. The one FileModelTest failure needs a DB connection and fails the same way on main.
  • AppReviewTest and tests/Unit/Auth/OAuthServer (90 tests) pass locally.
  • Full suite with coverage passes locally, at 100% on every enforced metric.
  • CI green on this branch.
  • Sign in with Fleetbase clicked through end to end on a running stack (not yet: the local Docker MySQL was being killed for memory).

roncodes and others added 4 commits October 22, 2026 21:18
…crets

- /v1/webhook-endpoints (create, list, show, update, rotate-secret, delete) for
  API keys, scoped to the key's company and live/test environment. The signing
  secret is returned only on create and rotate.
- Each endpoint has its own encrypted signing secret (whsec_...), generated on
  creation or on first use for existing endpoints.
- Deliveries add X-Fleetbase-Signature: t=<unix>,v1=<hmac_sha256(t.body)>. The
  legacy Signature header (API credential secret) is unchanged.
- Console: reveal and rotate an endpoint's secret.
Uploads were stored under the client's original extension, while
UploadFileRequest validates only the type detected from the contents. A
file whose contents pass that check could therefore be stored as .php or
.phtml, for example a PNG with PHP appended.

Add File::storageExtensionForUpload(). It keeps the client's extension when
it matches the detected type or is a plain data format that detection
reports loosely (CSV, XLSX, JSON, certificates and so on), otherwise takes
the extension of the detected type, falling back to "bin", and never
returns an extension a web server may execute. Use it for multipart uploads
(randomFileNameFromRequest) and for FileResolverService uploads.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@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 (494d885) to head (64245ec).

Additional details and impacted files
@@              Coverage Diff              @@
##                main      #322     +/-   ##
=============================================
  Coverage     100.00%   100.00%             
- Complexity      8935      9600    +665     
=============================================
  Files            473       519     +46     
  Lines          28067     29841   +1774     
=============================================
+ Hits           28067     29841   +1774     
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 and others added 15 commits October 23, 2026 13:39
…-signing

feat(webhooks): API-key webhook endpoints and per-endpoint signing secrets
…-mime

Derive uploaded file extension from the validated MIME type
Apple and Google reviewers can't receive a texted sign-in code. Extensions register what their app signs reviewers in to (a Storefront store, an organization's Navigator app) with a review number from the 555-0100-0199 range reserved for fiction; the owner turns access on in the Console and gives the app store that number and a six-digit code, stored hashed and accepted only for that subject. New review_accesses table, Fleetbase\Support\AppReview, and GET|PUT int/v1/review-access/{type}/{id}.

Numbers in the fictional range are never texted: SmsService answers as sent without calling a provider, and SMS verification codes are saved without reserving or sending. Tests that sent to 555-01xx numbers use other test numbers.
- Support\InstanceIdentity: a per-install ID and secret created at runtime
  and kept in the system.instance setting. Not .fleetbase-id, which is baked
  into the Docker image and shared by every install of a tag.
- Support\HostedRouting::register(): registers the install with Fleetbase
  Cloud (POST __/licenses/register-instance) with the install ID and secret,
  the admin email, the install URL and the version; stores the returned key
  in the valhalla setting (with host https://valhalla.routing.fleetbase.io)
  that the Valhalla panel and Fleet-Ops read, and the registration (plan,
  claim link, email; never the key) in system.hosted-routing. Idempotent:
  skips an install that holds its hosted key or runs its own Valhalla server.
  Separate from telemetry.
- php artisan routing:register [--email] [--domain] [--force]: explains what
  is sent and where it is processed; ROUTING_AUTO_REGISTER=false skips it
  unless forced.
- Onboarding: should-onboard reports hosted_routing (offered to the first
  admin while enabled and no own server is set); create-account takes
  hosted_routing and, for the first admin who kept it on, registers after
  the response is sent (RegisterHostedRouting via dispatchAfterResponse).
- config fleetbase.hosted_routing (ROUTING_AUTO_REGISTER,
  ROUTING_REGISTRATION_URL, ROUTING_API_HOST, ROUTING_HOSTED_DOMAIN,
  ROUTING_REGISTRATION_TIMEOUT).

Co-Authored-By: Claude <noreply@anthropic.com>
… classes

Co-Authored-By: Claude <noreply@anthropic.com>
…nect provider

Registered apps can offer "Continue with Fleetbase" and, with the user's
consent, act on one organization they administer. Built on
league/oauth2-server: authorization code with PKCE (S256, every client),
rotating refresh tokens, RFC 7009 revocation, ID tokens, userinfo, JWKS and
discovery. Codes and tokens are bound to a grant and its organization, which
every refresh and API call re-checks. Consent runs on the console session;
admins manage apps and users manage connected apps.
…sole sandbox mode

The consent screen runs on the console session, which switches models to the
sandbox connection when test mode is on. OAuth rows and the organization
checks now always use the core connection. Also raise the per-IP limit on the
token and resource endpoints, since an app's server makes every call from one
address.
…ints, commands and edge cases

core-api CI requires full coverage. Adds tests for the console endpoints, the
authorize redirect, the artisan commands, the authorized-app notice, real
spatie roles in the organization check, and the protocol edge cases. The
authorize endpoint builds its RedirectResponse directly.
…permission check

Unknown types, any type's number, a custom resolver, an unsaved or unregistered subject, the table before migration, an unreadable table, and the Console endpoint for nobody, a viewer, a permission or wildcard holder, an administrator and an unseeded permission. Brings both files to the 100% coverage gate.
feat(app-review): App Review access for apps built on Fleetbase
feat(oauth-server): Sign in with Fleetbase (OAuth 2.0 / OpenID Connect provider)
…e-registration

feat(routing): Fleetbase Hosted Routing keys at install time
The method clashed with AuthorizesRequests::authorize on the base
controller, so loading the class was a fatal error and GET
/oauth/authorize never worked.
fix(oauth-server): /oauth/authorize fatal error
…e scope

Software installed on many sites, such as the Fleetbase for WooCommerce plugin,
cannot share one registered redirect URI, so each install now registers its own
public PKCE client at POST /oauth/register (RFC 7591).

- Only software listed under oauth-server.registration.software may register,
  with the scopes listed there; the request supplies the software id and exactly
  one redirect URI. Clients are never official and are named after the
  redirect host, so the consent screen and Connected apps show the site.
  Registering again returns the same client; disabled clients are refused;
  clients that never get a grant are pruned after a day. Advertised as
  registration_endpoint in discovery; OAUTH_SERVER_REGISTRATION_ENABLED turns
  it off.
- api-key:create scope and POST /oauth/v1/api-key: creates or returns the live
  API key an app minted in the token's organization, tracked by the new
  api_credentials.oauth_client_id rather than by name.
- Revoking an app's last grant in an organization (Connected apps, admin
  revoke, disabling the app) expires the keys it minted there.
…i-key

For an app that serves many installations from one client, such as the Shopify
app (one official client, one key per shop):

- POST /oauth/v1/api-key takes an optional installation (string, at most 190
  characters). With it, the key is found or minted by (company, client,
  installation) and named "{app} ({installation})", stored in the new
  api_credentials.oauth_installation. Without it nothing changes.
- DELETE /oauth/v1/api-key, same scope and optional installation, expires only
  the calling app's key for that installation in the token's company (the
  app-wide key when installation is omitted). 204, idempotent; the grant and
  other installations' keys are untouched.
- Revoking the app's last grant in the organization still expires all of its
  keys, installation keys included.
feat(oauth-server): dynamic client registration and the api-key:create scope
@roncodes
roncodes merged commit ac97b56 into main Oct 27, 2026
7 checks passed
@roncodes
roncodes deleted the release/v1.6.74 branch October 27, 2026 08:58
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