).raw as string
if (!patterns.hasLiquid.test(markdown)) continue
try {
await liquid.parse(markdown)
diff --git a/src/frame/tests/site-tree.ts b/src/frame/tests/site-tree.ts
index a19b17a8d3c1..5637b026789f 100644
--- a/src/frame/tests/site-tree.ts
+++ b/src/frame/tests/site-tree.ts
@@ -7,6 +7,7 @@ import { loadSiteTree } from '@/frame/lib/page-data'
import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-version'
import { formatAjvErrors } from '@/tests/helpers/schemas'
import type { SiteTree, Tree } from '@/types'
+import findPageInSiteTree from '@/frame/lib/find-page-in-site-tree'
const latestEnterpriseRelease = EnterpriseServerReleases.latest
@@ -37,15 +38,14 @@ describe('siteTree', () => {
const ghesSiteTree = siteTree.en[ghesLatest]
// Find a page in the tree that we know contains Liquid
- // TODO: use new findPageInSiteTree helper when it's available
- const pageWithDynamicTitle = ghesSiteTree.childPages
- .find((child) => child.href === `/en/${ghesLatest}/admin`)
- ?.childPages.find(
- (child) => child.href === `/en/${ghesLatest}/admin/installing-your-enterprise-server`,
- )
+ const pageWithDynamicTitle = findPageInSiteTree(
+ ghesSiteTree,
+ siteTree.en[nonEnterpriseDefaultVersion],
+ `/en/${ghesLatest}/admin/installing-your-enterprise-server`,
+ )
// Confirm the raw title contains Liquid
- expect(pageWithDynamicTitle?.page.title).toEqual(
+ expect(pageWithDynamicTitle.page.title).toEqual(
'Installing {% data variables.product.prodname_enterprise %}',
)
})
diff --git a/src/graphql/data/fpt/changelog.json b/src/graphql/data/fpt/changelog.json
index 0ae892d0365e..5735597dbfef 100644
--- a/src/graphql/data/fpt/changelog.json
+++ b/src/graphql/data/fpt/changelog.json
@@ -1,4 +1,26 @@
[
+ {
+ "schemaChanges": [
+ {
+ "title": "The GraphQL schema includes these changes:",
+ "changes": [
+ "Type SuggestedReviewerActor was added
",
+ "Type SuggestedReviewerActorConnection was added
",
+ "Type SuggestedReviewerActorEdge was added
",
+ "Enum value 'ISSUE_FIELD_ADDED_EVENTwas added to enumIssueTimelineItemsItemType'
",
+ "Enum value 'ISSUE_FIELD_CHANGED_EVENTwas added to enumIssueTimelineItemsItemType'
",
+ "Enum value 'ISSUE_FIELD_REMOVED_EVENTwas added to enumIssueTimelineItemsItemType'
",
+ "Field suggestedReviewerActors was added to object type PullRequest
",
+ "Enum value 'ISSUE_FIELD_ADDED_EVENTwas added to enumPullRequestTimelineItemsItemType'
",
+ "Enum value 'ISSUE_FIELD_CHANGED_EVENTwas added to enumPullRequestTimelineItemsItemType'
",
+ "Enum value 'ISSUE_FIELD_REMOVED_EVENTwas added to enumPullRequestTimelineItemsItemType'
"
+ ]
+ }
+ ],
+ "previewChanges": [],
+ "upcomingChanges": [],
+ "date": "2025-11-30"
+ },
{
"schemaChanges": [
{
diff --git a/src/graphql/data/fpt/schema.docs.graphql b/src/graphql/data/fpt/schema.docs.graphql
index 9a9a6d015156..a052abfcbb8a 100644
--- a/src/graphql/data/fpt/schema.docs.graphql
+++ b/src/graphql/data/fpt/schema.docs.graphql
@@ -7335,7 +7335,9 @@ type ConvertedToDiscussionEvent implements Node {
}
"""
-Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+Request Copilot code review for new pull requests automatically if the author
+has access to Copilot code review and their premium requests quota has not
+reached the limit.
"""
type CopilotCodeReviewParameters {
"""
@@ -7350,7 +7352,9 @@ type CopilotCodeReviewParameters {
}
"""
-Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+Request Copilot code review for new pull requests automatically if the author
+has access to Copilot code review and their premium requests quota has not
+reached the limit.
"""
input CopilotCodeReviewParametersInput {
"""
@@ -20648,6 +20652,21 @@ enum IssueTimelineItemsItemType {
"""
ISSUE_COMMENT
+ """
+ Represents a 'issue_field_added' event on a given issue.
+ """
+ ISSUE_FIELD_ADDED_EVENT
+
+ """
+ Represents a 'issue_field_changed' event on a given issue.
+ """
+ ISSUE_FIELD_CHANGED_EVENT
+
+ """
+ Represents a 'issue_field_removed' event on a given issue.
+ """
+ ISSUE_FIELD_REMOVED_EVENT
+
"""
Represents a 'issue_type_added' event on a given issue.
"""
@@ -41291,6 +41310,31 @@ type PullRequest implements Assignable & Closable & Comment & Labelable & Lockab
query: String
): AssigneeConnection!
+ """
+ Reviewer actor suggestions based on commit history, past review comments, and integrations.
+ """
+ suggestedReviewerActors(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): SuggestedReviewerActorConnection!
+
"""
A list of reviewer suggestions based on commit history and past review comments.
"""
@@ -41905,7 +41949,9 @@ type PullRequestParameters {
allowedMergeMethods: [PullRequestAllowedMergeMethods!]
"""
- Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+ Request Copilot code review for new pull requests automatically if the author
+ has access to Copilot code review and their premium requests quota has not
+ reached the limit.
"""
automaticCopilotCodeReviewEnabled: Boolean!
@@ -41953,7 +41999,9 @@ input PullRequestParametersInput {
allowedMergeMethods: [PullRequestAllowedMergeMethods!]
"""
- Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+ Request Copilot code review for new pull requests automatically if the author
+ has access to Copilot code review and their premium requests quota has not
+ reached the limit.
"""
automaticCopilotCodeReviewEnabled: Boolean
@@ -43519,6 +43567,21 @@ enum PullRequestTimelineItemsItemType {
"""
ISSUE_COMMENT
+ """
+ Represents a 'issue_field_added' event on a given issue.
+ """
+ ISSUE_FIELD_ADDED_EVENT
+
+ """
+ Represents a 'issue_field_changed' event on a given issue.
+ """
+ ISSUE_FIELD_CHANGED_EVENT
+
+ """
+ Represents a 'issue_field_removed' event on a given issue.
+ """
+ ISSUE_FIELD_REMOVED_EVENT
+
"""
Represents a 'issue_type_added' event on a given issue.
"""
@@ -45719,9 +45782,13 @@ input RemoveAssigneesFromAssignableInput {
assignableId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "Assignable")
"""
- The id of users to remove as assignees.
+ The ids of actors to remove as assignees.
"""
- assigneeIds: [ID!]! @possibleTypes(concreteTypes: ["User"])
+ assigneeIds: [ID!]!
+ @possibleTypes(
+ concreteTypes: ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"]
+ abstractType: "Actor"
+ )
"""
A unique identifier for the client performing the mutation.
@@ -53261,7 +53328,9 @@ enum RepositoryRuleType {
COMMIT_MESSAGE_PATTERN
"""
- Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+ Request Copilot code review for new pull requests automatically if the author
+ has access to Copilot code review and their premium requests quota has not
+ reached the limit.
"""
COPILOT_CODE_REVIEW
@@ -60390,6 +60459,66 @@ type SuggestedReviewer {
reviewer: User!
}
+"""
+A suggestion to review a pull request based on an actor's commit history, review comments, and integrations.
+"""
+type SuggestedReviewerActor {
+ """
+ Is this suggestion based on past commits?
+ """
+ isAuthor: Boolean!
+
+ """
+ Is this suggestion based on past review comments?
+ """
+ isCommenter: Boolean!
+
+ """
+ Identifies the actor suggested to review the pull request.
+ """
+ reviewer: Actor!
+}
+
+"""
+A suggestion to review a pull request based on an actor's commit history, review comments, and integrations.
+"""
+type SuggestedReviewerActorConnection {
+ """
+ A list of edges.
+ """
+ edges: [SuggestedReviewerActorEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [SuggestedReviewerActor]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+
+ """
+ Identifies the total count of items in the connection.
+ """
+ totalCount: Int!
+}
+
+"""
+An edge in a connection.
+"""
+type SuggestedReviewerActorEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: SuggestedReviewerActor
+}
+
"""
Represents a Git tag.
"""
@@ -65626,9 +65755,13 @@ Autogenerated input type of UpdateIssue
"""
input UpdateIssueInput {
"""
- An array of Node IDs of users for this issue.
+ An array of Node IDs of users or bots for this issue.
"""
- assigneeIds: [ID!] @possibleTypes(concreteTypes: ["User"])
+ assigneeIds: [ID!]
+ @possibleTypes(
+ concreteTypes: ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"]
+ abstractType: "Actor"
+ )
"""
The body for the issue description.
diff --git a/src/graphql/data/fpt/schema.json b/src/graphql/data/fpt/schema.json
index 534ae6d97d30..4766206c9fcc 100644
--- a/src/graphql/data/fpt/schema.json
+++ b/src/graphql/data/fpt/schema.json
@@ -17559,7 +17559,7 @@
"kind": "objects",
"id": "copilotcodereviewparameters",
"href": "/graphql/reference/objects#copilotcodereviewparameters",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
",
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
",
"fields": [
{
"name": "reviewDraftPullRequests",
@@ -55187,6 +55187,56 @@
}
]
},
+ {
+ "name": "suggestedReviewerActors",
+ "description": "Reviewer actor suggestions based on commit history, past review comments, and integrations.
",
+ "type": "SuggestedReviewerActorConnection!",
+ "id": "suggestedrevieweractorconnection",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#suggestedrevieweractorconnection",
+ "arguments": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.
",
+ "type": {
+ "name": "String",
+ "id": "string",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#string"
+ }
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.
",
+ "type": {
+ "name": "String",
+ "id": "string",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#string"
+ }
+ },
+ {
+ "name": "first",
+ "description": "Returns the first n elements from the list.
",
+ "type": {
+ "name": "Int",
+ "id": "int",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#int"
+ }
+ },
+ {
+ "name": "last",
+ "description": "Returns the last n elements from the list.
",
+ "type": {
+ "name": "Int",
+ "id": "int",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#int"
+ }
+ }
+ ]
+ },
{
"name": "suggestedReviewers",
"description": "A list of reviewer suggestions based on commit history and past review comments.
",
@@ -56134,7 +56184,7 @@
},
{
"name": "automaticCopilotCodeReviewEnabled",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
",
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
",
"type": "Boolean!",
"id": "boolean",
"kind": "scalars",
@@ -75054,6 +75104,105 @@
}
]
},
+ {
+ "name": "SuggestedReviewerActor",
+ "kind": "objects",
+ "id": "suggestedrevieweractor",
+ "href": "/graphql/reference/objects#suggestedrevieweractor",
+ "description": "A suggestion to review a pull request based on an actor's commit history, review comments, and integrations.
",
+ "fields": [
+ {
+ "name": "isAuthor",
+ "description": "Is this suggestion based on past commits?.
",
+ "type": "Boolean!",
+ "id": "boolean",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#boolean"
+ },
+ {
+ "name": "isCommenter",
+ "description": "Is this suggestion based on past review comments?.
",
+ "type": "Boolean!",
+ "id": "boolean",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#boolean"
+ },
+ {
+ "name": "reviewer",
+ "description": "Identifies the actor suggested to review the pull request.
",
+ "type": "Actor!",
+ "id": "actor",
+ "kind": "interfaces",
+ "href": "/graphql/reference/interfaces#actor"
+ }
+ ]
+ },
+ {
+ "name": "SuggestedReviewerActorConnection",
+ "kind": "objects",
+ "id": "suggestedrevieweractorconnection",
+ "href": "/graphql/reference/objects#suggestedrevieweractorconnection",
+ "description": "A suggestion to review a pull request based on an actor's commit history, review comments, and integrations.
",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.
",
+ "type": "[SuggestedReviewerActorEdge]",
+ "id": "suggestedrevieweractoredge",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#suggestedrevieweractoredge"
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.
",
+ "type": "[SuggestedReviewerActor]",
+ "id": "suggestedrevieweractor",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#suggestedrevieweractor"
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.
",
+ "type": "PageInfo!",
+ "id": "pageinfo",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#pageinfo"
+ },
+ {
+ "name": "totalCount",
+ "description": "Identifies the total count of items in the connection.
",
+ "type": "Int!",
+ "id": "int",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#int"
+ }
+ ]
+ },
+ {
+ "name": "SuggestedReviewerActorEdge",
+ "kind": "objects",
+ "id": "suggestedrevieweractoredge",
+ "href": "/graphql/reference/objects#suggestedrevieweractoredge",
+ "description": "An edge in a connection.
",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.
",
+ "type": "String!",
+ "id": "string",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#string"
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.
",
+ "type": "SuggestedReviewerActor",
+ "id": "suggestedrevieweractor",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#suggestedrevieweractor"
+ }
+ ]
+ },
{
"name": "Tag",
"kind": "objects",
@@ -90453,6 +90602,18 @@
"name": "ISSUE_COMMENT",
"description": "Represents a comment on an Issue.
"
},
+ {
+ "name": "ISSUE_FIELD_ADDED_EVENT",
+ "description": "Represents aissue_field_addedevent on a given issue.
"
+ },
+ {
+ "name": "ISSUE_FIELD_CHANGED_EVENT",
+ "description": "Represents aissue_field_changedevent on a given issue.
"
+ },
+ {
+ "name": "ISSUE_FIELD_REMOVED_EVENT",
+ "description": "Represents aissue_field_removedevent on a given issue.
"
+ },
{
"name": "ISSUE_TYPE_ADDED_EVENT",
"description": "Represents aissue_type_addedevent on a given issue.
"
@@ -92636,6 +92797,18 @@
"name": "ISSUE_COMMENT",
"description": "Represents a comment on an Issue.
"
},
+ {
+ "name": "ISSUE_FIELD_ADDED_EVENT",
+ "description": "Represents aissue_field_addedevent on a given issue.
"
+ },
+ {
+ "name": "ISSUE_FIELD_CHANGED_EVENT",
+ "description": "Represents aissue_field_changedevent on a given issue.
"
+ },
+ {
+ "name": "ISSUE_FIELD_REMOVED_EVENT",
+ "description": "Represents aissue_field_removedevent on a given issue.
"
+ },
{
"name": "ISSUE_TYPE_ADDED_EVENT",
"description": "Represents aissue_type_addedevent on a given issue.
"
@@ -93413,7 +93586,7 @@
},
{
"name": "COPILOT_CODE_REVIEW",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
"
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
"
},
{
"name": "CREATION",
@@ -100474,7 +100647,7 @@
"kind": "inputObjects",
"id": "copilotcodereviewparametersinput",
"href": "/graphql/reference/input-objects#copilotcodereviewparametersinput",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
",
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
",
"inputFields": [
{
"name": "reviewDraftPullRequests",
@@ -106190,7 +106363,7 @@
},
{
"name": "automaticCopilotCodeReviewEnabled",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
",
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
",
"type": "Boolean",
"id": "boolean",
"kind": "scalars",
@@ -106499,7 +106672,7 @@
},
{
"name": "assigneeIds",
- "description": "The id of users to remove as assignees.
",
+ "description": "The ids of actors to remove as assignees.
",
"type": "[ID!]!",
"id": "id",
"kind": "scalars",
@@ -110782,7 +110955,7 @@
"inputFields": [
{
"name": "assigneeIds",
- "description": "An array of Node IDs of users for this issue.
",
+ "description": "An array of Node IDs of users or bots for this issue.
",
"type": "[ID!]",
"id": "id",
"kind": "scalars",
diff --git a/src/graphql/data/ghec/schema.docs.graphql b/src/graphql/data/ghec/schema.docs.graphql
index 9a9a6d015156..a052abfcbb8a 100644
--- a/src/graphql/data/ghec/schema.docs.graphql
+++ b/src/graphql/data/ghec/schema.docs.graphql
@@ -7335,7 +7335,9 @@ type ConvertedToDiscussionEvent implements Node {
}
"""
-Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+Request Copilot code review for new pull requests automatically if the author
+has access to Copilot code review and their premium requests quota has not
+reached the limit.
"""
type CopilotCodeReviewParameters {
"""
@@ -7350,7 +7352,9 @@ type CopilotCodeReviewParameters {
}
"""
-Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+Request Copilot code review for new pull requests automatically if the author
+has access to Copilot code review and their premium requests quota has not
+reached the limit.
"""
input CopilotCodeReviewParametersInput {
"""
@@ -20648,6 +20652,21 @@ enum IssueTimelineItemsItemType {
"""
ISSUE_COMMENT
+ """
+ Represents a 'issue_field_added' event on a given issue.
+ """
+ ISSUE_FIELD_ADDED_EVENT
+
+ """
+ Represents a 'issue_field_changed' event on a given issue.
+ """
+ ISSUE_FIELD_CHANGED_EVENT
+
+ """
+ Represents a 'issue_field_removed' event on a given issue.
+ """
+ ISSUE_FIELD_REMOVED_EVENT
+
"""
Represents a 'issue_type_added' event on a given issue.
"""
@@ -41291,6 +41310,31 @@ type PullRequest implements Assignable & Closable & Comment & Labelable & Lockab
query: String
): AssigneeConnection!
+ """
+ Reviewer actor suggestions based on commit history, past review comments, and integrations.
+ """
+ suggestedReviewerActors(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): SuggestedReviewerActorConnection!
+
"""
A list of reviewer suggestions based on commit history and past review comments.
"""
@@ -41905,7 +41949,9 @@ type PullRequestParameters {
allowedMergeMethods: [PullRequestAllowedMergeMethods!]
"""
- Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+ Request Copilot code review for new pull requests automatically if the author
+ has access to Copilot code review and their premium requests quota has not
+ reached the limit.
"""
automaticCopilotCodeReviewEnabled: Boolean!
@@ -41953,7 +41999,9 @@ input PullRequestParametersInput {
allowedMergeMethods: [PullRequestAllowedMergeMethods!]
"""
- Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+ Request Copilot code review for new pull requests automatically if the author
+ has access to Copilot code review and their premium requests quota has not
+ reached the limit.
"""
automaticCopilotCodeReviewEnabled: Boolean
@@ -43519,6 +43567,21 @@ enum PullRequestTimelineItemsItemType {
"""
ISSUE_COMMENT
+ """
+ Represents a 'issue_field_added' event on a given issue.
+ """
+ ISSUE_FIELD_ADDED_EVENT
+
+ """
+ Represents a 'issue_field_changed' event on a given issue.
+ """
+ ISSUE_FIELD_CHANGED_EVENT
+
+ """
+ Represents a 'issue_field_removed' event on a given issue.
+ """
+ ISSUE_FIELD_REMOVED_EVENT
+
"""
Represents a 'issue_type_added' event on a given issue.
"""
@@ -45719,9 +45782,13 @@ input RemoveAssigneesFromAssignableInput {
assignableId: ID! @possibleTypes(concreteTypes: ["Issue", "PullRequest"], abstractType: "Assignable")
"""
- The id of users to remove as assignees.
+ The ids of actors to remove as assignees.
"""
- assigneeIds: [ID!]! @possibleTypes(concreteTypes: ["User"])
+ assigneeIds: [ID!]!
+ @possibleTypes(
+ concreteTypes: ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"]
+ abstractType: "Actor"
+ )
"""
A unique identifier for the client performing the mutation.
@@ -53261,7 +53328,9 @@ enum RepositoryRuleType {
COMMIT_MESSAGE_PATTERN
"""
- Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
+ Request Copilot code review for new pull requests automatically if the author
+ has access to Copilot code review and their premium requests quota has not
+ reached the limit.
"""
COPILOT_CODE_REVIEW
@@ -60390,6 +60459,66 @@ type SuggestedReviewer {
reviewer: User!
}
+"""
+A suggestion to review a pull request based on an actor's commit history, review comments, and integrations.
+"""
+type SuggestedReviewerActor {
+ """
+ Is this suggestion based on past commits?
+ """
+ isAuthor: Boolean!
+
+ """
+ Is this suggestion based on past review comments?
+ """
+ isCommenter: Boolean!
+
+ """
+ Identifies the actor suggested to review the pull request.
+ """
+ reviewer: Actor!
+}
+
+"""
+A suggestion to review a pull request based on an actor's commit history, review comments, and integrations.
+"""
+type SuggestedReviewerActorConnection {
+ """
+ A list of edges.
+ """
+ edges: [SuggestedReviewerActorEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [SuggestedReviewerActor]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+
+ """
+ Identifies the total count of items in the connection.
+ """
+ totalCount: Int!
+}
+
+"""
+An edge in a connection.
+"""
+type SuggestedReviewerActorEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: SuggestedReviewerActor
+}
+
"""
Represents a Git tag.
"""
@@ -65626,9 +65755,13 @@ Autogenerated input type of UpdateIssue
"""
input UpdateIssueInput {
"""
- An array of Node IDs of users for this issue.
+ An array of Node IDs of users or bots for this issue.
"""
- assigneeIds: [ID!] @possibleTypes(concreteTypes: ["User"])
+ assigneeIds: [ID!]
+ @possibleTypes(
+ concreteTypes: ["Bot", "EnterpriseUserAccount", "Mannequin", "Organization", "User"]
+ abstractType: "Actor"
+ )
"""
The body for the issue description.
diff --git a/src/graphql/data/ghec/schema.json b/src/graphql/data/ghec/schema.json
index 534ae6d97d30..4766206c9fcc 100644
--- a/src/graphql/data/ghec/schema.json
+++ b/src/graphql/data/ghec/schema.json
@@ -17559,7 +17559,7 @@
"kind": "objects",
"id": "copilotcodereviewparameters",
"href": "/graphql/reference/objects#copilotcodereviewparameters",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
",
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
",
"fields": [
{
"name": "reviewDraftPullRequests",
@@ -55187,6 +55187,56 @@
}
]
},
+ {
+ "name": "suggestedReviewerActors",
+ "description": "Reviewer actor suggestions based on commit history, past review comments, and integrations.
",
+ "type": "SuggestedReviewerActorConnection!",
+ "id": "suggestedrevieweractorconnection",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#suggestedrevieweractorconnection",
+ "arguments": [
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.
",
+ "type": {
+ "name": "String",
+ "id": "string",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#string"
+ }
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.
",
+ "type": {
+ "name": "String",
+ "id": "string",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#string"
+ }
+ },
+ {
+ "name": "first",
+ "description": "Returns the first n elements from the list.
",
+ "type": {
+ "name": "Int",
+ "id": "int",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#int"
+ }
+ },
+ {
+ "name": "last",
+ "description": "Returns the last n elements from the list.
",
+ "type": {
+ "name": "Int",
+ "id": "int",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#int"
+ }
+ }
+ ]
+ },
{
"name": "suggestedReviewers",
"description": "A list of reviewer suggestions based on commit history and past review comments.
",
@@ -56134,7 +56184,7 @@
},
{
"name": "automaticCopilotCodeReviewEnabled",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
",
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
",
"type": "Boolean!",
"id": "boolean",
"kind": "scalars",
@@ -75054,6 +75104,105 @@
}
]
},
+ {
+ "name": "SuggestedReviewerActor",
+ "kind": "objects",
+ "id": "suggestedrevieweractor",
+ "href": "/graphql/reference/objects#suggestedrevieweractor",
+ "description": "A suggestion to review a pull request based on an actor's commit history, review comments, and integrations.
",
+ "fields": [
+ {
+ "name": "isAuthor",
+ "description": "Is this suggestion based on past commits?.
",
+ "type": "Boolean!",
+ "id": "boolean",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#boolean"
+ },
+ {
+ "name": "isCommenter",
+ "description": "Is this suggestion based on past review comments?.
",
+ "type": "Boolean!",
+ "id": "boolean",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#boolean"
+ },
+ {
+ "name": "reviewer",
+ "description": "Identifies the actor suggested to review the pull request.
",
+ "type": "Actor!",
+ "id": "actor",
+ "kind": "interfaces",
+ "href": "/graphql/reference/interfaces#actor"
+ }
+ ]
+ },
+ {
+ "name": "SuggestedReviewerActorConnection",
+ "kind": "objects",
+ "id": "suggestedrevieweractorconnection",
+ "href": "/graphql/reference/objects#suggestedrevieweractorconnection",
+ "description": "A suggestion to review a pull request based on an actor's commit history, review comments, and integrations.
",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.
",
+ "type": "[SuggestedReviewerActorEdge]",
+ "id": "suggestedrevieweractoredge",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#suggestedrevieweractoredge"
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.
",
+ "type": "[SuggestedReviewerActor]",
+ "id": "suggestedrevieweractor",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#suggestedrevieweractor"
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.
",
+ "type": "PageInfo!",
+ "id": "pageinfo",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#pageinfo"
+ },
+ {
+ "name": "totalCount",
+ "description": "Identifies the total count of items in the connection.
",
+ "type": "Int!",
+ "id": "int",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#int"
+ }
+ ]
+ },
+ {
+ "name": "SuggestedReviewerActorEdge",
+ "kind": "objects",
+ "id": "suggestedrevieweractoredge",
+ "href": "/graphql/reference/objects#suggestedrevieweractoredge",
+ "description": "An edge in a connection.
",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.
",
+ "type": "String!",
+ "id": "string",
+ "kind": "scalars",
+ "href": "/graphql/reference/scalars#string"
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.
",
+ "type": "SuggestedReviewerActor",
+ "id": "suggestedrevieweractor",
+ "kind": "objects",
+ "href": "/graphql/reference/objects#suggestedrevieweractor"
+ }
+ ]
+ },
{
"name": "Tag",
"kind": "objects",
@@ -90453,6 +90602,18 @@
"name": "ISSUE_COMMENT",
"description": "Represents a comment on an Issue.
"
},
+ {
+ "name": "ISSUE_FIELD_ADDED_EVENT",
+ "description": "Represents aissue_field_addedevent on a given issue.
"
+ },
+ {
+ "name": "ISSUE_FIELD_CHANGED_EVENT",
+ "description": "Represents aissue_field_changedevent on a given issue.
"
+ },
+ {
+ "name": "ISSUE_FIELD_REMOVED_EVENT",
+ "description": "Represents aissue_field_removedevent on a given issue.
"
+ },
{
"name": "ISSUE_TYPE_ADDED_EVENT",
"description": "Represents aissue_type_addedevent on a given issue.
"
@@ -92636,6 +92797,18 @@
"name": "ISSUE_COMMENT",
"description": "Represents a comment on an Issue.
"
},
+ {
+ "name": "ISSUE_FIELD_ADDED_EVENT",
+ "description": "Represents aissue_field_addedevent on a given issue.
"
+ },
+ {
+ "name": "ISSUE_FIELD_CHANGED_EVENT",
+ "description": "Represents aissue_field_changedevent on a given issue.
"
+ },
+ {
+ "name": "ISSUE_FIELD_REMOVED_EVENT",
+ "description": "Represents aissue_field_removedevent on a given issue.
"
+ },
{
"name": "ISSUE_TYPE_ADDED_EVENT",
"description": "Represents aissue_type_addedevent on a given issue.
"
@@ -93413,7 +93586,7 @@
},
{
"name": "COPILOT_CODE_REVIEW",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
"
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
"
},
{
"name": "CREATION",
@@ -100474,7 +100647,7 @@
"kind": "inputObjects",
"id": "copilotcodereviewparametersinput",
"href": "/graphql/reference/input-objects#copilotcodereviewparametersinput",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
",
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
",
"inputFields": [
{
"name": "reviewDraftPullRequests",
@@ -106190,7 +106363,7 @@
},
{
"name": "automaticCopilotCodeReviewEnabled",
- "description": "Request Copilot code review for new pull requests automatically if the author has access to Copilot code review.
",
+ "description": "Request Copilot code review for new pull requests automatically if the author\nhas access to Copilot code review and their premium requests quota has not\nreached the limit.
",
"type": "Boolean",
"id": "boolean",
"kind": "scalars",
@@ -106499,7 +106672,7 @@
},
{
"name": "assigneeIds",
- "description": "The id of users to remove as assignees.
",
+ "description": "The ids of actors to remove as assignees.
",
"type": "[ID!]!",
"id": "id",
"kind": "scalars",
@@ -110782,7 +110955,7 @@
"inputFields": [
{
"name": "assigneeIds",
- "description": "An array of Node IDs of users for this issue.
",
+ "description": "An array of Node IDs of users or bots for this issue.
",
"type": "[ID!]",
"id": "id",
"kind": "scalars",
diff --git a/src/landings/components/SidebarProduct.tsx b/src/landings/components/SidebarProduct.tsx
index 164dcab4f302..833e978d8e1b 100644
--- a/src/landings/components/SidebarProduct.tsx
+++ b/src/landings/components/SidebarProduct.tsx
@@ -146,8 +146,6 @@ function RestNavListItem({ category }: { category: ProductTreeNode }) {
},
{ rootMargin: '0px 0px -85% 0px' },
)
- // TODO: When we add the ## About the {title} API to each operation
- // we can remove the h2 here
const headingsList = Array.from(document.querySelectorAll('h2, h3'))
for (const heading of headingsList) {
diff --git a/src/languages/tests/translation-error-comments.ts b/src/languages/tests/translation-error-comments.ts
index 19bf22a914bb..7052e8023f42 100644
--- a/src/languages/tests/translation-error-comments.ts
+++ b/src/languages/tests/translation-error-comments.ts
@@ -8,9 +8,20 @@ import {
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<(template: string, context: any) => string>
+ let mockRenderContent: MockedFunction<
+ (template: string, context: Record) => string
+ >
beforeEach(() => {
mockRenderContent = vi.fn()
@@ -26,7 +37,7 @@ describe('Translation Error Comments', () => {
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 any).token = {
+ ;(error as unknown as ErrorWithToken).token = {
file: '/content/test/article.md',
getPosition: () => [1, 3],
}
@@ -48,11 +59,13 @@ describe('Translation Error Comments', () => {
test('includes original error message when available', () => {
const error = new Error("Unknown variable 'variables.nonexistent.value'")
error.name = 'RenderError'
- ;(error as any).token = {
+ ;(error as unknown as ErrorWithToken).token = {
file: '/content/test/intro.md',
getPosition: () => [3, 15],
}
- ;(error as any).originalError = new Error('Variable not found: variables.nonexistent.value')
+ ;(error as unknown as ErrorWithTokenAndOriginal).originalError = new Error(
+ 'Variable not found: variables.nonexistent.value',
+ )
const result = createTranslationFallbackComment(error, 'rawIntro')
@@ -67,7 +80,7 @@ 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 any).token = {
+ ;(error as unknown as ErrorWithToken).token = {
file: '/content/test.md',
getPosition: () => [1, 1],
}
@@ -82,7 +95,7 @@ describe('Translation Error Comments', () => {
test('includes tokenization error details', () => {
const error = new Error('Unexpected token, line:1, col:10')
error.name = 'TokenizationError'
- ;(error as any).token = {
+ ;(error as unknown as ErrorWithToken).token = {
file: '/content/test/page.md',
getPosition: () => [1, 10],
}
@@ -152,7 +165,7 @@ describe('Translation Error Comments', () => {
test('handles error with token but no file', () => {
const error = new Error('Error message')
error.name = 'ParseError'
- ;(error as any).token = {
+ ;(error as unknown as ErrorWithTokenNoFile).token = {
// No file property
getPosition: () => [5, 10],
}
@@ -167,7 +180,7 @@ describe('Translation Error Comments', () => {
test('handles error with token but no getPosition method', () => {
const error = new Error('Error message')
error.name = 'ParseError'
- ;(error as any).token = {
+ ;(error as unknown as ErrorWithTokenNoPosition).token = {
file: '/content/test.md',
// No getPosition method
}
@@ -246,7 +259,7 @@ describe('Translation Error Comments', () => {
test('comment format is valid HTML', () => {
const error = new Error('Test error')
error.name = 'ParseError'
- ;(error as any).token = {
+ ;(error as unknown as ErrorWithToken).token = {
file: '/content/test.md',
getPosition: () => [1, 1],
}
@@ -264,7 +277,7 @@ describe('Translation Error Comments', () => {
test('contains all required fields when available', () => {
const error = new Error('Detailed error message')
error.name = 'RenderError'
- ;(error as any).token = {
+ ;(error as unknown as ErrorWithToken).token = {
file: '/content/detailed-test.md',
getPosition: () => [42, 15],
}
@@ -283,7 +296,7 @@ describe('Translation Error Comments', () => {
test('maintains consistent field order', () => {
const error = new Error('Test message')
error.name = 'ParseError'
- ;(error as any).token = {
+ ;(error as unknown as ErrorWithToken).token = {
file: '/content/test.md',
getPosition: () => [1, 1],
}
@@ -320,18 +333,20 @@ describe('Translation Error Comments', () => {
}
// Mock renderContent to simulate error for Japanese, success for English
- mockRenderContent.mockImplementation((template: string, innerContext: any) => {
- if (innerContext.currentLanguage !== 'en' && template.includes('badtag')) {
- const error = new Error("Unknown tag 'badtag'")
- error.name = 'ParseError'
- ;(error as any).token = {
- file: '/content/test.md',
- getPosition: () => [1, 5],
+ 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 = {
+ file: '/content/test.md',
+ getPosition: () => [1, 5],
+ }
+ throw error
}
- throw error
- }
- return innerContext.currentLanguage === 'en' ? 'English Title' : template
- })
+ return innerContext.currentLanguage === 'en' ? 'English Title' : template
+ },
+ )
const result = await renderContentWithFallback(mockPage, 'rawTitle', context)
@@ -357,14 +372,16 @@ describe('Translation Error Comments', () => {
},
}
- mockRenderContent.mockImplementation((template: string, innerContext: any) => {
- if (innerContext.currentLanguage !== 'en' && template.includes('badtag')) {
- const error = new Error("Unknown tag 'badtag'")
- error.name = 'ParseError'
- throw error
- }
- return 'English Title'
- })
+ mockRenderContent.mockImplementation(
+ (template: string, innerContext: Record) => {
+ if (innerContext.currentLanguage !== 'en' && template.includes('badtag')) {
+ const error = new Error("Unknown tag 'badtag'")
+ error.name = 'ParseError'
+ throw error
+ }
+ return 'English Title'
+ },
+ )
const result = await renderContentWithFallback(mockPage, 'rawTitle', context, {
textOnly: true,
@@ -384,7 +401,7 @@ describe('Translation Error Comments', () => {
const failingCallable = async () => {
const error = new Error("Unknown variable 'variables.bad'")
error.name = 'RenderError'
- ;(error as any).token = {
+ ;(error as unknown as ErrorWithToken).token = {
file: '/content/article.md',
getPosition: () => [10, 20],
}
diff --git a/src/learning-track/middleware/learning-track.ts b/src/learning-track/middleware/learning-track.ts
index 1bec3b34c55a..28e9402890a9 100644
--- a/src/learning-track/middleware/learning-track.ts
+++ b/src/learning-track/middleware/learning-track.ts
@@ -27,8 +27,6 @@ export default async function learningTrack(
const trackName = req.query.learn as string
let trackProduct = req.context.currentProduct as string
- // TODO: Once getDeepDataByLanguage is ported to TS
- // a more appropriate API would be to use `getDeepDataByLanguage {
- // TODO: Once getDeepDataByLanguage is ported to TS
- // a more appropriate API would be to use `getDeepDataByLanguage & { end: () => unknown }
+
describe('getAutomaticRequestLogger', () => {
let originalEnv: typeof process.env
let originalConsoleLog: typeof console.log
@@ -43,7 +46,7 @@ describe('getAutomaticRequestLogger', () => {
}
// Override res.end to simulate response completion
- function endOverride(this: any, chunk?: any, encoding?: any) {
+ function endOverride(this: Response, chunk?: unknown, encoding?: unknown): Response {
if (!responseEnded) {
responseEnded = true
// Simulate a small delay for response time
@@ -54,7 +57,7 @@ describe('getAutomaticRequestLogger', () => {
return this
}
- ;(mockRes as any).end = endOverride
+ ;(mockRes as { end: typeof endOverride }).end = endOverride
mockNext = vi.fn()
@@ -86,7 +89,7 @@ describe('getAutomaticRequestLogger', () => {
middleware(mockReq as Request, mockRes as Response, mockNext)
// Simulate response completion
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
// Wait for async logging
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -143,7 +146,7 @@ describe('getAutomaticRequestLogger', () => {
}
// Override res.end to simulate response completion
- function endOverride(this: any, chunk?: any, encoding?: any) {
+ function endOverride(this: Response, chunk?: unknown, encoding?: unknown): Response {
if (!responseEnded) {
responseEnded = true
// Simulate a small delay for response time
@@ -154,7 +157,7 @@ describe('getAutomaticRequestLogger', () => {
return this
}
- ;(freshMockRes as any).end = endOverride
+ ;(freshMockRes as { end: typeof endOverride }).end = endOverride
const freshMockNext = vi.fn()
@@ -165,7 +168,7 @@ describe('getAutomaticRequestLogger', () => {
freshMockRes as Partial as Response,
freshMockNext,
)
- ;(freshMockRes as any).end()
+ ;(freshMockRes as MockResponseWithEnd).end()
// Wait for async logging with longer timeout for CI
await new Promise((resolve) => setTimeout(resolve, 50))
@@ -187,7 +190,7 @@ describe('getAutomaticRequestLogger', () => {
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -202,7 +205,7 @@ describe('getAutomaticRequestLogger', () => {
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -215,7 +218,7 @@ describe('getAutomaticRequestLogger', () => {
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -233,7 +236,7 @@ describe('getAutomaticRequestLogger', () => {
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -252,7 +255,7 @@ describe('getAutomaticRequestLogger', () => {
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -291,7 +294,7 @@ describe('getAutomaticRequestLogger', () => {
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
// Wait for any potential async logging with longer timeout for CI
await new Promise((resolve) => setTimeout(resolve, 50))
@@ -309,7 +312,7 @@ describe('getAutomaticRequestLogger', () => {
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -320,11 +323,13 @@ describe('getAutomaticRequestLogger', () => {
describe('edge cases', () => {
it('should handle missing content-length header', async () => {
- ;(mockRes as any).getHeader = vi.fn(() => undefined)
+ ;(mockRes as Partial & { getHeader: () => undefined }).getHeader = vi.fn(
+ () => undefined,
+ )
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -333,11 +338,11 @@ describe('getAutomaticRequestLogger', () => {
})
it('should handle missing status code', async () => {
- delete (mockRes as any).statusCode
+ delete (mockRes as Partial & { statusCode?: number }).statusCode
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -351,7 +356,7 @@ describe('getAutomaticRequestLogger', () => {
const middleware = getAutomaticRequestLogger()
middleware(mockReq as Request, mockRes as Response, mockNext)
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
@@ -368,7 +373,7 @@ describe('getAutomaticRequestLogger', () => {
// Simulate some processing time
await new Promise((resolve) => setTimeout(resolve, 50))
- ;(mockRes as any).end()
+ ;(mockRes as MockResponseWithEnd).end()
await new Promise((resolve) => setTimeout(resolve, 20))
const endTime = Date.now()
diff --git a/src/observability/tests/logger.ts b/src/observability/tests/logger.ts
index 8eb9a0239e54..db66f8d50298 100644
--- a/src/observability/tests/logger.ts
+++ b/src/observability/tests/logger.ts
@@ -327,10 +327,6 @@ describe('createLogger', () => {
logger = createLogger('file:///path/to/test.js')
})
- it('should include logger context in production logs', () => {
- // TODO
- })
-
it('should handle missing logger context gracefully in development', () => {
logger.info('No context test')
diff --git a/src/rest/scripts/update-files.ts b/src/rest/scripts/update-files.ts
index c4619cf5a6d5..c9d1abb44c92 100755
--- a/src/rest/scripts/update-files.ts
+++ b/src/rest/scripts/update-files.ts
@@ -114,10 +114,7 @@ async function main() {
// so that we don't spend time generating data files for them.
if (sourceRepos.includes(REST_API_DESCRIPTION_ROOT)) {
const derefDir = await readdir(TEMP_OPENAPI_DIR)
- // TODO: After migrating all-version.ts to TypeScript, we can remove the type assertion
- const currentOpenApiVersions = Object.values(allVersions).map(
- (elem) => (elem as any).openApiVersionName,
- )
+ const currentOpenApiVersions = Object.values(allVersions).map((elem) => elem.openApiVersionName)
for (const schema of derefDir) {
// if the schema does not start with a current version name, delete it
diff --git a/src/rest/scripts/utils/operation.ts b/src/rest/scripts/utils/operation.ts
index c8d08e545f91..aea5778c6f3f 100644
--- a/src/rest/scripts/utils/operation.ts
+++ b/src/rest/scripts/utils/operation.ts
@@ -168,10 +168,6 @@ export default class Operation {
// Operation Id: markdown/render-raw
const contentType = Object.keys(this.#operation.requestBody.content)[0]
const schema = get(this.#operation, `requestBody.content.${contentType}.schema`, {})
- // TODO: Remove this check
- if (this.#operation.operationId === 'checks/create') {
- delete schema.oneOf
- }
// Merges any instances of allOf in the schema using a deep merge
const mergedAllofSchema = mergeAllOf(schema)
try {
diff --git a/src/rest/tests/create-rest-examples.ts b/src/rest/tests/create-rest-examples.ts
index f371f8dbcfa4..ed1b531065ed 100644
--- a/src/rest/tests/create-rest-examples.ts
+++ b/src/rest/tests/create-rest-examples.ts
@@ -52,9 +52,12 @@ describe('rest example requests and responses', () => {
test('check example number and status code appear', async () => {
const mergedExamples = await getCodeSamples(operation)
- // example is any because getCodeSamples returns objects from untyped JavaScript module
+ // example has specific structure from getCodeSamples
for (let index = 0; index < mergedExamples.length; index++) {
- const example: any = mergedExamples[index]
+ const example = mergedExamples[index] as {
+ request: { description: string }
+ response: { statusCode: string }
+ }
expect(example.request.description).toBe(
`Example ${index + 1}: Status Code ${example.response.statusCode}`,
)
diff --git a/src/search/components/helpers/execute-search-actions.ts b/src/search/components/helpers/execute-search-actions.ts
index 3ed226121858..29834277ada2 100644
--- a/src/search/components/helpers/execute-search-actions.ts
+++ b/src/search/components/helpers/execute-search-actions.ts
@@ -4,6 +4,7 @@ import { DEFAULT_VERSION } from '@/versions/components/useVersion'
import { NextRouter } from 'next/router'
import { sendEvent } from '@/events/components/events'
import { SEARCH_OVERLAY_EVENT_GROUP } from '@/events/components/event-groups'
+import { sanitizeSearchQuery } from '@/search/lib/sanitize-search-query'
// Search context values for identifying each search event
export const GENERAL_SEARCH_CONTEXT = 'general-search'
@@ -21,7 +22,7 @@ export function executeGeneralSearch(
) {
sendEvent({
type: EventType.search,
- search_query: localQuery,
+ search_query: sanitizeSearchQuery(localQuery),
search_context: GENERAL_SEARCH_CONTEXT,
eventGroupKey: SEARCH_OVERLAY_EVENT_GROUP,
eventGroupId,
diff --git a/src/search/components/input/SearchOverlay.tsx b/src/search/components/input/SearchOverlay.tsx
index 250fc0317e21..8ab7fd39af7e 100644
--- a/src/search/components/input/SearchOverlay.tsx
+++ b/src/search/components/input/SearchOverlay.tsx
@@ -30,6 +30,8 @@ import { useSharedUIContext } from '@/frame/components/context/SharedUIContext'
import type { AIReference } from '../types'
import type { AutocompleteSearchHit, GeneralSearchHit } from '@/search/types'
+import { sanitizeSearchQuery } from '@/search/lib/sanitize-search-query'
+
import styles from './SearchOverlay.module.scss'
type Props = {
@@ -317,15 +319,14 @@ export function SearchOverlay({
const generalSearchResultOnSelect = (selectedOption: GeneralSearchHit) => {
sendEvent({
type: EventType.search,
- // TODO: Remove PII so we can include the actual query
- search_query: urlSearchInputQuery,
+ search_query: sanitizeSearchQuery(urlSearchInputQuery),
search_context: GENERAL_SEARCH_CONTEXT,
eventGroupKey: SEARCH_OVERLAY_EVENT_GROUP,
eventGroupId: searchEventGroupId.current,
})
sendEvent({
type: EventType.searchResult,
- search_result_query: urlSearchInputQuery,
+ search_result_query: sanitizeSearchQuery(urlSearchInputQuery),
search_result_index: selectedIndex,
search_result_total: totalGeneralSearchResults,
search_result_url: selectedOption.url || '',
diff --git a/src/search/lib/ai-search-proxy.ts b/src/search/lib/ai-search-proxy.ts
index dd84458da35f..a6bd834df737 100644
--- a/src/search/lib/ai-search-proxy.ts
+++ b/src/search/lib/ai-search-proxy.ts
@@ -21,8 +21,9 @@ export const aiSearchProxy = async (req: ExtendedRequest, res: Response) => {
let docsSource = ''
try {
docsSource = getCSECopilotSource(version)
- } catch (error: any) {
- errors.push({ message: error?.message || 'Invalid version' })
+ } catch (error: unknown) {
+ const message = error instanceof Error ? error.message : 'Invalid version'
+ errors.push({ message })
}
if (errors.length) {
diff --git a/src/search/lib/sanitize-search-query.ts b/src/search/lib/sanitize-search-query.ts
new file mode 100644
index 000000000000..0ad5e2c574bb
--- /dev/null
+++ b/src/search/lib/sanitize-search-query.ts
@@ -0,0 +1,58 @@
+// Remove PII from search queries before logging
+// Redacts common PII patterns like emails, tokens, and other sensitive data
+
+export function sanitizeSearchQuery(query: string): string {
+ if (!query) return query
+
+ let sanitized = query
+
+ // Redact email addresses
+ sanitized = sanitized.replace(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/g, '[EMAIL]')
+
+ // Redact GitHub tokens (all formats)
+ // Classic tokens: ghp_, gho_, ghu_, ghs_, ghr_
+ sanitized = sanitized.replace(/\b(ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{20,}\b/gi, '[TOKEN]')
+ // Fine-grained personal access tokens: github_pat_
+ sanitized = sanitized.replace(/\bgithub_pat_[A-Za-z0-9_]{20,}\b/gi, '[TOKEN]')
+ // OAuth tokens: gho_
+ sanitized = sanitized.replace(/\bgho_[A-Za-z0-9]{20,}\b/gi, '[TOKEN]')
+
+ // Redact UUIDs
+ sanitized = sanitized.replace(
+ /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,
+ '[UUID]',
+ )
+
+ // Redact JWT tokens (format: xxx.yyy.zzz where each part is base64url)
+ sanitized = sanitized.replace(
+ /\bey[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/g,
+ '[JWT]',
+ )
+
+ // Redact IP addresses (with proper validation for 0-255 range)
+ sanitized = sanitized.replace(
+ /\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b/g,
+ '[IP]',
+ )
+
+ // Redact SSH private key headers
+ sanitized = sanitized.replace(/-----BEGIN( [A-Z]+)? PRIVATE KEY-----/g, '[SSH_KEY]')
+
+ // Redact potential API keys (long strings of hex or base64-like characters)
+ // This catches high-entropy strings that might be secrets
+ sanitized = sanitized.replace(/\b[A-Za-z0-9_-]{40,}\b/g, (match) => {
+ // Only redact if it looks like high entropy (mixed case, numbers)
+ const hasLowerCase = /[a-z]/.test(match)
+ const hasUpperCase = /[A-Z]/.test(match)
+ const hasNumbers = /[0-9]/.test(match)
+ const entropyIndicators = [hasLowerCase, hasUpperCase, hasNumbers].filter(Boolean).length
+
+ // If it has at least 2 of the 3 character types, it's likely a secret
+ if (entropyIndicators >= 2) {
+ return '[SECRET]'
+ }
+ return match
+ })
+
+ return sanitized
+}
diff --git a/src/search/scripts/scrape/lib/domwaiter.ts b/src/search/scripts/scrape/lib/domwaiter.ts
index 34302c823b24..70e1251f6fe0 100644
--- a/src/search/scripts/scrape/lib/domwaiter.ts
+++ b/src/search/scripts/scrape/lib/domwaiter.ts
@@ -22,6 +22,10 @@ class HTTPError extends Error {
}
}
+// Type aliases for error objects with additional URL information
+type HTTPErrorWithUrl = HTTPError & { url?: string; relativePath?: string }
+type ErrorWithUrl = Error & { url?: string; relativePath?: string }
+
interface DomWaiterOptions {
parseDOM?: boolean
json?: boolean
@@ -94,8 +98,8 @@ async function getPage(page: Permalink, emitter: EventEmitter, opts: DomWaiterOp
{ requestUrl: { pathname: page.url } },
)
// Add URL and path info directly to the HTTPError
- ;(httpError as any).url = page.url
- ;(httpError as any).relativePath = page.relativePath
+ ;(httpError as HTTPErrorWithUrl).url = page.url
+ ;(httpError as HTTPErrorWithUrl).relativePath = page.relativePath
// Emit error instead of throwing
emitter.emit('error', httpError)
return // Exit early, don't continue processing
@@ -109,8 +113,8 @@ async function getPage(page: Permalink, emitter: EventEmitter, opts: DomWaiterOp
const enhancedError = new Error(err.message, { cause: err.cause })
enhancedError.name = err.name
enhancedError.stack = err.stack
- ;(enhancedError as any).url = page.url
- ;(enhancedError as any).relativePath = page.relativePath
+ ;(enhancedError as ErrorWithUrl).url = page.url
+ ;(enhancedError as ErrorWithUrl).relativePath = page.relativePath
emitter.emit('error', enhancedError)
} else {
emitter.emit('error', err)
@@ -130,15 +134,16 @@ async function getPage(page: Permalink, emitter: EventEmitter, opts: DomWaiterOp
{ requestUrl: { pathname: page.url } },
)
// Add URL and path info directly to the HTTPError
- ;(httpError as any).url = page.url
- ;(httpError as any).relativePath = page.relativePath
+ ;(httpError as HTTPErrorWithUrl).url = page.url
+ ;(httpError as HTTPErrorWithUrl).relativePath = page.relativePath
// Emit error instead of throwing
emitter.emit('error', httpError)
return // Exit early, don't continue processing
}
const body = await response.text()
const pageCopy = Object.assign({}, page, { body })
- if (opts.parseDOM) (pageCopy as any).$ = cheerio.load(body)
+ if (opts.parseDOM)
+ (pageCopy as Permalink & { $?: ReturnType }).$ = cheerio.load(body)
emitter.emit('page', pageCopy)
} catch (err) {
// Enhance error with URL information
@@ -146,8 +151,8 @@ async function getPage(page: Permalink, emitter: EventEmitter, opts: DomWaiterOp
const enhancedError = new Error(err.message, { cause: err.cause })
enhancedError.name = err.name
enhancedError.stack = err.stack
- ;(enhancedError as any).url = page.url
- ;(enhancedError as any).relativePath = page.relativePath
+ ;(enhancedError as ErrorWithUrl).url = page.url
+ ;(enhancedError as ErrorWithUrl).relativePath = page.relativePath
emitter.emit('error', enhancedError)
} else {
emitter.emit('error', err)
diff --git a/src/search/tests/sanitize-search-query.ts b/src/search/tests/sanitize-search-query.ts
new file mode 100644
index 000000000000..7e910ec562a2
--- /dev/null
+++ b/src/search/tests/sanitize-search-query.ts
@@ -0,0 +1,218 @@
+import { describe, expect, test } from 'vitest'
+import { sanitizeSearchQuery } from '@/search/lib/sanitize-search-query'
+
+describe('sanitizeSearchQuery', () => {
+ test('returns empty string for empty input', () => {
+ expect(sanitizeSearchQuery('')).toBe('')
+ })
+
+ test('returns query unchanged if no PII detected', () => {
+ expect(sanitizeSearchQuery('how to create a repository')).toBe('how to create a repository')
+ expect(sanitizeSearchQuery('git commit message')).toBe('git commit message')
+ })
+
+ describe('email redaction', () => {
+ test('redacts single email address', () => {
+ expect(sanitizeSearchQuery('contact user@example.com for help')).toBe(
+ 'contact [EMAIL] for help',
+ )
+ })
+
+ test('redacts multiple email addresses', () => {
+ expect(sanitizeSearchQuery('email john@example.com or jane@test.org')).toBe(
+ 'email [EMAIL] or [EMAIL]',
+ )
+ })
+
+ test('redacts emails with special characters', () => {
+ expect(sanitizeSearchQuery('user.name+tag@example.co.uk')).toBe('[EMAIL]')
+ })
+ })
+
+ describe('GitHub token redaction', () => {
+ test('redacts classic personal access tokens (ghp_)', () => {
+ expect(sanitizeSearchQuery('token ghp_1234567890123456789012345678901234567890')).toBe(
+ 'token [TOKEN]',
+ )
+ })
+
+ test('redacts OAuth tokens (gho_)', () => {
+ expect(sanitizeSearchQuery('oauth gho_1234567890123456789012345678901234567890')).toBe(
+ 'oauth [TOKEN]',
+ )
+ })
+
+ test('redacts user tokens (ghu_)', () => {
+ expect(sanitizeSearchQuery('user ghu_1234567890123456789012345678901234567890')).toBe(
+ 'user [TOKEN]',
+ )
+ })
+
+ test('redacts server tokens (ghs_)', () => {
+ expect(sanitizeSearchQuery('server ghs_1234567890123456789012345678901234567890')).toBe(
+ 'server [TOKEN]',
+ )
+ })
+
+ test('redacts refresh tokens (ghr_)', () => {
+ expect(sanitizeSearchQuery('refresh ghr_1234567890123456789012345678901234567890')).toBe(
+ 'refresh [TOKEN]',
+ )
+ })
+
+ test('redacts fine-grained PATs (github_pat_)', () => {
+ expect(
+ sanitizeSearchQuery('fine-grained github_pat_1234567890123456789012345678901234567890'),
+ ).toBe('fine-grained [TOKEN]')
+ })
+
+ test('redacts tokens with minimum length (20 chars)', () => {
+ expect(sanitizeSearchQuery('short ghp_12345678901234567890')).toBe('short [TOKEN]')
+ })
+
+ test('does not redact partial token prefixes', () => {
+ expect(sanitizeSearchQuery('ghp is not a token')).toBe('ghp is not a token')
+ })
+ })
+
+ describe('UUID redaction', () => {
+ test('redacts standard UUIDs', () => {
+ expect(sanitizeSearchQuery('id 550e8400-e29b-41d4-a716-446655440000 found')).toBe(
+ 'id [UUID] found',
+ )
+ })
+
+ test('redacts UUIDs regardless of case', () => {
+ expect(sanitizeSearchQuery('UUID 550E8400-E29B-41D4-A716-446655440000')).toBe('UUID [UUID]')
+ })
+
+ test('redacts multiple UUIDs', () => {
+ expect(
+ sanitizeSearchQuery(
+ '550e8400-e29b-41d4-a716-446655440000 and 6ba7b810-9dad-11d1-80b4-00c04fd430c8',
+ ),
+ ).toBe('[UUID] and [UUID]')
+ })
+ })
+
+ describe('JWT redaction', () => {
+ test('redacts JWT tokens', () => {
+ const jwt =
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'
+ expect(sanitizeSearchQuery(`token ${jwt}`)).toBe('token [JWT]')
+ })
+
+ test('redacts JWT-like tokens with underscores and hyphens', () => {
+ expect(sanitizeSearchQuery('eyABC123_-XYZ.eyDEF456_-UVW.eyGHI789_-RST')).toBe('[JWT]')
+ })
+ })
+
+ describe('IP address redaction', () => {
+ test('redacts valid IPv4 addresses', () => {
+ expect(sanitizeSearchQuery('server 192.168.1.1 down')).toBe('server [IP] down')
+ expect(sanitizeSearchQuery('10.0.0.1')).toBe('[IP]')
+ expect(sanitizeSearchQuery('172.16.254.1')).toBe('[IP]')
+ })
+
+ test('redacts edge case IPs (0.0.0.0 and 255.255.255.255)', () => {
+ expect(sanitizeSearchQuery('0.0.0.0')).toBe('[IP]')
+ expect(sanitizeSearchQuery('255.255.255.255')).toBe('[IP]')
+ })
+
+ test('does not redact invalid IPs with octets > 255', () => {
+ expect(sanitizeSearchQuery('999.999.999.999')).toBe('999.999.999.999')
+ expect(sanitizeSearchQuery('256.1.1.1')).toBe('256.1.1.1')
+ })
+
+ test('redacts multiple IP addresses', () => {
+ expect(sanitizeSearchQuery('connect 10.0.0.1 or 192.168.1.1')).toBe('connect [IP] or [IP]')
+ })
+ })
+
+ describe('SSH private key redaction', () => {
+ test('redacts RSA private key headers', () => {
+ expect(sanitizeSearchQuery('-----BEGIN RSA PRIVATE KEY----- content')).toBe(
+ '[SSH_KEY] content',
+ )
+ })
+
+ test('redacts generic private key headers', () => {
+ expect(sanitizeSearchQuery('-----BEGIN PRIVATE KEY----- content')).toBe('[SSH_KEY] content')
+ })
+
+ test('redacts EC private key headers', () => {
+ expect(sanitizeSearchQuery('-----BEGIN EC PRIVATE KEY----- content')).toBe(
+ '[SSH_KEY] content',
+ )
+ })
+ })
+
+ describe('high-entropy string redaction', () => {
+ test('redacts long high-entropy strings with mixed case and numbers', () => {
+ // 40+ chars with lowercase, uppercase, and numbers
+ const secret = 'aB3dEf9Gh2IjKlMn0PqRsTuVwXyZ1234567890aBcDeF'
+ expect(sanitizeSearchQuery(secret)).toBe('[SECRET]')
+ })
+
+ test('redacts strings with lowercase and numbers', () => {
+ const secret = 'abc123def456ghi789jkl012mno345pqr678stu901vwx234'
+ expect(sanitizeSearchQuery(secret)).toBe('[SECRET]')
+ })
+
+ test('redacts strings with uppercase and numbers', () => {
+ const secret = 'ABC123DEF456GHI789JKL012MNO345PQR678STU901VWX234'
+ expect(sanitizeSearchQuery(secret)).toBe('[SECRET]')
+ })
+
+ test('does not redact long strings with only lowercase', () => {
+ const notSecret = 'thisisalongstringwithnouppercharsornumbers'
+ expect(sanitizeSearchQuery(notSecret)).toBe(notSecret)
+ })
+
+ test('does not redact long strings with only numbers', () => {
+ const notSecret = '12345678901234567890123456789012345678901234567890'
+ expect(sanitizeSearchQuery(notSecret)).toBe(notSecret)
+ })
+
+ test('does not redact strings shorter than 40 chars', () => {
+ const shortString = 'aB3dEf9Gh2IjKlMn0PqRsTuVwXyZ'
+ expect(sanitizeSearchQuery(shortString)).toBe(shortString)
+ })
+ })
+
+ describe('multiple PII types in one query', () => {
+ test('redacts all PII types in a single query', () => {
+ const query =
+ 'email user@example.com token ghp_1234567890123456789012345678901234567890 from 192.168.1.1'
+ expect(sanitizeSearchQuery(query)).toBe('email [EMAIL] token [TOKEN] from [IP]')
+ })
+
+ test('handles complex mixed query', () => {
+ const query = `
+ Contact admin@github.com
+ Token: github_pat_12345678901234567890ABCDEFGH
+ UUID: 550e8400-e29b-41d4-a716-446655440000
+ Server: 10.0.0.1
+ `.trim()
+ const result = sanitizeSearchQuery(query)
+ expect(result).toContain('[EMAIL]')
+ expect(result).toContain('[TOKEN]')
+ expect(result).toContain('[UUID]')
+ expect(result).toContain('[IP]')
+ })
+ })
+
+ describe('preserves safe content', () => {
+ test('preserves URLs without emails', () => {
+ expect(sanitizeSearchQuery('https://github.com/docs')).toBe('https://github.com/docs')
+ })
+
+ test('preserves code snippets', () => {
+ expect(sanitizeSearchQuery('git commit -m "fix bug"')).toBe('git commit -m "fix bug"')
+ })
+
+ test('preserves version numbers', () => {
+ expect(sanitizeSearchQuery('node v18.0.0')).toBe('node v18.0.0')
+ })
+ })
+})
diff --git a/src/secret-scanning/data/public-docs.yml b/src/secret-scanning/data/public-docs.yml
index 3fb8c497a456..52d3682afc77 100644
--- a/src/secret-scanning/data/public-docs.yml
+++ b/src/secret-scanning/data/public-docs.yml
@@ -4493,6 +4493,19 @@
hasValidityCheck: false
base64Supported: false
isduplicate: false
+- provider: Paddle
+ supportedSecret: Paddle Sandbox API Key
+ secretType: paddle_sandbox_api_key
+ versions:
+ fpt: '*'
+ ghec: '*'
+ ghes: '>=3.20'
+ isPublic: true
+ isPrivateWithGhas: true
+ hasPushProtection: false
+ hasValidityCheck: false
+ base64Supported: false
+ isduplicate: false
- provider: PagerDuty
supportedSecret: PagerDuty OAuth Secret
secretType: pagerduty_oauth_secret
diff --git a/src/secret-scanning/lib/config.json b/src/secret-scanning/lib/config.json
index 60b1933ea2af..611f6c1a28b5 100644
--- a/src/secret-scanning/lib/config.json
+++ b/src/secret-scanning/lib/config.json
@@ -1,5 +1,5 @@
{
- "sha": "01009b022a23f59bee88e60046c6b425178c3cab",
- "blob-sha": "5fb38d54763b5d5170e70b153a2d0ddeb5bed7c9",
+ "sha": "b68ab4c2355b44a07d40d669fd28da652fe1929e",
+ "blob-sha": "403271a4c5adc2dc195b04553c514833765b388d",
"targetFilename": "code-security/secret-scanning/introduction/supported-secret-scanning-patterns"
}
\ No newline at end of file
diff --git a/src/types/json-schema-merge-allof.d.ts b/src/types/json-schema-merge-allof.d.ts
index 83f021e0bf12..d4e2d3512ee4 100644
--- a/src/types/json-schema-merge-allof.d.ts
+++ b/src/types/json-schema-merge-allof.d.ts
@@ -9,7 +9,7 @@ declare module 'json-schema-merge-allof' {
type?: string | string[]
items?: JSONSchema | JSONSchema[]
additionalProperties?: boolean | JSONSchema
- [key: string]: any // JSON Schema allows arbitrary additional properties per spec
+ [key: string]: unknown // JSON Schema allows arbitrary additional properties per spec
}
/**
@@ -23,7 +23,7 @@ declare module 'json-schema-merge-allof' {
*/
resolvers?: Record<
string,
- (values: any[], path: string[], mergeSchemas: any, options: any) => any
+ (values: unknown[], path: string[], mergeSchemas: unknown, options: unknown) => unknown
>
/**