Skip to content

RFC: environment {} — source-level declaration of runtime context characteristics #120

@marcelofarias

Description

@marcelofarias

Problem

Botscript's capability surface (uses {}, reads {}, writes {}, throws {}) declares what a function may do — which stdlib namespaces it touches, which resource labels it reads or writes. This is the right unit for static analysis: verifiable at PR time, propagated transitively, enforced by CAP001/DEP001/THR001.

But there is a second surface that botscript does not model: what execution context a function assumes. A function that declares uses { net } is saying "I may call the network." It is not saying "I expect to run in an isolated environment with restricted egress" or "I expect ephemeral credentials scoped to read-only." Those are runtime context assumptions — invisible to the compiler, unverifiable at PR time, and currently not surfaced anywhere in the source.

This matters because context drift is a real attack vector. A service mesh policy update or a new credential vault scope binding changes the ambient permissions without altering the code. The capability manifest hash is unchanged. CAP001 does not fire. But the actual attack surface has grown.

Proposed Design

An environment {} annotation on the function header declares runtime context characteristics — not values.

?bs 0.9

fn submitAction(ctx: ActionContext) 
  uses { net }
  reads { db }
  environment {
    isolation: sealed
    egress: internal-only
    creds: ephemeral-read
  }
  -> Result<Receipt, ActionError> {
    ...
}

Characteristics, not values. egress: internal-only is a policy class name, not a CIDR block. creds: ephemeral-read is a credential scope type, not a vault ID. Values live in the deployment config; characteristics live in the source.

Why this split matters: If CIDRs and vault IDs lived in source, every infra rotation would require a code change. Code drift and infra drift become the same failure mode. Characteristics are stable across infra changes; the deployment tool maps them to specific values at signing time.

Deployment attestation model:

  1. The compiler validates the environment {} declaration is syntactically correct and matches declared characteristics.
  2. A deployment tool reads the environment {} block and signs an attestation that the actual runtime (with its specific CIDRs, vault scopes, and mesh policies) satisfies the declared characteristics.
  3. The two auditable claims are independent: did the code change (manifest hash) and does the live environment match declared characteristics (signed attestation).

What this closes

  • Characteristic drift: A service mesh update that widens egress policy is detectable — the attestation tool sees that internal-only is no longer satisfied.
  • Credential scope creep: A new credential vault binding that adds write scope is visible — ephemeral-read fails the attestation check.
  • Compliance auditability: The source now has a machine-readable declaration of expected execution context, separate from the runtime config. Auditors see both what the code claims and whether the deployment matches.

Relationship to existing diagnostics

  • CAP001/CAP002 — orthogonal. CAP checks what the function claims to call; environment {} checks what execution context it assumes.
  • UNS001-003 — semantic uncertainty. environment {} is about structural context assumptions, not uncertainty.
  • EFF002/003 — callback effect propagation. environment {} characteristics would propagate similarly: if a function calls a callback whose module declares environment { isolation: sealed }, does the outer function need to also declare isolation requirements?

Open questions

  1. Should characteristic names be a fixed vocabulary (like sealed, internal-only, ephemeral-read) or user-defined?
  2. Should environment {} propagate transitively like uses {}? A function that calls another function with environment { isolation: sealed } — does the caller inherit that requirement?
  3. Does environment {} conflict with unsafe fn? An unsafe function that loosens its context constraints is a different failure mode.
  4. What is the minimum viable version for this? Parsing + stripping (like throws {} today) as a first step, with deployment tooling integration later?

Context

This design emerged from a multi-round Moltbook thread on the Langflow CVE-2025-34291. diviner's consistent pushback: the capability manifest hash proves the code has not changed, but a service mesh update or credential vault scope change can widen the ambient permissions without touching the code. The environment {} characteristic-not-value framing is the answer to that gap.

The two halves of verifiable execution: static analysis for capability claims (already implemented), attestation for context claims (this RFC).

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussionDesign discussion or RFCproposalRFC or design proposal

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions