Documentation
¶
Overview ¶
Package scim integrates a SCIM 2.0 service provider as a service-task Worker Type (RFC 7643/7644): a BPMN SCIM task performs a resource operation — create, get, replace, patch, delete, or search a User/Group — against a model-authored provider endpoint through the job path (ADR-0153), the same seam the rest package uses for a generic HTTP call (ADR-0067). It inherits the job protocol's durability and non-blocking properties (ADR-0007):
- A SCIM task creates a job carrying the reserved compiler.ScimJobType. The processor never performs the outbound call itself, so it stays allocation-free (invariant I1) and free of any HTTP dependency.
- The in-process Handler — a job worker — pulls those jobs, calls the SCIM provider off the processor goroutine and after fsync (invariant I2, never inside applyToState / I4), writes the JSON response into the task's result variable, and completes the job, which drives the token onward.
Like REST, a SCIM task authors its base URL, resource type, operation, resource id, and filter in the model; credentials are never authored there — authentication (basic/bearer/apiKey) names a server-side secret the worker resolves at runtime (ADR-0041/0067), so a token never appears in a BPMN file. Unlike the generic REST worker it speaks SCIM: it sends and accepts application/scim+json, addresses resources by path (…/Users/{id}), and turns a SCIM error response (a urn:…:Error object with a detail/scimType) into the job failure message rather than an opaque status.
Delivery is at-least-once (a crash between "the provider accepted the call" and "job completed" replays the request); every request carries the job key as an Idempotency-Key header so a well-behaved provider de-duplicates a replayed create rather than provisioning the account twice.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Handler ¶
func Handler(store state.Reader, lookup ProcessLookup, client Client, secret SecretResolver) job.OutputHandler
Handler builds a job handler that performs a SCIM 2.0 worker task. Register it with a job.Runner under the reserved compiler.ScimJobTypeIndex via HandleWithOutput; the runner then pulls activatable SCIM jobs, and for each the handler resolves the task's base URL / resource / operation / resource-id / filter / result-variable from the compiled process and calls the provider through client — evaluating any FEEL values over the variables the task sees, up its scope chain (the fx toggle, ADR-0067) and sending the request payload for create/replace/patch, keyed by the job key so an at-least-once retry de-duplicates. Authentication (basic/bearer/apiKey) is resolved through secret, which turns the model's secret *reference* into the credential at call time (ADR-0041); the token never lives in the model. When the task names a result variable, the JSON response is returned as that variable to be written back into the instance on completion. Returning an error fails the job (retry, then an incident, ADR-0061); the runner completes it only on success.
Types ¶
type Client ¶
Client calls a SCIM provider. It is an interface so the worker is testable without a live server.
type HTTPClient ¶
type HTTPClient struct {
// contains filtered or unexported fields
}
HTTPClient calls a real SCIM provider over HTTP. It sends Request.Body as an application/scim+json body (when present) with an Idempotency-Key header, and decodes a JSON response body. A non-2xx status is returned as an error carrying the SCIM error detail (RFC 7644 §3.12) so the job stays pending and is retried (at-least-once).
func NewHTTPClient ¶
func NewHTTPClient() *HTTPClient
NewHTTPClient builds a SCIM HTTP client bounded by the shared worker call budget (nettimeout.HTTPClient), like the REST worker: the worker runs on the run-loop goroutine, so an unbounded call would stall the whole engine (ADR-0149).
type Job ¶ added in v0.5.0
type Job struct {
Operation string `json:"operation"`
BaseURL string `json:"baseUrl"`
Resource string `json:"resource"`
ResourceID string `json:"resourceId,omitempty"`
// Filter narrows a search; it is sent as the SCIM `filter` query parameter.
Filter string `json:"filter,omitempty"`
// Body is the create/replace/patch payload: the named body variable, or the
// task's input mappings, or everything it sees. It is engine state — a worker has
// no scope chain to read a process variable from — so it travels resolved.
Body map[string]any `json:"body,omitempty"`
// Auth is the authored auth configuration, encoded as it sits in the compiled
// process. It names a secret; it never carries one (see [compiler.RestAuth]).
Auth string `json:"auth,omitempty"`
// IdempotencyKey is the job key, so a call retried after a lease elapsed is
// recognizable to the provider as the same one.
IdempotencyKey string `json:"idempotencyKey,omitempty"`
// Result names the process variable the response is written to; empty means the
// model discards it.
Result string `json:"resultVariable,omitempty"`
}
Job is a SCIM task with everything the engine can evaluate already evaluated.
func Resolve ¶ added in v0.5.0
func Resolve(store state.Reader, cp *compiler.CompiledProcess, detail *compiler.ConnectorTaskDetail, ei *model.ElementInstanceValue, elementInstanceKey, jobKey uint64) (Job, error)
Resolve turns a compiled SCIM task into a Job. Engine work by necessity: FEEL is compiled at deploy (ADR-0008/0015) and the scope lives in the store.
type ProcessLookup ¶
type ProcessLookup func(defKey uint64) *compiler.CompiledProcess
ProcessLookup resolves a process-definition key to its compiled process. The worker uses it to find the base URL, resource, operation, and result variable a SCIM job belongs to, so one handler serves every deployed process.
type Request ¶
type Request struct {
Method string
URL string
Headers map[string]string
Query map[string]string
Body map[string]any
IdempotencyKey string
}
Request is one SCIM call a task makes. URL is the resolved resource endpoint (base + resource type, plus /{id} for a single-resource operation). Headers are set on the request (including any Authorization/api-key header the worker resolved from a secret); Query is appended to the URL (a search's filter). Body, when non-nil, is sent as an application/scim+json request body (the worker attaches it only for create/replace/patch). IdempotencyKey is deterministic (the job key), so an at-least-once retry can be de-duplicated by the provider.
type Response ¶
Response is a SCIM call's outcome. Status is the HTTP status code; Body is the decoded JSON response (the resource, a ListResponse, or nil for a 204 delete), or the raw response text when it is not valid JSON.
type Result ¶ added in v0.5.0
Result is what calling a Job produces: the decoded response, and the variable it belongs in.
func Run ¶ added in v0.5.0
Run derives the request from a resolved job, applies the caller's own credential, and makes the call. The in-process path calls it too, so there is one definition of what a resolved SCIM task means rather than two that drift — only whose secret store is in reach differs.
func (Result) Variables ¶ added in v0.5.0
func (r Result) Variables() []model.VariableValue
Variables renders a call's result as the process variables the job completes with — none when the model named no result variable. Both halves call it, so an offloaded call and an in-engine one cannot disagree about what a SCIM task returns.
type SecretResolver ¶
SecretResolver returns the secret value for a reference name, or "" if unknown. The worker uses it to turn a SCIM task's authentication secret *reference* into the actual credential at call time (ADR-0041), so a token never lives in the model or the compiled process — only its reference does.