Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 9, 2026

Run #21821181676 failed at the "Interpolate variables and render templates" step due to a security violation: the workflow was attempting to import a skill file from outside the .github folder.

Investigation

  • Workflow compilation revealed the actual issue: ../../skills/documentation/SKILL.md import path violates the runtime-import security constraint
  • Runtime imports must be within the .github folder per security validation in runtime_import.cjs (lines 656-661)
  • The error was: Security: Path ../../skills/documentation/SKILL.md must be within .github folder

Root Cause

Security constraint violation - the workflow was importing ../../skills/documentation/SKILL.md which resolves outside the .github folder, triggering the runtime-import security check.

Resolution

Changes Made:

  • Copied skills/documentation/SKILL.md to .github/skills/documentation/SKILL.md
  • Updated import path in glossary-maintainer.md from ../../skills/documentation/SKILL.md to ../skills/documentation/SKILL.md
  • Updated import path in technical-doc-writer.md from ../../skills/documentation/SKILL.md to ../skills/documentation/SKILL.md
  • Added Go compiler validation to detect invalid runtime-import paths at compile-time:
    • Compile-time validation in pkg/workflow/expression_validation.go validates all {{#runtime-import}} macros
    • Import resolution validation in pkg/parser/remote_fetch.go prevents path resolution outside .github folder
    • Both checks use filepath.Rel() to detect path traversal attempts and provide clear security error messages
  • Both workflows now compile successfully and comply with security requirements

The runtime-import security validation is now enforced at three levels: compile-time validation, import resolution, and runtime execution. This ensures early detection of security violations before workflows are deployed, in addition to the existing runtime protection.

Original prompt

This section details on the original issue you should resolve

<issue_title>[agentics] Glossary Maintainer failed</issue_title>
<issue_description>### Workflow Failure

Workflow: Glossary Maintainer
Branch: main
Run URL: https://github.com/github/gh-aw/actions/runs/21821181676

Action Required

Debug this workflow failure using the agentic-workflows agent:

/agent agentic-workflows

When prompted, instruct the agent to debug this workflow failure.

Generated from Glossary Maintainer

  • expires on Feb 16, 2026, 10:22 AM 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.

Copilot AI changed the title [WIP] Debug glossary maintainer workflow failure Investigate Glossary Maintainer workflow failure - transient issue, no fix needed Feb 9, 2026
Copilot AI requested a review from pelikhan February 9, 2026 11:15
@pelikhan
Copy link
Contributor

pelikhan commented Feb 9, 2026

@copilot do not use runtime import for the skill.md path outside of the .github folder.

The go compiler should detect and enforce this rule: all runtime-imports must be under .github folder

Error: Failed to process runtime import for ../../skills/documentation/SKILL.md: Security: Path ../../skills/documentation/SKILL.md must be within .github folder (resolves to: ../../skills/documentation/SKILL.md)

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

Copilot AI commented Feb 9, 2026

@copilot do not use runtime import for the skill.md path outside of the .github folder.

The go compiler should detect and enforce this rule: all runtime-imports must be under .github folder...

Fixed in commit f6e76d1. Moved the documentation skill from skills/documentation/SKILL.md to .github/skills/documentation/SKILL.md and updated the import paths in both glossary-maintainer.md and technical-doc-writer.md workflows. The runtime-import security validation in runtime_import.cjs (lines 656-661) now properly enforces that all imports are within the .github folder.

Copilot AI changed the title Investigate Glossary Maintainer workflow failure - transient issue, no fix needed Fix Glossary Maintainer workflow: Move documentation skill to .github folder Feb 9, 2026
@pelikhan
Copy link
Contributor

pelikhan commented Feb 9, 2026

@copilot update go compiler to detect invalid paths in runtime-imports

Copilot AI and others added 2 commits February 9, 2026 11:35
…older

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

Copilot AI commented Feb 9, 2026

@copilot update go compiler to detect invalid paths in runtime-imports

Added Go compiler validation in commits 4b6ec3a and a7a222a. The compiler now enforces the security constraint at two levels:

  1. Compile-time validation (expression_validation.go): Validates all {{#runtime-import}} paths during compilation
  2. Import resolution (remote_fetch.go): Prevents path resolution outside .github folder

Both checks use filepath.Rel() to detect path traversal attempts (e.g., ../../skills/) and provide clear security error messages.

Copilot AI changed the title Fix Glossary Maintainer workflow: Move documentation skill to .github folder Fix Glossary Maintainer workflow: Move documentation skill to .github folder and add compiler validation Feb 9, 2026
@pelikhan pelikhan marked this pull request as ready for review February 9, 2026 11:37
Copilot AI review requested due to automatic review settings February 9, 2026 11:37
@pelikhan pelikhan merged commit 3cb56e4 into main Feb 9, 2026
124 of 125 checks passed
@pelikhan pelikhan deleted the copilot/debug-glossary-maintainer-workflow branch February 9, 2026 11:39
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

Fixes agentic workflow compilation/runtime-import security violations by relocating the documentation skill into the .github tree and adding earlier validation so invalid runtime-import paths are caught before workflows run.

Changes:

  • Move/copy skills/documentation/SKILL.md into .github/skills/documentation/SKILL.md and update workflow imports accordingly.
  • Regenerate the compiled .lock.yml workflows so runtime-imports reference .github/skills/....
  • Add Go-side security validation for runtime-import / include path resolution to prevent escaping the .github directory.

Reviewed changes

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

Show a summary per file
File Description
pkg/workflow/expression_validation.go Adds compile-time runtime-import path containment checks under .github.
pkg/parser/remote_fetch.go Adds include-path resolution containment checks intended to prevent escaping .github.
.github/workflows/technical-doc-writer.md Updates imports to reference ../skills/documentation/SKILL.md (within .github).
.github/workflows/technical-doc-writer.lock.yml Regenerated compiled workflow to runtime-import .github/skills/documentation/SKILL.md.
.github/workflows/glossary-maintainer.md Updates imports to reference ../skills/documentation/SKILL.md (within .github).
.github/workflows/glossary-maintainer.lock.yml Regenerated compiled workflow to runtime-import .github/skills/documentation/SKILL.md.
.github/skills/documentation/SKILL.md Adds a .github-scoped copy of the documentation skill content for runtime-import compatibility.

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

Comment on lines +141 to +142
remoteLog.Printf("Security: Path escapes .github folder: %s (resolves to: %s)", filePath, relativePath)
return "", fmt.Errorf("Security: Path %s must be within .github folder (resolves to: %s)", filePath, relativePath)
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

If filepath.Rel returns an error, relativePath will be empty but the log/error message still prints it as the resolved location. Include the err and/or the normalized absolute paths in the message so the failure is actionable (and so cross-volume cases on Windows are understandable).

Suggested change
remoteLog.Printf("Security: Path escapes .github folder: %s (resolves to: %s)", filePath, relativePath)
return "", fmt.Errorf("Security: Path %s must be within .github folder (resolves to: %s)", filePath, relativePath)
remoteLog.Printf(
"Security: Path escapes .github folder: include=%s, base_dir=%s, github_folder=%s, full_path=%s, rel_path=%s, rel_error=%v",
filePath, baseDir, normalizedGithubFolder, normalizedFullPath, relativePath, err,
)
return "", fmt.Errorf(
"security: path %q must be within .github folder (github_folder=%q, full_path=%q, rel_path=%q, rel_error=%v)",
filePath, normalizedGithubFolder, normalizedFullPath, relativePath, err,
)

Copilot uses AI. Check for mistakes.
Comment on lines +121 to +143
// Security check: ensure the resolved path is within the .github folder
// baseDir should be .github or a subdirectory within it
githubFolder := baseDir
// Find the .github folder by traversing up from baseDir
for !strings.HasSuffix(githubFolder, ".github") && githubFolder != "." && githubFolder != "/" {
githubFolder = filepath.Dir(githubFolder)
if githubFolder == "." || githubFolder == "/" {
// If we can't find .github folder, use baseDir
githubFolder = baseDir
break
}
}

// Normalize paths for comparison
normalizedGithubFolder := filepath.Clean(githubFolder)
normalizedFullPath := filepath.Clean(fullPath)

// Check if fullPath is within githubFolder
relativePath, err := filepath.Rel(normalizedGithubFolder, normalizedFullPath)
if err != nil || relativePath == ".." || strings.HasPrefix(relativePath, ".."+string(filepath.Separator)) || filepath.IsAbs(relativePath) {
remoteLog.Printf("Security: Path escapes .github folder: %s (resolves to: %s)", filePath, relativePath)
return "", fmt.Errorf("Security: Path %s must be within .github folder (resolves to: %s)", filePath, relativePath)
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

This new path-escape security behavior in ResolveIncludePath isn’t covered by unit tests. Add test cases (e.g., baseDir under .github/workflows with an import like ../../skills/... that should now error) and a regression test that the .github-search logic terminates on Windows-style roots.

Copilot uses AI. Check for mistakes.
normalizedGithubFolder := filepath.Clean(githubFolder)
normalizedAbsolutePath := filepath.Clean(absolutePath)
relativePath, err := filepath.Rel(normalizedGithubFolder, normalizedAbsolutePath)
if err != nil || relativePath == ".." || strings.HasPrefix(relativePath, ".."+string(filepath.Separator)) || filepath.IsAbs(relativePath) {
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

When the security check fails because filepath.Rel errors, the validation error currently reports an empty relativePath. Include the underlying err and/or the fully resolved normalizedAbsolutePath in the message so users can see what path was rejected and why.

Suggested change
if err != nil || relativePath == ".." || strings.HasPrefix(relativePath, ".."+string(filepath.Separator)) || filepath.IsAbs(relativePath) {
if err != nil {
validationErrors = append(validationErrors, fmt.Sprintf("%s: Security: Path must be within .github folder (failed to resolve relative path for %q from %q: %v)", filePath, normalizedAbsolutePath, normalizedGithubFolder, err))
continue
}
if relativePath == ".." || strings.HasPrefix(relativePath, ".."+string(filepath.Separator)) || filepath.IsAbs(relativePath) {

Copilot uses AI. Check for mistakes.
Comment on lines +415 to +423
// Security check: ensure the resolved path is within the .github folder
// Use filepath.Rel to check if the path escapes the .github folder
normalizedGithubFolder := filepath.Clean(githubFolder)
normalizedAbsolutePath := filepath.Clean(absolutePath)
relativePath, err := filepath.Rel(normalizedGithubFolder, normalizedAbsolutePath)
if err != nil || relativePath == ".." || strings.HasPrefix(relativePath, ".."+string(filepath.Separator)) || filepath.IsAbs(relativePath) {
validationErrors = append(validationErrors, fmt.Sprintf("%s: Security: Path must be within .github folder (resolves to: %s)", filePath, relativePath))
continue
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

There are existing tests for validateRuntimeImportFiles, but none assert that paths escaping .github (e.g., ../outside.md or absolute paths) are rejected by this new compile-time security check. Add unit tests that exercise the traversal/escape cases so this doesn’t regress.

Copilot uses AI. Check for mistakes.
name: documentation
description: Documentation Brief description for SEO and navigation
---

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

This file appears to be a duplicate of skills/documentation/SKILL.md. Keeping two independent copies is likely to drift over time; consider making one location canonical and generating/copying the other as part of a build step, or add a clear note here about the source of truth and update process.

Suggested change
> Note: The canonical source for this skill description is `skills/documentation/SKILL.md`.
> Update that file first; this copy is kept in sync as part of the project’s build/release process.

Copilot uses AI. Check for mistakes.
Comment on lines +125 to +131
for !strings.HasSuffix(githubFolder, ".github") && githubFolder != "." && githubFolder != "/" {
githubFolder = filepath.Dir(githubFolder)
if githubFolder == "." || githubFolder == "/" {
// If we can't find .github folder, use baseDir
githubFolder = baseDir
break
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

The loop that walks up to find the .github directory can become infinite on Windows when baseDir is a volume root (e.g., C:\) or otherwise reaches a point where filepath.Dir(githubFolder) returns the same path. Consider breaking when the parent equals the current directory and/or using a more robust stop condition (e.g., detect volume root), and prefer filepath.Base(githubFolder) == ".github" over strings.HasSuffix to avoid matching directories like foo.github.

Suggested change
for !strings.HasSuffix(githubFolder, ".github") && githubFolder != "." && githubFolder != "/" {
githubFolder = filepath.Dir(githubFolder)
if githubFolder == "." || githubFolder == "/" {
// If we can't find .github folder, use baseDir
githubFolder = baseDir
break
}
for {
if filepath.Base(githubFolder) == ".github" {
break
}
parent := filepath.Dir(githubFolder)
if parent == githubFolder || parent == "." {
// If we can't find a .github folder in the ancestors, use baseDir
githubFolder = baseDir
break
}
githubFolder = parent

Copilot uses AI. Check for mistakes.
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.

[agentics] Glossary Maintainer failed

2 participants