refactor: improves error handling in repository management

This commit is contained in:
Ravinou 2025-04-20 20:34:01 +02:00
commit 5567cddfdb
No known key found for this signature in database
GPG key ID: EEEE670C40F6A4D7
9 changed files with 42 additions and 34 deletions

View file

@ -26,6 +26,7 @@
.modale h2 {
margin-top: 0;
color: #374151;
}
@keyframes append-animate {

View file

@ -93,7 +93,7 @@ export default function RepoManage(props: RepoManageProps) {
);
else {
const errorMessage = await response.json();
toast.error(`An error has occurred : ${errorMessage.message.stdout}`, toastOptions);
toast.error(`An error has occurred : ${errorMessage.message.stderr}`, toastOptions);
router.replace('/');
console.log('Fail to delete');
}
@ -171,7 +171,7 @@ export default function RepoManage(props: RepoManageProps) {
router.replace('/');
} else {
const errorMessage = await response.json();
toast.error(`An error has occurred : ${errorMessage.message.stdout}`, toastOptions);
toast.error(`An error has occurred : ${errorMessage.message.stderr}`, toastOptions);
router.replace('/');
console.log(`Fail to ${props.mode}`);
}
@ -208,7 +208,7 @@ export default function RepoManage(props: RepoManageProps) {
router.replace('/');
} else {
const errorMessage = await response.json();
toast.error(`An error has occurred : ${errorMessage.message.stdout}`, toastOptions);
toast.error(`An error has occurred : ${errorMessage.message.stderr}`, toastOptions);
router.replace('/');
console.log(`Fail to ${props.mode}`);
}

View file

@ -1,7 +1,19 @@
import { NextApiResponse } from 'next';
const getErrorMessage = (error: unknown): string => {
const getErrorMessage = (error: unknown): any => {
if (error instanceof Error) {
const shellError = error as any;
// Handle shell errors
if ('code' in shellError || 'stderr' in shellError || 'stdout' in shellError) {
return {
code: shellError.code ?? null,
cmd: shellError.cmd ?? null,
stderr: shellError.stderr ?? null,
stdout: shellError.stdout ?? null,
};
}
return error.message;
}

View file

@ -32,7 +32,7 @@ authorized_keys="${home}/.ssh/authorized_keys"
# Check args
if [ "$1" == "" ] || [ "$2" == "" ] || ! [[ "$2" =~ ^[0-9]+$ ]] || [ "$3" != "true" ] && [ "$3" != "false" ]; then
echo -n "This shell takes 3 arguments : SSH Public Key, Quota in Go [e.g. : 10], Append only mode [true|false]"
echo -n "This shell takes 3 arguments : SSH Public Key, Quota in Go [e.g. : 10], Append only mode [true|false]" >&2
exit 1
fi
@ -41,25 +41,25 @@ fi
pattern='(ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-rsa AAAAB3NzaC1yc2)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?'
if [[ ! "$1" =~ $pattern ]]
then
echo -n "Invalid public SSH KEY format. Provide a key in OpenSSH format (rsa, ed25519, ed25519-sk)"
echo -n "Invalid public SSH KEY format. Provide a key in OpenSSH format (rsa, ed25519, ed25519-sk)" >&2
exit 2
fi
## Check if authorized_keys exists
if [ ! -f "${authorized_keys}" ];then
echo -n "${authorized_keys} must be present"
echo -n "${authorized_keys} must be present" >&2
exit 5
fi
# Check if SSH pub key is already present in authorized_keys
if grep -q "$1" "$authorized_keys"; then
echo -n "SSH pub key already present in authorized_keys"
echo -n "SSH pub key already present in authorized_keys" >&2
exit 3
fi
# Check if borgbackup is installed
if ! [ -x "$(command -v borg)" ]; then
echo -n "You must install borgbackup package."
echo -n "You must install borgbackup package." >&2
exit 4
fi

View file

@ -21,7 +21,7 @@ authorized_keys="${home}/.ssh/authorized_keys"
# Check arg
if [[ $# -ne 1 || $1 = "" ]]; then
echo -n "You must provide a repositoryName in argument."
echo -n "You must provide a repositoryName in argument." >&2
exit 1
fi
@ -29,7 +29,7 @@ fi
# If we receive another pattern there is necessarily a problem.
repositoryName=$1
if ! [[ "$repositoryName" =~ ^[a-f0-9]{8}$ ]]; then
echo "Invalid repository name. Must be an 8-character hex string."
echo "Invalid repository name. Must be an 8-character hex string." >&2
exit 2
fi

View file

@ -17,7 +17,7 @@ fi
# Check args
if [ "$1" == "" ] || [ "$2" == "" ] || [ "$3" == "" ] || [ "$4" != "true" ] && [ "$4" != "false" ]; then
echo -n "This shell takes 4 args: [repositoryName] [new SSH pub key] [quota] [Append only mode [true|false]]"
echo -n "This shell takes 4 args: [repositoryName] [new SSH pub key] [quota] [Append only mode [true|false]]" >&2
exit 1
fi
@ -26,7 +26,7 @@ fi
pattern='(ssh-ed25519 AAAAC3NzaC1lZDI1NTE5|sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t|ssh-rsa AAAAB3NzaC1yc2)[0-9A-Za-z+/]+[=]{0,3}(\s.*)?'
if [[ ! "$2" =~ $pattern ]]
then
echo -n "Invalid public SSH KEY format. Provide a key in OpenSSH format (rsa, ed25519, ed25519-sk)"
echo -n "Invalid public SSH KEY format. Provide a key in OpenSSH format (rsa, ed25519, ed25519-sk)" >&2
exit 2
fi
@ -34,13 +34,13 @@ fi
# If we receive another pattern there is necessarily a problem.
repositoryName=$1
if ! [[ "$repositoryName" =~ ^[a-f0-9]{8}$ ]]; then
echo "Invalid repository name. Must be an 8-character hex string."
echo "Invalid repository name. Must be an 8-character hex string." >&2
exit 3
fi
# Check if a line in authorized_keys contains repository_name
if ! grep -q "command=\".*${repositoryName}.*\",restrict" "$home/.ssh/authorized_keys"; then
echo -n "No line containing $repositoryName found in authorized_keys"
echo -n "No line containing $repositoryName found in authorized_keys" >&2
exit 4
fi
@ -64,7 +64,7 @@ while IFS= read -r line; do
fi
done < "$home/.ssh/authorized_keys"
if [ "$found" = true ]; then
echo -n "This SSH pub key is already present in authorized_keys on a different line."
echo -n "This SSH pub key is already present in authorized_keys on a different line." >&2
exit 5
fi

View file

@ -216,7 +216,7 @@ describe('Repository PATCH by repositoryName', () => {
comment: 'Test repository',
},
]);
vi.mocked(ShellService.updateRepo).mockResolvedValue({ stderr: 'Error', stdout: '' });
vi.mocked(ShellService.updateRepo).mockRejectedValue(new Error('Failed to update repository'));
const { req, res } = createMocks({
method: 'PATCH',
query: { slug: 'a43928f3' },
@ -224,6 +224,11 @@ describe('Repository PATCH by repositoryName', () => {
});
await handler(req, res);
expect(res._getStatusCode()).toBe(500);
expect(res._getJSONData()).toEqual({
status: 500,
message: 'Failed to update repository',
});
expect(ConfigService.updateRepoList).not.toHaveBeenCalled();
});
it('should successfully update repository with a session', async () => {
@ -444,12 +449,12 @@ describe('Repository DELETE by repositoryName', () => {
comment: 'Test repository',
},
]);
vi.mocked(ShellService.deleteRepo).mockResolvedValue({ stderr: 'Error', stdout: '' });
vi.mocked(ShellService.deleteRepo).mockRejectedValue(new Error('Failed to delete repository'));
await handler(req, res);
expect(res._getStatusCode()).toBe(500);
expect(res._getJSONData()).toEqual({
status: 500,
message: 'API error, contact the administrator',
message: 'Failed to delete repository',
});
expect(ConfigService.updateRepoList).not.toHaveBeenCalled();
});

View file

@ -106,16 +106,12 @@ export default async function handler(
appendOnlyMode: appendOnlyMode ?? repo.appendOnlyMode,
};
const { stderr } = await ShellService.updateRepo(
await ShellService.updateRepo(
updatedRepo.repositoryName,
updatedRepo.sshPublicKey,
updatedRepo.storageSize,
updatedRepo.appendOnlyMode ?? false
);
if (stderr) {
console.log('Update repository error: ', stderr);
throw new Error();
}
const updatedRepoList = [...filteredRepoList, updatedRepo];
await ConfigService.updateRepoList(updatedRepoList, true);
@ -154,12 +150,7 @@ export default async function handler(
return ApiResponse.notFound(res, 'Repository with name ' + slug + ' not found');
}
const { stderr } = await ShellService.deleteRepo(repoList[indexToDelete].repositoryName);
if (stderr) {
console.log('Delete repository error: ', stderr);
return ApiResponse.serverError(res, undefined, 'Error deleting repository');
}
await ShellService.deleteRepo(repoList[indexToDelete].repositoryName);
const updatedRepoList = repoList.filter((repo) => repo.repositoryName !== slug);

View file

@ -94,14 +94,13 @@ export default async function handler(
appendOnlyMode: appendOnlyMode ?? false,
};
const { stdout, stderr } = await ShellService.createRepo(
const { stdout } = await ShellService.createRepo(
newRepo.sshPublicKey,
newRepo.storageSize,
newRepo.appendOnlyMode ?? false
);
if (stderr || !stdout) {
console.log('Create repository error: ', stderr);
throw new Error(stderr || 'Unknown error occurred while creating the repository');
if (!stdout) {
return ApiResponse.serverError(res, 'Error creating repository');
}
newRepo.repositoryName = stdout.trim();