fix(artifacts): reject malformed remote paths

This commit is contained in:
Jayesh Betala
2026-05-19 13:04:45 +05:30
committed by Garry Tan
parent 7320f36ab4
commit b9eefbed68
2 changed files with 32 additions and 1 deletions
+14 -1
View File
@@ -49,6 +49,19 @@ strip_git() {
echo "${1%.git}"
}
valid_owner_repo() {
local owner_repo="$1"
case "$owner_repo" in
""|/*|*/|*//*)
return 1
;;
esac
case "$owner_repo" in
*/*) return 0 ;;
*) return 1 ;;
esac
}
# Parse to (host, owner_repo) regardless of input shape.
parse_url() {
local u="$1"
@@ -82,7 +95,7 @@ parse_url() {
exit 3
;;
esac
if [ -z "$host" ] || [ -z "$owner_repo" ] || [ "$owner_repo" = "$u" ]; then
if [ -z "$host" ] || ! valid_owner_repo "$owner_repo"; then
echo "gstack-artifacts-url: failed to parse host/owner from: $u" >&2
exit 3
fi
+18
View File
@@ -67,6 +67,24 @@ describe('gstack-artifacts-url', () => {
expect(r.stderr).toContain('unrecognized URL form');
});
test('rejects remotes without both owner and repo path segments', () => {
const malformed = [
'https://github.com',
'https://github.com/owner',
'https://github.com/owner/',
'https://github.com/owner//repo',
'git@github.com:owner',
'ssh://git@github.com',
'ssh://git@github.com/owner',
];
for (const url of malformed) {
const r = run(['--to', 'ssh', url]);
expect(r.code, url).toBe(3);
expect(r.stderr, url).toContain('failed to parse host/owner');
}
});
test('rejects missing args with exit 2', () => {
expect(run([]).code).toBe(2);
expect(run(['--to']).code).toBe(2);