fix: load app config on remaining retention-relevant routes

The messages routes (branch, artifact, post), share-link create/patch, and
the agent chat-abort route read req.config.interfaceConfig but never ran
configMiddleware, so req.config was undefined and retention was skipped.
Under ephemeral (and all) this let branched/edited/aborted messages and
shared links persist without isTemporary/expiredAt, outliving the chat.

Apply configMiddleware to those routes so retention is enforced
consistently. Add a getSharedLinkExpiration ephemeral test and keep route
test middleware mocks in sync.
This commit is contained in:
Marco Beretta 2026-06-17 16:04:37 +02:00
parent 5d85b6b26e
commit 03d79523da
No known key found for this signature in database
GPG key ID: D918033D8E74CC11
2 changed files with 19 additions and 3 deletions

View file

@ -109,7 +109,7 @@ router.get('/', async (req, res) => {
* @param {string} req.body.agentId - The agentId to filter content by
* @returns {TMessage} The newly created branch message
*/
router.post('/branch', async (req, res) => {
router.post('/branch', configMiddleware, async (req, res) => {
try {
const { messageId, agentId } = req.body;
const userId = req.user.id;
@ -190,7 +190,7 @@ router.post('/branch', async (req, res) => {
}
});
router.post('/artifact/:messageId', async (req, res) => {
router.post('/artifact/:messageId', configMiddleware, async (req, res) => {
try {
const { messageId } = req.params;
const { index, original, updated } = req.body;
@ -283,7 +283,7 @@ router.get('/:conversationId', validateMessageReq, async (req, res) => {
}
});
router.post('/:conversationId', validateMessageReq, async (req, res) => {
router.post('/:conversationId', validateMessageReq, configMiddleware, async (req, res) => {
try {
const message = { ...req.body, conversationId: req.params.conversationId };
const reqCtx = {

View file

@ -394,6 +394,22 @@ describe('retention helpers', () => {
).resolves.toBe(expirationDate);
});
it('returns a fresh expiry for retentionMode EPHEMERAL conversations without an expiration', async () => {
dependencies.getConvo.mockResolvedValue({ expiredAt: null });
await expect(
getSharedLinkExpiration(
{
req: request({
config: { interfaceConfig: { retentionMode: RetentionMode.EPHEMERAL } },
}),
conversationId: 'convo-1',
},
dependencies,
),
).resolves.toBe(expirationDate);
});
it('returns an expired source conversation date so callers can reject the share', async () => {
const expiredAt = new Date(Date.now() - 60 * 60 * 1000);
dependencies.getConvo.mockResolvedValue({ expiredAt });