improve Vault plugin error messaging
This seeks to address issue #16176 by improving the error messaging surfaced to the UI with the Vault plugin encounters non-successful HTTP responses from the Vault API. Signed-off-by: Mike Ball <mikedball@gmail.com>
This commit is contained in:
@@ -50,8 +50,10 @@ describe('api', () => {
|
||||
const { path } = req.params;
|
||||
if (path === 'test/success') {
|
||||
return res(ctx.json(mockSecretsResult));
|
||||
} else if (path === 'test/error') {
|
||||
} else if (path === 'test/empty') {
|
||||
return res(ctx.json({ items: [] }));
|
||||
} else if (path === 'test/not-found') {
|
||||
return res(ctx.status(404));
|
||||
}
|
||||
return res(ctx.status(400));
|
||||
}),
|
||||
@@ -72,7 +74,7 @@ describe('api', () => {
|
||||
it('should return empty secret list', async () => {
|
||||
setupHandlers();
|
||||
const api = new VaultClient({ discoveryApi });
|
||||
expect(await api.listSecrets('test/error')).toEqual([]);
|
||||
expect(await api.listSecrets('test/empty')).toEqual([]);
|
||||
});
|
||||
|
||||
it('should return all the secrets if no path defined', async () => {
|
||||
@@ -80,4 +82,20 @@ describe('api', () => {
|
||||
const api = new VaultClient({ discoveryApi });
|
||||
expect(await api.listSecrets('')).toEqual(mockSecretsResult.items);
|
||||
});
|
||||
|
||||
it('should throw an error if the Vault API responds with an HTTP 404', async () => {
|
||||
setupHandlers();
|
||||
const api = new VaultClient({ discoveryApi });
|
||||
await expect(api.listSecrets('test/not-found')).rejects.toThrow(
|
||||
"No secrets found in path 'v1/secrets/test%2Fnot-found'",
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw an error if the Vault API responds with a non-successful HTTP status code', async () => {
|
||||
setupHandlers();
|
||||
const api = new VaultClient({ discoveryApi });
|
||||
await expect(api.listSecrets('test/error')).rejects.toThrow(
|
||||
'Request failed with 400 Error',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { DiscoveryApi, createApiRef } from '@backstage/core-plugin-api';
|
||||
import { NotFoundError } from '@backstage/errors';
|
||||
import { NotFoundError, ResponseError } from '@backstage/errors';
|
||||
|
||||
/**
|
||||
* @public
|
||||
@@ -75,9 +75,7 @@ export class VaultClient implements VaultApi {
|
||||
} else if (response.status === 404) {
|
||||
throw new NotFoundError(`No secrets found in path '${path}'`);
|
||||
}
|
||||
throw new Error(
|
||||
`Unexpected error while fetching secrets from path '${path}'`,
|
||||
);
|
||||
throw await ResponseError.fromResponse(response);
|
||||
}
|
||||
|
||||
async listSecrets(secretPath: string): Promise<VaultSecret[]> {
|
||||
|
||||
@@ -33,40 +33,28 @@ describe('EntityVaultTable', () => {
|
||||
let apis: TestApiRegistry;
|
||||
const mockBaseUrl = 'https://api-vault.com/api/vault';
|
||||
const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl);
|
||||
|
||||
const entityOk: ComponentEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test',
|
||||
description: 'This is the description',
|
||||
annotations: {
|
||||
'vault.io/secrets-path': 'test/success',
|
||||
const entity = (secretPath: string) => {
|
||||
return {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test',
|
||||
description: 'This is the description',
|
||||
annotations: {
|
||||
'vault.io/secrets-path': secretPath,
|
||||
},
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
lifecycle: 'production',
|
||||
owner: 'owner',
|
||||
type: 'service',
|
||||
},
|
||||
spec: {
|
||||
lifecycle: 'production',
|
||||
owner: 'owner',
|
||||
type: 'service',
|
||||
},
|
||||
} as ComponentEntity;
|
||||
};
|
||||
|
||||
const entityNotOk: ComponentEntity = {
|
||||
apiVersion: 'backstage.io/v1alpha1',
|
||||
kind: 'Component',
|
||||
metadata: {
|
||||
name: 'test',
|
||||
description: 'This is the description',
|
||||
annotations: {
|
||||
'vault.io/secrets-path': 'test/error',
|
||||
},
|
||||
},
|
||||
spec: {
|
||||
lifecycle: 'production',
|
||||
owner: 'owner',
|
||||
type: 'service',
|
||||
},
|
||||
};
|
||||
const entityOk = entity('test/success');
|
||||
const entityEmpty = entity('test/empty');
|
||||
const entityNotOk = entity('test/error');
|
||||
|
||||
const mockSecretsResult: { items: VaultSecret[] } = {
|
||||
items: [
|
||||
@@ -91,7 +79,7 @@ describe('EntityVaultTable', () => {
|
||||
const { path } = req.params;
|
||||
if (path === 'test/success') {
|
||||
return res(ctx.json(mockSecretsResult));
|
||||
} else if (path === 'test/error') {
|
||||
} else if (path === 'test/empty') {
|
||||
return res(ctx.json([]));
|
||||
}
|
||||
return res(ctx.status(400));
|
||||
@@ -122,10 +110,25 @@ describe('EntityVaultTable', () => {
|
||||
setupHandlers();
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider apis={apis}>
|
||||
<EntityVaultTable entity={entityNotOk} />
|
||||
<EntityVaultTable entity={entityEmpty} />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
expect(rendered.getByText(/No secrets found/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should surface an appropriate error when the Vault API responds unsuccessfully', async () => {
|
||||
setupHandlers();
|
||||
const rendered = await renderInTestApp(
|
||||
<ApiProvider apis={apis}>
|
||||
<EntityVaultTable entity={entityNotOk} />
|
||||
</ApiProvider>,
|
||||
);
|
||||
|
||||
expect(
|
||||
rendered.getByText(
|
||||
/Unexpected error while fetching secrets from path \'test\/error\'\: Request failed with 400 Error/,
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -81,7 +81,12 @@ export const EntityVaultTable = ({ entity }: { entity: Entity }) => {
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return <Alert severity="error">{error.message}</Alert>;
|
||||
return (
|
||||
<Alert severity="error">
|
||||
Unexpected error while fetching secrets from path '{secretPath}':{' '}
|
||||
{error.message}
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user