Skip to content

release(contract): reject byte-noncanonical topic-lineage artifact JSON #657

Open

Description

@seonghobae

Finding

TopicLineageArtifact is a digest-bound release projection and to_json() is documented as canonical serialization, but from_json() currently accepts any JSON text that deserializes to the same validated struct. Whitespace, pretty-printing, and other byte-distinct JSON representations can therefore be accepted even though the canonical artifact SHA-256 is derived from compact owner serialization.

That leaves two notions of artifact identity at the release boundary: accepted input bytes and the canonical bytes later reserialized for hashing. #654–#656 closed field-level aliases, but the outer JSON envelope itself still permits byte aliases.

Required RED

Using one otherwise valid tepp.trsl_topic_lineage.v2 artifact:

  • canonical artifact.to_json() bytes must parse successfully;
  • the same JSON with a trailing newline must fail closed; and
  • a pretty-printed representation of the same semantic object must fail closed.

The RED must use the public parser so the consumer boundary, not a private helper, owns the invariant.

Minimal causal repair

After deserialization and semantic validation, reserialize the parsed struct with the owner serializer and require exact byte equality with the supplied payload. Do not trim, normalize, or rewrite caller bytes. Keep the existing byte limit and field-level canonicalization rules unchanged.

This is deterministic release-identity hardening only. It does not alter estimator arithmetic, scientific thresholds, Membership semantics, or the v2 schema shape.

Record the rule in CHANGELOG/release contract and #639 lineage. Exact-head hosted GREEN and qualifying independent review remain required before any release.

Refs #638 #639 #654 #655 #656.

Activity

  1. seonghobae commented on Sep 21, 2026

    @seonghobae
    ContributorAuthor

    #657 RED → repair lineage is now ordinary-forward on canonical Draft #639. Source-level RED cf637dd9826a92ce361212f43ffe23f104ae9c09 proves canonical owner JSON parses while a trailing newline and pretty-printed aliases must fail. Causal parser repair 468b702b322e5ebdebab13b581fa7f4a72d7b806 validates then reserializes with the owner serializer and requires exact byte equality; caller bytes are not trimmed/normalized. CHANGELOG b6772ab596c691aa2f068b2fcfd5600d2be261d6, release-contract doctoring ab7f3afeab7fe2251f69da82dfeaa8e76cd1904f, and rustfmt-only current head 49f599c5b132a5d4a1a458645d61e068d12085d3 follow. Hosted exact-head GREEN is not claimed: Rust Foundation 35661104789, Security 35661104785, Semgrep 35661104822, CodeQL PR 35661104790, and Documentation 35661104807 are non-terminal. #639 remains Draft and has no submitted review/thread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions