component

package module
v0.30.0 Latest Latest
Warning

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

Go to latest
Published: Jul 6, 2026 License: MIT Imports: 1 Imported by: 0

README

workflow-plugin-signal

Signal protocol primitives for Workflow

Installation

wfctl plugin install workflow-plugin-signal

Development

# Build
make build

# Test
make test

# Install locally
make install-local

Step Types

  • step.signal_session_prepare - create a public pre-key bundle for a local identity store.
  • step.signal_public_prekey_publish - publish a host-owned public pre-key bundle for an intake ref.
  • step.signal_public_prekey_resolve - resolve a public intake bundle by ref, with expiry and audience checks.
  • step.signal_encrypt - encrypt plaintext into a Signal session envelope.
  • step.signal_decrypt - decrypt an inbound Signal session envelope after the configured principal gate passes.
  • step.signal_sender_certificate_issue - issue a local/app-managed sealed-sender certificate for a registered identity.
  • step.signal_sender_seal - wrap a Signal session envelope in sealed-sender wire bytes without exposing sender id in the transport message.
  • step.signal_sender_seal_fanout - wrap multiple recipient-specific Signal session envelopes in sealed-sender wire bytes for app-managed group fanout.
  • step.signal_sender_unseal - unseal sender-sealed bytes, validate the sender certificate, and restore the Signal session envelope after the configured principal gate passes.
  • step.signal_outbox_enqueue - queue a ciphertext envelope with sender, recipient, custody, authorization, and message refs.
  • step.signal_outbox_claim - claim a queued outbox envelope for host transport without exposing plaintext.
  • step.signal_outbox_release - return a claimed outbox envelope to the queue for retry with ref-only failure metadata.
  • step.signal_outbox_ack - mark a claimed outbox envelope delivered after the host transport admits it downstream.
  • step.signal_inbox_receive - admit a ciphertext envelope into an inbox queue for a recipient ref.
  • step.signal_inbox_decrypt - decrypt an inbox envelope only when the caller supplies custody and authorization refs.
  • step.signal_blob_encrypt - encrypt blob bytes with a random content key and Signal-encrypt the blob manifest/key material to a recipient.
  • step.signal_blob_decrypt - decrypt a Signal-encrypted blob manifest, verify ciphertext and digest metadata, and release plaintext only with custody and authorization refs.
  • step.signal_fingerprint - compute a Signal safety number and scannable fingerprint from serialized identity public keys.
  • step.signal_fingerprint_assert - compute a Signal safety number and fail closed unless expected display or scannable fingerprint evidence matches.
  • step.signal_trust_observe - compute a Signal safety number, record first observation under explicit TOFU policy, and fail closed on changed or missing trust evidence.
  • step.signal_trust_reset - replace a stored trust record after caller-approved key rotation, with reason refs and optional previous-record compare-and-set.
  • step.signal_trust_history - query bounded, redacted trust decision history for app audit/support flows without returning raw safety-number evidence.
  • step.signal_trust_policy_check - gate app send/fanout/transport steps on stored trust record, last trust event status, record CAS, and freshness policy.
  • step.signal_trust_policy_check_batch - gate room send, fanout, collaboration, and queue workflows across multiple trust refs with one aggregated fail-closed decision.
  • step.signal_account_keys - derive account entropy, SVR, backup, backup-id, and PIN hash keys.
  • step.signal_username_artifact_prepare - generate upstream-compatible username reservation hash artifacts and optional encrypted username-link payloads without creating username proofs.
  • step.signal_username_link_create - create an encrypted Signal username link payload.
  • step.signal_username_link_decrypt - decrypt an encrypted Signal username link payload.
  • step.signal_service_contract_check - validate the disabled/test-double official-service boundary and return upstream compatibility metadata.
  • step.signal_service_compliance_check - report official-service readiness requirements, blocked live actions, and upstream service metadata without opening live transport.
  • step.signal_service_policy_check - evaluate live-service approval metadata and requested actions without opening live transport.
  • step.signal_service_approval_validate - validate machine-checkable live-service approval metadata and return denial reasons.
  • step.signal_service_live_submit - submit fake/sandbox service operations through a registered transport or return a no-egress live denial/dry-run acceptance.
  • step.signal_service_register_prepare - build a register operation envelope without submitting it, enriched from registered account/custody refs when available.
  • step.signal_service_link_prepare - build a linked-device operation envelope with consent, revocation, and unlink proof metadata.
  • step.signal_service_send_prepare - build a send operation envelope using recipient and payload refs only, with custody attestation metadata when account custody is registered.
  • step.signal_service_receive_admit - build a receive admission envelope using cursor refs only, with custody attestation metadata when account custody is registered.
  • step.signal_service_challenge_respond - build a challenge response envelope using challenge and response refs only, with custody attestation metadata when account custody is registered.
  • step.signal_username_proof_prepare - report username proof readiness without confirming usernames.
  • step.signal_backup_manifest_verify - report backup manifest readiness without uploading or downloading backups.
  • step.signal_backup_auth_prepare - report backup auth readiness without opening service transport.
  • step.signal_service_test_register - exercise deterministic fake registration with idempotency and ref-only outputs.
  • step.signal_service_test_link_device - exercise deterministic fake linked-device setup with idempotency and ref-only outputs.
  • step.signal_service_test_send - exercise deterministic fake sends, including challenge-required status.
  • step.signal_service_test_receive - exercise deterministic fake receives with idempotency and ref-only outputs.
  • step.signal_service_test_username_reserve - exercise deterministic fake username reservation by hash with idempotency and ref-only outputs.
  • step.signal_service_test_backup_upload - exercise deterministic fake backup upload with idempotency and ref-only outputs.
  • step.signal_service_test_backup_download - exercise deterministic fake backup download with idempotency and ref-only outputs.
  • step.signal_custody_create - create account/device custody refs and return sealed custody metadata.
  • step.signal_custody_rotate - rotate custody KEK metadata while preserving ref-only outputs.
  • step.signal_custody_restore - restore a sealed custody bundle through host-managed KEK refs.
  • step.signal_custody_revoke - mark a custody ref revoked and return redacted audit metadata.
  • step.signal_custody_inspect - inspect custody metadata without exposing key material.
  • step.signal_custody_attest - return custody attestation and evidence refs for application policy checks.
  • step.signal_custody_export_request - create ref-only export review metadata that remains approval-required.

Modules

  • signal.identity_store - in-memory identity, pre-key, and session state for local composition and conformance tests.
  • signal.envelope_store - memory, explicit local-file, SQLite, local object-store, or host-managed HTTP ciphertext queues for outbox/inbox application flows.
  • signal.space - typed configuration surface for binding encrypted spaces to rooms/eventbus.
  • signal.official_service_boundary - typed disabled/test-double boundary for selected upstream service wire shapes.
  • signal.service_transport - registered fake, sandbox, or approval-gated live transport boundary.
  • signal.live_policy - operation-specific approval and local operator-fixture policy metadata.
  • signal.key_custody - host-managed key custody refs for exportable secret refs or non-exportable key handles.
  • signal.persistent_custody - host-secret-backed encrypted local custody for non-exportable key handles.
  • signal.custody_store - v2 custody-store contract with backend, KEK, schema, and storage metadata.
  • signal.account_ref - account/device/consent/audit refs bound to host custody for fake official-service tests.
  • signal.public_prekey_directory - local public intake directory for host-published pre-key bundles.
  • signal.trust_store - memory, explicit local-file, or host-managed HTTP safety-number trust store for application-managed TOFU and trust policy gates.
  • trigger.signal_envelope - typed trigger-module contract for encrypted envelope transports.
  • trigger.signal_service_envelope - typed trigger-module contract for service-envelope transports; no live stream is opened unless a host supplies an approved transport.

The built-in identity store remains in-memory for application composition and conformance testing. Production deployments should bind identities to signal.key_custody and host-managed persistence before relying on restart survival.

step.signal_fingerprint_assert is a stateless trust gate for Workflow pipelines. It reuses the Signal safety-number computation from step.signal_fingerprint, accepts expected display and/or scannable evidence from config or input, normalizes display grouping and scannable hex casing, and returns verified: true only when every supplied expected value matches. Missing expected evidence or mismatches fail the step before downstream encryption, fanout, queueing, or transport steps run. It does not persist trust-on-first-use state, contact the official Signal service, or replace application authz.

signal.trust_store, step.signal_trust_observe, step.signal_trust_reset, and step.signal_trust_history add restart-safe application trust policy over the same safety-number/scannable fingerprint computation. A host supplies trust_ref from request, event, route, or CLI inputs; trust_on_first_use records the first observed fingerprint, require_existing accepts only an already recorded matching fingerprint, and pin_expected requires supplied display and/or scannable evidence before recording or accepting trust. Changed fingerprints fail closed and do not overwrite the stored record. A caller can then use step.signal_trust_reset only with a non-empty reason_ref to bind the reset to app-side approval or audit. previous_record_ref is an optional compare-and-set guard that rejects stale approvals if the stored trust record has already changed. Reset outputs contain refs, status, rotation state, reason ref, and fingerprint hash only; they do not return raw display or scannable fingerprint evidence. The default backend is memory for conformance and composition tests. The local_file backend requires allow_local_file: true, writes a checksum-protected JSON snapshot atomically, reloads after restart, rejects corrupt snapshots, and appends JSONL audit rows for persistent trust decisions. production_policy: true rejects local_file unless allow_production_local_file: true is explicitly set by the host. The object_store backend is a local object-store emulator for scenarios and host integration tests that need durable object-shaped trust custody before a live cloud adapter is approved. It requires allow_object_store_backend: true and storage_path, writes one checksum-protected trust snapshot object under a hash-derived key for the store_ref, reloads after restart, and rejects tampered snapshots or same-store objects found under the wrong key. It is always rejected under production_policy: true; production deployments should use the host-managed HTTP backend or a future approved storage adapter with its own credential, audit, and abuse-control boundary. The http backend delegates trust snapshot custody to a host-managed service. It requires endpoint_url, rejects URL userinfo, rejects plain http:// unless allow_insecure_http: true is set for local loopback fixtures, optionally sends an auth header from auth_header_env to auth_header_name, and uses generation_ref compare-and-set snapshot writes so stale app instances cannot silently overwrite trust state. Redacted trust-history events are stored in the same checksum-protected snapshot and can be queried with step.signal_trust_history by trust_ref, status, limit, and cursor. History outputs contain refs, statuses, policy, reason refs, and timestamps only; they do not return raw display safety numbers, scannable fingerprints, identity key bytes, private keys, plaintext, ciphertext, service credentials, or auth headers. Unknown history cursors fail closed instead of looking like end of history. step.signal_trust_policy_check reads one stored trust record and the latest redacted trust event before an app proceeds to send, seal, fan out, queue, or transport encrypted data. step.signal_trust_policy_check_batch applies the same decision rules to multiple trust refs and returns redacted per recipient decisions plus aggregate allowed/denied counts and a batch policy ref. These gates can enforce required record refs, allowed last statuses, max observed age, and explicit legacy-record opt-in. Denied policy checks fail closed by default; report_only returns denial metadata for audit/routing flows without running downstream send steps. This is a stored-state gate, not fresh key verification: apps should still run step.signal_trust_observe with current identity evidence before policy checks when they need to detect key changes. These primitives store public trust evidence and refs only; they do not contact the official Signal service, link devices, register accounts, send or receive service messages, or interact with the official Signal app.

signal.public_prekey_directory provides a public-intake directory for Workflow apps such as website contact forms, support intake, private reports, and encrypted upload flows. A host app publishes an intake bundle with step.signal_public_prekey_publish; unauthenticated callers resolve it with step.signal_public_prekey_resolve and then use the existing encrypt/blob steps to send ciphertext. Directory outputs contain public bundle material, bundle hash, public identity-key fingerprint, expiry, audience, and redacted metadata only. The default backend is memory. The explicit file backend requires allow_file_backend: true and storage_path, writes a schema-versioned checksum snapshot through a temp-file plus rename sequence, and reloads published entries after restart. The http backend delegates storage to a host-managed service and is the only backend accepted under policy_mode: production. It requires endpoint_url, rejects URL userinfo, rejects plain http:// unless allow_insecure_http: true is set for local fixtures, and optionally sends an auth header by reading auth_header_env at call time and writing it to auth_header_name. request_timeout_ms defaults to 5000 and is capped at 60000.

The object_store backend is a local object-store emulator for scenarios and host integration tests that need per-entry durable object semantics before a live cloud adapter is approved. It requires allow_object_store_backend: true and storage_path, writes one checksum-protected JSON object per intake ref under a hash-derived object key, reloads entries after restart, and rejects tampered objects before returning bundles. The backend is rejected under policy_mode: production; production deployments should use the host-managed HTTP backend or a future approved storage adapter with its own credential, audit, and abuse-control boundary.

The HTTP backend calls POST <endpoint_url>/entries with directory_ref, intake_ref, and an entry object containing bundle, public_metadata, bundle_sha256, and identity_key_fingerprint. Resolves call GET <endpoint_url>/entries/<path-escaped intake_ref> with optional audience_ref and requested_at_unix query parameters. Resolve responses use status: resolved with an entry, or not_found, expired, or audience_mismatch without an entry. The plugin recomputes bundle hashes and fingerprints, validates refs and audience/expiry, rejects denied responses that carry a bundle, and reports non-2xx failures by status code only. This module does not contact the official Signal service, implement one-time pre-key depletion, package a browser SDK, implement live cloud object storage, provide SQL backends, or solve intake abuse controls.

step.signal_sender_certificate_issue, step.signal_sender_seal, step.signal_sender_seal_fanout, and step.signal_sender_unseal expose Signal sealed-sender wire bytes for Workflow applications that need sender metadata minimization on untrusted app transport. Certificate issuance is local/app-managed fixture material: it creates a local trust root and server signer for private Workflow app flows. It is not official Signal service certificate issuance, account login, linked-device automation, or delivery through the official Signal app. The seal steps wrap existing SignalEnvelope ciphertexts and emit only recipient routing plus opaque sealed bytes; the sender id/device is restored only after the recipient unseals and validates the embedded sender certificate. Fanout seals each recipient's already encrypted session envelope independently and returns an all-or-nothing message list. It is not Signal group sender-key crypto and does not create a shared group ratchet.

signal.envelope_store keeps queued outbox and inbox payloads as Signal ciphertext plus redacted routing metadata. The memory backend is intended for application composition and conformance tests. The local_file backend must be explicitly enabled, is rejected under production policy mode, and persists only ciphertext envelopes and refs. The sqlite backend is also explicit opt-in via allow_sqlite_backend: true, requires storage_path, stores the same ciphertext-only queue snapshot in a local SQLite database, and is rejected under production policy mode until a managed database adapter has its own credential, migration, and scenario proof. The object_store backend is an explicit local object-store emulator for scenarios and host composition tests. It requires allow_object_store_backend: true and storage_path, writes one checksum-protected snapshot object under a hash-derived key, reloads after restart, rejects tampered or wrong-key objects, and is rejected under production policy mode until a live cloud adapter has separate credential and scenario proof. The http backend delegates the same checksum-protected snapshot to a host-managed service. It requires endpoint_url, rejects URL userinfo, rejects plain http:// unless allow_insecure_http: true is set for local loopback fixtures, optionally sends an auth header from auth_header_env to auth_header_name, and uses generation_ref compare-and-set writes so stale app instances cannot silently overwrite newer queue state. Outbox workers claim an envelope, then either release it for retry with last_error_ref metadata or ack it after downstream admission; acked envelopes are terminal and cannot be reclaimed. Inbox decrypt requires both custody and authorization refs before it delegates to the local Signal decrypt primitive.

step.signal_blob_encrypt and step.signal_blob_decrypt provide a local hybrid attachment pattern for Workflow apps. Blob bytes are encrypted with AES-256-GCM using a random content key; the content key, nonce, blob ref, plaintext digest, ciphertext digest, size, and media metadata live only inside a Signal-encrypted manifest envelope. The clear blob output contains ciphertext, nonce, size, and ciphertext digest so untrusted object stores, queues, and app routes can move bytes without seeing plaintext, plaintext digests, or content keys. Blob decrypt requires custody and authorization refs, validates the manifest against the blob, and fails on tampering. These steps do not implement official Signal attachment upload/download or any bundled production service egress.

signal.persistent_custody stores encrypted custody state in a host-selected file and registers only non-exportable key handles with Workflow. local_file requires both allow_local_file_custody: true and a host secret resolver. test_file is explicitly marked non-production and requires opt-in for conformance tests. Production policy mode rejects both file-backed custody backends; production hosts should provide approved KMS/HSM/security service refs instead of local files. Hermetic test://signal/... KEK refs derive deterministic test secrets only when no host resolver is configured.

signal.custody_store is the v2 custody contract for durable host-managed key custody. Its step contracts return custody refs and metadata only; plain key bytes are not ordinary Workflow outputs. Attestation and export-request steps return refs/evidence/status metadata for application policy checks and do not restore sealed material. The existing signal.persistent_custody module remains available for backward compatibility.

The scenarios/signal-custody-restart fixture covers the v2 custody lifecycle: create a sealed custody ref, reload the store after a simulated restart, restore by ref, rotate KEK metadata, inspect redacted metadata, revoke the ref, and reject restore after revocation. The scenario uses the test_file backend only; production hosts should use local_file with host-managed KEK custody. The standalone testdata/pipelines/signal-custody.yaml fixture is validated by make pipeline-test against a locally built plugin install. It can be executed through wfctl pipeline run only in hosts where external plugin loading is available for pipeline execution, or after installing the plugin into the host's normal plugin path. testdata/pipelines/signal-public-prekeys.yaml validates the public-intake publish/resolve contract against the same locally built external plugin. testdata/pipelines/signal-sealed-sender.yaml validates both single-recipient sealed sender and two-recipient sealed-sender fanout shape through the same external plugin boundary. testdata/pipelines/signal-trust-reset.yaml validates and executes a two-party trust-reset flow through wfctl pipeline run; callers provide tenant, sender, recipient, and message refs at runtime while the config supplies a local fixture identity pool.

Official Signal service registration, linked-device, send, and receive steps support deterministic libsignal-service-go/fake clients and host-supplied sandbox/operator fixtures. They return request IDs, statuses, challenge refs, selected username hash metadata for fake hash reservations, and host secret refs; they do not register accounts, link devices, send messages, receive messages, confirm usernames, upload backups, download backups, or contact the official Signal service via any bundled production endpoint client. Official Signal service egress remains unavailable unless a host supplies an approved transport and a complete machine-checkable approval package.

Operation-specific *_prepare, receive_admit, and challenge_respond steps produce ServiceOperationEnvelope metadata for application composition and approval review. When signal.account_ref and signal.key_custody or signal.persistent_custody are registered, prepare steps inherit device, credential, consent, audit, custody, and non-exportable key refs, validate custody ownership, and return custody attestation metadata plus readiness warnings. Linked-device envelopes require display name, consent evidence, consent expiry, revocation URI, and unlink proof refs, and reject replayed or revoked ceremony artifacts. Username artifact preparation is vector-backed for reservation hashes; username proof/confirm and backup steps expose readiness classifications rather than claiming upstream parity without vector proof.

step.signal_service_live_submit supports fake and sandbox transport exercises for register, linked device, send, receive, username reserve, backup upload/download, and challenge response operations. Live mode never invokes a bundled production endpoint. Incomplete approval packages return status: denied with approval_ready: false; complete approval packages without egress_dry_run return status: denied, approval_ready: true, and denial reason egress_dry_run_required; complete approval packages with egress_dry_run: true return status: dry_run_accepted, approval_ready: true, egress_dry_run: true, and live_egress_attempted: false without constructing a fake/sandbox transport. Username reserve submits should pass username_hashes or username_hash_hexes; plaintext username remains legacy fake-only compatibility and is not required for hash-path idempotency.

scenarios/signal-service-operator-fixture documents the local operator-fixture path for operation-specific prepare/admit steps. The fixture uses loopback transport metadata only and remains default-deny for production egress. Optional official live smoke tests require an external operator approval package, account-owner consent, custody policy, abuse policy, audit policy, and endpoint allowlist supplied by the host application; they are not CI or release gates.

Module

Go module: github.com/GoCodeAlone/workflow-plugin-signal

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Execute

func Execute(ctx context.Context, params map[string]interface{}) (map[string]interface{}, error)

Execute runs the Signal plugin logic.

func Init

func Init(services map[string]interface{}) error

Init initializes the Signal plugin.

func Name

func Name() string

Name returns the name of the signal plugin.

func Start

func Start(ctx context.Context) error

Start starts the Signal plugin.

func Stop

func Stop(ctx context.Context) error

Stop stops the Signal plugin.

Types

This section is empty.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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