-
Task Breakup:
- Backend DTO + entity update to allow credential update
~45 minutes
• Add fields to ProjectUpdateDto (gitUsername, gitToken)
• Update service layer to persist changes
• Ensure token is encrypted/handled consistently
- Controller wiring + validation ~30–45 minutes • Allow optional update (don’t overwrite if null) • Add clear error message propagation
- UI change (Project Edit screen) ~45–60 minutes
• Add masked PAT field • UX note: “Leave blank to keep existing token” • Ensure it doesn’t echo token back 4. Error handling improvement on push failure ~30 minutes • Detect auth-related push errors • Map to meaningful message (“Authentication failed or token expired”) 5. Regression test (manual + curl) ~30–45 minutes
Total: ~3 hours focused work.
- Backend DTO + entity update to allow credential update
~45 minutes
• Add fields to ProjectUpdateDto (gitUsername, gitToken)
• Update service layer to persist changes
• Ensure token is encrypted/handled consistently
-
Happy path: MergeByURL handler → service.MergeByURL → inspector.Merge → one of the four merge strategy methods (regularMerge, squashMerge, etc.) → PushWithRetry → Push → e.Git("push", remote, branch) which shells out to git push.
Where the expired PAT is detected: At the very bottom —
e.Git("push", ...)in engine.go. This runs the real git push process. When the PAT is expired, GitHub returns an HTTP 401/403, and git writes something like fatal: Authentication failed for 'https://...' to stderr and exits non-zero. That stderr comes back in Result.Stderr.
Current problem: _Push() _sees r.Err != nil, wraps the raw stderr into a generic fmt.Errorf("push failed: %s", stderr), and returns it. PushWithRetry then retries this three times needlessly, and eventually returns "push failed after 3 attempts: push failed: fatal: Authentication failed...". That string propagates all the way up through the merge strategy, through service.MergeByURL, and out of the handler as a http/500 with a cryptic message.
Where I am adding detection: In _Push() i_tself — the earliest possible point — so the auth failure is classified before it ever leaves engine.go. Everything above it (PushWithRetry, the merge strategies, service.MergeByURL, the handler) then just uses errors.Is to react appropriately rather than string-matching on error messages.
-
rksuma@Ramakrishnans-MacBook-Pro sztab % git checkout -b bugfix/SZ-109-Expired-PAT-Causes-Post-Merge-Push-Failure-and-Cannot-Be-Updated-via-UI Switched to a new branch 'bugfix/SZ-109-Expired-PAT-Causes-Post-Merge-Push-Failure-and-Cannot-Be-Updated-via-UI' rksuma@Ramakrishnans-MacBook-Pro sztab % -
-
rksuma@Ramakrishnans-MacBook-Pro sztab % git checkout wolnosc git pull origin wolnosc git merge --ff-only bugfix/SZ-109-Expired-PAT-Causes-Post-Merge-Push-Failure-and-Cannot-Be-Updated-via-UI git push origin wolnosc Switched to branch 'wolnosc' Your branch is up to date with 'origin/wolnosc'. From https://tigase.dev/sztab * branch wolnosc -> FETCH_HEAD Already up to date. Updating c8d111f..a6b16ef Fast-forward backend/src/main/java/com/sztab/exception/GitCredentialsExpiredException.java | 12 +++++++ backend/src/main/java/com/sztab/exception/handlers/GlobalExceptionHandler.java | 15 +++++++++ backend/src/main/java/com/sztab/service/impl/PersonalAccessTokenServiceImpl.java | 4 ++- backend/src/main/java/com/sztab/sztabina/client/impl/SztabinaClient.java | 12 ++++++- backend/src/test/java/com/sztab/sztabina/client/SztabinaClientMergeTest.java | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ frontend/src/components/project/EditProjectModal.tsx | 19 +++++++++++ frontend/src/types/project.ts | 2 ++ sztabina/exec/engine.go | 30 +++++++++++++----- sztabina/handlers/git_handler.go | 4 +++ sztabina/service/gitservice.go | 13 +++++++- 10 files changed, 226 insertions(+), 11 deletions(-) create mode 100644 backend/src/main/java/com/sztab/exception/GitCredentialsExpiredException.java create mode 100644 backend/src/test/java/com/sztab/sztabina/client/SztabinaClientMergeTest.java Total 0 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0) To https://tigase.dev/sztab.git c8d111f..a6b16ef wolnosc -> wolnosc rksuma@Ramakrishnans-MacBook-Pro sztab % git branch -d bugfix/SZ-109-Expired-PAT-Causes-Post-Merge-Push-Failure-and-Cannot-Be-Updated-via-UI git push origin --delete bugfix/SZ-109-Expired-PAT-Causes-Post-Merge-Push-Failure-and-Cannot-Be-Updated-via-UI Deleted branch bugfix/SZ-109-Expired-PAT-Causes-Post-Merge-Push-Failure-and-Cannot-Be-Updated-via-UI (was a6b16ef). remote: remote: Create a pull request for 'bugfix/SZ-109-Expired-PAT-Causes-Post-Merge-Push-Failure-and-Cannot-Be-Updated-via-UI' by visiting: remote: https://tigase.dev/sztab/~pulls/new?target=1325:wolnosc&source=1325:bugfix/SZ-109-Expired-PAT-Causes-Post-Merge-Push-Failure-and-Cannot-Be-Updated-via-UI remote: To https://tigase.dev/sztab.git - [deleted] bugfix/SZ-109-Expired-PAT-Causes-Post-Merge-Push-Failure-and-Cannot-Be-Updated-via-UI rksuma@Ramakrishnans-MacBook-Pro sztab % -
SZ-109 Test Plan to verify this fix
1. Expired/invalid credentials — merge failure
- Configure a project with a GitHub/GitLab repo using an expired or revoked PAT
- Attempt to merge a PR in Sztab
- Expected: merge fails with a clear message indicating credentials have expired, not a generic 500
- Expected: failure is fast — no 3-attempt retry delay
2. Valid credentials — merge succeeds
- Configure a project with valid credentials
- Merge a PR
- Expected: merge succeeds normally, no regression
3. Credential update via Project Edit UI
- Open Project Edit for a project with expired credentials
- Leave the Git Password / Token field blank and save
- Expected: save succeeds, existing credentials unchanged
- Open Project Edit again, enter a new valid token, save
- Retry the merge
- Expected: merge succeeds with updated credentials
4. Credential update — invalid new token
- Enter a deliberately wrong token in the credential field and save
- Attempt a merge
- Expected: same clear auth failure message as test 1
5. Non-credential push failure
- Simulate a non-auth push failure (e.g. force-push rejected, network error)
- Expected: generic error message, not misclassified as a credential failure
6. Read-only git browser with expired credentials
- Navigate to the file browser for a project with expired credentials
- Expected: graceful error, not a silent empty result or raw exception
- Note: flagged as a follow-on during implementation — verify current behaviour and file a separate ticket if still surfacing a raw exception
| Type |
Bug
|
| Priority |
Normal
|
| Assignee | |
| Version |
1.9.2
|
| Sprints |
n/a
|
| Customer |
n/a
|
Summary
If the Personal Access Token (PAT) used for an external Git repository (e.g., GitHub) expires, merge operations in Sztab fail during the push step.
There is currently no way to update the stored PAT via the Project Edit UI. The only workaround is to either:
This is a functional gap and creates operational risk.
Environment
Version: 1.9.2
Component: Sztab + Sztabina
External Git: GitHub (PAT-based authentication)
Steps to Reproduce
Actual Behavior
Expected Behavior
Impact
Current Workaround
Suggested Fix
Severity
Medium–High
Blocks merge workflow once token expires.