From 7f692ba7182cc31ec9da5bcd95dfd607dc7d0c57 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Mar 2026 13:53:32 +0000 Subject: [PATCH 1/3] Initial plan From b18bec7a0dc5daa6e81ce57eb076eae04fbe3261 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:15:49 +0000 Subject: [PATCH 2/3] fix: add target-repo and allowed-repos support to submit_pull_request_review Adds cross-repository support to `submit_pull_request_review` to fix PR review submission failing with 404 in cross-repo workflows. - Add `TargetRepoSlug` and `AllowedRepos` fields to `SubmitPullRequestReviewConfig` - Parse `target-repo` and `allowed-repos` in `parseSubmitPullRequestReviewConfig` - Update compiler config to include new fields in handler config output - Update JS handler to use `resolveTargetRepoConfig`/`resolveAndValidateRepo` - Update TypeScript types to add `target`, `target-repo`, `allowed-repos` fields - Add cross-repo tests in JS and Go test files - Update documentation in safe-outputs.md Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- actions/setup/js/submit_pr_review.cjs | 76 ++++++---- actions/setup/js/submit_pr_review.test.cjs | 143 ++++++++++++++++++ .../setup/js/types/safe-outputs-config.d.ts | 3 + .../content/docs/reference/safe-outputs.md | 4 + pkg/workflow/compiler_safe_outputs_config.go | 2 + pkg/workflow/submit_pr_review.go | 16 +- pkg/workflow/submit_pr_review_footer_test.go | 93 ++++++++++++ 7 files changed, 302 insertions(+), 35 deletions(-) diff --git a/actions/setup/js/submit_pr_review.cjs b/actions/setup/js/submit_pr_review.cjs index d00a7891014..70eaa1cca32 100644 --- a/actions/setup/js/submit_pr_review.cjs +++ b/actions/setup/js/submit_pr_review.cjs @@ -6,16 +6,13 @@ */ const { resolveTarget } = require("./safe_output_helpers.cjs"); +const { resolveTargetRepoConfig, resolveAndValidateRepo } = require("./repo_helpers.cjs"); const { createAuthenticatedGitHubClient } = require("./handler_auth.cjs"); const { getErrorMessage } = require("./error_helpers.cjs"); /** @type {string} Safe output type handled by this module */ const HANDLER_TYPE = "submit_pull_request_review"; -// allowedRepos: this handler operates exclusively on the triggering repository. -// Cross-repository PR review submission is not supported; no target-repo allowlist -// check is required. - /** @type {Set} Valid review event types */ const VALID_EVENTS = new Set(["APPROVE", "REQUEST_CHANGES", "COMMENT"]); @@ -33,6 +30,7 @@ async function main(config = {}) { const maxCount = config.max || 1; const targetConfig = config.target || "triggering"; const buffer = config._prReviewBuffer; + const { defaultTargetRepo, allowedRepos } = resolveTargetRepoConfig(config); const githubClient = await createAuthenticatedGitHubClient(config); if (!buffer) { @@ -43,6 +41,10 @@ async function main(config = {}) { } core.info(`Submit PR review handler initialized: max=${maxCount}, target=${targetConfig}`); + core.info(`Default target repo: ${defaultTargetRepo}`); + if (allowedRepos.size > 0) { + core.info(`Allowed repos: ${Array.from(allowedRepos).join(", ")}`); + } let processedCount = 0; @@ -109,39 +111,47 @@ async function main(config = {}) { } } else if (targetResult.number) { const prNum = targetResult.number; - const repo = `${context.repo.owner}/${context.repo.repo}`; - const repoParts = { owner: context.repo.owner, repo: context.repo.repo }; - const payloadPR = context.payload?.pull_request; - const usePayloadPR = payloadPR && payloadPR.number === prNum && payloadPR.head?.sha; - - if (usePayloadPR) { - buffer.setReviewContext({ - repo, - repoParts, - pullRequestNumber: payloadPR.number, - pullRequest: payloadPR, - }); - core.info(`Set review context from triggering PR: ${repo}#${payloadPR.number}`); + + // Resolve and validate the target repository (supports cross-repo via target-repo config) + const repoResult = resolveAndValidateRepo(message, defaultTargetRepo, allowedRepos, "PR review"); + if (!repoResult.success) { + // Warn and leave context unset; submitReview() will subsequently fail + // with "No review context available" — this is not a silent failure. + core.warning(`Could not resolve repository for PR review context: ${repoResult.error}`); } else { - try { - const { data: fetchedPR } = await githubClient.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: prNum, + const { repo, repoParts } = repoResult; + const payloadPR = context.payload?.pull_request; + const usePayloadPR = payloadPR && payloadPR.number === prNum && payloadPR.head?.sha && repo === `${context.repo.owner}/${context.repo.repo}`; + + if (usePayloadPR) { + buffer.setReviewContext({ + repo, + repoParts, + pullRequestNumber: payloadPR.number, + pullRequest: payloadPR, }); - if (fetchedPR?.head?.sha) { - buffer.setReviewContext({ - repo, - repoParts, - pullRequestNumber: fetchedPR.number, - pullRequest: fetchedPR, + core.info(`Set review context from triggering PR: ${repo}#${payloadPR.number}`); + } else { + try { + const { data: fetchedPR } = await githubClient.rest.pulls.get({ + owner: repoParts.owner, + repo: repoParts.repo, + pull_number: prNum, }); - core.info(`Set review context from target: ${repo}#${fetchedPR.number}`); - } else { - core.warning("Fetched PR missing head.sha - cannot set review context"); + if (fetchedPR?.head?.sha) { + buffer.setReviewContext({ + repo, + repoParts, + pullRequestNumber: fetchedPR.number, + pullRequest: fetchedPR, + }); + core.info(`Set review context from target: ${repo}#${fetchedPR.number}`); + } else { + core.warning("Fetched PR missing head.sha - cannot set review context"); + } + } catch (fetchErr) { + core.warning(`Could not fetch PR #${prNum} for review context: ${getErrorMessage(fetchErr)}`); } - } catch (fetchErr) { - core.warning(`Could not fetch PR #${prNum} for review context: ${getErrorMessage(fetchErr)}`); } } } diff --git a/actions/setup/js/submit_pr_review.test.cjs b/actions/setup/js/submit_pr_review.test.cjs index d27c4b601cd..2aa35116b48 100644 --- a/actions/setup/js/submit_pr_review.test.cjs +++ b/actions/setup/js/submit_pr_review.test.cjs @@ -446,6 +446,149 @@ describe("submit_pr_review (Handler Factory Architecture)", () => { delete global.github; }); + it("should use target-repo for cross-repo PR review submission", async () => { + const fetchedPR = { + number: 1, + head: { sha: "consumer-sha" }, + user: { login: "author" }, + }; + global.context = { + eventName: "workflow_dispatch", + repo: { owner: "provider-org", repo: "provider-repo" }, + payload: {}, + }; + global.github = { + rest: { + pulls: { + get: vi.fn().mockResolvedValue({ data: fetchedPR }), + }, + }, + }; + + const localBuffer = createReviewBuffer(); + const { main } = require("./submit_pr_review.cjs"); + const localHandler = await main({ + max: 1, + target: "1", + "target-repo": "consumer-org/consumer-repo", + _prReviewBuffer: localBuffer, + }); + + const message = { + type: "submit_pull_request_review", + body: "LGTM", + event: "APPROVE", + }; + + const result = await localHandler(message, {}); + + expect(result.success).toBe(true); + const ctx = localBuffer.getReviewContext(); + expect(ctx).not.toBeNull(); + expect(ctx.repo).toBe("consumer-org/consumer-repo"); + expect(ctx.pullRequestNumber).toBe(1); + expect(ctx.pullRequest.head.sha).toBe("consumer-sha"); + // Ensure API was called on consumer-repo, not provider-repo + expect(global.github.rest.pulls.get).toHaveBeenCalledWith({ + owner: "consumer-org", + repo: "consumer-repo", + pull_number: 1, + }); + + delete global.context; + delete global.github; + }); + + it("should use target-repo with allowed-repos for cross-repo review", async () => { + const fetchedPR = { + number: 7, + head: { sha: "allowed-sha" }, + user: { login: "author" }, + }; + global.context = { + eventName: "workflow_dispatch", + repo: { owner: "provider-org", repo: "provider-repo" }, + payload: {}, + }; + global.github = { + rest: { + pulls: { + get: vi.fn().mockResolvedValue({ data: fetchedPR }), + }, + }, + }; + + const localBuffer = createReviewBuffer(); + const { main } = require("./submit_pr_review.cjs"); + const localHandler = await main({ + max: 1, + target: "7", + "target-repo": "consumer-org/consumer-repo", + allowed_repos: ["consumer-org/other-repo"], + _prReviewBuffer: localBuffer, + }); + + // Message with explicit repo matching an allowed repo + const message = { + type: "submit_pull_request_review", + body: "Looks good", + event: "APPROVE", + repo: "consumer-org/other-repo", + }; + + const result = await localHandler(message, {}); + + expect(result.success).toBe(true); + const ctx = localBuffer.getReviewContext(); + expect(ctx).not.toBeNull(); + expect(ctx.repo).toBe("consumer-org/other-repo"); + expect(global.github.rest.pulls.get).toHaveBeenCalledWith({ + owner: "consumer-org", + repo: "other-repo", + pull_number: 7, + }); + + delete global.context; + delete global.github; + }); + + it("should reject cross-repo review when repo is not in allowed list", async () => { + global.context = { + eventName: "workflow_dispatch", + repo: { owner: "provider-org", repo: "provider-repo" }, + payload: {}, + }; + + const localBuffer = createReviewBuffer(); + const { main } = require("./submit_pr_review.cjs"); + const localHandler = await main({ + max: 1, + target: "1", + "target-repo": "consumer-org/consumer-repo", + _prReviewBuffer: localBuffer, + }); + + // Message with explicit repo that is not allowed + const message = { + type: "submit_pull_request_review", + body: "Attempting to review disallowed repo", + event: "APPROVE", + repo: "attacker-org/attacker-repo", + }; + + const result = await localHandler(message, {}); + + // Metadata is stored successfully (success refers to buffering, not final submission) + expect(result.success).toBe(true); + expect(localBuffer.hasReviewMetadata()).toBe(true); + + // Review context should NOT be set because the disallowed repo was rejected + // submitReview() will subsequently fail with "No review context available" + expect(localBuffer.getReviewContext()).toBeNull(); + + delete global.context; + }); + it("should not override existing review context from comments", async () => { // Pre-set context as if a comment handler already set it buffer.setReviewContext({ diff --git a/actions/setup/js/types/safe-outputs-config.d.ts b/actions/setup/js/types/safe-outputs-config.d.ts index b3635fbf72b..7d470b29e2c 100644 --- a/actions/setup/js/types/safe-outputs-config.d.ts +++ b/actions/setup/js/types/safe-outputs-config.d.ts @@ -103,6 +103,9 @@ interface CreatePullRequestReviewCommentConfig extends SafeOutputConfig { * Boolean values are also supported: true maps to "always", false maps to "none". */ interface SubmitPullRequestReviewConfig extends SafeOutputConfig { + target?: string; + "target-repo"?: string; + "allowed-repos"?: string[]; footer?: boolean | "always" | "none" | "if-body"; } diff --git a/docs/src/content/docs/reference/safe-outputs.md b/docs/src/content/docs/reference/safe-outputs.md index 4ebc5e47dae..9b44af4391c 100644 --- a/docs/src/content/docs/reference/safe-outputs.md +++ b/docs/src/content/docs/reference/safe-outputs.md @@ -758,6 +758,8 @@ If the agent does not call `submit_pull_request_review` at all, buffered comment When the workflow is not triggered by a pull request (e.g. `workflow_dispatch`), set `target` to the PR number (e.g. `${{ github.event.inputs.pr_number }}`) so the review can be submitted. Same semantics as [add-comment](#comment-creation-add-comment) `target`: `"triggering"` (default), `"*"` (use `pull_request_number` from the message), or an explicit number. +For cross-repository scenarios, use `target-repo` to specify the repository where the PR lives. This mirrors the behavior of `create-pull-request-review-comment` and `add-comment`. + ```yaml wrap safe-outputs: create-pull-request-review-comment: @@ -765,6 +767,8 @@ safe-outputs: submit-pull-request-review: max: 1 # max reviews to submit (default: 1) target: "triggering" # or "*", or e.g. ${{ github.event.inputs.pr_number }} when not in pull_request trigger + target-repo: "owner/repo" # cross-repository: submit review on PR in another repo + allowed-repos: ["org/repo1", "org/repo2"] # additional allowed repositories footer: false # omit AI-generated footer from review body (default: true) ``` diff --git a/pkg/workflow/compiler_safe_outputs_config.go b/pkg/workflow/compiler_safe_outputs_config.go index 647f6d0a9f6..99e887ec40c 100644 --- a/pkg/workflow/compiler_safe_outputs_config.go +++ b/pkg/workflow/compiler_safe_outputs_config.go @@ -424,6 +424,8 @@ var handlerRegistry = map[string]handlerBuilder{ return newHandlerConfigBuilder(). AddTemplatableInt("max", c.Max). AddIfNotEmpty("target", c.Target). + AddIfNotEmpty("target-repo", c.TargetRepoSlug). + AddStringSlice("allowed_repos", c.AllowedRepos). AddIfNotEmpty("github-token", c.GitHubToken). AddStringPtr("footer", getEffectiveFooterString(c.Footer, cfg.Footer)). Build() diff --git a/pkg/workflow/submit_pr_review.go b/pkg/workflow/submit_pr_review.go index aff3c9850f3..135f6ebe560 100644 --- a/pkg/workflow/submit_pr_review.go +++ b/pkg/workflow/submit_pr_review.go @@ -12,8 +12,10 @@ var submitPRReviewLog = logger.New("workflow:submit_pr_review") // If this safe output type is not configured, review comments default to event: "COMMENT". type SubmitPullRequestReviewConfig struct { BaseSafeOutputConfig `yaml:",inline"` - Target string `yaml:"target,omitempty"` // Target PR: "triggering" (default), "*" (use message.pull_request_number), or explicit number e.g. ${{ github.event.inputs.pr_number }} - Footer *string `yaml:"footer,omitempty"` // Controls when to show footer in PR review body: "always" (default), "none", or "if-body" (only when review has body text) + Target string `yaml:"target,omitempty"` // Target PR: "triggering" (default), "*" (use message.pull_request_number), or explicit number e.g. ${{ github.event.inputs.pr_number }} + TargetRepoSlug string `yaml:"target-repo,omitempty"` // Target repository in format "owner/repo" for cross-repository PR review submission + AllowedRepos []string `yaml:"allowed-repos,omitempty"` // List of additional repositories that PR reviews can be submitted to (additionally to the target-repo) + Footer *string `yaml:"footer,omitempty"` // Controls when to show footer in PR review body: "always" (default), "none", or "if-body" (only when review has body text) } // parseSubmitPullRequestReviewConfig handles submit-pull-request-review configuration @@ -39,6 +41,16 @@ func (c *Compiler) parseSubmitPullRequestReviewConfig(outputMap map[string]any) } } + // Parse target-repo using shared helper with validation + targetRepoSlug, isInvalid := parseTargetRepoWithValidation(configMap) + if isInvalid { + return nil // Invalid configuration, return nil to cause validation error + } + config.TargetRepoSlug = targetRepoSlug + + // Parse allowed-repos + config.AllowedRepos = parseAllowedReposFromConfig(configMap) + // Parse footer configuration (string: "always"/"none"/"if-body", or bool for backward compat) if footer, exists := configMap["footer"]; exists { switch f := footer.(type) { diff --git a/pkg/workflow/submit_pr_review_footer_test.go b/pkg/workflow/submit_pr_review_footer_test.go index e6bbb23a3bc..bdc4a0f4afc 100644 --- a/pkg/workflow/submit_pr_review_footer_test.go +++ b/pkg/workflow/submit_pr_review_footer_test.go @@ -155,6 +155,61 @@ func TestSubmitPRReviewFooterConfig(t *testing.T) { require.NotNil(t, config, "Config should be parsed") assert.Empty(t, config.Target, "Target should be empty when not configured") }) + + t.Run("parses target-repo field", func(t *testing.T) { + compiler := NewCompiler() + outputMap := map[string]any{ + "submit-pull-request-review": map[string]any{ + "max": 1, + "target-repo": "consumer-org/consumer-repo", + }, + } + + config := compiler.parseSubmitPullRequestReviewConfig(outputMap) + require.NotNil(t, config, "Config should be parsed") + assert.Equal(t, "consumer-org/consumer-repo", config.TargetRepoSlug, "TargetRepoSlug should be parsed") + }) + + t.Run("target-repo empty when omitted", func(t *testing.T) { + compiler := NewCompiler() + outputMap := map[string]any{ + "submit-pull-request-review": map[string]any{ + "max": 1, + }, + } + + config := compiler.parseSubmitPullRequestReviewConfig(outputMap) + require.NotNil(t, config, "Config should be parsed") + assert.Empty(t, config.TargetRepoSlug, "TargetRepoSlug should be empty when not configured") + }) + + t.Run("parses allowed-repos field", func(t *testing.T) { + compiler := NewCompiler() + outputMap := map[string]any{ + "submit-pull-request-review": map[string]any{ + "max": 1, + "target-repo": "consumer-org/consumer-repo", + "allowed-repos": []any{"consumer-org/other-repo", "consumer-org/another-repo"}, + }, + } + + config := compiler.parseSubmitPullRequestReviewConfig(outputMap) + require.NotNil(t, config, "Config should be parsed") + assert.Equal(t, []string{"consumer-org/other-repo", "consumer-org/another-repo"}, config.AllowedRepos, "AllowedRepos should be parsed") + }) + + t.Run("returns nil for wildcard target-repo", func(t *testing.T) { + compiler := NewCompiler() + outputMap := map[string]any{ + "submit-pull-request-review": map[string]any{ + "max": 1, + "target-repo": "*", + }, + } + + config := compiler.parseSubmitPullRequestReviewConfig(outputMap) + assert.Nil(t, config, "Config should be nil for wildcard target-repo") + }) } func TestCreatePRReviewCommentNoFooter(t *testing.T) { @@ -299,4 +354,42 @@ func TestSubmitPRReviewFooterInHandlerConfig(t *testing.T) { } } }) + + t.Run("target-repo included in submit_pull_request_review handler config when set", func(t *testing.T) { + compiler := NewCompiler() + workflowData := &WorkflowData{ + Name: "Test", + SafeOutputs: &SafeOutputsConfig{ + SubmitPullRequestReview: &SubmitPullRequestReviewConfig{ + BaseSafeOutputConfig: BaseSafeOutputConfig{Max: strPtr("1")}, + TargetRepoSlug: "consumer-org/consumer-repo", + }, + }, + } + + var steps []string + compiler.addHandlerManagerConfigEnvVar(&steps, workflowData) + require.NotEmpty(t, steps, "Steps should not be empty") + + stepsContent := strings.Join(steps, "") + require.Contains(t, stepsContent, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG") + + for _, step := range steps { + if strings.Contains(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG") { + parts := strings.Split(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: ") + if len(parts) == 2 { + jsonStr := strings.TrimSpace(parts[1]) + jsonStr = strings.Trim(jsonStr, "\"") + jsonStr = strings.ReplaceAll(jsonStr, "\\\"", "\"") + var handlerConfig map[string]any + err := json.Unmarshal([]byte(jsonStr), &handlerConfig) + require.NoError(t, err, "Should unmarshal handler config") + + submitConfig, ok := handlerConfig["submit_pull_request_review"].(map[string]any) + require.True(t, ok, "submit_pull_request_review config should exist") + assert.Equal(t, "consumer-org/consumer-repo", submitConfig["target-repo"], "Target-repo should be in submit handler config") + } + } + } + }) } From 983fdf8397869a342f3b12c13bbeacf1359953d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Mar 2026 14:50:34 +0000 Subject: [PATCH 3/3] Changes before error encountered Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/submit_pr_review.go | 16 +++++++--------- pkg/workflow/submit_pr_review_footer_test.go | 8 ++++---- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/pkg/workflow/submit_pr_review.go b/pkg/workflow/submit_pr_review.go index 135f6ebe560..96ea51ed3bb 100644 --- a/pkg/workflow/submit_pr_review.go +++ b/pkg/workflow/submit_pr_review.go @@ -11,11 +11,9 @@ var submitPRReviewLog = logger.New("workflow:submit_pr_review") // are collected and submitted as a single PR review with the configured event type. // If this safe output type is not configured, review comments default to event: "COMMENT". type SubmitPullRequestReviewConfig struct { - BaseSafeOutputConfig `yaml:",inline"` - Target string `yaml:"target,omitempty"` // Target PR: "triggering" (default), "*" (use message.pull_request_number), or explicit number e.g. ${{ github.event.inputs.pr_number }} - TargetRepoSlug string `yaml:"target-repo,omitempty"` // Target repository in format "owner/repo" for cross-repository PR review submission - AllowedRepos []string `yaml:"allowed-repos,omitempty"` // List of additional repositories that PR reviews can be submitted to (additionally to the target-repo) - Footer *string `yaml:"footer,omitempty"` // Controls when to show footer in PR review body: "always" (default), "none", or "if-body" (only when review has body text) + BaseSafeOutputConfig `yaml:",inline"` + SafeOutputTargetConfig `yaml:",inline"` + Footer *string `yaml:"footer,omitempty"` // Controls when to show footer in PR review body: "always" (default), "none", or "if-body" (only when review has body text) } // parseSubmitPullRequestReviewConfig handles submit-pull-request-review configuration @@ -34,21 +32,19 @@ func (c *Compiler) parseSubmitPullRequestReviewConfig(outputMap map[string]any) // Parse common base fields with default max of 1 c.parseBaseSafeOutputConfig(configMap, &config.BaseSafeOutputConfig, 1) - // Parse target (same semantics as add-comment / create-pull-request-review-comment) + // Parse target config (target, target-repo, allowed-repos) + // Uses parseTargetRepoWithValidation to disallow wildcard "*" for target-repo if target, exists := configMap["target"]; exists { if targetStr, ok := target.(string); ok { config.Target = targetStr } } - // Parse target-repo using shared helper with validation targetRepoSlug, isInvalid := parseTargetRepoWithValidation(configMap) if isInvalid { return nil // Invalid configuration, return nil to cause validation error } config.TargetRepoSlug = targetRepoSlug - - // Parse allowed-repos config.AllowedRepos = parseAllowedReposFromConfig(configMap) // Parse footer configuration (string: "always"/"none"/"if-body", or bool for backward compat) @@ -74,6 +70,8 @@ func (c *Compiler) parseSubmitPullRequestReviewConfig(outputMap map[string]any) submitPRReviewLog.Printf("Footer control (mapped from bool): %s", footerStr) } } + + submitPRReviewLog.Printf("Parsed submit-pull-request-review config: max=%d, target=%s, target_repo=%s", templatableIntValue(config.Max), config.Target, config.TargetRepoSlug) } else { // If configData is nil or not a map, set the default max config.Max = defaultIntStr(1) diff --git a/pkg/workflow/submit_pr_review_footer_test.go b/pkg/workflow/submit_pr_review_footer_test.go index bdc4a0f4afc..aa1c4b986af 100644 --- a/pkg/workflow/submit_pr_review_footer_test.go +++ b/pkg/workflow/submit_pr_review_footer_test.go @@ -323,8 +323,8 @@ func TestSubmitPRReviewFooterInHandlerConfig(t *testing.T) { Name: "Test", SafeOutputs: &SafeOutputsConfig{ SubmitPullRequestReview: &SubmitPullRequestReviewConfig{ - BaseSafeOutputConfig: BaseSafeOutputConfig{Max: strPtr("1")}, - Target: targetValue, + BaseSafeOutputConfig: BaseSafeOutputConfig{Max: strPtr("1")}, + SafeOutputTargetConfig: SafeOutputTargetConfig{Target: targetValue}, }, }, } @@ -361,8 +361,8 @@ func TestSubmitPRReviewFooterInHandlerConfig(t *testing.T) { Name: "Test", SafeOutputs: &SafeOutputsConfig{ SubmitPullRequestReview: &SubmitPullRequestReviewConfig{ - BaseSafeOutputConfig: BaseSafeOutputConfig{Max: strPtr("1")}, - TargetRepoSlug: "consumer-org/consumer-repo", + BaseSafeOutputConfig: BaseSafeOutputConfig{Max: strPtr("1")}, + SafeOutputTargetConfig: SafeOutputTargetConfig{TargetRepoSlug: "consumer-org/consumer-repo"}, }, }, }