Skip to content

Commit 783ff28

Browse files
refactor(repos): simplify symlink read disclosure
Keep the lazy blob-identity check and bounded tree fallback while consolidating metadata handling and request-count tests. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21420b11-5dae-49b6-ac77-965faec7f88b
1 parent 9f92437 commit 783ff28

3 files changed

Lines changed: 362 additions & 866 deletions

File tree

pkg/github/repositories.go

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,41 +1073,34 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
10731073
}
10741074
const maxContentSize = 1024 * 1024 // 1MB
10751075

1076-
inspection, respInspect, err := inspectRepositoryFile(ctx, client, owner, repo, ref, path, fileContent)
1076+
read, respInspect, err := inspectRepositoryFile(ctx, client, owner, repo, ref, path, fileContent)
10771077
if err != nil {
10781078
if respInspect != nil {
1079-
return ghErrors.NewGitHubAPIErrorResponse(ctx,
1080-
"failed to inspect repository file",
1081-
respInspect,
1082-
err,
1083-
), nil, nil
1079+
return ghErrors.NewGitHubAPIErrorResponse(ctx, "failed to inspect repository file", respInspect, err), nil, nil
10841080
}
10851081
return utils.NewToolResultError(fmt.Sprintf("failed to inspect repository file: %s", err)), nil, nil
10861082
}
1087-
if inspection.Submodule != nil {
1088-
return attachIFC(utils.NewToolResultText(marshalRepositorySubmoduleMetadata(inspection.Submodule))), nil, nil
1083+
if read.Metadata != nil && read.Metadata.Type == "submodule" {
1084+
return attachIFC(utils.NewToolResultText(marshalRepositoryPathMetadata(read.Metadata, "", successNote))), nil, nil
10891085
}
1090-
if inspection.Symlink != nil &&
1091-
!inspection.ContentAvailable &&
1092-
(inspection.Symlink.Explicit || fileSize < maxContentSize) {
1093-
return attachIFC(utils.NewToolResultText(marshalRepositorySymlinkMetadata(
1094-
inspection.Symlink,
1095-
unavailableSymlinkContents,
1096-
successNote,
1097-
))), nil, nil
1086+
if read.Metadata != nil && fileContent.GetType() == "symlink" && !read.ContentAvailable {
1087+
return attachIFC(utils.NewToolResultText(marshalRepositoryPathMetadata(read.Metadata, "not_returned", successNote))), nil, nil
10981088
}
10991089

1100-
// Empty files are returned as empty text to avoid
1101-
// DetectContentType misclassifying them as binary.
1102-
if fileSize == 0 && inspection.ContentAvailable {
1090+
// Empty files (0 bytes) have no content to decode; return
1091+
// them directly as empty text to avoid errors from
1092+
// GetContent when the API returns null content with a
1093+
// base64 encoding field, and to avoid DetectContentType
1094+
// misclassifying them as binary.
1095+
if fileSize == 0 && read.ContentAvailable {
11031096
result := &mcp.ResourceContents{
11041097
URI: resourceURI,
11051098
Text: "",
11061099
MIMEType: "text/plain",
11071100
}
11081101
message := fmt.Sprintf("successfully downloaded empty file (SHA: %s)%s", fileSHA, successNote)
1109-
if inspection.Symlink != nil {
1110-
message = marshalRepositorySymlinkMetadata(inspection.Symlink, dereferencedContentLabel, successNote)
1102+
if read.Metadata != nil {
1103+
message = marshalRepositoryPathMetadata(read.Metadata, "dereferenced_target", successNote)
11111104
}
11121105
return attachIFC(utils.NewToolResultResource(message, result)), nil, nil
11131106
}
@@ -1123,26 +1116,23 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
11231116
}
11241117
message := fmt.Sprintf("File %s is too large to display (%d bytes). Use the download URL to fetch the content: %s (SHA: %s)%s",
11251118
path, fileSize, fileContent.GetDownloadURL(), fileSHA, successNote)
1126-
if inspection.Symlink != nil {
1127-
targetPath := inspection.Symlink.ResolvedTargetPath
1128-
if targetPath == "" {
1129-
targetPath = inspection.Symlink.Target
1130-
}
1131-
resourceLink.Title = fmt.Sprintf("Dereferenced target %s via symlink %s", targetPath, path)
1132-
message = marshalRepositorySymlinkMetadata(inspection.Symlink, dereferencedContentLabel, successNote)
1119+
if read.Metadata != nil {
1120+
message = marshalRepositoryPathMetadata(read.Metadata, "dereferenced_target", successNote)
1121+
resourceLink.Title = fmt.Sprintf("Dereferenced target %s via symlink %s", read.Metadata.ResolvedTargetPath, path)
11331122
}
11341123
return attachIFC(utils.NewToolResultResourceLink(
11351124
message,
11361125
resourceLink)), nil, nil
11371126
}
1138-
if !inspection.ContentAvailable {
1139-
return utils.NewToolResultError(fmt.Sprintf("failed to inspect repository file: Contents API did not provide content for path %q", path)), nil, nil
1127+
1128+
if !read.ContentAvailable {
1129+
return utils.NewToolResultError("failed to inspect repository file: content unavailable"), nil, nil
11401130
}
11411131

11421132
// Detect content type from the actual content bytes,
11431133
// mirroring the original approach of using the Content-Type header
11441134
// from the raw API response.
1145-
contentBytes := inspection.Content
1135+
contentBytes := read.Content
11461136
contentType := http.DetectContentType(contentBytes)
11471137

11481138
// Determine if content is text or binary based on detected content type
@@ -1159,8 +1149,8 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
11591149
MIMEType: contentType,
11601150
}
11611151
message := fmt.Sprintf("successfully downloaded text file (SHA: %s)%s", fileSHA, successNote)
1162-
if inspection.Symlink != nil {
1163-
message = marshalRepositorySymlinkMetadata(inspection.Symlink, dereferencedContentLabel, successNote)
1152+
if read.Metadata != nil {
1153+
message = marshalRepositoryPathMetadata(read.Metadata, "dereferenced_target", successNote)
11641154
}
11651155
return attachIFC(utils.NewToolResultResource(message, result)), nil, nil
11661156
}
@@ -1171,8 +1161,8 @@ func GetFileContents(t translations.TranslationHelperFunc) inventory.ServerTool
11711161
MIMEType: contentType,
11721162
}
11731163
message := fmt.Sprintf("successfully downloaded binary file (SHA: %s)%s", fileSHA, successNote)
1174-
if inspection.Symlink != nil {
1175-
message = marshalRepositorySymlinkMetadata(inspection.Symlink, dereferencedContentLabel, successNote)
1164+
if read.Metadata != nil {
1165+
message = marshalRepositoryPathMetadata(read.Metadata, "dereferenced_target", successNote)
11761166
}
11771167
return attachIFC(utils.NewToolResultResource(message, result)), nil, nil
11781168
} else if dirContent != nil {

0 commit comments

Comments
 (0)