Skip to content

fix: harden conjure CLI guards for hostile manifests and probes#22

Merged
BunsDev merged 2 commits into
mainfrom
fix/docs-claimed-cli-guards
Jul 9, 2026
Merged

fix: harden conjure CLI guards for hostile manifests and probes#22
BunsDev merged 2 commits into
mainfrom
fix/docs-claimed-cli-guards

Conversation

@BunsDev

@BunsDev BunsDev commented Jul 9, 2026

Copy link
Copy Markdown
Member

What & why

Hardens conjure's input guards in three places where bad input previously failed silently or hung:

  1. Unknown manifest fields now fail loudly. deny_unknown_fields on AdapterManifest, RuntimeAdapter, StreamArgs, Capabilities, and SandboxMapping — a typo like capabilties used to silently drop declared capabilities; now it's a parse error naming the field. (Verified the untagged SandboxMapping enum also rejects extras.)
  2. Registry versions must be strict major.minor.patch semver. conjure registry add refuses non-semver versions before writing anything to sources.
  3. Runtime probes get a 5s timeout. A binary that blocks on stdin (e.g. a REPL that ignores --version) can no longer hang conjure test; it's killed and reported as not runnable.

Also updates the validate CLI test: a registry index passed without --registry-index now fails at parse time (unknown field \format`) instead of the older no adapters` message — still loud, earlier.

Type

  • New runtime adapter (manifest)
  • Update to an existing adapter
  • SDK change (coven-runtime-* crate)
  • Docs / tooling / CI

If this changes the SDK

  • cargo fmt --all --check clean
  • cargo clippy --workspace --all-targets -- -D warnings clean
  • cargo test --workspace --locked green
  • Manifest shape changes are backward-compatible (no fields added/renamed/removed; all four registry manifests still validate)
  • JSON Schema updated in the same PR if the manifest shape changed — N/A, shape unchanged (schema already has additionalProperties: false; this aligns the Rust parser with it)
  • SCHEMA_VERSION bumped if the change is backward-incompatible — N/A
  • coven-runtime-spec remains pure (semver check is plain string parsing; probe timeout lives in the CLI crate)

Notes for reviewers

Stricter parsing is technically pickier than before: manifests carrying unrecognized fields that previously parsed will now be rejected. All canonical registry manifests (copilot, coven-code, hermes, opencode) validate cleanly. cargo deny check also green locally.

- Reject unknown manifest fields (deny_unknown_fields on AdapterManifest,
  RuntimeAdapter, StreamArgs, Capabilities, SandboxMapping) so typos like
  `capabilties` fail loudly instead of silently dropping capabilities.
- Validate registry versions as strict major.minor.patch semver; `conjure
  registry add` now refuses non-semver versions before writing sources.
- Give runtime probes a 5s timeout so a binary that blocks on stdin can no
  longer hang `conjure test`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 9, 2026 06:29
@BunsDev
BunsDev requested a review from CompleteDotTech as a code owner July 9, 2026 06:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens conjure’s safety/guardrails around adapter manifests and runtime probing to avoid silent misconfiguration and hangs when presented with hostile or malformed input.

Changes:

  • Enforces strict manifest parsing by rejecting unknown fields (deny_unknown_fields) across manifest-related types.
  • Adds registry version validation (major.minor.patch) and surfaces invalid versions as explicit validation errors.
  • Adds a timeout to runtime probe execution so conjure test can’t hang indefinitely on non-cooperative binaries.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
crates/coven-runtime-spec/src/validate.rs Adds adapter version validation and introduces valid_registry_version plus a test.
crates/coven-runtime-spec/src/sandbox.rs Rejects unknown fields for the untagged SandboxMapping enum.
crates/coven-runtime-spec/src/manifest.rs Rejects unknown fields for manifest envelope + adapter/stream args; adds a regression test.
crates/coven-runtime-spec/src/capabilities.rs Rejects unknown fields in Capabilities while preserving defaulting behavior.
crates/coven-runtime-cli/tests/validate_cli.rs Updates CLI test expectations to match earlier parse-time failure on registry-index-as-manifest input.
crates/coven-runtime-cli/tests/registry_cli.rs Adds a regression test ensuring non-semver versions are rejected without writing to sources.
crates/coven-runtime-cli/src/commands/test.rs Implements probe timeout logic and adds a regression test for blocking binaries.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +140 to +164
fn run_probe_command(executable: &str, flag: &str, timeout: Duration) -> std::io::Result<Output> {
let mut child = Command::new(executable)
.arg(flag)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
let deadline = Instant::now() + timeout;

loop {
if child.try_wait()?.is_some() {
return child.wait_with_output();
}

if Instant::now() >= deadline {
let _ = child.kill();
let _ = child.wait();
return Err(std::io::Error::new(
std::io::ErrorKind::TimedOut,
format!("probe `{executable} {flag}` timed out after {timeout:?}"),
));
}

thread::sleep(Duration::from_millis(10));
}
}
Comment on lines +193 to +196
use coven_runtime_spec::{Capabilities, SandboxMapping};
use std::fs;
use std::os::unix::fs::PermissionsExt;
use tempfile::tempdir;
Comment on lines +238 to +252
#[test]
fn probe_times_out_blocking_binary() {
let dir = tempdir().unwrap();
let script = dir.path().join("blocks");
fs::write(&script, "#!/bin/sh\nsleep 1\n").unwrap();
let mut perms = fs::metadata(&script).unwrap().permissions();
perms.set_mode(0o755);
fs::set_permissions(&script, perms).unwrap();

let a = adapter(script.to_str().unwrap());
match probe_adapter_with_timeout(&a, Some("--version"), Duration::from_millis(50)) {
ProbeResult::NotRunnable(msg) => assert!(msg.contains("timed out"), "{msg}"),
other => panic!("expected NotRunnable timeout, got {:?}", DebugProbe(&other)),
}
}
Comment on lines +277 to +280
parts.next().is_none()
&& [major, minor, patch]
.iter()
.all(|part| !part.is_empty() && part.parse::<u64>().is_ok())
The test builds a /bin/sh script and uses PermissionsExt, neither of
which exists on Windows, breaking the windows-latest CI job.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@BunsDev
BunsDev merged commit ad508ba into main Jul 9, 2026
3 checks passed
@BunsDev
BunsDev deleted the fix/docs-claimed-cli-guards branch July 9, 2026 07:02
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.

2 participants