moonseal

    Generate CycloneDX SBOMs and audit MoonBit projects for release readiness and open-source compliance.

    sbom
    cyclonedx
    license
    supply-chain
    security
    Download zip
    Author
    Version
    0.2.1
    License
    Apache-2.0
    Last updated
    2 months ago
    Downloads
    37

    #MoonSeal

    Seal your MoonBit supply chain.

    CI License

    MoonSeal is a MoonBit-native release-readiness auditor and CycloneDX SBOM generator. It understands MoonBit manifests and Mooncakes package coordinates, then turns repository metadata into actionable findings and a standard software bill of materials.

    中文简介: MoonSeal 是面向 MoonBit 项目的软件供应链清单与开源合规 工具。它可以检查项目发布条件、许可证声明和依赖信息,并生成 CycloneDX 1.6 SBOM。

    #Why MoonSeal?

    General-purpose scanners do not understand MoonBit's current moon.mod format, its legacy moon.mod.json format, or pkg:mooncakes package URLs. MoonSeal provides a small, deterministic core library plus a practical CLI designed for MoonBit repositories and CI pipelines.

    #Capabilities

    • Parse current and legacy MoonBit module manifests.
    • Extract module metadata and Mooncakes dependencies.
    • Validate common SPDX identifiers and compound expressions.
    • Detect common license texts and declaration mismatches.
    • Check README, LICENSE, repository URL, CI, changelog, and source presence.
    • Enforce repository-specific policy from moonseal-policy.json.
    • Analyze dependency pinning, coordinates, duplicates, and version conflicts.
    • Produce text, JSON, Markdown, and SARIF audit reports.
    • Generate deterministic CycloneDX 1.6 SBOM documents.
    • Compare audit baselines and identify regressions.
    • Generate in-toto/SLSA provenance statements.
    • Run on the WebAssembly backend; support native builds where available.

    #Functional boundaries

    MoonSeal is a deterministic release-readiness library and reference CLI. It analyzes repository metadata supplied by the caller and emits interoperable reports. It does not download packages, query vulnerability databases, provide legal conclusions, sign artifacts, or upload reports. Network enrichment and cryptographic signing belong in adapters built on top of the core library.

    This boundary keeps audits reproducible offline while leaving clear extension points for Mooncakes metadata, vulnerability feeds, and CI attestations.

    #Installation

    Install the current MoonBit toolchain. After version 0.2.1 is published on Mooncakes, library consumers can add it with:

    moon add liyun/moonseal@0.2.1

    To use the reference CLI, clone this repository and run the commands below.

    #Quick start

    Clone the public repository, resolve its pinned dependencies, and run the self-audit example:

    moon update moon run cmd/main scan .

    Example output:

    MoonSeal audit: liyun/moonseal Score: 100/100 Source: 4362 MoonBit lines | 0 errors | 0 warnings READY No release-readiness issues found.

    Generate a CycloneDX SBOM:

    moon run cmd/main sbom . -o moonseal.cdx.json

    See examples/moonseal.cdx.json for a schema-validated example generated from this repository.

    Use MoonSeal as a blocking CI check:

    moon run cmd/main check .

    Get a machine-readable report:

    moon run cmd/main scan . --json

    Generate a Markdown build summary:

    moon run cmd/main scan . --markdown

    Generate a SARIF report for code-scanning platforms:

    moon run cmd/main scan . --sarif

    Analyze direct Mooncakes dependencies:

    moon run cmd/main dependencies .

    Enforce the checked-in repository policy:

    moon run cmd/main policy . --policy moonseal-policy.json

    #Commands

    CommandPurpose
    moonseal scan [PATH] [--json \| --markdown \| --sarif]Audit a project and print findings
    moonseal check [PATH]Audit and fail if blocking findings exist
    moonseal sbom [PATH] [-o FILE]Generate a CycloneDX 1.6 SBOM
    moonseal dependencies [PATH] [--json]Analyze dependency metadata
    moonseal policy [PATH] [--policy FILE] [--json]Enforce repository policy
    moonseal helpShow command help

    During development, replace moonseal with moon run cmd/main.

    #Audit rules

    CodeSeverityCheck
    MS001ErrorModule name is present
    MS002ErrorModule version is present
    MS003ErrorSPDX license declaration is present
    MS004ErrorSPDX expression is recognized
    MS005WarningRepository URL is present
    MS006ErrorLicense file exists
    MS007ErrorREADME exists
    MS008WarningGitHub Actions workflow exists
    MS009WarningChangelog exists
    MS010Info.gitignore exists
    MS011ErrorDeclared and detected licenses agree
    MS012WarningLicense text can be identified
    MS013ErrorMoonBit source is present
    MS014WarningRepository URL uses a recognized Git transport

    MoonSeal provides engineering signals, not legal advice. A passing report does not replace legal review.

    #Library API

    The core package has no file-system side effects. Its main public functions are:

    • parse_manifest(path, text)
    • normalize_license(identifier)
    • valid_spdx(expression)
    • detect_license(text)
    • audit(facts)
    • evaluate_policy(policy, facts, report)
    • analyze_dependencies(project)
    • render_text(report), render_json(report), and render_sarif(report)
    • cyclonedx(project) and cyclonedx_string(project)
    • compare_reports(previous, current)
    • provenance(project, options)

    See the architecture guide for the package boundaries.

    #Development and tests

    moon fmt moon check --target wasm -d moon test --target wasm moon build --target wasm --release moon run --target wasm cmd/main check .

    The tests cover both manifest formats, dependency extraction, SPDX validation, license detection, audit scoring, report generation, and CycloneDX output. See the MVP status and reproduction checklist for the current delivery boundary.

    Reviewers can use the dedicated evidence documents:

    #Maintenance

    Bug reports and feature proposals use the GitHub issue forms. Contributions follow CONTRIBUTING.md and must include tests for behavior changes. User-visible changes are recorded in CHANGELOG.md, and published versions use immutable semantic-version tags.

    #Competition

    MoonSeal is being developed for the 2026 MoonBit 国产基础软件生态开源大赛 8 月黑客松. The competition applicant and primary maintainer is 马昀昀, who uses the GitHub account @liyun6666. Therefore, the applicant name and the repository owner/commit identity refer to the same contributor. Contact details are intentionally kept out of the public package.

    #License

    Apache-2.0. See LICENSE and THIRD_PARTY.md.

    AuditDelta

    pub(all) struct AuditDelta {
    project_name : String
    previous_score : Int
    current_score : Int
    previous_ready : Bool
    current_ready : Bool
    added : Array[Finding]
    resolved : Array[Finding]
    unchanged : Array[Finding]
    changed : Array[FindingChange]
    } derive(Eq,
    Debug
    )

    AuditDelta::has_changes

    fn AuditDelta::has_changes(self : AuditDelta) -> Bool

    AuditDelta::improved

    fn AuditDelta::improved(self : AuditDelta) -> Bool

    AuditDelta::regressed

    fn AuditDelta::regressed(self : AuditDelta) -> Bool

    AuditDelta::score_change

    fn AuditDelta::score_change(self : AuditDelta) -> Int

    AuditPolicy

    pub(all) struct AuditPolicy {
    minimum_score : Int
    minimum_source_lines : Int
    maximum_warnings : Int
    maximum_dependencies : Int
    require_repository : Bool
    require_ci : Bool
    require_changelog : Bool
    require_security_policy : Bool
    require_pinned_dependencies : Bool
    allowed_licenses : Array[String]
    denied_licenses : Array[String]
    required_files : Array[String]
    } derive(Eq,
    Debug
    )

    Repository-specific release policy loaded from moonseal-policy.json.

    AuditReport

    pub(all) struct AuditReport {
    project : Project
    findings : Array[Finding]
    moonbit_source_lines : Int
    score : Int
    } derive(Eq,
    Debug
    )

    Complete deterministic result of a MoonSeal audit.

    AuditReport::error_count

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

    AuditReport::is_ready

    fn AuditReport::is_ready(self : AuditReport) -> Bool

    AuditReport::warning_count

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

    Dependency

    pub(all) struct Dependency {
    name : String
    version : String
    } derive(Eq,
    Debug
    )

    A MoonBit module dependency discovered in the module manifest.

    DependencyHealth

    pub(all) struct DependencyHealth {
    total : Int
    pinned : Int
    unpinned : Int
    unique : Int
    namespaces : Array[NamespaceCount]
    issues : Array[DependencyIssue]
    } derive(Eq,
    Debug
    )

    DependencyHealth::error_count

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

    DependencyHealth::is_healthy

    fn DependencyHealth::is_healthy(self : DependencyHealth) -> Bool

    DependencyHealth::warning_count

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

    DependencyHealthSeverity

    pub enum DependencyHealthSeverity {
    DependencyInfo
    DependencyWarning
    DependencyError
    } derive(Eq,
    Debug
    )

    DependencyIssue

    pub(all) struct DependencyIssue {
    severity : DependencyHealthSeverity
    code : String
    dependency : String
    message : String
    } derive(Eq,
    Debug
    )

    Finding

    pub(all) struct Finding {
    severity : Severity
    code : String
    path : String
    message : String
    } derive(Eq,
    Debug
    )

    One actionable release-readiness or compliance observation.

    FindingChange

    pub(all) struct FindingChange {
    code : String
    path : String
    previous_severity : Severity
    current_severity : Severity
    previous_message : String
    current_message : String
    } derive(Eq,
    Debug
    )

    NamespaceCount

    pub(all) struct NamespaceCount {
    scope : String
    count : Int
    } derive(Eq,
    Debug
    )

    PolicyResult

    pub(all) struct PolicyResult {
    policy : AuditPolicy
    violations : Array[PolicyViolation]
    } derive(Eq,
    Debug
    )

    Result of applying repository policy to an audit.

    PolicyResult::is_allowed

    fn PolicyResult::is_allowed(self : PolicyResult) -> Bool

    PolicyViolation

    pub(all) struct PolicyViolation {
    code : String
    path : String
    message : String
    } derive(Eq,
    Debug
    )

    One policy-specific violation. These use the MP prefix so they remain distinguishable from built-in MS audit findings.

    Project

    pub(all) struct Project {
    name : String
    version : String
    license : String
    repository : String
    dependencies : Array[Dependency]
    } derive(Eq,
    Debug
    )

    Metadata parsed from moon.mod or legacy moon.mod.json.

    ProvenanceOptions

    pub(all) struct ProvenanceOptions {
    builder_id : String
    build_type : String
    source_uri : String
    revision : String
    subject_digest : String
    invocation_id : String
    started_on : String
    finished_on : String
    reproducible : Bool
    } derive(Eq,
    Debug
    )

    ScanFacts

    pub(all) struct ScanFacts {
    project : Project
    files : Array[String]
    moonbit_source_lines : Int
    license_text : String?
    } derive(Eq,
    Debug
    )

    File-system facts collected by the CLI and audited by the pure library.

    Severity

    pub(all) enum Severity {
    Info
    Warning
    Error
    } derive(Eq,
    Debug
    )

    Severity assigned to an audit finding.

    Severity::label

    fn Severity::label(self : Severity) -> String

    analyze_dependencies

    fn analyze_dependencies(project : Project) -> DependencyHealth

    Analyze direct Mooncakes dependencies for reproducibility and metadata quality. The analysis is deterministic and does not require network access.

    audit

    fn audit(facts : ScanFacts) -> AuditReport

    Audit pure scan facts. This function performs no file-system access and is therefore portable and deterministic.

    compare_reports

    fn compare_reports(previous : AuditReport, current : AuditReport) -> AuditDelta

    Compare two audit reports without depending on timestamps or filesystem state. Findings are matched by stable rule code and path.

    cyclonedx

    fn cyclonedx(project : Project) -> Json

    Generate a deterministic CycloneDX 1.6 SBOM as JSON.

    cyclonedx_string

    fn cyclonedx_string(project : Project, indent? : Int) -> String

    default_policy

    fn default_policy() -> AuditPolicy

    default_provenance_options

    fn default_provenance_options() -> ProvenanceOptions

    delta_json

    fn delta_json(delta : AuditDelta) -> Json

    dependency_health_json

    fn dependency_health_json(health : DependencyHealth) -> Json

    dependency_inventory

    fn dependency_inventory(project : Project) -> Json

    dependency_purl

    fn dependency_purl(dependency : Dependency) -> String

    detect_license

    fn detect_license(text : StringView) -> String?

    Identify common license texts without relying on file names.

    evaluate_policy

    fn evaluate_policy(policy : AuditPolicy, facts : ScanFacts, report : AuditReport) -> PolicyResult

    Apply repository policy to already-collected facts and an audit report.

    normalize_license

    fn normalize_license(identifier : StringView) -> String

    Normalize common aliases to SPDX identifiers.

    parse_manifest

    fn parse_manifest(path : StringView, text : StringView) -> Project raise

    Parse either supported module manifest based on its file name.

    parse_moon_mod

    fn parse_moon_mod(text : StringView) -> Project

    Parse the current TOML-like MoonBit module format.

    parse_moon_mod_json

    fn parse_moon_mod_json(text : StringView) -> Project raise

    Parse the legacy JSON MoonBit module format.

    parse_policy

    fn parse_policy(text : StringView) -> AuditPolicy raise

    Parse a MoonSeal policy document. Unknown keys are deliberately ignored so that policy files remain forwards compatible.

    provenance

    fn provenance(project : Project, options : ProvenanceOptions) -> Json

    Create an in-toto Statement carrying a SLSA Provenance v1 predicate. The caller supplies revision and digest values because the portable core does not read Git state or hash build artifacts.

    provenance_warnings

    fn provenance_warnings(project : Project, options : ProvenanceOptions) -> Array[String]

    Validate data required for a useful, publishable provenance statement.

    render_delta_json

    fn render_delta_json(delta : AuditDelta, indent? : Int) -> String

    render_delta_markdown

    fn render_delta_markdown(delta : AuditDelta) -> String

    render_delta_text

    fn render_delta_text(delta : AuditDelta) -> String

    render_dependency_json

    fn render_dependency_json(health : DependencyHealth, indent? : Int) -> String

    render_dependency_text

    fn render_dependency_text(health : DependencyHealth) -> String

    render_json

    fn render_json(report : AuditReport, indent? : Int) -> String

    Render a machine-readable report suitable for CI.

    render_markdown

    fn render_markdown(report : AuditReport) -> String

    Render an audit report for issue trackers, pull requests, and build summaries.

    render_policy_json

    fn render_policy_json(result : PolicyResult, indent? : Int) -> String

    render_policy_text

    fn render_policy_text(result : PolicyResult) -> String

    render_provenance

    fn render_provenance(project : Project, options : ProvenanceOptions, indent? : Int) -> String

    render_provenance_warnings

    fn render_provenance_warnings(project : Project, options : ProvenanceOptions) -> String

    render_sarif

    fn render_sarif(report : AuditReport, indent? : Int) -> String

    render_text

    fn render_text(report : AuditReport) -> String

    Render a compact human-readable audit report.

    sarif

    fn sarif(report : AuditReport) -> Json

    Convert an audit report to SARIF 2.1.0 for GitHub Code Scanning and other interoperable static-analysis consumers.

    valid_spdx

    fn valid_spdx(expression : StringView) -> Bool

    Validate a practical subset of SPDX expressions: identifiers joined by AND or OR, with optional grouping parentheses.