@trigguard/execution-sdk
v0.1.3
Published
Execution gateway client: POST /execute, local receipt verification via /.well-known/trigguard/keys.json
Maintainers
Readme
@trigguard/execution-sdk
Node.js client for the execution gateway (POST /execute, GET /.well-known/trigguard/keys.json) with local Ed25519 receipt verification.
API
Authorize (decide) only:
import { authorize, verifyReceiptOffline, createExecutionClient } from "@trigguard/execution-sdk";
await authorize({
gatewayUrl: process.env.TRIGGUARD_GATEWAY_URL!,
surface: "deploy.release",
actorId: "my-agent",
apiKey: process.env.TRIGGUARD_API_KEY,
});Gate a side effect — withExecute calls /execute and runs your function only on PERMIT:
import { withExecute } from "@trigguard/execution-sdk";
await withExecute(
"deploy.release",
async () => {
await doDeploy();
},
{
gatewayUrl: process.env.TRIGGUARD_GATEWAY_URL!,
apiKey: process.env.TRIGGUARD_API_KEY, // optional tg_live_…
actorId: "ci",
context: { repository: "org/repo" },
}
);On DENY / SILENCE, it throws ExecutionNotPermittedError (see error.trigguardResult). Also re-exported from @trigguard/runtime.
Choosing an API shape
| Goal | API | Notes |
| ---- | --- | ----- |
| Protect a side effect (fail-closed) | withExecute | Canonical — matches examples/canonical-first-execution/. |
| Authorize, then branch yourself | createExecutionClient → authorize | Same HTTP surface; you handle DENY/SILENCE. |
| One-shot authorize | authorize() | Thin wrapper over the client. |
All paths accept gatewayUrl plus either apiKey (tg_live_…) or
getBearerToken. Prefer apiKey for customer keys. Env cheat-sheet:
docs/infrastructure/ENVIRONMENT_REFERENCE.md.
Typed failures (Wave 5)
As of Wave 5, the SDK exposes a categorical error vocabulary so integrators can route failures by category instead of by string-matching. All typed errors inherit from TrigGuardSdkError; the pre-existing ExecutionNotPermittedError is now also a TrigGuardSdkError (purely additive — existing instanceof Error and instanceof ExecutionNotPermittedError checks keep working).
import {
attemptExecute,
TrigGuardSdkError,
TrigGuardAuthError,
TrigGuardTimeoutError,
ExecutionNotPermittedError,
} from "@trigguard/execution-sdk";
try {
await attemptExecute("deploy.release", { gatewayUrl, apiKey });
} catch (e) {
if (e instanceof ExecutionNotPermittedError) {
/* policy DENY / SILENCE — do not retry */
} else if (e instanceof TrigGuardAuthError) {
/* expired or wrong credential — do not retry */
} else if (e instanceof TrigGuardTimeoutError) {
/* retryable */
} else if (e instanceof TrigGuardSdkError) {
/* any other typed failure — use e.category, e.retryable */
}
}Categories: auth | forbidden | network | timeout | malformed | http | trust | policy | verification | client-config. The retry-safety flag (e.retryable) is a deterministic function of the category — see docs/infrastructure/SDK_OPERATIONS.md for the full table.
Detailed receipt verification (Wave 5)
verifyReceiptSignatureDetailed returns a categorical reason instead of boolean:
import { verifyReceiptSignatureDetailed } from "@trigguard/execution-sdk";
const r = verifyReceiptSignatureDetailed(receipt, keysDoc);
if (!r.ok) {
// r.reason is one of: unsigned | missing-signing-key | missing-key-id |
// malformed-signature | signature-invalid | crypto-error
}The legacy verifyReceiptSignature(...) boolean signature is unchanged.
Opt-in diagnostics (Wave 5)
Set TRIGGUARD_SDK_VERBOSE=1 to enable structured stderr diagnostics. Off by default. The SDK never logs the auth token, the request body, or the response body — only URL, HTTP status, decision string, classified failure category, and retryable flag.
TRIGGUARD_SDK_VERBOSE=1 node my-app.js
# trigguard-sdk: authorize decision=PERMIT, failureCategory=<none>, httpStatus=200, retryable=<none>, url=https://gatewaySafety notes
- Local-vs-prod auth. The SDK accepts a missing auth provider (no
apiKey, nogetBearerToken) — convenient for local dev. In production this almost always indicates a misconfiguration. EnableTRIGGUARD_SDK_VERBOSE=1during local development to surface a one-timeno-auth-tokenwarning. - Fail-closed contract.
withExecuteruns the protected function only ondecision === "PERMIT". Any other outcome — DENY, SILENCE, missing decision, non-2xx HTTP, network failure, timeout — does not run the function. - Receipt verification.
verifyReceiptSignature/verifyReceiptSignatureDetailedperform Ed25519 verification locally using keys from/.well-known/trigguard/keys.json. No external network call is made during verification once the keys document is in hand. - No secrets in diagnostics. See above.
Onboarding examples
Canonical, runnable, offline. From the repo root:
node examples/sdk-onboarding/00-minimal-authorize.mjs
node examples/sdk-onboarding/01-fail-closed-withexecute.mjs
node examples/sdk-onboarding/02-verify-receipt-locally.mjs
node examples/sdk-onboarding/03-local-dev-diagnostics.mjs
node examples/sdk-onboarding/04-typed-error-routing.mjsSee examples/sdk-onboarding/README.md for details and docs/infrastructure/SDK_OPERATIONS.md for the operator/integrator companion.
Build & test
npm ci && npm run build
npm testRelationship to other packages
trigguard(sdk/trigguard-js) — hosted site verification API (/protocol/verify-receipt, etc.).@trigguard/execution-sdk— Cloud Run execution gateway (authorize → receipt).
Protocol semantics remain in trigguard-protocol; this package is a thin HTTP + crypto wrapper.
