Skip to content

feat(pipeline): centralize bounded process execution - #370

Merged
szmyty merged 1 commit into
mainfrom
feat/process-execution-356
Aug 31, 2026
Merged

feat(pipeline): centralize bounded process execution#370
szmyty merged 1 commit into
mainfrom
feat/process-execution-356

Conversation

@szmyty

@szmyty szmyty commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Centralizes external tool execution behind one bounded, policy-aware process port and migrates the production wrapping paths tracked by #356.

Canonical process execution

Adds public renderflow::process primitives for:

  • direct executable + argv execution with no implicit shell interpretation
  • explicit shell classification and direct-shell rejection unless opted in
  • working directory and stdin/stdout/stderr modes
  • filtered environment inheritance with explicit allow/deny/override behavior
  • default and per-request timeouts
  • synchronous cancellation tokens
  • process-tree termination where supported
  • independently bounded stdout/stderr capture with truncation evidence
  • expected file/directory output validation
  • structured exit/timing/platform evidence
  • bounded --version probes
  • secret-bearing argument/environment redaction
  • declarative network/sandbox policy hooks without false enforcement claims

Process-tree behavior

  • Unix children run in their own process group; timeout/cancel sends group SIGTERM, waits a bounded grace period, then escalates to SIGKILL.
  • Windows attempts taskkill /T /F and falls back to direct-child termination.
  • Unsupported platforms retain explicit direct-child fallback evidence.

Migrated production paths

  • generic adapters::command::run_command
  • YAML CommandTransform
  • command-backed collection/aggregation transforms
  • dependency availability checks
  • Tectonic/PDF probing
  • renderflow doctor tool probes
  • plugin required-tool probes

Existing Pandoc, FFmpeg, HTML, DOCX, audio, and image rendering already flow through run_command, so they inherit the canonical executor through the adapter migration.

The historical repository-audit command still uses date/git only for its own report metadata. It is not a transform/tool adapter and is documented as outside this reusable execution-provider boundary.

Security and diagnostics

  • default environment strips credential-looking variable names unless explicitly allowed/set
  • sensitive argv/env values are hidden from Debug, tracing, and checked-execution errors
  • bearer tokens and URL authority credentials receive defense-in-depth redaction
  • raw captured bytes remain available explicitly but are never included directly in Debug
  • a child that exits 0 but fails declared output validation is not considered successful

Tests

The process module includes fixtures for:

  • missing executable
  • non-zero exit
  • timeout
  • cancellation with descendant-process termination on Unix
  • oversized stdout capture and explicit truncation
  • secret redaction
  • missing expected output
  • direct shell rejection
  • sensitive environment-name filtering
  • bearer/URL credential redaction
  • bounded tool version probing

docs/process-execution.md documents the execution/security contract and Linux/macOS/Windows behavior.

Architecture boundaries

This PR intentionally does not:

Validation

Final head: f1b88a267b3bb8c7fc96f58863bcca7d37c119da

All final-head workflows are green:

  • CI run 33433271956
    • Clippy with warnings denied and no lint allowances
    • Rust workspace build and full test suite
    • process timeout, cancellation/process-tree, bounded capture, redaction, expected-output, missing executable, non-zero exit, shell opt-in, environment filtering, and tool-probe fixtures
    • web frozen install, format, lint, typecheck, tests, build, and artifact upload
    • AUR stable and git package validation
    • portable installer release-build/install smoke test
    • Snap build, classic install, renderflow --version smoke test, and artifact upload
    • bundled dry-run, library embedding, and plugin registration examples
  • Docs run 33433271935
    • generated-doc regeneration and zero-diff verification
    • MkDocs build
    • versioned docs smoke build
  • Commit Lint runs 33433271840 and 33433810986

The final PR contains one Conventional Commit, contains no temporary validation workflow or lint suppression, and is mergeable.

Closes #356

Add one process execution port for wrapped tools and migrate command transforms,
aggregation, dependency probes, doctor/plugin checks, and PDF probing onto it.

Bound runtime and captured output, control child environments, classify explicit
shell use, redact secret-bearing diagnostics, validate declared outputs, and
terminate process trees on timeout or cancellation where supported.

Document platform behavior and keep toolchain fingerprints scoped to #359.

Closes #356
@szmyty
szmyty force-pushed the feat/process-execution-356 branch from 3b6e2bf to f1b88a2 Compare August 31, 2026 19:56
@szmyty
szmyty merged commit f1e78b1 into main Aug 31, 2026
20 checks passed
@szmyty
szmyty deleted the feat/process-execution-356 branch August 31, 2026 20:47
@devactivity-app

Copy link
Copy Markdown

Pull Request Summary by devActivity

Metrics

Cycle Time: 1h 5m Coding Time: < 1 min

Achievements

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.

Centralize and harden external tool execution with bounded process policies

1 participant