-
Notifications
You must be signed in to change notification settings - Fork 9
[PR #616] feat(jira): auto-discover projects β remove mandatory jira_project_keys #941
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
55add04
feat(jira): auto-discover projects via SubstreamPartitionRouter
mozhaev-dev 45f216c
docs(jira): address review β rename stream, add ADR-001, update DESIGβ¦
mozhaev-dev 11d0bb5
fix(jira): extend end_datetime by PT14H to cover positive UTC offsets
mozhaev-dev 49e0dff
docs(jira): fix ADR-007 typo in PRD.md; add known-behavior notes to Aβ¦
mozhaev-dev aa7b2c3
chore(jira): bump major version 1.0.0 β 2.0.0
mozhaev-dev be7b058
Merge branch 'main' into feat/jira-auto-project-discovery
mozhaev-dev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
125 changes: 125 additions & 0 deletions
125
...nents/connectors/task-tracking/jira/specs/ADR/ADR-001-auto-project-discovery.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| --- | ||
| status: accepted | ||
| date: 2026-06-02 | ||
| --- | ||
|
|
||
| # Auto-discovery of Jira projects via SubstreamPartitionRouter | ||
|
|
||
| <!-- toc --> | ||
|
|
||
| - [Context and Problem Statement](#context-and-problem-statement) | ||
| - [Decision Drivers](#decision-drivers) | ||
| - [Considered Options](#considered-options) | ||
| - [Decision Outcome](#decision-outcome) | ||
| - [Consequences](#consequences) | ||
| - [Confirmation](#confirmation) | ||
| - [Pros and Cons of the Options](#pros-and-cons-of-the-options) | ||
| - [Option 1 β Static allowlist in K8s Secret](#option-1--static-allowlist-in-ks-secret) | ||
| - [Option 2 β Auto-discovery via SubstreamPartitionRouter](#option-2--auto-discovery-via-substreampartitionrouter) | ||
| - [More Information](#more-information) | ||
| - [Traceability](#traceability) | ||
|
|
||
| <!-- /toc --> | ||
|
|
||
| **ID**: `cpt-insightspec-adr-jira-auto-project-discovery` | ||
|
|
||
| ## Context and Problem Statement | ||
|
|
||
| The original Jira connector required a `jira_project_keys` field in the K8s Secret β a comma-separated list of Jira project keys to sync (e.g., `TC,TNG`). The rationale at the time was that "Jira Cloud rejects unbounded JQL queries." | ||
|
|
||
| In practice this created operational pain: | ||
|
|
||
| - Jira projects are frequently created and archived. Every change required a manual Secret edit and connector re-trigger. | ||
| - The "unbounded query" concern was a misconception: Jira Cloud's API restriction applies to queries with *no* bounds at all. The connector already queries in 30-day windows (`step: P30D`), which is a valid temporal bound. Queries bounded by project key *and* time window are equivalent in cost and reliability to queries bounded by time window alone. | ||
| - The `jira_project_keys` allowlist diverges from the token's Browse Projects permission boundary. Rotating the token without updating the allowlist silently keeps ingesting a stale project set β or silently drops new projects. | ||
|
|
||
| ## Decision Drivers | ||
|
|
||
| - Operational simplicity: no manual maintenance when projects are added or archived. | ||
| - Permission-boundary alignment: the Jira API token already constrains what the connector can read. | ||
| - Consistency with YouTrack: YouTrack ADR-003 already chose full-ingestion for the same reasons. | ||
| - Correctness: per-project partitioning gives per-project incremental cursor state, which is strictly better than a single global cursor. | ||
|
|
||
| ## Considered Options | ||
|
|
||
| 1. **Static allowlist in K8s Secret** (`jira_project_keys`) β keep the current behaviour. | ||
| 2. **Auto-discovery via SubstreamPartitionRouter** β query `GET /rest/api/3/project/search` at the start of each sync to obtain all accessible project keys; partition `jira_issue` over those keys. | ||
|
|
||
| ## Decision Outcome | ||
|
|
||
| Chosen option: **auto-discovery via SubstreamPartitionRouter** (Option 2). | ||
|
|
||
| The connector now issues one JQL request per project partition: | ||
|
|
||
| ```sql | ||
| project = "<KEY>" AND updated >= "<t_start>" AND updated <= "<t_end>" | ||
| ORDER BY updated ASC | ||
| ``` | ||
|
|
||
| Project scope is delegated to Jira's Browse Projects permission on the API token. To limit ingestion to a specific subset of projects, operators scope the token in Jira β not in Insight config. | ||
|
|
||
| The `jira_project_keys` field is removed from `spec.connection_specification.required`, `spec.connection_specification.properties`, `descriptor.yaml:secret.required_fields`, and `jira.yaml.example`. | ||
|
|
||
| ### Consequences | ||
|
|
||
| **Positive**: | ||
|
|
||
| - New or renamed projects are ingested automatically on the next scheduled sync without any config change. | ||
| - Archived/deleted projects disappear from `/project/search` and are no longer queried β no stale state. | ||
| - Per-project incremental cursor state: each project advances independently; a new project backfills from `jira_start_date` without affecting other projects. | ||
| - Jira and YouTrack connectors converge on the same architecture (full-ingestion, token-scoped). | ||
| - Eliminates the class of drift bugs where `jira_project_keys` is stale relative to the token scope. | ||
|
|
||
| **Negative**: | ||
|
|
||
| - Operators who want to limit ingestion to a subset of projects must manage token permissions in Jira rather than in Insight config. This is a one-time workflow change. | ||
| - Syncing more projects costs more Jira API calls. For instances with hundreds of projects this adds latency to the directory-discovery phase. Jira rate-limits (429/503) are handled by the existing `Retry-After` backoff strategy. | ||
| - The parent stream (`jira_project_discovery`) makes an additional `/project/search` call every sync run. This is negligible β project lists are small (typically < 200) and fully paginated in one or two requests. | ||
|
|
||
| **State migration**: | ||
|
|
||
| Existing connections lose their per-source incremental cursor state on upgrade. The connector will perform a full re-sync from `jira_start_date` on the first run after the change. Acceptable for current deployments (dev stage; data has no production value). | ||
|
|
||
| ### Confirmation | ||
|
|
||
| Decision is confirmed when: | ||
|
|
||
| - `connector.yaml`'s `jira_issue.retriever` contains a `SubstreamPartitionRouter` whose parent stream queries `/rest/api/3/project/search`. | ||
| - `connector.yaml`'s shared JQL uses `project = "{{ stream_slice.project_key }}"` (not `project IN (...)`). | ||
| - `connector.yaml`'s `spec.connection_specification.required` does **not** list `jira_project_keys`. | ||
| - `descriptor.yaml:secret.required_fields` does **not** list `jira_project_keys`. | ||
| - `jira.yaml.example` does **not** contain a `jira_project_keys` entry. | ||
|
|
||
| ## Pros and Cons of the Options | ||
|
|
||
| ### Option 1 β Static allowlist in K8s Secret | ||
|
|
||
| - **Pros**: Explicit scope visible in config; operators control exactly which projects are ingested from Insight UI. | ||
| - **Cons**: Manual maintenance on every project change; allowlist can drift from token scope; blocks automatic onboarding of new projects; diverges from YouTrack architecture. | ||
|
|
||
| ### Option 2 β Auto-discovery via SubstreamPartitionRouter | ||
|
|
||
| - **Pros**: Zero maintenance; auto-pickup of new projects; per-project cursor state; consistent with YouTrack; permission boundary is the token (single source of truth). | ||
| - **Cons**: Scope management moves to Jira token administration; proportional API cost on large instances. | ||
|
|
||
| ## More Information | ||
|
|
||
| - Jira Cloud Project Search API: `GET /rest/api/3/project/search` β supports `startAt`/`maxResults` offset pagination; returns all projects accessible to the authenticated user. | ||
| - YouTrack equivalent decision: `docs/components/connectors/task-tracking/youtrack/specs/ADR/ADR-003-no-whitelist-full-ingestion.md`. | ||
| - Airbyte CDK `SubstreamPartitionRouter`: combines with `DatetimeBasedCursor` via cartesian product β each `(project_key, time_window)` pair becomes a request. | ||
|
|
||
| ## Traceability | ||
|
|
||
| - Supersedes the `jira_project_keys` design documented in DESIGN Β§3.3 and PRD Β§3.1. | ||
| - Mirrors YouTrack ADR-003 decision; Jira and YouTrack now converge on full-ingestion scope. | ||
| - Implementation PR: `feat/jira-auto-project-discovery`. | ||
|
|
||
| ## Known Behaviors | ||
|
|
||
| ### Archived projects | ||
|
|
||
| `GET /rest/api/3/project/search` returns **all project types** including archived projects by default (Jira Cloud does not filter by `status=live` unless explicitly requested). In practice archived projects return 0 issues via JQL and contribute negligible API cost. If this becomes a concern a follow-up can add `status=live` to the `jira_project_discovery` parent stream's `request_parameters` β that is a backwards-compatible, non-breaking change. | ||
|
|
||
| ### Issue pagination (`/rest/api/3/search/jql`) | ||
|
|
||
| The connector currently uses an `OffsetIncrement` paginator (`startAt` / `maxResults`) against `/rest/api/3/search/jql`. Atlassian's enhanced-JQL endpoint supports cursor-based pagination via `nextPageToken` (already used by the connector's own `CursorPagination` paginator config). The two mechanisms coexist on this endpoint β offset pagination is functional but will be replaced with `nextPageToken`-based pagination in a follow-up to align with Atlassian's recommended approach for large result sets. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix broken link fragment.
The static analysis tool flags this link fragment as invalid. The target
#option-1--static-allowlist-in-ks-secretdoes not match the actual heading#option-1--static-allowlist-in-k8s-secret(missing "8").π Proposed fix
π Committable suggestion
π§° Tools
πͺ markdownlint-cli2 (0.22.1)
[warning] 17-17: Link fragments should be valid
(MD051, link-fragments)
π€ Prompt for AI Agents