fix: npm repository url gap (CM-1305)#4334
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit a9be6d4. Configure here.
There was a problem hiding this comment.
Pull request overview
Fixes npm repository_url normalization for scp-style SSH URLs under ssh:// and introduces an offline backfill to recompute packages.repository_url (and keep package_repos consistent) from already-stored declared_repository_url without re-fetching npm registry data.
Changes:
- Extend
canonicalizeRepoUrlto handlessh://git@host:owner/repo(.git)inputs and add unit tests for the new cases. - Add DAL helpers to keyset-scan npm package rows and batch-update
repository_url(including NULL clears) while bumpinglast_synced_at. - Add an npm repo-url backfill worker + CLI entrypoint and expose it via
package.jsonscripts.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| services/libs/data-access-layer/src/packages/packages.ts | Adds npm-specific scan/update helpers for recomputing repository_url in batches. |
| services/apps/packages_worker/src/utils/canonicalizeRepoUrl.ts | Adds normalization for ssh://git@host:owner/repo scp-colon form. |
| services/apps/packages_worker/src/utils/tests/canonicalizeRepoUrl.test.ts | Adds regression tests for new canonicalization inputs. |
| services/apps/packages_worker/src/npm/backfillRepositoryUrl.ts | New offline backfill: recompute URLs and sync package_repos in atomic batches. |
| services/apps/packages_worker/src/bin/npm-repo-url-backfill.ts | New CLI wrapper with --dry-run / --critical-only and batch-size env var. |
| services/apps/packages_worker/package.json | Adds backfill:npm-repo-url scripts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
Signed-off-by: Umberto Sgueglia <usgueglia@contractor.linuxfoundation.org>
18cffab to
79e3552
Compare
| // declaredRepositoryUrl is guaranteed non-null by the query's IS NOT NULL filter. | ||
| const canonical = canonicalizeRepoUrl(row.declaredRepositoryUrl as string) | ||
| const desired = canonical?.url ?? null |
| // segment before the next `/` is a real port (e.g. `ssh://git@host:2222/owner/repo`), | ||
| // not an scp-style owner — leave those for the generic case, which URL parses fine. | ||
| const sshScp = s.match(/^ssh:\/\/git@([^/:]+):(.+)$/) | ||
| const sshScpIsPort = sshScp ? /^\d+$/.test(sshScp[2].split('/')[0]) : false |
| // so the inconsistency would never be repaired. | ||
| await withDeadlockRetry(() => | ||
| qx.tx(async (t: QueryExecutor) => { | ||
| await updateNpmRepositoryUrls(t, updates) |

Summary
Fixes the npm
repository_urlnormalization gap (Gap D):canonicalizeRepoUrlfailed to parse scp-style SSH URLs written under thessh://scheme (e.g.ssh://git@github.com:owner/repo.git), returningnulland leavingrepository_urlempty even though a usable repo URL was declared. Adds an offline backfill so existing npm rows can be recomputed from the already-storeddeclared_repository_urlwithout re-fetching the registry.Changes
src/utils/canonicalizeRepoUrl.ts: handlessh://git@host:owner/repo(colon before the path) before the existingssh://git@host/owner/repo(slash) case —new URL()throws on the colon form because the segment after the host looks like a port, so it's rewritten tohttps://first.src/utils/__tests__/canonicalizeRepoUrl.test.ts: added cases for the scp-colon form and a digit-leading owner name (1inch/...), plus extra unparseable-input cases.services/libs/data-access-layer/src/packages/packages.ts: newlistNpmPackagesForRepoUrlRecompute/updateNpmRepositoryUrlsDAL functions (keyset-paginated scan byid, split clear-vs-set UPDATE to avoidNULLs inside atext[]literal), modeled directly on the existing Maven equivalents.src/npm/backfillRepositoryUrl.ts(new): recomputesrepository_urlfor every npm row from its storeddeclared_repository_url— no packument re-fetch. Keepspackage_reposconsistent: prunes the stalesource='declared'link and re-links via the samegetOrCreateRepoByUrl/upsertPackageRepopair the ingest path uses. Wrapped inwithDeadlockRetry(duplicated from Maven's helper — see Notes) since the UPDATE + prune + relink must commit atomically per batch.src/bin/npm-repo-url-backfill.ts(new): CLI entrypoint, mirrorsbin/maven-repo-url-backfill.ts(--dry-run,--critical-only, graceful SIGINT/SIGTERM,NPM_REPO_URL_BACKFILL_BATCH_SIZEenv var).package.json: addedbackfill:npm-repo-url/backfill:npm-repo-url:localscripts.Type of change
JIRA ticket
CM-1305
Note
Medium Risk
Batch writes touch
packages,repos, andpackage_reposat scale; transactions and idempotent updates limit inconsistency, but a full backfill run still mutates core package metadata.Overview
Fixes npm repository_url gaps where
canonicalizeRepoUrlreturnednullfor scp-style SSH declarations (ssh://git@github.com:owner/repo), leaving canonical URLs empty despite a storeddeclared_repository_url.canonicalizeRepoUrlnow rewritesssh://git@host:path(colon before the path) tohttps://before URL parsing, while still treating a numeric segment after the colon as a real SSH port. Tests cover digit-leading owners,git+https, and additional invalid inputs.Adds an offline npm repo-url backfill (Maven-style): keyset scan of npm rows with a declared URL, recompute
repository_urlwithout packument fetches, and keeppackage_reposin sync via atomic batch transactions (update, prune staledeclaredlinks, relink) with deadlock retry. New DAL helperslistNpmPackagesForRepoUrlRecompute/updateNpmRepositoryUrls, CLInpm-repo-url-backfill(--dry-run,--critical-only, graceful shutdown), andbackfill:npm-repo-urlscripts.Reviewed by Cursor Bugbot for commit 79e3552. Bugbot is set up for automated code reviews on this repo. Configure here.