version: 2
title: CIEM Demo
contributor: thatDot
summary: A structural standing query rejects a compromised deployment before it ships, by recursively resolving version-specific dependency trees and marking the build blocked. No reliance on maintainer age.
description: >-
  Quine 2.0.2 v2 recipe. One streaming graph: a version-specific npm dependency tree
  (Version -[:DEPENDS_ON]-> Version), a cloud IAM chain, and a deployable service. Images link
  only to the packages they DIRECTLY use; the standing query does the deep resolution. One alerting
  standing query, block-deploy: when a pending image's direct deps recursively resolve to
  install-exec + env-secret-read + network-egress across distant branches AND its builder is a
  privilege bridge (an assume->pass->read chain reaching a secret), it sets the image status to
  "blocked" and reports it. A second tiny SQ, blocked-build-watch, simply surfaces blocked images to
  the UI. block-deploy does not use maintainer account age — that is an explanation detail surfaced
  by quick queries. The aha: a deep dependency re-resolves, a new build goes pending-deploy, and
  block-deploy rejects it structurally at build time, before deploy, with no IOC for the variant.
  Synthetic; trigger only.
ingestStreams:
  # ---- Baseline domain 1: version-specific npm dependency tree ----
  - name: package-registry
    source:
      type: File
      path: PackageBaseline.ndjson
      format:
        type: Json
    query: |-
      WITH $that AS that
      CALL {
        WITH that
        WITH that WHERE that.kind = "version"
        MATCH (pkg), (ver), (maint)
        WHERE id(pkg) = idFrom("package", that.pkg)
          AND id(ver) = idFrom("version", that.pkg, that.version)
          AND id(maint) = idFrom("maintainer", that.maintainer)
        SET pkg:Package, pkg.name = that.pkg, pkg.weekly_downloads = that.weekly_downloads,
            ver:Version, ver.version = that.version, ver.coord = that.pkg + "@" + that.version,
            ver.publish_ts = datetime({epochSeconds: that.publish_ts}),
            maint:Maintainer, maint.handle = that.maintainer, maint.account_age_days = that.maintainer_account_age_days
        CREATE (pkg)-[:HAS_VERSION]->(ver)
        CREATE (ver)-[:PUBLISHED_BY]->(maint)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "version"
        UNWIND that.dep_versions AS dv
        MATCH (ver), (depver)
        WHERE id(ver) = idFrom("version", that.pkg, that.version)
          AND id(depver) = idFrom("version", dv.pkg, dv.version)
        SET depver:Version, depver.version = dv.version, depver.coord = dv.pkg + "@" + dv.version
        CREATE (ver)-[:DEPENDS_ON]->(depver)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "version"
        UNWIND that.capabilities AS capId
        MATCH (ver), (cap)
        WHERE id(ver) = idFrom("version", that.pkg, that.version) AND id(cap) = idFrom("capability", capId)
        SET cap:Capability, cap.id = capId
        CREATE (ver)-[:HAS_CAPABILITY]->(cap)
      }
  # ---- Baseline domain 2: cloud IAM + service + currently-running image ----
  - name: cloud-asset-inventory
    source:
      type: File
      path: CloudBaseline.ndjson
      format:
        type: Json
    query: |-
      WITH $that AS that
      CALL {
        WITH that
        WITH that WHERE that.kind = "secret"
        MATCH (s) WHERE id(s) = idFrom("secret", that.name)
        SET s:Secret, s.name = that.name, s.arn = that.arn
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "identity"
        MATCH (idn) WHERE id(idn) = idFrom("identity", that.name)
        SET idn:Identity, idn.name = that.name, idn.subject = that.subject
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "identity"
        UNWIND that.can_assume_roles AS roleName
        MATCH (idn), (r)
        WHERE id(idn) = idFrom("identity", that.name) AND id(r) = idFrom("role", roleName)
        SET r:Role, r.role_name = roleName
        CREATE (idn)-[:CAN_ASSUME]->(r)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "role"
        MATCH (r) WHERE id(r) = idFrom("role", that.role_name)
        SET r:Role, r.role_name = that.role_name, r.arn = that.arn, r.account = that.account,
            r.incarnation = that.incarnation
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "role"
        UNWIND that.can_read_secrets AS secName
        MATCH (r), (s)
        WHERE id(r) = idFrom("role", that.role_name) AND id(s) = idFrom("secret", secName)
        SET s:Secret, s.name = secName
        CREATE (r)-[:CAN_READ]->(s)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "role"
        UNWIND that.can_assume_roles AS roleName
        MATCH (r), (r2)
        WHERE id(r) = idFrom("role", that.role_name) AND id(r2) = idFrom("role", roleName)
        SET r2:Role, r2.role_name = roleName
        CREATE (r)-[:CAN_ASSUME]->(r2)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "role"
        UNWIND that.can_pass_roles AS roleName
        MATCH (r), (r3)
        WHERE id(r) = idFrom("role", that.role_name) AND id(r3) = idFrom("role", roleName)
        SET r3:Role, r3.role_name = roleName
        CREATE (r)-[:CAN_PASS]->(r3)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "service"
        MATCH (svc) WHERE id(svc) = idFrom("service", that.name)
        SET svc:Service, svc.name = that.name
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "image"
        MATCH (img) WHERE id(img) = idFrom("image", that.digest)
        SET img:Image, img.digest = that.digest, img.built_at = datetime({epochSeconds: that.built_at}), img.status = "running"
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "image"
        MATCH (img), (idn)
        WHERE id(img) = idFrom("image", that.digest) AND id(idn) = idFrom("identity", that.built_by)
        SET idn:Identity, idn.name = that.built_by
        CREATE (img)-[:BUILT_BY]->(idn)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "image"
        MATCH (svc), (img)
        WHERE id(svc) = idFrom("service", that.running_for_service) AND id(img) = idFrom("image", that.digest)
        SET svc:Service, svc.name = that.running_for_service
        CREATE (svc)-[:RUNS]->(img)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "image"
        UNWIND that.uses AS u
        MATCH (img), (v)
        WHERE id(img) = idFrom("image", that.digest) AND id(v) = idFrom("version", u.pkg, u.version)
        SET v:Version, v.version = u.version, v.coord = u.pkg + "@" + u.version
        CREATE (img)-[:USES]->(v)
      }
  # ---- Foundation: a small, clean benign example, loaded fast at startup ----
  # Use it to explain the data model before the story. Same comprehensive query as background.
  - name: workload-inventory
    source:
      type: File
      path: FoundationData.ndjson
      format:
        type: Json
    query: &allKinds |-
      WITH $that AS that
      CALL {
        WITH that
        WITH that WHERE that.kind = "version"
        MATCH (pkg), (ver), (maint)
        WHERE id(pkg) = idFrom("package", that.pkg)
          AND id(ver) = idFrom("version", that.pkg, that.version)
          AND id(maint) = idFrom("maintainer", that.maintainer)
        SET pkg:Package, pkg.name = that.pkg, pkg.weekly_downloads = that.weekly_downloads,
            ver:Version, ver.version = that.version, ver.coord = that.pkg + "@" + that.version,
            ver.publish_ts = datetime({epochSeconds: that.publish_ts}),
            maint:Maintainer, maint.handle = that.maintainer, maint.account_age_days = that.maintainer_account_age_days
        CREATE (pkg)-[:HAS_VERSION]->(ver)
        CREATE (ver)-[:PUBLISHED_BY]->(maint)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "version"
        UNWIND that.dep_versions AS dv
        MATCH (ver), (depver)
        WHERE id(ver) = idFrom("version", that.pkg, that.version)
          AND id(depver) = idFrom("version", dv.pkg, dv.version)
        SET depver:Version, depver.version = dv.version, depver.coord = dv.pkg + "@" + dv.version
        CREATE (ver)-[:DEPENDS_ON]->(depver)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "version"
        UNWIND that.capabilities AS capId
        MATCH (ver), (cap)
        WHERE id(ver) = idFrom("version", that.pkg, that.version) AND id(cap) = idFrom("capability", capId)
        SET cap:Capability, cap.id = capId
        CREATE (ver)-[:HAS_CAPABILITY]->(cap)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "secret"
        MATCH (s) WHERE id(s) = idFrom("secret", that.name)
        SET s:Secret, s.name = that.name, s.arn = that.arn
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "identity"
        MATCH (idn) WHERE id(idn) = idFrom("identity", that.name)
        SET idn:Identity, idn.name = that.name, idn.subject = that.subject
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "identity"
        UNWIND that.can_assume_roles AS roleName
        MATCH (idn), (r)
        WHERE id(idn) = idFrom("identity", that.name) AND id(r) = idFrom("role", roleName)
        SET r:Role, r.role_name = roleName
        CREATE (idn)-[:CAN_ASSUME]->(r)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "role"
        MATCH (r) WHERE id(r) = idFrom("role", that.role_name)
        SET r:Role, r.role_name = that.role_name, r.arn = that.arn, r.account = that.account,
            r.incarnation = that.incarnation
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "role"
        UNWIND that.can_read_secrets AS secName
        MATCH (r), (s)
        WHERE id(r) = idFrom("role", that.role_name) AND id(s) = idFrom("secret", secName)
        SET s:Secret, s.name = secName
        CREATE (r)-[:CAN_READ]->(s)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "role"
        UNWIND that.can_assume_roles AS roleName
        MATCH (r), (r2)
        WHERE id(r) = idFrom("role", that.role_name) AND id(r2) = idFrom("role", roleName)
        SET r2:Role, r2.role_name = roleName
        CREATE (r)-[:CAN_ASSUME]->(r2)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "role"
        UNWIND that.can_pass_roles AS roleName
        MATCH (r), (r3)
        WHERE id(r) = idFrom("role", that.role_name) AND id(r3) = idFrom("role", roleName)
        SET r3:Role, r3.role_name = roleName
        CREATE (r)-[:CAN_PASS]->(r3)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "service"
        MATCH (svc) WHERE id(svc) = idFrom("service", that.name)
        SET svc:Service, svc.name = that.name
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "image"
        MATCH (img) WHERE id(img) = idFrom("image", that.digest)
        SET img:Image, img.digest = that.digest, img.built_at = datetime({epochSeconds: that.built_at}), img.status = "running"
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "image"
        MATCH (img), (idn)
        WHERE id(img) = idFrom("image", that.digest) AND id(idn) = idFrom("identity", that.built_by)
        SET idn:Identity, idn.name = that.built_by
        CREATE (img)-[:BUILT_BY]->(idn)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "image"
        MATCH (svc), (img)
        WHERE id(svc) = idFrom("service", that.running_for_service) AND id(img) = idFrom("image", that.digest)
        SET svc:Service, svc.name = that.running_for_service
        CREATE (svc)-[:RUNS]->(img)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "image"
        UNWIND that.uses AS u
        MATCH (img), (v)
        WHERE id(img) = idFrom("image", that.digest) AND id(v) = idFrom("version", u.pkg, u.version)
        SET v:Version, v.version = u.version, v.coord = u.pkg + "@" + u.version
        CREATE (img)-[:USES]->(v)
      }
  # ---- Background: large realistic benign stream, a logically-ordered sequence of service
  # deployments (deps-first). parallelism: 1 ingests strictly in order so the sequence is honored;
  # maxPerSecond throttles it so it streams over many minutes while you present. ----
  - name: cloud-workload-telemetry
    source:
      type: File
      path: BackgroundData.ndjson
      format:
        type: Json
    parallelism: 1
    maxPerSecond: 20
    query: *allKinds
  # ---- Injected signal events via named pipe (iam_grant | version | build) ----
  - name: ci-pipeline-events
    source:
      type: File
      path: ci-pipeline-events
      fileIngestMode: NAMED_PIPE
      format:
        type: Json
    query: |-
      WITH $that AS that
      CALL {
        WITH that
        WITH that WHERE that.kind = "iam_grant" AND that.grant = "pass_role"
        MATCH (src), (tgt)
        WHERE id(src) = idFrom("role", that.source_role) AND id(tgt) = idFrom("role", that.target_role)
        SET src:Role, tgt:Role
        CREATE (src)-[:CAN_PASS]->(tgt)
      }
      // ARN REUSE: the deploy pipeline recreated a role at the SAME arn but a new incarnation with
      // risky permissions. Keyed by (name, incarnation) so it is a DISTINCT node from the original
      // that happens to share the arn -- the structural pattern, not the arn, is what we detect on.
      CALL {
        WITH that
        WITH that WHERE that.kind = "arn_reuse"
        MATCH (r2) WHERE id(r2) = idFrom("role", that.role_name, that.incarnation)
        SET r2:Role, r2.role_name = that.role_name, r2.arn = that.arn, r2.account = that.account,
            r2.incarnation = that.incarnation, r2.recreated_at = datetime({epochSeconds: that.recreated_at})
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "arn_reuse"
        UNWIND that.can_pass_roles AS tgt
        MATCH (r2), (t)
        WHERE id(r2) = idFrom("role", that.role_name, that.incarnation) AND id(t) = idFrom("role", tgt)
        SET t:Role, t.role_name = tgt
        CREATE (r2)-[:CAN_PASS]->(t)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "arn_reuse"
        MATCH (idn), (r2)
        WHERE id(idn) = idFrom("identity", that.assumed_by) AND id(r2) = idFrom("role", that.role_name, that.incarnation)
        SET idn:Identity
        CREATE (idn)-[:CAN_ASSUME]->(r2)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "version"
        MATCH (pkg), (ver), (maint)
        WHERE id(pkg) = idFrom("package", that.pkg)
          AND id(ver) = idFrom("version", that.pkg, that.version)
          AND id(maint) = idFrom("maintainer", that.maintainer)
        SET pkg:Package, pkg.name = that.pkg, pkg.weekly_downloads = that.weekly_downloads,
            ver:Version, ver.version = that.version, ver.coord = that.pkg + "@" + that.version,
            ver.publish_ts = datetime({epochSeconds: that.publish_ts}),
            maint:Maintainer, maint.handle = that.maintainer, maint.account_age_days = that.maintainer_account_age_days
        CREATE (pkg)-[:HAS_VERSION]->(ver)
        CREATE (ver)-[:PUBLISHED_BY]->(maint)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "version"
        UNWIND that.capabilities AS capId
        MATCH (ver), (cap)
        WHERE id(ver) = idFrom("version", that.pkg, that.version) AND id(cap) = idFrom("capability", capId)
        SET cap:Capability, cap.id = capId
        CREATE (ver)-[:HAS_CAPABILITY]->(cap)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "build"
        UNWIND that.reresolve AS rr
        MATCH (depender:Version), (newV:Version)
        WHERE id(depender) = idFrom("version", rr.depender_pkg, rr.depender_version)
          AND id(newV) = idFrom("version", rr.new_pkg, rr.new_version)
        OPTIONAL MATCH (depender)-[oldEdge:DEPENDS_ON]->(oldV:Version)
        WHERE id(oldV) = idFrom("version", rr.old_pkg, rr.old_version)
        DELETE oldEdge
        CREATE (depender)-[:DEPENDS_ON]->(newV)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "build"
        MATCH (img) WHERE id(img) = idFrom("image", that.digest)
        SET img:Image, img.digest = that.digest,
            img.built_at = datetime(),
            img.status = "pending"
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "build"
        UNWIND that.uses AS u
        MATCH (img), (v)
        WHERE id(img) = idFrom("image", that.digest) AND id(v) = idFrom("version", u.pkg, u.version)
        SET v:Version, v.version = u.version, v.coord = u.pkg + "@" + u.version
        CREATE (img)-[:USES]->(v)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "build"
        MATCH (img), (idn)
        WHERE id(img) = idFrom("image", that.digest) AND id(idn) = idFrom("identity", that.built_by)
        SET idn:Identity, idn.name = that.built_by
        CREATE (img)-[:BUILT_BY]->(idn)
      }
      CALL {
        WITH that
        WITH that WHERE that.kind = "build"
        MATCH (img), (svc)
        WHERE id(img) = idFrom("image", that.digest) AND id(svc) = idFrom("service", that.deploy_to)
        SET svc:Service, svc.name = that.deploy_to
        CREATE (img)-[:PENDING_DEPLOY_TO]->(svc)
      }
standingQueries:
  # SQ block-deploy (AUTO-FIRES; the only alerting SQ). Pattern is a coarse, legal trigger: an image goes
  # pending-deploy. The OUTPUT is unconstrained Cypher, so it RECURSIVELY resolves the image's direct
  # deps down the version-specific DEPENDS_ON tree and rejects the deploy only if all three worm
  # capabilities are assembled (from distant branches) AND the builder is a privilege bridge.
  - name: block-deploy
    pattern:
      type: Cypher
      mode: MULTIPLE_VALUES
      query: |-
        MATCH (img:Image)-[:PENDING_DEPLOY_TO]->(:Service)
        RETURN img.digest AS digest
    outputs:
      - name: alert
        preEnrichmentTransformation:
          type: InlineData
        resultEnrichment:
          parameter: that
          allowAllNodeScan: false
          query: |-
            MATCH (img) WHERE id(img) = idFrom("image", $that.digest)
            MATCH (img)-[:USES]->(:Version)-[:DEPENDS_ON*0..15]->(ieV:Version)-[:HAS_CAPABILITY]->(iec:Capability)
            WHERE iec.id = "install-exec"
            MATCH (img)-[:USES]->(:Version)-[:DEPENDS_ON*0..15]->(esV:Version)-[:HAS_CAPABILITY]->(esc:Capability)
            WHERE esc.id = "env-secret-read"
            MATCH (img)-[:USES]->(:Version)-[:DEPENDS_ON*0..15]->(neV:Version)-[:HAS_CAPABILITY]->(nec:Capability)
            WHERE nec.id = "network-egress"
            MATCH (img)-[:BUILT_BY]->(idn:Identity)-[:CAN_ASSUME|CAN_PASS*1..6]->(:Role)-[:CAN_READ]->(s:Secret)
            SET img.status = "blocked",
                img.blocked_at = datetime()
            WITH img, ieV, esV, neV, idn, s, "http://localhost:8080/explorer#" + text.urlencode(
              "MATCH (img),(ie),(es),(ne),(idn),(s) WHERE id(img)='" + strId(img) + "' AND id(ie)='" + strId(ieV)
              + "' AND id(es)='" + strId(esV) + "' AND id(ne)='" + strId(neV) + "' AND id(idn)='" + strId(idn)
              + "' AND id(s)='" + strId(s) + "' RETURN img"
            ) AS url
            RETURN "[BLOCK-DEPLOY] image " + img.digest + " (built " + toString(img.built_at)
              + ", blocked " + toString(img.blocked_at) + " -- " + toString(duration.between(img.built_at, img.blocked_at).milliseconds)
              + "ms after build) assembled the full worm capability set from deep dependencies: install-exec via "
              + ieV.coord + ", env-secret-read via " + esV.coord + ", network-egress via " + neV.coord
              + " -- built by privilege-bridge identity '" + idn.name + "' that can reach '" + s.name
              + "'. DEPLOYMENT REJECTED, detected structurally at build time before deploy. Open in explorer: "
              + url AS alert
        destinations:
          - type: StandardOut
  # SQ-3 blocked-build-watch: a trivial pattern that matches ONLY builds block-deploy has marked
  # status="blocked". Its sole purpose is the SSE results endpoint the bookmarklet subscribes to,
  # so the browser auto-renders each blocked build the instant it is rejected.
  - name: blocked-build-watch
    pattern:
      type: Cypher
      mode: DISTINCT_ID
      query: |-
        MATCH (img:Image)
        WHERE img.status = "blocked"
        RETURN DISTINCT strId(img) AS id
    outputs:
      - name: log
        destinations:
          - type: StandardOut
nodeAppearances:
  - predicate:
      dbLabel: Package
      propertyKeys: []
      knownValues: {}
    icon: 📦
    color: '#9aa5b1'
    label:
      type: Property
      key: name
      prefix: ''
  - predicate:
      dbLabel: Version
      propertyKeys: []
      knownValues: {}
    icon: 🏷️
    color: '#4f86c6'
    label:
      type: Property
      key: coord
      prefix: ''
  - predicate:
      dbLabel: Maintainer
      propertyKeys: []
      knownValues: {}
    icon: 👤
    color: '#2e8b57'
    label:
      type: Property
      key: handle
      prefix: ''
  - predicate:
      dbLabel: Capability
      propertyKeys: []
      knownValues: {}
    icon: ⚠️
    color: '#e4572e'
    label:
      type: Property
      key: id
      prefix: ''
  - predicate:
      dbLabel: Identity
      propertyKeys: []
      knownValues: {}
    icon: 🤖
    color: '#8e5bb5'
    label:
      type: Property
      key: name
      prefix: ''
  - predicate:
      dbLabel: Role
      propertyKeys: []
      knownValues:
        incarnation: "2"
    icon: 🛡️
    color: '#c1121f'
    label:
      type: Property
      key: role_name
      prefix: 'recreated '
  - predicate:
      dbLabel: Role
      propertyKeys: []
      knownValues: {}
    icon: 🛡️
    color: '#2a9d8f'
    label:
      type: Property
      key: role_name
      prefix: ''
  - predicate:
      dbLabel: Secret
      propertyKeys: []
      knownValues: {}
    icon: 🔑
    color: '#d4af37'
    label:
      type: Property
      key: name
      prefix: ''
  - predicate:
      dbLabel: Service
      propertyKeys: []
      knownValues: {}
    icon: 🚀
    color: '#3d5a80'
    label:
      type: Property
      key: name
      prefix: ''
  - predicate:
      dbLabel: Image
      propertyKeys: []
      knownValues:
        status: blocked
    icon: 🛑
    color: '#c1121f'
    label:
      type: Property
      key: digest
      prefix: 'build '
  - predicate:
      dbLabel: Image
      propertyKeys: []
      knownValues:
        status: pending
    icon: 🐳
    color: '#f4a261'
    label:
      type: Property
      key: digest
      prefix: 'build '
  - predicate:
      dbLabel: Image
      propertyKeys: []
      knownValues:
        status: running
    icon: 🐳
    color: '#2a9d8f'
    label:
      type: Property
      key: digest
      prefix: 'build '
quickQueries:
  # 1-hop navigations: no arrow. Transitive multi-hop: arrow prefix; collapse with edgeLabel.
  # NOTE: "Adjacent Nodes" MUST be first — the explorer runs the first quick query on double-click,
  # so this is what expands a node's neighbors.
  - predicate:
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Adjacent Nodes
      querySuffix: MATCH (n)--(m) RETURN DISTINCT m
      queryLanguage: Cypher
      sort: NODE
  - predicate:
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Refresh
      querySuffix: RETURN n
      queryLanguage: Cypher
      sort: NODE
  - predicate:
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Local Properties
      querySuffix: RETURN id(n), properties(n)
      queryLanguage: Cypher
      sort: TEXT
  # ---- Image ----
  - predicate:
      dbLabel: Image
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Direct Dependencies Used
      querySuffix: MATCH (n)-[:USES]->(v:Version) RETURN v
      queryLanguage: Cypher
      sort: NODE
  - predicate:
      dbLabel: Image
      propertyKeys: []
      knownValues:
        status: blocked
    quickQuery:
      # Scoped to BLOCKED builds only (status=blocked). Surfaces the three worm capabilities the deep
      # dependency tree assembled, collapsed to synthetic edges straight from the build to each capability.
      name: → Why Blocked (dangerous capabilities)
      querySuffix: |-
        MATCH (n)-[:USES]->(:Version)-[:DEPENDS_ON*0..15]->(:Version)-[:HAS_CAPABILITY]->(c:Capability)
        WHERE c.id IN ["install-exec","env-secret-read","network-egress"]
        RETURN DISTINCT c
      queryLanguage: Cypher
      edgeLabel: Dangerous Capability
      sort: NODE
  - predicate:
      dbLabel: Image
      propertyKeys: []
      knownValues: {}
    quickQuery:
      # The mind-boggling expansion: the entire resolved dependency tree behind this image.
      name: → Full Resolved Dependency Tree
      querySuffix: MATCH (n)-[:USES]->(:Version)-[:DEPENDS_ON*0..15]->(d:Version) RETURN DISTINCT d
      queryLanguage: Cypher
      sort: NODE
  - predicate:
      dbLabel: Image
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Built By
      querySuffix: MATCH (n)-[:BUILT_BY]->(idn:Identity) RETURN idn
      queryLanguage: Cypher
      sort: NODE
  # ---- Version ----
  - predicate:
      dbLabel: Version
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Resolved Dependencies
      querySuffix: MATCH (n)-[:DEPENDS_ON]->(d:Version) RETURN d
      queryLanguage: Cypher
      sort: NODE
  - predicate:
      dbLabel: Version
      propertyKeys: []
      knownValues: {}
    quickQuery:
      # DOWN the chain, recursively: every version this one depends on, all the way to the leaves.
      # Returns the whole set so the real DEPENDS_ON edges render the full tree (no synthetic edge).
      name: → All Dependencies (down, recursive)
      querySuffix: MATCH (n)-[:DEPENDS_ON*1..20]->(d:Version) RETURN DISTINCT d
      queryLanguage: Cypher
      sort: NODE
  - predicate:
      dbLabel: Version
      propertyKeys: []
      knownValues: {}
    quickQuery:
      # Aggregate every capability anywhere in this version's resolved tree (itself + all transitive
      # deps via *0..20), collapsed to a synthetic edge straight from this version to each capability.
      # This is the recursive structural roll-up: the union of capabilities the whole subtree carries.
      name: → Aggregate Capabilities (deep, recursive)
      querySuffix: MATCH (n)-[:DEPENDS_ON*0..20]->(d:Version)-[:HAS_CAPABILITY]->(c:Capability) RETURN DISTINCT c
      queryLanguage: Cypher
      edgeLabel: Aggregated Capability
      sort: NODE
  - predicate:
      dbLabel: Version
      propertyKeys: []
      knownValues: {}
    quickQuery:
      # UP the chain, recursively: every version that depends on this one, directly or transitively.
      name: → All Dependents (up, recursive)
      querySuffix: MATCH (a:Version)-[:DEPENDS_ON*1..20]->(n) RETURN DISTINCT a
      queryLanguage: Cypher
      sort: NODE
  - predicate:
      dbLabel: Version
      propertyKeys: []
      knownValues: {}
    quickQuery:
      # Blast radius: every version that transitively pulls this one in.
      name: → Who Pulls Me In (blast radius)
      querySuffix: MATCH (a:Version)-[:DEPENDS_ON*1..15]->(n) RETURN DISTINCT a
      queryLanguage: Cypher
      edgeLabel: Transitively Depends
      sort: NODE
  - predicate:
      dbLabel: Version
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Published By
      querySuffix: MATCH (n)-[:PUBLISHED_BY]->(m:Maintainer) RETURN m
      queryLanguage: Cypher
      sort: NODE
  # ---- Secret (crown jewel) ----
  - predicate:
      dbLabel: Secret
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: → Who Can Reach Me (privilege bridge)
      querySuffix: MATCH (n)<-[:CAN_READ]-(:Role)<-[:CAN_ASSUME|CAN_PASS*1..6]-(idn:Identity) RETURN DISTINCT idn
      queryLanguage: Cypher
      edgeLabel: Can Reach
      sort: NODE
  # ---- Identity ----
  - predicate:
      dbLabel: Identity
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Roles I Can Assume
      querySuffix: MATCH (n)-[:CAN_ASSUME]->(r:Role) RETURN r
      queryLanguage: Cypher
      sort: NODE
  - predicate:
      dbLabel: Identity
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: → Secrets I Can Reach
      querySuffix: MATCH (n)-[:CAN_ASSUME|CAN_PASS*1..6]->(:Role)-[:CAN_READ]->(s:Secret) RETURN DISTINCT s
      queryLanguage: Cypher
      edgeLabel: Can Reach Secret
      sort: NODE
  - predicate:
      dbLabel: Identity
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Images I Built
      querySuffix: MATCH (n)<-[:BUILT_BY]-(img:Image) RETURN img
      queryLanguage: Cypher
      sort: NODE
  # ---- Role ----
  - predicate:
      dbLabel: Role
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Grants (assume / pass / read)
      querySuffix: MATCH (n)-[:CAN_ASSUME|CAN_PASS|CAN_READ]->(m) RETURN m
      queryLanguage: Cypher
      sort: NODE
  - predicate:
      dbLabel: Role
      propertyKeys: []
      knownValues: {}
    quickQuery:
      # ARN reuse: other Role nodes that share this role's ARN — i.e. earlier/later incarnations
      # of "the same" role recreated at the same ARN with different permissions.
      name: → Other incarnations (same ARN)
      querySuffix: MATCH (o:Role) WHERE o.arn = n.arn AND id(o) <> id(n) RETURN o
      queryLanguage: Cypher
      edgeLabel: Same ARN
      sort: NODE
  # ---- Service ----
  - predicate:
      dbLabel: Service
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Running & Pending Images
      querySuffix: MATCH (n)<-[:RUNS|PENDING_DEPLOY_TO]-(img:Image) RETURN img
      queryLanguage: Cypher
      sort: NODE
  # ---- Maintainer ----
  - predicate:
      dbLabel: Maintainer
      propertyKeys: []
      knownValues: {}
    quickQuery:
      name: Versions Published
      querySuffix: MATCH (n)<-[:PUBLISHED_BY]-(v:Version) RETURN v
      queryLanguage: Cypher
      sort: NODE
sampleQueries:
  # Sample queries return ONLY nodes so they render on the canvas (edges auto-draw).
  # Start here: the clean teaching example. Double-click acme-web to expand outward.
  - name: Start here · acme-web service
    query: MATCH (s) WHERE id(s) = idFrom("service", "acme-web") RETURN s
  - name: Full graph
    query: MATCH (n) RETURN n
  - name: Deployment state (service, running, pending)
    query: MATCH (i:Image)--(s:Service) RETURN i, s
  - name: IAM — assume / pass / read chain
    query: MATCH (n)-[:CAN_ASSUME|CAN_PASS|CAN_READ]->(m) RETURN n, m
  - name: ARN reuse — same ARN, two role identities
    query: MATCH (r:Role) WHERE r.arn = "arn:aws:iam::111111111111:role/deploy-role" RETURN r
  - name: viz-charts resolved dependency tree
    query: MATCH (v:Version)-[:DEPENDS_ON*0..15]->(d:Version) WHERE v.coord = "viz-charts@3.4.0" RETURN v, d
  # 5 examples of each node type, returned WITH a neighbor so the canvas shows their connections
  # (a bare `MATCH (n:Label) RETURN n` would render isolated nodes — the explorer only draws edges
  # between nodes that are BOTH in the result, even though the edges exist).
  - name: 5 · Services (with their build)
    query: MATCH (n:Service)-[:RUNS]->(b:Image) RETURN n, b LIMIT 5
  - name: 5 · Images / builds (with build identity)
    query: MATCH (n:Image)-[:BUILT_BY]->(idn:Identity) RETURN n, idn LIMIT 5
  - name: 5 · Identities (with assumable role)
    query: MATCH (n:Identity)-[:CAN_ASSUME]->(r:Role) RETURN n, r LIMIT 5
  - name: 5 · Roles (with grant)
    query: MATCH (n:Role)-[:CAN_ASSUME|CAN_READ]->(m) RETURN n, m LIMIT 5
  - name: 5 · Secrets (with reader role)
    query: MATCH (n:Secret)<-[:CAN_READ]-(r:Role) RETURN n, r LIMIT 5
  - name: 5 · Packages (with a version)
    query: MATCH (n:Package)-[:HAS_VERSION]->(v:Version) RETURN n, v LIMIT 5
  - name: 5 · Versions (with a dependency)
    query: MATCH (n:Version)-[:DEPENDS_ON]->(d:Version) RETURN n, d LIMIT 5
  - name: 5 · Maintainers (with a published version)
    query: MATCH (n:Maintainer)<-[:PUBLISHED_BY]-(v:Version) RETURN n, v LIMIT 5
  - name: 5 · Capabilities (with a version that has it)
    query: MATCH (n:Capability)<-[:HAS_CAPABILITY]-(v:Version) RETURN n, v LIMIT 5
  # one full deployment, to confirm a service is wired to everything
  - name: One full service deployment
    query: |-
      MATCH (s:Service)-[:RUNS]->(img:Image)
      OPTIONAL MATCH (img)-[:BUILT_BY]->(idn:Identity)-[:CAN_ASSUME]->(dr:Role)-[:CAN_ASSUME]->(tr:Role)-[:CAN_READ]->(sec:Secret)
      OPTIONAL MATCH (img)-[:USES]->(v:Version)
      RETURN s, img, idn, dr, tr, sec, v LIMIT 20
