Skip to content

v0.17.0

Choose a tag to compare

@github-actions github-actions released this 13 Jul 14:23

Forge v0.17.0 — AARM (Autonomous Action Runtime Management) compliance: intent alignment, step-up & defer authorization, JIT credentials, and tamper-evident audit signing

Forge v0.17.0 is the largest security release yet for the open-source AI agent runtime. It implements AARM — Autonomous Action Runtime Management, an open-source security specification for governing what AI agents are allowed to do at runtime. This release lands the AARM control set end to end: per-call intent-alignment scoring (R3, #245), longitudinal intent-drift detection (R7, #246), tool-wide guardrail enforcement (R4a, #221), RFC 9470 step-up authorization (R4b, #247), pause-and-resume defer authorization (R4c, #248), a tamper-evident audit hash chain with Ed25519 signing (R5/R6, #220, #237), and just-in-time credential dispensing per tool call (R9, #236). Together they let a platform prove what an agent did, why it was allowed, and that the record wasn't altered.

This release also ships reversible context compression (ctxzip) that cuts 60–95% of tokens on bulky tool outputs losslessly (#241, #279), an opt-in headless-browser tool family driven through the egress proxy (#260), a pluggable session store with a remote backend for stateless Kubernetes replicas (#244), guardrails that now apply to every tool rather than just cli_execute (#221), a platform guardrails policy overlay (#285), and a wave of Skill Builder improvements — structured JSON output (#276), built-in-tool awareness (#297), and skill-first activation routing (#298).

Highlights

  • Intent alignment — every tool call scored against the user's stated goal (#245, governance R3). Each action is embedded (tool_description + args_json) and compared by cosine similarity to the task's stated intent. Fail-closed: when enabled and the embedder is unavailable, calls DENY rather than silently bypass. Off by default (security.intent_alignment.enabled), with a recommended warn-only first rollout. Emits an intent_alignment audit event per call. See Intent Alignment.
  • Intent drift detection — catches the "boiling frog" (#246, governance R7). A rolling window watches the trend of intent-alignment scores across a task's lifetime and trips on either a mean-below-threshold or a monotone-decrease pattern. intent_drift fires only on state changes (enter / recover), so long drift stretches never flood the audit stream.
  • Step-up authorization — RFC 9470 challenges (#247, governance R4b). A high-assurance tool call whose caller lacks a sufficient acr claim returns HTTP 401 with a WWW-Authenticate: Bearer error="step_up_required" challenge instead of running. Optional acr_hierarchy lets a stronger assurance satisfy a weaker requirement. Emits auth_step_up_required. See Step-up Authorization.
  • Defer authorization — pause, approve out-of-band, resume (#248, governance R4c). A high-risk tool call pauses the executor; an external approver POSTs a decision and the executor resumes exactly where it left off. The A2A task status flips to deferred while blocked. Distinct from DENY (refuses) and STEP_UP (re-auths). See Deferred Authorization.
  • JIT credential dispensing — short-lived secrets per tool call (#236, governance R9). A new forge-core/credentials/ package materializes credentials at the moment of a tool call and revokes them after, so long-lived secrets never sit in the agent's environment. Ships static and sts_assume_role (AWS STS AssumeRole via SDK-free hand-rolled SigV4) providers. Emits credential_issued / credential_revoked / credential_failed — never the credential material itself. See Least-privilege credentials.
  • Tamper-evident audit logging — Ed25519 signatures + hash chain + JWKS (#220, #237). Every audit event now carries a prev_hash link, and — when signing is enabled — a kid + sig. The signature covers prev_hash, so altering the chain breaks both the chain walk and the signature check. A JWKS endpoint publishes the verification key. See Audit signing.
  • Reversible context compression (ctxzip) — 60–95% fewer tokens, losslessly (#241, #279). Bulky tool outputs (JSON arrays, logs, grep, kubectl get -o json) are compressed before reaching the LLM behind an inline <<ctxzip:HASH …>> marker, and recovered on demand via a new context_expand tool. Lossy on the wire, lossless end-to-end. v0.3.0 adds whole-record items[] crushing, categorical drop summaries, and a YAML/describe crusher, plus a keep_patterns learning loop. Off by default (compression.enabled). See Context Compression.
  • Opt-in headless-browser tool family (#260, issue #94). Agents can drive a real headless Chromium (via chromedp) to navigate, read, click, fill, and screenshot — registered only when an active skill declares requires.capabilities: [browser]. The LLM acts on a compact indexed page digest (~1–3 KB), not raw HTML. All traffic is forced through the existing EgressProxy (allowlist / SSRF / DNS-rebinding protection); browser_fill refuses password and payment fields unless the skill opts in. See Browser Tools.
  • Guardrails now apply to every tool, not just cli_execute (#221, governance R4a). deny_commands / deny_output patterns previously no-op'd for web_search, http_request, MCP, and custom tools. That short-circuit is removed. Potentially breaking — see Upgrade notes.
  • Platform guardrails overlay (#285). A platform policy.yaml can now layer additional, most-restrictive-wins guardrails on top of an agent's guardrails.json, and the unused MongoDB "DB mode" guardrails path is removed. See Platform Policy.
  • Pluggable session store with a remote backend (#244). memory.session_store: remote pushes per-task session snapshots to a platform service over HTTP with conditional GET (If-None-Match) and If-Match CAS commits, so stateless Kubernetes replicas resume any task on any pod without a PVC. Defaults to the local file backend. See Memory System.
  • Audit event correlation + quieter export heartbeat (#300, #301). Auth events are now attributed to their invocation via an ingress-minted correlation id (#278), and the audit_export_status heartbeat moved to a hybrid cadence — it emits immediately on a sink health change and otherwise a slow keepalive, cutting ~1,440 rows/agent/day to a handful (#280).

What's new

AARM — Autonomous Action Runtime Management

AARM (Autonomous Action Runtime Management) is an open-source security specification for governing what autonomous AI agents are allowed to do at runtime. v0.17.0 implements its control set, keyed by requirement ID (R3–R9); see the security architecture overview for how these layers fit together. At the center is the R4 policy-decision taxonomyAllow < Modify < StepUp < Defer < Deny, ordered by restrictiveness — with the R3/R7 intent surface and R9 credentials around it. Every AARM control is off by default and fail-closed when enabled.

AARM control Requirement PR
Intent alignment (per-call semantic gate) R3 #245
Guardrail MODIFY/DENY across all tools R4a #221
Step-up authorization (RFC 9470) R4b #247
Defer authorization (pause / approve / resume) R4c #248
Audit hash chain R5 #237
Ed25519 audit signing + JWKS R6 #220, #237
Intent drift detection (longitudinal) R7 #246
JIT credential dispensing R9 #236

Intent alignment (#245) & drift (#246)

security:
  intent_alignment:
    enabled: true              # off by default; recommend warn-only first
    provider: openai           # openai | gemini | ollama
    model: text-embedding-3-small
    threshold: 0.5             # soft: below → warn
    hard_threshold: 0.3        # hard: below → deny
    cache_size: 1024           # LRU size for action-side embeddings

Intent is anchored on the tool description (not its name — MCP names like fn_42 carry no meaning) plus the arguments JSON. Both sides are embedded; the action side hits an LRU keyed on sha256(action_text) so repeated identical calls skip the round-trip. R7 drift layers longitudinal telemetry on top: it trips on a rolling-window mean below the drift threshold or a monotone decrease of the last N scores.

Step-up (#247) & defer (#248) authorization

security:
  step_up:                     # R4b — require stronger auth for risky tools
    enabled: true
    tools:
      cli_execute: acr:mfa     # per-tool required acr value
    acr_hierarchy: [acr:password, acr:mfa, acr:hardware]  # optional: stronger satisfies weaker
  defer:                       # R4c — pause for out-of-band approval
    enabled: true
    tools:
      cli_execute:
        to: channel:slack:#oncall
        timeout: 10m
        context_template: "Agent wants to run {tool} with args: {args}"

Step-up returns an RFC 9470 challenge on insufficient assurance; defer blocks the executor goroutine on a decision channel and flips the A2A task to deferred until an approver POSTs a decision (or the timeout auto-denies). Both hooks run after guardrails so a guardrail-denied call never produces an unnecessary challenge or deferral.

JIT credentials (#236)

credentials:
  - tool: cli_execute
    binary: aws
    provider: sts_assume_role
    spec:
      role_arn: arn:aws:iam::123456789012:role/forge-skill-read
      external_id: skill-alpha
      session_name: forge-agent-jit
      duration: 15m

Credentials are materialized on every Execute, merged into the subprocess environment, and revoked on completion. The sts_assume_role provider uses Forge's SDK-free SigV4 signer (no aws-sdk-go-v2), enforces AWS 15m–12h duration bounds, and supports external_id, session_name, and an inline session_policy.

Tamper-evident audit logging (#220, #237)

Every event carries prev_hash unconditionally; enabling FORGE_AUDIT_SIGNING_KEY_B64 adds kid + sig (Ed25519 over the JCS-canonicalized event, covering prev_hash). Because the signature commits to the previous hash, editing or reordering any line breaks both the chain walk and the per-event signature. A JWKS endpoint publishes the public key for offline verification. See Audit signing and the audit env-var reference (#254).

Reversible context compression (#241, #279)

compression:
  enabled: true

ctxzip compresses bulky tool outputs once at production time (an AfterToolExec seam), so the conversation prefix stays byte-stable and provider prompt caches keep hitting. Dropped content is stored in a durable local bbolt store behind an inline <<ctxzip:HASH …>> marker and retrieved via the context_expand tool. v0.3.0 (#279) routes list-API shapes like kubectl get -o json through whole-record items[] crushing — anomalous records survive intact while the rest offload as a retrievable array — and adds categorical drop summaries ([offloaded: 139 running, 24 batch completed]) plus a YAML/describe crusher. A keep_patterns learning loop mines context_expand retrievals so frequently-needed fields stop being offloaded.

Opt-in headless-browser tools (#260)

The browser_navigate / browser_state / browser_click / browser_fill / browser_extract / browser_screenshot family registers only when a skill declares requires.capabilities: [browser] and a Chromium binary is present. Every request routes through the EgressProxy (same allowlist / SSRF / DNS-rebinding protection as in-process tools); the analyzer scores the capability high-risk and flags a browser + trust_hints.network: false contradiction as a Critical violation. forge build installs Chromium into the image only for browser agents.

Skill Builder & skills runtime

  • Structured {message, skill} JSON output (#276, #252 part 2) — the Skill Builder now returns a machine-parseable envelope so the dashboard reliably separates chat from the drafted skill, with a hardened parser that rejects wrapper objects and incidental JSON.
  • Built-in-tool awareness (#297, closes #270) — the builder knows Forge's built-in tools (read_file, write_file, edit_file, glob, grep, file_create, scheduling, …), authors rather than role-plays, and gates scheduling behind an explicit ask.
  • Skill-first activation routing (#298, closes #271) — the runtime checks whether a request matches an attached skill before answering from model defaults.
  • Interview convergence + custom-binary install recipes (#258, #252 part 1), robust draft extraction so the preview always populates (#253), a persistently-visible Edit button (#262, closes #261), and skill-catalog names aligned with read_skill resolution (#250).
  • Skill-relative file reads + multi-language script execution (#257, closes #251) and env_required / env_optional surfaced in build-manifest.json (#259). forge build no longer purges curl when a skill needs it at runtime (#242).

Platform & operations

  • Guardrails overlay in policy.yaml (#285, #288) — most-restrictive-wins platform layering over an agent's guardrails.json; the unused MongoDB DB-mode path is removed.
  • Remote session store for stateless replicas (#244) — resume any task on any Kubernetes pod without a PVC; 412 CAS conflicts yield to the newer state instead of clobbering it.
  • Rolling vnext prerelease on every merge to main (#249) — a continuously-built prerelease of the runtime for early adopters.
  • Dependency hardeninggolang.org/x/crypto bumped to 0.52.0 across forge-core and forge-cli (#274, #275).

Upgrade notes

  • Guardrail MODIFY / DENY now apply to every tool (#221 / governance R4a) — potentially breaking. The SkillGuardrailEngine no longer short-circuits on non-cli_execute tools, so deny_commands / deny_output patterns that previously no-op'd for web_search, http_request, MCP calls, and custom tools now fire. Review your guardrail patterns before upgrading.
    • Match-target asymmetry: for cli_execute the match target is still the reconstructed shell command line (binary arg1 arg2 …), so existing shell-style patterns keep working. For every other tool the match target is the raw tool-input JSON as the LLM produced it — write patterns accordingly.
    • API change: GuardrailChecker.CheckInbound / CheckOutbound now return (PolicyResult, error). The new PolicyDecision enum is ordered by restrictiveness (Allow < Modify < StepUp < Defer < Deny). Callers today read only Allow / Modify / Deny; StepUp / Defer are emitted by the R4b (#210) / R4c (#211) hooks. The guardrail_check audit wire shape is unchanged.
    • Migration guidance: docs/security/policy-decisions.md.
  • Guardrails MongoDB "DB mode" removed (#285). If you set FORGE_GUARDRAILS_DB, migrate to guardrails.json plus the platform policy.yaml overlay. See Platform Policy.
  • All governance features are off by default. Intent alignment, drift, step-up, defer, and JIT credentials ship disabled and fail-closed when enabled — turn them on deliberately, and roll intent alignment out in warn-only mode first.

Full changelog

Full changelog: v0.16.0...v0.17.0