Skip to content

Add deterministic body footer templates to safe outputs - #58841

Merged
pelikhan merged 4 commits into
mainfrom
copilot/add-footer-message-template
Sep 5, 2026
Merged

Add deterministic body footer templates to safe outputs#58841
pelikhan merged 4 commits into
mainfrom
copilot/add-footer-message-template

Conversation

Copilot AI commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Workflow authors can now define deterministic footer content for issues and pull requests, ensuring required text is appended regardless of agent-generated content.

Changes

  • Configuration

    • Adds body-footer to create-issue and create-pull-request.
    • Supports {workflow_name} and {run_url} placeholders.
  • Rendering

    • Appends the template as the final visible body content.
    • Preserves hidden tracking metadata after the footer.
    • Applies even when the standard attribution footer is disabled.
  • Fallback handling

    • Includes the configured footer in protected-file fallback issues.
    • Neutralizes closing keywords when adapting PR content into an issue.
safe-outputs:
  create-pull-request:
    footer: false
    body-footer: |
      ---
      Generated by [{workflow_name}]({run_url})

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 37.8 AIC · ⌖ 8.62 AIC · ⊞ 9.2K ·
Comment /souschef to run again


Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 21.6 AIC · ⌖ 8.57 AIC · ⊞ 9.2K ·
Comment /souschef to run again

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
@pelikhan

pelikhan commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

This footer is different from the other template footer defined in messages

@pelikhan
pelikhan marked this pull request as ready for review September 5, 2026 19:27
Copilot AI balanced review requested due to automatic review settings September 5, 2026 19:27
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

No ADR enforcement needed: PR does not have the 'implementation' label and has ≤100 new lines of code in business logic directories.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

Completed PR review for #58841 and submitted review output via safeoutputs.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • github.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Ponytail Reviewer completed successfully!

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Ponytail Reviewer for #58841

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.

🟡 Changes recommended

Fallback footer ordering and body-length validation remain unresolved, with fallback coverage also incomplete.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds configurable deterministic body footers to issue and pull-request safe outputs.

Changes:

  • Adds body-footer configuration with workflow placeholders.
  • Supports footer rendering, metadata ordering, and fallback handling.
  • Adds tests, documentation, typings, schema updates, and release metadata.
File summaries
File Description
pkg/workflow/safe_outputs_handler_registry_pull_requests.go Serializes PR footer configuration.
pkg/workflow/safe_outputs_handler_registry_issues.go Serializes issue footer configuration.
pkg/workflow/safe_outputs_footer_test.go Tests configuration propagation.
pkg/workflow/safe_outputs_config_types.go Defines the footer field.
pkg/parser/schemas/main_workflow_schema.json Adds schema entries.
pkg/parser/schema_test.go Tests schema acceptance.
docs/src/content/docs/reference/footers.md Documents deterministic footers.
actions/setup/js/types/safe-outputs-config.d.ts Adds TypeScript declarations.
actions/setup/js/messages.test.cjs Tests template rendering.
actions/setup/js/messages.cjs Exports the footer renderer.
actions/setup/js/messages_footer.cjs Implements footer rendering.
actions/setup/js/create_pull_request.test.cjs Tests standard PR footer behavior.
actions/setup/js/create_pull_request.cjs Applies PR and fallback footers.
actions/setup/js/create_issue.test.cjs Tests issue footer behavior.
actions/setup/js/create_issue.cjs Applies issue footers.
.changeset/patch-add-safe-output-body-footer.md Records the patch release.
Review details

Suppressed comments (2)

actions/setup/js/create_pull_request.cjs:1712

  • The new fallback-specific behavior is not exercised by the added PR test: that test only reaches the successful pulls.create path. Please extend the existing protected-files fallback-to-issue tests (including the push-failed variant) with a body_footer containing a closing keyword and assert that it remains at the end of visible content and that the keyword is escaped; these split-body paths can otherwise regress independently of normal PR creation.
      const issueSafeBody = neutralizeClosingKeywordsForIssueBody(body);
      // Footer section (footer + workflow-id marker) used when ordering protected-files notices
      const footerContent = footerParts.join("\n\n");
      const issueSafeFooterContent = neutralizeClosingKeywordsForIssueBody(footerContent);

actions/setup/js/create_pull_request.test.cjs:1474

  • The added test covers only successful PR creation, so the new protected-file fallback propagation and closing-keyword neutralization are untested even though those paths have substantial existing test coverage. Add fallback-to-issue tests for both push-success and push-failure variants, asserting that the configured footer is present at the end of visible content and that closing keywords in it are escaped.
  it("should append the configured body footer when the generated footer is disabled", async () => {
  • Files reviewed: 15/16 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

const bodyFooter = getBodyFooterMessage(config.body_footer, { workflowName, runUrl });
if (bodyFooter) {
const renderedBodyFooter = bodyFooter.trimEnd();
bodyLines.push(``, renderedBodyFooter);
GitHubApp *GitHubAppConfig `yaml:"github-app,omitempty"` // GitHub App credentials for minting a per-handler installation access token
Staged *TemplatableBool `yaml:"staged,omitempty"` // Templatable preview-only mode for this specific output type
Footer *string `yaml:"footer,omitempty"` // Controls AI-generated footer behavior. Values vary by handler; false omits the visible footer but keeps XML markers.
BodyFooter string `yaml:"body-footer,omitempty"` // Deterministic template appended after agent-generated body content by supported handlers.
@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-09-05T19:34:04Z
review_event: REQUEST_CHANGES
top_themes:
- missing protected-files fallback coverage for body-footer
files_reviewed:
- actions/setup/js/create_issue.cjs
- actions/setup/js/create_pull_request.cjs
- actions/setup/js/messages.cjs
- actions/setup/js/messages_footer.cjs
- actions/setup/js/create_issue.test.cjs
- actions/setup/js/create_pull_request.test.cjs
- actions/setup/js/messages.test.cjs
- pkg/parser/schema_test.go
- pkg/parser/schemas/main_workflow_schema.json
- pkg/workflow/safe_outputs_config_types.go
- pkg/workflow/safe_outputs_footer_test.go
- pkg/workflow/safe_outputs_handler_registry_issues.go
- pkg/workflow/safe_outputs_handler_registry_pull_requests.go
comment_count: 1

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 35.3 AIC · ⌖ 7.39 AIC · ⊞ 21.8K ·
Comment /review to run again

@github-actions github-actions Bot 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.

Request changes

The new body-footer plumbing is close, but the protected-files fallback path still has no targeted coverage.

Blocking theme

This feature now depends on a second body-construction path for fallback issues, including keyword neutralization, and the diff does not prove that path preserves the configured footer. That gap is enough to let a regression through unnoticed.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 35.3 AIC · ⌖ 7.39 AIC · ⊞ 21.8K
Comment /review to run again

const issueSafeBody = neutralizeClosingKeywordsForIssueBody(body);
// Footer section (footer + workflow-id marker) used when ordering protected-files notices
const footerContent = footerParts.join("\n\n");
const issueSafeFooterContent = neutralizeClosingKeywordsForIssueBody(footerContent);

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.

This adds a second footer code path for protected-file fallback issues, but the tests never exercise it, so a regression here will ship silently.

💡 Add a focused fallback-path test

create_pull_request.cjs now threads body_footer through issueSafeFooterContent and the manifest-protection fallback body builder, which is exactly the branch most likely to drift because it has its own body assembly and closing-keyword neutralization. Please add a test that forces the protected-files fallback issue path and asserts the configured body_footer is present after sanitization, otherwise this feature is only covered for the happy-path PR body.

@github-actions github-actions Bot 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.

Simpler path: drop the extra body-footer helper and its public re-export so the new footer logic stays inline at the two call sites. net: -8 lines possible.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by ✂️ Ponytail Reviewer for #58841 · codex · mai10 · 5.23 AIC · ⌖ 10.7 AIC · ⊞ 13.5K
Comment /ponytail to run again

* @param {{workflowName: string, runUrl: string}} ctx - Template context
* @returns {string} Rendered body footer, or an empty string when not configured
*/
function getBodyFooterMessage(template, ctx) {

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.

actions/setup/js/messages_footer.cjs:302: yagni: new getBodyFooterMessage helper for one renderTemplate call. Inline it at the two call sites and drop the wrapper.

@github-actions github-actions Bot 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.

Reviewed with the Impeccable framework, falling back to a standard correctness/security review since this PR is a backend (Go/Node) feature change with no UI surface.

Scope: Adds body-footer templating to create-issue and create-pull-request safe outputs, with ordering guarantees (footer always last, before hidden XML markers) and closing-keyword neutralization for fallback issue bodies.

Findings: No blocking issues found.

Review notes
  • body-footer is a workflow-author-controlled config value (not agent/untrusted content), so template interpolation via renderTemplate's {key} substitution poses no injection risk.
  • Ordering is correctly enforced in both create_issue.cjs and create_pull_request.cjs: body footer appended after the standard footer and before XML markers, verified by new tests (create_issue.test.cjs, create_pull_request.test.cjs).
  • create_pull_request.cjs correctly threads issueSafeFooterContent (closing-keyword-neutralized) into the manifest-protection fallback issue body paths, consistent with existing issueSafeMainBodyContent handling.
  • Schema, Go config plumbing (BodyFooter field, handler registries), and docs are consistent with the existing title-prefix pattern.
  • Nit (non-blocking): getBodyFooterMessage returns "" (not trimmed) if template is falsy, but if template is a whitespace-only string it renders and is pushed (after trimEnd(), becomes empty), producing an extra blank line in bodyLines.push(``, bodyFooter.trimEnd()). Very low impact, not tied to changed core logic beyond this feature.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · copilot · sonnet50 · 48.5 AIC · ⌖ 13.3 AIC · ⊞ 8.3K

@github-actions github-actions Bot 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.

Skills-Based Review 🧠

Applied /tdd and /codebase-design to the new deterministic body-footer feature (getBodyFooterMessage, create_issue.cjs, create_pull_request.cjs). Overall the change is small, well-tested for the happy paths, and the docs/schema/changeset are all updated consistently.

📋 Key Themes & Highlights

Key Themes

  • Missing regression test for neutralization order: create_pull_request.cjs now runs neutralizeClosingKeywordsForIssueBody over the combined footerContent (which includes the new body_footer) before it lands in protected-file fallback issues, but there's no test with a body_footer containing a closing keyword to confirm it's actually neutralized in that path.
  • Sanitization asymmetry: the new footer content bypasses the existing sanitizeContent step used for the rest of the issue/PR body. Likely fine given body-footer is workflow-author-controlled, but worth a documenting comment or explicit note since it diverges from the established pattern for all other body content.

Positive Highlights

  • ✅ Good placement/ordering tests confirming the footer lands after the generated footer and before hidden XML markers, for both issue and PR handlers.
  • getBodyFooterMessage follows the existing renderTemplate/toSnakeCase pattern used elsewhere in messages_footer.cjs, keeping the new code consistent with the module's established idioms.
  • ✅ Schema, type definitions, docs, and changeset are all updated together — nice completeness for a small feature addition.

@copilot please address the review comments above.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 74.1 AIC · ⌖ 14.8 AIC · ⊞ 10.3K
Comment /matt to run again

const issueSafeBody = neutralizeClosingKeywordsForIssueBody(body);
// Footer section (footer + workflow-id marker) used when ordering protected-files notices
const footerContent = footerParts.join("\n\n");
const issueSafeFooterContent = neutralizeClosingKeywordsForIssueBody(footerContent);

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.

[/tdd] New issueSafeFooterContent neutralizes closing keywords in the footer (which now includes the configured body-footer) before it reaches the protected-file fallback issue, but no test exercises this path with a body_footer containing a closing keyword (e.g. Fixes #1).

💡 Suggested test

Add a case to the manifest-protection fallback tests that configures body_footer: "Fixes #1" and asserts the resulting fallback issue body contains a neutralized keyword (e.g. `Fixes` #1 or similar) rather than an active closing reference. Without this, a regression that skips neutralization for the new footer content would silently auto-close unrelated issues.

@copilot please address this.

bodyLines.push(``, footer);
}

const bodyFooter = getBodyFooterMessage(config.body_footer, { workflowName, runUrl });

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.

[/codebase-design] body_footer is appended to bodyLines directly, bypassing the sanitizeContent call applied to processedBody a few lines above (line 919). Since body-footer is workflow-author-controlled (not agent output), this is lower risk than the main body, but it's inconsistent with the codebase's existing security posture where all body content flows through sanitization before hitting bodyLines.

💡 Consideration

If body-footer templates ever interpolate values that could contain untrusted data (e.g. a future placeholder pulling from PR/issue titles), this unsanitized path would become an injection vector. Worth a one-line comment documenting the assumption that body-footer is always static/workflow-author-controlled and never agent-influenced.

@copilot please address this.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator
pr-sous-chef

@copilot Please take the next forward-progress pass on this PR.

  • Review the newest feedback on current HEAD, especially the PR fallback-body ordering/body-length concerns and the fallback-path coverage gaps.
  • Refresh the branch if needed, then address the outstanding review comments and run the pr-finisher skill.
  • In your maintainer-facing handoff, state clearly whether any blockers remain after those fixes.

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 37.8 AIC · ⌖ 8.62 AIC · ⊞ 9.2K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author
pr-sous-chef
```...

Implemented in ff8db86. Pull-request fallback issues now build from the main body and append the configured footer after visible recovery instructions, while preserving hidden metadata. Oversized combined issue/PR bodies are rejected before GitHub API calls; affected JavaScript tests and final validation passed. No blockers remain from this feedback.

@pelikhan

pelikhan commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

@copilot the new field is additive and a shared agentic workflow can define one and it will be appended together

Copilot AI commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

@copilot the new field is additive and a shared agentic workflow can define one and it will be appended together

Correct—the field is additive. The configured body-footer is rendered separately and appended in addition to the existing messages footer; shared workflows can define it and each supported output will include both footer contents.

@pelikhan
pelikhan merged commit 988d3d9 into main Sep 5, 2026
@pelikhan
pelikhan deleted the copilot/add-footer-message-template branch September 5, 2026 21:04
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.88.5

github-actions Bot added a commit that referenced this pull request Sep 8, 2026
Document the body-footer safe-output field added in #58841, which was
missing from .github/aw instructions despite being documented on the
public docs site.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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.

4 participants