Skip to content

Latest commit

 

History

History
133 lines (97 loc) · 3.81 KB

File metadata and controls

133 lines (97 loc) · 3.81 KB

Function Manifest (v2)

This document defines the per-function manifest used by the runtime.

  • Schema file: schemas/function-manifest.v2.schema.json
  • Base schemas:
    • schemas/base/common.schema.json
    • schemas/base/network.schema.json
  • JSON Schema draft: 2020-12

Versioning

The runtime accepts only:

  • manifestVersion: 2

Any payload using manifestVersion: 1 is rejected.

Goal

The manifest lets each function declare:

  • Deploy flavor (flavor):
    • single
    • routed-app
  • Optional route table (routes) for routed apps:
    • kind: "function" routes with per-route entrypoint
    • kind: "asset" routes with assetDir
  • Environment variables (env.allow, env.secretRefs)
  • Network allowlist (network.allow)
  • Optional resource limits (resources)
  • Optional auth and observability preferences
  • Optional profile overrides (profiles)

Security Model

The runtime enforces internal SSRF deny rules regardless of the manifest.

  • A manifest cannot allow entries that collide with deny ranges from runtime-core/src/ssrf.rs.
  • If network.allow contains denylisted targets, deployment fails.
  • * is not allowed in network.allow.

At runtime, when a manifest is attached to a function:

  • network.allow is enforced as a per-function allowlist.
  • env.allow and env.secretRefs are enforced as per-function env controls.
  • Resource fields from resources are applied into IsolateConfig limits.

When no manifest is attached, runtime behavior remains the default policy.

Flavor and Routes Rules

  • flavor: "single"
    • must not define routes.
  • flavor: "routed-app"
    • must define at least one route.
  • kind: "function" route:
    • requires non-empty entrypoint
    • cannot define assetDir
  • kind: "asset" route:
    • requires non-empty assetDir
    • cannot define entrypoint
    • if methods is provided, only GET and HEAD are allowed

Deploy API Integration

Deploy endpoint:

  • POST /_internal/functions
  • Required header: x-function-name
  • Optional header: x-function-manifest-b64
  • Optional header: x-function-manifest-profile

x-function-manifest-b64 must contain the manifest JSON encoded as Base64.

If present, the server validates:

  1. JSON decode / parse
  2. JSON Schema v2020-12 (v2 schema)
  3. Semantic checks (flavor/routes and denylist)

If validation fails, response is 400 Bad Request.

If the header is absent but the uploaded BundlePackage contains an embedded manifest (generated by thunder bundle --manifest ...), the deploy flow resolves and applies that embedded manifest.

Update and Reload Behavior

  • PUT /_internal/functions/{name}:
    • If x-function-manifest-b64 is provided, the function manifest is replaced.
    • If x-function-manifest-b64 is omitted, the existing manifest is preserved.
  • POST /_internal/functions/{name}/reload:
    • Keeps the currently attached manifest.

Inspecting Current Manifest

  • GET /_internal/functions/{name}/manifest

Responses:

  • 200: returns current ResolvedFunctionManifest
  • 404: function exists without manifest ({"error":"manifest not configured for function"})
  • 404: function not found ({"error":"not found"})

Watch Mode Note

thunder watch deploys functions without attaching a manifest automatically.

If you need manifest-enforced behavior in development, deploy via admin endpoint with x-function-manifest-b64.

Example Manifest (v2 single)

{
  "$schema": "https://thunder.dev/schemas/function-manifest.v2.schema.json",
  "manifestVersion": 2,
  "name": "hello",
  "entrypoint": "./index.ts",
  "flavor": "single",
  "env": {
    "allow": ["LOG_LEVEL"],
    "secretRefs": ["APP_SECRET"]
  },
  "network": {
    "mode": "allowlist",
    "allow": ["api.example.com:443"]
  },
  "resources": {
    "maxHeapMiB": 128,
    "cpuTimeMs": 50000,
    "wallClockTimeoutMs": 60000
  }
}