@predicatesystems/temporal
v0.1.0
Published
Temporal.io Worker Interceptor for Predicate Authority Zero-Trust authorization
Maintainers
Readme
@predicatesystems/temporal
Temporal.io Worker Interceptor for Predicate Authority Zero-Trust authorization.
This package provides a pre-execution security gate for all Temporal Activities, enforcing cryptographic authorization mandates before any activity code runs.
Prerequisites
This package requires the Predicate Authority Sidecar daemon to be running. The sidecar is a lightweight Rust binary that handles policy evaluation and mandate signing.
| Resource | Link | |----------|------| | Sidecar Repository | github.com/PredicateSystems/predicate-authority-sidecar | | Download Binaries | Latest Releases | | License | MIT / Apache 2.0 |
Quick Sidecar Setup
# Download the latest release for your platform
# Linux x64, macOS x64/ARM64, Windows x64 available
# Extract and run
tar -xzf predicate-authorityd-*.tar.gz
chmod +x predicate-authorityd
# Start with a policy file
./predicate-authorityd --port 8787 --policy-file policy.jsonInstallation
npm install @predicatesystems/temporal
# or
yarn add @predicatesystems/temporal
# or
pnpm add @predicatesystems/temporalQuick Start
import { Worker } from "@temporalio/worker";
import { AuthorityClient } from "@predicatesystems/authority";
import { createPredicateInterceptors } from "@predicatesystems/temporal";
// Initialize the Predicate Authority client
const authorityClient = new AuthorityClient({
baseUrl: "http://127.0.0.1:8787",
});
// Create interceptors
const interceptors = createPredicateInterceptors({
authorityClient,
principal: "temporal-worker",
});
// Create worker with the interceptors
const worker = await Worker.create({
connection,
namespace: "default",
taskQueue: "my-task-queue",
workflowsPath: require.resolve("./workflows"),
activities,
interceptors,
});How It Works
The interceptor sits in the Temporal activity execution pipeline:
- Temporal dispatches an activity to your worker
- Before the activity code runs, the interceptor extracts:
- Activity type (action)
- Activity arguments (context)
- The interceptor calls
AuthorityClient.authorize()to request a mandate - If denied: throws
PredicateAuthorizationError- activity never executes - If approved: activity proceeds normally
This ensures that no untrusted code or payload reaches your OS until it has been cryptographically authorized.
Configuration
Interceptor Options
import { createPredicateInterceptors } from "@predicatesystems/temporal";
const interceptors = createPredicateInterceptors({
// Required: The Predicate Authority client
authorityClient: new AuthorityClient({ baseUrl: "http://127.0.0.1:8787" }),
// Optional: Principal ID (default: "temporal-worker")
principal: "my-worker",
// Optional: Tenant ID for multi-tenant setups
tenantId: "tenant-123",
// Optional: Session ID for request correlation
sessionId: "session-456",
// Optional: Custom resource identifier (default: "temporal:activity")
resource: "temporal:my-queue",
});Policy File
Create a policy file for the Predicate Authority daemon:
{
"rules": [
{
"name": "allow-safe-activities",
"effect": "allow",
"principals": ["temporal-worker"],
"actions": ["processOrder", "sendNotification"],
"resources": ["*"]
},
{
"name": "deny-dangerous-activities",
"effect": "deny",
"principals": ["*"],
"actions": ["delete*", "admin*"],
"resources": ["*"]
}
]
}API Reference
createPredicateInterceptors(options)
Creates the interceptor configuration object for Worker.create().
Parameters:
options.authorityClient(required):AuthorityClient- The Predicate Authority client instanceoptions.principal(optional):string- Principal ID (default:"temporal-worker")options.tenantId(optional):string- Tenant ID for multi-tenant setupsoptions.sessionId(optional):string- Session ID for request correlationoptions.resource(optional):string- Resource identifier (default:"temporal:activity")
Returns: WorkerInterceptors - The interceptor configuration for Temporal Worker
PredicateActivityInterceptor
The activity interceptor class. Usually you don't need to instantiate this directly - use createPredicateInterceptors() instead.
PredicateAuthorizationError
Custom error thrown when authorization is denied.
import { PredicateAuthorizationError } from "@predicatesystems/temporal";
try {
await workflow.executeActivity("dangerousActivity", args);
} catch (error) {
if (error instanceof PredicateAuthorizationError) {
console.log(`Denied: ${error.reason}`);
console.log(`Violated rule: ${error.violatedRule}`);
}
}Error Handling
When authorization is denied, the interceptor throws a PredicateAuthorizationError:
import { ApplicationFailure } from "@temporalio/workflow";
try {
await workflow.executeActivity("sensitiveActivity", args, {
startToCloseTimeout: "30s",
});
} catch (error) {
if (error instanceof ApplicationFailure) {
// Check if it's a Predicate denial
if (error.message.includes("Predicate Zero-Trust Denial")) {
// Handle authorization denial
console.log("Activity was blocked by security policy");
}
}
}Development
# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Type checking
npm run typecheck
# Linting
npm run lintLicense
MIT
