{
  // OCSF-compliant parser for JSON application logs
  // Schema: OCSF v1.3.0 - Security Finding (class_uid 2001)
  // https://schema.ocsf.io/1.3.0/classes/security_finding

  attributes: {
    // ─── OCSF Metadata ──────────────────────────────────────────────
    "metadata.version":             "1.3.0",
    "metadata.product.vendor_name": "GenericApp",
    "metadata.product.name":        "Application Logger",
    "metadata.product.version":     "1.0.0",
    "metadata.log_provider":        "hec",

    // ─── OCSF Classification (Security Finding) ──────────────────────
    "category_uid":                 2,
    "category_name":                "Findings",
    "class_uid":                    2001,
    "class_name":                   "Security Finding",
    "activity_id":                  1,
    "activity_name":                "Create",
    "type_uid":                     200101,
    "type_name":                    "Security Finding: Create",

    // ─── OCSF Finding state defaults (overridable via rewrites) ─────
    "status_id":                    1,             // 1=New
    "status":                       "New",
    "disposition_id":               0,             // 0=Unknown
    "disposition":                  "Unknown",

    // ─── SDL/S1 routing fields (non-OCSF) ───────────────────────────
    "Category":                     "security",
    "dataSource.vendor":            "GenericApp",
    "dataSource.name":              "alert",
    "dataSource.category":          "security",
    "finding_info.types":           ["Authentication"]
  },

  formats: [
    {
      // Auto-extract every JSON top-level field as an attribute
      format: "$=json{parse=json}$",
      halt: true,
      rewrites: [
        // ─── Time handling ─────────────────────────────────────────────
        // Source JSON uses `event_iso` (ISO string). NEVER use the bare
        // `time` attr (SDL reserved, expects epoch ms) or any `*_time`
        // suffix (AI SIEM auto-parses as date, shows "Invalid Date" for
        // ISO strings).
        { input: "event_iso", output: "finding_info.created_time_dt", match: ".*", replace: "$0" },

        // ─── Actor (user) ───────────────────────────────────────────
        { input: "user", output: "actor.user.name", match: ".*", replace: "$0" },
        { input: "user", output: "actor.user.uid",  match: ".*", replace: "$0" },

        // ─── Finding info ───────────────────────────────────────────
        { input: "msg", output: "finding_info.title", match: ".*", replace: "$0" },
        { input: "msg", output: "finding_info.desc",  match: ".*", replace: "$0" },
        // finding_info.uid: use the original log line hash; SDL has no hash fn,
        // so fall back to msg+user concatenation (callers SHOULD add an `id` field)
        { input: "msg", output: "finding_info.uid",   match: ".*", replace: "$0" },

        // ─── Raw log preservation (OCSF: raw_data) ──────────────────
        { input: "msg", output: "raw_data",           match: ".*", replace: "$0" },

        // ─── Severity (string + int, OCSF v1.3.0 ranges) ────────────
        // NOTE: SDL reserves the bare `severity` field name and renames our
        // attribute to `severity_`. We populate `severity_str` (queryable) and
        // `severity_id` (OCSF integer 0-6).
        { input: "level", output: "severity_id",  match: "(?i)error",  replace: "5" },
        { input: "level", output: "severity_id",  match: "(?i)warn",   replace: "4" },
        { input: "level", output: "severity_id",  match: "(?i)info",   replace: "3" },
        { input: "level", output: "severity_id",  match: "(?i)debug",  replace: "1" },
        { input: "level", output: "severity_str", match: "(?i)error",  replace: "Critical" },
        { input: "level", output: "severity_str", match: "(?i)warn",   replace: "High" },
        { input: "level", output: "severity_str", match: "(?i)info",   replace: "Informational" },
        { input: "level", output: "severity_str", match: "(?i)debug",  replace: "Other" }
      ]
    }
  ]
}
