moonsarif

    Pure MoonBit toolkit for parsing, validating, filtering and summarizing SARIF 2.1.0 logs

    sarif
    static-analysis
    code-scanning
    developer-tools
    Download zip
    Version
    0.4.0
    License
    Apache-2.0
    Last updated
    last month
    Downloads
    10

    Dependencies

    #MoonSARIF

    纯 MoonBit 实现的 SARIF 2.1.0 生成、解析、校验、筛选、合并、去重、基线门禁与报告工具链。

    #项目定位

    MoonSARIF 面向 MoonBit 静态分析器、CI/CD、代码扫描平台和 AI 编程 Agent,提供一套可复用的 SARIF 领域模型与工程工具。它不是通用 JSON Schema 验证器,而是针对 SARIF 工作流提供:

    • 2.1.0 核心类型和 JSON 往返;
    • 版本、工具、规则、结果、消息和位置的语义校验;
    • 结果统计、按等级/规则/路径筛选;
    • 跨 Windows/Linux 路径归一化;
    • 多日志合并;
    • 确定性结果指纹、同日志去重;
    • 当前日志与历史 baseline 的 new/unchanged/absent 对比;
    • 将 baselineState 写回当前 SARIF 结果;
    • Markdown/HTML 自包含报告;
    • 可在 CI 中拒绝新增问题的 baseline 门禁;
    • GitHub Code Scanning 上传前兼容性检查;
    • SARIF Builder,可从 MoonBit 静态分析器直接创建日志、规则、结果和位置;
    • Generic、Github、Strict 三种校验 Profile;
    • relatedLocations、fingerprints、suppressions、fixes、properties 等常用结果字段;
    • 文件型 CLI,便于接入 CI。

    #当前状态

    当前版本为 0.4.0。核心库和 CLI 已完成第一轮闭环,支持 wasm、wasm-gc、JavaScript、native 四个稳定后端的检查与测试;文件读写 CLI 主要面向 native 环境,库本身保持跨后端设计。

    项目明确不承诺覆盖 SARIF 规范的所有可选字段,也不替代平台官方的完整 JSON Schema 校验器。对未建模字段,解析时会按当前公开 API 范围处理;提交到具体平台前,仍建议执行平台侧校验。

    #快速开始

    #库 API

    ///|
    test {
    let input =
    #|{
    #| "version": "2.1.0",
    #| "runs": [{
    #| "tool": { "driver": { "name": "MoonLint" } },
    #| "results": [{
    #| "ruleId": "MB001",
    #| "level": "warning",
    #| "message": { "text": "example finding" }
    #| }]
    #| }]
    #|}
    let log = @moonsarif.parse(input)
    let report = @moonsarif.validate(log)
    let summary = @moonsarif.summarize(log)
    assert_true(report.is_valid())
    assert_eq(summary.result_count, 1)
    }

    #Builder

    let builder = @moonsarif.LogBuilder::new(tool_name="MoonLint", tool_version="0.4.0")
    builder.add_rule(id="MB001")
    let index = builder.add_result(
    rule_id="MB001",
    level="warning",
    message=@moonsarif.message_text("unused declaration"),
    location=@moonsarif.make_location(uri="src/main.mbt", start_line=12),
    )
    builder.set_partial_fingerprints(index, { "primaryLocationLineHash": "example" })
    let log = builder.finish()

    Builder 固定生成 SARIF 2.1.0,并可继续设置 related locations、fingerprints、suppressions、fixes、properties 和 baseline state。

    #校验 Profile

    moon run cmd/main -- validate examples/sample.sarif --profile generic moon run cmd/main -- validate examples/sample.sarif --profile github moon run cmd/main -- validate examples/sample.sarif --profile strict

    generic 执行通用语义检查,github 执行 Code Scanning 上传前检查,strict 额外要求结果有声明规则、位置和相对 artifact URI,并拒绝重复指纹。旧的 github-check 命令继续可用。

    #GitHub Actions

    可复制 GitHub Actions 示例,或直接使用 examples/github-actions/moonsarif-code-scanning.yml。

    # 检查 SARIF;发现结构/语义错误时退出码为 1 moon run cmd/main -- validate examples/sample.sarif # 输出统计摘要 moon run cmd/main -- summary examples/sample.sarif --pretty # 筛选 warning,支持 rule/path 条件 moon run cmd/main -- filter examples/sample.sarif \ --level warning --path src/main.mbt --output filtered.sarif # 合并多个同版本日志 moon run cmd/main -- merge first.sarif second.sarif --output merged.sarif # 删除同一日志中的重复结果 moon run cmd/main -- deduplicate merged.sarif --output unique.sarif # 比较当前结果与历史 baseline;有新增问题时退出码为 3 moon run cmd/main -- baseline current.sarif baseline.sarif --fail-on-new # 限制新增问题数量 moon run cmd/main -- baseline current.sarif baseline.sarif --max-new 0 # 生成 Markdown 报告 moon run cmd/main -- report examples/sample.sarif --format markdown # 生成 HTML 报告 moon run cmd/main -- report examples/sample.sarif --format html --output report.html # 报告中标记 new/unchanged moon run cmd/main -- report current.sarif --baseline baseline.sarif --format markdown # 检查 GitHub Code Scanning 常见兼容性问题 moon run cmd/main -- github-check current.sarif

    CLI 退出码:0 表示成功,1 表示校验发现 SARIF 错误,2 表示命令参数、文件读写或解析错误,3 表示 baseline 门禁拒绝新增问题。CLI 的错误信息当前写入标准输出,以便在不同宿主和后端中保持一致;自动化脚本应以退出码为准。

    #验证

    moon fmt moon check --target all --deny-warn --warn-list +73 moon test --target all --deny-warn moon info

    GitHub Actions 会执行格式检查、四个稳定后端的检查/测试、CLI 回归测试、1000 条结果的小型性能基准以及公共接口生成检查。

    #文档

    #后续计划

    • 补充更多 SARIF 可选字段与官方样例覆盖;
    • 增加更细粒度的平台兼容规则和真实上传回归样例;
    • 评估流式解析/写出和大文件优化;
    • 已发布 Noverberrain/moonsarif@0.4.0;后续根据 API 稳定性和赛事要求持续维护。

    #开源与 AI 使用说明

    项目依据公开的 OASIS SARIF 2.1.0 标准进行原创 MoonBit 实现,不复制第三方实现源码。开发过程中使用 Codex 辅助需求整理、架构设计、实现、测试和文档;最终代码审核、提交、许可证合规和参赛责任由项目申报人承担。

    #许可证

    Apache License 2.0。

    ArtifactChange

    pub struct ArtifactChange {
    artifactLocation : ArtifactLocation
    replacements : Array[Replacement]
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A change to one artifact proposed by a fix.

    ArtifactContent

    pub struct ArtifactContent {
    text : String?
    binary : String?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Embedded artifact content.

    ArtifactLocation

    pub struct ArtifactLocation {
    uri : String?
    uriBaseId : String?
    index : Int?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Identifies an artifact using a URI.

    BaselineReport

    pub struct BaselineReport {
    new_results : Int
    unchanged_results : Int
    absent_results : Int
    } derive(Eq, ToJson,
    Debug
    )

    Aggregate counts produced by a baseline comparison.

    BaselineState

    pub enum BaselineState {
    New
    Unchanged
    Absent
    } derive(Eq, ToJson,
    Debug
    )

    State of a result when compared with a previous SARIF baseline.

    Fix

    A proposed fix attached to a SARIF result.

    IssueSeverity

    pub enum IssueSeverity {
    IssueError
    IssueWarning
    } derive(Eq, ToJson,
    Debug
    )

    Severity assigned to a validation issue.

    Location

    pub struct Location {
    physicalLocation : PhysicalLocation?
    message : Message?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A logical or physical result location.

    LogBuilder

    pub struct LogBuilder {
    tool : ToolComponent
    results : Array[SarifResult]
    schema : String?
    }

    A mutable builder for one SARIF analysis log.

    LogBuilder::add_result

    fn LogBuilder::add_result(self : LogBuilder, rule_id? : String, level? : String, message~ : Message, location? : Location) -> Int

    Add a result and return its zero-based index.

    LogBuilder::add_rule

    fn LogBuilder::add_rule(self : LogBuilder, id~ : String, name? : String, help_uri? : String) -> Unit

    Add a rule to the tool driver.

    LogBuilder::finish

    fn LogBuilder::finish(self : LogBuilder) -> SarifLog

    Finish the log and return the ordinary SARIF data model.

    LogBuilder::new

    fn LogBuilder::new(tool_name~ : String, tool_version? : String) -> LogBuilder

    Create a builder with a SARIF 2.1.0 tool driver.

    LogBuilder::set_baseline_state

    fn LogBuilder::set_baseline_state(self : LogBuilder, result_index : Int, baseline_state : String) -> Unit

    Set the baseline state for a result.

    LogBuilder::set_fingerprints

    fn LogBuilder::set_fingerprints(self : LogBuilder, result_index : Int, fingerprints : Map[String, String]) -> Unit

    Set fingerprints for a result.

    LogBuilder::set_fixes

    fn LogBuilder::set_fixes(self : LogBuilder, result_index : Int, fixes : Array[Fix]) -> Unit

    Set fixes for a result.

    LogBuilder::set_locations

    fn LogBuilder::set_locations(self : LogBuilder, result_index : Int, locations : Array[Location]) -> Unit

    Replace the primary locations of a result.

    LogBuilder::set_partial_fingerprints

    fn LogBuilder::set_partial_fingerprints(self : LogBuilder, result_index : Int, fingerprints : Map[String, String]) -> Unit

    Set partial fingerprints for a result.

    LogBuilder::set_properties

    fn LogBuilder::set_properties(self : LogBuilder, result_index : Int, properties : Map[String, Json]) -> Unit

    Set arbitrary SARIF properties for a result.
    fn LogBuilder::set_related_locations(self : LogBuilder, result_index : Int, locations : Array[Location]) -> Unit

    Set related locations for a result.

    LogBuilder::set_schema

    fn LogBuilder::set_schema(self : LogBuilder, schema : String) -> Unit

    Set the JSON schema URI emitted by the builder.

    LogBuilder::set_suppressions

    fn LogBuilder::set_suppressions(self : LogBuilder, result_index : Int, suppressions : Array[Suppression]) -> Unit

    Set suppressions for a result.

    Message

    pub struct Message {
    text : String?
    markdown : String?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Human-readable SARIF content.

    PhysicalLocation

    pub struct PhysicalLocation {
    artifactLocation : ArtifactLocation?
    region : Region?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A location in an artifact such as a source file.

    Region

    pub struct Region {
    startLine : Int?
    startColumn : Int?
    endLine : Int?
    endColumn : Int?
    snippet : ArtifactContent?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A source region. Line and column values are one-based in SARIF.

    Replacement

    pub struct Replacement {
    deletedRegion : Region
    insertedContent : ArtifactContent?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A replacement within an artifact.

    ReportingDescriptor

    pub struct ReportingDescriptor {
    id : String
    name : String?
    shortDescription : Message?
    fullDescription : Message?
    helpUri : String?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Metadata describing a rule emitted by an analysis tool.

    Run

    A single analysis run.

    RunAutomationDetails

    pub struct RunAutomationDetails {
    id : String?
    guid : String?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    Stable identity information for an automated run.

    SarifLog

    pub struct SarifLog {
    version : String
    schema : String?
    runs : Array[Run]
    } derive(Eq,
    Debug
    )

    A SARIF 2.1.0 log.

    The JSON member $schema is exposed as schema because $ is not a valid MoonBit identifier.
    impl ToJson for SarifLog

    SarifResult

    pub struct SarifResult {
    ruleId : String?
    ruleIndex : Int?
    level : String?
    message : Message
    locations : Array[Location]?
    relatedLocations : Array[Location]?
    partialFingerprints : Map[String, String]?
    fingerprints : Map[String, String]?
    suppressions : Array[Suppression]?
    fixes : Array[Fix]?
    properties : Map[String, Json]?
    baselineState : String?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A single analysis result.

    SarifSummary

    pub struct SarifSummary {
    run_count : Int
    result_count : Int
    error_count : Int
    warning_count : Int
    note_count : Int
    none_count : Int
    unknown_level_count : Int
    unique_rule_count : Int
    } derive(Eq, ToJson,
    Debug
    )

    Compact metrics for a SARIF log.

    Suppression

    pub struct Suppression {
    kind : String
    justification : String?
    location : Location?
    guid : String?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A suppression attached to a SARIF result.

    Tool

    Tool metadata attached to a run.

    ToolComponent

    pub struct ToolComponent {
    name : String
    version : String?
    semanticVersion : String?
    informationUri : String?
    rules : Array[ReportingDescriptor]?
    } derive(Eq, ToJson,
    Debug
    ,
    FromJson
    )

    A component of an analysis tool.

    ValidationIssue

    pub struct ValidationIssue {
    severity : IssueSeverity
    code : String
    path : String
    message : String
    } derive(Eq, ToJson,
    Debug
    )

    A machine-readable validation finding.

    ValidationProfile

    pub enum ValidationProfile {
    Generic
    Github
    Strict
    } derive(Eq, ToJson,
    Debug
    )

    Validation rules to apply to a SARIF log.

    ValidationReport

    pub struct ValidationReport {
    issues : Array[ValidationIssue]
    } derive(Eq, ToJson,
    Debug
    )

    Complete validation result for one SARIF log.

    ValidationReport::error_count

    fn ValidationReport::error_count(self : ValidationReport) -> Int

    Count errors in a validation report.

    ValidationReport::is_valid

    fn ValidationReport::is_valid(self : ValidationReport) -> Bool

    Whether validation produced no errors.

    ValidationReport::warning_count

    fn ValidationReport::warning_count(self : ValidationReport) -> Int

    Count warnings in a validation report.

    WireSarifLog

    type WireSarifLog derive(
    FromJson
    )

    annotate_baseline

    fn annotate_baseline(current : SarifLog, baseline : SarifLog) -> SarifLog

    Add SARIF baselineState values to results in the current log.

    Results found in the baseline are marked unchanged; other current results are marked new. Baseline-only results are represented by the counts returned from compare_baseline and are not added to the current log.

    compare_baseline

    fn compare_baseline(current : SarifLog, baseline : SarifLog) -> BaselineReport

    Compare unique result identities in current with baseline.

    Results present only in current are new. Results present in both logs are unchanged. Results present only in baseline are absent.

    deduplicate

    fn deduplicate(log : SarifLog) -> SarifLog

    Remove duplicate findings from every run while retaining the first result.

    filter_results

    fn filter_results(log : SarifLog, level? : String, rule_id? : String, path_contains? : String) -> SarifLog

    Filter results while preserving run and tool metadata.

    fingerprint

    fn fingerprint(result : SarifResult) -> String

    Build a deterministic identity for a SARIF result.

    The identity intentionally avoids object addresses, array indexes and timestamps. It combines the rule, normalized first location and message; this makes it stable across separate tool runs and useful for de-duplication and baseline comparisons.

    generic_validation_profile

    fn generic_validation_profile() -> ValidationProfile

    Return the generic validation profile.

    github_validation_profile

    fn github_validation_profile() -> ValidationProfile

    Return the GitHub validation profile.

    make_location

    fn make_location(uri~ : String, start_line~ : Int, start_column? : Int, end_line? : Int, end_column? : Int) -> Location

    Construct a source location with a one-based start line.

    make_suppression

    fn make_suppression(kind~ : String, justification? : String, location? : Location, guid? : String) -> Suppression

    Construct a suppression for a result.

    merge

    fn merge(logs : ArrayView[SarifLog]) -> SarifLog?

    Merge logs by concatenating runs. All inputs must use the same version.

    message_markdown

    fn message_markdown(markdown : String) -> Message

    Construct a markdown SARIF message.

    message_text

    fn message_text(text : String) -> Message

    Construct a text SARIF message.

    normalize_path

    fn normalize_path(input : StringView) -> String

    Normalize common SARIF artifact paths for stable comparisons.

    This converts backslashes to slashes, removes repeated separators and . segments, resolves safe .. segments, and preserves URI schemes such as https:// and file://.

    parse

    fn parse(input : StringView) -> SarifLog raise

    Parse a SARIF JSON string into a typed log.

    JSON syntax failures and typed decoding failures are propagated to the caller, preserving their detailed paths.

    parse_validation_profile

    fn parse_validation_profile(value : String) -> ValidationProfile?

    Parse the profile name used by the command-line interface.

    render_html

    fn render_html(log : SarifLog) -> String

    Render a self-contained HTML report for a SARIF log.

    render_markdown

    fn render_markdown(log : SarifLog) -> String

    Render a compact Markdown report for a SARIF log.

    strict_validation_profile

    fn strict_validation_profile() -> ValidationProfile

    Return the strict validation profile.

    stringify

    fn stringify(log : SarifLog, pretty? : Bool) -> String

    Serialize a typed SARIF log as JSON.

    summarize

    fn summarize(log : SarifLog) -> SarifSummary

    Build an aggregate summary across every run.

    validate

    fn validate(log : SarifLog) -> ValidationReport

    Perform structural and semantic checks that are useful before uploading a SARIF file to a code-scanning service.

    validate_github_compatibility

    fn validate_github_compatibility(log : SarifLog) -> ValidationReport

    Validate the subset of SARIF conventions expected by GitHub Code Scanning.

    This complements validate with checks that are useful immediately before uploading a SARIF artifact. It intentionally remains conservative: missing locations are warnings because some analyzers emit project-level findings.

    validate_with_profile

    fn validate_with_profile(log : SarifLog, profile : ValidationProfile) -> ValidationReport

    Validate a SARIF log using a named engineering profile.