Overview

This guide explains how to create an execution action that allows Glean Assistant to create Jira issues on behalf of users. The implementation uses OAuth-based authentication and ensures proper user attribution for created issues.

Prerequisites

Before beginning this implementation, ensure you have:

  • Administrator access to your Jira and Glean instances
  • Familiarity with OAuth 2.0 authentication flows
  • Basic understanding of API implementation
  • Access to necessary development resources

Action Manifest Configuration

The first step involves creating an action manifest that defines the core properties of your Jira integration. This manifest establishes the fundamental characteristics and authentication requirements of your action.

{
  "type": "ACTION",
  "name": "CreateJiraIssue",
  "displayName": "Create Jira Issue Action",
  "description": "This action allows you to create a new issue in Jira. You can specify the project, issue type, and other details.",
  "enablePreview": true,
  "actionType": "EXECUTION",
  "logoUrl": "path/to/your/logo.png",
  "auth": {
    "type": "OAUTH_ADMIN",
    "client_url": "https://auth.atlassian.com/authorize?audience={ATLASSIAN-DOMAIN}.atlassian.net&prompt=consent",
    "scopes": [
      "write:jira-work",
      "offline_access",
      "read:me"
    ],
    "authorization_url": "https://auth.atlassian.com/oauth/token"
  }
}

We use the OAUTH_ADMIN authentication type because Jira’s cloud API supports using admin tokens to create issues on behalf of other users. This approach simplifies the authentication flow while maintaining proper user attribution.

Server Implementation

The server implementation handles requests from Glean’s actions backend and manages the creation of Jira issues. This implementation includes proper security measures and ensures accurate user attribution.

from flask import Flask, request, jsonify
import requests
import json

app = Flask(__name__)
cloud_id = "your_jira_cloud_id_here"
create_issue_url_format = f"https://api.atlassian.com/ex/jira/{cloud_id}/rest/api/3/issue"
users_search_url = f"https://your-domain.atlassian.net/rest/api/3/users/search"

def get_reporter_id(email, auth_header):
    """
    Retrieves the Jira account ID for a given email address.
    This function supports proper user attribution in Jira issues.
    """
    start_at = 0
    max_results = 50
    while True:
        params = {'startAt': start_at, 'maxResults': max_results}
        headers = {'Accept': 'application/json', 'Authorization': auth_header}
        response = requests.get(users_search_url, params=params, headers=headers)
        users = json.loads(response.text)
        for user in users:
            if user['emailAddress'] == email:
                return user['accountId']
        if len(users) < max_results:
            break
        start_at += max_results
    return None

def transform_to_jira_request(input_payload, reporter_id):
    """
    Transforms the input payload into Jira's required format.
    Ensures all required fields are properly formatted.
    """
    jira_request = {
        "fields": {
            "project": {"id": input_payload['pid']},
            "issuetype": {"id": str(input_payload['issuetype'])},
            "priority": {"id": str(input_payload['priority'])},
            "summary": input_payload['summary'],
            "components": [{"id": input_payload['components']}],
            "description": {
                "type": "doc",
                "version": 1,
                "content": [{"type": "text", "text": input_payload['description']}]
            },
            "assignee": {"id": input_payload['assignee']},
            "reporter": {"id": reporter_id}
        }
    }
    return jira_request

@app.route('/create_issue', methods=['POST'])
def create_issue():
    """
    Endpoint handler for creating Jira issues.
    Includes authentication validation and error handling.
    """
    authorization_header = request.headers.get('Authorization')
    glean_user_email = request.headers.get('Glean-User-Email')

    if authorization_header is None or glean_user_email is None:
        return jsonify({"error": "Authorization header or Glean-User-Email not found"}), 401

    reporter_id = get_reporter_id(glean_user_email, authorization_header)
    if reporter_id is None:
        return jsonify({"error": "Reporter ID not found"}), 400

    input_payload = request.json
    jira_request = transform_to_jira_request(input_payload, reporter_id)

    headers = {
        "Content-Type": "application/json",
        "Authorization": authorization_header
    }

    response = requests.post(create_issue_url_format, headers=headers, json=jira_request)
    if response.status_code == 200:
        return jsonify({"resultURL": json.loads(response.text).get("key")}), 200
    else:
        return jsonify({"error": "Failed to create issue", "details": response.text}), response.status_code

if __name__ == '__main__':
    app.run(port=8080)

API Specification

The OpenAPI specification defines how Glean Assistant interacts with your action server. This specification provides clear guidance for field population and ensures consistent behavior.

openapi: 3.0.0
info:
  title: Jira Execution Action
  version: 1.0.0
servers:
  - url: https://{domain}-be.glean.com/tools/jira
    variables:
      domain:
        default: domain
        description: Email domain (without extension) that determines the deployment backend.
paths:
  /create_issue:
    post:
      summary: Creates an issue or a sub-task from a JSON representation
      description: |
        This API allows you to create an issue in Jira.
      parameters:
        - name: Glean-User-Email
          in: header
          required: true
          schema:
            type: string
          description: Email of the authenticated glean user.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                pid:
                  x-glean-typehint: 'JiraProjectID'
                  type: string
                  description: Project ID where the ticket is created.
                issuetype:
                  type: integer
                  description: The ID corresponding to the type of issue being created.
                priority:
                  type: integer
                  minimum: 1
                  maximum: 5
                  description: Numeric priority. 1 (highest) to 5 (lowest).
                summary:
                  x-glean-typehint: 'Content'
                  type: string
                  description: Title of the issue
                components:
                  x-glean-typehint: 'JiraComponentId'
                  type: string
                  description: Component name where the ticket should be filed.
                description:
                  x-glean-typehint: 'Content'
                  type: string
                  description: Body of the issue.
                assignee:
                  x-glean-typehint: 'EmailAddress'
                  type: string
                  description: User to which the issue is assigned.
        required: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateIssuePostResponse'
        '400':
          description: Bad Request
        '401':
          description: Not Authorized
        '409':
          description: Conflict
components:
  schemas:
    CreateIssuePostResponse:
      type: object
      properties:
        resultURL:
          type: string
          description: URL of the created issue.

Implementation Considerations

Security and Authentication

The implementation incorporates several security measures that protect your Jira integration:

First, the OAuth configuration uses admin-level authentication, which provides centralized control while maintaining individual user attribution. This approach simplifies token management while ensuring proper access controls.

Second, the server implementation validates all incoming requests and enforces proper user attribution. The Glean-User-Email header ensures that issues are created with the correct reporter, maintaining accountability and traceability.

User Attribution

The user attribution system works through several mechanisms:

The server retrieves the appropriate Jira account ID for each user by matching their email address. This process ensures that issues appear in Jira with the correct reporter, maintaining accurate audit trails and user accountability.

The implementation handles cases where users might not be found in Jira, preventing issues from being created without proper attribution. This safeguard maintains data integrity within your Jira instance.

Error Handling

The implementation includes comprehensive error handling that addresses common scenarios:

  1. Authentication failures receive appropriate error responses with clear messages
  2. Missing or invalid user information is caught and handled gracefully
  3. Jira API errors are properly captured and communicated back to users
  4. Network issues and timeouts are managed appropriately

Performance Optimization

Several measures ensure optimal performance of the Jira integration:

The implementation uses efficient user lookup mechanisms, implementing pagination for user searches to handle large organizations effectively. The code includes proper request timeouts and connection pooling to manage resources effectively.

The API specification includes type hints that help Glean Assistant populate fields correctly the first time, reducing the need for repeated attempts or corrections.

Maintenance Requirements

To maintain the integration effectively:

  1. Monitor OAuth token usage and implement proper rotation schedules
  2. Track API usage against Jira rate limits
  3. Maintain up-to-date user mappings
  4. Review and update API specifications as needed
  5. Monitor error rates and user feedback

Troubleshooting Guide

When issues arise, investigate these common areas:

  1. Authentication Issues

    • Verify OAuth token validity
    • Check scope configurations
    • Confirm user permissions
  2. User Attribution Problems

    • Verify email mapping functionality
    • Check Jira user account status
    • Confirm proper header parsing
  3. Performance Concerns

    • Monitor response times
    • Check rate limit usage
    • Review connection pooling settings

Next Steps

After implementing the Jira integration:

  1. Create comprehensive user documentation
  2. Establish monitoring and alerting systems
  3. Set up regular maintenance schedules
  4. Plan for feature enhancements
  5. Configure backup and recovery procedures