Compute cache keys from tokens instead of user entity refs
Signed-off-by: Joe Porpeglia <josephp@spotify.com>
This commit is contained in:
committed by
Joe Porpeglia
parent
e9857d0b82
commit
f1918143e5
@@ -16,13 +16,7 @@
|
||||
import { CachedEntityLoader } from './CachedEntityLoader';
|
||||
import { CatalogClient } from '@backstage/catalog-client';
|
||||
import { CacheClient } from '@backstage/backend-common';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import {
|
||||
BackstageIdentityResponse,
|
||||
IdentityClient,
|
||||
} from '@backstage/plugin-auth-backend';
|
||||
import { EntityName } from '@backstage/catalog-model';
|
||||
import { Response } from 'cross-fetch';
|
||||
|
||||
describe('CachedEntityLoader', () => {
|
||||
const catalog: jest.Mocked<CatalogClient> = {
|
||||
@@ -34,10 +28,6 @@ describe('CachedEntityLoader', () => {
|
||||
set: jest.fn(),
|
||||
} as any;
|
||||
|
||||
const identity: jest.Mocked<IdentityClient> = {
|
||||
authenticate: jest.fn(),
|
||||
} as any;
|
||||
|
||||
const entityName: EntityName = {
|
||||
kind: 'component',
|
||||
namespace: 'default',
|
||||
@@ -55,24 +45,13 @@ describe('CachedEntityLoader', () => {
|
||||
|
||||
const token = 'test-token';
|
||||
|
||||
const identityResponse: BackstageIdentityResponse = {
|
||||
id: '',
|
||||
token,
|
||||
identity: {
|
||||
type: 'user',
|
||||
userEntityRef: 'user:default/test-user',
|
||||
ownershipEntityRefs: [],
|
||||
},
|
||||
};
|
||||
|
||||
const loader = new CachedEntityLoader({ catalog, cache, identity });
|
||||
const loader = new CachedEntityLoader({ catalog, cache });
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('writes entities to cache', async () => {
|
||||
identity.authenticate.mockResolvedValue(identityResponse);
|
||||
cache.get.mockResolvedValue(undefined);
|
||||
catalog.getEntityByName.mockResolvedValue(entity);
|
||||
|
||||
@@ -80,14 +59,13 @@ describe('CachedEntityLoader', () => {
|
||||
|
||||
expect(result).toEqual(entity);
|
||||
expect(cache.set).toBeCalledWith(
|
||||
'catalog:component:default/test:user:default/test-user',
|
||||
'catalog:component:default/test:test-token',
|
||||
entity,
|
||||
{ ttl: 5000 },
|
||||
);
|
||||
});
|
||||
|
||||
it('returns entities from cache', async () => {
|
||||
identity.authenticate.mockResolvedValue(identityResponse);
|
||||
cache.get.mockResolvedValue(entity);
|
||||
|
||||
const result = await loader.load(entityName, token);
|
||||
@@ -97,7 +75,6 @@ describe('CachedEntityLoader', () => {
|
||||
});
|
||||
|
||||
it('does not cache missing entites', async () => {
|
||||
identity.authenticate.mockResolvedValue(identityResponse);
|
||||
cache.get.mockResolvedValue(undefined);
|
||||
catalog.getEntityByName.mockResolvedValue(undefined);
|
||||
|
||||
@@ -120,7 +97,6 @@ describe('CachedEntityLoader', () => {
|
||||
});
|
||||
|
||||
it('calls the catalog if the cache read takes too long', async () => {
|
||||
identity.authenticate.mockResolvedValue(identityResponse);
|
||||
cache.get.mockImplementation(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
|
||||
@@ -20,24 +20,20 @@ import {
|
||||
EntityName,
|
||||
stringifyEntityRef,
|
||||
} from '@backstage/catalog-model';
|
||||
import { IdentityClient } from '@backstage/plugin-auth-backend';
|
||||
|
||||
export type CachedEntityLoaderOptions = {
|
||||
catalog: CatalogClient;
|
||||
cache: CacheClient;
|
||||
identity: IdentityClient;
|
||||
};
|
||||
|
||||
export class CachedEntityLoader {
|
||||
private readonly catalog: CatalogClient;
|
||||
private readonly cache: CacheClient;
|
||||
private readonly identity: IdentityClient;
|
||||
private readonly readTimeout = 1000;
|
||||
|
||||
constructor({ catalog, cache, identity }: CachedEntityLoaderOptions) {
|
||||
constructor({ catalog, cache }: CachedEntityLoaderOptions) {
|
||||
this.catalog = catalog;
|
||||
this.cache = cache;
|
||||
this.identity = identity;
|
||||
}
|
||||
|
||||
async load(
|
||||
@@ -73,12 +69,10 @@ export class CachedEntityLoader {
|
||||
entityName: EntityName,
|
||||
token: string | undefined,
|
||||
): Promise<string> {
|
||||
const key = ['catalog'];
|
||||
key.push(stringifyEntityRef(entityName));
|
||||
const key = ['catalog', stringifyEntityRef(entityName)];
|
||||
|
||||
if (token) {
|
||||
const response = await this.identity.authenticate(token);
|
||||
key.push(response.identity.userEntityRef);
|
||||
key.push(token);
|
||||
}
|
||||
|
||||
return key.join(':');
|
||||
|
||||
@@ -35,7 +35,6 @@ import { ScmIntegrations } from '@backstage/integration';
|
||||
import { DocsSynchronizer, DocsSynchronizerSyncOpts } from './DocsSynchronizer';
|
||||
import { createCacheMiddleware, TechDocsCache } from '../cache';
|
||||
import { CachedEntityLoader } from './CachedEntityLoader';
|
||||
import { IdentityClient } from '@backstage/plugin-auth-backend';
|
||||
|
||||
/**
|
||||
* All of the required dependencies for running TechDocs in the "out-of-the-box"
|
||||
@@ -87,17 +86,12 @@ export async function createRouter(
|
||||
const router = Router();
|
||||
const { publisher, config, logger, discovery } = options;
|
||||
const catalogClient = new CatalogClient({ discoveryApi: discovery });
|
||||
const identity = new IdentityClient({
|
||||
discovery,
|
||||
issuer: await discovery.getBaseUrl('auth'),
|
||||
});
|
||||
|
||||
// Entities are cached to optimize the /static/docs request path, which can be called many times
|
||||
// when loading a single techdocs page.
|
||||
const entityLoader = new CachedEntityLoader({
|
||||
catalog: catalogClient,
|
||||
cache: options.cache.getClient(),
|
||||
identity,
|
||||
});
|
||||
|
||||
// Set up a cache client if configured.
|
||||
|
||||
Reference in New Issue
Block a user