Skip to content

Prevent and clean up corrupted application links - #509

Merged
pathob merged 1 commit into
mainfrom
applink-override-hardening
Aug 10, 2026
Merged

Prevent and clean up corrupted application links#509
pathob merged 1 commit into
mainfrom
applink-override-hardening

Conversation

@pathob

@pathob pathob commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Overriding an application link is a non-atomic delete and recreate. If the recreation failed, the instance was left with a registered application link ID without properties, causing repeated 'Link is corrupted' warnings. Now the original link is restored when the recreation fails, a missing application type module aborts the request before the delete, the OAuth configs are applied to the recreated link instead of the deleted instance, and an unknown UUID returns 404 instead of an NPE.

Already corrupted links cannot be retrieved through the applinks API: enumeration skips them, retrieval by ID throws
TypeNotInstalledException, and creating a link whose URL-derived ID collides with the remnant fails with 'already exists'. Deletion, however, only requires the ID, so a minimal ApplicationLink implementation carrying just the ID is enough to purge the remnant. Corrupted links are now cleaned up in all three paths: deleting by UUID purges an unretrievable link instead of failing with a 400, creating a link first removes a corrupted remnant registered under the ID derived from the rpc URL, and overriding by UUID purges and recreates the link from the supplied configuration.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves application-link recovery and cleanup when Atlassian link records are corrupted.

Changes:

  • Restores links after failed recreation and corrects OAuth configuration targeting.
  • Purges corrupted remnants during create, update, and delete operations.
  • Returns 404 for unknown IDs and validates installed application types.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
DefaultApplicationLinksServiceImpl.java Implements recovery, cleanup, validation, and 404 handling.
DefaultApplicationLinkServiceTest.java Adds tests for corruption and recovery paths.
Suppressed comments (1)

commons/src/main/java/com/deftdevs/bootstrapi/commons/service/DefaultApplicationLinksServiceImpl.java:227

  • Catching TypeNotInstalledException does not prove this ID is a corrupted remnant; it can be an existing valid link whose type module is currently unavailable. This create path would silently delete that link merely because its URL-derived ID collides. Verify the raw record is actually missing its type property before purging, and otherwise preserve the existing link and report the collision/unavailable module.
            } catch (TypeNotInstalledException e) {
                log.warn("Removing corrupted application link '{}' before creating a new link for URL '{}'",
                        generatedApplicationId, applicationLinkModel.getRpcUrl());
                deleteCorruptedApplicationLink(generatedApplicationId);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@pathob
pathob force-pushed the applink-override-hardening branch from f14cbc2 to 37a0526 Compare August 10, 2026 10:53
@pathob
pathob requested a balanced review from Copilot August 10, 2026 10:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

@pathob
pathob force-pushed the applink-override-hardening branch 3 times, most recently from a5f2327 to bb26d53 Compare August 10, 2026 14:30
Overriding an application link is a non-atomic delete and recreate. If
the recreation failed, the instance was left with a registered
application link ID without properties, causing repeated 'Link is
corrupted' warnings. Now the original link is restored when the
recreation fails, a missing application type module aborts the request
before the delete, the OAuth configs are applied to the recreated link
instead of the deleted instance, and an unknown UUID returns 404
instead of an NPE.

Already corrupted links cannot be retrieved through the applinks API:
enumeration skips them, retrieval by ID throws
TypeNotInstalledException, and creating a link whose URL-derived ID
collides with the remnant fails with 'already exists'. Deletion,
however, only requires the ID, so a minimal ApplicationLink
implementation carrying just the ID is enough to purge the remnant.
Corrupted links are now cleaned up in all three paths: deleting by
UUID purges an unretrievable link instead of failing with a 400,
creating a link first removes a corrupted remnant registered under the
ID derived from the rpc URL, and overriding by UUID purges and
recreates the link from the supplied configuration.
@pathob
pathob force-pushed the applink-override-hardening branch from bb26d53 to 91556ff Compare August 10, 2026 16:18
@sonarqubecloud

Copy link
Copy Markdown

@pathob
pathob marked this pull request as ready for review August 10, 2026 16:37
@pathob
pathob requested a balanced review from Copilot August 10, 2026 16:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (2)

commons/src/main/java/com/deftdevs/bootstrapi/commons/service/DefaultApplicationLinksServiceImpl.java:289

  • TypeNotInstalledException also represents a valid link whose application-type module is temporarily unavailable, not only a corrupted link. This branch currently deletes both cases, causing data loss for a valid link; preserve the previous 400 response unless isCorrupted(e) confirms the reserved unknown type.
        } catch (TypeNotInstalledException e) {
            // the ID is registered, but the link cannot be retrieved because its type
            // property is missing ("Link is corrupted") or its type module is not installed
            log.warn("Deleting application link '{}' that cannot be retrieved: {}", applicationId, e.getMessage());
            deleteCorruptedApplicationLink(applicationId);

commons/src/main/java/com/deftdevs/bootstrapi/commons/service/DefaultApplicationLinksServiceImpl.java:201

  • When addApplicationLink fails in the corruption scenario described by this PR, it has already left applicationId registered without properties. Re-adding the original link with that same ID therefore fails as “already exists,” so this restore path cannot actually recover the case it targets. Purge the partial registration before calling restoreApplicationLink; the test should also model the failed call leaving the ID occupied until deletion.
        } catch (Exception e) {
            if (originalApplicationLinkDetails != null) {
                restoreApplicationLink(applicationId, originalApplicationType, originalApplicationLinkDetails,
                        originalOutgoingOAuthConfig, originalIncomingConsumerKey);

@pathob
pathob merged commit 5d301a2 into main Aug 10, 2026
10 checks passed
@pathob
pathob deleted the applink-override-hardening branch August 10, 2026 17:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants