Documentation
¶
Overview ¶
Package ops hosts chassis-core op handlers that consume the per-tenant secret store. These are computed-secret ops: they read cleartext from op.Secrets (via context), compute a digest or signature in-process, and write the **non-secret derived value** back into the response envelope. The cleartext is consumed once inside the op and goes nowhere else.
See internal docs/todo-secret-store.md §4.2 for the substitution-vs- computation split.
Index ¶
- func BasicAuthEncode(ctx context.Context, opName string, in, _ []byte) (event.Payload, error)
- func Copy(ctx context.Context, _ string, in, _ []byte) (event.Payload, error)
- func HMACSign(ctx context.Context, opName string, in, _ []byte) (event.Payload, error)
- func HMACVerify(ctx context.Context, opName string, in, _ []byte) (event.Payload, error)
- func WebRender(ctx context.Context, _ string, in, _ []byte) (event.Payload, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func BasicAuthEncode ¶
BasicAuthEncode is the handler for `txco://basic-auth-encode`. It produces the `base64(user:password)` value used by HTTP Basic auth (RFC 7617), with the password coming from op.Secrets.
WITH parameters (op.Meta):
secrets.password.secret = "TWILIO_AUTH_TOKEN" // required user = "AC1234567890" // required output_path = "_txc.computed.basic_auth" // default
The handler writes the encoded value (NOT the cleartext) at output_path. Downstream ops set the Authorization header as `Basic <encoded>` — typically via a `secrets.headers.authorization` declaration with `format = "Basic {output_path-value}"`, but since the encoded value is not itself a secret, simpler: just a normal SET that interpolates the envelope value into the header.
Cleartext is consumed inside this function and never leaves it. The base64 encoding is one-way only in the sense that base64- decoding reveals the cleartext — DO NOT trace this output as "non-secret"; it IS a wire credential. The op writes it at _txc.computed.* by default, where the operator chooses how to route it.
func Copy ¶
Copy is the handler for `txco://copy`. It reads a value from one envelope path and writes it to another, with optional encoding.
This is the chassis-side answer to "txcl SET RHS is literal-only" (the constraint that forces `txco://route` to exist in Go). When a rule needs to move an envelope field — e.g. "the response body for this web request lives at .text, please put it at _txc.web.res.body" — Copy is the primitive.
WITH parameters (op.Meta):
from = ".text" (required: source path on input envelope)
to = "_txc.web.res.body" (required: destination path on response)
encode = "base64" (optional: "base64" | "" — default "")
default = "fallback value" (optional: literal substituted when
the source path is empty/missing)
Path syntax follows gjson on read (a leading "." is optional and stripped) and sjson on write. When the source path is absent or resolves to an empty value AND `default` is set, the literal `default` value is used as the source instead — letting one rule express "use query param if present, else fall back to this." Without `default`, an empty source produces an empty destination (no failure). A missing `from` or `to` parameter at the WITH level IS an authoring error and fails loud.
func HMACSign ¶
HMACSign is the handler for `txco://hmac-sign`. It HMACs an envelope-path value with a named secret key and writes the digest at a declared output path.
WITH parameters (op.Meta):
secrets.key.secret = "WEBHOOK_HMAC" // required: NAME in op.Secrets algorithm = "sha256" // sha256 (default) | sha512 input_path = "body" // gjson path on op.Input output_path = "_txc.computed.sig" // sjson path on the response encoding = "hex" // hex (default) | base64
The handler reads `op.Secrets["WEBHOOK_HMAC"]` (the splice puts it there during processor.Run), computes `HMAC-<alg>(secret, gjson.Get(op.Input, input_path).Raw)`, and writes the digest into the response at output_path. The response is JSON; output_path defaults to `_txc.computed.hmac` if absent.
Cleartext is consumed inside this function and never leaves it — the digest is the safe-to-publish artifact (one-way function of input+key).
func HMACVerify ¶
HMACVerify is the handler for `txco://hmac-verify`. It recomputes an HMAC over an envelope-path value with a named secret key and constant-time-compares it to an expected signature carried on the envelope, writing a boolean result at output_path.
It is the verification counterpart to txco://hmac-sign, and it lives as an op (not a txcl function) for two reasons functions can't satisfy: the keyed HMAC needs the per-op secret bag (txcl functions never see it), and the comparison must be constant-time (a txcl `==` short-circuits and leaks timing). This is the primitive behind signed-webhook verification — Stripe / GitHub / Shopify / Slack all use minor variants of HMAC-over-body.
Gate it with a WHEN like any op; it only runs when its rule fires. It adds `sig_valid` to the response so a later rule can branch, e.g.:
WHEN ._txc.computed.sig_valid != true EXEC "txco://..." # reject / 401
WITH parameters (op.Meta):
secrets.key.secret = "STRIPE_WEBHOOK_SECRET" // required: NAME in op.Secrets algorithm = "sha256" // sha256 (default) | sha512 input_path = "verify.signed" // gjson path to the signed data expected_path = "verify.v1" // required: gjson path to the expected sig encoding = "hex" // hex (default) | base64 (of the expected sig) output_path = "_txc.computed.sig_valid" // sjson path for the bool result
String inputs are hashed as their literal (unquoted) value, so a scheme that signs a constructed string like Stripe's "t.body" works; object/array inputs use the raw JSON bytes (preserving whitespace and key order, which is what vendors sign).
Config problems (missing secret ref or expected_path, unmaterialized secret, bad algorithm/encoding) return an error. A missing, empty, or malformed expected signature is NOT an error — it's a failed verification, so the op emits sig_valid=false (fail closed).
The op emits ONLY the boolean — never the recomputed digest, which is itself a valid signature and must not leak into the envelope/trace.
func WebRender ¶
WebRender is the handler for `txco://web-render`. It reads a value from a source envelope path, optionally transforms it (raw / HTML wrap / markdown-to-HTML), base64-encodes it, and writes the result into the web-response shape `_txc.web.res.*` plus `_txc.halt = true`. Designed for the "scope 200 renders the answer that scope 100 produced" pattern.
WITH parameters (op.Meta):
source = ".text" (optional, default ".text")
content_type = "text/plain; charset=utf-8" (optional, default
matches the wrap mode)
status = 200 (optional, default 200)
wrap = "raw" (optional: "raw" |
"html" | "markdown-to-html")
`wrap` modes:
- "raw" — verbatim bytes. Default content-type "text/plain; charset=utf-8".
- "html" — wrap the (HTML-escaped) source in a minimal `<pre>` document. Default content-type "text/html; charset=utf-8".
- "markdown-to-html" — render the source as CommonMark via goldmark. Default content-type "text/html; charset=utf-8".
Types ¶
This section is empty.