Skip to content

fix: preserve literal code fences in template config#2072

Merged
yottahmd merged 6 commits intomainfrom
fix/template-config-literal-code-fences
Apr 30, 2026
Merged

fix: preserve literal code fences in template config#2072
yottahmd merged 6 commits intomainfrom
fix/template-config-literal-code-fences

Conversation

@yottahmd
Copy link
Copy Markdown
Collaborator

@yottahmd yottahmd commented Apr 30, 2026

Summary

Preserve literal fenced template data in type: template executor config.

What Changed

  • allow object evaluation to accept evaluator options at the call site
  • disable backtick substitution when evaluating template with: data while keeping variable expansion and omitted optional param handling
  • add runtime and end-to-end regressions for literal fenced content in template data

Why

Template step config evaluation was treating backticks inside with.data as command substitution before the template executor ran. When a prior step injected fenced YAML or Markdown into template data, executor setup tried to run that content as shell commands and failed before rendering.

Validation

  • go test ./internal/runtime -run 'TestEvalExecutorConfig_Template' -count=1
  • go test ./internal/intg -run 'TestTemplateExecutor' -count=1
  • go test ./... -run '^$' -count=1

Summary by CodeRabbit

  • Bug Fixes

    • Template rendering preserves Markdown fenced code blocks and literal content during interpolation.
    • Improved shutdown handling so interrupted tasks are marked aborted earlier and report interrupt errors promptly.
  • Tests

    • Added integration and unit tests verifying fenced code blocks remain intact for substituted multi-line values.
  • Refactor

    • Evaluation API now accepts optional evaluation options to control substitution behavior.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 19523975-a386-4503-b409-608d4201ab98

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Object evaluation now accepts variadic options and builds options from them; runtime evaluation disables substitution for omitted template params; tests (integration and unit) added to ensure multi-line Markdown code fences survive template interpolation; node signal handling order adjusted and tests updated to assert aborted state timing.

Changes

Cohort / File(s) Summary
Core evaluation API
internal/cmn/eval/eval.go
Object signature changed to Object[T any](ctx, obj, vars, opts ...Option) and now builds options via buildOptions(opts) instead of always using NewOptions().
Runtime evaluation invocation
internal/runtime/eval.go
eval.Object is now called with eval.WithoutSubstitute() so omitted parameters are treated as empty and substitution is disabled during templating; variables still computed from templateConfigEvalVariables(GetEnv(ctx)).
Template integration tests
internal/intg/template_test.go
Adds end-to-end integration test verifying template rendering preserves fenced Markdown blocks (including newline before closing fence) and literal interpolated content.
Runtime/unit template tests
internal/runtime/node_internal_test.go, internal/runtime/node_test.go
Adds unit test to ensure ${ISSUE_TEXT} interpolation preserves backtick-fenced content; modifies node tests to add signal synchronization hooks and a test asserting node is marked aborted before Kill returns; introduces withNodeSignalExecutorFactory test helper.
Node signal handling
internal/runtime/node.go
Reorders (*Node).Signal so a termination killSignal causes n to be marked core.NodeAborted before calling n.cmd.Kill(killSignal).

Sequence Diagram(s)

(omitted)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: disabling backtick substitution (via WithoutSubstitute) to preserve literal code fences in template configuration, which is the core issue being fixed across eval.go, runtime files, and associated tests.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/template-config-literal-code-fences

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@yottahmd
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yottahmd
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/intg/template_test.go (1)

223-226: ⚡ Quick win

Assert the closing code fence too to tighten the regression guard.

This test proves the opening fence is preserved, but it can still pass if the trailing fence is dropped. Add one assertion for the closing fence marker.

Proposed diff
 		dag.AssertOutputs(t, map[string]any{
 			"RESULT": []test.Contains{
 				test.Contains("```yaml"),
+				test.Contains("\n```"),
 				test.Contains("touch $TEST_FILE"),
 			},
 		})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/intg/template_test.go` around lines 223 - 226, The test currently
asserts the opening code fence via test.Contains("```yaml") but doesn't verify
the closing fence; update the "RESULT" assertions in the template test (the
slice of test.Contains entries) to include an assertion for the closing fence
marker (for example test.Contains("\n```") or equivalent) right after the
opening-fence check so the test fails if the trailing ``` is dropped.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/intg/template_test.go`:
- Around line 223-226: The test currently asserts the opening code fence via
test.Contains("```yaml") but doesn't verify the closing fence; update the
"RESULT" assertions in the template test (the slice of test.Contains entries) to
include an assertion for the closing fence marker (for example
test.Contains("\n```") or equivalent) right after the opening-fence check so the
test fails if the trailing ``` is dropped.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0009713c-852e-45cf-85f5-0319abe83252

📥 Commits

Reviewing files that changed from the base of the PR and between 80052fa and 528b97a.

📒 Files selected for processing (2)
  • internal/intg/template_test.go
  • internal/runtime/node_internal_test.go

@yottahmd
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yottahmd
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/runtime/node_test.go (1)

229-237: ⚡ Quick win

Add bounded waits to avoid potential test hangs on regressions.

Line 229 and Line 234 block indefinitely. If signal flow regresses, this test can stall until global go test timeout. Use timeout-guarded receives for faster, clearer failures.

Proposed patch
-		<-exec.killStarted
+		select {
+		case <-exec.killStarted:
+		case <-time.After(2 * time.Second):
+			t.Fatal("timeout waiting for Kill to start")
+		}
 		require.Equal(t, core.NodeAborted.String(), node.State().Status.String())

 		close(exec.killContinue)

-		err := <-errCh
+		var err error
+		select {
+		case err = <-errCh:
+		case <-time.After(2 * time.Second):
+			t.Fatal("timeout waiting for Execute to return")
+		}
 		require.Error(t, err)
 		require.Contains(t, err.Error(), "signal: interrupt")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/runtime/node_test.go` around lines 229 - 237, The test currently
performs unbounded receives on exec.killStarted and errCh which can hang; change
those blocking receives to timeout-guarded selects (e.g., select with
time.After) so the test fails fast on regressions. Specifically, replace the
receive from exec.killStarted and the receive from errCh with select statements
that return a helpful test error if a timeout elapses, and likewise guard the
final assert after closing exec.killContinue; keep assertions using
node.State().Status.String() and core.NodeAborted.String() intact but fail the
test with a clear message if the timeouts trigger.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/runtime/node_test.go`:
- Around line 229-237: The test currently performs unbounded receives on
exec.killStarted and errCh which can hang; change those blocking receives to
timeout-guarded selects (e.g., select with time.After) so the test fails fast on
regressions. Specifically, replace the receive from exec.killStarted and the
receive from errCh with select statements that return a helpful test error if a
timeout elapses, and likewise guard the final assert after closing
exec.killContinue; keep assertions using node.State().Status.String() and
core.NodeAborted.String() intact but fail the test with a clear message if the
timeouts trigger.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d5de3642-a1e5-46a0-ab8c-ba995e73f59e

📥 Commits

Reviewing files that changed from the base of the PR and between df68fed and b25c16c.

📒 Files selected for processing (2)
  • internal/runtime/node.go
  • internal/runtime/node_test.go
✅ Files skipped from review due to trivial changes (1)
  • internal/runtime/node.go

@yottahmd yottahmd merged commit 5d9abfe into main Apr 30, 2026
10 checks passed
@yottahmd yottahmd deleted the fix/template-config-literal-code-fences branch April 30, 2026 08:24
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