RFC-138: Move fields out of invocation context to address header size limits for Forge Remote and Forge Containers

I think this RFC tries to address two problems that are not directly related to each other:

  1. How to solve the header size limit
  2. How to improve the context contract, including the distinction between trusted/untrusted contexts

Generally, I share the concern highlighted above that the proposed solution is a band-aid solution.

Header size limit problem

Moving the context to the request body seems to be a reasonable, long-term solution. Removing untrusted context from the FIT seems to just defer the problem. I do not quite understand why this would solve it. How would Atlassian ensure that no single module fills it with excessively large trusted context data?

The biggest impact of this change is that the remote may no longer receive some of the context it previously did. Whether the Remote is reading the body or FIT context doesn’t make much of a difference.

I think it is totally reasonable for Atlassian to reserve some of the remote request body for its own use (with a clear contract! see below) to pass platform context to a Remote/Container app, rather than relying solely on headers.

Trusted/untrusted context distinction

This is a welcome change, but “trusted vs untrusted context” is part of a larger problem: a generally vague contract between Remotes/Functions and the Forge platform.

If Atlassian does not clearly know today which fields in the context are trusted, how are we supposed to build a secure Remote/Function?

From a developer’s perspective, context is a black box. For Atlassian teams, it appears to be a container to provide anything that may be required/useful for an invocation. There is no clear contract around it other than “an object of data”. Forge module context documentation is often wrong and/or incomplete.

Context is fragile and needs rethinking ([1], [2], [3]). I do not know what the platform implementation looks like, but here are just some ideas on how this may be improved:

  • Treat the boundary as an interface that needs to be specified the same way as Atlassian uses OpenAPI spec to define the contract for REST APIs.
  • Atlassian teams define the context shape for a module as a JSON schema and publish that with the module to a centralized location
  • Typescript types for each module’s context can be derived from the JSON schema.
  • Module context documentation can be generated from the published JSON schemas
  • Teams can mark trusted vs untrusted context directly in the JSON schema, maybe even with additional details.

I am aware that these suggestions go far beyond this RFC, but I think it’s a problem that is being ignored and needs to be addressed.

Focused RFC questions/feedback:

We currently use these fields in Remotes:

FIT context JSON source Forge module type(s) in our code path
context.extension.issue.id jira:issueContext
context.extension.project.id jira:issueContext, jira:projectSettingsPage
context.extension.request.key jiraServiceManagement:portalRequestDetailPanel
context.siteUrl core:trigger, jira:workflowPostFunction

I strongly believe the fix for this should be the same across all modules and invocations. Atlassian should work to unify the contract rather than fragment it further.