Skip to content

Persist and expose the seal conformance level (blocked on the dpp-domain repin) #289

Description

@LKSNDRTMLKV

SealedEnvelope in dpp-domain now carries conformance_level: Option<SealConformanceLevel>, serialised as conformanceLevel. The engine cannot use it until it repins dpp-domain past the release that contains it (currently pinned at 0.19.0, from crates.io, with no [patch]).

Blocked on that repin. Filing now so the work is not rediscovered.

Why the field exists

SealConformanceLevel documents why the level is on the request: a BaselineB seal stops verifying when its signing certificate expires, ESPR retention outlives certificate lifetimes comfortably, the seal is bought once, and the passport it covers is retention-locked — so the choice cannot be corrected afterwards.

All of that is about the stored seal, and the stored seal did not record it. A node that runs the local backend at B, then a hosted provider at T, then LT, leaves three populations of passport that are indistinguishable in storage — and the ones that will stop verifying first are the ones nobody can identify.

What to change

  1. crates/dpp-seal/src/local/sealer.rsLocalIdentity::seal sets conformance_level: Some(SealConformanceLevel::BaselineB). It advertises BaselineB only, and sign_detached sets unsigned_attrs: None, so BaselineB is what the bytes are. Not req.conformance_level: the boot gate already refuses a mismatch, so echoing would only launder a bug.
  2. crates/dpp-seal/src/eideasy/client.rs — set it from level_for_profile(&self.config.signature_profile), the same source capabilities() uses. That is the level the client was configured to ask for, which is the honest claim available without reading the returned CMS. Reading it out of the bytes is #TODO-DETECT.
  3. crates/dpp-seal/src/adapter.rs and src/ghost.rs — the ghost echoes the request, matching GhostSeal in dpp-domain.
  4. api/components/schemas/passport/SealedEnvelope.yaml — add an optional conformanceLevel referencing a new SealConformanceLevel.yaml enum (baseline-b, baseline-t, baseline-lt, baseline-lta; kebab-case, matching the serde representation). Optional in both directions: an envelope written before the field reads back absent, and an absent level must be omitted, never serialised as null — a "conformanceLevel": null appearing on a stored passport would be a content change on a retention-locked document.
  5. crates/dpp-vault/src/handlers/seal.rs — add conformance_level to SealResponse, documented in the register the rest of that struct already uses: a record of what was requested, the same standing as sealedPayloadHash, not proof of what arrived. Mirror it in api/components/schemas/seals/SealResponse.yaml.
  6. ops/pg/ — no migration needed. The seal lives inside passport.doc, seal is already on the retention guard's mutable_keys, and the field is additive within that JSON.

Tests worth having

  • A seal drained end to end carries the level the backend advertises.
  • A stored envelope predating the field still deserialises, with the level absent.
  • openapi_contract.rs covers the new property in both directions.

The dpp-domain conformance kit already gained rule 6 (seal.misrecorded_level), which fails an adapter whose envelope records a level disagreeing with the request it answered. adapter.rs runs that kit, so an implementation mistake here shows up as a kit failure rather than as a wrong record in production.

Activity

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