Problem
server/routes/update.js:78-125 implements POST /api/update/sync-fork, which fast-forwards a user's GitHub fork from upstream via updateChecker.syncFork.
The route defines input schema validation (syncForkSchema:24-26) and structured error mapping:
- 502
GIT_UNAVAILABLE when getRemoteInfo throws.
- 400
NO_ORIGIN when !info?.hasOrigin.
- 400
NOT_GITHUB when !info.isGithub.
- 400
ALREADY_UPSTREAM when info.isUpstream.
- 400
NOT_A_FORK when !info.isFork.
- 409
FORK_DIVERGED with recovery guidance when syncFork rejects with a non-fast-forward message.
- 502
FORK_SYNC_FAILED on general syncFork errors.
- 200 with
{ synced: true, ... } on success.
Currently, server/routes/update.test.js has zero tests for POST /api/update/sync-fork. The route is completely unasserted at the HTTP boundary.
Trigger
A user operating PortOS on a GitHub fork visits the Update page or triggers fork synchronization via POST /api/update/sync-fork.
Impact
PortOS's distribution model (AGENTS.md and docs/SELF_UPDATE.md) strictly requires fork safety. If origin validation gates drift or the regex matching diverged commits breaks, fork users could receive unhelpful 500 errors or have sync attempts fail silently. Without HTTP boundary tests, regressions in schema validation (e.g. invalid branch characters), status codes, or error messaging cannot be caught before deployment.
Fix
Add a new describe('POST /api/update/sync-fork') test block in server/routes/update.test.js:
- Assert 200 OK with sync result when
updateChecker.getRemoteInfo returns a valid fork and updateChecker.syncFork succeeds.
- Assert 400
NO_ORIGIN when getRemoteInfo returns { hasOrigin: false }.
- Assert 400
NOT_GITHUB when getRemoteInfo returns { hasOrigin: true, isGithub: false }.
- Assert 400
ALREADY_UPSTREAM when getRemoteInfo returns { hasOrigin: true, isGithub: true, isUpstream: true }.
- Assert 400
NOT_A_FORK when getRemoteInfo returns { hasOrigin: true, isGithub: true, isUpstream: false, isFork: false }.
- Assert 502
GIT_UNAVAILABLE when getRemoteInfo rejects.
- Assert 409
FORK_DIVERGED when syncFork throws an error containing "not a fast forward" or "diverged", verifying the error message includes guidance.
- Assert 502
FORK_SYNC_FAILED when syncFork throws an unexpected error.
- Assert 400 validation error when
branch contains disallowed characters (e.g. ;, spaces, control characters).
Rejected alternative: Relying only on updateChecker.test.js unit tests for syncFork was rejected because unit tests for the service method do not assert route validation schemas, HTTP status codes, or the route's error handling and regex translation.
Acceptance criteria
Problem
server/routes/update.js:78-125implementsPOST /api/update/sync-fork, which fast-forwards a user's GitHub fork from upstream viaupdateChecker.syncFork.The route defines input schema validation (
syncForkSchema:24-26) and structured error mapping:GIT_UNAVAILABLEwhengetRemoteInfothrows.NO_ORIGINwhen!info?.hasOrigin.NOT_GITHUBwhen!info.isGithub.ALREADY_UPSTREAMwheninfo.isUpstream.NOT_A_FORKwhen!info.isFork.FORK_DIVERGEDwith recovery guidance whensyncForkrejects with a non-fast-forward message.FORK_SYNC_FAILEDon generalsyncForkerrors.{ synced: true, ... }on success.Currently,
server/routes/update.test.jshas zero tests forPOST /api/update/sync-fork. The route is completely unasserted at the HTTP boundary.Trigger
A user operating PortOS on a GitHub fork visits the Update page or triggers fork synchronization via
POST /api/update/sync-fork.Impact
PortOS's distribution model (
AGENTS.mdanddocs/SELF_UPDATE.md) strictly requires fork safety. If origin validation gates drift or the regex matching diverged commits breaks, fork users could receive unhelpful 500 errors or have sync attempts fail silently. Without HTTP boundary tests, regressions in schema validation (e.g. invalid branch characters), status codes, or error messaging cannot be caught before deployment.Fix
Add a new
describe('POST /api/update/sync-fork')test block inserver/routes/update.test.js:updateChecker.getRemoteInforeturns a valid fork andupdateChecker.syncForksucceeds.NO_ORIGINwhengetRemoteInforeturns{ hasOrigin: false }.NOT_GITHUBwhengetRemoteInforeturns{ hasOrigin: true, isGithub: false }.ALREADY_UPSTREAMwhengetRemoteInforeturns{ hasOrigin: true, isGithub: true, isUpstream: true }.NOT_A_FORKwhengetRemoteInforeturns{ hasOrigin: true, isGithub: true, isUpstream: false, isFork: false }.GIT_UNAVAILABLEwhengetRemoteInforejects.FORK_DIVERGEDwhensyncForkthrows an error containing"not a fast forward"or"diverged", verifying the error message includes guidance.FORK_SYNC_FAILEDwhensyncForkthrows an unexpected error.branchcontains disallowed characters (e.g.;, spaces, control characters).Rejected alternative: Relying only on
updateChecker.test.jsunit tests forsyncForkwas rejected because unit tests for the service method do not assert route validation schemas, HTTP status codes, or the route's error handling and regex translation.Acceptance criteria
server/routes/update.test.jscontains adescribe('POST /api/update/sync-fork')block.NO_ORIGIN,NOT_GITHUB,ALREADY_UPSTREAM, andNOT_A_FORK.FORK_DIVERGEDwhensyncForkreports divergent commits.GIT_UNAVAILABLEandFORK_SYNC_FAILED.server/routes/update.test.jspass withcd server && npm test routes/update.test.js.