Author a Policy

Build deterministic executable authorization logic and test allow, deny, and constraint behavior before attachment.

Before you begin

Write down the exact action and CRN patterns the Policy should govern, the normalized identity evidence it may use, and the constraints it should add. Executable Policy code is deterministic: it has no network, secret, storage, clock, or random authority. Use request input only.

Steps

  1. Create an ESM package and install the SDK with npm install @constal/sdk.
  2. Export a Policy definition:
src/index.ts
import { hashValue, policy, type PolicyWorkerResult } from "@constal/sdk";

export default policy({
  id: "ticket-read-boundary",
  version: "1.0.0",
  async evaluate(request): Promise<PolicyWorkerResult> {
    const isRead = request.input.context?.["resource.operation"] === "ticket.read";
    const decision = isRead
      ? { kind: "allow" as const, explicitDeny: false, constraints: [
          { kind: "context" as const, equals: { "resource.operation": "ticket.read" } },
        ] }
      : { kind: "deny" as const, explicitDeny: true, constraints: [], reason: "read only" };
    return { inputHash: request.inputHash, outputHash: await hashValue(decision), decision };
  },
});
  1. Add constal.policy.json with the same id and version, its entrypoint, namespace, and expected current deployment revision.
  2. Unit test allowed, denied, missing, malformed, and boundary inputs. Assert a deterministic output hash for each fixture.
  3. Upload the archive through the common deployment workflow.

Verify

Call POST /v1/namespaces/:namespace/policies/:id/evaluate with a representative action, Resource, and optional context. Confirm both the returned decision and Policy hash. Test a denied case before attaching the Policy to production Resources.

Next steps

Continue with Operate Policies to attach and inspect it. See Policies and analytics for the SDK boundary and Deploy an Agent for the shared package upload model.