Disallow unsafe type assertions (#18688)

This commit is contained in:
Christian Gunderman
2026-02-10 00:10:15 +00:00
committed by GitHub
parent bce1caefd0
commit fd65416a2f
188 changed files with 592 additions and 47 deletions

View File

@@ -73,6 +73,7 @@ export async function executeToolWithHooks(
setPidCallback?: (pid: number) => void,
config?: Config,
): Promise<ToolResult> {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const toolInput = (invocation.params || {}) as Record<string, unknown>;
let inputWasModified = false;
let modifiedKeys: string[] = [];

View File

@@ -224,6 +224,7 @@ export class CoreToolScheduler {
tool: toolInstance,
invocation,
status: 'success',
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
response: auxiliaryData as ToolCallResponseInfo,
durationMs,
outcome,
@@ -237,6 +238,7 @@ export class CoreToolScheduler {
request: currentCall.request,
status: 'error',
tool: toolInstance,
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
response: auxiliaryData as ToolCallResponseInfo,
durationMs,
outcome,
@@ -247,6 +249,7 @@ export class CoreToolScheduler {
request: currentCall.request,
tool: toolInstance,
status: 'awaiting_approval',
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
confirmationDetails: auxiliaryData as ToolCallConfirmationDetails,
startTime: existingStartTime,
outcome,
@@ -347,6 +350,7 @@ export class CoreToolScheduler {
const invocationOrError = this.buildInvocation(
call.tool,
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
args as Record<string, unknown>,
);
if (invocationOrError instanceof Error) {
@@ -356,6 +360,7 @@ export class CoreToolScheduler {
ToolErrorType.INVALID_TOOL_PARAMS,
);
return {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
request: { ...call.request, args: args as Record<string, unknown> },
status: 'error',
tool: call.tool,
@@ -365,6 +370,7 @@ export class CoreToolScheduler {
return {
...call,
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
request: { ...call.request, args: args as Record<string, unknown> },
invocation: invocationOrError,
};
@@ -749,6 +755,7 @@ export class CoreToolScheduler {
this.cancelAll(signal);
return; // `cancelAll` calls `checkAndNotifyCompletion`, so we can exit here.
} else if (outcome === ToolConfirmationOutcome.ModifyWithEditor) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const waitingToolCall = toolCall as WaitingToolCall;
const editorType = this.getPreferredEditor();
@@ -756,6 +763,7 @@ export class CoreToolScheduler {
return;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
this.setStatusInternal(callId, 'awaiting_approval', signal, {
...waitingToolCall.confirmationDetails,
isModifying: true,
@@ -770,12 +778,14 @@ export class CoreToolScheduler {
// Restore status (isModifying: false) and update diff if result exists
if (result) {
this.setArgsInternal(callId, result.updatedParams);
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
this.setStatusInternal(callId, 'awaiting_approval', signal, {
...waitingToolCall.confirmationDetails,
fileDiff: result.updatedDiff,
isModifying: false,
} as ToolCallConfirmationDetails);
} else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
this.setStatusInternal(callId, 'awaiting_approval', signal, {
...waitingToolCall.confirmationDetails,
isModifying: false,
@@ -786,13 +796,16 @@ export class CoreToolScheduler {
// re-confirmation.
if (payload && 'newContent' in payload && toolCall) {
const result = await this.toolModifier.applyInlineModify(
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
toolCall as WaitingToolCall,
payload,
signal,
);
if (result) {
this.setArgsInternal(callId, result.updatedParams);
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
this.setStatusInternal(callId, 'awaiting_approval', signal, {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
...(toolCall as WaitingToolCall).confirmationDetails,
fileDiff: result.updatedDiff,
} as ToolCallConfirmationDetails);

View File

@@ -51,6 +51,7 @@ export class FakeContentGenerator implements ContentGenerator {
const responses = fileContent
.split('\n')
.filter((line) => line.trim() !== '')
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
.map((line) => JSON.parse(line) as FakeResponse);
return new FakeContentGenerator(responses);
}
@@ -71,6 +72,7 @@ export class FakeContentGenerator implements ContentGenerator {
`Unexpected response type, next response was for ${response.method} but expected ${method}`,
);
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return response.response as R;
}

View File

@@ -560,6 +560,7 @@ export class GeminiChat {
beforeModelResult.modifiedContents &&
Array.isArray(beforeModelResult.modifiedContents)
) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
contentsToUse = beforeModelResult.modifiedContents as Content[];
}
@@ -577,6 +578,7 @@ export class GeminiChat {
toolSelectionResult.tools &&
Array.isArray(toolSelectionResult.tools)
) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
config.tools = toolSelectionResult.tools as Tool[];
}
}
@@ -820,6 +822,7 @@ export class GeminiChat {
(candidate) => candidate.finishReason,
);
if (candidateWithReason) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
finishReason = candidateWithReason.finishReason as FinishReason;
}

View File

@@ -96,6 +96,7 @@ export class Logger {
await this._backupCorruptedLogFile('malformed_array');
return [];
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return parsedLogs.filter(
(entry) =>
typeof entry.sessionId === 'string' &&
@@ -105,6 +106,7 @@ export class Logger {
typeof entry.message === 'string',
) as LogEntry[];
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const nodeError = error as NodeJS.ErrnoException;
if (nodeError.code === 'ENOENT') {
return [];
@@ -298,6 +300,7 @@ export class Logger {
await fs.access(newPath);
return newPath; // Found it, use the new path.
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const nodeError = error as NodeJS.ErrnoException;
if (nodeError.code !== 'ENOENT') {
throw error; // A real error occurred, rethrow it.
@@ -311,6 +314,7 @@ export class Logger {
await fs.access(oldPath);
return oldPath; // Found it, use the old path.
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const nodeError = error as NodeJS.ErrnoException;
if (nodeError.code !== 'ENOENT') {
throw error; // A real error occurred, rethrow it.
@@ -352,6 +356,7 @@ export class Logger {
// Handle legacy format (just an array of Content)
if (Array.isArray(parsedContent)) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return { history: parsedContent as Content[] };
}
@@ -360,6 +365,7 @@ export class Logger {
parsedContent !== null &&
'history' in parsedContent
) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
return parsedContent as Checkpoint;
}
@@ -368,6 +374,7 @@ export class Logger {
);
return { history: [] };
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const nodeError = error as NodeJS.ErrnoException;
if (nodeError.code === 'ENOENT') {
// This is okay, it just means the checkpoint doesn't exist in either format.
@@ -397,6 +404,7 @@ export class Logger {
await fs.unlink(newPath);
deletedSomething = true;
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const nodeError = error as NodeJS.ErrnoException;
if (nodeError.code !== 'ENOENT') {
debugLogger.error(
@@ -415,6 +423,7 @@ export class Logger {
await fs.unlink(oldPath);
deletedSomething = true;
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const nodeError = error as NodeJS.ErrnoException;
if (nodeError.code !== 'ENOENT') {
debugLogger.error(
@@ -444,6 +453,7 @@ export class Logger {
await fs.access(filePath);
return true;
} catch (error) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
const nodeError = error as NodeJS.ErrnoException;
if (nodeError.code === 'ENOENT') {
return false; // It truly doesn't exist in either format.

View File

@@ -177,7 +177,8 @@ export class LoggingContentGenerator implements ContentGenerator {
this.config.getContentGeneratorConfig()?.authType,
errorType,
isStructuredError(error)
? (error as StructuredError).status
? // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
(error as StructuredError).status
: undefined,
),
);

View File

@@ -48,6 +48,7 @@ export class RecordingContentGenerator implements ContentGenerator {
);
const recordedResponse: FakeResponse = {
method: 'generateContent',
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
response: {
candidates: response.candidates,
usageMetadata: response.usageMetadata,
@@ -73,6 +74,7 @@ export class RecordingContentGenerator implements ContentGenerator {
async function* stream(filePath: string) {
for await (const response of realResponses) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
(recordedResponse.response as GenerateContentResponse[]).push({
candidates: response.candidates,
usageMetadata: response.usageMetadata,

View File

@@ -384,7 +384,8 @@ export class Turn {
error !== null &&
'status' in error &&
typeof (error as { status: unknown }).status === 'number'
? (error as { status: number }).status
? // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
(error as { status: number }).status
: undefined;
const structuredError: StructuredError = {
message: getErrorMessage(error),