Bundles several in-progress efforts that were sitting uncommitted: - User queue-preferences (migration 087, API route, popover component) - QBO invoice soft-delete (migration 088) and AR diagnostics route - Dashboard/mobile engagement route and page adjustments - Docker Compose log-rotation config - One-off ticket/RMM investigation scripts (scripts/) - Planning docs: phase verification/pattern notes, mobile shell design spec - .gitignore: exclude local scratch financial/inventory data and Claude Code worktree/local-settings runtime state (never meant for version control) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6RuWdiUiXrPK6FLBHjtpY
94 lines
3.5 KiB
TypeScript
94 lines
3.5 KiB
TypeScript
/**
|
|
* verify-guardian-protection-mimecast.ts
|
|
*
|
|
* Ticket 699687 (Tomlinson, Seubert) — an accidental phishing report of a
|
|
* genuine Guardian Protection (alarm.com-platform) home-security notification
|
|
* ("The Front Door was left unlocked"). The forwarded/reported copy's
|
|
* primary Authentication-Results shows spf=fail/dkim=fail/dmarc=fail (a
|
|
* known forwarding artifact — see authResultsOriginal), while the pre-
|
|
* forwarding authResultsOriginal shows all-pass. Before concluding Guardian
|
|
* Protection has bad email hygiene, independently verify against Mimecast's
|
|
* own real-time record of this exact message at Seubert's tenant.
|
|
*
|
|
* Usage:
|
|
* npx tsx scripts/verify-guardian-protection-mimecast.ts
|
|
*/
|
|
|
|
import { config } from 'dotenv';
|
|
import { resolve } from 'path';
|
|
config({ path: resolve('/opt/stacks/pulse/.env.local') });
|
|
|
|
import postgresClient from '../lib/services/postgres-client';
|
|
import { getMimecastClientForTenant } from '../lib/services/mimecast-client';
|
|
|
|
const SEUBERT_COMPANY_ID = 29683407;
|
|
const SENDER = 'guardian_protection_do_not_reply@guardianprotection.com';
|
|
const RECIPIENT = 'btomlinson@seubert.com';
|
|
const MESSAGE_ID = '<d12e6a25451a7f6dddac51480c302bef@guardianprotection.com>';
|
|
|
|
async function main() {
|
|
const tenantRow = await postgresClient.query<{
|
|
client_id: string;
|
|
client_secret: string;
|
|
base_url: string | null;
|
|
account_name: string | null;
|
|
}>(
|
|
`SELECT client_id, client_secret, base_url, account_name FROM mimecast_tenants WHERE company_id = $1 AND enabled = true`,
|
|
[SEUBERT_COMPANY_ID]
|
|
);
|
|
const tenant = tenantRow.rows[0];
|
|
if (!tenant) {
|
|
console.log('No enabled Mimecast tenant for Seubert — cannot verify.');
|
|
process.exit(1);
|
|
}
|
|
console.log(`Using Mimecast tenant: ${tenant.account_name}`);
|
|
|
|
const client = getMimecastClientForTenant({
|
|
client_id: tenant.client_id,
|
|
client_secret: tenant.client_secret,
|
|
base_url: tenant.base_url ?? undefined,
|
|
});
|
|
|
|
const now = new Date();
|
|
const start = new Date(now.getTime() - 3 * 24 * 60 * 60 * 1000);
|
|
const startStr = start.toISOString().replace(/\.\d{3}Z$/, '+0000');
|
|
const endStr = now.toISOString().replace(/\.\d{3}Z$/, '+0000');
|
|
|
|
console.log(`\n=== 1. Exact sender+recipient match, Mimecast's own trace ===`);
|
|
const exact = await client.searchDeliveredMessages({
|
|
from: SENDER,
|
|
to: RECIPIENT,
|
|
start: startStr,
|
|
end: endStr,
|
|
});
|
|
console.log(JSON.stringify(exact, null, 2));
|
|
|
|
console.log(`\n=== 2. getMessageInfo by Message-ID ===`);
|
|
try {
|
|
const info = await client.getMessageInfo(MESSAGE_ID);
|
|
console.log(JSON.stringify(info, null, 2));
|
|
} catch (err) {
|
|
console.log('getMessageInfo failed:', err instanceof Error ? err.message : err);
|
|
}
|
|
|
|
console.log(`\n=== 3. Held messages for Tomlinson ===`);
|
|
const held = await client.getHeldMessages({ recipient: RECIPIENT });
|
|
console.log(JSON.stringify(held, null, 2));
|
|
|
|
console.log(`\n=== 4. Recent threat events mentioning guardianprotection.com or alarm.com ===`);
|
|
const threats = await client.getThreatEvents({ pageSize: 500 });
|
|
const relevant = threats.items.filter((t) =>
|
|
(t.actorEmail ?? '').toLowerCase().includes('guardianprotection.com') ||
|
|
(t.actorEmail ?? '').toLowerCase().includes('alarm.com')
|
|
);
|
|
console.log(`Total threat events fetched: ${threats.items.length}`);
|
|
console.log(`Events involving guardianprotection.com/alarm.com: ${relevant.length}`);
|
|
console.log(JSON.stringify(relevant, null, 2));
|
|
|
|
process.exit(0);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|