wispwisp
Core concepts

IAM derivation

Why wisp never asks you to write an IAM policy by hand.

Every wisp app has one Lambda function per route, queue consumer, schedule, bucket event, or workflow — which means IAM can be genuinely least-privilege: each function's role only grants what that function's own code actually touches, not what the app as a whole might need.

How it works

  1. The compiler walks each handler's body for calls on a known Store/Queue/Bucket/Workflow instance — orders.put(...), fulfillment.send(...), uploads.getObject(...), checkout.start(...).

  2. Each call maps to a concrete action:

    MethodAction
    store.get / .query / .batchGetread
    store.put / .updatewrite
    store.deletedelete
    store.transactWritewrite + delete
    queue.sendsend
    (registered as a queue's consumer)receive
    bucket.getObjectread
    bucket.putObject / .presignedPutwrite
    workflow.startinvoke
  3. Each action maps to concrete IAM actions — store.read becomes dynamodb:GetItem, dynamodb:Query, dynamodb:BatchGetItem; queue.receive becomes sqs:ReceiveMessage, sqs:DeleteMessage, sqs:GetQueueAttributes; and so on.

  4. Every statement is scoped to the specific resource's ARN. The only wildcard Resource wisp ever emits is the function's own CloudWatch Logs statement (logs:CreateLogStream/PutLogEvents, scoped to that function's own log group) — nothing else gets a "*".

Seeing it for yourself

wisp iam

prints a table of every function and its exact derived permissions — a real audit artifact, not a summary.

What this catches automatically

Because permissions are derived from what your code actually calls, a function that only reads from a store never gets write access, and a function that doesn't touch a bucket at all gets no S3 permissions whatsoever — there's no shared "app role" to accidentally over-grant.

A known, documented gap

If a store has global secondary indexes, a function that queries it gets read access to all of that store's indexes, not just the specific one a given .query() call targets — figuring out which index a call used would need deeper call-argument analysis than the compiler currently performs. It's a real least-privilege gap, but a narrow one: a read grant, not a write grant.

On this page