scim

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 9, 2026 License: AGPL-3.0 Imports: 16 Imported by: 0

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

type Client interface {
	Do(ctx context.Context, r Request) (Response, error)
}

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).

func (*HTTPClient) Do

func (c *HTTPClient) Do(ctx context.Context, r Request) (Response, error)

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

type Response struct {
	Status int
	Body   any
}

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

type Result struct {
	ResultVariable string
	Body           any
}

Result is what calling a Job produces: the decoded response, and the variable it belongs in.

func Run added in v0.5.0

func Run(ctx context.Context, j Job, client Client, secret SecretResolver) (Result, error)

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

type SecretResolver func(ref string) string

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL