Wire up data flow paths view (#2182)
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
|
||||
## [UNRELEASED]
|
||||
|
||||
- Show data flow paths of a variant analysis in a new tab
|
||||
|
||||
## 1.8.0 - 9 March 2023
|
||||
|
||||
- Send telemetry about unhandled errors happening within the extension. [#2125](https://github.com/github/vscode-codeql/pull/2125)
|
||||
|
||||
@@ -449,6 +449,11 @@ export interface CancelVariantAnalysisMessage {
|
||||
t: "cancelVariantAnalysis";
|
||||
}
|
||||
|
||||
export interface ShowDataFlowPathsMessage {
|
||||
t: "showDataFlowPaths";
|
||||
dataFlowPaths: DataFlowPaths;
|
||||
}
|
||||
|
||||
export type ToVariantAnalysisMessage =
|
||||
| SetVariantAnalysisMessage
|
||||
| SetRepoResultsMessage
|
||||
@@ -462,7 +467,8 @@ export type FromVariantAnalysisMessage =
|
||||
| CopyRepositoryListMessage
|
||||
| ExportResultsMessage
|
||||
| OpenLogsMessage
|
||||
| CancelVariantAnalysisMessage;
|
||||
| CancelVariantAnalysisMessage
|
||||
| ShowDataFlowPathsMessage;
|
||||
|
||||
export interface SetDataFlowPathsMessage {
|
||||
t: "setDataFlowPaths";
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { ComponentStory, ComponentMeta } from "@storybook/react";
|
||||
import { ThemeProvider } from "@primer/react";
|
||||
|
||||
import { CodePaths } from "../../view/common";
|
||||
import type { CodeFlow } from "../../variant-analysis/shared/analysis-result";
|
||||
@@ -9,13 +8,7 @@ import type { CodeFlow } from "../../variant-analysis/shared/analysis-result";
|
||||
export default {
|
||||
title: "Code Paths",
|
||||
component: CodePaths,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<ThemeProvider colorMode="auto">
|
||||
<Story />
|
||||
</ThemeProvider>
|
||||
),
|
||||
],
|
||||
decorators: [(Story) => <Story />],
|
||||
} as ComponentMeta<typeof CodePaths>;
|
||||
|
||||
const Template: ComponentStory<typeof CodePaths> = (args) => (
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import * as React from "react";
|
||||
|
||||
import { ComponentMeta, ComponentStory } from "@storybook/react";
|
||||
|
||||
import { DataFlowPaths as DataFlowPathsComponent } from "../../view/data-flow-paths/DataFlowPaths";
|
||||
import { createMockDataFlowPaths } from "../../../test/factories/variant-analysis/shared/data-flow-paths";
|
||||
export default {
|
||||
title: "Data Flow Paths/Data Flow Paths",
|
||||
component: DataFlowPathsComponent,
|
||||
} as ComponentMeta<typeof DataFlowPathsComponent>;
|
||||
|
||||
const Template: ComponentStory<typeof DataFlowPathsComponent> = (args) => (
|
||||
<DataFlowPathsComponent {...args} />
|
||||
);
|
||||
|
||||
export const PowerShell = Template.bind({});
|
||||
PowerShell.args = {
|
||||
dataFlowPaths: createMockDataFlowPaths(),
|
||||
};
|
||||
@@ -21,12 +21,15 @@ import {
|
||||
} from "../helpers";
|
||||
import { telemetryListener } from "../telemetry";
|
||||
import { redactableError } from "../pure/errors";
|
||||
import { DataFlowPathsView } from "./data-flow-paths-view";
|
||||
import { DataFlowPaths } from "./shared/data-flow-paths";
|
||||
|
||||
export class VariantAnalysisView
|
||||
extends AbstractWebview<ToVariantAnalysisMessage, FromVariantAnalysisMessage>
|
||||
implements VariantAnalysisViewInterface
|
||||
{
|
||||
public static readonly viewType = "codeQL.variantAnalysis";
|
||||
private readonly dataFlowPathsView: DataFlowPathsView;
|
||||
|
||||
public constructor(
|
||||
ctx: ExtensionContext,
|
||||
@@ -36,6 +39,8 @@ export class VariantAnalysisView
|
||||
super(ctx);
|
||||
|
||||
manager.registerView(this);
|
||||
|
||||
this.dataFlowPathsView = new DataFlowPathsView(ctx);
|
||||
}
|
||||
|
||||
public async openView() {
|
||||
@@ -151,6 +156,9 @@ export class VariantAnalysisView
|
||||
this.variantAnalysisId,
|
||||
);
|
||||
break;
|
||||
case "showDataFlowPaths":
|
||||
await this.showDataFlows(msg.dataFlowPaths);
|
||||
break;
|
||||
case "telemetry":
|
||||
telemetryListener?.sendUIInteraction(msg.action);
|
||||
break;
|
||||
@@ -201,4 +209,8 @@ export class VariantAnalysisView
|
||||
? `${variantAnalysis.query.name} - Variant Analysis Results`
|
||||
: `Variant Analysis ${this.variantAnalysisId} - Results`;
|
||||
}
|
||||
|
||||
private async showDataFlows(dataFlows: DataFlowPaths): Promise<void> {
|
||||
await this.dataFlowPathsView.showDataFlows(dataFlows);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import * as React from "react";
|
||||
import { useRef, useState } from "react";
|
||||
import styled from "styled-components";
|
||||
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react";
|
||||
|
||||
import { Overlay, ThemeProvider } from "@primer/react";
|
||||
|
||||
import {
|
||||
AnalysisMessage,
|
||||
CodeFlow,
|
||||
ResultSeverity,
|
||||
} from "../../../variant-analysis/shared/analysis-result";
|
||||
import { CodePathsOverlay } from "./CodePathsOverlay";
|
||||
import { useTelemetryOnChange } from "../telemetry";
|
||||
import { vscode } from "../../vscode-api";
|
||||
|
||||
const ShowPathsLink = styled(VSCodeLink)`
|
||||
cursor: pointer;
|
||||
@@ -24,46 +20,27 @@ export type CodePathsProps = {
|
||||
severity: ResultSeverity;
|
||||
};
|
||||
|
||||
const filterIsOpenTelemetry = (v: boolean) => v;
|
||||
|
||||
export const CodePaths = ({
|
||||
codeFlows,
|
||||
ruleDescription,
|
||||
message,
|
||||
severity,
|
||||
}: CodePathsProps) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
useTelemetryOnChange(isOpen, "code-path-is-open", {
|
||||
filterTelemetryOnValue: filterIsOpenTelemetry,
|
||||
});
|
||||
|
||||
const linkRef = useRef<HTMLAnchorElement>(null);
|
||||
|
||||
const closeOverlay = () => setIsOpen(false);
|
||||
const onShowPathsClick = () => {
|
||||
vscode.postMessage({
|
||||
t: "showDataFlowPaths",
|
||||
dataFlowPaths: {
|
||||
codeFlows,
|
||||
ruleDescription,
|
||||
message,
|
||||
severity,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ShowPathsLink onClick={() => setIsOpen(true)} ref={linkRef}>
|
||||
Show paths
|
||||
</ShowPathsLink>
|
||||
{isOpen && (
|
||||
<ThemeProvider colorMode="auto">
|
||||
<Overlay
|
||||
returnFocusRef={linkRef}
|
||||
onEscape={closeOverlay}
|
||||
onClickOutside={closeOverlay}
|
||||
anchorSide="outside-top"
|
||||
>
|
||||
<CodePathsOverlay
|
||||
codeFlows={codeFlows}
|
||||
ruleDescription={ruleDescription}
|
||||
message={message}
|
||||
severity={severity}
|
||||
onClose={closeOverlay}
|
||||
/>
|
||||
</Overlay>
|
||||
</ThemeProvider>
|
||||
)}
|
||||
<ShowPathsLink onClick={onShowPathsClick}>Show paths</ShowPathsLink>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { useState } from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
import {
|
||||
AnalysisMessage,
|
||||
CodeFlow,
|
||||
ResultSeverity,
|
||||
} from "../../../variant-analysis/shared/analysis-result";
|
||||
import { useTelemetryOnChange } from "../telemetry";
|
||||
import { SectionTitle } from "../SectionTitle";
|
||||
import { VerticalSpace } from "../VerticalSpace";
|
||||
import { CodeFlowsDropdown } from "./CodeFlowsDropdown";
|
||||
import { CodePath } from "./CodePath";
|
||||
|
||||
const StyledCloseButton = styled.button`
|
||||
position: absolute;
|
||||
top: 1em;
|
||||
right: 4em;
|
||||
background-color: var(--vscode-editor-background);
|
||||
color: var(--vscode-editor-foreground);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const OverlayContainer = styled.div`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 2em;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: var(--vscode-editor-background);
|
||||
color: var(--vscode-editor-foreground);
|
||||
overflow-y: scroll;
|
||||
`;
|
||||
|
||||
const CloseButton = ({ onClick }: { onClick: () => void }) => (
|
||||
<StyledCloseButton onClick={onClick} tabIndex={-1}>
|
||||
<span className="codicon codicon-chrome-close" />
|
||||
</StyledCloseButton>
|
||||
);
|
||||
|
||||
const PathsContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const PathDetailsContainer = styled.div`
|
||||
padding: 0;
|
||||
border: 0;
|
||||
`;
|
||||
|
||||
const PathDropdownContainer = styled.div`
|
||||
flex-grow: 1;
|
||||
padding: 0 0 0 0.2em;
|
||||
border: none;
|
||||
`;
|
||||
|
||||
type CodePathsOverlayProps = {
|
||||
codeFlows: CodeFlow[];
|
||||
ruleDescription: string;
|
||||
message: AnalysisMessage;
|
||||
severity: ResultSeverity;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export const CodePathsOverlay = ({
|
||||
codeFlows,
|
||||
ruleDescription,
|
||||
message,
|
||||
severity,
|
||||
onClose,
|
||||
}: CodePathsOverlayProps) => {
|
||||
const [selectedCodeFlow, setSelectedCodeFlow] = useState(codeFlows[0]);
|
||||
useTelemetryOnChange(selectedCodeFlow, "code-flow-selected");
|
||||
|
||||
return (
|
||||
<OverlayContainer>
|
||||
<CloseButton onClick={onClose} />
|
||||
|
||||
<SectionTitle>{ruleDescription}</SectionTitle>
|
||||
<VerticalSpace size={2} />
|
||||
|
||||
<PathsContainer>
|
||||
<PathDetailsContainer>
|
||||
{codeFlows.length} paths available:{" "}
|
||||
{selectedCodeFlow.threadFlows.length} steps in
|
||||
</PathDetailsContainer>
|
||||
<PathDropdownContainer>
|
||||
<CodeFlowsDropdown
|
||||
codeFlows={codeFlows}
|
||||
setSelectedCodeFlow={setSelectedCodeFlow}
|
||||
/>
|
||||
</PathDropdownContainer>
|
||||
</PathsContainer>
|
||||
|
||||
<VerticalSpace size={2} />
|
||||
<CodePath
|
||||
codeFlow={selectedCodeFlow}
|
||||
severity={severity}
|
||||
message={message}
|
||||
/>
|
||||
<VerticalSpace size={3} />
|
||||
</OverlayContainer>
|
||||
);
|
||||
};
|
||||
@@ -18,20 +18,25 @@ describe(CodePaths.name, () => {
|
||||
/>,
|
||||
);
|
||||
|
||||
it("renders correctly when unexpanded", () => {
|
||||
it("renders 'show paths' link", () => {
|
||||
render();
|
||||
|
||||
expect(screen.getByText("Show paths")).toBeInTheDocument();
|
||||
expect(screen.queryByText("Code snippet text")).not.toBeInTheDocument();
|
||||
expect(screen.queryByText("Rule description")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders correctly when expanded", async () => {
|
||||
it("posts extension message when 'show paths' link clicked", async () => {
|
||||
render();
|
||||
|
||||
await userEvent.click(screen.getByText("Show paths"));
|
||||
|
||||
expect(screen.getByText("Code snippet text")).toBeInTheDocument();
|
||||
expect(screen.getByText("Rule description")).toBeInTheDocument();
|
||||
expect((window as any).vsCodeApi.postMessage).toHaveBeenCalledWith({
|
||||
t: "showDataFlowPaths",
|
||||
dataFlowPaths: {
|
||||
codeFlows: createMockCodeFlows(),
|
||||
ruleDescription: "Rule description",
|
||||
message: createMockAnalysisMessage(),
|
||||
severity: "Recommendation",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import * as React from "react";
|
||||
import styled from "styled-components";
|
||||
import { useState } from "react";
|
||||
|
||||
import { useTelemetryOnChange } from "../common/telemetry";
|
||||
import { CodeFlowsDropdown } from "../common/CodePaths/CodeFlowsDropdown";
|
||||
import { SectionTitle, VerticalSpace } from "../common";
|
||||
import { CodePath } from "../common/CodePaths/CodePath";
|
||||
import { DataFlowPaths as DataFlowPathsDomainModel } from "../../variant-analysis/shared/data-flow-paths";
|
||||
|
||||
const PathsContainer = styled.div`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const PathDetailsContainer = styled.div`
|
||||
padding: 0;
|
||||
border: 0;
|
||||
`;
|
||||
|
||||
const PathDropdownContainer = styled.div`
|
||||
flex-grow: 1;
|
||||
padding: 0 0 0 0.2em;
|
||||
border: none;
|
||||
`;
|
||||
|
||||
export type DataFlowPathsProps = {
|
||||
dataFlowPaths: DataFlowPathsDomainModel;
|
||||
};
|
||||
|
||||
export const DataFlowPaths = ({
|
||||
dataFlowPaths,
|
||||
}: {
|
||||
dataFlowPaths: DataFlowPathsDomainModel;
|
||||
}): JSX.Element => {
|
||||
const [selectedCodeFlow, setSelectedCodeFlow] = useState(
|
||||
dataFlowPaths.codeFlows[0],
|
||||
);
|
||||
useTelemetryOnChange(selectedCodeFlow, "code-flow-selected");
|
||||
|
||||
const { codeFlows, ruleDescription, message, severity } = dataFlowPaths;
|
||||
|
||||
return (
|
||||
<>
|
||||
<VerticalSpace size={2} />
|
||||
<SectionTitle>{ruleDescription}</SectionTitle>
|
||||
<VerticalSpace size={2} />
|
||||
|
||||
<PathsContainer>
|
||||
<PathDetailsContainer>
|
||||
{codeFlows.length} paths available:{" "}
|
||||
{selectedCodeFlow?.threadFlows.length} steps in
|
||||
</PathDetailsContainer>
|
||||
<PathDropdownContainer>
|
||||
<CodeFlowsDropdown
|
||||
codeFlows={codeFlows}
|
||||
setSelectedCodeFlow={setSelectedCodeFlow}
|
||||
/>
|
||||
</PathDropdownContainer>
|
||||
</PathsContainer>
|
||||
|
||||
<VerticalSpace size={2} />
|
||||
<CodePath
|
||||
codeFlow={selectedCodeFlow}
|
||||
severity={severity}
|
||||
message={message}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,18 +1,19 @@
|
||||
import * as React from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { ToDataFlowPathsMessage } from "../../pure/interface-types";
|
||||
import { DataFlowPaths } from "../../variant-analysis/shared/data-flow-paths";
|
||||
import { DataFlowPaths as DataFlowPathsDomainModel } from "../../variant-analysis/shared/data-flow-paths";
|
||||
import { DataFlowPaths } from "./DataFlowPaths";
|
||||
|
||||
export type DataFlowPathsViewProps = {
|
||||
dataFlowPaths?: DataFlowPaths;
|
||||
dataFlowPaths?: DataFlowPathsDomainModel;
|
||||
};
|
||||
|
||||
export function DataFlowPathsView({
|
||||
dataFlowPaths: initialDataFlowPaths,
|
||||
}: DataFlowPathsViewProps): JSX.Element {
|
||||
const [dataFlowPaths, setDataFlowPaths] = useState<DataFlowPaths | undefined>(
|
||||
initialDataFlowPaths,
|
||||
);
|
||||
const [dataFlowPaths, setDataFlowPaths] = useState<
|
||||
DataFlowPathsDomainModel | undefined
|
||||
>(initialDataFlowPaths);
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (evt: MessageEvent) => {
|
||||
@@ -20,6 +21,10 @@ export function DataFlowPathsView({
|
||||
const msg: ToDataFlowPathsMessage = evt.data;
|
||||
if (msg.t === "setDataFlowPaths") {
|
||||
setDataFlowPaths(msg.dataFlowPaths);
|
||||
|
||||
// Scroll to the top of the page when we're rendering
|
||||
// new data flow paths.
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
} else {
|
||||
// sanitize origin
|
||||
@@ -38,11 +43,5 @@ export function DataFlowPathsView({
|
||||
return <>Loading data flow paths</>;
|
||||
}
|
||||
|
||||
// For now, just render the data flows as JSON.
|
||||
return (
|
||||
<>
|
||||
Loaded
|
||||
<pre>{JSON.stringify(dataFlowPaths)}</pre>
|
||||
</>
|
||||
);
|
||||
return <DataFlowPaths dataFlowPaths={dataFlowPaths} />;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import * as React from "react";
|
||||
import { render as reactRender, screen } from "@testing-library/react";
|
||||
import { DataFlowPaths, DataFlowPathsProps } from "../DataFlowPaths";
|
||||
import { createMockDataFlowPaths } from "../../../../test/factories/variant-analysis/shared/data-flow-paths";
|
||||
|
||||
describe(DataFlowPaths.name, () => {
|
||||
const render = (props: DataFlowPathsProps) =>
|
||||
reactRender(<DataFlowPaths {...props} />);
|
||||
|
||||
it("renders data flow paths", () => {
|
||||
const dataFlowPaths = createMockDataFlowPaths();
|
||||
|
||||
render({ dataFlowPaths });
|
||||
|
||||
expect(screen.getByText(dataFlowPaths.ruleDescription)).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("1 paths available", { exact: false }),
|
||||
).toBeInTheDocument();
|
||||
expect(
|
||||
screen.getByText("3 steps in", {
|
||||
exact: false,
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
|
||||
expect(
|
||||
screen.getByText("This zip file may have a dangerous path", {
|
||||
exact: false,
|
||||
}),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
DataFlowPathsView,
|
||||
DataFlowPathsViewProps,
|
||||
} from "../DataFlowPathsView";
|
||||
import { createMockCodeFlows } from "../../../../test/factories/variant-analysis/shared/CodeFlow";
|
||||
import { createMockDataFlowPaths } from "../../../../test/factories/variant-analysis/shared/data-flow-paths";
|
||||
|
||||
describe(DataFlowPathsView.name, () => {
|
||||
@@ -17,8 +18,14 @@ describe(DataFlowPathsView.name, () => {
|
||||
});
|
||||
|
||||
it("renders a data flow paths view", () => {
|
||||
render({ dataFlowPaths: createMockDataFlowPaths() });
|
||||
const dataFlowPaths = createMockDataFlowPaths({
|
||||
ruleDescription: "Rule description",
|
||||
codeFlows: createMockCodeFlows(),
|
||||
});
|
||||
|
||||
expect(screen.getByText("Loaded")).toBeInTheDocument();
|
||||
render({ dataFlowPaths });
|
||||
|
||||
expect(screen.queryByText("Code snippet text")).toBeInTheDocument();
|
||||
expect(screen.getByText("Rule description")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,106 +1,122 @@
|
||||
import { CodeFlow } from "../../../../src/variant-analysis/shared/analysis-result";
|
||||
import {
|
||||
AnalysisMessage,
|
||||
CodeFlow,
|
||||
ResultSeverity,
|
||||
} from "../../../../src/variant-analysis/shared/analysis-result";
|
||||
import { DataFlowPaths } from "../../../../src/variant-analysis/shared/data-flow-paths";
|
||||
|
||||
export function createMockDataFlowPaths(): DataFlowPaths {
|
||||
const codeFlows: CodeFlow[] = [
|
||||
{
|
||||
threadFlows: [
|
||||
{
|
||||
fileLink: {
|
||||
fileLinkPrefix:
|
||||
"https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff",
|
||||
filePath:
|
||||
"src/System.Management.Automation/help/UpdatableHelpSystem.cs",
|
||||
},
|
||||
codeSnippet: {
|
||||
startLine: 1260,
|
||||
endLine: 1260,
|
||||
text: " string extractPath = Path.Combine(destination, entry.FullName);",
|
||||
},
|
||||
highlightedRegion: {
|
||||
startLine: 1260,
|
||||
startColumn: 72,
|
||||
endLine: 1260,
|
||||
endColumn: 86,
|
||||
},
|
||||
message: {
|
||||
tokens: [
|
||||
{
|
||||
t: "text",
|
||||
text: "access to property FullName : String",
|
||||
},
|
||||
],
|
||||
},
|
||||
const defaultCodeFlows: CodeFlow[] = [
|
||||
{
|
||||
threadFlows: [
|
||||
{
|
||||
fileLink: {
|
||||
fileLinkPrefix:
|
||||
"https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff",
|
||||
filePath:
|
||||
"src/System.Management.Automation/help/UpdatableHelpSystem.cs",
|
||||
},
|
||||
{
|
||||
fileLink: {
|
||||
fileLinkPrefix:
|
||||
"https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff",
|
||||
filePath:
|
||||
"src/System.Management.Automation/help/UpdatableHelpSystem.cs",
|
||||
},
|
||||
codeSnippet: {
|
||||
startLine: 1260,
|
||||
endLine: 1260,
|
||||
text: " string extractPath = Path.Combine(destination, entry.FullName);",
|
||||
},
|
||||
highlightedRegion: {
|
||||
startLine: 1260,
|
||||
startColumn: 46,
|
||||
endLine: 1260,
|
||||
endColumn: 87,
|
||||
},
|
||||
message: {
|
||||
tokens: [
|
||||
{
|
||||
t: "text",
|
||||
text: "call to method Combine : String",
|
||||
},
|
||||
],
|
||||
},
|
||||
codeSnippet: {
|
||||
startLine: 1260,
|
||||
endLine: 1260,
|
||||
text: " string extractPath = Path.Combine(destination, entry.FullName);",
|
||||
},
|
||||
{
|
||||
fileLink: {
|
||||
fileLinkPrefix:
|
||||
"https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff",
|
||||
filePath:
|
||||
"src/System.Management.Automation/help/UpdatableHelpSystem.cs",
|
||||
},
|
||||
codeSnippet: {
|
||||
startLine: 1261,
|
||||
endLine: 1261,
|
||||
text: " entry.ExtractToFile(extractPath);",
|
||||
},
|
||||
highlightedRegion: {
|
||||
startLine: 1261,
|
||||
startColumn: 45,
|
||||
endLine: 1261,
|
||||
endColumn: 56,
|
||||
},
|
||||
message: {
|
||||
tokens: [
|
||||
{
|
||||
t: "text",
|
||||
text: "access to local variable extractPath",
|
||||
},
|
||||
],
|
||||
},
|
||||
highlightedRegion: {
|
||||
startLine: 1260,
|
||||
startColumn: 72,
|
||||
endLine: 1260,
|
||||
endColumn: 86,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
message: {
|
||||
tokens: [
|
||||
{
|
||||
t: "text",
|
||||
text: "access to property FullName : String",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
fileLink: {
|
||||
fileLinkPrefix:
|
||||
"https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff",
|
||||
filePath:
|
||||
"src/System.Management.Automation/help/UpdatableHelpSystem.cs",
|
||||
},
|
||||
codeSnippet: {
|
||||
startLine: 1260,
|
||||
endLine: 1260,
|
||||
text: " string extractPath = Path.Combine(destination, entry.FullName);",
|
||||
},
|
||||
highlightedRegion: {
|
||||
startLine: 1260,
|
||||
startColumn: 46,
|
||||
endLine: 1260,
|
||||
endColumn: 87,
|
||||
},
|
||||
message: {
|
||||
tokens: [
|
||||
{
|
||||
t: "text",
|
||||
text: "call to method Combine : String",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
fileLink: {
|
||||
fileLinkPrefix:
|
||||
"https://github.com/PowerShell/PowerShell/blob/450d884668ca477c6581ce597958f021fac30bff",
|
||||
filePath:
|
||||
"src/System.Management.Automation/help/UpdatableHelpSystem.cs",
|
||||
},
|
||||
codeSnippet: {
|
||||
startLine: 1261,
|
||||
endLine: 1261,
|
||||
text: " entry.ExtractToFile(extractPath);",
|
||||
},
|
||||
highlightedRegion: {
|
||||
startLine: 1261,
|
||||
startColumn: 45,
|
||||
endLine: 1261,
|
||||
endColumn: 56,
|
||||
},
|
||||
message: {
|
||||
tokens: [
|
||||
{
|
||||
t: "text",
|
||||
text: "access to local variable extractPath",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const defaultMessage: AnalysisMessage = {
|
||||
tokens: [
|
||||
{
|
||||
t: "text",
|
||||
text: "This zip file may have a dangerous path",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export function createMockDataFlowPaths({
|
||||
codeFlows = defaultCodeFlows,
|
||||
ruleDescription = "ZipSlip vulnerability",
|
||||
message = defaultMessage,
|
||||
severity = "Warning",
|
||||
}: {
|
||||
codeFlows?: CodeFlow[];
|
||||
ruleDescription?: string;
|
||||
message?: AnalysisMessage;
|
||||
severity?: ResultSeverity;
|
||||
} = {}): DataFlowPaths {
|
||||
return {
|
||||
codeFlows,
|
||||
ruleDescription: "ZipSlip vulnerability",
|
||||
message: {
|
||||
tokens: [
|
||||
{
|
||||
t: "text",
|
||||
text: "This zip file may have a dangerous path",
|
||||
},
|
||||
],
|
||||
},
|
||||
severity: "Warning",
|
||||
ruleDescription,
|
||||
message,
|
||||
severity,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user