/**
 * P0-2 smoke test — webhook channel and synthetic-test runner refuse to
 * connect to cloud-metadata / loopback / RFC1918 destinations.
 *
 * Run: npx tsx scripts/smoke/p0-2-ssrf.ts
 *
 * Offline-safe: drives the safeOutboundFetch helper and WebhookChannel
 * directly. No HTTP requests leave the box.
 */
import { ok, fail } from './_lib';
import { safeOutboundFetch } from '../../src/lib/network-security/safe-fetch';
import { BlockedHostError } from '../../src/lib/network-security/ssrf-guard';
import { WebhookChannel } from '../../src/lib/notification-system/channels/webhook.channel';

async function expectBlocked(label: string, url: string): Promise<void> {
    try {
        await safeOutboundFetch(url);
        fail(label, `expected BlockedHostError, got success against ${url}`);
    } catch (err) {
        if (err instanceof BlockedHostError) {
            ok(label, `${url} rejected as ${err.message}`);
            return;
        }
        fail(label, `expected BlockedHostError, got ${String(err)}`);
    }
}

async function main(): Promise<void> {
    // ALLOW_PRIVATE_NETWORK should not relax the cloud-metadata block.
    const original = process.env.ALLOW_PRIVATE_NETWORK;
    process.env.ALLOW_PRIVATE_NETWORK = 'true';
    try {
        await expectBlocked(
            'AWS IMDS blocked even with ALLOW_PRIVATE_NETWORK',
            'http://169.254.169.254/latest/meta-data/iam/security-credentials/'
        );
        await expectBlocked(
            'GCP metadata blocked even with ALLOW_PRIVATE_NETWORK',
            'http://metadata.google.internal/'
        );
    } finally {
        if (original === undefined) delete process.env.ALLOW_PRIVATE_NETWORK;
        else process.env.ALLOW_PRIVATE_NETWORK = original;
    }

    // Default mode rejects loopback / private nets.
    delete process.env.ALLOW_PRIVATE_NETWORK;
    await expectBlocked('loopback blocked', 'http://127.0.0.1:8080/');
    await expectBlocked('RFC1918 blocked', 'http://10.10.10.10/');
    await expectBlocked('IPv6 loopback blocked', 'http://[::1]/');
    await expectBlocked('non-http(s) scheme blocked', 'file:///etc/passwd');

    // WebhookChannel.sendOrThrow surfaces BlockedHostError.
    const channel = new WebhookChannel();
    try {
        await channel.sendOrThrow('test message', {
            webhookUrl: 'http://169.254.169.254/exfiltrate',
        });
        fail('WebhookChannel rejects IMDS', 'expected throw, got success');
    } catch (err) {
        if (err instanceof BlockedHostError) {
            ok('WebhookChannel rejects IMDS', err.message);
        } else {
            fail(
                'WebhookChannel rejects IMDS',
                `expected BlockedHostError, got ${String(err)}`
            );
        }
    }

    ok('P0-2 ssrf', 'all guard paths reject private/loopback/metadata destinations');
}

main().catch((err) => fail('P0-2 ssrf', String(err)));
