From c1e640f4cc5c1cf1c87c996104ea2704e9ab1aad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 25 Jun 2026 01:42:16 +0000 Subject: [PATCH] fix: extract GraphQL query to named constant (CWE-89, alert #626) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the hardcoded GraphQL query string in checkRepositoryHasDiscussionsUncached into a package-level named constant checkRepositoryHasDiscussionsQuery. This addresses code scanning alert #626 (workflow-graphql-static-concat / CWE-89): static analysis flagged the string concatenation pattern 'query='+query even though the query variable held a hardcoded literal. Using a named constant makes it unambiguous to static analysis tools that the value is not user-controlled input. No runtime behavior changes — the same query string is passed to gh api graphql. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../repository_features_validation.go | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/pkg/workflow/repository_features_validation.go b/pkg/workflow/repository_features_validation.go index e8b2f4e6c15..4ee7403b27c 100644 --- a/pkg/workflow/repository_features_validation.go +++ b/pkg/workflow/repository_features_validation.go @@ -54,6 +54,15 @@ import ( var repositoryFeaturesLog = newValidationLogger("repository_features") +// checkRepositoryHasDiscussionsQuery is a hardcoded static GraphQL query template used to check +// if discussions are enabled for a repository. Declared as a named constant to make clear +// it is not user-controlled input (CWE-89 / workflow-graphql-static-concat). +const checkRepositoryHasDiscussionsQuery = `query($owner: String!, $name: String!) { + repository(owner: $owner, name: $name) { + hasDiscussionsEnabled + } +}` + // RepositoryFeatures holds cached information about repository capabilities type RepositoryFeatures struct { HasDiscussions bool @@ -252,14 +261,6 @@ func checkRepositoryHasDiscussions(repo string, verbose bool) (bool, error) { // checkRepositoryHasDiscussionsUncached checks if a repository has discussions enabled (no caching) func checkRepositoryHasDiscussionsUncached(repo string) (bool, error) { - // Use GitHub GraphQL API to check if discussions are enabled - // The hasDiscussionsEnabled field is the canonical way to check this - query := `query($owner: String!, $name: String!) { - repository(owner: $owner, name: $name) { - hasDiscussionsEnabled - } - }` - // Split repo into owner and name parts := strings.SplitN(repo, "/", 2) if len(parts) != 2 || parts[0] == "" || parts[1] == "" { @@ -267,7 +268,8 @@ func checkRepositoryHasDiscussionsUncached(repo string) (bool, error) { } owner, name := parts[0], parts[1] - // Execute GraphQL query using gh CLI + // Execute GraphQL query using gh CLI. + // checkRepositoryHasDiscussionsQuery is a package-level constant — not user-controlled. type GraphQLResponse struct { Data struct { Repository struct { @@ -276,7 +278,7 @@ func checkRepositoryHasDiscussionsUncached(repo string) (bool, error) { } `json:"data"` } - stdOut, _, err := gh.Exec("api", "graphql", "-f", "query="+query, + stdOut, _, err := gh.Exec("api", "graphql", "-f", "query="+checkRepositoryHasDiscussionsQuery, "-f", "owner="+owner, "-f", "name="+name) if err != nil { return false, fmt.Errorf("failed to query discussions status: %w", err)