/**
 * RED-GREEN tests for the insurance certificate signer.
 *
 * @connexum/ai-governance  Insurance Certificate
 */
import { describe, it } from 'node:test';
import * as assert from 'node:assert/strict';
import { issueInsuranceCertificate, verifyInsuranceCertificate, certificateFingerprint, DEFAULT_CERT_MAX_AGE_DAYS, } from './insurance-certificate.js';
import { generateOrgKeyPair } from './signed-manifest.js';
import { generateAgentTrustReport } from './agent-trust-report.js';
import { composeThreeDimensionalScore } from './trust-score-three-dim.js';
import { scanAgent } from './owasp-agentic-scanner.js';
import { buildRecommendationSet } from './improvement-recommendations.js';
const cleanManifest = () => ({
    agentId: 'agent-x',
    tools: [],
    hooks: { preToolUse: true, postToolUse: true, postResponse: true },
    llmProvider: 'connexum-proxy/anthropic',
    pluginIntegrityVerified: true,
    rateLimitsConfigured: true,
    declaredApprovalGates: [],
    declaredForbiddenCapabilities: [],
});
function makeReport() {
    const dim = (c) => ({
        scope_adherence: c, policy_compliance: c, anomaly_rate: c,
        incident_history: c, behavioral_consistency: c, composite: c,
    });
    const opDim = (c) => ({
        out_of_scope_ingestion: c, scope_violation_by_team: c,
        scope_violation_by_data_class: c, human_override_frequency: c, composite: c,
    });
    const bDim = (c) => ({
        owasp_agentic_score: c, hook_coverage_count: 3,
        declared_capability_class_count: 4, has_human_in_loop: true,
        plugin_integrity_verified: true, proxy_routed: true, composite: c,
    });
    const scan = scanAgent(cleanManifest());
    return generateAgentTrustReport({
        agentId: 'agent-x',
        orgId: 'subject-org',
        period: { from: '2026-05-01T00:00:00.000Z', to: '2026-05-12T00:00:00.000Z' },
        packBindings: ['hipaa'],
        score: composeThreeDimensionalScore({
            agent_activity: dim(90),
            operator_activity: opDim(90),
            agent_build_structure: bDim(90),
        }),
        scanReport: scan,
        recommendations: buildRecommendationSet({ agentId: 'agent-x', buildScan: scan }),
    });
}
describe('insurance certificate signer', () => {
    it('issues a certificate and verifies it with the issuer public key', () => {
        const { publicKey, privateKey } = generateOrgKeyPair();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey,
        });
        const payload = verifyInsuranceCertificate(cert, publicKey);
        assert.equal(payload.issuerOrgId, 'issuer-org');
        assert.equal(payload.subjectOrgId, 'subject-org');
        assert.equal(payload.class, 'standard');
        assert.equal(payload.report.agentId, 'agent-x');
    });
    it('subjectOrgId defaults to the report.orgId when not supplied', () => {
        const { publicKey, privateKey } = generateOrgKeyPair();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey,
        });
        const payload = verifyInsuranceCertificate(cert, publicKey);
        assert.equal(payload.subjectOrgId, 'subject-org'); // from report.orgId
    });
    it('explicit certClass is preserved', () => {
        const { publicKey, privateKey } = generateOrgKeyPair();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            certClass: 'attested',
            privateKey,
        });
        const payload = verifyInsuranceCertificate(cert, publicKey);
        assert.equal(payload.class, 'attested');
    });
    it('verification rejects a tampered payload', () => {
        const { publicKey, privateKey } = generateOrgKeyPair();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey,
        });
        const tampered = {
            ...cert,
            payload: { ...cert.payload, class: 'attested' },
        };
        assert.throws(() => verifyInsuranceCertificate(tampered, publicKey), (e) => e.code === 'INVALID_SIGNATURE');
    });
    it('verification rejects signature from a different private key', () => {
        const { privateKey: pkA } = generateOrgKeyPair();
        const { publicKey: pubB } = generateOrgKeyPair();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey: pkA,
        });
        assert.throws(() => verifyInsuranceCertificate(cert, pubB), (e) => e.code === 'INVALID_SIGNATURE');
    });
    it('expectedIssuerOrgId mismatch is rejected (confused-deputy guard)', () => {
        const { publicKey, privateKey } = generateOrgKeyPair();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey,
        });
        assert.throws(() => verifyInsuranceCertificate(cert, publicKey, {
            expectedIssuerOrgId: 'a-different-issuer',
        }), (e) => e.code === 'ISSUER_MISMATCH');
    });
    it('expired certificate is rejected (default max-age 90 days)', () => {
        const { publicKey, privateKey } = generateOrgKeyPair();
        const old = new Date(Date.now() - (DEFAULT_CERT_MAX_AGE_DAYS + 5) * 24 * 60 * 60 * 1000).toISOString();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey,
            nowIso: old,
        });
        assert.throws(() => verifyInsuranceCertificate(cert, publicKey), (e) => e.code === 'EXPIRED');
    });
    it('explicit expiresAt overrides the default max-age window', () => {
        const { publicKey, privateKey } = generateOrgKeyPair();
        const now = new Date().toISOString();
        const future = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey,
            nowIso: now,
            expiresAt: future,
        });
        const payload = verifyInsuranceCertificate(cert, publicKey);
        assert.equal(payload.expiresAt, future);
    });
    it('certificate issued at a future timestamp beyond skew is rejected', () => {
        const { publicKey, privateKey } = generateOrgKeyPair();
        const future = new Date(Date.now() + 60 * 60 * 1000).toISOString();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey,
            nowIso: future,
        });
        assert.throws(() => verifyInsuranceCertificate(cert, publicKey), (e) => e.code === 'NOT_YET_VALID');
    });
    it('missing issuerOrgId throws', () => {
        const { privateKey } = generateOrgKeyPair();
        assert.throws(() => issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: '',
            privateKey,
        }));
    });
    it('certificateFingerprint produces a stable 16-char base64url id', () => {
        const { privateKey } = generateOrgKeyPair();
        const cert1 = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey,
            nowIso: '2026-05-12T00:00:00.000Z',
        });
        const fp = certificateFingerprint(cert1);
        assert.equal(fp.length, 16);
        assert.match(fp, /^[A-Za-z0-9_-]+$/);
        // Same cert -> same fingerprint
        assert.equal(certificateFingerprint(cert1), fp);
    });
    it('different reports produce different fingerprints', () => {
        const { privateKey } = generateOrgKeyPair();
        const c1 = issueInsuranceCertificate({
            report: { ...makeReport(), id: 'cr-1' },
            issuerOrgId: 'issuer-org',
            privateKey,
        });
        const c2 = issueInsuranceCertificate({
            report: { ...makeReport(), id: 'cr-2' },
            issuerOrgId: 'issuer-org',
            privateKey,
        });
        assert.notEqual(certificateFingerprint(c1), certificateFingerprint(c2));
    });
    it('alg field is locked to ed25519; mismatched alg fails verification', () => {
        const { publicKey, privateKey } = generateOrgKeyPair();
        const cert = issueInsuranceCertificate({
            report: makeReport(),
            issuerOrgId: 'issuer-org',
            privateKey,
        });
        const bad = { ...cert, alg: 'hmac-sha256' };
        assert.throws(() => verifyInsuranceCertificate(bad, publicKey), (e) => e.code === 'MALFORMED');
    });
});
//# sourceMappingURL=insurance-certificate.test.js.map