Add null checks in feedback processing pipeline (FRE-4514)
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -253,6 +253,18 @@ export class SpamShieldService {
|
||||
throw new Error('Feedback loop disabled via feature flag');
|
||||
}
|
||||
|
||||
if (!userId || typeof userId !== 'string' || userId.trim().length === 0) {
|
||||
throw new Error('Feedback: userId is required');
|
||||
}
|
||||
|
||||
if (!phoneNumber || typeof phoneNumber !== 'string') {
|
||||
throw new Error('Feedback: phoneNumber must be a non-empty string');
|
||||
}
|
||||
|
||||
if (typeof isSpam !== 'boolean') {
|
||||
throw new Error('Feedback: isSpam must be a boolean');
|
||||
}
|
||||
|
||||
const validated = this.validatePhoneNumber(phoneNumber);
|
||||
const encrypted = FieldEncryptionService.encrypt(validated);
|
||||
const hash = FieldEncryptionService.hashPhoneNumber(validated);
|
||||
|
||||
@@ -418,6 +418,61 @@ describe('SpamShieldService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('recordFeedback null checks', () => {
|
||||
it('throws when userId is null', async () => {
|
||||
process.env.FLAG_ENABLEFEEDBACKLOOP = 'true';
|
||||
const result = service.recordFeedback(null as any, '+14155552671', true);
|
||||
await expect(result).rejects.toThrow('Feedback: userId is required');
|
||||
});
|
||||
|
||||
it('throws when userId is empty string', async () => {
|
||||
process.env.FLAG_ENABLEFEEDBACKLOOP = 'true';
|
||||
const result = service.recordFeedback('', '+14155552671', true);
|
||||
await expect(result).rejects.toThrow('Feedback: userId is required');
|
||||
});
|
||||
|
||||
it('throws when phoneNumber is null', async () => {
|
||||
process.env.FLAG_ENABLEFEEDBACKLOOP = 'true';
|
||||
const result = service.recordFeedback('user123', null as any, true);
|
||||
await expect(result).rejects.toThrow('Feedback: phoneNumber must be a non-empty string');
|
||||
});
|
||||
|
||||
it('throws when isSpam is null', async () => {
|
||||
process.env.FLAG_ENABLEFEEDBACKLOOP = 'true';
|
||||
const result = service.recordFeedback('user123', '+14155552671', null as any);
|
||||
await expect(result).rejects.toThrow('Feedback: isSpam must be a boolean');
|
||||
});
|
||||
|
||||
it('throws when isSpam is undefined', async () => {
|
||||
process.env.FLAG_ENABLEFEEDBACKLOOP = 'true';
|
||||
const result = service.recordFeedback('user123', '+14155552671', undefined as any);
|
||||
await expect(result).rejects.toThrow('Feedback: isSpam must be a boolean');
|
||||
});
|
||||
|
||||
it('throws when userId is undefined', async () => {
|
||||
process.env.FLAG_ENABLEFEEDBACKLOOP = 'true';
|
||||
const result = service.recordFeedback(undefined as any, '+14155552671', true);
|
||||
await expect(result).rejects.toThrow('Feedback: userId is required');
|
||||
});
|
||||
|
||||
it('throws when phoneNumber is undefined', async () => {
|
||||
process.env.FLAG_ENABLEFEEDBACKLOOP = 'true';
|
||||
const result = service.recordFeedback('user123', undefined as any, true);
|
||||
await expect(result).rejects.toThrow('Feedback: phoneNumber must be a non-empty string');
|
||||
});
|
||||
|
||||
it('handles null metadata gracefully (falls back to default)', async () => {
|
||||
process.env.FLAG_ENABLEFEEDBACKLOOP = 'true';
|
||||
const result = service.recordFeedback('user123', '+14155552671', true, undefined, null as any);
|
||||
try {
|
||||
await result;
|
||||
} catch (e) {
|
||||
expect((e as Error).message).not.toContain('userId is required');
|
||||
expect((e as Error).message).not.toContain('isSpam must be a boolean');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('enableFeedbackLoop flag', () => {
|
||||
it('throws when feedback loop is disabled in recordFeedback', async () => {
|
||||
process.env.FLAG_ENABLEFEEDBACKLOOP = 'false';
|
||||
|
||||
Reference in New Issue
Block a user