Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/two-dodos-drum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"vscode-ui5-language-assistant": patch
"@ui5-language-assistant/vscode-ui5-language-assistant-bas-ext": patch
---

fix: sanitize adaptive card schema URL
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axios from "axios";
import fs from "fs/promises";
import { join } from "path";
import prettier from "prettier";
import { getSchemaUri } from "../../src/utils";
import { getSchemaUri, sanitizeAdaptiveCardUrl } from "../../src/utils";

const BASE_PATH = join(process.cwd(), "src", "manifest");
const ADAPTIVE_CARD_LOCATION = join(BASE_PATH, "adaptive-card.json");
Expand Down Expand Up @@ -77,10 +77,7 @@ async function updateManifestSchema() {
for (const version of versions) {
const SCHEMA_URI = getSchemaUri(version);
const content = await axiosGetRequest(SCHEMA_URI);
const finalString = content.replace(
/"(https:\/\/adaptivecards\.io[^"]*)"/,
`"/manifest/adaptive-card.json"`
);
const finalString = sanitizeAdaptiveCardUrl(content);
const prettifiedContent = prettifyFileContent(SCHEMA_URI, finalString);
await fs.writeFile(
join(BASE_PATH, `schema-v${version}.json`),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import {
} from "vscode";
import { tryFetch } from "@ui5-language-assistant/logic-utils";
import { MANIFEST_SCHEMA } from "./constants";
import { getSchemaContent, getSchemaUri } from "./utils";
import {
getSchemaContent,
getSchemaUri,
sanitizeAdaptiveCardUrl,
} from "./utils";
import {
findManifestPath,
getUI5Manifest,
Expand Down Expand Up @@ -75,6 +79,7 @@ export const getManifestSchemaProvider = async (
const response = await tryFetch(SCHEMA_URI);
if (response) {
content = await response.text();
content = sanitizeAdaptiveCardUrl(content);
} else {
// fallback to local schema which is based on main branch
content = await getSchemaContent(context, version);
Expand Down
7 changes: 7 additions & 0 deletions packages/vscode-ui5-language-assistant/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,10 @@ export {
export function getSchemaUri(version: string): string {
return `https://raw.githubusercontent.com/UI5/manifest/refs/tags/v${version}/schema.json`;
}

export function sanitizeAdaptiveCardUrl(content: string): string {
return content.replace(
/"(https:\/\/adaptivecards\.io[^"]*)"/,
`"/manifest/adaptive-card.json"`
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ describe("Manifest schema provider", () => {
expect(result.schemaContent).toBe("schema content from web");
});

it("sanitizes adaptivecards.io URL in schema fetched from web", async () => {
const rawContent = `{"$ref": "https://adaptivecards.io/schemas/adaptive-card.json"}`;
jest.spyOn(logicUtils, "tryFetch").mockResolvedValue({
text: () => rawContent,
} as unknown as Response);

getUI5ManifestSpy.mockResolvedValue({ _version: "1.58.0" });

const result = await getManifestSchemaProvider(fakeExtensionContext);

expect(result.schemaContent).toBe(
`{"$ref": "/manifest/adaptive-card.json"}`
);
});

it("loads schema from local when web fetch fails", async () => {
const fetchSpy = jest
.spyOn(logicUtils, "tryFetch")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { ExtensionContext } from "vscode";
import { getSchemaContent, getSchemaUri } from "../../../src/utils";
import {
getSchemaContent,
getSchemaUri,
sanitizeAdaptiveCardUrl,
} from "../../../src/utils";
import { getLogger } from "../../../src/logger";
import { readFile, readdir } from "fs/promises";

Expand Down Expand Up @@ -163,3 +167,23 @@ describe("getSchemaUri", () => {
);
});
});

describe("sanitizeAdaptiveCardUrl", () => {
it("replaces adaptivecards.io URL with local path", () => {
const input = `{"$ref": "https://adaptivecards.io/schemas/adaptive-card.json"}`;
const result = sanitizeAdaptiveCardUrl(input);
expect(result).toBe(`{"$ref": "/manifest/adaptive-card.json"}`);
});

it("replaces any adaptivecards.io URL variant", () => {
const input = `{"$ref": "https://adaptivecards.io/schemas/other-path.json"}`;
const result = sanitizeAdaptiveCardUrl(input);
expect(result).toBe(`{"$ref": "/manifest/adaptive-card.json"}`);
});

it("leaves content unchanged when no adaptivecards.io URL is present", () => {
const input = `{"$ref": "https://example.com/schema.json"}`;
const result = sanitizeAdaptiveCardUrl(input);
expect(result).toBe(input);
});
});
Loading