189 lines
10 KiB
Markdown
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.
|