Skip to content

fix: PR #39 medium-priority code quality improvements (M-01 through M-09)#43

Merged
bkrabach merged 10 commits intomainfrom
fix/pr39-medium-priority-items
Mar 9, 2026
Merged

fix: PR #39 medium-priority code quality improvements (M-01 through M-09)#43
bkrabach merged 10 commits intomainfrom
fix/pr39-medium-priority-items

Conversation

@bkrabach
Copy link
Collaborator

@bkrabach bkrabach commented Mar 8, 2026

Summary

Addresses all 9 medium-priority items identified by the 4-agent code review of PR #39 (Cross-Language SDK). The Critical and High priority items were already fixed in v1.1.0; this PR completes the remaining code quality improvements.

Changes (9 commits, ordered quickest-first)

Security Hardening

  • M-09: Clamp timeout_seconds to max 300s in EmitHookAndCollect — prevents thread pool exhaustion from absurdly large timeouts. Also fixes a panic on NaN/Infinity inputs. (grpc_server.rs)
  • M-08: Add optional sha256 field to amplifier.toml for WASM module integrity verification — detects supply chain attacks or corrupted WASM files at load time. (module_resolver.rs, Cargo.toml)

Bug Fixes

  • M-03: Replace unwrap() with swap_remove(0) in module resolver — eliminates a panic-capable unwrap with invisible invariant. (module_resolver.rs)
  • M-05: Add debug_assert! before 5 block_on calls in orchestrator bridge — catches deadlock-inducing misuse in debug builds. (wasm_orchestrator.rs)

Node Bindings Cleanup

  • M-06: Remove unused _reason parameter from cancellation methods — the parameter was accepted but silently discarded. (bindings/node/src/lib.rs)
  • M-07: Remove dead API surface (JsToolResult, JsToolSpec, JsSessionConfig, Role) — 4 exported types with no method that accepts or returns them. (bindings/node/src/lib.rs)

Code Deduplication

  • M-02: Extract to_json_or_warn / from_json_or_default helpers — replaces 26 repeated serialization patterns. Net -76 lines. (generated/conversions.rs)
  • M-01: Extract shared get_typed_func to bridges/mod.rs — deduplicates 6 nearly-identical WASM function lookup implementations across bridge files. Net -157 lines. (bridges/*.rs)

Type Safety

  • M-04: Introduce WasmPath(PathBuf) variant in ModuleArtifact — makes the deferred-load contract explicit in the type system instead of using an empty Vec<u8> sentinel. Also removes dead ensure_wasm_bytes_loaded helper from Python bindings. (module_resolver.rs, bindings/*/src/lib.rs)

Stats

  • 19 files changed, +2,417 / -482 lines (includes implementation plan document)
  • 8 new tests added (timeout clamping, sha256 verification, WasmPath variant)
  • 68/68 Node tests pass, all Rust tests pass
  • Clippy clean on both --features wasm and without

Testing

cargo test -p amplifier-core --features wasm
cargo clippy -p amplifier-core --features wasm -- -D warnings
cargo clippy -p amplifier-core -- -D warnings
cd bindings/node && npm run build && npx vitest run

Review Methodology

Each task was implemented via a three-agent pipeline (implementer → spec-reviewer → code-quality-reviewer) with both reviews passing before proceeding to the next task.

bkrabach and others added 10 commits March 8, 2026 13:27
Previously NaN/Infinity would panic in Duration::from_secs_f64 and
arbitrarily large values were uncapped. Now:
- finite positive values are clamped to MAX_HOOK_COLLECT_TIMEOUT_SECS (300s)
- non-finite or non-positive values fall back to DEFAULT (30s)
adds 5 debug_assert! guards verifying tokio::runtime::Handle::try_current().is_ok() before each block_on call in register_kernel_service_imports(). These fire only in debug builds and document the invariant that WASM host import closures must execute inside spawn_blocking. Includes an invariant test.

🤖 Generated with Amplifier

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…lt helpers

Replace 18 serde_json::to_string and 8 serde_json::from_str inline
unwrap_or_else+warn patterns with two shared private helpers:

  fn to_json_or_warn(value, label) -> String
  fn from_json_or_default<T>(json, label) -> T

No behavior change — identical serialization paths and identical warn
messages, just deduplicated. All 49 conversion tests pass.
All 6 WASM bridge files contained a nearly identical function for resolving
a typed WASM Component export (try root-level first, then try nested inside
an interface-exported instance). The only differences were the local function
name, the INTERFACE_NAME constant used, and whether the types were generic or
hardcoded.

Consolidate into a single pub(crate) get_typed_func<Params, Results> in
bridges/mod.rs, parameterized by func_name and interface_name.

Removed functions:
- wasm_tool:     get_typed_func_from_instance<P, R>
- wasm_provider: get_provider_func<P, R>
- wasm_context:  get_context_func<P, R>
- wasm_hook:     get_handle_func (hardcoded types)
- wasm_orchestrator: get_execute_func (hardcoded types)
- wasm_approval: get_request_approval_func (hardcoded types)

Also removed now-unused type aliases (HandleFunc, OrchestratorExecuteFunc,
RequestApprovalFunc, WasmResult<T> in context/hook/approval) and unused
imports (Store, WasmState in hook/approval/provider/orchestrator).

Net: -233 lines / +76 lines across 7 files. All 41 bridge tests pass.
… loaded WASM artifacts

- Add WasmPath(PathBuf) variant to ModuleArtifact enum with doc comment
  explaining it is the pre-load state returned by parse_amplifier_toml
- Change parse_amplifier_toml to return WasmPath(wasm_path) instead of
  WasmBytes { bytes: Vec::new(), path: wasm_path } — the invisible empty-bytes
  contract is now made explicit via the type system
- Update load_module (wasm feature) to handle WasmPath by reading bytes from
  disk via std::fs::read before dispatching to the appropriate wasm transport;
  WasmBytes continues to work as before for already-loaded bytes
- Update all match arms on ModuleArtifact throughout the codebase:
  - bindings/node/src/lib.rs: add WasmPath arm (returns path string, same as WasmBytes)
  - bindings/python/src/lib.rs: add WasmPath arm (same artifact_path behavior)
- Update existing parse_toml_wasm_transport test to expect WasmPath
- Add three new tests:
  - parse_toml_wasm_transport_returns_wasm_path: verifies parse_amplifier_toml
    returns WasmPath, not WasmBytes with empty bytes
  - wasm_path_variant_basic: WasmPath can be constructed, cloned, and compared
  - load_module_wasm_path_loads_bytes_from_disk: WasmPath artifact in a manifest
    causes load_module to read bytes from disk and load successfully

WasmBytes is preserved for backward compatibility (used by resolve_module
wasm auto-detection path and direct-bytes test scenarios).
…odules

- Add sha2 = { version = "0.10", optional = true } dependency, feature-gated
  under the 'wasm' feature flag to avoid pulling in sha2 for non-WASM builds
- Add sha256: Option<String> field to ModuleManifest for optional integrity hash
- Parse optional 'sha256' field from [module] section in amplifier.toml
  (available for all transport types, primarily useful for WASM)
- Add ModuleResolverError::IntegrityMismatch variant with descriptive message
  showing path, expected hash, and actual hash
- Add verify_wasm_integrity() function (cfg(feature = "wasm")) using sha2 crate
  to compute and compare SHA-256 digests; logs debug message on success
- Wire verification into load_module() for both WasmPath and WasmBytes artifacts,
  executing before bytes are passed to wasmtime for compilation
- Update all ModuleManifest construction sites to include sha256: None

Tests added (TDD - written before implementation):
- parse_toml_with_sha256_field: parses sha256 from amplifier.toml into manifest
- parse_toml_without_sha256_field: missing sha256 field yields None (no verification)
- sha256_missing_field_skips_verification: None sha256 skips check, load succeeds
- sha256_matching_hash_passes: correct hash passes verification, load succeeds
- sha256_mismatched_hash_returns_error: wrong hash returns IntegrityMismatch error
@bkrabach bkrabach merged commit 9212113 into main Mar 9, 2026
6 of 8 checks passed
@bkrabach bkrabach deleted the fix/pr39-medium-priority-items branch March 9, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant