fix(installer): restore validateGitHubUrl strictness and fix prettier

- Restore original GitHub-only regex in deprecated validateGitHubUrl
  wrapper so existing tests pass (rejects non-GitHub URLs, trailing
  slashes)
- Run prettier to fix formatting in custom-module-manager.js
This commit is contained in:
Brian Madison 2026-04-09 17:56:46 -05:00
parent ed51e6c538
commit 225e5ee77b
1 changed files with 59 additions and 15 deletions

View File

@ -26,12 +26,30 @@ class CustomModuleManager {
*/
parseSource(input) {
if (!input || typeof input !== 'string') {
return { type: null, cloneUrl: null, subdir: null, localPath: null, cacheKey: null, displayName: null, isValid: false, error: 'Source is required' };
return {
type: null,
cloneUrl: null,
subdir: null,
localPath: null,
cacheKey: null,
displayName: null,
isValid: false,
error: 'Source is required',
};
}
const trimmed = input.trim();
if (!trimmed) {
return { type: null, cloneUrl: null, subdir: null, localPath: null, cacheKey: null, displayName: null, isValid: false, error: 'Source is required' };
return {
type: null,
cloneUrl: null,
subdir: null,
localPath: null,
cacheKey: null,
displayName: null,
isValid: false,
error: 'Source is required',
};
}
// Local path detection: starts with /, ./, ../, or ~
@ -91,7 +109,16 @@ class CustomModuleManager {
};
}
return { type: null, cloneUrl: null, subdir: null, localPath: null, cacheKey: null, displayName: null, isValid: false, error: 'Not a valid Git URL or local path' };
return {
type: null,
cloneUrl: null,
subdir: null,
localPath: null,
cacheKey: null,
displayName: null,
isValid: false,
error: 'Not a valid Git URL or local path',
};
}
/**
@ -104,7 +131,16 @@ class CustomModuleManager {
const resolved = path.resolve(expanded);
if (!fs.pathExistsSync(resolved)) {
return { type: 'local', cloneUrl: null, subdir: null, localPath: resolved, cacheKey: null, displayName: path.basename(resolved), isValid: false, error: `Path does not exist: ${resolved}` };
return {
type: 'local',
cloneUrl: null,
subdir: null,
localPath: resolved,
cacheKey: null,
displayName: path.basename(resolved),
isValid: false,
error: `Path does not exist: ${resolved}`,
};
}
return {
@ -126,17 +162,25 @@ class CustomModuleManager {
* @returns {Object} { owner, repo, isValid, error }
*/
validateGitHubUrl(url) {
const parsed = this.parseSource(url);
if (!parsed.isValid) {
return { owner: null, repo: null, isValid: false, error: parsed.error };
if (!url || typeof url !== 'string') {
return { owner: null, repo: null, isValid: false, error: 'URL is required' };
}
if (parsed.type === 'local') {
const trimmed = url.trim();
// HTTPS format: https://github.com/owner/repo[.git] (strict, no trailing path)
const httpsMatch = trimmed.match(/^https?:\/\/github\.com\/([^/]+)\/([^/.]+?)(?:\.git)?$/);
if (httpsMatch) {
return { owner: httpsMatch[1], repo: httpsMatch[2], isValid: true, error: null };
}
// SSH format: git@github.com:owner/repo[.git]
const sshMatch = trimmed.match(/^git@github\.com:([^/]+)\/([^/.]+?)(?:\.git)?$/);
if (sshMatch) {
return { owner: sshMatch[1], repo: sshMatch[2], isValid: true, error: null };
}
return { owner: null, repo: null, isValid: false, error: 'Not a valid GitHub URL (expected https://github.com/owner/repo)' };
}
// Extract owner/repo from cacheKey (host/owner/repo)
const parts = parsed.cacheKey.split('/');
return { owner: parts[1] || null, repo: parts[2] || null, isValid: true, error: null };
}
// ─── Marketplace JSON ─────────────────────────────────────────────────────