Skip to content

v2.12.3

Choose a tag to compare

@mp-christian-armstrong mp-christian-armstrong released this 18 Sep 19:10
· 134 commits to main since this release

IBeam v2.12.3

Completes the provider-webhook fix from v2.12.2 for hosts that use licensed
service operations. One commit: b3e9b98 (PR #24).

Provider webhooks still failed under AddIBeamLicensedServiceOperations()

v2.12.2 (ee1e8f8) let a verified provider callback run without tenant
authorization. BillingWebhookProcessor opens an IServiceOperationSystemContext
scope after signature verification, and ServiceOperationExecutor skips the
tenant demand inside it.

That fix never reached hosts that call AddIBeamLicensedServiceOperations().
The call replaces the executor with LicensedServiceOperationExecutor, which
builds its own inner ServiceOperationExecutor and passed it no system
context. The scope was open, but the executor doing the authorization check
couldn't see it. So every webhook still returned 500 with
"tenantId is required for service operation authorization", the failure
v2.12.2 set out to remove. In Qurvia, 21 of 21 Stripe sandbox events failed on
v2.12.2.

What changed

  • LicensedServiceOperationExecutor takes IServiceOperationSystemContext as
    an optional constructor parameter and passes it to its inner executor.
  • Its licence check is skipped only while the scope is active. A verified
    webhook has no licence subject and no tenant, so demanding a licence fails
    the same way. This matters because a host's IBillingPaidPurchaseHandlers run
    inside ProcessAsync and can call licensed operations. Outside the scope,
    every caller is licence-checked exactly as before, including admin and
    support tooling that calls the same operations.
  • AddIBeamLicensedServiceOperations() now also registers the context
    (scoped, via TryAdd). The processor and the executor share one instance per
    request, even in a host that never called AddIBeamServicePolicies.

The design is unchanged from v2.12.2: a request-scoped exemption, not
Permission = false or a licence-free operation list. Annotating operations
would also exempt authenticated callers, and would need a new annotation every
time the webhook path grew.

Why it was not caught

The processor tests built their services by hand with the plain executor,
which does honour the scope. The composition production uses was never
exercised: same code, different container. Both halves of this fix are needed.
With only the context pass-through, the new tests still fail, this time on the
licence check.

Tests

  • New LicensedWebhookCompositionTests: builds the container the way a host
    does (billing, licensing, AddIBeamLicensedServiceOperations() and a
    denying authorizer) and runs a signed event end to end. All four cases fail
    on v2.12.2 with the production exception, and pass on v2.12.3.
  • Executor unit tests: inside and outside a system scope, plus an
    authenticated caller with no licence (still denied).
  • Full suite: 594 passed, 2 failed. The 2 failures are OAuth tests that
    already failed before this change (587 passed, same 2 failed).

Upgrade notes

  • Additive only. The new constructor parameter is optional and last, so
    existing direct construction of LicensedServiceOperationExecutor compiles
    and behaves as before.
  • Hosts on v2.12.2 that call AddIBeamLicensedServiceOperations():
    webhooks start succeeding with no code change beyond the package bump.
  • Remove any workaround that caught AccessControlException /
    UnauthorizedAccessException around webhook recording (Qurvia's QUR-0261
    catch in PaymentWebhookService). With this release, IBeam records provider
    events and runs its own paid-purchase handlers again. Verified against
    Qurvia with its workaround removed: webhook tests 7/7, including a signed
    commerce purchase reaching paid.
  • Hosts that don't use licensed service operations are unaffected.