diff --git a/forge/forge.js b/forge/forge.js index 4147da6e68..c055961817 100644 --- a/forge/forge.js +++ b/forge/forge.js @@ -85,16 +85,40 @@ module.exports = async (options = {}) => { level: runtimeConfig.logging.level, serializers: { res (reply) { - return { + const response = { statusCode: reply.statusCode, request: { user: reply.request?.session?.User?.username, + ownerId: undefined, + ownerType: undefined, url: reply.request?.raw?.url, method: reply.request?.method, remoteAddress: reply.request?.ip, remotePort: reply.request?.socket.remotePort } } + if (reply.request?.session?.ownerType) { + switch (reply.request?.session?.ownerType) { + case 'team': + response.request.ownerId = server.db.models.Team.encodeHashid(reply.request?.session?.ownerId) + response.request.ownerType = 'team' + break + case 'device': + response.request.ownerId = server.db.models.Device.encodeHashid(reply.request?.session?.ownerId) + response.request.ownerType = 'device' + break + case 'project': + case 'instance': + response.request.ownerId = reply.request?.session?.ownerId + response.request.ownerType = reply.request?.session?.ownerType + break + default: + // Don't log the id as we don't know how to hash it + // Log the type so we can spot cases we aren't handling and address it + response.request.ownerType = reply.request?.session?.ownerType + } + } + return response } } } diff --git a/forge/routes/api/assistant.js b/forge/routes/api/assistant.js index 658159cac0..27d51d5eea 100644 --- a/forge/routes/api/assistant.js +++ b/forge/routes/api/assistant.js @@ -63,6 +63,22 @@ module.exports = async function (app) { // post to the assistant service const headers = {} + if (request.session?.ownerType) { + switch (request.session.ownerType) { + case 'team': + headers['ff-owner-type'] = 'team' + headers['ff-owner-id'] = app.db.models.Team.encodeHashid(request.session.ownerId) + break + case 'device': + headers['ff-owner-type'] = 'device' + headers['ff-owner-id'] = app.db.models.Device.encodeHashid(request.session.ownerId) + break + case 'project': + case 'instance': + headers['ff-owner-type'] = request.session.ownerType + headers['ff-owner-id'] = request.session.ownerId + } + } if (serviceToken) { headers.Authorization = `Bearer ${serviceToken}` } diff --git a/test/unit/forge/routes/api/assistant_spec.js b/test/unit/forge/routes/api/assistant_spec.js index 8afd479020..5580f2e340 100644 --- a/test/unit/forge/routes/api/assistant_spec.js +++ b/test/unit/forge/routes/api/assistant_spec.js @@ -192,6 +192,34 @@ describe('Assistant API', async function () { }) response.statusCode.should.equal(400) }) + it('contains owner info in headers for an instance', async function () { + sinon.stub(axios, 'post').resolves({ data: { status: 'ok' } }) + await app.inject({ + method: 'POST', + url: `/api/v1/assistant/${serviceName}`, + headers: { authorization: 'Bearer ' + TestObjects.tokens.instance }, + payload: { prompt: 'multiply by 5', transactionId: '1234' } + }) + axios.post.calledOnce.should.be.true() + axios.post.args[0][2].headers.should.have.properties({ + 'ff-owner-type': 'project', + 'ff-owner-id': TestObjects.instance.id + }) + }) + it('contains owner info in headers for a device', async function () { + sinon.stub(axios, 'post').resolves({ data: { status: 'ok' } }) + await app.inject({ + method: 'POST', + url: `/api/v1/assistant/${serviceName}`, + headers: { authorization: 'Bearer ' + TestObjects.tokens.device }, + payload: { prompt: 'multiply by 5', transactionId: '1234' } + }) + axios.post.calledOnce.should.be.true() + axios.post.args[0][2].headers.should.have.properties({ + 'ff-owner-type': 'device', + 'ff-owner-id': TestObjects.device.hashid + }) + }) } describe('function service', async function () { serviceTests('function')