Apply progressive disclosure to protected files warning messages#22855
Conversation
- Wrap protected file details (file list + explanation) in <details>/<summary> blocks - Generate valid GitHub URLs for protected files, formatted as markdown lists - Update all three protected files templates: - manifest_protection_push_failed_fallback.md - manifest_protection_create_pr_fallback.md - manifest_protection_push_to_pr_fallback.md - Update create_pull_request.cjs and push_to_pull_request_branch.cjs to generate file list as markdown bullet points with clickable GitHub URLs Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/gh-aw/sessions/310c5718-65a3-45e1-9085-6bbd833e94b7
…URLs Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/gh-aw/sessions/310c5718-65a3-45e1-9085-6bbd833e94b7
…to avoid duplication Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/gh-aw/sessions/310c5718-65a3-45e1-9085-6bbd833e94b7
…leList API Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/gh-aw/sessions/310c5718-65a3-45e1-9085-6bbd833e94b7
There was a problem hiding this comment.
Pull request overview
This PR reduces noise in protected-files fallback messages by collapsing verbose content behind a <details> toggle and replacing inline backticked filenames with a clickable, properly-encoded file list.
Changes:
- Updated protected-files fallback markdown templates to show a concise warning and place file lists in a collapsed
<details>/<summary>section. - Added URL/path encoding and protected-file list link generation helpers in
messages_core.cjs. - Updated protected-files fallback issue creation in
create_pull_request.cjsandpush_to_pull_request_branch.cjsto use the new linked list formatting.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| actions/setup/md/manifest_protection_push_to_pr_fallback.md | Collapses protected file list into a <details> block in the push-to-PR fallback template. |
| actions/setup/md/manifest_protection_push_failed_fallback.md | Collapses protected file list and pushes verbose explanation into the <details> block for push-failed fallback. |
| actions/setup/md/manifest_protection_create_pr_fallback.md | Collapses protected file list into a <details> block for create-PR fallback. |
| actions/setup/js/push_to_pull_request_branch.cjs | Uses buildProtectedFileList(...) when rendering protected-files fallback issue bodies. |
| actions/setup/js/messages_core.cjs | Introduces encodePathSegments and buildProtectedFileList helpers and exports them for use by handlers. |
| actions/setup/js/create_pull_request.cjs | Uses buildProtectedFileList(...) and encodePathSegments(...) in manifest-protection fallback issue rendering and compare URL construction. |
Comments suppressed due to low confidence (2)
actions/setup/js/messages_core.cjs:140
- The Markdown link label uses the raw filename/path (
[${f}]). File paths can legally contain Markdown-significant characters like[,],(,), or backslashes, which can break the list formatting or enable Markdown injection. Escape the link text (and consider escaping/encoding the URL portion consistently) before rendering.
.map(f => {
const encodedPath = encodePathSegments(f);
return `- [${f}](${githubServer}/${owner}/${repo}/blob/${encodedBranch}/${encodedPath})`;
})
actions/setup/js/messages_core.cjs:151
encodePathSegments/buildProtectedFileListare new exported helpers and are part of user-visible issue bodies. There are existing Vitest tests formessages_core.cjs, but these helpers currently have no coverage. Add unit tests covering typical paths and edge cases (slashes, spaces, parentheses/brackets, and mixed basename vs path inputs) to prevent regressions in link generation.
module.exports = {
getMessages,
renderTemplate,
renderTemplateFromFile,
toSnakeCase,
encodePathSegments,
buildProtectedFileList,
};
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const allFound = manifestProtectionFallback; | ||
| const filesFormatted = allFound.map(f => `\`${f}\``).join(", "); | ||
| const githubServer = process.env.GITHUB_SERVER_URL || "https://github.com"; | ||
| const fileList = buildProtectedFileList(allFound, githubServer, repoParts.owner, repoParts.repo, baseBranch); |
There was a problem hiding this comment.
In the manifest-protection fallback (push succeeded) case, the protected file links are currently built against baseBranch. That means clicking a file will often show the pre-change version (and could even 404 if the protected path only exists on the head branch). Use branchName for the normal (push-succeeded) path, and reserve baseBranch only for the push-failed path where the head branch is not on the remote.
| const fileList = buildProtectedFileList(allFound, githubServer, repoParts.owner, repoParts.repo, baseBranch); | |
| const branchForLinks = manifestProtectionPushFailedError ? baseBranch : branchName; | |
| const fileList = buildProtectedFileList(allFound, githubServer, repoParts.owner, repoParts.repo, branchForLinks); |
| * URL-encode each segment of a slash-separated path. | ||
| * Preserves the slash separators while encoding special characters in each segment. | ||
| * @param {string} path - A slash-separated path (e.g. branch name or file path) | ||
| * @returns {string} Path with each segment individually URL-encoded | ||
| */ | ||
| function encodePathSegments(path) { | ||
| return path.split("/").map(encodeURIComponent).join("/"); |
There was a problem hiding this comment.
encodePathSegments() uses encodeURIComponent, which intentionally leaves characters like ( and ) unescaped. Since these values are later embedded inside Markdown link targets, unescaped parentheses can break link parsing (or produce ambiguous URLs). Consider RFC3986-style encoding (e.g., additionally percent-encode [!'()*()]) so the generated Markdown links remain valid for branches/paths containing these characters.
This issue also appears on line 137 of the same file.
| * URL-encode each segment of a slash-separated path. | |
| * Preserves the slash separators while encoding special characters in each segment. | |
| * @param {string} path - A slash-separated path (e.g. branch name or file path) | |
| * @returns {string} Path with each segment individually URL-encoded | |
| */ | |
| function encodePathSegments(path) { | |
| return path.split("/").map(encodeURIComponent).join("/"); | |
| * RFC3986-compliant encoding for individual URI components. | |
| * Starts with encodeURIComponent and then additionally percent-encodes | |
| * characters that are still reserved in RFC3986. | |
| * @param {string} value | |
| * @returns {string} | |
| */ | |
| function encodeRFC3986URIComponent(value) { | |
| return encodeURIComponent(value).replace(/[!'()*]/g, c => | |
| "%" + c.charCodeAt(0).toString(16).toUpperCase() | |
| ); | |
| } | |
| /** | |
| * URL-encode each segment of a slash-separated path. | |
| * Preserves the slash separators while encoding special characters in each segment. | |
| * @param {string} path - A slash-separated path (e.g. branch name or file path) | |
| * @returns {string} Path with each segment individually URL-encoded | |
| */ | |
| function encodePathSegments(path) { | |
| return path.split("/").map(encodeRFC3986URIComponent).join("/"); |
| const encodedPath = encodePathSegments(f); | ||
| return `- [${f}](${githubServer}/${owner}/${repo}/blob/${encodedBranch}/${encodedPath})`; |
There was a problem hiding this comment.
buildProtectedFileList() assumes every entry in files is a full path. However, checkFileProtection() can return a mix of basenames (from manifest matching) and full paths (from prefix matching). For basename-only entries like package.json from a nested directory, this will link to /blob/<branch>/package.json at repo root, which may be incorrect. Either update the protection logic to return full paths for manifest matches, or have this formatter detect basename-only entries and render them differently (e.g., as code spans or a search link).
This issue also appears on line 144 of the same file.
| const encodedPath = encodePathSegments(f); | |
| return `- [${f}](${githubServer}/${owner}/${repo}/blob/${encodedBranch}/${encodedPath})`; | |
| // If the entry looks like a full path (contains a slash), render it as a blob link. | |
| // Otherwise, treat it as a basename-only entry (e.g. from manifest matching) and | |
| // render it as a code span to avoid linking to a potentially incorrect root path. | |
| if (f.includes("/")) { | |
| const encodedPath = encodePathSegments(f); | |
| return `- [${f}](${githubServer}/${owner}/${repo}/blob/${encodedBranch}/${encodedPath})`; | |
| } | |
| return `- \`${f}\``; |
|
@copilot Review comments |
…nk correctness - Add encodeRFC3986URIComponent to also percent-encode !'()* chars that break Markdown link syntax - buildProtectedFileList renders basename-only entries (no slash) as code spans instead of blob links, to avoid incorrect root-path links - create_pull_request.cjs: use branchName (head branch) for file links in the normal push-succeeded case; only fall back to baseBranch when push failed Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/gh-aw/sessions/3ba55709-7936-4710-9cb7-c7cfc7b4afa4
…o-digit hex encoding Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> Agent-Logs-Url: https://github.com/github/gh-aw/sessions/3ba55709-7936-4710-9cb7-c7cfc7b4afa4
All three review comments addressed in commits
|
Protected files warnings were dumping the full explanation and raw file list inline, making the issue body noisy. Files were also listed as plain backtick strings with no way to navigate to them.
Changes
Templates (
actions/setup/md/)<details>/<summary>block with a "🔒 Protected files" toggle, across all three fallback templates:manifest_protection_push_failed_fallback.mdmanifest_protection_create_pr_fallback.mdmanifest_protection_push_to_pr_fallback.md[!WARNING]callout now shows only a concise summary; details are collapsed by defaultmessages_core.cjsencodePathSegments(path)— URL-encodes each slash-delimited segment of a pathbuildProtectedFileList(files, githubServer, owner, repo, branch)— generates a markdown bullet list of clickable GitHub blob URLs with proper encoding for both branch name and file path segmentscreate_pull_request.cjs/push_to_pull_request_branch.cjs`file`strings withbuildProtectedFileList(...), linking each file to its location on the relevant branchBefore:
After (collapsed by default):
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/graphql/usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw .cfg 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git ormatted successgit failure.md 64/pkg/tool/linu--show-toplevel git(http block)https://api.github.com/orgs/test-owner/actions/secrets/usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name(http block)https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1/usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v3/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha k/gh-aw/gh-aw/pkg/fileutil/fileutil.go k/gh-aw/gh-aw/pkg/fileutil/tar.go ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet -errorsas -ifaceassert -nilfunc ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v5/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha te 'scripts/**/*.js' --ignore-path .prettierignore --log-level=error .cfg 64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha github.event.inputs.branch x_amd64/vet /usr/bin/git lex-frontmatter-git security 64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git rite '**/*.cjs' git owner 64/pkg/tool/linu--show-toplevel git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel ache/go/1.25.0/x64/pkg/tool/linutest@example.com /usr/bin/git --write scripts/**/*.js ache/go/1.25.0/x--show-toplevel git rev-�� --show-toplevel ache/go/1.25.0/x64/pkg/tool/linu^remote\..*\.gh-resolved$ /usr/bin/git --write ../../../**/*.jsrev-parse 5748158/b177/vet--show-toplevel git(http block)https://api.github.com/repos/actions/checkout/git/ref/tags/v6/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha -bool -buildtags /usr/bin/git -errorsas -ifaceassert -nilfunc git rev-�� --show-toplevel -tests /usr/bin/git -2.15.1.3-py3.12git committer.name x_amd64/vet git(http block)/usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git se 5748158/b061/vetrev-parse .cfg git rev-�� --show-toplevel ache/go/1.25.0/x64/pkg/tool/linuorigin /usr/bin/git se 5748158/b217/vetrev-parse .cfg git(http block)https://api.github.com/repos/actions/github-script/git/ref/tags/v8/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha on' --ignore-pat-errorsas --local es/.bin/sh http.https://git/opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha on' --ignore-path ../../../.prettierignore --local tnet/tools/git(http block)https://api.github.com/repos/actions/setup-go/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha /tmp/go-build2515748158/b447/timeutil.test -importcfg /usr/bin/git -s -w -buildmode=exe git rev-�� --git-dir -extld=gcc /usr/bin/git --local committer.name x_amd64/vet git(http block)https://api.github.com/repos/actions/setup-node/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha /tmp/go-build2515748158/b443/testutil.test -importcfg /usr/bin/git -s -w -buildmode=exe git comm�� -m Add workflow /usr/bin/git files..." committer.name nch,headSha,disp--show-toplevel git(http block)https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4/usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha ithub/workflows/agent-persona-explorer.md /tmp/go-build2515748158/b073/vet.cfg 5748158/b359/vet.cfg(http block)https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0/usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq .object.sha 999 /tmp/go-build2515748158/b078/vet.cfg /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3/usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq .object.sha runs/20260325-110028-13313/test-244557664/.github/workflows /tmp/go-build2515748158/b077/vet.cfg 0/x64/bin/node(http block)https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts/usr/bin/gh gh run download 1 --dir test-logs/run-1(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts/usr/bin/gh gh run download 12345 --dir test-logs/run-12345(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts/usr/bin/gh gh run download 12346 --dir test-logs/run-12346 k/gh-aw/gh-aw/actions/setup/js/p-test.run=^Test x_amd64/link(http block)https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts/usr/bin/gh gh run download 2 --dir test-logs/run-2(http block)https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts/usr/bin/gh gh run download 3 --dir test-logs/run-3(http block)https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts/usr/bin/gh gh run download 4 --dir test-logs/run-4(http block)https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts/usr/bin/gh gh run download 5 --dir test-logs/run-5(http block)https://api.github.com/repos/github/gh-aw/actions/workflows/usr/bin/gh gh workflow list --json name,state,path(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6(http block)https://api.github.com/repos/github/gh-aw/contents/.github%2Fworkflows%2Faudit-workflows.md/opt/hostedtoolcache/node/24.14.0/x64/bin/node /opt/hostedtoolcache/node/24.14.0/x64/bin/node --experimental-import-meta-resolve --require /home/REDACTED/work/gh-aw/gh-aw/actions/setup/js/node_modules/vitest/suppress-warnings.cjs --conditions node --conditions development /home/REDACTED/work/gh-aw/gh-aw/actions/setup/js/node_modules/vitest/dist/workers/forks.js(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha ty-test.md .cfg 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.2.3/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq .object.sha th .prettierigno-errorsas --local es/.bin/node user.email(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/v2.0.0/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha th .prettierigno-errorsas --local /home/REDACTED/.ca-nilfunc tion_push_failed/opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linux_amd64/compile(http block)/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha get --local odules/npm/node_-nilfunc user.email(http block)/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha it} --local ache/uv/0.11.1/x-nilfunc committer.name(http block)https://api.github.com/repos/github/gh-aw/git/ref/tags/v3.0.0/usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq .object.sha get --local /usr/local/.ghcup/bin/git user.email(http block)https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999/usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha ting Go code..."-c=4 .cfg 64/pkg/tool/linu-importcfg(http block)https://api.github.com/repos/nonexistent/repo/actions/runs/12345/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion nore /home/REDACTED/wor/tmp/js-hash-test-1981750996/test-hash.js /home/REDACTED/wor/home/REDACTED/work/gh-aw/gh-aw/.github/workflows/audit-workflows.md 64/pkg/tool/linux_amd64/vet --no�� te '**/*.cjs' '**/*.ts' '**/*.js-p /home/REDACTED/work/gh-aw/gh-aw/acgithub.com/github/gh-aw/pkg/parser_test 64/pkg/tool/linux_amd64/vet /home/REDACTED/worgit /home/REDACTED/worrev-parse /home/REDACTED/wor--show-toplevel 64/pkg/tool/linux_amd64/vet(http block)https://api.github.com/repos/owner/repo/actions/workflows/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo node(http block)/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo t[bot](http block)https://api.github.com/repos/owner/repo/contents/file.md/tmp/go-build2515748158/b402/cli.test /tmp/go-build2515748158/b402/cli.test -test.testlogfile=/tmp/go-build2515748158/b402/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true(http block)https://api.github.com/repos/test-owner/test-repo/actions/secrets/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name(http block)invalid.example.invalid/usr/lib/git-core/git-remote-https /usr/lib/git-core/git-remote-https origin https://invalid.example.invalid/nonexistent-repo.git e/git init�� de/node/bin/git git tions/setup/js/node_modules/.bin/git user.email test@example.comcheckout /git git bran�� -M main k/gh-aw/gh-aw/actions/setup/js/node_modules/.bin/git /tmp/bare-incremgit gin/feature-branadd cal/bin/git git(dns block)If you need me to access, download, or install something from one of these locations, you can either:
⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.