feat: protect well-known top-level .md files from agent modification#29794
Conversation
Add protect_top_level_md_files flag to both create_pull_request and push_to_pull_request_branch handlers so that any .md file at the repository root is treated as a protected file. Agents may import any top-level .md file (e.g. README.md, CONTRIBUTING.md) at any time, so all such files should require explicit protected-files: allowed override. - manifest_file_helpers.cjs: add checkForTopLevelMdFiles() function and wire it into checkFileProtection() via protect_top_level_md_files flag - compiler_safe_outputs_handlers.go: emit protect_top_level_md_files: true as a default in both PR-creating handler configs - Tests added for both the JS helper function and the Go compiler output Agent-Logs-Url: https://github.com/github/gh-aw/sessions/cccddca6-61d5-4ae6-964c-1390cc25ba47 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
@copilot Merge main and review all comments |
There was a problem hiding this comment.
Pull request overview
Adds a new safe-outputs protection rule to block agent modifications to any root-level Markdown files (e.g., README.md, CONTRIBUTING.md), since these can be imported as context/instructions.
Changes:
- Add
checkForTopLevelMdFiles()and integrate it intocheckFileProtection()behind a newprotect_top_level_md_filesflag. - Emit
protect_top_level_md_files: trueby default in the Go compiler for relevant handler configs. - Update JS/Go tests and update workflow lock configs to include the new flag.
Show a summary per file
| File | Description |
|---|---|
| pkg/workflow/compiler_safe_outputs_handlers.go | Adds protect_top_level_md_files: true default to handler configs. |
| pkg/workflow/compiler_safe_outputs_config_test.go | Adds a Go test asserting the new flag is always present/true in handler configs. |
| actions/setup/js/manifest_file_helpers.cjs | Implements top-level .md detection and includes it in protection checks. |
| actions/setup/js/manifest_file_helpers.test.cjs | Adds unit tests for the new detector and integration tests for protection behavior. |
| .github/workflows/weekly-safe-outputs-spec-review.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/weekly-editors-health-check.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/weekly-blog-post-writer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/update-astro.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/unbloat-docs.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/ubuntu-image-analyzer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/tidy.lock.yml | Adds protect_top_level_md_files to locked handler config JSON (create + push handlers). |
| .github/workflows/test-create-pr-error-handling.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/technical-doc-writer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/spec-extractor.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/spec-enforcer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/smoke-update-cross-repo-pr.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/smoke-project.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/smoke-multi-pr.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/smoke-create-cross-repo-pr.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/smoke-claude.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/slide-deck-maintainer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/schema-feature-coverage.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/refiner.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/q.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/poem-bot.lock.yml | Adds protect_top_level_md_files to locked handler config JSON (create + push handlers). |
| .github/workflows/mergefest.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/layout-spec-maintainer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/jsweep.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/instructions-janitor.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/hourly-ci-cleaner.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/go-logger.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/glossary-maintainer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/github-mcp-tools-report.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/functional-pragmatist.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/dictation-prompt.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/developer-docs-consolidator.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/design-decision-gate.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/dependabot-repair.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/dead-code-remover.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/daily-workflow-updater.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/daily-safe-output-integrator.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/daily-rendering-scripts-verifier.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/daily-doc-updater.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/daily-doc-healer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/daily-community-attribution.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/daily-caveman-optimizer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/daily-astrostylelite-markdown-spellcheck.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/daily-architecture-diagram.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/craft.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/code-simplifier.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/code-scanning-fixer.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/cloclo.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/ci-coach.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
| .github/workflows/changeset.lock.yml | Adds protect_top_level_md_files to locked handler config JSON. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 54/54 changed files
- Comments generated: 2
| const { topLevelDotFoldersFound } = config.protect_top_level_dot_folders ? checkForTopLevelDotFolders(patchContent, dotFolderExcludes) : { topLevelDotFoldersFound: [] }; | ||
| const allFound = [...new Set([...manifestFilesFound, ...protectedPathsFound, ...topLevelDotFoldersFound])]; | ||
| const { topLevelMdFilesFound } = config.protect_top_level_md_files ? checkForTopLevelMdFiles(patchContent) : { topLevelMdFilesFound: [] }; | ||
| const allFound = [...new Set([...manifestFilesFound, ...protectedPathsFound, ...topLevelDotFoldersFound, ...topLevelMdFilesFound])]; |
| func TestProtectTopLevelMdFiles(t *testing.T) { | ||
| compiler := NewCompiler() | ||
| workflowData := &WorkflowData{ | ||
| Name: "Test Workflow", | ||
| SafeOutputs: &SafeOutputsConfig{ | ||
| CreatePullRequests: &CreatePullRequestsConfig{ | ||
| BaseSafeOutputConfig: BaseSafeOutputConfig{Max: strPtr("1")}, | ||
| }, | ||
| PushToPullRequestBranch: &PushToPullRequestBranchConfig{}, | ||
| }, | ||
| } | ||
|
|
||
| var steps []string | ||
| compiler.addHandlerManagerConfigEnvVar(&steps, workflowData) | ||
| require.NotEmpty(t, steps, "should produce config steps") | ||
|
|
||
| var configJSON string | ||
| for _, step := range steps { | ||
| if strings.Contains(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG") { | ||
| parts := strings.Split(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: ") | ||
| require.Len(t, parts, 2, "should split env var line") | ||
| configJSON = strings.TrimSpace(parts[1]) | ||
| configJSON = strings.Trim(configJSON, "\"") | ||
| configJSON = strings.ReplaceAll(configJSON, "\\\"", "\"") | ||
| } | ||
| } |
|
@copilot update the instructions file to explain that if a AW plans to modify any top level markdown files, it should exclude them from protected-files in the front matter |
…n-for-top-level-md-files # Conflicts: # .github/workflows/unbloat-docs.lock.yml Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…n-for-top-level-md-files Agent-Logs-Url: https://github.com/github/gh-aw/sessions/9eeb44f2-7ad3-4967-abdd-c51e5db38114 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done — merged main into this branch (7a84a94). The only conflict was in 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:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot do not add new field protect_top_level_md_files , there is already protected_files |
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/750f8352-88e0-4425-9b17-eca2f2efb871 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 4eac289. Updated
|
|
@copilot review all existing agentic workflows that may write top-level files such as radiate.me.md and agents.md, and ensure they have proper protected file exclusions configured. |
…urityConfigFiles Agent-Logs-Url: https://github.com/github/gh-aw/sessions/4bd4dfc7-b313-457d-8e52-7db656e54720 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 278cc1c. Removed 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:
If you need me to access, download, or install something from one of these locations, you can either:
|
…ibution workflows Agent-Logs-Url: https://github.com/github/gh-aw/sessions/b6e07ed4-14dd-4921-bf0f-8e5561d2964c Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in 9480c7d. Reviewed all workflows and found two that write to files with now-protected basenames:
Other workflows were already correctly handled:
I didn't find a 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:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot merge main and recompile. |
…n-for-top-level-md-files # Conflicts: # .github/workflows/schema-feature-coverage.lock.yml Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/gh-aw/sessions/10cf0479-4d6e-42ba-ac51-c2a57e048f04 Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Done in c1edcf6. Merged main (one conflict in 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:
If you need me to access, download, or install something from one of these locations, you can either:
|
Agents frequently import top-level
.mdfiles as context. Common root-level Markdown files (README.md,CONTRIBUTING.md,CHANGELOG.md,SECURITY.md,CODE_OF_CONDUCT.md) should therefore be treated as protected files alongside existing agent instruction files likeAGENTS.md,CLAUDE.md, andGEMINI.md.Changes
runtime_definitions.go— addsREADME.md,CONTRIBUTING.md,CHANGELOG.md,SECURITY.md, andCODE_OF_CONDUCT.mdtosecurityConfigFiles, so they appear in the existingprotected_filesarray sent to the runtime handler. No new config flag is introduced; the existingprotected_filesbasename-matching mechanism handles these files, and the standardexcludelist can be used to opt specific files out.compiler_safe_outputs_handlers.go— no new flags; the new files are picked up automatically viagetAllManifestFiles().safe-outputs-pull-requests.md— documents the newly protected files in the "What Is Protected" section and adds a tip explaining that workflows explicitly designed to modify a root-level Markdown file (e.g.CHANGELOG.md) should add it to theexcludelist in their frontmatter.spec-extractor.md— addsprotected-files: exclude: [README.md]since this workflow writespkg/*/README.mdspecification files. Becauseprotected_filesuses basename-only matching,README.mdat any path depth would otherwise be blocked.daily-community-attribution.md— addsprotected-files: exclude: [README.md]since this workflow explicitly updates the root-levelREADME.mdCommunity Contributions section.Tests —
TestProtectTopLevelMdFilesGo test verifies thatREADME.md,CONTRIBUTING.md,CHANGELOG.md,SECURITY.md, andCODE_OF_CONDUCT.mdare present inprotected_filesfor both handler configs; JScheckFileProtectiontests updated to useprotected_filesdirectly;TestProtectTopLevelDotFoldersandTestProtectTopLevelMdFilesshare anextractHandlerManagerConfigJSONhelper to eliminate duplication.