Graph Asset Registry

Owner: Graph Indexer Guild Contract: Asset Registry v1 Schema version: asset-registry.v1 Primary code: src/Graph/StellaOps.Graph.Indexer/Assets/

Purpose

Graph owns the canonical asset registry used by the shared EU compliance substrate. The same asset node schema is consumed by the NIS2 N4 inventory plan, the DORA D2 Register of Information plan, and later TLPT scoping work under the one-registry rule in the EU sprint execution directions.

Asset Registry v1 adds deterministic asset graph nodes, ASSET_VERSION lineage edges, and append-only asset lifecycle events. It does not replace the SBOM dependency graph: software components remain component nodes and may be linked to image or service assets.

Architecture Overview

The implemented Graph-owned slice has four layers:

The current Graph-owned adapters materialize image, container, integration, service, and plugin assets from their approved observation shapes. The v1 taxonomy also admits host, but the current adapter slice only carries host references on container/service attributes; a production host-asset source feed is not implemented in the committed Graph adapter code.

Schema Reference

Authoritative schema and contract files:

V1 asset types are closed to:

The enum is intentionally closed for v1. Credentials, secrets, people, teams, vulnerabilities, policy controls, findings, and software components are excluded asset types. The registry may store opaque references such as credential_ref, credentialRefs, ownerActorRef, and ownerTeamRef; it must not store secret values, names, email addresses, or dereferenced human PII.

Graph node mapping:

Asset lifecycle events:

Events carry payload_hash, previous_event_hash, merkle_leaf_hash, and event_hash. Removed assets are tombstones, not physical deletes. Findings Ledger mirrors those source rows read-only into findings.asset_registry_events and preserves the Graph payload and hash fields unchanged.

Source Indexing Pipeline

The Graph Indexer owns normalization from approved observations into asset registry documents:

Within one indexing batch, duplicate observations for the same deterministic asset ID reduce to the latest observation by observedAt, eventOffset, and tombstone state. Removed observations produce tombstone nodes, asset.removed events, and ASSET_VERSION edges with valid_to set to the removal time.

Production subscriptions use the Graph-owned file spool bridge:

The production bridge is intentionally file-based rather than a cross-module table write: Scanner, Integrations, Signals, and plugin hosts can publish the normalized contract without taking a dependency on Graph persistence or writing the graph PostgreSQL schema directly.

Sync Envelope

The formal offline/federated delta sync contract is Asset Inventory Sync v1. It wraps the Graph asset event stream without redefining asset payloads:

  1. Export existing asset-registry.v1 events.
  2. Order entries by occurred_at ASC, event_hash ASC.
  3. Canonicalize the bundle with Graph Indexer canonical JSON.
  4. Compute bundle_hash over the envelope excluding bundle_id and bundle_hash.
  5. On import, reconstruct every AssetRegistryEvent from the included payload and require existing payload/event/Merkle hashes to match.
  6. Apply only when the local per-asset chain contains the predecessor named by previous_event_hash, or skip the event when the same event hash already exists locally.

The local implementation is in src/Graph/StellaOps.Graph.Indexer/Assets/AssetInventorySyncEnvelope.cs. Focused tests in src/Graph/__Tests/StellaOps.Graph.Indexer.Tests/AssetInventorySyncEnvelopeTests.cs cover canonical serialization, idempotent apply, tamper detection, and missing-predecessor rejection.

Downstream Compliance Use

NIS2 inventory:

DORA RoI:

TLPT:

Implementation Status

Implemented:

Blocked or not yet implemented:

Offline Expectations

Sprint Evidence