fix(#377): remediate code review and security findings
Some checks failed
ci/woodpecker/push/infra Pipeline was successful
ci/woodpecker/push/api Pipeline failed

- Fix sendThreadMessage room mismatch: use channelId from options instead of hardcoded controlRoomId
- Add .catch() to fire-and-forget handleRoomMessage to prevent silent error swallowing
- Wrap dispatchJob in try-catch for user-visible error reporting in handleFixCommand
- Add MATRIX_BOT_USER_ID validation in connect() to prevent infinite message loops
- Fix streamResponse error masking: wrap finally/catch side-effects in try-catch
- Replace unsafe type assertion with public getClient() in MatrixRoomService
- Add orphaned room warning in provisionRoom on DB failure
- Add provider identity to Herald error logs
- Add channelId to ThreadMessageOptions interface and all callers
- Add missing env var warnings in BridgeModule factory
- Fix JSON injection in setup-bot.sh: use jq for safe JSON construction

Fixes #377

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 03:00:53 -06:00
parent a1f0d1dd71
commit 8d19ac1f4b
13 changed files with 179 additions and 76 deletions

View File

@@ -486,9 +486,9 @@ describe("Matrix Bridge Integration Tests", () => {
})
);
// Confirmation message sent as thread reply
// Confirmation message sent as thread reply (uses channelId from message, not hardcoded controlRoomId)
const confirmationCall = sendCalls[1];
expect(confirmationCall?.[0]).toBe("!control-room:example.com");
expect(confirmationCall?.[0]).toBe("!room:example.com");
expect(confirmationCall?.[1]).toEqual(
expect.objectContaining({
body: expect.stringContaining("Job created: job-integ-001"),
@@ -519,7 +519,7 @@ describe("Matrix Bridge Integration Tests", () => {
setMatrixEnv();
// Create a connected mock MatrixService that tracks sendThreadMessage calls
const threadMessages: Array<{ threadId: string; content: string }> = [];
const threadMessages: Array<{ threadId: string; channelId: string; content: string }> = [];
const mockMatrixProvider: IChatProvider = {
connect: vi.fn().mockResolvedValue(undefined),
disconnect: vi.fn().mockResolvedValue(undefined),
@@ -527,7 +527,7 @@ describe("Matrix Bridge Integration Tests", () => {
sendMessage: vi.fn().mockResolvedValue(undefined),
createThread: vi.fn().mockResolvedValue("$thread-id"),
sendThreadMessage: vi.fn().mockImplementation(async (options) => {
threadMessages.push(options as { threadId: string; content: string });
threadMessages.push(options as { threadId: string; channelId: string; content: string });
}),
parseCommand: vi.fn().mockReturnValue(null),
};
@@ -545,6 +545,7 @@ describe("Matrix Bridge Integration Tests", () => {
payload: {
metadata: {
threadId: "$thread-herald-root",
channelId: "!herald-room:example.com",
issueNumber: 55,
},
},
@@ -617,6 +618,7 @@ describe("Matrix Bridge Integration Tests", () => {
payload: {
metadata: {
threadId: "$thread-skip",
channelId: "!skip-room:example.com",
issueNumber: 1,
},
},
@@ -689,6 +691,7 @@ describe("Matrix Bridge Integration Tests", () => {
payload: {
metadata: {
threadId: "$thread-err",
channelId: "!err-room:example.com",
issueNumber: 77,
},
},