Files
govoplan-connectors/docs/ZNUNY_OTRS_CONNECTOR.md
zemion b277e8d7ac
Module Package Release / publish-packages (push) Successful in 12s
Release Connectors v0.1.22 with service-desk federation
2026-08-22 16:11:07 +02:00

189 lines
10 KiB
Markdown

# Znuny and OTRS-compatible service-desk connector
## Boundary
Connectors owns the governed endpoint profile, GenericInterface REST transport,
credential hand-off, provider discovery, bounded synchronization, external
references, mapping diagnostics, health, and recovery evidence. It does not own
ticket, helpdesk, or case semantics. A synchronized provider ticket remains an
external service-desk ticket; creating or relating a GovOPlaN Ticket, Helpdesk
item, or Case is the responsibility of the corresponding optional module.
The provider interface is `connectors.external_service_desk@1.0.0`, and the
target-tested provider declaration is `connectors.znuny.tickets`.
## Governed configuration and routes
Create an active connector definition/configuration with:
- `provider`: `znuny`, `otrs`, or `znuny_otrs`;
- `protocol`: `generic_interface_rest` (the aliases `rest` and
`otrs_generic_interface_rest` are accepted);
- an HTTP(S) endpoint that passes the central outbound-request policy; and
- an optional scoped Core credential-envelope reference.
Znuny GenericInterface routes are configured by each deployment rather than
being one universal product API. The profile therefore governs relative search,
ticket-read, and optional update paths and their supported
methods. Ticket and update paths must contain `{ticket_id}`. An optional
absolute HTTP(S) browser URL template may contain `{ticket_id}` or
`{ticket_number}`. `search_filters` carries up to 100 deployment-supported,
secret-free GenericTicket search criteria such as queue identifiers. It cannot
override synchronization bounds, ordering, change cursors, or authentication.
Routes cannot change authority or contain credentials.
Header authentication is the recommended default. The adapter supports the
documented `X-OTRS-Header-UserLogin`, `X-OTRS-Header-Password`,
`X-OTRS-Header-SessionID`, and customer-login headers. A legacy credential may
declare `auth_mode: body`, but then every affected route must use POST. Secret
fields are never placed in a GET URL, persisted projection, diagnostic, or API
response. Core also treats these provider headers as redirect-sensitive and
removes them before following any cross-origin redirect.
Reference configuration examples:
- [Znuny GenericTicketConnectorREST example](https://doc.znuny.org/znuny/admin/webservices/examples/GenericTicketConnectorREST/index.html)
- [Znuny provider and header authentication](https://doc.znuny.org/znuny-7_1/admin/webservices/provider/)
- [Znuny web-service configuration](https://doc.znuny.org/znuny-7_3/admin/webservices/config/index.html)
## Profile policy
The integration and authority choices are intentionally separate but bounded:
| Integration mode | Allowed authority | Maturity |
| --- | --- | --- |
| `link` | `linked_reference` | `link` through `search` |
| `import` | `external_authoritative`, `external_mirror` | exactly `read` |
| `synchronize` | `external_authoritative`, `governed_sync` | exactly `synchronize` |
`link` retains stable identity and routing facts and asks the provider not to
return articles, attachments, or dynamic fields; any unexpectedly returned
content is still discarded. `import` is a deliberate bounded full snapshot and
never silently changes to delta synchronization.
`synchronize` completes a full reconciliation and then advances to overlap-safe
change-time deltas.
Queue mappings govern inclusion, an optional opaque target queue reference, and
tenant or restricted visibility with ACL tokens. A restricted default requires
at least one ACL token. Provider-supplied `GovOPlaNVisibility` and
`GovOPlaNACL` fields win when valid. Otherwise a reviewed queue mapping wins,
then the profile default. Standard GenericInterface installations do not expose
a portable ticket-ACL contract, so every fallback is visible as a diagnostic.
Dynamic-field mappings govern source name, optional target name, inclusion, and
`string`, `number`, `boolean`, `date`, or `json` conversion. Conversion loss,
unreturned configured fields, provider-specific ticket fields, synthesized
identities, and truncation are structured diagnostics rather than silent loss.
## Discovery and synchronization
Discovery performs a bounded ticket search and records health, API family,
route hash, the exact governed configuration revision/hash, product/version
evidence, capabilities, maturity, and diagnostics. A changed endpoint,
configuration revision, or route map invalidates that evidence: synchronization,
and updates fail closed until discovery is repeated, while prior projections are
invalidated and Search stays closed until a new full reconciliation verifies
them. Integration, route, queue, or dynamic-field mapping changes also reset the
cursor and require a full reconciliation. Recognized Znuny or OTRS major
versions 6 and later can reach synchronization maturity. An unverified
product/version stays at read maturity. An update route adds the technical
`publish` capability, but does not override profile authority.
Full synchronization first obtains a stable ordered identity set, then reads at
most 500 tickets per call. A continued full run stores its offset, identity-set
fingerprint, and cumulative high-watermark. If the provider identity set changes
mid-run, the cursor is rejected and the operator must restart the full run. A
completed full run reconciles local removals and, for `synchronize` mode,
transitions to an overlap-safe delta cursor.
An explicit `full` request always restarts at the beginning; `auto` continues a
committed full cursor or advances a completed delta cursor. A caller-supplied
cursor must exactly match the profile's committed cursor, and delta mode cannot
bootstrap a profile that has not completed its full synchronization.
Delta synchronization reads the bounded candidate set, orders changes by
provider change time and ticket id, and suppresses only the exact ticket
revisions already observed at the current timestamp boundary. A previously seen
ticket that has changed again is therefore not lost. Every run requires a
profile-wide idempotency key. An exact replay returns the committed run without
contacting the provider; reuse for a different request or changed profile policy
is rejected.
Operational bounds:
- at most 10,000 ticket identities per profile search;
- at most 500 ticket reads per API call;
- at most 10 MB per provider response;
- a 20-second outbound timeout; and
- a 4,000-character cursor, including timestamp-boundary identities.
Partition larger or unusually bursty providers into queue-scoped profiles by
combining provider-side queue `search_filters` with matching queue mappings. A
full-run fingerprint conflict requires a restart. A timestamp-boundary overflow
requires a narrower partition. These are explicit safety stops, not partial
success claims.
## Mapping and attachment policy
Each ticket projection retains stable ticket id/number, title, type, queue,
target queue reference, state, priority, owner, responsible user, customer user,
organization, service, SLA, creation/change times, mapped dynamic fields,
articles, attachment metadata, permission source, ACLs, canonical URL, content
hash, provider revision, cursor, observation time, and source provenance.
Article and attachment references use Core `ExternalObjectReference` values.
Article bodies are capped at 200,000 characters. Attachment content is never
retained; only stable identity, filename, media type, size, disposition, content
id, article/ticket relationship, version, and provenance are mapped. Returned
bytes produce an `attachment_content_omitted` diagnostic.
## Search authorization
When Search is installed and both desired and discovered maturity permit it,
active non-deleted ticket projections are indexed. Search documents carry the
current visibility, ACL tokens, external reference, source revision, routing
metadata, article text, and bounded dynamic-field keywords.
Authorization always fails closed unless all of these remain true:
- the requesting principal belongs to the exact tenant;
- the principal has `connectors:service_desk:read`;
- the profile remains active and search-capable;
- the ticket remains active; and
- tenant visibility applies or a current account, membership, identity, group,
role, function, or scope ACL token intersects.
Pausing a profile or changing fallback/queue ACLs updates or removes Search
projections immediately. Search also rechecks the current database state for
every result, so a delayed index update does not grant access.
## Governed external updates and recovery
An external update is allowed only when the profile is active, authority is
`governed_sync`, discovery recorded the `publish` capability, and the caller has
`connectors:service_desk:update`. The request must include the synchronized
provider revision and a new idempotency key. Supported governed fields are
title, queue, state, priority, owner, responsible user, and explicitly mapped
dynamic fields.
Before dispatch, the adapter refetches the ticket and rejects a stale revision.
After dispatch, it refetches again and verifies both the changed revision and
every requested field value. A transport failure before a conclusive provider
response, an unchanged revision, or a requested value that cannot be confirmed
becomes `outcome_unknown`. Do not retry with another key. Inspect the provider
ticket and reconcile its accepted revision through the Core recovery evidence
first. Local database rollback cannot undo a remote provider mutation.
## Administrator verification
1. Create the governed definition/configuration and scoped credential envelope.
2. Create a restricted profile with reviewed routes, queue partitions, dynamic
fields, authority, and fallback ACLs.
3. Discover and confirm product/version, maturity, capabilities, and diagnostics.
4. Finish a keyed full run; continue while its cursor kind is `full`.
5. Run a new keyed automatic delta and inspect effects, losses, and health.
6. Verify one allowed and one denied Search principal against a restricted ticket.
7. If governed writes are enabled, update a non-production ticket with its
current revision, then verify provider and recovery evidence.
8. Reconcile every `outcome_unknown` run before any retry.