import { afterEach, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { saveExecApprovals } from "../infra/exec-approvals.js";
import { collectExecRuntimeFindings } from "./audit.js";

function hasFinding(
  checkId:
    | "tools.exec.auto_allow_skills_enabled"
    | "tools.exec.allowlist_interpreter_without_strict_inline_eval"
    | "security.exposure.open_channels_with_exec"
    | "tools.exec.security_full_configured",
  severity: "warn" | "critical",
  findings: ReturnType<typeof collectExecRuntimeFindings>,
) {
  return findings.some((finding) => finding.checkId === checkId && finding.severity === severity);
}

afterEach(() => {
  saveExecApprovals({ version: 1, agents: {} });
});

describe("security audit exec surface findings", () => {
  it("warns when exec approvals enable autoAllowSkills", () => {
    saveExecApprovals({
      version: 1,
      defaults: {
        autoAllowSkills: true,
      },
      agents: {},
    });

    expect(
      hasFinding("tools.exec.auto_allow_skills_enabled", "warn", collectExecRuntimeFindings({})),
    ).toBe(true);
  });

  it("warns when interpreter allowlists are present without strictInlineEval", () => {
    saveExecApprovals({
      version: 1,
      agents: {
        main: {
          allowlist: [{ pattern: "/usr/bin/python3" }, { pattern: "/usr/bin/awk" }],
        },
        ops: {
          allowlist: [{ pattern: "/usr/local/bin/node" }, { pattern: "/usr/local/bin/find" }],
        },
      },
    });

    expect(
      hasFinding(
        "tools.exec.allowlist_interpreter_without_strict_inline_eval",
        "warn",
        collectExecRuntimeFindings({
          agents: {
            list: [{ id: "ops" }],
          },
        } satisfies OpenClawConfig),
      ),
    ).toBe(true);
  });

  it("suppresses interpreter allowlist warnings when strictInlineEval is enabled", () => {
    saveExecApprovals({
      version: 1,
      agents: {
        main: {
          allowlist: [{ pattern: "/usr/bin/python3" }, { pattern: "/usr/bin/xargs" }],
        },
      },
    });

    expect(
      hasFinding(
        "tools.exec.allowlist_interpreter_without_strict_inline_eval",
        "warn",
        collectExecRuntimeFindings({
          tools: {
            exec: {
              strictInlineEval: true,
            },
          },
        } satisfies OpenClawConfig),
      ),
    ).toBe(false);
  });

  it("flags open channel access combined with exec-enabled scopes", () => {
    const findings = collectExecRuntimeFindings({
      channels: {
        discord: {
          groupPolicy: "open",
        },
      },
      tools: {
        exec: {
          security: "allowlist",
          host: "gateway",
        },
      },
    } satisfies OpenClawConfig);

    expect(hasFinding("security.exposure.open_channels_with_exec", "warn", findings)).toBe(true);
  });

  it("escalates open channel exec exposure when full exec is configured", () => {
    const findings = collectExecRuntimeFindings({
      channels: {
        slack: {
          dmPolicy: "open",
        },
      },
      tools: {
        exec: {
          security: "full",
        },
      },
    } satisfies OpenClawConfig);

    expect(hasFinding("tools.exec.security_full_configured", "critical", findings)).toBe(true);
    expect(hasFinding("security.exposure.open_channels_with_exec", "critical", findings)).toBe(
      true,
    );
  });
});
