-
Notifications
You must be signed in to change notification settings - Fork 902
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add StorageRulesManagerRegistry to handle rules files for multiple targets #4281
Merged
tohhsinpei
merged 18 commits into
master
from
hsinpei/storage-emulator-multiple-targets-3
Mar 16, 2022
Merged
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
586e660
Address PR feedback; add JSDocs for new method
tohhsinpei fff9889
Make StorageRulesManager an interface; add StorageRulesManagerRegistry
tohhsinpei fc487e4
Modify RulesetProvider to take resource parameter
tohhsinpei edb0bd7
Rebase; fix lint error
tohhsinpei 1ddd733
Change emulator arg to take SourceFile only
tohhsinpei 6f45411
PR feedback, mostly re: API usage
tohhsinpei 0594bf2
Don't delete source file or ruleset on stop(); add CHANGELOG
tohhsinpei 8e42a13
Address PR feedback
tohhsinpei 8f3d045
Moved Storage rules integration tests under scripts/ (#4309)
tohhsinpei 007e1f4
Make StorageRulesManager an interface; add StorageRulesManagerRegistry
tohhsinpei 18dbd2f
Modify RulesetProvider to take resource parameter
tohhsinpei fc6cdf0
Change emulator arg to take SourceFile only
tohhsinpei b7c5de5
PR feedback, mostly re: API usage
tohhsinpei f221cb8
Don't delete source file or ruleset on stop(); add CHANGELOG
tohhsinpei 6ed793c
Address PR feedback
tohhsinpei 0c8c165
Merge branch 'master' into hsinpei/storage-emulator-multiple-targets-3
tohhsinpei 2107f90
Fix lint
tohhsinpei 76d7a42
Add test for failing to find rules for given resource
tohhsinpei File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
- Adds support for configuration with multiple storage targets (#4281). | ||
116 changes: 66 additions & 50 deletions
116
scripts/storage-emulator-integration/rules/manager.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,92 +1,108 @@ | ||
import { expect } from "chai"; | ||
import { tmpdir } from "os"; | ||
import { v4 as uuidv4 } from "uuid"; | ||
|
||
import { FirebaseError } from "../../../src/error"; | ||
import { StorageRulesFiles, TIMEOUT_MED } from "../../../src/test/emulators/fixtures"; | ||
import { StorageRulesManager } from "../../../src/emulator/storage/rules/manager"; | ||
import { | ||
createTmpDir, | ||
StorageRulesFiles, | ||
TIMEOUT_LONG, | ||
} from "../../../src/test/emulators/fixtures"; | ||
import { | ||
createStorageRulesManager, | ||
StorageRulesManager, | ||
} from "../../../src/emulator/storage/rules/manager"; | ||
import { StorageRulesRuntime } from "../../../src/emulator/storage/rules/runtime"; | ||
import { Persistence } from "../../../src/emulator/storage/persistence"; | ||
import { RulesetOperationMethod } from "../../../src/emulator/storage/rules/types"; | ||
import { RulesetOperationMethod, SourceFile } from "../../../src/emulator/storage/rules/types"; | ||
import { isPermitted } from "../../../src/emulator/storage/rules/utils"; | ||
import { readFile } from "../../../src/fsutils"; | ||
|
||
describe("Storage Rules Manager", function () { | ||
const rulesRuntime = new StorageRulesRuntime(); | ||
const rulesManager = new StorageRulesManager(rulesRuntime); | ||
const rules = [ | ||
{ resource: "bucket_0", rules: StorageRulesFiles.readWriteIfTrue }, | ||
{ resource: "bucket_1", rules: StorageRulesFiles.readWriteIfAuth }, | ||
]; | ||
const opts = { method: RulesetOperationMethod.GET, file: {}, path: "/b/bucket_2/o/" }; | ||
let rulesManager: StorageRulesManager; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-invalid-this | ||
this.timeout(TIMEOUT_MED); | ||
this.timeout(TIMEOUT_LONG); | ||
|
||
before(async () => { | ||
beforeEach(async () => { | ||
await rulesRuntime.start(); | ||
|
||
rulesManager = createStorageRulesManager(rules, rulesRuntime); | ||
await rulesManager.start(); | ||
}); | ||
|
||
after(async () => { | ||
afterEach(async () => { | ||
rulesRuntime.stop(); | ||
await rulesManager.close(); | ||
await rulesManager.stop(); | ||
}); | ||
|
||
it("should load ruleset from SourceFile object", async () => { | ||
await rulesManager.setSourceFile(StorageRulesFiles.readWriteIfTrue); | ||
expect(rulesManager.ruleset).not.to.be.undefined; | ||
it("should load multiple rulesets on start", async () => { | ||
tohhsinpei marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const bucket0Ruleset = rulesManager.getRuleset("bucket_0"); | ||
expect(await isPermitted({ ...opts, ruleset: bucket0Ruleset! })).to.be.true; | ||
|
||
const bucket1Ruleset = rulesManager.getRuleset("bucket_1"); | ||
expect(await isPermitted({ ...opts, ruleset: bucket1Ruleset! })).to.be.false; | ||
}); | ||
|
||
it("should load ruleset from file path", async () => { | ||
// Write rules to file | ||
const fileName = "storage.rules"; | ||
const testDir = `${tmpdir()}/${uuidv4()}`; | ||
const persistence = new Persistence(testDir); | ||
persistence.appendBytes(fileName, Buffer.from(StorageRulesFiles.readWriteIfTrue.content)); | ||
it("should load single ruleset on start", async () => { | ||
const otherRulesManager = createStorageRulesManager( | ||
StorageRulesFiles.readWriteIfTrue, | ||
rulesRuntime | ||
); | ||
await otherRulesManager.start(); | ||
|
||
await rulesManager.setSourceFile(`${testDir}/${fileName}`); | ||
const ruleset = otherRulesManager.getRuleset("default"); | ||
expect(await isPermitted({ ...opts, ruleset: ruleset! })).to.be.true; | ||
|
||
expect(rulesManager.ruleset).not.to.be.undefined; | ||
await otherRulesManager.stop(); | ||
}); | ||
|
||
it("should load ruleset on update with SourceFile object", async () => { | ||
await rulesManager.updateSourceFile(StorageRulesFiles.readWriteIfTrue, "bucket_2"); | ||
expect(rulesManager.getRuleset("bucket_2")).not.to.be.undefined; | ||
}); | ||
|
||
it("should set source file", async () => { | ||
await rulesManager.setSourceFile(StorageRulesFiles.readWriteIfTrue); | ||
const opts = { method: RulesetOperationMethod.GET, file: {}, path: "/b/bucket/o/" }; | ||
expect((await rulesManager.ruleset!.verify(opts)).permitted).to.be.true; | ||
await rulesManager.updateSourceFile(StorageRulesFiles.readWriteIfTrue, "bucket_2"); | ||
|
||
const issues = await rulesManager.setSourceFile(StorageRulesFiles.readWriteIfAuth); | ||
expect(await isPermitted({ ...opts, ruleset: rulesManager.getRuleset("bucket_2")! })).to.be | ||
.true; | ||
|
||
const issues = await rulesManager.updateSourceFile( | ||
StorageRulesFiles.readWriteIfAuth, | ||
"bucket_2" | ||
); | ||
|
||
expect(issues.errors.length).to.equal(0); | ||
expect(issues.warnings.length).to.equal(0); | ||
expect((await rulesManager.ruleset!.verify(opts)).permitted).to.be.false; | ||
expect(await isPermitted({ ...opts, ruleset: rulesManager.getRuleset("bucket_2")! })).to.be | ||
.false; | ||
}); | ||
|
||
it("should reload ruleset on changes to source file", async () => { | ||
const opts = { method: RulesetOperationMethod.GET, file: {}, path: "/b/bucket/o/" }; | ||
|
||
// Write rules to file | ||
const fileName = "storage.rules"; | ||
const testDir = `${tmpdir()}/${uuidv4()}`; | ||
const testDir = createTmpDir("storage-files"); | ||
const persistence = new Persistence(testDir); | ||
persistence.appendBytes(fileName, Buffer.from(StorageRulesFiles.readWriteIfTrue.content)); | ||
|
||
await rulesManager.setSourceFile(`${testDir}/${fileName}`); | ||
expect((await rulesManager.ruleset!.verify(opts)).permitted).to.be.true; | ||
const sourceFile = getSourceFile(testDir, fileName); | ||
await rulesManager.updateSourceFile(sourceFile, "bucket_2"); | ||
expect(await isPermitted({ ...opts, ruleset: rulesManager.getRuleset("bucket_2")! })).to.be | ||
.true; | ||
|
||
// Write new rules to file | ||
persistence.deleteFile(fileName); | ||
persistence.appendBytes(fileName, Buffer.from(StorageRulesFiles.readWriteIfAuth.content)); | ||
|
||
await rulesManager.setSourceFile(`${testDir}/${fileName}`); | ||
expect((await rulesManager.ruleset!.verify(opts)).permitted).to.be.false; | ||
}); | ||
|
||
it("should throw FirebaseError when attempting to set invalid source file", async () => { | ||
const invalidFileName = "foo"; | ||
await expect(rulesManager.setSourceFile(invalidFileName)).to.be.rejectedWith( | ||
FirebaseError, | ||
`File not found: ${invalidFileName}` | ||
); | ||
}); | ||
|
||
it("should delete ruleset when storage manager is closed", async () => { | ||
await rulesManager.setSourceFile(StorageRulesFiles.readWriteIfTrue); | ||
expect(rulesManager.ruleset).not.to.be.undefined; | ||
|
||
await rulesManager.close(); | ||
expect(rulesManager.ruleset).to.be.undefined; | ||
expect(await isPermitted(opts)).to.be.false; | ||
}); | ||
}); | ||
|
||
function getSourceFile(testDir: string, fileName: string): SourceFile { | ||
const filePath = `${testDir}/${fileName}`; | ||
return { name: filePath, content: readFile(filePath) }; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should coordinate with @puf to get the public docs updated once this is released :) https://firebase.google.com/docs/emulator-suite/install_and_configure#security_rules_configuration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some docs, somewhat hidden away...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's true, the emulator-specific docs don't seem to mention this: https://firebase.google.com/docs/emulator-suite/install_and_configure#security_rules_configuration
But it's okay that we don't reiterate everything since it's already in the CLI documentation