RFC-29: App Access Rule - Revised followup to New Data Access APIs

Hi @remie . Your nudge to reply is well timed - we obtained internal approval yesterday and are able to share our altered approach today. :smiley:

First however I would like to attend to some of your previous comments.

our feedback is dead on arrival

Iā€™m hearing that you feel our RFC process is disingenuous, which is unfortunate. We have taken a considerable amount of time to evaluate the feedback we have received, evidenced by the substantial shifts in how we have looked to deliver a solution that works for Partners. Not only is this so, in this RFC we have also sought to provide additional insight and reasoning into the various constraints we are having to consider. I can confidently assert that to claim RFC feedback is dead on arrival is not correct. :slightly_smiling_face:

Cloudevents

yet another fad

I can assure you Cloudevents is not a fad. It is a specification with broad industry participation and adoption, and an open PR to move it to CNCF graduated status alongside other not-fads such as envoy, istio, kubernetes and prometheus. I am not aware of any competing specifications for defining common event metadata and extensions (if you know of alternatives please let us know!), and a reason Cloudevents is part of CNCF is to demonstrate a multi-vendor commitment to its ongoing maintenance.

Atlassian does have a ā€œnot invented hereā€ problem

As you point out I have not been at Atlassian for a long time, so Iā€™m unable to comment on this sorry. However I do bring experience and an awareness of the need for unambiguous interoperability standards when operating public APIs at scale and with broad reach. One reason we have considered Cloudevents is with an eye towards future interoperability needs. Another is because it is simply good practice to define and use standard for message headers - a recent AWS architecture blog post about implementing Webhooks references Cloudevents as a best practice, the use of which ā€œprovides an industry standard format and common payload structureā€¦ā€.

So as we look to be a step ahead of future problems I hope you will agree our use of standard specifications is not reinventing solutions in-house.

look beyond your nice little project working with this Shiny New Thing

We have a lot of respect for our Partners and their needs, and we hope participants in the RFC process will afford us a similar level of respect, with consideration of the various concerns and constraints we are having to balance at our end. Let me assure you we are not treating App Access Rules as some sort of vanity project to advance peoplesā€™ careers. We select technologies and specifications for solutions based on whether they are fit for purpose, not for any personal promotion agenda.

Finally, let me restate that the only difference between cloudevents and not-cloudevents is the presence of two additional attributes in the event and a custom json media type, all of which you may ignore. Given you appear to agree there are no actual technical concerns with the use of Cloudevents I will draw a line under the Cloudevents aspect of the RFC. We have sought feedback and it has been received - thank you for your expression of Partnersā€™ desires for stability and consistency of our public APIs. We too appreciate these things. :slightly_smiling_face:


Now to the substantive matter of this replyā€¦

Web APIs

The additional details/use cases @remie and @danielwester and @lexek-92 recently provided have been very helpful, thank you all! One reason this reply is so delayed is because we have gone back and worked with Jira and Confluence to try and move our solution closer to what Partners have suggested.

Previously we proposed an architecture with a new centralised API, that necessarily uses ARIs in its contract;

Having taken on board feedback we instead propose the following;

In this architecture new API endpoints relevant to App Access Rules are provided directly from Jira and Confluence and the API shape is product-specific (i.e. determined by Jira and Confluence). The web API endpoints provided for apps running in an environment where App Access Rules could be in effect can now be summarised as follows.

Determine whether the app is subject to policy restrictions in a given installation context:

Jira

GET /rest/api/3/contentpolicy

{
    "anyContentBlocked": true
}

Confluence

GET /rest/api/3/contentpolicy

{
    "anyContentBlocked": true
}

Retrieve containers (Jira projects or Confluence spaces) and their associated content policy:

Jira

GET /rest/api/3/project/search?expand=contentpolicy

{
  "self": "https://your-domain.atlassian.net/rest/api/3/project/search?expand=contentpolicy&startAt=0&maxResults=2",
  "nextPage": "https://your-domain.atlassian.net/rest/api/3/project/search?expand=contentpolicy&startAt=2&maxResults=2",
  "maxResults": 2,
  "startAt": 0,
  "total": 7,
  "isLast": false,
  "values": [
    {
      "self": "https://your-domain.atlassian.net/rest/api/3/project/EX",
      "id": "10000",
      "key": "EX",
      "name": "Example",
      "contentpolicy": {
        "anyContentBlocked": true
      }
    },
    {
      "self": "https://your-domain.atlassian.net/rest/api/3/project/ABC",
      "id": "10001",
      "key": "ABC",
      "name": "Alphabetical",
      "contentpolicy": {
        "anyContentBlocked": false
      }
    }
  ]
}

Confluence

GET /rest/api/3/contentpolicy/space

{
  "results": [
    {
      "id": "string",
      "key": "string",
      "name": "string",
      "contentpolicy": {
        "anyContentBlocked": true
      }
      "_links": {
        "webui": "string"
      }
    }
  ],
  "_links": {
    "next": "string"
  }
}

Our understanding is that these changes will resolve the following concerns expressed by Partners;

  • Use of ARIs - these are no longer part of the API contract.
  • Use of GraphQL - the new API capabilities are provided via product RESTful APIs.
  • Performance - it is possible to retrieve in a single request both containers (i.e. Jira projects or Confluence spaces) and their associated content policy indicators, such as whether there is anyContentBlocked. While evaluating policy will always incur some compute overhead, we have removed the additional network hop.

OpenAPI contracts may be found in a separate reply - as to include them here causes the reply length to exceed limits.

Events

We are yet to confirm this (will take another day or two) but I would like to share already an event we propose to publish to help address the following use case;

in which app access is blocked after the user configured the project synchronisation, in which synchronisation will fail without any warning and we do not have any means to communicate this to the end-user

The proposed AppAccessToObjectsInContainerBlocked event will look similar to this:

{
  "specversion": "1.0",
  "type": "avi:ecosystem.app_policy:blocked:app_access_to_objects_in_container.v1",
  "source": "com.atlassian/ecosystem.app_policy",
  "id": "7a6796c0-746d-4504-92cd-819eca234306",
  "time": "2023-10-24T08:08:08Z",
  "data": {
    "site": { 
      "url": "https://site_name.atlassian.net"
    },
    "blockedContainer": "12345"
  }
}

The purpose of this event is to allow apps to

  1. Store a record that a configuration change has occurred (useful in customer support scenarios)
  2. Update app configuration in light of the fact that background processes such as synchronisation will have been affected.

Conclusion

This RFC (and related earlier RFCs) has taken much longer to resolve than we had hoped. We know there will be improvements we can make to the process and will be taking this into consideration for future RFCs.

As noted at the start of this long reply we really do take notice of what our Partners have to say, and are greatly appreciative of the engagement we have had in this RFC. We hope you agree that even a long RFC process is still better than our delivering a solution as a fait accompli!

Thank you again, and we look forward to seeing some of you at Atlas camp. :slight_smile:

4 Likes

Jira API contract details

Please note that while correct in principle and approved by products, these API contracts are still draft - the exact API contract will be finalised during implementation. Again, the nicest way to read these OpenAPI contracts is to use the Swagger Editor.

These contracts are taken from DAC and reduced to include only those paths and components affected by this RFC.

openapi: 3.0.1
info:
  title: The Jira Cloud platform REST API
  description: Jira Cloud platform REST API documentation
  termsOfService: http://atlassian.com/terms/
  contact:
    email: ecosystem@atlassian.com
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: 1001.0.0-SNAPSHOT
paths:
  /rest/api/3/contentpolicy:
    get:
      summary: Get content policy for the entire workspace
      description: |-
        Returns content policy for the entire workspace.
      operationId: getContentPolicy
      responses:
        '200':
          description: Returned if the request is successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContentPolicy'
        '400':
          description: Returned if the request is not valid.
        '401':
          description: Returned if the authentication credentials are incorrect or missing.
      deprecated: false
      security:
        - basicAuth: []
        - OAuth2:
            - read:jira-work
        - {}
      x-atlassian-oauth2-scopes:
        - state: Current
          scheme: OAuth2
          scopes:
            - read:jira-work
      x-atlassian-connect-scope: READ
  /rest/api/3/project/search:
    get:
      description: |-
        Returns a [paginated](#pagination) list of projects visible to the user.
      parameters:
        - name: startAt
          in: query
          description: The index of the first item to return in a page of results (page offset).
          schema:
            type: integer
            format: int64
            default: 0
        - name: maxResults
          in: query
          description: The maximum number of items to return per page.
          schema:
            type: integer
            format: int32
            default: 50
        - name: orderBy
          in: query
          description: |-
            [Order](#ordering) the results by a field.

             *  `category` Sorts by project category. A complete list of category IDs is found using [Get all project categories](#api-rest-api-3-projectCategory-get).
             *  `issueCount` Sorts by the total number of issues in each project.
             *  `key` Sorts by project key.
             *  `lastIssueUpdatedTime` Sorts by the last issue update time.
             *  `name` Sorts by project name.
             *  `owner` Sorts by project lead.
             *  `archivedDate` EXPERIMENTAL. Sorts by project archived date.
             *  `deletedDate` EXPERIMENTAL. Sorts by project deleted date.
          schema:
            type: string
            default: key
            enum:
              - category
              - '-category'
              - +category
              - key
              - '-key'
              - +key
              - name
              - '-name'
              - +name
              - owner
              - '-owner'
              - +owner
              - issueCount
              - '-issueCount'
              - +issueCount
              - lastIssueUpdatedDate
              - '-lastIssueUpdatedDate'
              - +lastIssueUpdatedDate
              - archivedDate
              - +archivedDate
              - '-archivedDate'
              - deletedDate
              - +deletedDate
              - '-deletedDate'
        - name: id
          in: query
          description: The project IDs to filter the results by. To include multiple IDs, provide an ampersand-separated list. For example, `id=10000&id=10001`. Up to 50 project IDs can be provided.
          schema:
            uniqueItems: true
            type: array
            items:
              type: integer
              format: int64
        - name: keys
          in: query
          description: The project keys to filter the results by. To include multiple keys, provide an ampersand-separated list. For example, `keys=PA&keys=PB`. Up to 50 project keys can be provided.
          schema:
            uniqueItems: true
            type: array
            items:
              type: string
        - name: query
          in: query
          description: Filter the results using a literal string. Projects with a matching `key` or `name` are returned (case insensitive).
          schema:
            type: string
        - name: typeKey
          in: query
          description: Orders results by the [project type](https://confluence.atlassian.com/x/GwiiLQ#Jiraapplicationsoverview-Productfeaturesandprojecttypes). This parameter accepts a comma-separated list. Valid values are `business`, `service_desk`, and `software`.
          schema:
            type: string
        - name: categoryId
          in: query
          description: The ID of the project's category. A complete list of category IDs is found using the [Get all project categories](#api-rest-api-3-projectCategory-get) operation.
          schema:
            type: integer
            format: int64
        - name: action
          in: query
          description: |-
            Filter results by projects for which the user can:

             *  `view` the project, meaning that they have one of the following permissions:
                
                 *  *Browse projects* [project permission](https://confluence.atlassian.com/x/yodKLg) for the project.
                 *  *Administer projects* [project permission](https://confluence.atlassian.com/x/yodKLg) for the project.
                 *  *Administer Jira* [global permission](https://confluence.atlassian.com/x/x4dKLg).
             *  `browse` the project, meaning that they have the *Browse projects* [project permission](https://confluence.atlassian.com/x/yodKLg) for the project.
             *  `edit` the project, meaning that they have one of the following permissions:
                
                 *  *Administer projects* [project permission](https://confluence.atlassian.com/x/yodKLg) for the project.
                 *  *Administer Jira* [global permission](https://confluence.atlassian.com/x/x4dKLg).
             *  `create` the project, meaning that they have the *Create issues* [project permission](https://confluence.atlassian.com/x/yodKLg) for the project in which the issue is created.
          schema:
            type: string
            default: view
            enum:
              - view
              - browse
              - edit
              - create
        - name: expand
          in: query
          description: |-
            Use [expand](#expansion) to include additional information in the response. This parameter accepts a comma-separated list. Expanded options include:

             *  `description` Returns the project description.
             *  `projectKeys` Returns all project keys associated with a project.
             *  `lead` Returns information about the project lead.
             *  `issueTypes` Returns all issue types associated with the project.
             *  `url` Returns the URL associated with the project.
             *  `insight` EXPERIMENTAL. Returns the insight details of total issue count and last issue update time for the project.
             *  `contentpolicy` EXPERIMENTAL. Returns content policy associated with the project.
          schema:
            type: string
        - name: status
          in: query
          description: |-
            EXPERIMENTAL. Filter results by project status:

             *  `live` Search live projects.
             *  `archived` Search archived projects.
             *  `deleted` Search deleted projects, those in the recycle bin.
          schema:
            type: array
            items:
              type: string
              default: live
              enum:
                - live
                - archived
                - deleted
        - name: properties
          in: query
          description: EXPERIMENTAL. A list of project properties to return for the project. This parameter accepts a comma-separated list.
          schema:
            type: array
            items:
              $ref: '#/components/schemas/StringList'
        - name: propertyQuery
          in: query
          description: EXPERIMENTAL. A query string used to search properties. The query string cannot be specified using a JSON object. For example, to search for the value of `nested` from `{"something":{"nested":1,"other":2}}` use `[thepropertykey].something.nested=1`. Note that the propertyQuery key is enclosed in square brackets to enable searching where the propertyQuery key includes dot (.) or equals (=) characters. Note that `thepropertykey` is only returned when included in `properties`.
          schema:
            type: string
      responses:
        '200':
          description: Returned if the request is successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PageBeanProject'
        '400':
          description: Returned if the request is not valid.
        '401':
          description: Returned if the authentication credentials are incorrect or missing.
        '404':
          description: Returned if no projects matching the search criteria are found.
      deprecated: false
      security:
        - basicAuth: []
        - OAuth2:
            - read:jira-work
        - {}
      x-atlassian-oauth2-scopes:
        - state: Current
          scheme: OAuth2
          scopes:
            - read:jira-work
        - state: Beta
          scheme: OAuth2
          scopes:
            - read:issue-type:jira
            - read:project:jira
            - read:project.property:jira
            - read:user:jira
            - read:application-role:jira
            - read:avatar:jira
            - read:group:jira
            - read:issue-type-hierarchy:jira
            - read:project-category:jira
            - read:project-version:jira
            - read:project.component:jira
      x-atlassian-connect-scope: READ
components:
  schemas:
    ContentPolicy:
      type: object
      properties:
        anyContentBlocked:
          type: boolean
          description: Whether the workspace contains any content blocked for (inaccessible to) the requesting client application.
          readOnly: true
      additionalProperties: false
      description: Details about content policy.
      xml:
        name: contentpolicy
    Project:
      type: object
      properties:
        contentpolicy:
          type: object
          properties:
            anyContentBlocked:
              type: boolean
              description: Whether the project contains *any* content blocked for the requesting client application.
              readOnly: true
        archived:
          type: boolean
          description: Whether the project is archived.
          readOnly: true
        archivedBy:
          description: The user who archived the project.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/User'
        archivedDate:
          type: string
          description: The date when the project was archived.
          format: date-time
          readOnly: true
        assigneeType:
          type: string
          description: The default assignee when creating issues for this project.
          readOnly: true
          enum:
            - PROJECT_LEAD
            - UNASSIGNED
        avatarUrls:
          description: The URLs of the project's avatars.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/AvatarUrlsBean'
        components:
          type: array
          description: List of the components contained in the project.
          readOnly: true
          items:
            $ref: '#/components/schemas/ProjectComponent'
        deleted:
          type: boolean
          description: Whether the project is marked as deleted.
          readOnly: true
        deletedBy:
          description: The user who marked the project as deleted.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/User'
        deletedDate:
          type: string
          description: The date when the project was marked as deleted.
          format: date-time
          readOnly: true
        description:
          type: string
          description: A brief description of the project.
          readOnly: true
        email:
          type: string
          description: An email address associated with the project.
        expand:
          type: string
          description: Expand options that include additional project details in the response.
          readOnly: true
          xml:
            attribute: true
        favourite:
          type: boolean
          description: Whether the project is selected as a favorite.
        id:
          type: string
          description: The ID of the project.
        insight:
          description: Insights about the project.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/ProjectInsight'
        isPrivate:
          type: boolean
          description: Whether the project is private from the user's perspective. This means the user can't see the project or any associated issues.
          readOnly: true
        issueTypeHierarchy:
          description: The issue type hierarchy for the project.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/Hierarchy'
        issueTypes:
          type: array
          description: List of the issue types available in the project.
          readOnly: true
          items:
            $ref: '#/components/schemas/IssueTypeDetails'
        key:
          type: string
          description: The key of the project.
          readOnly: true
        landingPageInfo:
          description: The project landing page info.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/ProjectLandingPageInfo'
        lead:
          description: The username of the project lead.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/User'
        name:
          type: string
          description: The name of the project.
          readOnly: true
        permissions:
          description: User permissions on the project
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/ProjectPermissions'
        projectCategory:
          description: The category the project belongs to.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/ProjectCategory'
        projectTypeKey:
          type: string
          description: The [project type](https://confluence.atlassian.com/x/GwiiLQ#Jiraapplicationsoverview-Productfeaturesandprojecttypes) of the project.
          readOnly: true
          enum:
            - software
            - service_desk
            - business
        properties:
          type: object
          additionalProperties:
            readOnly: true
          description: Map of project properties
          readOnly: true
        retentionTillDate:
          type: string
          description: The date when the project is deleted permanently.
          format: date-time
          readOnly: true
        roles:
          type: object
          additionalProperties:
            type: string
            format: uri
            readOnly: true
          description: The name and self URL for each role defined in the project. For more information, see [Create project role](#api-rest-api-3-role-post).
          readOnly: true
        self:
          type: string
          description: The URL of the project details.
          format: uri
          readOnly: true
        simplified:
          type: boolean
          description: Whether the project is simplified.
          readOnly: true
        style:
          type: string
          description: The type of the project.
          readOnly: true
          enum:
            - classic
            - next-gen
        url:
          type: string
          description: A link to information about this project, such as project documentation.
          readOnly: true
        uuid:
          type: string
          description: Unique ID for next-gen projects.
          format: uuid
          readOnly: true
        versions:
          type: array
          description: The versions defined in the project. For more information, see [Create version](#api-rest-api-3-version-post).
          readOnly: true
          items:
            $ref: '#/components/schemas/Version'
      additionalProperties: false
      description: Details about a project.
      xml:
        name: project
    PageBeanProject:
      type: object
      properties:
        isLast:
          type: boolean
          description: Whether this is the last page.
          readOnly: true
        maxResults:
          type: integer
          description: The maximum number of items that could be returned.
          format: int32
          readOnly: true
        nextPage:
          type: string
          description: If there is another page of results, the URL of the next page.
          format: uri
          readOnly: true
        self:
          type: string
          description: The URL of the page.
          format: uri
          readOnly: true
        startAt:
          type: integer
          description: The index of the first item returned.
          format: int64
          readOnly: true
        total:
          type: integer
          description: The number of items returned.
          format: int64
          readOnly: true
        values:
          type: array
          description: The list of items.
          readOnly: true
          items:
            $ref: '#/components/schemas/Project'
      additionalProperties: false
      description: A page of items.
    Hierarchy:
      type: object
      properties:
        baseLevelId:
          type: integer
          description: 'The ID of the base level. This property is deprecated, see [Change notice: Removing hierarchy level IDs from next-gen APIs](https://developer.atlassian.com/cloud/jira/platform/change-notice-removing-hierarchy-level-ids-from-next-gen-apis/).'
          format: int64
        levels:
          type: array
          description: Details about the hierarchy level.
          readOnly: true
          items:
            $ref: '#/components/schemas/SimplifiedHierarchyLevel'
      additionalProperties: false
      description: The project issue type hierarchy.
      xml:
        name: hierarchy
    StringList:
      type: object
      additionalProperties: false
    SimplifiedHierarchyLevel:
      type: object
      properties:
        aboveLevelId:
          type: integer
          description: 'The ID of the level above this one in the hierarchy. This property is deprecated, see [Change notice: Removing hierarchy level IDs from next-gen APIs](https://developer.atlassian.com/cloud/jira/platform/change-notice-removing-hierarchy-level-ids-from-next-gen-apis/).'
          format: int64
        belowLevelId:
          type: integer
          description: 'The ID of the level below this one in the hierarchy. This property is deprecated, see [Change notice: Removing hierarchy level IDs from next-gen APIs](https://developer.atlassian.com/cloud/jira/platform/change-notice-removing-hierarchy-level-ids-from-next-gen-apis/).'
          format: int64
        externalUuid:
          type: string
          description: 'The external UUID of the hierarchy level. This property is deprecated, see [Change notice: Removing hierarchy level IDs from next-gen APIs](https://developer.atlassian.com/cloud/jira/platform/change-notice-removing-hierarchy-level-ids-from-next-gen-apis/).'
          format: uuid
        hierarchyLevelNumber:
          type: integer
          format: int32
        id:
          type: integer
          description: 'The ID of the hierarchy level. This property is deprecated, see [Change notice: Removing hierarchy level IDs from next-gen APIs](https://developer.atlassian.com/cloud/jira/platform/change-notice-removing-hierarchy-level-ids-from-next-gen-apis/).'
          format: int64
        issueTypeIds:
          type: array
          description: The issue types available in this hierarchy level.
          items:
            type: integer
            format: int64
        level:
          type: integer
          description: The level of this item in the hierarchy.
          format: int32
        name:
          type: string
          description: The name of this hierarchy level.
        projectConfigurationId:
          type: integer
          description: 'The ID of the project configuration. This property is deprecated, see [Change oticen: Removing hierarchy level IDs from next-gen APIs](https://developer.atlassian.com/cloud/jira/platform/change-notice-removing-hierarchy-level-ids-from-next-gen-apis/).'
          format: int64
      additionalProperties: false
    Version:
      type: object
      properties:
        approvers:
          type: array
          description: If the expand option `approvers` is used, returns a list containing the approvers for this version.
          readOnly: true
          items:
            $ref: '#/components/schemas/VersionApprover'
        archived:
          type: boolean
          description: Indicates that the version is archived. Optional when creating or updating a version.
        description:
          type: string
          description: The description of the version. Optional when creating or updating a version. The maximum size is 16,384 bytes.
        driver:
          type: string
          description: If the expand option `driver` is used, returns the Atlassian account ID of the driver.
          readOnly: true
        expand:
          type: string
          description: |-
            Use [expand](em>#expansion) to include additional information about version in the response. This parameter accepts a comma-separated list. Expand options include:

             *  `operations` Returns the list of operations available for this version.
             *  `issuesstatus` Returns the count of issues in this version for each of the status categories *to do*, *in progress*, *done*, and *unmapped*. The *unmapped* property contains a count of issues with a status other than *to do*, *in progress*, and *done*.
             *  `driver` Returns the Atlassian account ID of the version driver.
             *  `approvers` Returns a list containing approvers for this version.

            Optional for create and update.
          xml:
            attribute: true
        id:
          type: string
          description: The ID of the version.
          readOnly: true
        issuesStatusForFixVersion:
          description: If the expand option `issuesstatus` is used, returns the count of issues in this version for each of the status categories *to do*, *in progress*, *done*, and *unmapped*. The *unmapped* property contains a count of issues with a status other than *to do*, *in progress*, and *done*.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/VersionIssuesStatus'
        moveUnfixedIssuesTo:
          type: string
          description: The URL of the self link to the version to which all unfixed issues are moved when a version is released. Not applicable when creating a version. Optional when updating a version.
          format: uri
        name:
          type: string
          description: The unique name of the version. Required when creating a version. Optional when updating a version. The maximum length is 255 characters.
        operations:
          type: array
          description: If the expand option `operations` is used, returns the list of operations available for this version.
          readOnly: true
          items:
            $ref: '#/components/schemas/SimpleLink'
        overdue:
          type: boolean
          description: Indicates that the version is overdue.
          readOnly: true
        project:
          type: string
          description: Deprecated. Use `projectId`.
        projectId:
          type: integer
          description: The ID of the project to which this version is attached. Required when creating a version. Not applicable when updating a version.
          format: int64
        releaseDate:
          type: string
          description: The release date of the version. Expressed in ISO 8601 format (yyyy-mm-dd). Optional when creating or updating a version.
          format: date
        released:
          type: boolean
          description: Indicates that the version is released. If the version is released a request to release again is ignored. Not applicable when creating a version. Optional when updating a version.
        self:
          type: string
          description: The URL of the version.
          format: uri
          readOnly: true
        startDate:
          type: string
          description: The start date of the version. Expressed in ISO 8601 format (yyyy-mm-dd). Optional when creating or updating a version.
          format: date
        userReleaseDate:
          type: string
          description: The date on which work on this version is expected to finish, expressed in the instance's *Day/Month/Year Format* date format.
          readOnly: true
        userStartDate:
          type: string
          description: The date on which work on this version is expected to start, expressed in the instance's *Day/Month/Year Format* date format.
          readOnly: true
      additionalProperties: false
      description: Details about a project version.
      xml:
        name: version
    VersionIssuesStatus:
      type: object
      properties:
        done:
          type: integer
          description: Count of issues with status *done*.
          format: int64
          readOnly: true
        inProgress:
          type: integer
          description: Count of issues with status *in progress*.
          format: int64
          readOnly: true
        toDo:
          type: integer
          description: Count of issues with status *to do*.
          format: int64
          readOnly: true
        unmapped:
          type: integer
          description: Count of issues with a status other than *to do*, *in progress*, and *done*.
          format: int64
          readOnly: true
      additionalProperties: true
      description: Counts of the number of issues in various statuses.
    SimpleLink:
      type: object
      properties:
        href:
          type: string
        iconClass:
          type: string
        id:
          type: string
        label:
          type: string
        styleClass:
          type: string
        title:
          type: string
        weight:
          type: integer
          format: int32
      additionalProperties: false
      description: Details about the operations available in this version.
      xml:
        name: link
    VersionApprover:
      type: object
      properties:
        accountId:
          type: string
          description: The Atlassian account ID of the approver.
          readOnly: true
        declineReason:
          type: string
          description: A description of why the user is declining the approval.
          readOnly: true
        description:
          type: string
          description: A description of what the user is approving within the specified version.
          readOnly: true
        status:
          type: string
          description: The status of the approval, which can be *PENDING*, *APPROVED*, or *DECLINED*
          readOnly: true
      additionalProperties: true
      description: Contains details about a version approver.
    User:
      type: object
      properties:
        accountId:
          maxLength: 128
          type: string
          description: The account ID of the user, which uniquely identifies the user across all Atlassian products. For example, *5b10ac8d82e05b22cc7d4ef5*. Required in requests.
        accountType:
          type: string
          description: |-
            The user account type. Can take the following values:

             *  `atlassian` regular Atlassian user account
             *  `app` system account used for Connect applications and OAuth to represent external systems
             *  `customer` Jira Service Desk account representing an external service desk
          readOnly: true
          enum:
            - atlassian
            - app
            - customer
            - unknown
        active:
          type: boolean
          description: Whether the user is active.
          readOnly: true
        applicationRoles:
          description: The application roles the user is assigned to.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/SimpleListWrapperApplicationRole'
        avatarUrls:
          description: The avatars of the user.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/AvatarUrlsBean'
        displayName:
          type: string
          description: The display name of the user. Depending on the userā€™s privacy setting, this may return an alternative value.
          readOnly: true
        emailAddress:
          type: string
          description: The email address of the user. Depending on the userā€™s privacy setting, this may be returned as null.
          readOnly: true
        expand:
          type: string
          description: Expand options that include additional user details in the response.
          readOnly: true
          xml:
            attribute: true
        groups:
          description: The groups that the user belongs to.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/SimpleListWrapperGroupName'
        key:
          type: string
          description: This property is no longer available and will be removed from the documentation soon. See the [deprecation notice](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-user-privacy-api-migration-guide/) for details.
        locale:
          type: string
          description: The locale of the user. Depending on the userā€™s privacy setting, this may be returned as null.
          readOnly: true
        name:
          type: string
          description: This property is no longer available and will be removed from the documentation soon. See the [deprecation notice](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-user-privacy-api-migration-guide/) for details.
        self:
          type: string
          description: The URL of the user.
          format: uri
          readOnly: true
        timeZone:
          type: string
          description: The time zone specified in the user's profile. Depending on the userā€™s privacy setting, this may be returned as null.
          readOnly: true
      additionalProperties: false
      description: |-
        A user with details as permitted by the user's Atlassian Account privacy settings. However, be aware of these exceptions:

         *  User record deleted from Atlassian: This occurs as the result of a right to be forgotten request. In this case, `displayName` provides an indication and other parameters have default values or are blank (for example, email is blank).
         *  User record corrupted: This occurs as a results of events such as a server import and can only happen to deleted users. In this case, `accountId` returns *unknown* and all other parameters have fallback values.
         *  User record unavailable: This usually occurs due to an internal service outage. In this case, all parameters have fallback values.
      xml:
        name: user
    SimpleListWrapperApplicationRole:
      type: object
      properties:
        callback:
          $ref: '#/components/schemas/ListWrapperCallbackApplicationRole'
        items:
          type: array
          items:
            $ref: '#/components/schemas/ApplicationRole'
        max-results:
          type: integer
          format: int32
          xml:
            name: max-results
            attribute: true
        pagingCallback:
          $ref: '#/components/schemas/ListWrapperCallbackApplicationRole'
        size:
          type: integer
          format: int32
          xml:
            attribute: true
      additionalProperties: false
      xml:
        name: list
    SimpleListWrapperGroupName:
      type: object
      properties:
        callback:
          $ref: '#/components/schemas/ListWrapperCallbackGroupName'
        items:
          type: array
          items:
            $ref: '#/components/schemas/GroupName'
        max-results:
          type: integer
          format: int32
          xml:
            name: max-results
            attribute: true
        pagingCallback:
          $ref: '#/components/schemas/ListWrapperCallbackGroupName'
        size:
          type: integer
          format: int32
          xml:
            attribute: true
      additionalProperties: false
      xml:
        name: list
    ApplicationRole:
      type: object
      properties:
        defaultGroups:
          uniqueItems: true
          type: array
          description: The groups that are granted default access for this application role. As a group's name can change, use of `defaultGroupsDetails` is recommended to identify a groups.
          items:
            type: string
        defaultGroupsDetails:
          type: array
          description: The groups that are granted default access for this application role.
          items:
            $ref: '#/components/schemas/GroupName'
        defined:
          type: boolean
          description: Deprecated.
        groupDetails:
          type: array
          description: The groups associated with the application role.
          items:
            $ref: '#/components/schemas/GroupName'
        groups:
          uniqueItems: true
          type: array
          description: The groups associated with the application role. As a group's name can change, use of `groupDetails` is recommended to identify a groups.
          items:
            type: string
        hasUnlimitedSeats:
          type: boolean
        key:
          type: string
          description: The key of the application role.
        name:
          type: string
          description: The display name of the application role.
        numberOfSeats:
          type: integer
          description: The maximum count of users on your license.
          format: int32
        platform:
          type: boolean
          description: Indicates if the application role belongs to Jira platform (`jira-core`).
        remainingSeats:
          type: integer
          description: The count of users remaining on your license.
          format: int32
        selectedByDefault:
          type: boolean
          description: Determines whether this application role should be selected by default on user creation.
        userCount:
          type: integer
          description: The number of users counting against your license.
          format: int32
        userCountDescription:
          type: string
          description: The [type of users](https://confluence.atlassian.com/x/lRW3Ng) being counted against your license.
      additionalProperties: false
      description: Details of an application role.
    GroupName:
      type: object
      properties:
        groupId:
          type: string
          description: The ID of the group, which uniquely identifies the group across all Atlassian products. For example, *952d12c3-5b5b-4d04-bb32-44d383afc4b2*.
          nullable: true
        name:
          type: string
          description: The name of group.
        self:
          type: string
          description: The URL for these group details.
          format: uri
          readOnly: true
      additionalProperties: false
      description: Details about a group.
    ListWrapperCallbackGroupName:
      type: object
      additionalProperties: false
    ListWrapperCallbackApplicationRole:
      type: object
      additionalProperties: false
    AvatarUrlsBean:
      type: object
      properties:
        16x16:
          type: string
          description: The URL of the item's 16x16 pixel avatar.
          format: uri
        24x24:
          type: string
          description: The URL of the item's 24x24 pixel avatar.
          format: uri
        32x32:
          type: string
          description: The URL of the item's 32x32 pixel avatar.
          format: uri
        48x48:
          type: string
          description: The URL of the item's 48x48 pixel avatar.
          format: uri
      additionalProperties: false
    ProjectCategory:
      type: object
      properties:
        description:
          type: string
          description: The description of the project category.
        id:
          type: string
          description: The ID of the project category.
          readOnly: true
        name:
          type: string
          description: The name of the project category. Required on create, optional on update.
        self:
          type: string
          description: The URL of the project category.
          format: uri
          readOnly: true
      additionalProperties: false
      description: A project category.
    ProjectPermissions:
      type: object
      properties:
        canEdit:
          type: boolean
          description: Whether the logged user can edit the project.
          readOnly: true
      additionalProperties: false
      description: Permissions which a user has on a project.
    ProjectInsight:
      type: object
      properties:
        lastIssueUpdateTime:
          type: string
          description: The last issue update time.
          format: date-time
          readOnly: true
        totalIssueCount:
          type: integer
          description: Total issue count.
          format: int64
          readOnly: true
      additionalProperties: false
      description: Additional details about a project.
    ProjectLandingPageInfo:
      type: object
      properties:
        attributes:
          type: object
          additionalProperties:
            type: string
        boardId:
          type: integer
          format: int64
        boardName:
          type: string
        projectKey:
          type: string
        projectType:
          type: string
        queueCategory:
          type: string
        queueId:
          type: integer
          format: int64
        queueName:
          type: string
        simpleBoard:
          type: boolean
        simplified:
          type: boolean
        url:
          type: string
      additionalProperties: false
    IssueTypeDetails:
      type: object
      properties:
        avatarId:
          type: integer
          description: The ID of the issue type's avatar.
          format: int64
          readOnly: true
        description:
          type: string
          description: The description of the issue type.
          readOnly: true
        entityId:
          type: string
          description: Unique ID for next-gen projects.
          format: uuid
          readOnly: true
        hierarchyLevel:
          type: integer
          description: Hierarchy level of the issue type.
          format: int32
          readOnly: true
        iconUrl:
          type: string
          description: The URL of the issue type's avatar.
          readOnly: true
        id:
          type: string
          description: The ID of the issue type.
          readOnly: true
        name:
          type: string
          description: The name of the issue type.
          readOnly: true
        scope:
          description: Details of the next-gen projects the issue type is available in.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/Scope'
        self:
          type: string
          description: The URL of these issue type details.
          readOnly: true
        subtask:
          type: boolean
          description: Whether this issue type is used to create subtasks.
          readOnly: true
      additionalProperties: false
      description: Details about an issue type.
    Scope:
      type: object
      properties:
        project:
          description: The project the item has scope in.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/ProjectDetails'
        type:
          type: string
          description: The type of scope.
          readOnly: true
          enum:
            - PROJECT
            - TEMPLATE
      additionalProperties: true
      description: The projects the item is associated with. Indicated for items associated with [next-gen projects](https://confluence.atlassian.com/x/loMyO).
    ProjectDetails:
      type: object
      properties:
        avatarUrls:
          description: The URLs of the project's avatars.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/AvatarUrlsBean'
        id:
          type: string
          description: The ID of the project.
        key:
          type: string
          description: The key of the project.
          readOnly: true
        name:
          type: string
          description: The name of the project.
          readOnly: true
        projectCategory:
          description: The category the project belongs to.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/UpdatedProjectCategory'
        projectTypeKey:
          type: string
          description: The [project type](https://confluence.atlassian.com/x/GwiiLQ#Jiraapplicationsoverview-Productfeaturesandprojecttypes) of the project.
          readOnly: true
          enum:
            - software
            - service_desk
            - business
        self:
          type: string
          description: The URL of the project details.
          readOnly: true
        simplified:
          type: boolean
          description: Whether or not the project is simplified.
          readOnly: true
      additionalProperties: false
      description: Details about a project.
    UpdatedProjectCategory:
      type: object
      properties:
        description:
          type: string
          description: The name of the project category.
          readOnly: true
        id:
          type: string
          description: The ID of the project category.
          readOnly: true
        name:
          type: string
          description: The description of the project category.
          readOnly: true
        self:
          type: string
          description: The URL of the project category.
          readOnly: true
      additionalProperties: false
      description: A project category.
    ProjectComponent:
      type: object
      properties:
        ari:
          type: string
          description: Compass component's ID. Can't be updated. Not required for creating a Project Component.
          readOnly: true
        assignee:
          description: The details of the user associated with `assigneeType`, if any. See `realAssignee` for details of the user assigned to issues created with this component.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/User'
        assigneeType:
          type: string
          description: |-
            The nominal user type used to determine the assignee for issues created with this component. See `realAssigneeType` for details on how the type of the user, and hence the user, assigned to issues is determined. Can take the following values:

             *  `PROJECT_LEAD` the assignee to any issues created with this component is nominally the lead for the project the component is in.
             *  `COMPONENT_LEAD` the assignee to any issues created with this component is nominally the lead for the component.
             *  `UNASSIGNED` an assignee is not set for issues created with this component.
             *  `PROJECT_DEFAULT` the assignee to any issues created with this component is nominally the default assignee for the project that the component is in.

            Default value: `PROJECT_DEFAULT`.  
            Optional when creating or updating a component.
          enum:
            - PROJECT_DEFAULT
            - COMPONENT_LEAD
            - PROJECT_LEAD
            - UNASSIGNED
        description:
          type: string
          description: The description for the component. Optional when creating or updating a component.
        id:
          type: string
          description: The unique identifier for the component.
          readOnly: true
        isAssigneeTypeValid:
          type: boolean
          description: Whether a user is associated with `assigneeType`. For example, if the `assigneeType` is set to `COMPONENT_LEAD` but the component lead is not set, then `false` is returned.
          readOnly: true
        lead:
          description: The user details for the component's lead user.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/User'
        leadAccountId:
          maxLength: 128
          type: string
          description: The accountId of the component's lead user. The accountId uniquely identifies the user across all Atlassian products. For example, *5b10ac8d82e05b22cc7d4ef5*.
          writeOnly: true
        leadUserName:
          type: string
          description: This property is no longer available and will be removed from the documentation soon. See the [deprecation notice](https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-user-privacy-api-migration-guide/) for details.
        metadata:
          type: object
          additionalProperties:
            type: string
            readOnly: true
          description: Compass component's metadata. Can't be updated. Not required for creating a Project Component.
          readOnly: true
        name:
          type: string
          description: The unique name for the component in the project. Required when creating a component. Optional when updating a component. The maximum length is 255 characters.
        project:
          type: string
          description: The key of the project the component is assigned to. Required when creating a component. Can't be updated.
        projectId:
          type: integer
          description: The ID of the project the component is assigned to.
          format: int64
          readOnly: true
        realAssignee:
          description: The user assigned to issues created with this component, when `assigneeType` does not identify a valid assignee.
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/User'
        realAssigneeType:
          type: string
          description: |-
            The type of the assignee that is assigned to issues created with this component, when an assignee cannot be set from the `assigneeType`. For example, `assigneeType` is set to `COMPONENT_LEAD` but no component lead is set. This property is set to one of the following values:

             *  `PROJECT_LEAD` when `assigneeType` is `PROJECT_LEAD` and the project lead has permission to be assigned issues in the project that the component is in.
             *  `COMPONENT_LEAD` when `assignee`Type is `COMPONENT_LEAD` and the component lead has permission to be assigned issues in the project that the component is in.
             *  `UNASSIGNED` when `assigneeType` is `UNASSIGNED` and Jira is configured to allow unassigned issues.
             *  `PROJECT_DEFAULT` when none of the preceding cases are true.
          readOnly: true
          enum:
            - PROJECT_DEFAULT
            - COMPONENT_LEAD
            - PROJECT_LEAD
            - UNASSIGNED
        self:
          type: string
          description: The URL of the component.
          format: uri
          readOnly: true
      additionalProperties: false
      description: Details about a project component.
      xml:
        name: component
  securitySchemes:
    basicAuth:
      type: http
      description: You can access this resource via basic auth.
      scheme: basic
    OAuth2:
      type: oauth2
      description: OAuth2 scopes for Jira
      flows:
        authorizationCode:
          authorizationUrl: https://auth.atlassian.com/authorize
          tokenUrl: https://auth.atlassian.com/oauth/token
          scopes:
            read:jira-work: Read project and issue data. Search for issues and objects associated with issues (such as attachments and worklogs).

Confluence contract details

Please note that while correct in principle and approved by products, these API contracts are still draft - the exact API contract will be finalised during implementation. Again, the nicest way to read these OpenAPI schemas is to use the Swagger Editor.

These contracts are taken from DAC and reduced to include only those paths and components affected by this RFC.

openapi: 3.0.3
info:
  title: The Confluence Cloud REST API v2
  description: This document describes Confluence's v2 APIs. This is intended to be an iteration on the existing Confluence Cloud REST API with improvements in both endpoint definitions and performance.
  termsOfService: https://developer.atlassian.com/platform/marketplace/atlassian-developer-terms/
  version: 2.0.0
paths:
  /contentpolicy:
    get:
      summary: Get content policy for the entire workspace
      description: |-
        Returns content policy for the entire workspace.
      operationId: getContentPolicy
      responses:
        '200':
          description: Returned if the request is successful.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ContentPolicy'
        '400':
          description: Returned if the request is not valid.
        '401':
          description: Returned if the authentication credentials are incorrect or missing.
      deprecated: false
      security:
        - basicAuth: []
        - oAuthDefinitions:
            - read:space:confluence
      x-atlassian-oauth2-scopes:
        - scheme: oAuthDefinitions
          state: Current
          scopes:
            - read:space:confluence
      x-atlassian-connect-scope: READ
  /contentpolicy/spaces:
    get:
      tags:
        - ContentPolicySpace
      operationId: getContentPolicySpaces
      summary: Get spaces with content policy
      description: |-
        Returns all spaces. The results will be sorted by id ascending. The number of results is limited by the `limit` parameter and
        additional results (if available) will be available through the `next` URL present in the `Link` response header.

        **[Permissions](https://confluence.atlassian.com/x/_AozKw) required**:
        Permission to access the Confluence site ('Can use' global permission).
        Only spaces that the user has permission to view will be returned.
      parameters:
        - name: ids
          in: query
          required: false
          description: Filter the results to spaces based on their IDs. Multiple IDs can be specified as a comma-separated list.
          schema:
            type: array
            maxItems: 250
            items:
              type: integer
              format: int64
        - name: keys
          in: query
          required: false
          description: Filter the results to spaces based on their keys. Multiple keys can be specified as a comma-separated list.
          schema:
            type: array
            maxItems: 250
            items:
              type: string
        - name: sort
          in: query
          required: false
          description: Used to sort the result by a particular field.
          schema:
            $ref: '#/components/schemas/SpaceSortOrder'
        - name: cursor
          in: query
          required: false
          description: Used for pagination, this opaque cursor will be returned in the `next` URL in the `Link` response header. Use the relative URL in the `Link` header to retrieve the `next` set of results.
          schema:
            type: string
        - name: limit
          in: query
          description: Maximum number of spaces per result to return. If more results exist, use the `Link` response header to retrieve a relative URL that will return the next set of results.
          schema:
            format: int32
            default: 25
            minimum: 1
            maximum: 250
            type: integer
      responses:
        '200':
          description: Returned if the requested spaces are returned.
          content:
            application/json:
              schema:
                title: MultiEntityResult<Space>
                type: object
                properties:
                  results:
                    type: array
                    items:
                      $ref: '#/components/schemas/ContentPolicySpace'
                  _links:
                    type: object
                    properties:
                      next:
                        type: string
                        description: |-
                          Used for pagination. Contains the relative URL for the next set of results, using a cursor query parameter.
                          This property will not be present if there is no additional data available.
          headers:
            Link:
              schema:
                type: string
              description: |
                Used for pagination. This header contains URL(s) within angle brackets and a relation description for each URL, describing how the provided URL relates to the incoming request's URL. For example, rel="next" would be the URL necessary to get the next page of information. If there are no additional results, this header will not be returned. Example response header format: `Link: </wiki/api/v2/spaces?cursor=<opaque cursor token>>; rel="next"`
        '400':
          description: Returned if an invalid request is provided.
          content: {}
        '401':
          description: |-
            Returned if the authentication credentials are incorrect or missing
            from the request.
          content: {}
      security:
        - basicAuth: []
        - oAuthDefinitions:
            - read:space:confluence
      x-atlassian-oauth2-scopes:
        - scheme: oAuthDefinitions
          state: Current
          scopes:
            - read:space:confluence
      x-atlassian-connect-scope: READ
components:
  schemas:
    ContentPolicy:
      type: object
      properties:
        anyContentBlocked:
          type: boolean
          description: Whether the workspace contains any content blocked for (inaccessible to) the requesting client application.
          readOnly: true
      additionalProperties: false
      description: Details about content policy.
      xml:
        name: contentpolicy
    ContentPolicySpace:
      type: object
      properties:
        id:
          type: string
          description: ID of the space.
        key:
          type: string
          description: Key of the space.
        name:
          type: string
          description: Name of the space.
        description:
          $ref: '#/components/schemas/SpaceDescription'
        contentpolicy:
          type: object
          properties:
            anyContentBlocked:
              type: boolean
              description: Whether the project contains *any* content blocked for (inaccessible to) the requesting client application.
              readOnly: true
        icon:
          $ref: '#/components/schemas/SpaceIcon'
        _links:
          $ref: '#/components/schemas/SpaceLinks'
    BodyType:
      type: object
      properties:
        representation:
          type: string
          description: Type of content representation used for the value field.
        value:
          type: string
          description: Body of the content, in the format found in the representation field.
    SpaceDescription:
      type: object
      description: Contains fields for each representation type requested.
      properties:
        plain:
          $ref: '#/components/schemas/BodyType'
        view:
          $ref: '#/components/schemas/BodyType'
    SpaceIcon:
      type: object
      description: The icon of the space
      properties:
        path:
          type: string
          description: The path (relative to base URL) at which the space's icon can be retrieved. The format should be like `/wiki/download/...` or `/wiki/aa-avatar/...`
        apiDownloadLink:
          type: string
          description: |
            The path (relative to base URL) that can be used to retrieve a link to download the space icon. 3LO apps should use this link instead of the value provided
            in the `path` property to retrieve the icon.

            Currently this field is only returned for `global` spaces and not `personal` spaces.
    SpaceLinks:
      type: object
      properties:
        webui:
          type: string
          description: Web UI link of the space.
    SpaceSortOrder:
      enum:
        - id
        - '-id'
        - key
        - '-key'
        - name
        - '-name'
      type: string
      description: The sort fields for spaces. The default sort direction is ascending. To sort in descending order, append a `-` character before the sort field. For example, `fieldName` or `-fieldName`.
  securitySchemes:
    basicAuth:
      type: http
      description: You can access this resource via basic auth.
      scheme: basic
    oAuthDefinitions:
      type: oauth2
      description: This API uses OAuth 2 with the authorizationCode grant flow.
      flows:
        authorizationCode:
          authorizationUrl: https://auth.atlassian.com/authorize
          tokenUrl: https://auth.atlassian.com/oauth/token
          scopes:
            read:space:confluence: View spaces and their properties.

Hi @JustinThirkell ,
Wow, that really looks like an improvement!
For us using/extending the existing REST API is great.

1 Like

Hi @JustinThirkell,

It still fails to address the issue of arbitrary JQL search in Jira, which will be the major pain point for troubleshooting for customers and vendors.

In terms of Project API, this looks much better, with only one concern: is it possible to add this to Get Project method as well? https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-projects/#api-rest-api-3-project-projectidorkey-get ?

Hi @AngelinaIgnatova

Is this the case that you canā€™t have locked custom fields in connect?

Thanks!

Further to a previous comment, Iā€™m not sure if Confluence spaceIds should also be officially typed as integer or string. The REST v2 API apparently goes both ways: methods like this use integers for spaceIds in its query params, but it uses strings for spaceIds in the response object. :man_shrugging: Maybe itā€™s mostly irrelevant because query parameters arenā€™t technically typed on the client side (they all get converted into a string anyway), but I wanted to mention it in case there is an issue. (If clients are using type-safe libraries for constructing requests based on the OpenAPI spec, it would probably be better to have the correct type, whatever that might be.)

@JustinThirkell Please make all IDs strings, as this will avoid the type of drama that happened when the Confluence API v2 used integers and had to change to strings on short notice.

Hi @scott.dudley and @marc ,

Thanks - yes noted. As these API changes will now be incorporated into existing product APIs, we will effectively be adopting whatever parameter and response types already exist in these APIs. Our ability to change or even influence the shapes of these APIs is greatly restricted (which is one reason we had wanted to create a new API where we would have full control over the contract).

If I have inadvertently proposed an API contract here which contravenes the contract actually used by products, please consider the existing product contract to be the source of truth. Weā€™ll work through these details ourselves as we implement the new API operations.

cheers, justin

2 Likes

Hey @BenDavies,

All Connect fields (from the issue field module) are locked. Was that what you were looking for?

Cheers,
Angelina

2 Likes

This is a reasonable ask. I probably wonā€™t be able to obtain a commitment for this from both Jira and Confluence before we close this RFC in a couple of days but I will ask and weā€™ll hopefully be able to make it available. :+1:

1 Like

Can you clarify please, what exactly you mean by ā€˜the issueā€™?

It will be the case that when an app has been restricted from some issues that yes, those issues are filtered out of JQL search results. While I can understand that issues ā€˜missingā€™ from search results could be confusing to users, issues being filtered is by design.

This is where we have been thinking the ability of an app to determine when policy is in effect either within the workspace, or within a particular space would be helpful - the app can provide messaging to the user explaining (for example) that some issues may be missing from search results.

Could you describe what kind of capability you would like us to provide (that is not already planned) to mitigate this and reduce the partner support burden?

Thanks :slight_smile:

Can you please extend that request to include every REST API that returns a Project/Space object that supports the expand request parameter?

Also, how would this work for Confluence REST API v2, in which the expand option has been removed from many endpoints, including /wiki/rest/api/space

For differences, see https://developer.atlassian.com/cloud/confluence/rest/v1/api-group-space/#api-wiki-rest-api-space-get (V1) and https://developer.atlassian.com/cloud/confluence/rest/v2/api-group-space/#api-spaces-get (V2)

It might be by design, but it will definetely will bring confusion for many users in cases of the apps that are relying on JQL search for core functionality if no proper communication about filtered issues in specific search can be provided to the end user.

The problem is that we cannot know what projects are involved in arbitrary JQL query and current Jira API doesnā€™t provide any methods to extract this information. We cannot communicate to users message like ā€œyou have app access rule enabled in your installation, so you might not see some issues, but we donā€™t know for fact if it affects specific query or notā€

I think that addition of warning message to existing response field warningMessages in search api if some issues were filtered from reqponse, might be resonable enough, which would specify that some issues were filtered out from search results due to the app access rule, preferably with the count of filtered issues.

Sorry but weā€™re unable to commit to modifying all product REST APIs within the timeframes we have available. Given our time constraints we are focusing on the concrete use cases we have gathered to date - as a workaround, apps may always make a second request to the API endpoint we are providing. But we welcome further specific use cases which we can use to advise future prioritisation. :slight_smile:

Indeed! - this is possibly why the Confluence team have elected to create a whole new API resource.

Can you please explain a bit more why providing this kind of messaging is not possible for your use case?

Ah, I understand thanks.
The complication here (for us) is that App Access Rule filtering can occur right down in the data store. Identifying that filtering has resulted in some objects not being returned (and how many) would require changes through all application layers and also into the data store query implementation, and even then itā€™s possible that identifying filtered items would require a doubling of search compute and IO - which will have an obvious impact on performance across the board. Itā€™s not just a matter of filtering at the point where the response is buffered and passing information about the filtering out to API clients. There is no quick fix here Iā€™m sorry.

Sadly, it sounds like this is being rushed for no apparrent reason at the expense of proper implementation which would not significantly diminish user experience when access rules are active.

Why wouldnā€™t it be possible to look for other suitable implementation that would allow proper communication? Simplest one would be filtering in application layer after data fetching.

Of course itā€™s technically possible, but it would mean that both vendors and Atlassian must communicate to all customers and their users that if they use app access rules, filters will be applied silently and no proper communication would be provided when theyā€™re applied.

Only realistic option I can see to convey this information to every single app user, is to put huge banner on top of the app page saying ā€œyour installation has access rules enabled, so you wonā€™t be able to see issues from projects A,B,C,D inside this appā€.

Letā€™s imagine very simple use case: imagine an app that is the exact clone of Jira search and average non-admin Jira user. User first tests their query in regular Jira search, everything looks good. Then user goes into our app and doesnā€™t see some issues for no apparent reason. Now we have a new support case: why certain issue is not present in our app. All we can do in this case is to :man_shrugging: and tell user to verify with Jira admin if this issue falls into any app access rule.

And with large amount of installations with good amount of users this will create a significant support burden for every vendor that has features relying on Jira issue search. And not only for vendors, but for Atlassian support and customer IT departments as well.

1 Like

Isnā€™t that a self-imposed deadline? Why would Atlassian want to ship something that potentially degrades customer success to be able to meet an artificial deadline? Something something company values?

4 Likes

This thread is very disappointing.

Atlassian has chosen to:

  • Use weak data to justify
  • To ship a feature that is highly disruptive to the ecosystem
  • Which will increase development and support costs for partners without a clear corresponding revenue benefit to partners
  • To somehow increase the revenue from Access
  • Using unnecessary new technical formats
  • On an self imposed short timeline
  • Where the technical implementation clearly shows a lack of understand of Atlassianā€™s own APIs

Would the behavior of Atlassian in shipping this be something you could proudly tell your moms about? I would be ashamed.