Zetect Usage Guide Connector GuideSwitch portal ⇄

Publishing Results to Zetect

How a connector's result actually reaches Zetect — the publisher contract, what happens under the hood, and exactly which exchange/routing key/headers each result type uses.

The publisher contract

InterfaceUsed byRule
ConnectorPublisherhandle() — IDENTITY_SYNC, SYNC_USER, SYNC_GROUP, legacy actionsCall publish(ConnectorResult) exactly once — except a chunked sync (see connector-requests-responses), where you call it once per chunk.
ProvisioningPublisherhandleProvisioning() — CREATE_ACCOUNT, UPDATE_ACCOUNT, ADD_TO_GROUP, DELETE_ACCOUNT, REMOVE_FROM_GROUP, RESET_PASSWORDCall publish(ProvisioningResult) exactly once, always — provisioning results are never chunked.

What happens when you call publish()

  1. Your handle()/handleProvisioning() runs on an AMQP consumer thread inside cyiam-agent.
  2. publisher.publish(result) is a plain lambda — it calls the agent's internal publish method directly and synchronously, on the same thread your connector is running on.
  3. The agent serializes your ConnectorResult/ProvisioningResult to JSON. Null fields are omitted from the wire format, so unused/inapplicable fields never appear.
  4. The message is published to a single shared exchange with a routing key and headers that depend on the action (table below).
  5. If your plugin throws instead of publishing, the agent catches it and publishes a generic failure result on your behalf — so a crash never leaves Zetect waiting forever. Publish explicitly on every path anyway; don't rely on this as your error handling.

Exchange, routing keys & headers

ResultExchangeRouting keyHeaders
ConnectorResult — IDENTITY_SYNCcyiam.agentimport.outbound.<tenantId>x-run-id, x-connector-name, x-action
ConnectorResult — SYNC_USER / SYNC_GROUPcyiam.agentprov.outbound.<tenantId>x-run-id, x-connector-name, x-action
ProvisioningResult — everything elsecyiam.agentprov.outbound.<tenantId>x-request-id, x-status