Skip to content

feat(runtime): apply kiln.resource_limits manifest on-target — complete the AD-WCMC-001 enforcement (SR-45, closes #415 #421) - #464

Merged
avrabe merged 2 commits into
mainfrom
feat/sr-45-apply-manifest-resource-limits
Jul 22, 2026
Merged

feat(runtime): apply kiln.resource_limits manifest on-target — complete the AD-WCMC-001 enforcement (SR-45, closes #415 #421)#464
avrabe merged 2 commits into
mainfrom
feat/sr-45-apply-manifest-resource-limits

Conversation

@avrabe

@avrabe avrabe commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

What

Completes the AD-WCMC-001 embedded trust chain's on-target end (SR-45, #415, #421): a module's signed kiln.resource_limits custom section is now applied at load, not extracted-then-discarded. An embedded/gale deployment with no --memory CLI flag is still bounded by the module's own manifest, and a present-but-malformed manifest fails the load instead of silently proceeding unbounded.

How

  • kiln-decoder (resource_limits_section.rs): new real extract_resource_limits_from_binary(binary) — scans the binary's top-level custom sections and decodes kiln.resource_limits. Three strictly-distinguished outcomes: Ok(None) (section absent), Ok(Some) (present + valid), Err (present but undecodable/invalid, or broken section framing). The old kiln-foundation "extractor" was a stub that ignored the binary and returned a defaulted config; it is deleted.
  • kiln-runtime CapabilityAwareEngine::load_module: the manifest's max_memory_usage is converted with EngineResourceLimits::from_max_memory_bytes and fed into the same SR-46/47/48 pre-instantiate gate (check_declared_minimums) and runtime grow caps (set_runtime_max_pages / set_runtime_max_elements) the CLI path uses. The banned .unwrap_or(None) fallback and the TODO: Apply resource limits are gone.
  • Precedence: when both a CLI --memory bound and a manifest bound exist, the most-restrictive (min) wins (EngineResourceLimits::most_restrictive) — an operator cannot loosen a module's signed self-declared bound, and a module cannot loosen the operator's cap.
  • EngineBuilder::from_binary: no longer swallows errors (the old loop always produced ASIL-D from the stub). It selects the ASIL mode from the manifest's qualified level, fails loud on malformed manifests / unknown levels, defaults to QM only when the manifest or its level is genuinely absent. The dead with_resource_config storage (never read by build()) is removed.

Manifest fields EngineResourceLimits cannot express (max_call_depth, fuel) are not yet enforced by this gate; the memory bound — the WCMC attack surface — is.

Tests (TDD, RED→GREEN)

Engine level (kiln-runtime/tests/resource_limits_gate_tests.rs, serial):

  • manifest_memory_bound_enforced_without_cli_limits — manifest bound, no CLI flag, oversized declared min → rejected before allocation (was: loaded unbounded)
  • manifest_bound_admits_fitting_module_and_caps_growth — fitting module loads and carries the manifest-derived runtime page cap
  • manifest_tighter_than_cli_wins / cli_tighter_than_manifest_wins — min-precedence in both directions
  • malformed_manifest_section_fails_loud — truncated payload → load error
  • builder_from_binary_fails_loud_on_malformed_manifest, builder_from_binary_selects_manifest_asil_level

Decoder level (kiln-decoder/src/resource_limits_section.rs):

  • test_extract_absent_section_is_none, test_extract_present_section_roundtrips, test_extract_malformed_section_is_error, test_extract_non_wasm_binary_is_error

All 12 gate tests green; kiln-runtime lib 101 passed; kiln-foundation lib+tests 148+ passed; workspace cargo check clean. Pre-existing broken test targets on main (7 in kiln-runtime, kiln-decoder no_std lib, 2 decoder lib tests, foundation example) are unchanged and untouched by this PR.

Closes #415
Closes #421

Implements: SR-45

🤖 Generated with Claude Code

https://claude.ai/code/session_01FcTUZgts331Z1TK3q8YBQj

avrabe and others added 2 commits July 22, 2026 15:59
…(SR-45)

Complete the AD-WCMC-001 on-target enforcement: a module's signed
`kiln.resource_limits` custom section is now APPLIED at load time, not
extracted-then-discarded. An embedded/gale deployment with NO `--memory`
CLI flag is still bounded by the module's own manifest.

- kiln-decoder: real `extract_resource_limits_from_binary` — scans the
  binary's custom sections and decodes `kiln.resource_limits`. Strictly
  distinguishes absent (Ok(None)) from present-but-malformed (Err): a
  broken manifest must fail loud, never be treated as absent.
- kiln-runtime load_module: the manifest's max_memory_usage is converted
  via EngineResourceLimits::from_max_memory_bytes and fed into the SAME
  SR-46/47/48 pre-instantiate gate (check_declared_minimums) and runtime
  grow caps (set_runtime_max_pages / set_runtime_max_elements) that the
  CLI path uses. The banned `.unwrap_or(None)` masking fallback and the
  "TODO: Apply resource limits" are gone; a malformed section is now a
  load error.
- Precedence (SR-45): when both a CLI `--memory` bound and a manifest
  bound are present, the MOST-RESTRICTIVE (minimum) wins — an operator
  cannot loosen a module's signed self-declared bound, and a module
  cannot loosen the operator's cap (EngineResourceLimits::most_restrictive).
- EngineBuilder::from_binary: no longer swallows extraction errors (the
  old loop always yielded ASIL-D from a stub). It now selects the ASIL
  mode from the manifest's qualified level, fails loud on a malformed
  manifest or unknown level, and defaults to QM only when the manifest
  (or its level) is genuinely absent. Dead `with_resource_config`
  storage (never read by build()) removed.
- kiln-foundation: deleted the vacuous extract_resource_limits_from_binary
  stub that ignored the binary and returned a defaulted config.

Manifest fields not expressible by EngineResourceLimits (max_call_depth,
fuel) are not yet enforced by this gate; the memory bound — the WCMC
attack surface — is.

Tests (RED->GREEN): manifest_memory_bound_enforced_without_cli_limits,
manifest_bound_admits_fitting_module_and_caps_growth,
manifest_tighter_than_cli_wins, cli_tighter_than_manifest_wins (pins the
converse), malformed_manifest_section_fails_loud,
builder_from_binary_fails_loud_on_malformed_manifest,
builder_from_binary_selects_manifest_asil_level; decoder unit tests
test_extract_{absent_section_is_none,present_section_roundtrips,
malformed_section_is_error,non_wasm_binary_is_error}.

Closes #415
Closes #421

Implements: SR-45
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FcTUZgts331Z1TK3q8YBQj
Bump SR-45 to implemented, retarget release v0.5.0 -> v0.4.4 (the
enforcement-capstone release), and record the IMPLEMENTED (PR #464) note
with the verifying test names, matching the SR-46..51 convention.

Implements: SR-45
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FcTUZgts331Z1TK3q8YBQj
@github-actions

Copy link
Copy Markdown

🔍 Build Diagnostics Report

Summary

Metric Base Branch This PR Change
Errors 0 0 0
Warnings 5 5 0

🎯 Impact Analysis

Issues in Files You Modified

  • 0 new errors introduced by your changes
  • 0 new warnings introduced by your changes
  • 0 total errors in modified files
  • 0 total warnings in modified files
  • 0 files you modified

Cascading Issues (Your Changes Breaking Other Files)

  • 0 new errors in unchanged files
  • 0 new warnings in unchanged files
  • 0 unchanged files now affected

Note: "Cascading issues" are errors in files you didn't modify, caused by your changes (e.g., breaking API changes, dependency issues).

✅ No Issues Detected

Perfect! Your changes don't introduce any new errors or warnings, and don't break any existing code.


📊 Full diagnostic data available in workflow artifacts

🔧 To reproduce locally:

# Install cargo-kiln
cargo install --path cargo-kiln

# Analyze your changes
cargo-kiln build --output json --filter-severity error
cargo-kiln check --output json --filter-severity warning

@codecov

codecov Bot commented Jul 22, 2026

Copy link
Copy Markdown

⚠️ JUnit XML file not found

The CLI was unable to find any JUnit XML files to upload.
For more help, visit our troubleshooting guide.

@avrabe
avrabe merged commit 35a573b into main Jul 22, 2026
22 checks passed
@avrabe
avrabe deleted the feat/sr-45-apply-manifest-resource-limits branch July 22, 2026 18:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant