Skip to content

Our health:liveness attestations are self-attested, which CC 3.1.9.4 forbids #51

Description

@emooreatx

Found by a source audit of the pinned revs (ciris-server v0.5.169, ciris-persist v30.11.0) while specifying FSD/MULTI_VANTAGE.md.

The defect

Our health:liveness:v1 rows are self-attested: src/adapter.rs sets attested_key_id to this node's own key, while src/ceg.rs simultaneously declares witness_relation: "external".

Persist's family rule for health:liveness: is explicit:

health:liveness:"witness_relation MUST be external — a service never attests its own liveness (attester != attested)" — CC 3.1.9.4 / CC 3.4.3

So every row we emit asserts an external witness relation about a subject that is the attester. The claim contradicts itself.

Why it is admitted anyway

The invariant gate is keyed on the row's attestation_type, not the envelope's dimension. Our rows carry attestation_type = "scores" with dimension = "health:liveness:v1", and "scores".starts_with("health:liveness:") is false — so the check never fires.

Persist has already fixed this exact wrong-axis bug for capacity:, one line above in the same function, with a comment noting that the type-keyed arm "never fired on the real emit shape". The health:liveness: twin is one line away and follows an established pattern.

When it lands, our emits stop being admitted. Silently, at the ingest gate, with no trace — that is the fail-secure design.

Options

  1. Register service keys and attest about them properly (attested_key_id = the billing/proxy node key). Most correct; makes every monitored service a fabric identity; the attested subject must resolve to a registered key or check_attested_subject_admission refuses it.
  2. Move to an observation:* dimension. A monitor attesting "I observed X at T" is a genuinely different claim from "X is alive" — and the honest one for an outside observer that cannot see inside the service. Needs a :v1 segment; lands in the registry-conformance grey zone.
  3. Keep the dimension, name the subject only in subject_key_ids. Closest to today, still fails the rule's intent once the gate is keyed correctly.

(1) is the shape the grammar wants; (2) is the shape the epistemics want. Either is a deliberate choice. Doing nothing means the choice gets made for us by an upstream one-line fix.

Related, same audit

  • No signed instant in the envelope. Equivocation detection (CC 6.1.1 N4) compares the instant inside the signed envelope; ours omits asserted_at, so every row is NoSignedInstant — invisible to it. One-line fix, real integrity value. (The row column asserted_at is stamped at write time and is not covered by the content hash, so it cannot substitute.)
  • Nothing consumes health:liveness. Flow A filters dimension_prefixes = ["capacity:"], so these rows — ours or a peer's — are read by nothing today.

See FSD/MULTI_VANTAGE.md §2 (D5/D6) and §5 P2.

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