Merge branch 'microsoft:master' into ross/devcontainer.json

This commit is contained in:
Ross Smith 2023-10-17 13:35:18 +01:00 коммит произвёл GitHub
Родитель 153bac76e6 6e590a25b7
Коммит 42823f3aa5
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 11747 добавлений и 223 удалений

Просмотреть файл

@ -2,6 +2,23 @@
All notable changes to the "Azure Api Management VS Code" extension will be documented in this file.
## [1.0.8 - 2023-09-12]
- Fixed loading API Management instances when expanding an Azure subscription
## [1.0.7 - 2023-09-08]
- Update api-version to 2019-12-01
- Fix issue with policy debugging
## [1.0.6 - 2023-05-06]
- Overridding fevents version to move off a vulnerable package
## [1.0.5 - 2022-06-24]
- Enable Authorizations in Consumption Sku
## [1.0.4 - 2022-06-05]
- Update to latest API Management devops resource kit

11743
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -2,7 +2,7 @@
"name": "vscode-apimanagement",
"displayName": "Azure API Management",
"description": "An Azure API Management extension for Visual Studio Code.",
"version": "1.0.6",
"version": "1.0.8",
"publisher": "ms-azuretools",
"icon": "resources/apim-icon-newone.png",
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
@ -820,7 +820,7 @@
"webpack-profile": "webpack --profile --json --mode production > webpack-stats.json && echo Use http://webpack.github.io/analyse to analyze the stats"
},
"devDependencies": {
"@azure/ms-rest-js": "^2.2.0",
"@azure/ms-rest-js": "^2.7.0",
"@types/fs-extra": "^4.0.3",
"@types/gulp": "^4.0.6",
"@types/mocha": "^5.2.6",

Просмотреть файл

@ -6,7 +6,22 @@
import { HttpOperationResponse, ServiceClient } from "@azure/ms-rest-js";
import { TokenCredentialsBase } from "@azure/ms-rest-nodeauth";
import { createGenericClient } from "vscode-azureextensionui";
import { IApimServiceContract, IAuthorizationAccessPolicyContract, IAuthorizationAccessPolicyPropertiesContract, IAuthorizationContract, IAuthorizationLoginLinkRequest, IAuthorizationLoginLinkResponse, IAuthorizationPropertiesContract, IAuthorizationProviderContract, IAuthorizationProviderPropertiesContract, IGatewayApiContract, IGatewayContract, IMasterSubscription, ITokenStoreIdentityProviderContract } from "./contracts";
import * as Constants from "../../constants";
import {
IApimServiceContract,
IAuthorizationAccessPolicyContract,
IAuthorizationAccessPolicyPropertiesContract,
IAuthorizationContract,
IAuthorizationLoginLinkRequest,
IAuthorizationLoginLinkResponse,
IAuthorizationPropertiesContract,
IAuthorizationProviderContract,
IAuthorizationProviderPropertiesContract,
IGatewayApiContract,
IGatewayContract,
IMasterSubscriptionsSecrets,
ITokenStoreIdentityProviderContract
} from "./contracts";
export class ApimService {
public baseUrl: string;
@ -15,7 +30,6 @@ export class ApimService {
public subscriptionId: string;
public resourceGroup: string;
public serviceName: string;
private readonly apiVersion: string = "2018-06-01-preview";
private readonly authorizationProviderApiVersion: string = "2021-12-01-preview";
constructor(credentials: TokenCredentialsBase, endPointUrl: string, subscriptionId: string, resourceGroup: string, serviceName: string) {
@ -31,7 +45,7 @@ export class ApimService {
const client: ServiceClient = await createGenericClient(this.credentials);
const result: HttpOperationResponse = await client.sendRequest({
method: "GET",
url: `${this.baseUrl}/gateways?api-version=${this.apiVersion}&$top=100`
url: `${this.baseUrl}/gateways?api-version=${Constants.apimApiVersion}&$top=100`
});
// tslint:disable-next-line: no-unsafe-any
return <IGatewayContract[]>(result.parsedBody.value);
@ -41,7 +55,7 @@ export class ApimService {
const client: ServiceClient = await createGenericClient(this.credentials);
const result: HttpOperationResponse = await client.sendRequest({
method: "GET",
url: `${this.baseUrl}/gateways/${gatewayName}/apis?api-version=${this.apiVersion}&$top=100`
url: `${this.baseUrl}/gateways/${gatewayName}/apis?api-version=${Constants.apimApiVersion}&$top=100`
});
// tslint:disable-next-line: no-unsafe-any
return <IGatewayApiContract[]>(result.parsedBody.value);
@ -51,7 +65,7 @@ export class ApimService {
const client: ServiceClient = await createGenericClient(this.credentials);
const result: HttpOperationResponse = await client.sendRequest({
method: "PUT",
url: `${this.baseUrl}/gateways/${gatewayName}/apis/${apiName}?api-version=${this.apiVersion}`
url: `${this.baseUrl}/gateways/${gatewayName}/apis/${apiName}?api-version=${Constants.apimApiVersion}`
});
// tslint:disable-next-line: no-unsafe-any
return <IGatewayApiContract>(result.parsedBody);
@ -61,7 +75,7 @@ export class ApimService {
const client: ServiceClient = await createGenericClient(this.credentials);
await client.sendRequest({
method: "DELETE",
url: `${this.baseUrl}/gateways/${gatewayName}/apis/${apiName}?api-version=${this.apiVersion}`
url: `${this.baseUrl}/gateways/${gatewayName}/apis/${apiName}?api-version=${Constants.apimApiVersion}`
});
}
@ -72,7 +86,7 @@ export class ApimService {
const client: ServiceClient = await createGenericClient(this.credentials);
const result: HttpOperationResponse = await client.sendRequest({
method: "POST",
url: `https://management.azure.com/subscriptions/${this.subscriptionId}/resourceGroups/${this.resourceGroup}/providers/Microsoft.ApiManagement/service/${this.serviceName}/gateways/${gatewayName}/token?api-version=2018-06-01-preview`,
url: `https://management.azure.com/subscriptions/${this.subscriptionId}/resourceGroups/${this.resourceGroup}/providers/Microsoft.ApiManagement/service/${this.serviceName}/gateways/${gatewayName}/token?api-version=${Constants.apimApiVersion}`,
body: {
keyType: keyType,
expiry: expiryDate
@ -82,12 +96,13 @@ export class ApimService {
return result.parsedBody.value;
}
public async getSubscriptionMasterkey(): Promise<IMasterSubscription> {
public async getSubscriptionMasterkey(): Promise<IMasterSubscriptionsSecrets> {
const client: ServiceClient = await createGenericClient(this.credentials);
const result: HttpOperationResponse = await client.sendRequest({
method: "GET",
url: `${this.baseUrl}/subscriptions/master?api-version=${this.apiVersion}`
method: "POST",
url: `${this.baseUrl}/subscriptions/master/listSecrets?api-version=${Constants.apimApiVersion}`
});
// tslint:disable-next-line: no-unsafe-any
return result.parsedBody;
}
@ -241,7 +256,7 @@ export class ApimService {
return undefined;
}
// tslint:disable-next-line: no-unsafe-any
// tslint:disable-next-line: no-unsafe-any
return <IAuthorizationProviderContract>(result.parsedBody);
}
@ -260,7 +275,7 @@ export class ApimService {
const client: ServiceClient = await createGenericClient(this.credentials);
const result: HttpOperationResponse = await client.sendRequest({
method: "GET",
url: `${this.baseUrl}?api-version=${this.apiVersion}`
url: `${this.baseUrl}?api-version=${Constants.apimApiVersion}`
});
// tslint:disable-next-line:no-any
return <IApimServiceContract>(result.parsedBody);
@ -270,10 +285,10 @@ export class ApimService {
const client: ServiceClient = await createGenericClient(this.credentials);
const result: HttpOperationResponse = await client.sendRequest({
method: "PATCH",
url: `${this.baseUrl}?api-version=${this.apiVersion}`,
body: { identity : { type: "systemassigned" } }
url: `${this.baseUrl}?api-version=${Constants.apimApiVersion}`,
body: { identity: { type: "systemassigned" } }
});
// tslint:disable-next-line:no-any
// tslint:disable-next-line:no-any
return <IApimServiceContract>(result.parsedBody);
}

Просмотреть файл

@ -3,6 +3,21 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface IArmResource {
id: string;
// tslint:disable-next-line: no-reserved-keywords
type: string;
name: string;
// tslint:disable-next-line:no-any
properties: any;
}
export interface IPaged<T> {
value: T[];
count: number;
nextLink?: string;
}
export interface IApimServiceContract {
id: string;
name: string;
@ -49,11 +64,16 @@ export interface IGatewayTokenList {
}
export interface IMasterSubscription {
id : string;
name : string;
id: string;
name: string;
properties: ISubscriptionProperty;
}
export interface IMasterSubscriptionsSecrets {
primaryKey: string;
secondaryKey: string;
}
export interface ISubscriptionProperty {
displayName: string;
primaryKey: string;

Просмотреть файл

@ -62,7 +62,7 @@ function getManagementUrl(root: IOperationTreeRoot): string {
async function getDebugGatewayAddressUrl(node: ApiOperationTreeItem): Promise<string> {
// tslint:disable-next-line: prefer-template
const gatewayUrl : string | undefined = ext.context.globalState.get(node.root.serviceName + gatewayHostName);
const gatewayUrl: string | undefined = ext.context.globalState.get(node.root.serviceName + gatewayHostName);
if (gatewayUrl !== undefined) {
return `wss://${gatewayUrl}/debug-0123456789abcdef`;
}
@ -73,7 +73,7 @@ async function getDebugGatewayAddressUrl(node: ApiOperationTreeItem): Promise<st
let gatewayHostNameUl = "";
if (hostNameConfigs.length > 1) {
const allHostNames = hostNameConfigs.filter((s) => (s.type === "Proxy"));
const pick = await ext.ui.showQuickPick(allHostNames.map((s) => { return {label: s.hostName, gateway: s}; }), { canPickMany: false});
const pick = await ext.ui.showQuickPick(allHostNames.map((s) => { return { label: s.hostName, gateway: s }; }), { canPickMany: false });
gatewayHostNameUl = `wss://${pick.gateway.hostName}/debug-0123456789abcdef`;
} else {
gatewayHostNameUl = `wss://${hostNameConfigs[0].hostName}/debug-0123456789abcdef`;

Просмотреть файл

@ -95,7 +95,7 @@ function getDockerRunCommand(token: string, confEndpoint: string, gatewayName: s
}
function getConfigEndpointUrl(node: GatewayTreeItem): string {
return `"https://${node!.root.serviceName}.management.azure-api.net/subscriptions/${node!.root.subscriptionId}/resourceGroups/${node!.root.resourceGroupName}/providers/Microsoft.ApiManagement/service/${node!.root.serviceName}?api-version=2018-06-01-preview"`;
return `"https://${node!.root.serviceName}.management.azure-api.net/subscriptions/${node!.root.subscriptionId}/resourceGroups/${node!.root.resourceGroupName}/providers/Microsoft.ApiManagement/service/${node!.root.serviceName}?api-version=${Constants.apimApiVersion}"`;
}
function generateDeploymentYaml(gatewayName: string, gatewayToken: string, gatewayEndpoint: string): string {

Просмотреть файл

@ -63,7 +63,7 @@ async function extract(node: ApiTreeItem | ServiceTreeItem, apiName?: string): P
},
async () => {
await azUtils.checkAzInstalled();
await dotnetUtils.checkDotnetInstalled();
await dotnetUtils.validateDotnetInstalled();
await runExtractor(configFile, subscriptionId);
}
).then(
@ -104,20 +104,16 @@ async function runExtractor(filePath: string, subscriptionId: string): Promise<v
subscriptionId
);
if (await dotnetUtils.checkDotnetVersionInstalled("2.1")) {
await cpUtils.executeCommand(
ext.outputChannel,
workingFolderPath,
'dotnet',
'apimtemplate.dll',
'extract',
'--extractorConfig',
`"${filePath}"`
);
} else {
window.showInformationMessage(localize("dotnetNotInstalled", ".NET framework 2.1 not installed. Please go to 'https://aka.ms/dotnet-core-applaunch?framework=Microsoft.NETCore.App&framework_version=2.1.0&arch=x64&rid=win10-x64' to download"));
throw new Error();
}
await dotnetUtils.validateDotnetInstalled();
await cpUtils.executeCommand(
ext.outputChannel,
workingFolderPath,
'dotnet',
'apimtemplate.dll',
'extract',
'--extractorConfig',
`"${filePath}"`
);
}
async function askFolder(): Promise<Uri[]> {

Просмотреть файл

@ -30,7 +30,7 @@ export enum HttpTriggerDirectionContract {
export const HttpTriggerAuthLevelAdmin = "admin";
export const FunctionAppKeyLength = 40;
export const webAppApiVersion20190801 = "2019-08-01";
export const apimApiVersion = "2019-01-01";
export const apimApiVersion = "2019-12-01";
export const maxTokenValidTimeSpan = 29;
export const gatewayHostName = "CustomerHostName";

Просмотреть файл

@ -7,6 +7,8 @@ import * as request from 'request-promise-native';
import * as vscode from 'vscode';
import { Breakpoint, Handles, InitializedEvent, Logger, logger, LoggingDebugSession, OutputEvent, Scope, StackFrame, StoppedEvent, TerminatedEvent, Thread, ThreadEvent, Variable } from 'vscode-debugadapter';
import { DebugProtocol } from 'vscode-debugprotocol';
import { IArmResource, IMasterSubscriptionsSecrets, IPaged } from "../azure/apim/contracts";
import * as Constants from "../constants";
import { localize } from "../localize";
import { createTemporaryFile } from "../utils/fsUtil";
import { getBearerToken } from '../utils/requestUtil';
@ -387,9 +389,9 @@ export class ApimDebugSession extends LoggingDebugSession {
}
private async getMasterSubscriptionKey(managementAddress: string, credential?: TokenCredentialsBase, managementAuth?: string) {
const resourceUrl = `${managementAddress}/subscriptions/master?api-version=2019-01-01`;
const resourceUrl = `${managementAddress}/subscriptions/master/listSecrets?api-version=${Constants.apimApiVersion}`;
const authToken = managementAuth ? managementAuth : await getBearerToken(resourceUrl, "GET", credential!);
const subscription: IApimSubscription = await request.get(resourceUrl, {
const subscription: IMasterSubscriptionsSecrets = await request.post(resourceUrl, {
headers: {
Authorization: authToken
},
@ -404,13 +406,13 @@ export class ApimDebugSession extends LoggingDebugSession {
}
});
return subscription.properties.primaryKey;
return subscription.primaryKey;
}
private async getAvailablePolicies(managementAddress: string, credential?: TokenCredentialsBase, managementAuth?: string) {
const resourceUrl = `${managementAddress}/policysnippets?api-version=2019-01-01`;
const resourceUrl = `${managementAddress}/policyDescriptions?api-version=${Constants.apimApiVersion}`;
const authToken = managementAuth ? managementAuth : await getBearerToken(resourceUrl, "GET", credential!);
const snippets: IPolicySnippet[] = await request.get(resourceUrl, {
const policyDescriptions: IPaged<IArmResource> = await request.get(resourceUrl, {
headers: {
Authorization: authToken
},
@ -425,19 +427,7 @@ export class ApimDebugSession extends LoggingDebugSession {
}
});
const allPolicies: string[] = [];
let index = 0;
for (const snippet of snippets) {
if (snippet.content !== undefined && snippet.content !== "") {
const idx = /[\s>/]/.exec(snippet.content)!.index;
allPolicies[index] = snippet.content.substring(1, idx);
index += 1;
}
}
// tslint:disable-next-line: no-unnecessary-local-variable
//const allPolicies = snippets.filter(s => s.content !== undefined).map(s => s.content.substring(1, /[\s>/]/.exec(s.content)!.index));
return allPolicies;
return policyDescriptions.value.map(p => p.name);
}
private findThreadByUiId(id: number): [UiRequest, UiThread] | null {
@ -515,14 +505,3 @@ export class ApimDebugSession extends LoggingDebugSession {
}
}
}
interface IApimSubscription {
properties: {
primaryKey: string;
secondaryKey: string;
};
}
interface IPolicySnippet {
content: string;
}

Просмотреть файл

@ -40,7 +40,7 @@ export class DebuggerConnection extends EventEmitter {
public async attach(address: string, key: string, stopOnEntry: boolean) {
let connection: WebSocket;
return new Promise((resolve, reject) => {
return new Promise<void>((resolve, reject) => {
connection = new WebSocket(`${address}?key=${key}`)
.on('error', e => {
if (this.connection == null || this.connection === connection) {

Просмотреть файл

@ -6,6 +6,7 @@ import { TokenCredentialsBase } from "@azure/ms-rest-nodeauth";
import * as path from 'path';
import * as request from 'request-promise-native';
import { Source } from 'vscode-debugadapter';
import * as Constants from "../constants";
import { getBearerToken } from '../utils/requestUtil';
import { StackFrameScopeContract } from './debuggerConnection';
import { PolicyLocation, PolicyMap, PolicyMapper } from './policyMapper';
@ -143,9 +144,9 @@ export class PolicySource {
private getPolicyUrl(scopeId: string): string {
if (scopeId === StackFrameScopeContract.tenant) {
return `${this.managementAddress}/policies/policy?api-version=2019-01-01&format=xml-raw`;
return `${this.managementAddress}/policies/policy?api-version=${Constants.apimApiVersion}&format=xml-raw`;
} else {
return `${this.managementAddress}/${scopeId}/policies/policy?api-version=2019-01-01&format=xml-raw`;
return `${this.managementAddress}/${scopeId}/policies/policy?api-version=${Constants.apimApiVersion}&format=xml-raw`;
}
}
}

Просмотреть файл

@ -8,6 +8,7 @@ import { HttpOperationResponse, RequestPrepareOptions, ServiceClient } from "@az
import { ProgressLocation, window } from "vscode";
import { appendExtensionUserAgent, createGenericClient } from "vscode-azureextensionui";
import { openApiAcceptHeader, openApiExport, openApiSchema, showSavePromptConfigKey, swaggerAcceptHeader, swaggerExport, swaggerSchema } from "../../../constants";
import * as Constants from "../../../constants";
import { localize } from "../../../localize";
import { IOpenApiImportObject } from "../../../openApi/OpenApiImportObject";
import { OpenApiParser } from "../../../openApi/OpenApiParser";
@ -117,7 +118,7 @@ export class OpenApiEditor extends Editor<ApiTreeItem> {
private buildAPIExportUrl(context: ApiTreeItem, exportFormat: string) : string {
let url = `${context.root.environment.resourceManagerEndpointUrl}/subscriptions/${context.root.subscriptionId}/resourceGroups/${context.root.resourceGroupName}/providers/Microsoft.ApiManagement/service/${context.root.serviceName}/apis/${context.root.apiName}`;
url = `${url}?export=true&format=${exportFormat}&api-version=2019-01-01`;
url = `${url}?export=true&format=${exportFormat}&api-version=${Constants.apimApiVersion}`;
return url;
}

Просмотреть файл

@ -84,7 +84,7 @@ export class OperationConsole {
const apimService = new ApimService(root.credentials, root.environment.resourceManagerEndpointUrl, root.subscriptionId, root.resourceGroupName, root.serviceName);
const masterSubscription = await apimService.getSubscriptionMasterkey();
headers.forEach(header => {
requestSummary += `${header}: ${masterSubscription.properties.primaryKey}\n`;
requestSummary += `${header}: ${masterSubscription.primaryKey}\n`;
});
requestSummary += "Ocp-Apim-Trace: true\n";
if (consoleOperation.request.body) {

Просмотреть файл

@ -19,46 +19,48 @@ export namespace dotnetUtils {
}
}
export async function validateDotnetInstalled(actionContext: IActionContext): Promise<void> {
if (!await isDotnetInstalled()) {
const message: string = localize('dotnetNotInstalled', 'You must have the .NET CLI installed to perform this operation.');
export async function validateDotnetInstalled(actionContext?: IActionContext, minVersion: string = "2.1"): Promise<void> {
if (!await isDotnetInstalled() || !await checkDotnetVersionInstalled(minVersion)) {
const message: string = localize('dotnetNotInstalled', 'You must have the .NET CLI {0} or older installed to perform this operation.', minVersion);
if (!actionContext.errorHandling.suppressDisplay) {
if (!actionContext || !actionContext.errorHandling.suppressDisplay) {
// don't wait
vscode.window.showErrorMessage(message, DialogResponses.learnMore).then(async (result) => {
if (result === DialogResponses.learnMore) {
await openUrl('https://aka.ms/AA4ac70');
}
});
actionContext.errorHandling.suppressDisplay = true;
}
throw new Error(message);
}
}
export async function checkDotnetInstalled(): Promise<void> {
if (!await isDotnetInstalled()) {
const message: string = localize('dotnetNotInstalled', 'You must have a .NET Core SDK v2.1.x CLI installed to perform this operation.');
// don't wait
vscode.window.showErrorMessage(message, DialogResponses.learnMore).then(async (result) => {
if (result === DialogResponses.learnMore) {
await openUrl('https://aka.ms/AA4ac70');
if (actionContext) {
actionContext.errorHandling.suppressDisplay = true;
}
});
}
throw new Error(message);
}
}
export async function checkDotnetVersionInstalled(targetVersion: string): Promise<boolean> {
const response = await cpUtils.executeCommand(undefined, undefined, 'dotnet', '--list-sdks');
const versions = response.split(/\r?\n/);
for (const version of versions) {
if (version.startsWith(targetVersion)) {
return true;
function compareVersion(version1: string, version2: string): number {
const v1 = version1.split('.').map(parseInt);
const v2 = version2.split('.').map(parseInt);
for (let i = 0; i < Math.min(v1.length, v2.length); i++) {
if (v1[i] > v2[i]) { return 1; }
if (v1[i] < v2[i]) { return -1; }
}
return v1.length === v2.length ? 0 : (v1.length < v2.length ? -1 : 1);
}
async function checkDotnetVersionInstalled(minVersion: string): Promise<boolean> {
try {
const response = await cpUtils.executeCommand(undefined, undefined, 'dotnet', '--list-runtimes');
const versions = response.split(/\r?\n/);
for (const version of versions) {
const versionNumber = version.split(' ')[1];
if (compareVersion(versionNumber, minVersion) >= 0) {
return false;
}
}
} catch (error) {
return false;
}
return false;
}