Skip to content

feat: mandatory engine lifecycle + text-file path guardrails#7

Merged
Pmaster-dev merged 3 commits into
developfrom
copilot/add-guardrail-safety
Jul 5, 2026
Merged

feat: mandatory engine lifecycle + text-file path guardrails#7
Pmaster-dev merged 3 commits into
developfrom
copilot/add-guardrail-safety

Conversation

Copilot AI commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

The engine had no lifecycle contract — it would run automations in any state, with no enforcement boundary. Text-file path payloads had no safety validation, leaving pipelines open to path traversal and extension-based attacks.

Engine lifecycle (engine.py)

  • Added start() / stop() methods to AutomationEngine; stop() triggers teardown() on all registered components
  • trigger() / trigger_type() now raise EngineNotStartedError if the engine hasn't been started — lifecycle is mandatory
  • is_running property exposes current state
  • default_engine is auto-started to preserve backward compatibility

Text-file guardrail (guardrails.py, new)

  • TextFileGuardrail — pipeline component that validates string file-path payloads before downstream steps execute
    • Rejects: path traversal (..), null bytes, absolute paths (configurable), disallowed extensions
    • Passes payload through unchanged on success
  • DEFAULT_TEXT_EXTENSIONS — configurable frozenset of allowed extensions (.txt, .log, .csv, .md, .rst, …)

Exports

EngineNotStartedError, TextFileGuardrail, and DEFAULT_TEXT_EXTENSIONS added to automation.__all__.

Usage

engine = AutomationEngine()
engine.start()

engine.components.register("guard", TextFileGuardrail())
engine.register_fn("read", lambda inp: open(inp.payload).read())
engine.define(AutomationDefinition(
    name="safe_read",
    triggers=["file.read"],
    steps=["guard", "read"],
))

# Blocked — path traversal
engine.trigger_type("file.read", payload="../secrets.txt")  # FAILED

# Allowed
engine.trigger_type("file.read", payload="data.txt")  # SUCCESS

engine.stop()  # tears down all components

@Pmaster-dev Pmaster-dev marked this pull request as ready for review July 5, 2026 02:58
Copilot AI review requested due to automatic review settings July 5, 2026 02:58
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@Pmaster-dev Pmaster-dev merged commit 158a7d3 into develop Jul 5, 2026
7 checks passed

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 introduces an explicit lifecycle contract for AutomationEngine (requiring start() before triggering runs, and adding stop() teardown semantics) and adds a new TextFileGuardrail component to validate string file-path payloads against traversal/absolute-path/null-byte/extension rules. It also updates package exports and expands regression tests to cover the new lifecycle and guardrail behaviors.

Changes:

  • Added mandatory engine lifecycle (start()/stop(), is_running, and EngineNotStartedError enforcement in trigger()/trigger_type()), with default_engine auto-started for backward compatibility.
  • Added TextFileGuardrail + DEFAULT_TEXT_EXTENSIONS guardrail component for file-path payload validation.
  • Added/updated tests and public exports for the new engine error and guardrail symbols.

Reviewed changes

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

File Description
tests/test_automation_review_regressions.py Adds regression coverage for lifecycle enforcement and TextFileGuardrail validation + pipeline behavior.
src/automation/guardrails.py Introduces TextFileGuardrail and DEFAULT_TEXT_EXTENSIONS for safe text-file path payload validation.
src/automation/engine.py Adds lifecycle management (start/stop), enforces “must be started” on triggers, and auto-starts default_engine.
src/automation/init.py Exposes EngineNotStartedError, TextFileGuardrail, and DEFAULT_TEXT_EXTENSIONS via package exports.

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

Comment thread src/automation/engine.py
Comment on lines +59 to +60
class EngineNotStartedError(RuntimeError):
"""Raised when :meth:`AutomationEngine.trigger` is called before :meth:`start`."""
Comment thread src/automation/engine.py
Comment on lines +203 to +207
Stop the engine and tear down all registered components.

After :meth:`stop` returns, :meth:`trigger` / :meth:`trigger_type`
will raise :class:`EngineNotStartedError` until :meth:`start` is
called again. All component teardown hooks are invoked; any
Comment thread src/automation/engine.py
Comment on lines +196 to +199
if not self._running:
self._running = True
logger.info("AutomationEngine started")
return self
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.

3 participants