Skip to main content
Glama
auditevent.test.ts4.21 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import type { WithId } from '@medplum/core'; import type { AuditEvent, Bot, Observation, ProjectMembership } from '@medplum/fhirtypes'; import 'aws-sdk-client-mock-jest'; import { randomUUID } from 'node:crypto'; import type { BotExecutionRequest } from '../bots/types'; import { loadTestConfig } from '../config/loader'; import { AuditEventOutcome, createAuditEvent, createBotAuditEvent, CreateInteraction, logAuditEvent, RestfulOperationType, } from './auditevent'; describe('AuditEvent utils', () => { test('AuditEvents disabled', async () => { console.info = jest.fn(); console.log = jest.fn(); const config = await loadTestConfig(); config.logAuditEvents = false; logAuditEvent({ resourceType: 'AuditEvent' } as AuditEvent); expect(console.info).not.toHaveBeenCalled(); expect(console.log).not.toHaveBeenCalled(); }); test('AuditEvent to console.log', async () => { console.log = jest.fn(); const config = await loadTestConfig(); config.logAuditEvents = true; // Log an AuditEvent logAuditEvent({ resourceType: 'AuditEvent' } as AuditEvent); // It should have been logged expect(console.log).toHaveBeenCalledWith('{"resourceType":"AuditEvent"}'); }); test('Redacts display text when config flag set', async () => { console.log = jest.fn(); const config = await loadTestConfig(); config.logAuditEvents = true; config.redactAuditEvents = true; const resource: Observation = { resourceType: 'Observation', id: randomUUID(), status: 'final', code: { text: 'HIV Test' }, }; // Log an AuditEvent const auditEvent = createAuditEvent( RestfulOperationType, CreateInteraction, randomUUID(), { reference: 'Practitioner/123', display: 'Test User' }, undefined, AuditEventOutcome.Success, { resource } ); logAuditEvent(auditEvent); // It should have been logged expect(console.log).toHaveBeenCalledTimes(1); const auditLog = (console.log as jest.Mock).mock.calls[0][0]; expect(auditLog).toContain(`{"resourceType":"AuditEvent",`); expect(auditLog).not.toContain('HIV'); expect(auditLog).not.toContain('Test'); expect(auditLog).not.toContain('User'); }); test.each<Bot['auditEventTrigger']>(['never', 'on-error', 'on-output'])( 'Skips creating audit event with `%s` trigger', async (trigger) => { const bot: WithId<Bot> = { resourceType: 'Bot', id: randomUUID(), auditEventTrigger: trigger, auditEventDestination: ['log'], }; const runAs: WithId<ProjectMembership> = { resourceType: 'ProjectMembership', id: randomUUID(), project: { reference: `Project/${randomUUID()}` }, user: { reference: `User/${randomUUID()}` }, profile: { reference: `Practitioner/${randomUUID()}` }, }; const req: BotExecutionRequest = { bot, runAs, input: 'foo', contentType: 'text/plain' }; // Successful execution with no output won't trigger on-error or on-output console.log = jest.fn(); await createBotAuditEvent(req, new Date().toISOString(), AuditEventOutcome.Success, ''); expect(console.log).not.toHaveBeenCalled(); } ); test('Logs Bot output', async () => { const bot: WithId<Bot> = { resourceType: 'Bot', id: randomUUID(), auditEventTrigger: 'on-output', auditEventDestination: ['log'], }; const runAs: WithId<ProjectMembership> = { resourceType: 'ProjectMembership', id: randomUUID(), project: { reference: `Project/${randomUUID()}` }, user: { reference: `User/${randomUUID()}` }, profile: { reference: `Practitioner/${randomUUID()}` }, }; const req: BotExecutionRequest = { bot, runAs, input: 'foo', contentType: 'text/plain' }; console.log = jest.fn(); await createBotAuditEvent(req, new Date().toISOString(), AuditEventOutcome.Success, 'foo'); expect(console.log).toHaveBeenCalledWith(expect.stringContaining(`,"outcomeDesc":"foo"`)); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server