codeql/cpp-queries:codeql-suites/cpp-code
This command downloads the `codeql/cpp-queries` {% data variables.product.prodname_codeql %} query pack, runs the analysis, and generates a file in the SARIF version 2.1.0 format that is supported by all versions of {% data variables.product.prodname_dotcom %}. This file can be uploaded to {% data variables.product.prodname_dotcom %} by executing `codeql github upload-results` or the code scanning API.
For more information, see [AUTOTITLE](/code-security/codeql-cli/getting-started-with-the-codeql-cli/uploading-codeql-analysis-results-to-github)
-or [AUTOTITLE](/rest/code-scanning).
+or [AUTOTITLE](/rest/code-scanning/code-scanning).
{% data variables.product.prodname_codeql %} query suites are `.qls` files that use directives to select queries to run
based on certain metadata properties. The standard {% data variables.product.prodname_codeql %} packs have metadata that specify
diff --git a/data/reusables/code-scanning/choose-alert-dismissal-reason.md b/data/reusables/code-scanning/choose-alert-dismissal-reason.md
index b09bebf5b144..36ddfc3964eb 100644
--- a/data/reusables/code-scanning/choose-alert-dismissal-reason.md
+++ b/data/reusables/code-scanning/choose-alert-dismissal-reason.md
@@ -1 +1 @@
-It's important to choose the appropriate reason from the drop-down menu as this may affect whether a query continues to be included in future analysis. Optionally, you can comment on a dismissal to record the context of an alert dismissal. The dismissal comment is added to the alert timeline and can be used as justification during auditing and reporting. You can retrieve or set a comment by using the code scanning REST API. The comment is contained in `dismissed_comment` for the `alerts/{alert_number}` endpoint. For more information, see [AUTOTITLE](/rest/code-scanning#update-a-code-scanning-alert).
+It's important to choose the appropriate reason from the drop-down menu as this may affect whether a query continues to be included in future analysis. Optionally, you can comment on a dismissal to record the context of an alert dismissal. The dismissal comment is added to the alert timeline and can be used as justification during auditing and reporting. You can retrieve or set a comment by using the code scanning REST API. The comment is contained in `dismissed_comment` for the `alerts/{alert_number}` endpoint. For more information, see [AUTOTITLE](/rest/code-scanning/code-scanning#update-a-code-scanning-alert).
diff --git a/src/graphql/data/fpt/changelog.json b/src/graphql/data/fpt/changelog.json
index e499d9623b49..cc48673762b5 100644
--- a/src/graphql/data/fpt/changelog.json
+++ b/src/graphql/data/fpt/changelog.json
@@ -1,4 +1,18 @@
[
+ {
+ "schemaChanges": [
+ {
+ "title": "The GraphQL schema includes these changes:",
+ "changes": [
+ "Input field actorLogins of type '[String!]was added to input object typeReplaceActorsForAssignableInput'
",
+ "Input field ReplaceActorsForAssignableInput.actorIds changed type from '[ID!]!to[ID!]'
"
+ ]
+ }
+ ],
+ "previewChanges": [],
+ "upcomingChanges": [],
+ "date": "2026-01-23"
+ },
{
"schemaChanges": [
{
diff --git a/src/graphql/data/fpt/schema.docs.graphql b/src/graphql/data/fpt/schema.docs.graphql
index d1c7d2509627..da6f5937b3f5 100644
--- a/src/graphql/data/fpt/schema.docs.graphql
+++ b/src/graphql/data/fpt/schema.docs.graphql
@@ -46635,14 +46635,22 @@ Autogenerated input type of ReplaceActorsForAssignable
"""
input ReplaceActorsForAssignableInput {
"""
- The ids of the actors to replace the existing assignees.
+ The ids of the actors to replace the existing assignees. May be used as an
+ alternative to or in conjunction with actorLogins.
"""
- actorIds: [ID!]!
+ actorIds: [ID!]
@possibleTypes(
concreteTypes: ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"]
abstractType: "Actor"
)
+ """
+ The usernames of the actors to replace the existing assignees. May be used as
+ an alternative to or in conjunction with actorIds. For bots, use the login
+ format with [bot] suffix (e.g., 'my-app[bot]').
+ """
+ actorLogins: [String!]
+
"""
The id of the assignable object to replace the assignees for.
"""
diff --git a/src/graphql/data/fpt/schema.json b/src/graphql/data/fpt/schema.json
index 089b89cb87e0..255c280fb59a 100644
--- a/src/graphql/data/fpt/schema.json
+++ b/src/graphql/data/fpt/schema.json
@@ -106498,13 +106498,21 @@
"inputFields": [
{
"name": "actorIds",
- "description": "The ids of the actors to replace the existing assignees.
",
- "type": "[ID!]!",
+ "description": "The ids of the actors to replace the existing assignees. May be used as an\nalternative to or in conjunction with actorLogins.
",
+ "type": "[ID!]",
"id": "id",
"kind": "scalars",
"href": "/graphql/reference/scalars#id",
"isDeprecated": false
},
+ {
+ "name": "actorLogins",
+ "description": "The usernames of the actors to replace the existing assignees. May be used as\nan alternative to or in conjunction with actorIds. For bots, use the login\nformat with [bot] suffix (e.g., 'my-app[bot]').
",
+ "type": "[String!]",
+ "id": "string",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#string"
+ },
{
"name": "assignableId",
"description": "The id of the assignable object to replace the assignees for.
",
diff --git a/src/graphql/data/ghec/schema.docs.graphql b/src/graphql/data/ghec/schema.docs.graphql
index d1c7d2509627..da6f5937b3f5 100644
--- a/src/graphql/data/ghec/schema.docs.graphql
+++ b/src/graphql/data/ghec/schema.docs.graphql
@@ -46635,14 +46635,22 @@ Autogenerated input type of ReplaceActorsForAssignable
"""
input ReplaceActorsForAssignableInput {
"""
- The ids of the actors to replace the existing assignees.
+ The ids of the actors to replace the existing assignees. May be used as an
+ alternative to or in conjunction with actorLogins.
"""
- actorIds: [ID!]!
+ actorIds: [ID!]
@possibleTypes(
concreteTypes: ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"]
abstractType: "Actor"
)
+ """
+ The usernames of the actors to replace the existing assignees. May be used as
+ an alternative to or in conjunction with actorIds. For bots, use the login
+ format with [bot] suffix (e.g., 'my-app[bot]').
+ """
+ actorLogins: [String!]
+
"""
The id of the assignable object to replace the assignees for.
"""
diff --git a/src/graphql/data/ghec/schema.json b/src/graphql/data/ghec/schema.json
index 089b89cb87e0..255c280fb59a 100644
--- a/src/graphql/data/ghec/schema.json
+++ b/src/graphql/data/ghec/schema.json
@@ -106498,13 +106498,21 @@
"inputFields": [
{
"name": "actorIds",
- "description": "The ids of the actors to replace the existing assignees.
",
- "type": "[ID!]!",
+ "description": "The ids of the actors to replace the existing assignees. May be used as an\nalternative to or in conjunction with actorLogins.
",
+ "type": "[ID!]",
"id": "id",
"kind": "scalars",
"href": "/graphql/reference/scalars#id",
"isDeprecated": false
},
+ {
+ "name": "actorLogins",
+ "description": "The usernames of the actors to replace the existing assignees. May be used as\nan alternative to or in conjunction with actorIds. For bots, use the login\nformat with [bot] suffix (e.g., 'my-app[bot]').
",
+ "type": "[String!]",
+ "id": "string",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#string"
+ },
{
"name": "assignableId",
"description": "The id of the assignable object to replace the assignees for.
",
diff --git a/src/languages/lib/render-with-fallback.ts b/src/languages/lib/render-with-fallback.ts
index 30c3686e5439..fe9d53bc5ffe 100644
--- a/src/languages/lib/render-with-fallback.ts
+++ b/src/languages/lib/render-with-fallback.ts
@@ -5,14 +5,27 @@ import type { Context } from '@/types'
export class EmptyTitleError extends Error {}
-interface LiquidToken {
+export interface LiquidToken {
file?: string
getPosition?: () => [number, number]
}
-interface LiquidError extends Error {
+/**
+ * Custom error class for Liquid rendering errors with proper type safety.
+ * Use this instead of creating Error objects and mutating them with type assertions.
+ *
+ * @example
+ * const error = new LiquidError('Unknown tag', 'ParseError')
+ * error.token = { file: '/content/test.md', getPosition: () => [1, 5] }
+ */
+export class LiquidError extends Error {
token?: LiquidToken
originalError?: Error
+
+ constructor(message: string, name: 'ParseError' | 'RenderError' | 'TokenizationError') {
+ super(message)
+ this.name = name
+ }
}
interface RenderOptions {
diff --git a/src/languages/scripts/count-translation-corruptions.ts b/src/languages/scripts/count-translation-corruptions.ts
index a46a1bc2ed5f..bc8e89007e18 100644
--- a/src/languages/scripts/count-translation-corruptions.ts
+++ b/src/languages/scripts/count-translation-corruptions.ts
@@ -77,11 +77,19 @@ function run(languageCode: string, site: Site, englishReusables: Reusables) {
const illegalTags = new Map()
function countError(error: TokenizationError, where: string) {
- const originalError = (error as { originalError?: Error }).originalError
+ // TokenizationError from liquidjs may have originalError and token.content
+ // but these aren't in the public type definitions
+ const errorWithExtras = error as TokenizationError & {
+ originalError?: Error
+ token?: { content?: string }
+ }
+ const originalError = errorWithExtras.originalError
const errorString = originalError ? originalError.message : error.message
- if (errorString.includes('illegal tag syntax')) {
- const illegalTag = (error as unknown as { token: { content: string } }).token.content
- illegalTags.set(illegalTag, (illegalTags.get(illegalTag) || 0) + 1)
+ if (errorString.includes('illegal tag syntax') && errorWithExtras.token?.content) {
+ illegalTags.set(
+ errorWithExtras.token.content,
+ (illegalTags.get(errorWithExtras.token.content) || 0) + 1,
+ )
}
errors.set(errorString, (errors.get(errorString) || 0) + 1)
wheres.set(where, (wheres.get(where) || 0) + 1)
diff --git a/src/languages/tests/translation-error-comments.ts b/src/languages/tests/translation-error-comments.ts
index 7052e8023f42..af5986944f66 100644
--- a/src/languages/tests/translation-error-comments.ts
+++ b/src/languages/tests/translation-error-comments.ts
@@ -4,19 +4,11 @@ import {
EmptyTitleError,
renderContentWithFallback,
executeWithFallback,
+ LiquidError,
} from '../lib/render-with-fallback'
import { TitleFromAutotitleError } from '@/content-render/unified/rewrite-local-links'
import Page from '@/frame/lib/page'
-// Type aliases for error objects with token information
-type ErrorWithToken = Error & { token: { file: string; getPosition: () => number[] } }
-type ErrorWithTokenNoFile = Error & { token: { getPosition: () => number[] } }
-type ErrorWithTokenNoPosition = Error & { token: { file: string } }
-type ErrorWithTokenAndOriginal = Error & {
- token: { file: string; getPosition: () => number[] }
- originalError: Error
-}
-
describe('Translation Error Comments', () => {
// Mock renderContent for integration tests
let mockRenderContent: MockedFunction<
@@ -35,9 +27,8 @@ describe('Translation Error Comments', () => {
describe('createTranslationFallbackComment', () => {
describe('Liquid ParseError', () => {
test('includes all fields when token information is available', () => {
- const error = new Error("Unknown tag 'badtag', line:1, col:3")
- error.name = 'ParseError'
- ;(error as unknown as ErrorWithToken).token = {
+ const error = new LiquidError("Unknown tag 'badtag', line:1, col:3", 'ParseError')
+ error.token = {
file: '/content/test/article.md',
getPosition: () => [1, 3],
}
@@ -57,15 +48,15 @@ describe('Translation Error Comments', () => {
describe('Liquid RenderError', () => {
test('includes original error message when available', () => {
- const error = new Error("Unknown variable 'variables.nonexistent.value'")
- error.name = 'RenderError'
- ;(error as unknown as ErrorWithToken).token = {
+ const error = new LiquidError(
+ "Unknown variable 'variables.nonexistent.value'",
+ 'RenderError',
+ )
+ error.token = {
file: '/content/test/intro.md',
getPosition: () => [3, 15],
}
- ;(error as unknown as ErrorWithTokenAndOriginal).originalError = new Error(
- 'Variable not found: variables.nonexistent.value',
- )
+ error.originalError = new Error('Variable not found: variables.nonexistent.value')
const result = createTranslationFallbackComment(error, 'rawIntro')
@@ -78,9 +69,8 @@ describe('Translation Error Comments', () => {
})
test('falls back to main error message when no originalError', () => {
- const error = new Error('Main error message')
- error.name = 'RenderError'
- ;(error as unknown as ErrorWithToken).token = {
+ const error = new LiquidError('Main error message', 'RenderError')
+ error.token = {
file: '/content/test.md',
getPosition: () => [1, 1],
}
@@ -93,9 +83,8 @@ describe('Translation Error Comments', () => {
describe('Liquid TokenizationError', () => {
test('includes tokenization error details', () => {
- const error = new Error('Unexpected token, line:1, col:10')
- error.name = 'TokenizationError'
- ;(error as unknown as ErrorWithToken).token = {
+ const error = new LiquidError('Unexpected token, line:1, col:10', 'TokenizationError')
+ error.token = {
file: '/content/test/page.md',
getPosition: () => [1, 10],
}
@@ -147,9 +136,8 @@ describe('Translation Error Comments', () => {
describe('Error handling edge cases', () => {
test('handles error with no token information gracefully', () => {
- const error = new Error('Generic liquid error without token info')
- error.name = 'RenderError'
- // No token property
+ const error = new LiquidError('Generic liquid error without token info', 'RenderError')
+ // No token property set
const result = createTranslationFallbackComment(error, 'rawIntro')
@@ -163,9 +151,8 @@ describe('Translation Error Comments', () => {
})
test('handles error with token but no file', () => {
- const error = new Error('Error message')
- error.name = 'ParseError'
- ;(error as unknown as ErrorWithTokenNoFile).token = {
+ const error = new LiquidError('Error message', 'ParseError')
+ error.token = {
// No file property
getPosition: () => [5, 10],
}
@@ -178,9 +165,8 @@ describe('Translation Error Comments', () => {
})
test('handles error with token but no getPosition method', () => {
- const error = new Error('Error message')
- error.name = 'ParseError'
- ;(error as unknown as ErrorWithTokenNoPosition).token = {
+ const error = new LiquidError('Error message', 'ParseError')
+ error.token = {
file: '/content/test.md',
// No getPosition method
}
@@ -194,8 +180,7 @@ describe('Translation Error Comments', () => {
test('truncates very long error messages', () => {
const longMessage = 'A'.repeat(300) // Very long error message
- const error = new Error(longMessage)
- error.name = 'ParseError'
+ const error = new LiquidError(longMessage, 'ParseError')
const result = createTranslationFallbackComment(error, 'rawTitle')
@@ -211,8 +196,7 @@ describe('Translation Error Comments', () => {
})
test('properly escapes quotes in error messages', () => {
- const error = new Error('Error with "double quotes" and more')
- error.name = 'RenderError'
+ const error = new LiquidError('Error with "double quotes" and more', 'RenderError')
const result = createTranslationFallbackComment(error, 'rawTitle')
@@ -233,9 +217,7 @@ describe('Translation Error Comments', () => {
})
test('handles error with no message', () => {
- const error = new Error()
- error.name = 'ParseError'
- // Message will be empty string by default
+ const error = new LiquidError('', 'ParseError')
const result = createTranslationFallbackComment(error, 'title')
@@ -245,8 +227,7 @@ describe('Translation Error Comments', () => {
})
test('cleans up multiline messages', () => {
- const error = new Error('Line 1\nLine 2\n Line 3 \n\nLine 5')
- error.name = 'RenderError'
+ const error = new LiquidError('Line 1\nLine 2\n Line 3 \n\nLine 5', 'RenderError')
const result = createTranslationFallbackComment(error, 'content')
@@ -257,9 +238,8 @@ describe('Translation Error Comments', () => {
describe('Comment format validation', () => {
test('comment format is valid HTML', () => {
- const error = new Error('Test error')
- error.name = 'ParseError'
- ;(error as unknown as ErrorWithToken).token = {
+ const error = new LiquidError('Test error', 'ParseError')
+ error.token = {
file: '/content/test.md',
getPosition: () => [1, 1],
}
@@ -275,9 +255,8 @@ describe('Translation Error Comments', () => {
})
test('contains all required fields when available', () => {
- const error = new Error('Detailed error message')
- error.name = 'RenderError'
- ;(error as unknown as ErrorWithToken).token = {
+ const error = new LiquidError('Detailed error message', 'RenderError')
+ error.token = {
file: '/content/detailed-test.md',
getPosition: () => [42, 15],
}
@@ -294,9 +273,8 @@ describe('Translation Error Comments', () => {
})
test('maintains consistent field order', () => {
- const error = new Error('Test message')
- error.name = 'ParseError'
- ;(error as unknown as ErrorWithToken).token = {
+ const error = new LiquidError('Test message', 'ParseError')
+ error.token = {
file: '/content/test.md',
getPosition: () => [1, 1],
}
@@ -336,9 +314,8 @@ describe('Translation Error Comments', () => {
mockRenderContent.mockImplementation(
(template: string, innerContext: Record) => {
if (innerContext.currentLanguage !== 'en' && template.includes('badtag')) {
- const error = new Error("Unknown tag 'badtag'")
- error.name = 'ParseError'
- ;(error as unknown as ErrorWithToken).token = {
+ const error = new LiquidError("Unknown tag 'badtag'", 'ParseError')
+ error.token = {
file: '/content/test.md',
getPosition: () => [1, 5],
}
@@ -375,8 +352,7 @@ describe('Translation Error Comments', () => {
mockRenderContent.mockImplementation(
(template: string, innerContext: Record) => {
if (innerContext.currentLanguage !== 'en' && template.includes('badtag')) {
- const error = new Error("Unknown tag 'badtag'")
- error.name = 'ParseError'
+ const error = new LiquidError("Unknown tag 'badtag'", 'ParseError')
throw error
}
return 'English Title'
@@ -399,9 +375,8 @@ describe('Translation Error Comments', () => {
}
const failingCallable = async () => {
- const error = new Error("Unknown variable 'variables.bad'")
- error.name = 'RenderError'
- ;(error as unknown as ErrorWithToken).token = {
+ const error = new LiquidError("Unknown variable 'variables.bad'", 'RenderError')
+ error.token = {
file: '/content/article.md',
getPosition: () => [10, 20],
}
@@ -427,8 +402,7 @@ describe('Translation Error Comments', () => {
}
const failingCallable = async () => {
- const error = new Error('Test error')
- error.name = 'RenderError'
+ const error = new LiquidError('Test error', 'RenderError')
throw error
}