diff --git a/.changeset/mean-rice-beg.md b/.changeset/mean-rice-beg.md new file mode 100644 index 0000000000..19cef51292 --- /dev/null +++ b/.changeset/mean-rice-beg.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-vault': patch +--- + +Use `fetchApi` instead of raw `fetch` in order to pass auth header if necessary. diff --git a/plugins/vault/src/api.test.ts b/plugins/vault/src/api.test.ts index 471cadc87e..ec88412303 100644 --- a/plugins/vault/src/api.test.ts +++ b/plugins/vault/src/api.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { setupRequestMockHandlers } from '@backstage/test-utils'; +import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { VaultSecret, VaultClient } from './api'; @@ -26,6 +26,7 @@ describe('api', () => { const mockBaseUrl = 'https://api-vault.com/api/vault'; const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); + const fetchApi = new MockFetchApi(); const mockSecretsResult: { items: VaultSecret[] } = { items: [ @@ -65,7 +66,7 @@ describe('api', () => { it('should return secrets', async () => { setupHandlers(); - const api = new VaultClient({ discoveryApi }); + const api = new VaultClient({ discoveryApi, fetchApi }); expect(await api.listSecrets('test/success')).toEqual( mockSecretsResult.items, ); @@ -73,19 +74,19 @@ describe('api', () => { it('should return empty secret list', async () => { setupHandlers(); - const api = new VaultClient({ discoveryApi }); + const api = new VaultClient({ discoveryApi, fetchApi }); expect(await api.listSecrets('test/empty')).toEqual([]); }); it('should return all the secrets if no path defined', async () => { setupHandlers(); - const api = new VaultClient({ discoveryApi }); + const api = new VaultClient({ discoveryApi, fetchApi }); 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 }); + const api = new VaultClient({ discoveryApi, fetchApi }); await expect(api.listSecrets('test/not-found')).rejects.toThrow( "No secrets found in path 'v1/secrets/test%2Fnot-found'", ); @@ -93,7 +94,7 @@ describe('api', () => { it('should throw an error if the Vault API responds with a non-successful HTTP status code', async () => { setupHandlers(); - const api = new VaultClient({ discoveryApi }); + const api = new VaultClient({ discoveryApi, fetchApi }); await expect(api.listSecrets('test/error')).rejects.toThrow( 'Request failed with 400 Error', ); diff --git a/plugins/vault/src/api.ts b/plugins/vault/src/api.ts index 84843c9176..d924336a2e 100644 --- a/plugins/vault/src/api.ts +++ b/plugins/vault/src/api.ts @@ -13,7 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { DiscoveryApi, createApiRef } from '@backstage/core-plugin-api'; +import { + DiscoveryApi, + createApiRef, + FetchApi, +} from '@backstage/core-plugin-api'; import { NotFoundError, ResponseError } from '@backstage/errors'; /** @@ -52,9 +56,17 @@ export interface VaultApi { */ export class VaultClient implements VaultApi { private readonly discoveryApi: DiscoveryApi; + private readonly fetchApi: FetchApi; - constructor({ discoveryApi }: { discoveryApi: DiscoveryApi }) { + constructor({ + discoveryApi, + fetchApi, + }: { + discoveryApi: DiscoveryApi; + fetchApi: FetchApi; + }) { this.discoveryApi = discoveryApi; + this.fetchApi = fetchApi; } private async callApi( @@ -62,7 +74,7 @@ export class VaultClient implements VaultApi { query: { [key in string]: any }, ): Promise { const apiUrl = `${await this.discoveryApi.getBaseUrl('vault')}`; - const response = await fetch( + const response = await this.fetchApi.fetch( `${apiUrl}/${path}?${new URLSearchParams(query).toString()}`, { headers: { diff --git a/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.test.tsx b/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.test.tsx index 27cc0ed91e..e5bd5b43de 100644 --- a/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.test.tsx +++ b/plugins/vault/src/components/EntityVaultTable/EntityVaultTable.test.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { setupServer } from 'msw/node'; import { + MockFetchApi, setupRequestMockHandlers, TestApiRegistry, } from '@backstage/test-utils'; @@ -33,6 +34,8 @@ describe('EntityVaultTable', () => { let apis: TestApiRegistry; const mockBaseUrl = 'https://api-vault.com/api/vault'; const discoveryApi = UrlPatternDiscovery.compile(mockBaseUrl); + const fetchApi = new MockFetchApi(); + const entity = (secretPath: string) => { return { apiVersion: 'backstage.io/v1alpha1', @@ -90,7 +93,7 @@ describe('EntityVaultTable', () => { beforeEach(() => { apis = TestApiRegistry.from([ vaultApiRef, - new VaultClient({ discoveryApi }), + new VaultClient({ discoveryApi, fetchApi }), ]); }); diff --git a/plugins/vault/src/plugin.ts b/plugins/vault/src/plugin.ts index 8275505abb..f62a8a73e4 100644 --- a/plugins/vault/src/plugin.ts +++ b/plugins/vault/src/plugin.ts @@ -19,9 +19,11 @@ import { createPlugin, DiscoveryApi, discoveryApiRef, + FetchApi, + fetchApiRef, } from '@backstage/core-plugin-api'; -import { VaultClient, vaultApiRef } from './api'; +import { vaultApiRef, VaultClient } from './api'; /** * The vault plugin. @@ -32,10 +34,17 @@ export const vaultPlugin = createPlugin({ apis: [ createApiFactory({ api: vaultApiRef, - deps: { discoveryApi: discoveryApiRef }, - factory: ({ discoveryApi }: { discoveryApi: DiscoveryApi }) => + deps: { discoveryApi: discoveryApiRef, fetchApi: fetchApiRef }, + factory: ({ + discoveryApi, + fetchApi, + }: { + discoveryApi: DiscoveryApi; + fetchApi: FetchApi; + }) => new VaultClient({ discoveryApi, + fetchApi, }), }), ],