Encapsulate execution behind run/run_captured/run_agent (v0.3.0) - #11
Merged
Conversation
Narrow mdtask-core's public API so consumers deal only in jobs, their
metadata, and running them, never in execution mechanics. The Task struct
is renamed Job; its script, lang, opts, and env fields become internal, as
do Invocation, TaskFile::invocation, interpreter, dependency_order, bind,
substitute, parse_args, and Job::inherits_cwd/script_arg_templates. No
consumer sees a program, argv, interpreter, or temp file.
Three entry points run a job and its Requires: chain:
run inherits stdio (the CLI, streaming)
run_captured aggregates stdout/stderr across the chain (embedders)
run_agent the agent gate: allowlist, within-file dependency
resolution, and the {{ arg }} injection guard, captured
The two previously found RCEs stay fixed: run_agent resolves the Requires:
chain within the allowed target's own file (so a nearer untrusted task file
cannot shadow a dependency), and refuses a target that raw-templates a
declared arg. Both are covered by regression tests in lib.rs and, through
the tool path, in mcp.rs.
The CLI run loop collapses to mdtask_core::run; mcp.rs run_task delegates to
run_agent and list_tasks to agent_jobs, with all security logic moved to
core. The lint subcommand (shellcheck) is removed entirely. The fixture test
now drives the public surface (parse, jobs(), run_captured, run_agent). Both
crates bump to 0.3.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Breaking (v0.3.0). Narrows
mdtask-core's public API so consumers deal only in jobs, metadata, and running — never in execution mechanics. Every future change to how a job runs (scriptfile delivery,Interpreter:, cancellation, new interpreters, per #10) becomes internal, with no consumer seam.Public surface
parse,find_task_files,TaskFile::jobs()/job()/warnings(),agent_jobs(files).Job { name, description, args, requires, agent_allow }(renamed fromTask;script/lang/opts/envnowpub(crate)).run(CLI, inherits stdio) /run_captured(gloaming) /run_agent(MCP, gated), all running theRequires:chain internally;RunError.Invocation,invocation(),interpreter(),dependency_order,bind,substitute. No consumer ever holds a command.Consumers collapsed
mdtask_core::run(...).run_taskis onerun_agent(...); the allowlist/same-file/injection logic moved into core (one audited place), so the script never leaves the library.shellcheck, out of scope).Security preserved (verified end-to-end, not just unit tests)
Re-ran both prior RCE proof-of-concepts against the built binary: the dependency-shadow PoC prints
real-build, notPWNED; the{{ arg }}injection PoC is refused with no marker file written.run_agentstill enforces nearest-def allowlist, same-file dependency resolution, and injection refusal.Verification
fmt, clippy
-D warnings(default +--features mcp), all tests both ways (incl. both RCE tests and a 200k-deep chain), builds, CLI smoke (list / Requires chain / usage / errors), no em-dashes. Both crates bumped to 0.3.0.Follow-up after release: rework gloaming onto
jobs()+run_captured()and bump its dep.🤖 Generated with Claude Code