Sanitize db name for dacpac/bacpac file names (#5479)

* Sanitize db name for filename

* Add unit tests

* lower timeout to 60 seconds

* add extra coverageConfig.json and missing character check
This commit is contained in:
kisantia
2019-05-14 15:00:28 -07:00
committed by GitHub
parent be60ad6766
commit 48ba9ce175
12 changed files with 1496 additions and 6 deletions

View File

@@ -1 +1,2 @@
coverage
*.vsix

View File

@@ -1,2 +1,4 @@
coverage/**
coverageConfig.json
src/**
tsconfig.json

View File

@@ -0,0 +1,17 @@
{
"enabled": false,
"relativeSourcePath": "..",
"relativeCoverageDir": "../../coverage",
"ignorePatterns": [
"**/node_modules/**"
],
"includePid": false,
"reports": [
"cobertura"
],
"verbose": false,
"remapOptions": {
"basePath": ".",
"useAbsolutePaths": true
}
}

View File

@@ -55,7 +55,12 @@
"htmlparser2": "^3.10.1",
"vscode-nls": "^3.2.1"
},
"devDependencies": {},
"devDependencies": {
"@types/mocha": "^5.2.5",
"mocha": "^5.2.0",
"should": "^13.2.1",
"vscodetestcover": "^1.0.2"
},
"__metadata": {
"id": "33",
"publisherDisplayName": "Microsoft",

View File

@@ -0,0 +1,47 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'mocha';
import * as should from 'should';
import * as os from 'os';
import { isValidFilenameCharacter, sanitizeStringForFilename } from '../wizard/api/utils';
describe('Sanitize database name for filename tests', function (): void {
it('Should only validate if one character is passed', async () => {
should(isValidFilenameCharacter(null)).equal(false);
should(isValidFilenameCharacter('')).equal(false);
should(isValidFilenameCharacter('abc')).equal(false);
should(isValidFilenameCharacter('c')).equal(true);
});
it('Should determine invalid file name characters', async () => {
// invalid for both Windows and non-Windows
should(isValidFilenameCharacter('\\')).equal(false);
should(isValidFilenameCharacter('/')).equal(false);
});
it('Should determine invalid Windows file name characters', async () => {
let isWindows = os.platform() === 'win32';
// invalid only for Windows
should(isValidFilenameCharacter('?')).equal(isWindows ? false : true);
should(isValidFilenameCharacter(':')).equal(isWindows ? false : true);
should(isValidFilenameCharacter('*')).equal(isWindows ? false : true);
should(isValidFilenameCharacter('<')).equal(isWindows ? false : true);
should(isValidFilenameCharacter('>')).equal(isWindows ? false : true);
should(isValidFilenameCharacter('|')).equal(isWindows ? false : true);
should(isValidFilenameCharacter('"')).equal(isWindows ? false : true);
});
it('Should sanitize database name for filename', async () => {
let invalidDbName = '"in|valid*<>db/?name';
let expectedWindows = '_in_valid___db__name';
let expectedNonWindows = '"in|valid*<>db_?name';
let isWindows = os.platform() === 'win32';
should(sanitizeStringForFilename(invalidDbName)).equal(isWindows ? expectedWindows : expectedNonWindows);
});
});

View File

@@ -0,0 +1,34 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path = require('path');
import * as testRunner from 'vscodetestcover';
const suite = 'DacFx Tests';
const testOptions: any = {
ui: 'bdd',
useColors: true,
timeout: 60000
};
const coverageConfig: any = {
coverConfig: '../../coverageConfig.json'
};
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
testOptions.reporter = 'mocha-multi-reporters';
testOptions.reporterOptions = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
testsuitesTitle: `${suite} ${process.platform}`,
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
}
};
}
testRunner.configure(testOptions, coverageConfig);
export = testRunner;

View File

@@ -12,6 +12,7 @@ import * as path from 'path';
import { DataTierApplicationWizard } from '../dataTierApplicationWizard';
import { DacFxDataModel } from './models';
import { BasePage } from './basePage';
import { sanitizeStringForFilename } from './utils';
const localize = nls.loadMessageBundle();
@@ -147,7 +148,7 @@ export abstract class DacFxConfigPage extends BasePage {
}
protected generateFilePathFromDatabaseAndTimestamp(): string {
return path.join(this.getRootPath(), this.model.database + '-' + this.getDateTime() + this.fileExtension);
return path.join(this.getRootPath(), sanitizeStringForFilename(this.model.database) + '-' + this.getDateTime() + this.fileExtension);
}
protected getDateTime(): string {

View File

@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as os from 'os';
const INVALID_FILE_CHARS_Windows = /[\\/:\*\?"<>\|]/g;
const INVALID_FILE_CHARS = /[\\/]/g;
/**
* Determines if a given character is a valid filename character
* @param c Character to validate
*/
export function isValidFilenameCharacter(c: string): boolean {
// only a character should be passed
if (!c || c.length !== 1) {
return false;
}
let isWindows = os.platform() === 'win32';
INVALID_FILE_CHARS_Windows.lastIndex = 0;
INVALID_FILE_CHARS.lastIndex = 0;
if (isWindows && INVALID_FILE_CHARS_Windows.test(c)) {
return false;
} else if (!isWindows && INVALID_FILE_CHARS.test(c)) {
return false;
}
return true;
}
/**
* Replaces invalid filename characters in a string with underscores
* @param s The string to be sanitized for a filename
*/
export function sanitizeStringForFilename(s: string): string {
// replace invalid characters with an underscore
let result = '';
for (let i = 0; i < s.length; ++i) {
result += this.isValidFilenameCharacter(s[i]) ? s[i] : '_';
}
return result;
}

View File

@@ -8,10 +8,10 @@ import * as azdata from 'azdata';
import * as nls from 'vscode-nls';
import * as vscode from 'vscode';
import * as path from 'path';
import * as os from 'os';
import { DacFxDataModel } from '../api/models';
import { DataTierApplicationWizard, Operation } from '../dataTierApplicationWizard';
import { DacFxConfigPage } from '../api/dacFxConfigPage';
import { sanitizeStringForFilename } from '../api/utils';
const localize = nls.loadMessageBundle();
@@ -167,7 +167,7 @@ export class DeployActionPage extends DacFxConfigPage {
}
private setDefaultScriptFilePath(): void {
this.fileTextBox.value = path.join(this.getRootPath(), this.model.database + '_UpgradeDACScript_' + this.getDateTime() + '.sql');
this.fileTextBox.value = path.join(this.getRootPath(), sanitizeStringForFilename(this.model.database) + '_UpgradeDACScript_' + this.getDateTime() + '.sql');
this.model.scriptFilePath = this.fileTextBox.value;
}

File diff suppressed because it is too large Load Diff

View File

@@ -14,6 +14,7 @@ call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\admin-too
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\agent --extensionTestsPath=%~dp0\..\extensions\agent\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --disableExtensions --remote-debugging-port=9222
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\cms --extensionTestsPath=%~dp0\..\extensions\cms\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\dacpac --extensionTestsPath=%~dp0\..\extensions\dacpac\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\notebook --extensionTestsPath=%~dp0\..\extensions\notebook\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222
if %errorlevel% neq 0 exit /b %errorlevel%

View File

@@ -22,6 +22,7 @@ echo $VSCODEEXTDIR
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/agent --extensionTestsPath=$ROOT/extensions/agent/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/cms --extensionTestsPath=$ROOT/extensions/cms/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/dacpac --extensionTestsPath=$ROOT/extensions/dacpac/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/notebook --extensionTestsPath=$ROOT/extensions/notebook/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
rm -r $VSCODEUSERDATADIR