Skip to content

Commit

Permalink
Helping prevention of accidental directory exclusion when using the -…
Browse files Browse the repository at this point in the history
…-export-on-exit option (#4127)

* Adding condition to prevent the user from setting the export data folder to the CWD, inflicting in directory exclusion after stopping the emulators

* Added another test case when the user sets the --export-on-exit implicitly via the set of --import

* Improved the message presented to user
Fixed a cenario where the user could ingress a pattern of cwd and it would fail incorrectly

Co-authored-by: Yuchen Shi <yuchenshi@google.com>
  • Loading branch information
Muritavo and yuchenshi committed Feb 15, 2022
1 parent eca1b4d commit 8a874e1
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/emulator/commandUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export const EXPORT_ON_EXIT_USAGE_ERROR =
`"${FLAG_EXPORT_ON_EXIT_NAME}" must be used with "${FLAG_IMPORT}"` +
` or provide a dir directly to "${FLAG_EXPORT_ON_EXIT}"`;

export const EXPORT_ON_EXIT_CWD_DANGER = `"${FLAG_EXPORT_ON_EXIT_NAME}" must not point to the current directory or parents. Please choose a new/dedicated directory for exports.`;

export const FLAG_UI = "--ui";
export const DESC_UI = "run the Emulator UI";

Expand Down Expand Up @@ -203,6 +205,10 @@ export function setExportOnExitOptions(options: any) {
// firebase emulators:start --debug --import '' --export-on-exit ''
throw new FirebaseError(EXPORT_ON_EXIT_USAGE_ERROR);
}

if (path.resolve(".").startsWith(path.resolve(options.exportOnExit))) {
throw new FirebaseError(EXPORT_ON_EXIT_CWD_DANGER);
}
}
return;
}
Expand Down
61 changes: 60 additions & 1 deletion src/test/emulators/commandUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,73 @@
import * as commandUtils from "../../emulator/commandUtils";
import { expect } from "chai";
import { FirebaseError } from "../../error";
import { EXPORT_ON_EXIT_USAGE_ERROR } from "../../emulator/commandUtils";
import { EXPORT_ON_EXIT_USAGE_ERROR, EXPORT_ON_EXIT_CWD_DANGER } from "../../emulator/commandUtils";
import { delimiter, join, resolve } from "path";
import * as sinon from "sinon";

describe("commandUtils", () => {
const testSetExportOnExitOptions = (options: any): any => {
commandUtils.setExportOnExitOptions(options);
return options;
};

describe("Mocked path resolve", () => {
const mockCWD = "/a/resolved/path/example";
const mockDestinationDir = "/path/example";

let pathStub: sinon.SinonStub;
beforeEach(() => {
pathStub = sinon.stub(require("path"), "resolve").callsFake((path) => {
return path === "." ? mockCWD : mockDestinationDir;
});
});

afterEach(() => {
pathStub.reset();
});

it("Should not block if destination contains a match to the CWD", () => {
const directoryToAllow = mockDestinationDir;
expect(testSetExportOnExitOptions({ exportOnExit: directoryToAllow }).exportOnExit).to.equal(
directoryToAllow
);
});
});

/**
* Currently, setting the --export-on-exit as the current CWD can inflict on
* full directory deletion
*/
const directoriesThatShouldFail = [
".", // The current dir
"./", // The current dir with /
resolve("."), // An absolute path
resolve(".."), // A folder that directs to the CWD
resolve("../.."), // Another folder that directs to the CWD
];

directoriesThatShouldFail.forEach((dir) => {
it(`Should disallow the user to set the current folder (ex: ${dir}) as --export-on-exit option`, () => {
expect(() => testSetExportOnExitOptions({ exportOnExit: dir })).to.throw(
EXPORT_ON_EXIT_CWD_DANGER
);
const cwdSubDir = join(dir, "some-dir");
expect(testSetExportOnExitOptions({ exportOnExit: cwdSubDir }).exportOnExit).to.equal(
cwdSubDir
);
});
});

it("Should disallow the user to set the current folder via the --import flag", () => {
expect(() => testSetExportOnExitOptions({ import: ".", exportOnExit: true })).to.throw(
EXPORT_ON_EXIT_CWD_DANGER
);
const cwdSubDir = join(".", "some-dir");
expect(
testSetExportOnExitOptions({ import: cwdSubDir, exportOnExit: true }).exportOnExit
).to.equal(cwdSubDir);
});

it("should validate --export-on-exit options", () => {
expect(testSetExportOnExitOptions({ import: "./data" }).exportOnExit).to.be.undefined;
expect(
Expand Down

0 comments on commit 8a874e1

Please sign in to comment.