Silent breaking change of how detect active license?

Hi,

When we started out with publish our app “build with Forge” back in June 2022, we carefully followed the nice documentation written by Atlassian on how to enable licensing, including the manifest and code to check the presence of an active license.

Now we’ve just been brought to attention that Atlassian announced in the Forge change log a breaking change on how to check the license.

@Atlassian - have I missed something or did you “announce” this just via the Forge changelog???

Ok, so here’s the “paper trail”:

  1. The “how to” as it was just a few months back (thanks Internet Archive): https://web.archive.org/web/20230605180347/https://developer.atlassian.com/platform/marketplace/listing-forge-apps/
  2. The “how to” as it reads today: https://developer.atlassian.com/platform/marketplace/listing-forge-apps/#checking-the-licence-status
  3. The change log entry about the old way being broken and fixed by introducing a breaking change: https://developer.atlassian.com/changelog/#CHANGE-1184

Quoting #3 here:

“FIXED” license property in context object now has correct active status property
The license object returned by view.getContext() in Custom UI previously had an isActive property. This property was always undefined regardless of whether the app had a valid license or not.

This is now fixed with the introduction of a new active property. license.active will be true for valid installations and false otherwise. More details on how to check for the license status can be found here.

EDIT: Had to change the bold FIXED to a quoted “FIXED”. In reality the ‘FIX’ breaks things…

Kind regards,
Fredrik

5 Likes

FYI this change break our Forge app in production last week :angry:

We were using isActive and we have to debug urgently why our app was broken and do a new release with active.
Now @freatt is saying on Slack that he is seeing both values in production :angry: :angry:
We might have to re-do a release quickly to support both property for a while.
I am really piss of from the lack of professionalism from Atlassian on this type of change.

This is a clear API change from Atlassian being rollout without notice.
Others apps will/are broken because of this :

https://jira.atlassian.com/browse/ECO-70
https://jira.atlassian.com/browse/ECO-73

@Dave (I hope this is the right user) Can we have a precise info about this change ? Is it a progressive rollout, and we have to support both properties in the meantime ? Why no proper announcement ? Why the ECO tickets have not being transformed into FRGE tickets (we are not monitoring ECO board for Forge bug, only FRGE one) ?

3 Likes

@freatt,

I’m just catching up on the issue as a whole so I don’t know where things have gone wrong. I’ll try pursuing @SilvreLestang point that the problem has already been reported.

@SilvreLestang,

If I understand your point correctly, the problems were reported already but they haven’t made their way to the right team. Hopefully, “connecting the dots” will get this resolved quickly.

So can you confirm, that the solution from the docs in the reslover still works correctly?

  if (context.license.active !== true) {
    console.log("App is not licensed");
    return;
  }

In my resolver code I see this

    let isLicenseValid = context && context.license && context.license.isActive;

And I haven’t deployed for some time now.
So you say when I deploy, it will be broken, and I need to fix context.license.isActive to context.license.active?

Atlassian: Where is the changelog for this change?

Thanks,
Bernhard

@clouless,

I’m still trying to understand the problem but I think this is the changelog entry:

1 Like

By the way, the statement in that changelog entry:

The license object returned by view.getContext() in Custom UI previously had an isActive property. This property was always undefined regardless of whether the app had a valid license or not.

Is definitely NOT TRUE for Forge jira apps.

2 Likes

Hi Jeff, can you explain what the current situation is for you, thanks.

I really struggle with situations like these, where you can only test stuff in production.
There should be a way to test real license states on staging too.

I only check the license in my resolver and pass that to the frontend, so I do not use view.getContext() right now.

But the active <-> isActive silent breaking change is really something …
I am really afraid to deploy now and might implement something like:

    let isLicenseValid = context && context.license && 
        ( context.license.isActive === true || context.license.active === true);

:man_facepalming: :face_exhaling:

3 Likes

@clouless @jeffryan @SilvreLestang @freatt (or anyone also suffering from this problem),

Could you please open an incident on the developer support portal and post back here?

2 Likes

Hi Ian,
Ok I have opened ECOHELP-29688 for my app. I am looking forward to any advice on what to do best in my situation :slight_smile:

Hi Team,

We understand this is confusing, and so I’m writing an update to try and clarify all the positions about Forge and licences.

In summary, we updated Custom UI to include licence.active. However, we updated some Custom UI documentation just before the code rolled out, and incorrectly updated some documentation for UI Kit 1 to licence.active around the same time, most of which we’ve now corrected.

In UI Kit 1, you can check a licence by confirming if license.isActive is true. This is from the useProductContext() from @forge/ui documented in UI kit hooks. This was documented incorrectly in the original CHANGELOG entry was fixed in ECO-73: Using “active” instead of “isActive” to perform a license check on Forge UI Kit 1 applications fails .

In UI Kit 2 and Custom UI, you can check a licence in the front end by confirming if license.active is true. This is via the getContext() method from @forge/bridge and documented in Custom UI view. Previously it was documented as isActive and did not work at all. This was fixed in ECO-70 - License type object returned by view.getContext() in @forge/bridge does not have the new structure.

In the back-end, documented in Custom UI resolver, you can check a licence by using the @forge/resolver package and the define() function with context.accountType being one of

  • 'licensed'
  • 'unlicensed'
  • 'customer'
  • 'anonymous'

Where is gets confusing is the remaining documentation. Specifically, in 2 places.

In List an Atlassian Forge app’s Checking the licence status section, it mentions using UI Kit 1, but the example is actually for Custom UI. We’re going to fix this.

In Forge changelog CHANGE-1184 states

The license object returned by view.getContext() in Custom UI previously had an isActive property. This property was always undefined regardless of whether the app had a valid license or not.

This is now fixed with the introduction of a new active property. license.active will be true for valid installations and false otherwise. More details on how to check for the license status can be found here.

Is almost correct. Although some reports have indicated that this was not undefined previously, we can’t confirm that, because our review shows that the license object never had isActive.

I really hope this clears things up for everyone.

Regards,
James.

As clear as mud. Developers will need a method to test the real license object instead of the current Forge method of faking the data. Since we can’t trust the docs, this will be the only way to resolve things without snowballing the confusion.

4 Likes

Raised this ticket ECOHELP-29700

Thanks,
Fredrik

Same here. Using context.isActive in the resolver. App deployed last in 24th of August.
Also wishing for testability of licenses in staging.

Second wish:
@jrichards : Can you please outline the license states exactly, thanks:

  • 'licensed' => ok this one is clear
  • 'unlicensed' => ok this one is clear
  • 'customer' => what does that mean? is this in Jira Service Management, when a customer user visits the portal?
  • 'anonymous' => is this in Jira Service Management, when an anonymous user visits the portal?

So the check should be (to get all the use cases):

const licenseIsActive = context && context.accountType && (context.accountType === 'licensed' || context.accountType === 'customer' || context.accountType === 'anonymous')

1 Like

@ibuchanan our app is not experiencing difficulties that I am aware of. We are checking license.isActive in our server side custom UI and valueOf resolver functions. It seems to still be working so I don’t know if we’re just lucky or if it’s an alternate path.

1 Like

Yeah I agree with you @clouless that there should be a better testability story here. We did a fair amount of work to mock the license object and we turn that mock on or off via a feature flag so that we could test our running app behavior when the license expires or is re-enabled. There should be better tools than this because you’re never quite sure what atlassian will return in the license object until you see it for the first time in production. We had a number of conversations with them before hand about ‘what exactly is in the license object’…

4 Likes

Most definitely license.isActive DOES EXIST and IS USED by JMCF in server side resolver functions for both CUI invoke and custom field type ValueOf functions.

This kind of API and doc change has potential for a huge negative impact on customers and partners and it needs to be taken with much more care than has been shown in this instance.

Clearly there is a consistency issue going on here… and yes it should be addressed but it must be done in a way that does not break existing partner applications. If you are going to consolidate on one way of checking the license (which I support) then thats fine but partners need time to adjust their application so a proper notification and deprecation needs to occur.

6 Likes

Hi @clouless,

customer is a JSM customer who is using the customer portal. They may also have access to a Confluence Space for documentation via JSM. However, be aware they are not a paid user and so in some contexts they won’t have a licence object.

anonymous is a someone with no account at all. They haven’t logged in and have only the permission that are allowed as an anonymous user (hopefully just read access to Spaces and Projects). This is relevant for both Jira and Confluence.

James.

2 Likes

Hi James,
Thanks for outlining this. But from my perspective this is not a great architecture design choice.
Why is the state of the license dependent on which user accesses my app?

The Jira-admin has globally set a license and either it is active or not. This applies to all users of the instance.

Should the JSM thing, if the user is loggedin, anonymous or customer portal user be something completely unrelated to the license at all?

I think there should always be a global context.license object which always has an active Boolean.

I personally cannot understand why this got mixed up together.

Just my personal opinion :sweat_smile:

6 Likes

I agree @clouless. The app license status should not be affected by the user making the call. If we need to differentiate processing based on the type of user then shouldn’t that be based on their accountId and permissions?

4 Likes

Just to keep this thread alive. The engineer that answered my ECOHELP ticket told me to not do anything before they have checked internally what is going on.

Maybe the isActive might still be correct in the resolver and only the docs are incorrect.
But that is only a hunch of the engineer.

For now I will not deploy new features until this is clarified (and I am hoping I do not need to perform a bug fixing release in the meantime :smiling_face_with_tear:)

2 Likes