mongo/jstests/auth/lib/commands_lib.js

9554 lines
361 KiB
JavaScript

/*
Declaratively defined tests for the authorization properties
of all database commands.
This file contains an array of test definitions, as well as
some shared test logic.
See jstests/auth/commands_builtin_roles.js and jstests/auth/commands_user_defined_roles.js for two
separate implementations of the test logic, respectively to test authorization with builtin roles
and authorization with user-defined roles.
Example test definition:
This tests that when run on the "roles_commands_1" database,
the given command will return an authorization error unless
the user has the role with key "readWrite" or the role with
key "readWriteAnyDatabase". The command will be run as a
user with each of the roles in the "roles" array below.
Similarly, this tests that when run on the "roles_commands_2"
database, only a user with role "readWriteAnyDatabase" should
be authorized.
{
testname: "aggregate_out_legacy",
command: {aggregate: "foo", pipeline: [ {$out: "foo_out"} ], cursor: {} },
testcases: [
{ runOnDb: "roles_commands_1", roles: {readWrite: 1, readWriteAnyDatabase: 1} },
{ runOnDb: "roles_commands_2", roles: {readWriteAnyDatabase: 1} }
]
},
Additional options:
1) expectFail
You can add "expectFail: true" to an individual element of the testcases
array. This means that if the command is authorized, then you still expect
it to fail with a non-auth related error. As always, for roles other than
those in the "roles" array, an auth error is expected.
2) expectAuthzFailure
Like "expectFailure", this option applies to an individual test case rather than
than the full test object. When this option is true, it means the test case is
*not* testing that the given roles/privileges make the command authorized to run,
instead it makes it so it is testing that the given roles/privileges are *not* sufficient
to be authorized to run the command.
3) skipSharded
Add "skipSharded: true" if you want to run the test only ony in a non-sharded configuration.
4) skipUnlessSharded
Add "skipUnlessSharded: true" if you want to run the test only in sharded
configuration. The command in the test will be run on a mongos.
5) skipUnlessReplicaSet
Add "skipUnlessReplicaSet: true" if you want to run the test only when replica sets are in use.
6) setup
The setup function, if present, is called before testing whether a
particular role authorizes a command for a particular database.
7) teardown
The teardown function, if present, is called immediately after
testing whether a particular role authorizes a command for a
particular database.
8) privileges
An array of privileges used when testing user-defined roles. The test case tests that a user with
the specified privileges is authorized to run the command, and that having only a subset of the
privileges causes an authorization failure. If an individual privilege specifies
"removeWhenTestingAuthzFailure: false", then that privilege will not be removed when testing for
authorization failure.
9) commandArgs
Set of options to be passed to your 'command' function. Can be used to send different versions of
the command depending on the testcase being run.
10) skipTest
Add "skipTest: <function>" to not run the test for more complex reasons. The function is passed
one argument, the connection object.
*/
import {FeatureFlagUtil} from "jstests/libs/feature_flag_util.js";
import {
storageEngineIsWiredTigerOrInMemory,
storageEngineIsWiredTiger,
} from "jstests/libs/storage_engine/storage_engine_utils.js";
import {getUriForColl} from "jstests/disk/libs/wt_file_helper.js";
import {testOnlyCommands} from "jstests/auth/test_only_commands_list.js";
// constants
// All roles that are specific to one database will be given only for 'firstDbName'. For example,
// when using the roles in 'roles_read', the 'read' role will only be granted on 'firstDbName'. In
// particular, this means that when 'runOnDb' is 'secondDbName', the test user with the 'read' role
// should not be able to perform read operations.
export const firstDbName = "roles_commands_1";
export const secondDbName = "roles_commands_2";
export const adminDbName = "admin";
export const configDbName = "config";
export const authErrCode = 13;
export const commandNotSupportedCode = 115;
let shard0name = "shard0000";
// useful shorthand when defining the tests below
let roles_write = {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, restore: 1, root: 1, __system: 1};
let roles_read = {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbOwner: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
};
let roles_userAdmin = {
userAdmin: 1,
dbOwner: 1,
userAdminAnyDatabase: 1,
restore: 1,
root: 1,
__system: 1,
};
let roles_userAdminAny = {
userAdminAnyDatabase: 1,
restore: 1,
root: 1,
__system: 1,
};
let roles_readAny = {
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
};
let roles_dbAdmin = {dbAdmin: 1, dbAdminAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1};
let roles_dbAdminAny = {dbAdminAnyDatabase: 1, root: 1, __system: 1};
let roles_writeDbAdmin = {
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
root: 1,
__system: 1,
};
let roles_writeDbAdminAny = {readWriteAnyDatabase: 1, dbAdminAnyDatabase: 1, root: 1, __system: 1};
let roles_readDbAdmin = {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
};
let roles_readDbAdminAny = {
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
dbAdminAnyDatabase: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
};
let roles_monitoring = {clusterMonitor: 1, clusterAdmin: 1, root: 1, searchCoordinator: 1, __system: 1};
let roles_hostManager = {hostManager: 1, clusterAdmin: 1, root: 1, __system: 1};
let roles_clusterManager = {clusterManager: 1, clusterAdmin: 1, root: 1, __system: 1};
let roles_all = {
read: 1,
readLocal: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteLocal: 1,
readWriteAnyDatabase: 1,
userAdmin: 1,
userAdminAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
enableSharding: 1,
clusterMonitor: 1,
hostManager: 1,
clusterManager: 1,
clusterAdmin: 1,
backup: 1,
restore: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
};
// Common test cases for the aggregation stages that perform transformation only.
let testcases_transformationOnly = [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]}],
},
];
// Similar to 'testcases_transformationOnly' with expectation to fail. For instance, a stage is not
// allowed in user request.
let testcases_transformationOnlyExpectFail = testcases_transformationOnly.map((t) =>
Object.extend({expectFail: true}, t),
);
// The following agggregation stages are skipped in 'authCommandsLib' because they are unable to be
// tested here and already have auth tests elsewhere.
const skippedAuthTestingAggStages = [
"$_analyzeShardKeyReadWriteDistribution", // Already covered. And it cannot not be tested in
// commands_lib framework due to its requirement on
// non-mongos node on a sharded cluster.
"$merge", // Already covered in 'aggregate_merge_insert_documents' and
// 'aggregate_merge_replace_documents'.
"$set", // Alias for "$addFields" and already covered.
// The following stages are required to be tested in stream processors.
"$hoppingWindow",
"$tumblingWindow",
"$sessionWindow",
"$validate",
"$setStreamMeta",
// The following stages are stubs defined in aggregation_stage_stub_parsers.json.
"$stubStage",
"$testFoo",
];
// The following commands are skipped in 'authCommandsLib' because they are unable to be
// tested here and already have auth tests elsewhere.
//TODO SERVER-112286: Audit commands skipped.
const skippedAuthTestingCommands = [
"analyzeShardKey",
"authenticate",
"autoSplitVector",
"balancerCollectionStatus",
"changePrimary",
"clearLog",
"commitTransitionToDedicatedConfigServer",
"configureCollectionBalancing",
"configureQueryAnalyzer",
"coordinateCommitTransaction",
"createUnsplittableCollection",
"dbCheck",
"dropAllRolesFromDatabase",
"dropAllUsersFromDatabase",
"dropConnections",
"dropRole",
"dropUser",
"echo",
"endSessions",
"explain",
"exportCollection",
"getAuditConfig",
"getChangeStreamState",
"getShardingReady",
"getTransitionToDedicatedConfigServerStatus",
"grantPrivilegesToRole",
"grantRolesToRole",
"grantRolesToUser",
"hello",
"httpClientRequest",
"importCollection",
"internalRenameIfOptionsAndIndexesMatch",
"invalidateUserCache",
"isdbgrid",
"killCursors",
"killSessions",
"listDatabasesForAllTenants",
"logApplicationMessage",
"logMessage",
"logout",
"makeSnapshot",
"mapReduce",
"mergeAllChunksOnShard",
"multicast",
"pinHistoryReplicated",
"planCacheListFilters",
"planCacheSetFilter",
"prepareTransaction",
"reapLogicalSessionCacheNow",
"releaseMemory",
"repairShardedCollectionChunksHistory",
"replicateSearchIndexCommand",
"replSetAbortPrimaryCatchUp",
"replSetRequestVotes",
"replSetResizeOplog",
"replSetTestEgress",
"replSetUpdatePosition",
"resetPlacementHistory",
"revokePrivilegesFromRole",
"revokeRolesFromRole",
"revokeRolesFromUser",
"rolesInfo",
"saslContinue",
"saslStart",
"setAllowMigrations",
"setAuditConfig",
"setChangeStreamState",
"setCommittedSnapshot",
"setIndexCommitQuorum",
"shardDrainingStatus",
"startShardDraining",
"startTransitionToDedicatedConfigServer",
"stopTransitionToDedicatedConfigServer",
"streams_getMetrics",
"streams_getMoreStreamSample",
"streams_getStats",
"streams_listStreamProcessors",
"streams_sendEvent",
"streams_startStreamProcessor",
"streams_startStreamSample",
"streams_stopStreamProcessor",
"streams_testOnlyGetFeatureFlags",
"streams_testOnlyInsert",
"streams_updateConnection",
"streams_updateFeatureFlags",
"streams_writeCheckpoint",
"testCommandFeatureFlaggedOnLatestFCV83",
"testDeprecation",
"testDeprecationInVersion2",
"testInternalTransactions",
"testRemoval",
"testReshardCloneCollection",
"testVersion2",
"testVersions1And2",
"timeseriesCatalogBucketParamsChanged",
"transitionToShardedCluster",
"usersInfo",
"voteAbortIndexBuild",
"voteCommitImportCollection",
"voteCommitIndexBuild",
"waitForFailPoint",
"whatsmysni",
];
import {getUUIDFromListCollections} from "jstests/libs/uuid_util.js";
import {FixtureHelpers} from "jstests/libs/fixture_helpers.js";
export const authCommandsLib = {
/************* TEST CASES ****************/
tests: [
{
testname: "applyOps_container_insert",
skipSharded: true,
skipTest: (conn) =>
!isFeatureEnabled(conn, "featureFlagPrimaryDrivenIndexBuilds") || !storageEngineIsWiredTiger(),
setup: function (db) {
const coll = "containerOpsColl";
db[coll].drop();
assert.commandWorked(db.createCollection(coll));
const uri = getUriForColl(db[coll]);
return {nss: db.getName() + "." + coll, coll, uri};
},
command: function (state) {
return {
applyOps: [
{
op: "ci",
ns: state.nss,
container: state.uri,
o: {k: BinData(0, "QQ=="), v: BinData(0, "Qg==")},
},
],
};
},
teardown: function (db, state) {
if (state && state.coll) db[state.coll].drop();
},
testcases: [
{runOnDb: firstDbName, roles: {__system: 1, root: 1, restore: 1}},
{runOnDb: "local", roles: {__system: 1, root: 1, restore: 1}},
{
runOnDb: firstDbName,
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["containerInsert"]},
{resource: {cluster: true}, actions: ["applyOps"]},
],
},
],
},
{
testname: "applyOps_container_delete",
skipSharded: true,
skipTest: (conn) =>
!isFeatureEnabled(conn, "featureFlagPrimaryDrivenIndexBuilds") || !storageEngineIsWiredTiger(),
setup: function (db) {
const coll = "containerOpsColl";
db[coll].drop();
assert.commandWorked(db.createCollection(coll));
const uri = getUriForColl(db[coll]);
return {nss: db.getName() + "." + coll, coll, uri};
},
command: function (state) {
return {
applyOps: [
{
op: "cd",
ns: state.nss,
container: state.uri,
o: {k: BinData(0, "QQ==")},
},
],
};
},
teardown: function (db, state) {
if (state && state.coll) db[state.coll].drop();
},
testcases: [
// Attempting to delete a nonexistent key from a container fails.
{runOnDb: firstDbName, roles: {__system: 1, root: 1, restore: 1}, expectFail: true},
{runOnDb: "local", roles: {__system: 1, root: 1, restore: 1}, expectFail: true},
{
runOnDb: firstDbName,
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["containerDelete"]},
{resource: {cluster: true}, actions: ["applyOps"]},
],
expectFail: true,
},
],
},
{
testname: "abortMoveCollection",
command: {abortMoveCollection: "test.x"},
skipUnlessSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagMoveCollection"),
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["moveCollection"]}],
expectFail: true,
},
],
},
{
testname: "abortReshardCollection",
command: {abortReshardCollection: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["reshardCollection"]}],
expectFail: true,
},
],
},
{
testname: "abortRewriteCollection",
command: {abortRewriteCollection: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["rewriteCollection"]}],
expectFail: true,
},
],
},
{
testname: "abortUnshardCollection",
command: {abortUnshardCollection: "test.x"},
skipUnlessSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagUnshardCollection"),
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["unshardCollection"]}],
expectFail: true,
},
],
},
{
testname: "_clusterQueryWithoutShardKey",
command: {
_clusterQueryWithoutShardKey: 1,
writeCmd: {
update: "foo",
updates: [{q: {x: 1}, u: {$set: {a: 90}, upsert: false}}],
},
stmtId: NumberInt(1),
},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{
runOnDb: secondDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "_clusterWriteWithoutShardKey",
command: {_clusterWriteWithoutShardKey: 1, writeCmd: {}, shardId: "", targetDocId: {}},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
// The command expects to be run within a transaction.
expectFail: true,
},
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
// The command expects to be run within a transaction.
expectFail: true,
},
{
runOnDb: secondDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
// The command expects to be run within a transaction.
expectFail: true,
},
],
},
{
testname: "_configsvrAbortReshardCollection",
command: {_configsvrAbortReshardCollection: "test.x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_shardsvrAbortReshardCollection",
command: {_shardsvrAbortReshardCollection: UUID(), userCanceled: true},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "abortTxn",
command: {abortTransaction: 1},
skipSharded: true,
skipUnlessReplicaSet: true,
testcases: [
{
runOnDb: adminDbName, // Must be run against the admin database.
roles: roles_all,
expectFail: true, // Must be run within a transaction.
},
],
},
{
testname: "analyze",
command: {analyze: "x"},
setup: function (db) {
assert.commandWorked(db.x.insert({}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdmin,
privileges: [
{
resource: {db: firstDbName, collection: "x"},
actions: ["analyze"],
},
],
expectFail: true,
},
{
runOnDb: secondDbName,
roles: roles_dbAdminAny,
privileges: [
{
resource: {db: secondDbName, collection: "x"},
actions: ["analyze"],
},
],
expectFail: true,
},
],
},
{
testname: "clusterAbortTransaction",
command: {clusterAbortTransaction: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_addShard",
command: {
_addShard: 1,
shardIdentity: {
shardName: shard0name,
clusterId: ObjectId("5b2031806195dffd744258ee"),
configsvrConnectionString: "foobarbaz/host:20022,host:20023,host:20024",
},
},
skipSharded: true, // Command doesn't exist on mongos
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "addShard",
command: {addShard: "x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["addShard"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
// transitionFromDedicatedConfigServer and transitionToDedicatedConfigServer should be together
// so that we are not in a scenario where the config server is a shard since this interferes with
// other test cases.
{
testname: "transitionFromDedicatedConfigServer",
command: {transitionFromDedicatedConfigServer: 1},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["transitionFromDedicatedConfigServer"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_configsvrTransitionFromDedicatedConfigServer",
command: {_configsvrTransitionFromDedicatedConfigServer: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "transitionToDedicatedConfigServer",
command: {transitionToDedicatedConfigServer: 1},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
expectFail: true,
privileges: [{resource: {cluster: true}, actions: ["transitionToDedicatedConfigServer"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_configsvrTransitionToDedicatedConfigServer",
command: {_configsvrTransitionToDedicatedConfigServer: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
// Test that clusterManager role has permission to run addTagRange
testname: "addTagRange",
command: {
// addTagRange is not a "real command"; it updates config.tags
update: "tags",
updates: [
{
q: {_id: {ns: "test.x", min: 1}},
u: {_id: {ns: "test.x", min: 1}, ns: "test.x"},
},
],
},
skipUnlessSharded: true,
testcases: [
{
runOnDb: "config",
roles: {...roles_clusterManager},
},
],
},
{
testname: "applyOps_empty",
command: {applyOps: []},
skipSharded: true,
testcases: [
{
roles: {__system: 1},
runOnDb: adminDbName,
},
{
roles: {__system: 1},
runOnDb: firstDbName,
},
],
},
{
testname: "applyOps_c_create",
command: {
applyOps: [
{
"op": "c",
"ns": firstDbName + ".$cmd",
"o": {
"create": "x",
},
},
],
},
skipSharded: true,
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {
dbAdminAnyDatabase: 1,
root: 1,
__system: 1,
restore: 1,
},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["createCollection"]},
{resource: {cluster: true}, actions: ["applyOps"]},
],
},
],
},
{
testname: "applyOps_c_create_UUID",
command: {
applyOps: [
{
"ui": UUID("71f1d1d7-68ca-493e-a7e9-f03c94e2e960"),
"op": "c",
"ns": firstDbName + ".$cmd",
"o": {
"create": "x",
},
},
],
},
skipSharded: true,
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1, root: 1, restore: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["createCollection"]},
{resource: {cluster: true}, actions: ["useUUID", "forceUUID", "applyOps"]},
],
},
],
},
{
testname: "applyOps_c_create_UUID_failure",
command: {
applyOps: [
{
"ui": UUID("71f1d1d7-68ca-493e-a7e9-f03c94e2e960"),
"op": "c",
"ns": firstDbName + ".$cmd",
"o": {
"create": "x",
},
},
],
},
skipSharded: true,
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
expectAuthzFailure: true,
runOnDb: adminDbName,
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["createCollection"]},
// Do not have forceUUID.
{resource: {cluster: true}, actions: ["useUUID", "applyOps"]},
],
},
],
},
{
testname: "applyOps_c_drop",
command: {
applyOps: [
{
"op": "c",
"ns": firstDbName + ".$cmd",
"o": {
"drop": "x",
},
},
],
},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.getSiblingDB(firstDbName).x.save({}));
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {
dbAdminAnyDatabase: 1,
root: 1,
__system: 1,
restore: 1,
},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["dropCollection"]},
{resource: {cluster: true}, actions: ["applyOps"]},
],
},
],
},
{
testname: "applyOps_c_drop_UUID",
command: function (state) {
return {
applyOps: [
{
"op": "c",
"ui": state.uuid,
"ns": firstDbName + ".$cmd",
"o": {
"drop": "x",
},
},
],
};
},
skipSharded: true,
setup: function (db) {
let sibling = db.getSiblingDB(firstDbName);
assert.commandWorked(sibling.runCommand({create: "x"}));
return {
collName: sibling.x.getFullName(),
uuid: getUUIDFromListCollections(sibling, sibling.x.getName()),
};
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1, root: 1, restore: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["dropCollection"]},
{resource: {cluster: true}, actions: ["useUUID", "applyOps"]},
],
},
],
},
{
testname: "applyOps_c_drop_UUID_failure",
command: function (state) {
return {
applyOps: [
{
"op": "c",
"ui": state.uuid,
"ns": firstDbName + ".$cmd",
"o": {
"drop": "x",
},
},
],
};
},
skipSharded: true,
setup: function (db) {
let sibling = db.getSiblingDB(firstDbName);
assert.commandWorked(sibling.runCommand({create: "x"}));
return {
collName: sibling.x.getFullName(),
uuid: getUUIDFromListCollections(sibling, sibling.x.getName()),
};
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
expectAuthzFailure: true,
runOnDb: adminDbName,
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["dropCollection"]},
{resource: {cluster: true}, actions: ["applyOps"]},
// don't have useUUID privilege.
],
},
],
},
{
testname: "applyOps_noop",
command: {applyOps: [{"op": "n", "ns": "", "o": {}}]},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
privileges: [{resource: {cluster: true}, actions: ["appendOplogNote", "applyOps"]}],
},
{
runOnDb: firstDbName,
privileges: [{resource: {cluster: true}, actions: ["appendOplogNote", "applyOps"]}],
expectFailure: true,
},
],
},
{
testname: "applyOps_c_renameCollection_twoDbs",
command: {
applyOps: [
{
"op": "c",
"ns": firstDbName + ".$cmd",
"o": {
"renameCollection": firstDbName + ".x",
"to": secondDbName + ".y",
"stayTemp": false,
"dropTarget": false,
},
},
],
},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.getSiblingDB(firstDbName).x.save({}));
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
db.getSiblingDB(secondDbName).y.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1, root: 1},
privileges: [
{
resource: {db: firstDbName, collection: "x"},
actions: ["find", "dropCollection"],
},
{
resource: {db: secondDbName, collection: "y"},
actions: ["insert", "createIndex"],
},
{resource: {cluster: true}, actions: ["applyOps"]},
],
},
],
},
{
testname: "applyOps_insert",
command: {
applyOps: [
{
"op": "i",
"ns": firstDbName + ".x",
"o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5},
},
],
},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.getSiblingDB(firstDbName).x.save({}));
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1, root: 1, restore: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["insert"]},
{resource: {cluster: true}, actions: ["applyOps"]},
],
},
],
},
{
testname: "applyOps_insert_UUID",
command: function (state) {
return {
applyOps: [
{
"op": "i",
"ns": state.collName,
"ui": state.uuid,
"o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5},
},
],
};
},
skipSharded: true,
setup: function (db) {
let sibling = db.getSiblingDB(firstDbName);
assert.commandWorked(sibling.runCommand({create: "x"}));
return {
collName: sibling.x.getFullName(),
uuid: getUUIDFromListCollections(sibling, sibling.x.getName()),
};
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1, root: 1, restore: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["insert"]},
{resource: {cluster: true}, actions: ["useUUID", "applyOps"]},
],
},
],
},
{
testname: "applyOps_insert_with_nonexistent_UUID",
command: function (state) {
return {
applyOps: [
{
"op": "i",
"ns": state.collName,
// Given a nonexistent UUID. The command should fail.
"ui": UUID("71f1d1d7-68ca-493e-a7e9-f03c94e2e960"),
"o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5},
},
],
};
},
skipSharded: true,
setup: function (db) {
let sibling = db.getSiblingDB(firstDbName);
assert.commandWorked(sibling.runCommand({create: "x"}));
return {
collName: sibling.x.getFullName(),
uuid: getUUIDFromListCollections(sibling, sibling.x.getName()),
};
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
// It would be an sanity check failure rather than a auth check
// failure.
expectFail: true,
runOnDb: adminDbName,
roles: {__system: 1, root: 1, restore: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["insert"]},
{resource: {cluster: true}, actions: ["useUUID", "applyOps"]},
],
},
],
},
{
testname: "applyOps_insert_UUID_failure",
command: function (state) {
return {
applyOps: [
{
"op": "i",
"ns": state.collName,
"ui": state.uuid,
"o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5},
},
],
};
},
skipSharded: true,
setup: function (db) {
let sibling = db.getSiblingDB(firstDbName);
assert.commandWorked(sibling.runCommand({create: "x"}));
return {
collName: sibling.x.getFullName(),
uuid: getUUIDFromListCollections(sibling, sibling.x.getName()),
};
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
expectAuthzFailure: true,
runOnDb: adminDbName,
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["insert"]},
{resource: {cluster: true}, actions: ["applyOps"]},
// Don't have useUUID privilege.
],
},
],
},
{
testname: "applyOps_create_and_insert_UUID_failure",
command: function (state) {
return {
applyOps: [
{
"ui": UUID("71f1d1d7-68ca-493e-a7e9-f03c94e2e960"),
"op": "c",
"ns": firstDbName + ".$cmd",
"o": {
"create": "x",
},
},
{
"op": "i",
"ns": firstDbName + ".x",
"ui": UUID("71f1d1d7-68ca-493e-a7e9-f03c94e2e960"),
"o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5},
},
],
};
},
skipSharded: true,
setup: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
// Batching createCollection and insert together is not allowed.
expectAuthzFailure: true,
runOnDb: adminDbName,
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["insert"]},
{resource: {cluster: true}, actions: ["useUUID", "forceUUID", "applyOps"]},
// Require universal privilege set.
],
},
],
},
{
testname: "applyOps_upsert",
command: {
applyOps: [
{
"op": "u",
"ns": firstDbName + ".x",
"o2": {"_id": 1},
"o": {"_id": 1, "data": 8},
},
],
},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.getSiblingDB(firstDbName).x.save({_id: 1, data: 1}));
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1, root: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["update", "insert"]},
{resource: {cluster: true}, actions: ["applyOps"]},
],
},
],
},
{
testname: "applyOps_update",
command: {
applyOps: [
{
"op": "u",
"ns": firstDbName + ".x",
"o2": {"_id": 1},
"o": {"_id": 1, "data": 8},
},
],
},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.getSiblingDB(firstDbName).x.save({_id: 1, data: 1}));
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1, root: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["update"]},
{resource: {cluster: true}, actions: ["applyOps"]},
],
},
],
},
{
testname: "applyOps_update_UUID",
command: function (state) {
return {
applyOps: [
{
"op": "u",
"ns": state.collName,
"ui": state.uuid,
"o2": {"_id": 1},
"o": {"_id": 1, "data": 8},
},
],
};
},
skipSharded: true,
setup: function (db) {
let sibling = db.getSiblingDB(firstDbName);
assert.writeOK(sibling.x.save({_id: 1, data: 1}));
return {
collName: sibling.x.getFullName(),
uuid: getUUIDFromListCollections(sibling, sibling.x.getName()),
};
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1, root: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["update"]},
{resource: {cluster: true}, actions: ["useUUID", "applyOps"]},
],
},
],
},
{
testname: "applyOps_update_UUID_failure",
command: function (state) {
return {
applyOps: [
{
"op": "u",
"ns": state.collName,
"ui": state.uuid,
"o2": {"_id": 1},
"o": {"_id": 1, "data": 8},
},
],
};
},
skipSharded: true,
setup: function (db) {
let sibling = db.getSiblingDB(firstDbName);
assert.writeOK(sibling.x.save({_id: 1, data: 1}));
return {
collName: sibling.x.getFullName(),
uuid: getUUIDFromListCollections(sibling, sibling.x.getName()),
};
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
expectAuthzFailure: true,
runOnDb: adminDbName,
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["update"]},
{resource: {cluster: true}, actions: ["applyOps"]},
],
},
],
},
{
testname: "applyOps_delete",
command: {applyOps: [{"op": "d", "ns": firstDbName + ".x", "o": {"_id": 1}}]},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.getSiblingDB(firstDbName).x.save({_id: 1, data: 1}));
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1, root: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["remove"]},
{resource: {cluster: true}, actions: ["applyOps"]},
],
},
],
},
{
testname: "clusterAggregate",
command: {clusterAggregate: "foo", pipeline: [], cursor: {}},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "aggregate_readonly",
command: {aggregate: "foo", pipeline: [], cursor: {}},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]}],
},
],
},
{
testname: "aggregate_documents",
command: {aggregate: 1, pipeline: [{$documents: [{a: 1}]}], cursor: {}},
testcases: [
{runOnDb: firstDbName, roles: roles_all, privileges: []},
{runOnDb: secondDbName, roles: roles_all, privileges: []},
],
},
{
testname: "aggregate_readonly_views",
setup: function (db) {
assert.commandWorked(db.createView("view", "collection", [{$match: {}}]));
},
teardown: function (db) {
db.view.drop();
},
command: {aggregate: "view", pipeline: [], cursor: {}},
testcases: [
// Tests that a user with read privileges on a view can aggregate it, even if they
// don't have read privileges on the underlying namespace.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "view"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "view"}, actions: ["find"]}],
},
],
},
{
testname: "aggregate_explain",
command: {aggregate: "foo", explain: true, pipeline: [{$match: {bar: 1}}]},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]}],
},
],
},
{
testname: "aggregate_explain_views",
setup: function (db) {
assert.commandWorked(db.createView("view", "collection", [{$match: {}}]));
},
teardown: function (db) {
db.view.drop();
},
command: {aggregate: "view", explain: true, pipeline: [{$match: {bar: 1}}]},
testcases: [
// Tests that a user with read privileges on a view can explain an aggregation on the
// view, even if they don't have read privileges on the underlying namespace.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "view"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "view"}, actions: ["find"]}],
},
],
},
{
testname: "aggregate_out_legacy",
command: function (state, args) {
return {
aggregate: "foo",
pipeline: [{$out: "foo_out"}],
cursor: {},
bypassDocumentValidation: args.bypassDocumentValidation,
};
},
setup: function (db) {
assert.commandWorked(db.getSiblingDB(firstDbName).foo.insert({}));
assert.commandWorked(db.getSiblingDB(secondDbName).foo.insert({}));
},
teardown: function (db) {
assert.commandWorked(db.getSiblingDB(firstDbName).dropDatabase());
assert.commandWorked(db.getSiblingDB(secondDbName).dropDatabase());
},
testcases: [
{
runOnDb: firstDbName,
commandArgs: {bypassDocumentValidation: false},
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "foo_out"}, actions: ["insert"]},
{resource: {db: firstDbName, collection: "foo_out"}, actions: ["remove"]},
],
},
{
runOnDb: secondDbName,
commandArgs: {bypassDocumentValidation: false},
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "foo_out"}, actions: ["insert"]},
{resource: {db: secondDbName, collection: "foo_out"}, actions: ["remove"]},
],
},
{
runOnDb: firstDbName,
commandArgs: {bypassDocumentValidation: true},
// Note that the built-in role must have 'bypassDocumentValidation' for this test.
roles: {dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "foo_out"},
actions: ["insert", "remove", "bypassDocumentValidation"],
},
],
},
],
},
{
testname: "aggregate_out_to_different_db",
command: function (state, args) {
return {
aggregate: "foo",
pipeline: [{$out: {db: args.targetDB, coll: "foo_out"}}],
cursor: {},
bypassDocumentValidation: args.bypassDocumentValidation,
};
},
setup: function (db) {
assert.commandWorked(db.getSiblingDB(firstDbName).foo.insert({}));
assert.commandWorked(db.getSiblingDB(secondDbName).foo.insert({}));
},
teardown: function (db) {
assert.commandWorked(db.getSiblingDB(firstDbName).dropDatabase());
assert.commandWorked(db.getSiblingDB(secondDbName).dropDatabase());
},
testcases: [
{
runOnDb: firstDbName,
commandArgs: {targetDB: firstDbName, bypassDocumentValidation: false},
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "foo_out"},
actions: ["insert", "remove"],
},
],
},
{
runOnDb: secondDbName,
commandArgs: {targetDB: secondDbName, bypassDocumentValidation: false},
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "foo_out"},
actions: ["insert", "remove"],
},
],
},
{
runOnDb: firstDbName,
commandArgs: {targetDB: secondDbName, bypassDocumentValidation: false},
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "foo_out"},
actions: ["insert", "remove"],
},
],
},
// Test for bypassDocumentValidation.
{
runOnDb: firstDbName,
commandArgs: {targetDB: firstDbName, bypassDocumentValidation: true},
// Note that the built-in role must have 'bypassDocumentValidation' for this test.
roles: {dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "foo_out"},
actions: ["insert", "remove", "bypassDocumentValidation"],
},
],
},
// Test for bypassDocumentValidation to a foreign database.
{
runOnDb: firstDbName,
commandArgs: {targetDB: secondDbName, bypassDocumentValidation: true},
// Note that the built-in role must have 'bypassDocumentValidation' for this test.
roles: {root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "foo_out"},
actions: ["insert", "remove", "bypassDocumentValidation"],
},
],
},
],
},
{
testname: "aggregate_merge_insert_documents",
command: function (state, args) {
return {
aggregate: "foo",
pipeline: [
{
$merge: {
into: {db: args.targetDB, coll: "foo_out"},
whenMatched: "fail",
whenNotMatched: "insert",
},
},
],
cursor: {},
bypassDocumentValidation: args.bypassDocumentValidation,
};
},
testcases: [
{
runOnDb: firstDbName,
commandArgs: {targetDB: firstDbName, bypassDocumentValidation: false},
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "foo_out"}, actions: ["insert"]},
],
},
{
runOnDb: secondDbName,
commandArgs: {targetDB: secondDbName, bypassDocumentValidation: false},
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "foo_out"}, actions: ["insert"]},
],
},
{
runOnDb: firstDbName,
commandArgs: {targetDB: secondDbName, bypassDocumentValidation: false},
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "foo_out"}, actions: ["insert"]},
],
},
// Test for bypassDocumentValidation.
{
runOnDb: firstDbName,
commandArgs: {targetDB: firstDbName, bypassDocumentValidation: true},
// Note that the built-in role must have 'bypassDocumentValidation' for this test.
roles: {dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "foo_out"},
actions: ["insert", "bypassDocumentValidation"],
},
],
},
// Test for bypassDocumentValidation to a foreign database.
{
runOnDb: firstDbName,
commandArgs: {targetDB: secondDbName, bypassDocumentValidation: true},
// Note that the built-in role must have 'bypassDocumentValidation' for this test.
roles: {root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "foo_out"},
actions: ["insert", "bypassDocumentValidation"],
},
],
},
],
},
{
testname: "aggregate_merge_replace_documents",
command: function (state, args) {
return {
aggregate: "foo",
pipeline: [
{
$merge: {
into: {db: args.targetDB, coll: "foo_out"},
whenMatched: "replace",
whenNotMatched: "insert",
},
},
],
cursor: {},
bypassDocumentValidation: args.bypassDocumentValidation,
};
},
testcases: [
{
runOnDb: firstDbName,
commandArgs: {targetDB: firstDbName, bypassDocumentValidation: false},
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "foo_out"}, actions: ["insert"]},
{resource: {db: firstDbName, collection: "foo_out"}, actions: ["update"]},
],
},
{
runOnDb: secondDbName,
commandArgs: {targetDB: secondDbName, bypassDocumentValidation: false},
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "foo_out"}, actions: ["insert"]},
{resource: {db: secondDbName, collection: "foo_out"}, actions: ["update"]},
],
},
{
runOnDb: firstDbName,
commandArgs: {targetDB: secondDbName, bypassDocumentValidation: false},
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "foo_out"}, actions: ["insert"]},
{resource: {db: secondDbName, collection: "foo_out"}, actions: ["update"]},
],
},
// Test for bypassDocumentValidation.
{
runOnDb: firstDbName,
commandArgs: {targetDB: firstDbName, bypassDocumentValidation: true},
// Note that the built-in role must have 'bypassDocumentValidation' for this test.
roles: {dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "foo_out"},
actions: ["insert", "update", "bypassDocumentValidation"],
},
],
},
// Test for bypassDocumentValidation to a foreign database.
{
runOnDb: firstDbName,
commandArgs: {targetDB: secondDbName, bypassDocumentValidation: true},
// Note that the built-in role must have 'bypassDocumentValidation' for this test.
roles: {root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "foo_out"},
actions: ["insert", "update", "bypassDocumentValidation"],
},
],
},
],
},
{
testname: "aggregate_readView_writeCollection",
setup: function (db) {
assert.commandWorked(db.createView("view", "collection", [{$match: {}}]));
},
teardown: function (db) {
db.view.drop();
},
command: {aggregate: "view", pipeline: [{$out: "view_out"}], cursor: {}},
testcases: [
{
runOnDb: firstDbName,
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "view"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "view_out"}, actions: ["insert"]},
{resource: {db: firstDbName, collection: "view_out"}, actions: ["remove"]},
],
},
{
runOnDb: secondDbName,
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: secondDbName, collection: "view"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "view_out"}, actions: ["insert"]},
{resource: {db: secondDbName, collection: "view_out"}, actions: ["remove"]},
],
},
],
},
{
testname: "aggregate_writeView",
setup: function (db) {
assert.commandWorked(db.createView("view", "collection", [{$match: {}}]));
},
teardown: function (db) {
db.view.drop();
},
command: {aggregate: "foo", pipeline: [{$out: "view"}], cursor: {}},
testcases: [
{
runOnDb: firstDbName,
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "view"}, actions: ["insert"]},
{resource: {db: firstDbName, collection: "view"}, actions: ["remove"]},
],
expectFail: true, // Cannot write to a view.
},
{
runOnDb: secondDbName,
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "view"}, actions: ["insert"]},
{resource: {db: secondDbName, collection: "view"}, actions: ["remove"]},
],
expectFail: true, // Cannot write to a view.
},
],
},
{
testname: "aggregate_indexStats",
command: {aggregate: "foo", pipeline: [{$indexStats: {}}], cursor: {}},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
},
teardown: function (db) {
db.foo.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_monitoring,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["indexStats"]}],
},
{
runOnDb: secondDbName,
roles: roles_monitoring,
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["indexStats"]}],
},
],
},
{
testname: "aggregate_planCacheStats",
command: {aggregate: "foo", pipeline: [{$planCacheStats: {}}], cursor: {}},
skipSharded: true,
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
},
teardown: function (db) {
db.foo.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_readDbAdmin,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["planCacheRead"]}],
},
{
runOnDb: secondDbName,
roles: roles_readDbAdminAny,
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["planCacheRead"]}],
},
],
},
{
testname: "aggregate_currentOp_allUsers_true",
command: {aggregate: 1, pipeline: [{$currentOp: {allUsers: true}}], cursor: {}},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["inprog"]}],
},
{
runOnDb: adminDbName,
privileges: [{resource: {cluster: true}, actions: ["inprog"]}],
},
{
runOnDb: firstDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["inprog"]}],
expectFail: true,
},
],
},
{
testname: "aggregate_currentOp_allUsers_false",
command: {aggregate: 1, pipeline: [{$currentOp: {allUsers: false}}], cursor: {}},
testcases: [{runOnDb: adminDbName, roles: roles_all}],
skipSharded: true,
},
{
testname: "aggregate_currentOp_allUsers_false_localOps_true",
command: {
aggregate: 1,
pipeline: [{$currentOp: {allUsers: false, localOps: true}}],
cursor: {},
},
testcases: [{runOnDb: adminDbName, roles: roles_all}],
},
{
testname: "aggregate_listLocalSessions_allUsers_true",
command: {aggregate: 1, pipeline: [{$listLocalSessions: {allUsers: true}}], cursor: {}},
testcases: [
{
runOnDb: "config",
roles: {
clusterAdmin: 1,
clusterMonitor: 1,
clusterManager: 1,
root: 1,
__system: 1,
searchCoordinator: 1,
},
},
],
skipSharded: true,
},
{
testname: "aggregate_listLocalSessions_allUsers_false",
command: {aggregate: 1, pipeline: [{$listLocalSessions: {allUsers: false}}], cursor: {}},
testcases: [{runOnDb: adminDbName, roles: roles_all}],
skipSharded: true,
},
{
testname: "aggregate_listSessions_allUsers_true",
command: {
aggregate: "system.sessions",
pipeline: [{$listSessions: {allUsers: true}}],
cursor: {},
},
testcases: [
{
runOnDb: "config",
roles: {
clusterAdmin: 1,
clusterMonitor: 1,
clusterManager: 1,
root: 1,
__system: 1,
searchCoordinator: 1,
},
},
],
},
{
testname: "aggregate_listSessions_allUsers_false",
command: {
aggregate: "system.sessions",
pipeline: [{$listSessions: {allUsers: false}}],
cursor: {},
},
testcases: [{runOnDb: "config", roles: roles_all}],
},
{
testname: "aggregate_lookup",
command: {
aggregate: "foo",
pipeline: [{$lookup: {from: "bar", localField: "_id", foreignField: "_id", as: "results"}}],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
assert.commandWorked(db.createCollection("bar"));
},
teardown: function (db) {
db.foo.drop();
db.bar.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_lookup_documents",
command: {
aggregate: "foo",
pipeline: [{$lookup: {as: "results", pipeline: [{$documents: [{a: 1}]}]}}],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
},
teardown: function (db) {
db.foo.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]}],
},
],
},
{
// A pipeline starting with $documents still requires permissions of other document
// sources later in the pipeline.
testname: "aggregate_documents_then_lookup",
command: {
aggregate: 1,
pipeline: [
{$documents: [{_id: 0}]},
{$lookup: {from: "bar", localField: "_id", foreignField: "_id", as: "results"}},
],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("bar"));
},
teardown: function (db) {
db.bar.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]}],
},
],
},
{
testname: "aggregate_lookup_nested_pipeline",
command: {
aggregate: "foo",
pipeline: [
{
$lookup: {
from: "bar",
pipeline: [{$lookup: {from: "baz", pipeline: [], as: "lookup2"}}],
as: "lookup1",
},
},
],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
assert.commandWorked(db.createCollection("bar"));
assert.commandWorked(db.createCollection("baz"));
},
teardown: function (db) {
db.foo.drop();
db.bar.drop();
db.baz.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "baz"}, actions: ["find"]},
],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "baz"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_lookup_views",
setup: function (db) {
db.createView("view", "collection", [{$match: {}}]);
assert.commandWorked(db.createCollection("foo"));
},
teardown: function (db) {
db.view.drop();
db.foo.drop();
},
command: {
aggregate: "foo",
pipeline: [{$lookup: {from: "view", localField: "_id", foreignField: "_id", as: "results"}}],
cursor: {},
},
testcases: [
// Tests that a user can successfully $lookup into a view when given read access.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "view"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [
{resource: {db: secondDbName, collection: "view"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_graphLookup",
command: {
aggregate: "foo",
pipeline: [
{
$graphLookup: {
from: "bar",
startWith: [1],
connectFromField: "_id",
connectToField: "barId",
as: "results",
},
},
],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
assert.commandWorked(db.createCollection("bar"));
},
teardown: function (db) {
db.foo.drop();
db.bar.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_graphLookup_views",
setup: function (db) {
db.createView("view", "collection", [{$match: {}}]);
assert.commandWorked(db.createCollection("foo"));
},
teardown: function (db) {
db.view.drop();
db.foo.drop();
},
command: {
aggregate: "foo",
pipeline: [
{
$graphLookup: {
from: "view",
startWith: [1],
connectFromField: "_id",
connectToField: "viewId",
as: "results",
},
},
],
cursor: {},
},
testcases: [
// Tests that a user can successfully $graphLookup into a view when given read access.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "view"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [
{resource: {db: secondDbName, collection: "view"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_collStats",
command: {aggregate: "foo", pipeline: [{$collStats: {latencyStats: {}}}], cursor: {}},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
},
teardown: function (db) {
db.foo.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
clusterMonitor: 1,
clusterAdmin: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["collStats"]}],
},
{
runOnDb: secondDbName,
roles: {
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
dbAdminAnyDatabase: 1,
clusterMonitor: 1,
clusterAdmin: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["collStats"]}],
},
],
},
{
testname: "aggregate_collStats_facet",
command: {
aggregate: "foo",
pipeline: [{$collStats: {latencyStats: {}}}, {$facet: {matched: [{$match: {a: 1}}]}}],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
},
teardown: function (db) {
db.foo.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
clusterMonitor: 1,
clusterAdmin: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["collStats"]}],
},
],
},
{
testname: "aggregate_collStats_within_lookup",
command: {
aggregate: "foo",
pipeline: [
{
$lookup: {
from: "lookupColl",
pipeline: [
{
$collStats: {latencyStats: {}},
},
],
as: "result",
},
},
],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
assert.commandWorked(db.createCollection("lookupColl"));
},
teardown: function (db) {
db.foo.drop();
db.lookupColl.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "lookupColl"}, actions: ["collStats"]},
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_collStats_within_union",
command: {
aggregate: "foo",
pipeline: [{$unionWith: {coll: "unionColl", pipeline: [{$collStats: {latencyStats: {}}}]}}],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
assert.commandWorked(db.createCollection("unionColl"));
},
teardown: function (db) {
db.foo.drop();
db.unionColl.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "unionColl"}, actions: ["collStats"]},
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_facet",
command: {
aggregate: "foo",
pipeline: [
{
// There are stages within the $facet stage that require additional privileges.
$facet: {
lookup: [
{
$lookup: {
from: "bar",
localField: "_id",
foreignField: "_id",
as: "results",
},
},
],
graphLookup: [
{
$graphLookup: {
from: "baz",
startWith: [1],
connectFromField: "_id",
connectToField: "bazId",
as: "results",
},
},
],
},
},
],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
assert.commandWorked(db.createCollection("bar"));
assert.commandWorked(db.createCollection("baz"));
},
teardown: function (db) {
db.foo.drop();
db.bar.drop();
db.baz.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "baz"}, actions: ["find"]},
],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "baz"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_facet_views",
command: {
aggregate: "foo",
pipeline: [
{
$facet: {
lookup: [
{
$lookup: {
from: "view1",
localField: "_id",
foreignField: "_id",
as: "results",
},
},
],
graphLookup: [
{
$graphLookup: {
from: "view2",
startWith: "foo",
connectFromField: "_id",
connectToField: "_id",
as: "results",
},
},
],
},
},
],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
assert.commandWorked(
db.createView("view1", "bar", [
{$lookup: {from: "qux", localField: "_id", foreignField: "_id", as: "results"}},
]),
);
assert.commandWorked(
db.createView("view2", "baz", [
{
$graphLookup: {
from: "quz",
startWith: [1],
connectFromField: "_id",
connectToField: "_id",
as: "results",
},
},
]),
);
},
teardown: function (db) {
db.foo.drop();
db.view1.drop();
db.view2.drop();
},
testcases: [
// Tests that a user can successfully $lookup and $graphLookup into views when the
// lookups are nested within a $facet.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "view1"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "view2"}, actions: ["find"]},
],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "view1"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "view2"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_changeStream_one_collection",
command: {aggregate: "foo", pipeline: [{$changeStream: {}}], cursor: {}},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
},
teardown: function (db) {
db.foo.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbOwner: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{
resource: {db: firstDbName, collection: "foo"},
actions: ["changeStream", "find"],
},
],
expectFail: true, // because no replication enabled
},
{
runOnDb: secondDbName,
roles: {readAnyDatabase: 1, readWriteAnyDatabase: 1, root: 1, searchCoordinator: 1, __system: 1},
privileges: [
{
resource: {db: secondDbName, collection: "foo"},
actions: ["changeStream", "find"],
},
],
expectFail: true, // because no replication enabled
},
],
},
{
testname: "aggregate_changeStream_whole_db",
command: {aggregate: 1, pipeline: [{$changeStream: {}}], cursor: {}},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbOwner: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{
resource: {db: firstDbName, collection: ""},
actions: ["changeStream", "find"],
},
],
expectFail: true, // because no replication enabled
},
{
runOnDb: secondDbName,
roles: {readAnyDatabase: 1, readWriteAnyDatabase: 1, root: 1, searchCoordinator: 1, __system: 1},
privileges: [
{
resource: {db: secondDbName, collection: ""},
actions: ["changeStream", "find"],
},
],
expectFail: true, // because no replication enabled
},
],
},
{
testname: "aggregate_changeStream_whole_cluster",
command: {aggregate: 1, pipeline: [{$changeStream: {allChangesForCluster: true}}], cursor: {}},
testcases: [
{
runOnDb: adminDbName,
roles: {readAnyDatabase: 1, readWriteAnyDatabase: 1, root: 1, searchCoordinator: 1, __system: 1},
privileges: [{resource: {db: "", collection: ""}, actions: ["changeStream", "find"]}],
expectFail: true, // because no replication enabled
},
],
},
{
testname: "aggregate_changeStreamSplitLargeEvent_one_collection",
command: {
aggregate: "foo",
pipeline: [{$changeStream: {}}, {$changeStreamSplitLargeEvent: {}}],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("foo"));
},
teardown: function (db) {
db.foo.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbOwner: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{
resource: {db: firstDbName, collection: "foo"},
actions: ["changeStream", "find"],
},
],
expectFail: true, // because no replication enabled
},
{
runOnDb: secondDbName,
roles: {readAnyDatabase: 1, readWriteAnyDatabase: 1, root: 1, searchCoordinator: 1, __system: 1},
privileges: [
{
resource: {db: secondDbName, collection: "foo"},
actions: ["changeStream", "find"],
},
],
expectFail: true, // because no replication enabled
},
],
},
{
testname: "aggregate_changeStreamSplitLargeEvent_whole_db",
command: {aggregate: 1, pipeline: [{$changeStream: {}}, {$changeStreamSplitLargeEvent: {}}], cursor: {}},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbOwner: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{
resource: {db: firstDbName, collection: ""},
actions: ["changeStream", "find"],
},
],
expectFail: true, // because no replication enabled
},
{
runOnDb: secondDbName,
roles: {readAnyDatabase: 1, readWriteAnyDatabase: 1, root: 1, searchCoordinator: 1, __system: 1},
privileges: [
{
resource: {db: secondDbName, collection: ""},
actions: ["changeStream", "find"],
},
],
expectFail: true, // because no replication enabled
},
],
},
{
testname: "aggregate_changeStreamSplitLargeEvent_whole_cluster",
command: {
aggregate: 1,
pipeline: [{$changeStream: {allChangesForCluster: true}}, {$changeStreamSplitLargeEvent: {}}],
cursor: {},
},
testcases: [
{
runOnDb: adminDbName,
roles: {readAnyDatabase: 1, readWriteAnyDatabase: 1, root: 1, searchCoordinator: 1, __system: 1},
privileges: [{resource: {db: "", collection: ""}, actions: ["changeStream", "find"]}],
expectFail: true, // because no replication enabled
},
],
},
{
testname: "appendOplogNote",
command: {appendOplogNote: 1, data: {a: 1}},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {backup: 1, clusterManager: 1, clusterAdmin: 1, root: 1, __system: 1},
privileges: [{resource: {cluster: true}, actions: ["appendOplogNote"]}],
expectFail: true, // because no replication enabled
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "aggregate_geoNear",
command: {
aggregate: "coll",
cursor: {},
pipeline: [{$geoNear: {near: [50, 50], distanceField: "dist"}}],
},
setup: (db) => {
db.coll.drop();
assert.commandWorked(db.coll.createIndex({loc: "2d"}));
assert.commandWorked(db.coll.insert({loc: [45.32, 51.12]}));
},
teardown: (db) => {
db.coll.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "coll"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "coll"}, actions: ["find"]}],
},
],
},
{
testname: "autoCompact",
// Not need to actually enable background compaction, just verify the user can run this
// command.
command: {autoCompact: false},
skipSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagAutoCompact"),
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["compact"]}],
expectFail: true,
},
],
},
{
testname: "buildInfo",
command: {buildInfo: 1},
testcases: [
{runOnDb: firstDbName, roles: roles_all, privileges: []},
{runOnDb: secondDbName, roles: roles_all, privileges: []},
],
},
{
testname: "bulkWrite_insert",
command: {
bulkWrite: 1,
ops: [
{insert: 0, document: {skey: "MongoDB"}},
{insert: 1, document: {skey: "MongoDB"}},
],
nsInfo: [{ns: firstDbName + ".coll"}, {ns: secondDbName + ".coll1"}],
},
skipSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagBulkWriteCommand"),
testcases: [
{
runOnDb: adminDbName,
privileges: [
{resource: {db: firstDbName, collection: "coll"}, actions: ["insert"]},
{resource: {db: secondDbName, collection: "coll1"}, actions: ["insert"]},
],
},
],
},
{
testname: "bulkWrite_insertBypassDocumentValidation",
command: {
bulkWrite: 1,
ops: [
{insert: 0, document: {skey: "MongoDB"}},
{insert: 1, document: {skey: "MongoDB"}},
],
nsInfo: [{ns: firstDbName + ".coll"}, {ns: secondDbName + ".coll1"}],
bypassDocumentValidation: true,
},
skipSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagBulkWriteCommand"),
testcases: [
{
runOnDb: adminDbName,
privileges: [
{
resource: {db: firstDbName, collection: "coll"},
actions: ["insert", "bypassDocumentValidation"],
},
{
resource: {db: secondDbName, collection: "coll1"},
actions: ["insert", "bypassDocumentValidation"],
},
],
},
],
},
{
testname: "bulkWrite_update",
command: {
bulkWrite: 1,
ops: [
{update: 0, filter: {skey: "MongoDB"}, updateMods: {field1: 1}},
{update: 1, filter: {skey: "MongoDB"}, updateMods: {field1: 1}},
],
nsInfo: [{ns: firstDbName + ".coll"}, {ns: secondDbName + ".coll1"}],
},
skipSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagBulkWriteCommand"),
testcases: [
{
runOnDb: adminDbName,
privileges: [
{resource: {db: firstDbName, collection: "coll"}, actions: ["update"]},
{resource: {db: secondDbName, collection: "coll1"}, actions: ["update"]},
],
},
],
},
{
testname: "bulkWrite_updateBypassDocumentValidation",
command: {
bulkWrite: 1,
ops: [
{update: 0, filter: {skey: "MongoDB"}, updateMods: {field1: 1}},
{update: 1, filter: {skey: "MongoDB"}, updateMods: {field1: 1}},
],
nsInfo: [{ns: firstDbName + ".coll"}, {ns: secondDbName + ".coll1"}],
bypassDocumentValidation: true,
},
skipSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagBulkWriteCommand"),
testcases: [
{
runOnDb: adminDbName,
privileges: [
{
resource: {db: firstDbName, collection: "coll"},
actions: ["update", "bypassDocumentValidation"],
},
{
resource: {db: secondDbName, collection: "coll1"},
actions: ["update", "bypassDocumentValidation"],
},
],
},
],
},
{
testname: "bulkWrite_delete",
command: {
bulkWrite: 1,
ops: [
{delete: 0, filter: {skey: "MongoDB"}},
{delete: 1, filter: {skey: "MongoDB"}},
],
nsInfo: [{ns: firstDbName + ".coll"}, {ns: secondDbName + ".coll1"}],
},
skipSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagBulkWriteCommand"),
testcases: [
{
runOnDb: adminDbName,
privileges: [
{resource: {db: firstDbName, collection: "coll"}, actions: ["remove"]},
{resource: {db: secondDbName, collection: "coll1"}, actions: ["remove"]},
],
},
],
},
{
testname: "bulkWrite_deleteBypassDocumentValidation",
command: {
bulkWrite: 1,
ops: [
{delete: 0, filter: {skey: "MongoDB"}},
{delete: 1, filter: {skey: "MongoDB"}},
],
nsInfo: [{ns: firstDbName + ".coll"}, {ns: secondDbName + ".coll1"}],
bypassDocumentValidation: true,
},
skipSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagBulkWriteCommand"),
testcases: [
{
runOnDb: adminDbName,
privileges: [
{
resource: {db: firstDbName, collection: "coll"},
actions: ["remove", "bypassDocumentValidation"],
},
{
resource: {db: secondDbName, collection: "coll1"},
actions: ["remove", "bypassDocumentValidation"],
},
],
},
],
},
{
testname: "bulkWrite_insert_update_delete",
command: {
bulkWrite: 1,
ops: [
{insert: 0, document: {skey: "MongoDB"}},
{insert: 1, document: {skey: "MongoDB"}},
{update: 0, filter: {skey: "MongoDB"}, updateMods: {field1: 1}},
{update: 1, filter: {skey: "MongoDB"}, updateMods: {field1: 1}},
{delete: 0, filter: {skey: "MongoDB"}},
{delete: 1, filter: {skey: "MongoDB"}},
],
nsInfo: [{ns: firstDbName + ".coll"}, {ns: secondDbName + ".coll1"}],
},
skipSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagBulkWriteCommand"),
testcases: [
{
runOnDb: adminDbName,
privileges: [
{resource: {db: firstDbName, collection: "coll"}, actions: ["insert", "update", "remove"]},
{resource: {db: secondDbName, collection: "coll1"}, actions: ["insert", "update", "remove"]},
],
},
],
},
{
testname: "checkShardingIndex_firstDb",
command: {checkShardingIndex: firstDbName + ".x", keyPattern: {_id: 1}},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["find"]}],
},
],
},
{
testname: "checkShardingIndex_secondDb",
command: {checkShardingIndex: secondDbName + ".x", keyPattern: {_id: 1}},
skipSharded: true,
testcases: [
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["find"]}],
},
],
},
{
testname: "cleanupOrphaned",
command: {cleanupOrphaned: firstDbName + ".x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["cleanupOrphaned"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "cleanupReshardCollection",
command: {cleanupReshardCollection: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["reshardCollection"]}],
expectFail: true,
},
],
},
{
testname: "_configsvrCleanupReshardCollection",
command: {_configsvrCleanupReshardCollection: "test.x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_shardsvrCleanupReshardCollection",
command: {_shardsvrCleanupReshardCollection: "test.x", reshardingUUID: UUID()},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "cloneCollectionAsCapped",
command: {cloneCollectionAsCapped: "x", toCollection: "y", size: 1000},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.x.save({}));
db.y.drop();
},
teardown: function (db) {
db.x.drop();
db.y.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{
resource: {db: firstDbName, collection: "y"},
actions: ["insert", "createIndex", "convertToCapped"],
},
{resource: {db: firstDbName, collection: "x"}, actions: ["find"]},
],
},
{
runOnDb: secondDbName,
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{
resource: {db: secondDbName, collection: "y"},
actions: ["insert", "createIndex", "convertToCapped"],
},
{resource: {db: secondDbName, collection: "x"}, actions: ["find"]},
],
},
],
},
{
testname: "collMod",
command: {collMod: "foo"},
setup: function (db) {
assert.writeOK(db.foo.save({}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_dbAdmin),
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["collMod"]}],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_dbAdminAny),
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["collMod"]}],
},
],
},
{
testname: "collMod_views",
setup: function (db) {
assert.commandWorked(db.createView("view", "foo", [{$match: {}}]));
},
teardown: function (db) {
db.view.drop();
},
command: {collMod: "view", viewOn: "bar", pipeline: [{$limit: 7}]},
testcases: [
// Tests that a user who can modify a view (but not read it) may modify it to be a
// view on a namespace the user also cannot read.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_dbAdmin),
privileges: [{resource: {db: firstDbName, collection: "view"}, actions: ["collMod"]}],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_dbAdminAny),
privileges: [{resource: {db: secondDbName, collection: "view"}, actions: ["collMod"]}],
},
// Tests that a user who can both read and modify a view has read privileges on the
// view's underlying namespace.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_dbAdmin),
privileges: [
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "view"},
actions: ["collMod", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_dbAdminAny),
privileges: [
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "view"},
actions: ["collMod", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
],
},
{
testname: "collMod_views_lookup",
setup: function (db) {
assert.commandWorked(db.createView("view", "foo", [{$match: {}}]));
},
teardown: function (db) {
db.view.drop();
},
command: {
collMod: "view",
viewOn: "bar",
pipeline: [{$lookup: {from: "baz", localField: "_id", foreignField: "_id", as: "results"}}],
},
testcases: [
// Tests that a user who can modify a view (but not read it) may modify it to depend
// on namespaces the user also cannot read, including namespaces accessed via $lookup.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_dbAdmin),
privileges: [{resource: {db: firstDbName, collection: "view"}, actions: ["collMod"]}],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_dbAdminAny),
privileges: [{resource: {db: secondDbName, collection: "view"}, actions: ["collMod"]}],
},
// Tests that a user who can both read and modify a view has read privileges on all
// the view's dependent namespaces, including namespaces accessed via $lookup.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_dbAdmin),
privileges: [
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "baz"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "view"},
actions: ["collMod", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_dbAdminAny),
privileges: [
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "baz"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "view"},
actions: ["collMod", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
],
},
{
testname: "collMod_views_graphLookup",
setup: function (db) {
assert.commandWorked(db.createView("view", "foo", [{$match: {}}]));
},
teardown: function (db) {
db.view.drop();
},
command: {
collMod: "view",
viewOn: "bar",
pipeline: [
{
$graphLookup: {
from: "baz",
startWith: [1],
connectFromField: "_id",
connectToField: "bazId",
as: "results",
},
},
],
},
testcases: [
// Tests that a user who can modify a view (but not read it) may modify it to depend
// on namespaces the user also cannot read, including namespaces accessed via
// $graphLookup.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_dbAdmin),
privileges: [{resource: {db: firstDbName, collection: "view"}, actions: ["collMod"]}],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_dbAdminAny),
privileges: [{resource: {db: secondDbName, collection: "view"}, actions: ["collMod"]}],
},
// Tests that a user who can both read and modify a view has read privileges on all
// the view's dependent namespaces, including namespaces accessed via $graphLookup.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_dbAdmin),
privileges: [
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "baz"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "view"},
actions: ["collMod", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_dbAdminAny),
privileges: [
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "baz"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "view"},
actions: ["collMod", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
],
},
{
testname: "collMod_views_facet",
setup: function (db) {
assert.commandWorked(db.createView("view", "foo", []));
},
teardown: function (db) {
db.view.drop();
},
command: {
collMod: "view",
viewOn: "bar",
pipeline: [
{
$facet: {
lookup: [
{
$lookup: {
from: "baz",
localField: "_id",
foreignField: "_id",
as: "results",
},
},
],
graphLookup: [
{
$graphLookup: {
from: "qux",
startWith: "blah",
connectFromField: "_id",
connectToField: "_id",
as: "results",
},
},
],
},
},
],
},
testcases: [
// Tests that a user who can modify a view (but not read it) may modify it to depend
// on namespaces the user also cannot read, including namespaces accessed via $lookup
// and $graphLookup that are nested within a $facet.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_dbAdmin),
privileges: [{resource: {db: firstDbName, collection: "view"}, actions: ["collMod"]}],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_dbAdminAny),
privileges: [{resource: {db: secondDbName, collection: "view"}, actions: ["collMod"]}],
},
// Tests that a user who can both read and modify a view has read privileges on all
// the view's dependent namespaces, including namespaces accessed via $lookup and
// $graphLookup that are nested within a $facet.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_dbAdmin),
privileges: [
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "baz"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "qux"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "view"},
actions: ["collMod", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_dbAdminAny),
privileges: [
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "baz"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "qux"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "view"},
actions: ["collMod", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
],
},
{
testname: "collStats",
command: {collStats: "bar", scale: 1},
setup: function (db) {
assert.writeOK(db.bar.save({}));
},
teardown: function (db) {
assert.commandWorked(db.dropDatabase());
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
clusterMonitor: 1,
clusterAdmin: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: "bar"}, actions: ["collStats"]}],
},
{
runOnDb: secondDbName,
roles: {
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
dbAdminAnyDatabase: 1,
clusterMonitor: 1,
clusterAdmin: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: secondDbName, collection: "bar"}, actions: ["collStats"]}],
},
],
},
{
testname: "commitReshardCollection",
command: {commitReshardCollection: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["reshardCollection"]}],
expectFail: true,
},
],
},
{
testname: "_configsvrCommitReshardCollection",
command: {_configsvrCommitReshardCollection: "test.x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_shardsvrCommitReshardCollection",
command: {_shardsvrCommitReshardCollection: "test.x", reshardingUUID: UUID()},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "commitTxn",
command: {commitTransaction: 1},
skipSharded: true,
skipUnlessReplicaSet: true,
testcases: [
{
runOnDb: adminDbName, // Must be run against the admin database.
roles: roles_all,
expectFail: true, // Must be run within a transaction.
},
],
},
{
testname: "_shardsvrReshardRecipientClone",
command: {
_shardsvrReshardRecipientClone: UUID(),
approxCopySize: {},
cloneTimestamp: new Timestamp(),
donorShards: [],
},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_shardsvrReshardRecipientCriticalSectionStarted",
command: {
_shardsvrReshardRecipientCriticalSectionStarted: UUID(),
},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "clusterCommitTransaction",
command: {clusterCommitTransaction: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "compact",
command: {compact: "foo"},
skipSharded: true,
skipReplicaSet: true, // Will not run compact on a replica set primary.
setup: function (db) {
assert.writeOK(db.foo.save({}));
},
teardown: function (db) {
assert.commandWorked(db.dropDatabase());
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdmin,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["compact"]}],
},
{
runOnDb: secondDbName,
roles: roles_dbAdminAny,
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["compact"]}],
},
],
},
{
testname: "compactStructuredEncryptionData",
command: {compactStructuredEncryptionData: "foo", compactionTokens: {}},
skipSharded: true,
skipUnlessReplicaSet: true,
setup: function (db) {
assert.commandWorked(
db.createCollection("foo", {
encryptedFields: {
"fields": [
{
"path": "firstName",
"keyId": UUID("11d58b8a-0c6c-4d69-a0bd-70c6d9befae9"),
"bsonType": "string",
"queries": {"queryType": "equality"},
},
],
},
}),
);
},
teardown: function (db) {
assert.commandWorked(db.dropDatabase());
},
testcases: [
{
runOnDb: firstDbName,
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["compactStructuredEncryptionData"]},
],
expectFail: true, // Missing compaction token.
},
{
runOnDb: secondDbName,
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["compactStructuredEncryptionData"]},
],
expectFail: true, // Missing compaction token.
},
],
},
{
testname: "cleanupStructuredEncryptionData",
command: {cleanupStructuredEncryptionData: "foo", cleanupTokens: {}},
skipSharded: true,
skipUnlessReplicaSet: true,
setup: function (db) {
assert.commandWorked(
db.createCollection("foo", {
encryptedFields: {
"fields": [
{
"path": "firstName",
"keyId": UUID("11d58b8a-0c6c-4d69-a0bd-70c6d9befae9"),
"bsonType": "string",
"queries": {"queryType": "equality"},
},
],
},
}),
);
},
teardown: function (db) {
assert.commandWorked(db.dropDatabase());
},
testcases: [
{
runOnDb: firstDbName,
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["cleanupStructuredEncryptionData"]},
],
expectFail: true, // Missing compaction token.
},
{
runOnDb: secondDbName,
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["cleanupStructuredEncryptionData"]},
],
expectFail: true, // Missing compaction token.
},
],
},
{
testname: "connectionStatus",
command: {connectionStatus: 1},
testcases: [
{runOnDb: firstDbName, roles: roles_all, privileges: []},
{runOnDb: secondDbName, roles: roles_all, privileges: []},
],
},
{
testname: "connPoolStats",
command: {connPoolStats: 1},
testcases: [
{
runOnDb: firstDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["connPoolStats"]}],
},
{
runOnDb: secondDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["connPoolStats"]}],
},
],
},
{
testname: "connPoolSync",
command: {connPoolSync: 1},
testcases: [
{
runOnDb: firstDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["connPoolSync"]}],
},
{
runOnDb: secondDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["connPoolSync"]}],
},
],
},
{
testname: "convertToCapped",
command: {convertToCapped: "toCapped", size: 1000},
setup: function (db) {
assert.writeOK(db.toCapped.save({}));
},
teardown: function (db) {
db.toCapped.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{
resource: {db: firstDbName, collection: "toCapped"},
actions: ["convertToCapped"],
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "toCapped"},
actions: ["convertToCapped"],
},
],
},
],
},
{
testname: "createRole_authenticationRestrictions",
command: {
createRole: "testRole",
roles: [],
privileges: [],
authenticationRestrictions: [{clientSource: ["127.0.0.1"]}],
},
teardown: function (db) {
db.runCommand({dropRole: "testRole"});
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_userAdmin,
privileges: [
{
resource: {db: firstDbName, collection: ""},
actions: ["createRole", "setAuthenticationRestriction"],
},
],
},
{
runOnDb: secondDbName,
roles: roles_userAdminAny,
privileges: [
{
resource: {db: secondDbName, collection: ""},
actions: ["createRole", "setAuthenticationRestriction"],
},
],
},
],
},
{
testname: "createUser_authenticationRestrictions",
command: {
createUser: "testUser",
pwd: "test",
roles: [],
authenticationRestrictions: [{clientSource: ["127.0.0.1"]}],
},
teardown: function (db) {
db.runCommand({dropUser: "testUser"});
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_userAdmin,
privileges: [
{
resource: {db: firstDbName, collection: ""},
actions: ["createUser", "setAuthenticationRestriction"],
},
],
},
{
runOnDb: secondDbName,
roles: roles_userAdminAny,
privileges: [
{
resource: {db: secondDbName, collection: ""},
actions: ["createUser", "setAuthenticationRestriction"],
},
],
},
],
},
{
testname: "balancerStart",
command: {balancerStart: 1},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
privileges: [{resource: {db: "config", collection: "settings"}, actions: ["update"]}],
expectFail: true, // Command cannot be run on non-config server
},
],
},
{
testname: "_configsvrBalancerStart",
command: {_configsvrBalancerStart: 1},
skipSharded: true,
testcases: [{runOnDb: adminDbName, roles: {__system: 1}, expectFail: true}],
},
{
testname: "balancerStop",
command: {balancerStop: 1},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
privileges: [{resource: {db: "config", collection: "settings"}, actions: ["update"]}],
expectFail: true, // Command cannot be run on non-config server
},
],
},
{
testname: "_configsvrBalancerStop",
command: {_configsvrBalancerStop: 1},
skipSharded: true,
testcases: [{runOnDb: adminDbName, roles: {__system: 1}, expectFail: true}],
},
{
testname: "balancerStatus",
command: {balancerStatus: 1},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
privileges: [{resource: {db: "config", collection: "settings"}, actions: ["find"]}],
},
],
},
{
testname: "_configsvrBalancerStatus",
command: {_configsvrBalancerStatus: 1},
skipSharded: true,
testcases: [{runOnDb: adminDbName, roles: {__system: 1}, expectFail: true}],
},
{
testname: "checkClusterMetadataConsistency",
command: {checkMetadataConsistency: 1},
skipUnlessSharded: true,
setup: function (db) {
assert.commandWorked(db.getSiblingDB("test").createCollection("coll"));
},
teardown: function (db) {
assert.commandWorked(db.getSiblingDB("test").dropDatabase());
},
testcases: [
{
runOnDb: adminDbName,
roles: {clusterManager: 1, clusterAdmin: 1, root: 1, __system: 1},
},
{
runOnDb: adminDbName,
privileges: [{resource: {cluster: true}, actions: ["checkMetadataConsistency"]}],
},
{
runOnDb: adminDbName,
privileges: [{resource: {db: "", collection: ""}, actions: ["checkMetadataConsistency"]}],
expectAuthzFailure: true,
},
{
runOnDb: adminDbName,
privileges: [
{
resource: {db: adminDbName, collection: ""},
actions: ["checkMetadataConsistency"],
},
],
expectAuthzFailure: true,
},
{
runOnDb: adminDbName,
privileges: [
{
resource: {db: adminDbName, collection: "coll"},
actions: ["checkMetadataConsistency"],
},
],
expectAuthzFailure: true,
},
{
runOnDb: adminDbName,
privileges: [{resource: {cluster: true}, actions: ["allCollectionStats"]}],
expectAuthzFailure: true,
},
],
},
{
testname: "checkDatabaseMetadataConsistency",
command: {checkMetadataConsistency: 1},
skipUnlessSharded: true,
setup: function (db) {
assert.commandWorked(db.getSiblingDB("test").createCollection("coll"));
},
teardown: function (db) {
assert.commandWorked(db.getSiblingDB("test").dropDatabase());
},
testcases: [
{
runOnDb: "test",
roles: {clusterManager: 1, clusterAdmin: 1, root: 1, __system: 1},
},
{
runOnDb: "test",
privileges: [{resource: {cluster: true}, actions: ["checkMetadataConsistency"]}],
},
{
runOnDb: "test",
privileges: [{resource: {db: "", collection: ""}, actions: ["checkMetadataConsistency"]}],
},
{
runOnDb: "test",
privileges: [
{
resource: {db: "test", collection: ""},
actions: ["checkMetadataConsistency"],
},
],
},
{
runOnDb: "test",
privileges: [
{
resource: {db: "test", collection: "coll"},
actions: ["checkMetadataConsistency"],
},
],
expectAuthzFailure: true,
},
{
runOnDb: "test",
privileges: [{resource: {cluster: true}, actions: ["allCollectionStats"]}],
expectAuthzFailure: true,
},
],
},
{
testname: "checkCollectionMetadataConsistency",
command: {checkMetadataConsistency: "coll"},
skipUnlessSharded: true,
setup: function (db) {
assert.commandWorked(db.getSiblingDB("test").createCollection("coll"));
},
teardown: function (db) {
assert.commandWorked(db.getSiblingDB("test").dropDatabase());
},
testcases: [
{
runOnDb: "test",
roles: {clusterManager: 1, clusterAdmin: 1, root: 1, __system: 1},
},
{
runOnDb: "test",
privileges: [{resource: {cluster: true}, actions: ["checkMetadataConsistency"]}],
},
{
runOnDb: "test",
privileges: [{resource: {db: "", collection: ""}, actions: ["checkMetadataConsistency"]}],
},
{
runOnDb: "test",
privileges: [
{
resource: {db: "test", collection: ""},
actions: ["checkMetadataConsistency"],
},
],
},
{
runOnDb: "test",
privileges: [
{
resource: {db: "test", collection: "coll"},
actions: ["checkMetadataConsistency"],
},
],
},
{
runOnDb: "test",
privileges: [{resource: {cluster: true}, actions: ["allCollectionStats"]}],
expectAuthzFailure: true,
},
],
},
{
testname: "clusterCount",
command: {clusterCount: "x"},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {cluster: true}, actions: ["internal"]},
{resource: {db: firstDbName, collection: "x"}, actions: ["find"]},
],
// clusterCount is only supported on a shardsvr mongod so this test case is expected
// to fail when it runs against a standalone mongod.
expectFail: true,
},
],
},
{
testname: "count",
command: {count: "x"},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["find"]}],
},
],
},
{
testname: "countWithUUID",
command: function (state) {
return {count: state.uuid};
},
skipSharded: true,
setup: function (db) {
assert.commandWorked(db.runCommand({create: "foo"}));
return {uuid: getUUIDFromListCollections(db, db.foo.getName())};
},
teardown: function (db) {
db.foo.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1, root: 1, backup: 1, searchCoordinator: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {cluster: true}, actions: ["useUUID"]},
],
},
],
},
{
testname: "_configsvrCommitChunkMigration",
command: {
_configsvrCommitChunkMigration: "db.fooHashed",
fromShard: "move_chunk_basic-rs0",
toShard: "move_chunk_basic-rs1",
migratedChunk: {
lastmod: {
e: new ObjectId("62b052ac7f5653479a67a54f"),
t: new Timestamp(1655722668, 22),
v: new Timestamp(1, 0),
},
min: {_id: MinKey},
max: {_id: -4611686018427387902},
},
fromShardCollectionVersion: {
e: new ObjectId("62b052ac7f5653479a67a54f"),
t: new Timestamp(1655722668, 22),
v: new Timestamp(1, 3),
},
validAfter: new Timestamp(1655722670, 6),
},
skipSharded: true,
expectFail: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "_configsvrCommitChunksMerge",
command: {
_configsvrCommitChunksMerge: "x.y",
shard: "shard0000",
collUUID: {uuid: UUID()},
chunkRange: {min: {a: 1}, max: {a: 10}},
},
skipSharded: true,
expectFail: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "_configsvrCommitChunkSplit",
command: {_configsvrCommitChunkSplit: "x.y"},
skipSharded: true,
expectFail: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "create",
command: {create: "x"},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["createCollection"]}],
},
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["insert"]}],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "x"},
actions: ["createCollection"],
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["insert"]}],
},
],
},
{
testname: "create_views",
command: {create: "view", viewOn: "collection", pipeline: [{$match: {}}]},
teardown: function (db) {
db.view.drop();
},
testcases: [
// Tests that a user who can create a view (but not read it) can create a view on a
// namespace the user also cannot read.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{
resource: {db: firstDbName, collection: "view"},
actions: ["createCollection"],
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "view"},
actions: ["createCollection"],
},
],
},
// Tests that a user who can both create and read a view has read privileges on the
// view's underlying namespace.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{resource: {db: firstDbName, collection: "collection"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "view"},
actions: ["createCollection", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{resource: {db: secondDbName, collection: "collection"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "view"},
actions: ["createCollection", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
],
},
{
testname: "create_views_lookup",
command: {
create: "view",
viewOn: "foo",
pipeline: [{$lookup: {from: "bar", localField: "_id", foreignField: "_id", as: "results"}}],
},
teardown: function (db) {
db.view.drop();
},
testcases: [
// Tests that a user who can create a view (but not read it) may create a view that
// depends on namespaces the user also cannot read, including namespaces accessed via
// $lookup.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{
resource: {db: firstDbName, collection: "view"},
actions: ["createCollection"],
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "view"},
actions: ["createCollection"],
},
],
},
// Tests that a user who can both create and read a view has read privileges on all
// the view's dependent namespaces, including namespaces accessed via $lookup.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "view"},
actions: ["createCollection", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "view"},
actions: ["createCollection", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
],
},
{
testname: "create_views_graphLookup",
command: {
create: "view",
viewOn: "foo",
pipeline: [
{
$graphLookup: {
from: "bar",
startWith: [1],
connectFromField: "_id",
connectToField: "barId",
as: "results",
},
},
],
},
teardown: function (db) {
db.view.drop();
},
testcases: [
// Tests that a user who can create a view (but not read it) may create a view that
// depends on namespaces the user also cannot read, including namespaces accessed via
// $graphLookup.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{
resource: {db: firstDbName, collection: "view"},
actions: ["createCollection"],
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "view"},
actions: ["createCollection"],
},
],
},
// Tests that a user who can both create and read a view has read privileges on all
// the view's dependent namespaces, including namespaces accessed via $graphLookup.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "view"},
actions: ["createCollection", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "view"},
actions: ["createCollection", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
],
},
{
testname: "create_views_facet",
command: {
create: "view",
viewOn: "foo",
pipeline: [
{
$facet: {
lookup: [
{
$lookup: {
from: "bar",
localField: "_id",
foreignField: "_id",
as: "results",
},
},
],
graphLookup: [
{
$graphLookup: {
from: "baz",
startWith: "foo",
connectFromField: "_id",
connectToField: "_id",
as: "results",
},
},
],
},
},
],
},
teardown: function (db) {
db.view.drop();
},
testcases: [
// Tests that a user who can create a view (but not read it) may create a view that
// depends on namespaces the user also cannot read, including namespaces accessed via
// $lookup and $graphLookup that are nested within a $facet.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{
resource: {db: firstDbName, collection: "view"},
actions: ["createCollection"],
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "view"},
actions: ["createCollection"],
},
],
},
// Tests that a user who can both create and read a view has read privileges on all
// the view's dependent namespaces, including namespaces accessed via $lookup and
// $graphLookup that are nested within a $facet.
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "baz"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "view"},
actions: ["createCollection", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "bar"}, actions: ["find"]},
{resource: {db: secondDbName, collection: "baz"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "view"},
actions: ["createCollection", "find"],
removeWhenTestingAuthzFailure: false,
},
],
},
],
},
{
testname: "create_capped",
command: {create: "x", capped: true, size: 1000},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{
resource: {db: firstDbName, collection: "x"},
actions: ["createCollection", "convertToCapped"],
},
],
},
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{
resource: {db: firstDbName, collection: "x"},
actions: ["insert", "convertToCapped"],
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "x"},
actions: ["createCollection", "convertToCapped"],
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "x"},
actions: ["insert", "convertToCapped"],
},
],
},
],
},
{
testname: "createIndexes",
command: {createIndexes: "x", indexes: [{key: {a: 1}, name: "a_1"}]},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: Object.extend({
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
restore: 1,
root: 1,
__system: 1,
}),
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["createIndex"]}],
},
],
},
{
testname: "createSearchIndexes",
command: {
createSearchIndexes: "x",
indexes: [{"definition": {"mappings": {"dynamic": true}}}],
},
testcases: [
{
runOnDb: firstDbName,
roles: Object.extend({
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
restore: 1,
root: 1,
__system: 1,
}),
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["createSearchIndexes"]}],
expectFail: true,
},
],
},
{
testname: "currentOp_$ownOps_false",
command: {currentOp: 1, $all: true, $ownOps: false},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["inprog"]}],
},
{runOnDb: firstDbName, roles: {}},
],
},
{
testname: "currentOp_$ownOps_true",
command: {currentOp: 1, $all: true, $ownOps: true},
testcases: [{runOnDb: adminDbName, roles: roles_all}],
skipSharded: true,
},
{
testname: "lockInfo",
command: {lockInfo: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({backup: 1}, roles_monitoring),
privileges: [{resource: {cluster: true}, actions: ["serverStatus"]}],
},
{runOnDb: firstDbName, roles: {}, expectFail: true},
{runOnDb: secondDbName, roles: {}, expectFail: true},
],
},
{
testname: "dataSize_1",
command: {dataSize: firstDbName + ".x"},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["find"]}],
},
],
},
{
testname: "dataSize_2",
command: {dataSize: secondDbName + ".x"},
setup: function (db) {
assert.writeOK(db.x.insert({}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["find"]}],
},
],
},
{
testname: "dbHash",
command: {dbHash: 1},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbOwner: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["dbHash"]}],
},
{
runOnDb: secondDbName,
roles: {readAnyDatabase: 1, readWriteAnyDatabase: 1, root: 1, searchCoordinator: 1, __system: 1},
privileges: [{resource: {db: secondDbName, collection: ""}, actions: ["dbHash"]}],
},
],
},
{
testname: "dbStats",
command: {dbStats: 1, scale: 1024},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
clusterMonitor: 1,
clusterAdmin: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["dbStats"]}],
},
{
runOnDb: secondDbName,
roles: {
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
dbAdminAnyDatabase: 1,
clusterMonitor: 1,
clusterAdmin: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: secondDbName, collection: ""}, actions: ["dbStats"]}],
},
],
},
{
testname: "distinct",
command: {distinct: "coll", key: "a", query: {}},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "coll"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "coll"}, actions: ["find"]}],
},
],
},
{
testname: "drop",
command: {drop: "x"},
setup: function (db) {
assert.writeOK(db.x.save({}));
},
testcases: [
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["dropCollection"]}],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "x"},
actions: ["dropCollection"],
},
],
},
],
},
{
testname: "drop_views",
setup: function (db) {
db.view.drop();
assert.commandWorked(db.createView("view", "collection", [{$match: {}}]));
},
teardown: function (db) {
db.view.drop();
},
command: {drop: "view"},
testcases: [
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [
{
resource: {db: firstDbName, collection: "view"},
actions: ["dropCollection"],
},
],
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [
{
resource: {db: secondDbName, collection: "view"},
actions: ["dropCollection"],
},
],
},
],
},
{
testname: "dropDatabase",
command: {dropDatabase: 1},
setup: function (db) {
assert.writeOK(db.x.save({}));
},
teardown: function (db) {
assert.writeOK(db.x.save({}));
},
testcases: [
{
runOnDb: firstDbName,
roles: {
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
clusterAdmin: 1,
root: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["dropDatabase"]}],
},
{
runOnDb: secondDbName,
roles: {dbAdminAnyDatabase: 1, clusterAdmin: 1, root: 1, __system: 1},
privileges: [{resource: {db: secondDbName, collection: ""}, actions: ["dropDatabase"]}],
},
],
},
{
testname: "dropIndexes",
command: {dropIndexes: "x", index: "*"},
testcases: [
{
runOnDb: firstDbName,
roles: roles_writeDbAdmin,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["dropIndex"]}],
},
{
runOnDb: secondDbName,
roles: roles_writeDbAdminAny,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["dropIndex"]}],
},
],
},
{
testname: "dropSearchIndex",
command: {
dropSearchIndex: "x",
name: "indexName",
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_writeDbAdmin,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["dropSearchIndex"]}],
expectFail: true,
},
{
runOnDb: secondDbName,
roles: roles_writeDbAdminAny,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["dropSearchIndex"]}],
expectFail: true,
},
],
},
{
testname: "enableSharding",
command: {enableSharding: "x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "x", collection: ""}, actions: ["enableSharding"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "features",
command: {features: 1},
testcases: [
{runOnDb: firstDbName, roles: roles_all, privileges: []},
{runOnDb: secondDbName, roles: roles_all, privileges: []},
],
},
{
testname: "features_oidReset",
command: {features: 1, oidReset: true},
testcases: [
{
runOnDb: firstDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["oidReset"]}],
},
{
runOnDb: secondDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["oidReset"]}],
},
],
},
{
testname: "filemd5",
command: {filemd5: 1, root: "fs"},
setup: function (db) {
db.fs.chunks.drop();
assert.writeOK(db.fs.chunks.insert({files_id: 1, n: 0, data: new BinData(0, "test")}));
assert.commandWorked(db.fs.chunks.createIndex({files_id: 1, n: 1}));
},
teardown: function (db) {
db.fs.chunks.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: ""}, actions: ["find"]}],
},
],
},
{
testname: "clusterFind",
command: {clusterFind: "foo"},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "find",
command: {find: "foo"},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]}],
},
],
},
{
testname: "dbstats_on_local",
command: {dbStats: 1},
skipSharded: true,
testcases: [
{
runOnDb: "local",
roles: {
"readLocal": 1,
"readWriteLocal": 1,
"clusterAdmin": 1,
"clusterMonitor": 1,
"root": 1,
"__system": 1,
searchCoordinator: 1,
},
},
],
},
{
testname: "find_config_changelog",
command: {find: "changelog"},
testcases: [
{
runOnDb: "config",
roles: {
"clusterAdmin": 1,
"clusterManager": 1,
"clusterMonitor": 1,
"backup": 1,
"root": 1,
"__system": 1,
"searchCoordinator": 1,
},
privileges: [{resource: {db: "config", collection: "changelog"}, actions: ["find"]}],
},
],
},
{
testname: "find_local_me",
skipSharded: true,
command: {find: "me"},
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterMonitor": 1,
"readLocal": 1,
"readWriteLocal": 1,
"backup": 1,
"root": 1,
"__system": 1,
searchCoordinator: 1,
},
privileges: [{resource: {db: "local", collection: "me"}, actions: ["find"]}],
},
],
},
{
testname: "find_oplog_main",
skipSharded: true,
command: {find: "oplog.$main"},
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterMonitor": 1,
"readLocal": 1,
"readWriteLocal": 1,
"backup": 1,
"root": 1,
"__system": 1,
searchCoordinator: 1,
},
privileges: [{resource: {db: "local", collection: "oplog.$main"}, actions: ["find"]}],
},
],
},
{
testname: "find_oplog_rs",
skipSharded: true,
command: {find: "oplog.rs"},
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterMonitor": 1,
"readLocal": 1,
"readWriteLocal": 1,
"backup": 1,
"root": 1,
"__system": 1,
searchCoordinator: 1,
},
privileges: [{resource: {db: "local", collection: "oplog.rs"}, actions: ["find"]}],
},
],
},
{
testname: "find_replset_election",
skipSharded: true,
command: {find: "replset.election"},
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterMonitor": 1,
"backup": 1,
"root": 1,
"__system": 1,
searchCoordinator: 1,
},
privileges: [{resource: {db: "local", collection: "replset.election"}, actions: ["find"]}],
},
],
},
{
testname: "find_replset_minvalid",
skipSharded: true,
command: {find: "replset.minvalid"},
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterMonitor": 1,
"backup": 1,
"root": 1,
"__system": 1,
searchCoordinator: 1,
},
privileges: [{resource: {db: "local", collection: "replset.minvalid"}, actions: ["find"]}],
},
],
},
{
testname: "find_sources",
skipSharded: true,
command: {find: "sources"},
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterMonitor": 1,
"readLocal": 1,
"readWriteLocal": 1,
"backup": 1,
"root": 1,
"__system": 1,
searchCoordinator: 1,
},
privileges: [{resource: {db: "local", collection: "sources"}, actions: ["find"]}],
},
],
},
{
testname: "find_startup_log",
command: {find: "startup_log"},
skipSharded: true,
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterMonitor": 1,
"readLocal": 1,
"readWriteLocal": 1,
"backup": 1,
"root": 1,
"__system": 1,
searchCoordinator: 1,
},
privileges: [{resource: {db: "local", collection: "startup_log"}, actions: ["find"]}],
},
],
},
{
testname: "find_views",
setup: function (db) {
assert.commandWorked(db.createView("view", "collection", [{$match: {}}]));
},
teardown: function (db) {
db.view.drop();
},
command: {find: "view"},
testcases: [
// Tests that a user with read access to a view can perform a find on it, even if they
// don't have read access to the underlying namespace.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "view"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "view"}, actions: ["find"]}],
},
],
},
{
testname: "findWithTerm",
command: {find: "foo", limit: 1, term: NumberLong(1)},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true, // because of invalid limit
},
],
},
{
testname: "findWithUUID",
command: function (state) {
return {find: state.uuid};
},
skipSharded: true,
setup: function (db) {
assert.commandWorked(db.runCommand({create: "foo"}));
return {uuid: getUUIDFromListCollections(db, db.foo.getName())};
},
teardown: function (db) {
db.foo.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1, root: 1, backup: 1, searchCoordinator: 1},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
{resource: {cluster: true}, actions: ["useUUID"]},
],
},
],
},
{
testname: "findAndModify",
command: {findAndModify: "x", query: {_id: "abc"}, update: {$inc: {n: 1}}},
setup: function (db) {
db.x.drop();
assert.writeOK(db.x.save({_id: "abc", n: 0}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["find", "update"]}],
},
{
runOnDb: secondDbName,
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{
resource: {db: secondDbName, collection: "x"},
actions: ["find", "update"],
},
],
},
],
},
{
testname: "flushRouterConfig",
command: {flushRouterConfig: 1},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({clusterManager: 1}, roles_hostManager),
privileges: [{resource: {cluster: true}, actions: ["flushRouterConfig"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "fsync",
command: {fsync: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["fsync"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "fsyncUnlock",
command: {fsyncUnlock: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["unlock"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "getClusterParameter",
command: {getClusterParameter: "testIntClusterParameter"},
skipTest: (conn) => {
return isStandalone(conn);
},
testcases: [
{
runOnDb: adminDbName,
roles: {clusterManager: 1, clusterAdmin: 1, root: 1, __system: 1},
privileges: [{resource: {cluster: true}, actions: ["getClusterParameter"]}],
},
],
},
{
testname: "getCmdLineOpts",
command: {getCmdLineOpts: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["getCmdLineOpts"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "getDatabaseVersion",
command: {getDatabaseVersion: "test"},
skipSharded: true, // only available on mongod
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {db: "test", collection: ""}, actions: ["getDatabaseVersion"]}],
expectFail: true, // only allowed on shard servers
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "getDefaultRWConcern",
command: {getDefaultRWConcern: 1},
testcases: [
{
runOnDb: adminDbName,
roles: Object.merge(roles_monitoring, roles_clusterManager),
privileges: [{resource: {cluster: true}, actions: ["getDefaultRWConcern"]}],
expectFail: true, // Will fail on standalone servers.
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "getDiagnosticData",
command: {getDiagnosticData: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [
{resource: {cluster: true}, actions: ["serverStatus"]},
{resource: {cluster: true}, actions: ["replSetGetStatus"]},
{resource: {db: "local", collection: "oplog.rs"}, actions: ["collStats"]},
{
resource: {cluster: true},
actions: ["connPoolStats"],
}, // Only needed against mongos
],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "getLog",
command: {getLog: "*"},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["getLog"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "clusterGetMore",
command: {clusterGetMore: NumberLong(1), collection: "foo"},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "getMoreWithTerm",
command: {getMore: NumberLong("1"), collection: "foo", term: NumberLong(1)},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "getParameter",
command: {getParameter: 1, quiet: 1},
testcases: [
{
runOnDb: adminDbName,
roles: {
backup: 1,
restore: 1,
clusterMonitor: 1,
clusterAdmin: 1,
root: 1,
__system: 1,
searchCoordinator: 1,
},
privileges: [{resource: {cluster: true}, actions: ["getParameter"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "getQueryableEncryptionCountInfo",
command: {
getQueryableEncryptionCountInfo: "foo",
tokens: [{tokens: [{"s": BinData(0, "lUBO7Mov5Sb+c/D4cJ9whhhw/+PZFLCk/AQU2+BpumQ=")}]}],
"queryType": "insert",
},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
},
],
},
{
testname: "getShardMap",
command: {getShardMap: "x"},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["getShardMap"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "getShardVersion",
command: {getShardVersion: "test.foo"},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {db: "test", collection: "foo"}, actions: ["getShardVersion"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "hostInfo",
command: {hostInfo: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["hostInfo"]}],
},
{
runOnDb: firstDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["hostInfo"]}],
},
{
runOnDb: secondDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["hostInfo"]}],
},
],
},
{
testname: "clusterBulkWrite",
command: {
clusterBulkWrite: 1,
ops: [
{insert: 0, document: {skey: "MongoDB"}},
{insert: 1, document: {skey: "MongoDB"}},
],
nsInfo: [{ns: firstDbName + ".coll"}, {ns: secondDbName + ".coll1"}],
},
skipSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagBulkWriteCommand"),
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "clusterDelete",
command: {clusterDelete: "foo", deletes: [{q: {}, limit: 1}]},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "clusterInsert",
command: {clusterInsert: "foo", documents: [{data: 5}]},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "clusterUpdate",
command: {clusterUpdate: "foo", updates: [{q: {doesNotExist: 1}, u: {x: 1}}]},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "commitShardRemoval",
command: {commitShardRemoval: "x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["removeShard"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "insert",
command: {insert: "foo", documents: [{data: 5}]},
testcases: [
{
runOnDb: firstDbName,
roles: roles_write,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["insert"]}],
},
{
runOnDb: secondDbName,
roles: {"readWriteAnyDatabase": 1, "root": 1, "__system": 1, "restore": 1},
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["insert"]}],
},
],
},
{
testname: "insert_config_changelog",
command: {insert: "changelog", documents: [{data: 5}]},
testcases: [
{
runOnDb: "config",
roles: {"clusterAdmin": 1, "clusterManager": 1, "root": 1, "__system": 1, "restore": 1},
privileges: [{resource: {db: "config", collection: "changelog"}, actions: ["insert"]}],
},
],
},
{
testname: "insert_me",
command: {insert: "me", documents: [{data: 5}]},
skipSharded: true,
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterManager": 1,
"readWriteLocal": 1,
"root": 1,
"__system": 1,
"restore": 1,
},
privileges: [{resource: {db: "local", collection: "me"}, actions: ["insert"]}],
},
],
},
/* Untestable, because insert to oplog.$main will always fail
{
testname: "insert_oplog_main",
command: {insert: "oplog.$main", documents: [{ts: Timestamp()}]},
skipSharded: true,
setup: function(db) {
assert.commandWorked(db.createCollection("oplog.$main", {capped: true, size: 10000}));
},
teardown: function(db) {
db.oplog.$main.drop();
},
testcases: [
{
runOnDb: "local",
roles: {"clusterAdmin": 1, "clusterMonitor": 1, "readWriteLocal": 1, "restore": 1,
"root": 1, "__system": 1},
privileges:
[{resource: {db: "local", collection: "oplog.$main"}, actions: ["insert"]}],
},
]
},*/
{
testname: "insert_oplog_rs",
command: {insert: "oplog.rs", documents: [{ts: Timestamp()}]},
skipSharded: true,
skipReplicaSet: true, // Write operations to oplog on clusters running as replica sets are unavailable since 5.0.
setup: function (db) {
if (!db.getCollectionNames().includes("oplog.rs")) {
assert.commandWorked(db.runCommand({create: "oplog.rs", capped: true, size: 10000}));
} else {
if (storageEngineIsWiredTigerOrInMemory()) {
assert.commandWorked(db.adminCommand({replSetResizeOplog: 1, size: 10000}));
} else {
assert.commandWorked(db.runCommand({drop: "oplog.rs"}));
assert.commandWorked(db.runCommand({create: "oplog.rs", capped: true, size: 10000}));
}
}
},
teardown: function (db) {
assert.commandWorked(db.oplog.rs.deleteMany({}));
},
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterManager": 1,
"readWriteLocal": 1,
"restore": 1,
"root": 1,
"__system": 1,
},
privileges: [{resource: {db: "local", collection: "oplog.rs"}, actions: ["insert"]}],
},
],
},
{
testname: "insert_replset_election",
command: {insert: "replset.election", documents: [{data: 5}]},
skipSharded: true,
testcases: [
{
runOnDb: "local",
roles: {"clusterAdmin": 1, "clusterManager": 1, "root": 1, "__system": 1, "restore": 1},
privileges: [{resource: {db: "local", collection: "replset.election"}, actions: ["insert"]}],
},
],
},
{
testname: "insert_replset_minvalid",
command: {insert: "replset.minvalid", documents: [{data: 5}]},
skipSharded: true,
testcases: [
{
runOnDb: "local",
roles: {"clusterAdmin": 1, "clusterManager": 1, "root": 1, "__system": 1, "restore": 1},
privileges: [{resource: {db: "local", collection: "replset.minvalid"}, actions: ["insert"]}],
},
],
},
{
testname: "insert_system_users",
command: {insert: "system.users", documents: [{user: "unique", db: "test"}]},
setup: function (db) {
// Ensure unique indexes consistently cause insertion failure
db.system.users.remove({user: "unique", db: "test"});
assert.writeOK(db.system.users.insert({user: "unique", db: "test"}));
},
teardown: function (db) {
db.system.users.remove({user: "unique", db: "test"});
},
testcases: [
{
runOnDb: "admin",
roles: {"root": 1, "__system": 1, "restore": 1},
privileges: [{resource: {db: "admin", collection: "system.users"}, actions: ["insert"]}],
expectFail: true,
},
],
},
{
testname: "insert_sources",
command: {insert: "sources", documents: [{data: 5}]},
skipSharded: true,
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterManager": 1,
"readWriteLocal": 1,
"root": 1,
"__system": 1,
"restore": 1,
},
privileges: [{resource: {db: "local", collection: "sources"}, actions: ["insert"]}],
},
],
},
{
testname: "insert_startup_log",
command: {insert: "startup_log", documents: [{data: 5}]},
skipSharded: true,
testcases: [
{
runOnDb: "local",
roles: {
"clusterAdmin": 1,
"clusterManager": 1,
"readWriteLocal": 1,
"root": 1,
"__system": 1,
"restore": 1,
},
privileges: [{resource: {db: "local", collection: "startup_log"}, actions: ["insert"]}],
},
],
},
{
testname: "isMaster",
command: {isMaster: 1},
testcases: [
{runOnDb: adminDbName, roles: roles_all, privileges: []},
{runOnDb: firstDbName, roles: roles_all, privileges: []},
{runOnDb: secondDbName, roles: roles_all, privileges: []},
],
},
{
testname: "killCursors",
setup: function (runOnDb) {
return runOnDb;
},
command: function (runOnDb) {
// Don't create the cursor during setup() because we're not logged in yet.
// Cursor must be created with same user who tries to kill it.
const cmd = runOnDb.runCommand({find: "foo", batchSize: 2});
if (cmd.ok === 1) {
return {killCursors: "foo", cursors: [cmd.cursor.id]};
} else {
// If we can't even execute a find, then we certainly can't kill it.
// Let it fail/unauthorized via the find command
return {find: "foo", batchSize: 2};
}
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbOwner: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
expectFail: true,
},
{
runOnDb: secondDbName,
roles: {
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]}],
expectFail: true,
},
],
},
{
testname: "killOp", // standalone version
command: {killOp: 1, op: 123},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["killop"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "killOp", // sharded version
command: {killOp: 1, op: "shard1:123"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["killop"]}],
expectFail: true, // we won't be able to find the shardId
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
// The rest of kill sessions auth testing is in the kill_sessions fixture (because calling
// the commands logged in as a different user needs to have different results). These tests
// merely verify that the hostManager is the only role with killAnySession.
{
testname: "killAllSessions",
command: {killAllSessions: []},
testcases: [{runOnDb: adminDbName, roles: roles_hostManager}],
},
{
testname: "killAllSessionsByPattern",
command: {killAllSessionsByPattern: []},
testcases: [{runOnDb: adminDbName, roles: roles_hostManager, expectFail: true}],
},
{
testname: "listCommands",
command: {listCommands: 1},
testcases: [
{runOnDb: adminDbName, roles: roles_all, privileges: [], expectFail: true},
{runOnDb: firstDbName, roles: roles_all, privileges: []},
{runOnDb: secondDbName, roles: roles_all, privileges: []},
],
},
{
testname: "listDatabases",
command: {listDatabases: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_all,
privileges: [{resource: {cluster: true}, actions: ["listDatabases"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "listCollections",
command: {listCollections: 1},
setup: function (db) {
assert.writeOK(db.x.insert({_id: 5}));
assert.writeOK(db.y.insert({_id: 6}));
},
teardown: function (db) {
db.x.drop();
db.y.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
backup: 1,
restore: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["listCollections"]}],
},
],
},
{
testname: "listOwnCollections",
command: {listCollections: 1, nameOnly: true, authorizedCollections: true},
setup: function (db) {
assert.writeOK(db.x.insert({_id: 5}));
assert.writeOK(db.y.insert({_id: 6}));
},
teardown: function (db) {
db.x.drop();
db.y.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
userAdmin: 1,
userAdminAnyDatabase: 1,
hostManager: 1,
enableSharding: 1,
clusterMonitor: 1,
clusterManager: 1,
clusterAdmin: 1,
backup: 1,
restore: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
},
{
runOnDb: firstDbName,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["find"]}],
},
{
runOnDb: firstDbName,
privileges: [{resource: {db: "", collection: "x"}, actions: ["find"]}],
},
{
runOnDb: firstDbName,
privileges: [{resource: {db: "", collection: ""}, actions: ["find"]}],
},
{
runOnDb: firstDbName,
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["find"]}],
},
{
runOnDb: firstDbName,
privileges: [{resource: {cluster: true}, actions: ["find"]}],
expectAuthzFailure: true,
},
{
runOnDb: firstDbName,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["find"]}],
expectAuthzFailure: true,
},
{runOnDb: firstDbName, privileges: [], expectAuthzFailure: true},
],
},
{
testname: "listCollections_rawData",
command: {listCollections: 1, rawData: true},
testcases: [{runOnDb: firstDbName, roles: {__system: 1}}],
},
{
testname: "listIndexes",
command: {listIndexes: "x"},
setup: function (db) {
assert.writeOK(db.x.insert({_id: 5}));
assert.writeOK(db.x.insert({_id: 6}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["listIndexes"]}],
},
],
},
{
testname: "listIndexesWithUUID",
command: function (state) {
return {listIndexes: state.uuid};
},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.x.insert({_id: 5}));
assert.writeOK(db.x.insert({_id: 6}));
return {uuid: getUUIDFromListCollections(db, db.x.getName())};
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {backup: 1, root: 1, searchCoordinator: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["listIndexes"]},
{resource: {cluster: true}, actions: ["useUUID"]},
],
},
],
},
{
testname: "listSearchIndexes",
command: {listSearchIndexes: "x"},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["listSearchIndexes"]}],
expectFail: true,
},
],
},
{
testname: "listShards",
command: {listShards: 1},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({clusterManager: 1}, roles_monitoring),
privileges: [{resource: {cluster: true}, actions: ["listShards"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "logRotate",
command: {logRotate: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["logRotate"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "mapReduce_readonly",
command: {
mapreduce: "x",
map: function () {
emit(this.groupby, this.n);
},
reduce: function (id, emits) {
return Array.sum(emits);
},
out: {inline: 1},
},
setup: function (db) {
assert.writeOK(db.x.insert({groupby: 1, n: 5}));
assert.writeOK(db.x.insert({groupby: 1, n: 6}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["find"]}],
},
],
},
{
testname: "mapReduce_write",
command: {
mapreduce: "x",
map: function () {
emit(this.groupby, this.n);
},
reduce: function (id, emits) {
return Array.sum(emits);
},
out: "mr_out",
},
setup: function (db) {
assert.writeOK(db.x.insert({groupby: 1, n: 5}));
assert.writeOK(db.x.insert({groupby: 1, n: 6}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: {readWrite: 1, readWriteAnyDatabase: 1, dbOwner: 1, root: 1, __system: 1},
privileges: [
{resource: {db: firstDbName, collection: "x"}, actions: ["find"]},
{
resource: {db: firstDbName, collection: "mr_out"},
actions: ["insert", "remove"],
},
],
},
{
runOnDb: secondDbName,
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{resource: {db: secondDbName, collection: "x"}, actions: ["find"]},
{
resource: {db: secondDbName, collection: "mr_out"},
actions: ["insert", "remove"],
},
],
},
],
},
{
testname: "s_mergeChunks",
command: {mergeChunks: "test.x", bounds: [{i: 0}, {i: 5}]},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {db: "test", collection: "x"}, actions: ["splitChunk"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "d_mergeChunks",
command: {mergeChunks: "test.x", bounds: [{i: 0}, {i: 5}], epoch: ObjectId("57dc3d7da4fce4358afa85b8")},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "updateSearchIndex",
command: {
updateSearchIndex: "foo",
id: "index-ID-number",
definition: {"textBlob": "blob"},
},
testcases: [
{
runOnDb: firstDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdmin),
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["updateSearchIndex"]}],
expectFail: true,
},
{
runOnDb: secondDbName,
roles: Object.extend({restore: 1}, roles_writeDbAdminAny),
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["updateSearchIndex"]}],
expectFail: true,
},
],
},
{
testname: "s_moveChunk",
command: {moveChunk: "test.x", find: {}, to: "a"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {db: "test", collection: "x"}, actions: ["moveChunk"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "d_moveChunk",
command: {moveChunk: "test.x", fromShard: "a", toShard: "b", min: {}, max: {}, maxChunkSizeBytes: 1024},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "moveCollection",
command: {moveCollection: "test.x", toShard: "move_collection-rs"},
skipUnlessSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagMoveCollection"),
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["moveCollection"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "s_moveRange",
command: {moveRange: "test.x", min: {x: 1}, toShard: "a"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {db: "test", collection: "x"}, actions: ["moveChunk"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "d_moveRange",
command: {
_shardsvrMoveRange: "test.x",
fromShard: "a",
toShard: "b",
min: {},
max: {},
maxChunkSizeBytes: 1024,
collectionTimestamp: Timestamp(1, 0),
},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "movePrimary",
command: {movePrimary: "x", to: "a"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {db: "x", collection: ""}, actions: ["moveChunk"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "netstat",
command: {netstat: "x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["netstat"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "eseRotateActiveKEK",
command: {eseRotateActiveKEK: 1},
skipTest: () => {
return !getBuildInfo().modules.includes("atlas");
},
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["eseRotateActiveKEK"]}],
expectFail: true,
},
],
},
{
testname: "getESERotateActiveKEKStatus",
command: {getESERotateActiveKEKStatus: 1},
skipTest: () => {
return !getBuildInfo().modules.includes("atlas");
},
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["getESERotateActiveKEKStatus"]}],
expectFail: true,
},
],
},
{
testname: "oidcListKeys",
command: {oidcListKeys: 1},
// Only enterprise knows of this command.
skipTest: (conn) => {
return !getBuildInfo().modules.includes("enterprise");
},
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["oidcListKeys"]}],
expectFail: true, // Server isn't configured for MONGODB-OIDC as an auth mechanism.
},
],
},
{
testname: "oidcRefreshKeys",
command: {oidcRefreshKeys: 1},
// Only enterprise knows of this command.
skipTest: (conn) => {
return !getBuildInfo().modules.includes("enterprise");
},
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["oidcRefreshKeys"]}],
expectFail: true, // Server isn't figured for MONGODB-OIDC as an auth mechanism.
},
],
},
{
testname: "planCacheIndexFilter",
command: {planCacheClearFilters: "x"},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.x.save({}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdmin,
privileges: [
{
resource: {db: firstDbName, collection: "x"},
actions: ["planCacheIndexFilter"],
},
],
},
{
runOnDb: secondDbName,
roles: roles_dbAdminAny,
privileges: [
{
resource: {db: secondDbName, collection: "x"},
actions: ["planCacheIndexFilter"],
},
],
},
],
},
{
testname: "planCacheWrite",
command: {planCacheClear: "x"},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.x.save({}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdmin,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["planCacheWrite"]}],
},
{
runOnDb: secondDbName,
roles: roles_dbAdminAny,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["planCacheWrite"]}],
},
],
},
{
testname: "ping",
command: {ping: 1},
testcases: [
{runOnDb: adminDbName, roles: roles_all, privileges: []},
{runOnDb: firstDbName, roles: roles_all, privileges: []},
{runOnDb: secondDbName, roles: roles_all, privileges: []},
],
},
{
testname: "profile",
command: {profile: 0},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdmin,
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["enableProfiler"]}],
},
{
runOnDb: secondDbName,
roles: roles_dbAdminAny,
privileges: [{resource: {db: secondDbName, collection: ""}, actions: ["enableProfiler"]}],
},
],
},
{
testname: "profileGetLevel",
command: {profile: -1},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: {
backup: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
clusterMonitor: 1,
clusterAdmin: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{
resource: {db: firstDbName, collection: "system.profile"},
actions: ["find"],
},
],
},
{
runOnDb: secondDbName,
roles: {
backup: 1,
dbAdminAnyDatabase: 1,
clusterMonitor: 1,
clusterAdmin: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{
resource: {db: secondDbName, collection: "system.profile"},
actions: ["find"],
},
],
},
],
},
{
testname: "profileSetSampleRate",
command: {profile: -1, sampleRate: 0.5},
skipSharded: true,
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdmin,
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["enableProfiler"]}],
},
{
runOnDb: secondDbName,
roles: roles_dbAdminAny,
privileges: [{resource: {db: secondDbName, collection: ""}, actions: ["enableProfiler"]}],
},
],
},
{
testname: "profile_mongos",
command: {profile: 0, slowms: 10, sampleRate: 0.5},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_dbAdminAny,
privileges: [{resource: {db: adminDbName, collection: ""}, actions: ["enableProfiler"]}],
},
{
runOnDb: firstDbName,
roles: roles_dbAdmin,
},
],
},
{
testname: "profileGetLevel_mongos",
command: {profile: -1},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {
backup: 1,
dbAdminAnyDatabase: 1,
clusterMonitor: 1,
clusterAdmin: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{
resource: {db: adminDbName, collection: "system.profile"},
actions: ["find"],
},
],
},
{
runOnDb: firstDbName,
roles: {
backup: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
clusterMonitor: 1,
clusterAdmin: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{
resource: {db: firstDbName, collection: "system.profile"},
actions: ["find"],
},
],
},
],
},
{
testname: "refineCollectionShardKey",
command: {refineCollectionShardKey: "test.x", key: {aKey: 1}},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [
{
resource: {db: "test", collection: "x"},
actions: ["refineCollectionShardKey"],
},
],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_configsvrCommitRefineCollectionShardKey",
command: {
_configsvrCommitRefineCollectionShardKey: "test.x",
key: {aKey: 1},
newEpoch: new ObjectId(),
newTimestamp: Timestamp(),
oldTimestamp: Timestamp(),
},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "renameCollection_sameDb",
command: {renameCollection: firstDbName + ".x", to: firstDbName + ".y", dropTarget: true},
setup: function (db) {
assert.writeOK(db.getSiblingDB(firstDbName).x.save({}));
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
db.getSiblingDB(firstDbName).y.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: roles_writeDbAdmin,
privileges: [
{
resource: {db: firstDbName, collection: ""},
actions: ["renameCollectionSameDB"],
},
{resource: {db: firstDbName, collection: "y"}, actions: ["dropCollection"]},
],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
// Make sure that you cannot use renameCollectionSameDB to rename from a collection you
// don't have read access on to one that you do.
testname: "renameCollection_sameDb_failure",
command: {renameCollection: firstDbName + ".x", to: firstDbName + ".y"},
setup: function (db) {
assert.writeOK(db.getSiblingDB(firstDbName).x.save({}));
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
db.getSiblingDB(firstDbName).y.drop();
},
testcases: [
{
runOnDb: adminDbName,
privileges: [
{
resource: {db: firstDbName, collection: ""},
actions: ["renameCollectionSameDB"],
},
{resource: {db: firstDbName, collection: "y"}, actions: ["find"]},
],
expectAuthzFailure: true,
},
],
},
{
testname: "renameCollection_twoDbs",
command: {renameCollection: firstDbName + ".x", to: secondDbName + ".y"},
skipSharded: true,
setup: function (db) {
assert.writeOK(db.getSiblingDB(firstDbName).x.save({}));
assert.writeOK(db.getSiblingDB(secondDbName).y.save({}));
db.getSiblingDB(secondDbName).y.drop();
// Running movePrimary is necessary on mongos, but doesn't exist on non-sharded
// systems.
if (db.getMongo().isMongos()) {
const shardId = assert.commandWorked(db.getSiblingDB(adminDbName).runCommand({listShards: 1}))
.shards[0]["_id"];
assert.commandWorked(
db.getSiblingDB(adminDbName).runCommand({movePrimary: firstDbName, to: shardId}),
);
assert.commandWorked(
db.getSiblingDB(adminDbName).runCommand({movePrimary: secondDbName, to: shardId}),
);
}
},
teardown: function (db) {
db.getSiblingDB(firstDbName).x.drop();
db.getSiblingDB(secondDbName).y.drop();
},
testcases: [
{
runOnDb: adminDbName,
roles: {readWriteAnyDatabase: 1, root: 1, __system: 1},
privileges: [
{
resource: {db: firstDbName, collection: "x"},
actions: ["find", "dropCollection"],
},
{
resource: {db: secondDbName, collection: "y"},
actions: ["insert", "createIndex"],
},
],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "reIndex",
command: {reIndex: "x"},
skipSharded: true,
skipReplicaSet: true, // Only allowed on a standalone mongod instance.
setup: function (db) {
assert.writeOK(db.x.save({}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdmin,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["reIndex"]}],
},
{
runOnDb: secondDbName,
roles: roles_dbAdminAny,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["reIndex"]}],
},
],
},
{
testname: "removeShard",
command: {removeShard: "x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["removeShard"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetFreeze",
command: {replSetFreeze: "x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["replSetStateChange"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetGetRBID",
command: {replSetGetRBID: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetGetStatus",
command: {replSetGetStatus: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {
clusterMonitor: 1,
clusterManager: 1,
clusterAdmin: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {cluster: true}, actions: ["replSetGetStatus"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetGetConfig",
command: {replSetGetConfig: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {
clusterMonitor: 1,
clusterManager: 1,
clusterAdmin: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {cluster: true}, actions: ["replSetGetConfig"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetHeartbeat",
command: {replSetHeartbeat: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetInitiate",
command: {replSetInitiate: "x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["replSetConfigure"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetMaintenance",
command: {replSetMaintenance: "x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["replSetStateChange"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetReconfig",
command: {replSetReconfig: "x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["replSetConfigure"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetStepDown",
command: {replSetStepDown: "x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["replSetStateChange"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetStepUp",
command: {replSetStepUp: "x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["replSetStateChange"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "replSetSyncFrom",
command: {replSetSyncFrom: "x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["replSetStateChange"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "reshardCollection",
command: {reshardCollection: "test.x", key: {_id: 1}},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["reshardCollection"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "rewriteCollection",
command: {rewriteCollection: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["rewriteCollection"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_configsvrReshardCollection",
command: {_configsvrReshardCollection: "test.x", key: {_id: 1}},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "rotateCertificates",
command: {rotateCertificates: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["rotateCertificates"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "rotateFTDC",
command: {rotateFTDC: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [
{resource: {cluster: true}, actions: ["serverStatus"]},
{resource: {cluster: true}, actions: ["replSetGetStatus"]},
{resource: {db: "local", collection: "oplog.rs"}, actions: ["collStats"]},
{
resource: {cluster: true},
actions: ["connPoolStats"],
}, // Only needed against mongos
],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "serverStatus",
command: {serverStatus: 1},
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({backup: 1}, roles_monitoring),
privileges: [{resource: {cluster: true}, actions: ["serverStatus"]}],
},
{
runOnDb: firstDbName,
roles: Object.extend({backup: 1}, roles_monitoring),
privileges: [{resource: {cluster: true}, actions: ["serverStatus"]}],
},
{
runOnDb: secondDbName,
roles: Object.extend({backup: 1}, roles_monitoring),
privileges: [{resource: {cluster: true}, actions: ["serverStatus"]}],
},
],
},
{
testname: "setClusterParameter",
command: {setClusterParameter: {testIntClusterParameter: {intData: 17}}},
skipTest: (conn) => {
return isStandalone(conn);
},
testcases: [
{
runOnDb: adminDbName,
roles: {clusterManager: 1, clusterAdmin: 1, root: 1, __system: 1},
privileges: [{resource: {cluster: true}, actions: ["setClusterParameter"]}],
},
],
},
{
testname: "setDefaultRWConcern",
command: {
setDefaultRWConcern: 1,
defaultReadConcern: {level: "local"},
defaultWriteConcern: {w: 1},
},
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["setDefaultRWConcern"]}],
expectFail: true, // Will fail on standalone servers.
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "setFeatureCompatibilityVersion",
command: {setFeatureCompatibilityVersion: latestFCV, confirm: true},
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["setFeatureCompatibilityVersion"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "setProfilingFilterGlobally",
command: {setProfilingFilterGlobally: 1, filter: {nreturned: 0}},
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdminAny,
privileges: [{resource: {db: "", collection: ""}, actions: ["enableProfiler"]}],
expectFail: true /* the command will fail because the query knob is not turned on */,
},
{
runOnDb: firstDbName,
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["enableProfiler"]}],
expectAuthzFailure: true,
},
],
},
{
testname: "setParameter",
command: {setParameter: 1, quiet: 1},
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["setParameter"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "setShardVersion",
command: {setShardVersion: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "setUserWriteBlockMode",
command: {setUserWriteBlockMode: 1, global: false},
skipTest: (conn) => {
return isStandalone(conn);
},
testcases: [
{
runOnDb: adminDbName,
roles: {backup: 1, restore: 1, root: 1, __system: 1},
privileges: [{resource: {cluster: true}, actions: ["setUserWriteBlockMode"]}],
},
],
},
{
testname: "shardCollection",
command: {shardCollection: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["enableSharding"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "shardingState",
command: {shardingState: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["shardingState"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "shutdown",
command: {shutdown: 1},
testcases: [
{runOnDb: firstDbName, roles: {}, expectFail: true},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "split",
command: {split: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {db: "test", collection: "x"}, actions: ["splitChunk"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "splitChunk",
command: {splitChunk: "test.x"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "splitVector",
command: {splitVector: "test.x"},
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {db: "test", collection: "x"}, actions: ["splitVector"]}],
expectFail: true,
},
{
runOnDb: firstDbName,
roles: roles_clusterManager,
privileges: [{resource: {db: "test", collection: "x"}, actions: ["splitVector"]}],
expectFail: true,
},
{
runOnDb: secondDbName,
roles: roles_clusterManager,
privileges: [{resource: {db: "test", collection: "x"}, actions: ["splitVector"]}],
expectFail: true,
},
],
},
{
testname: "stopShardDraining",
command: {stopShardDraining: "x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["removeShard"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
// Test that clusterMonitor has permission to run $queryStats without transformation
testname: "testQueryStatsReadPrivilege",
command: {aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}},
skipSharded: false,
testcases: [{runOnDb: adminDbName, roles: roles_monitoring}],
},
{
// Test that clusterMonitor has permission to run $queryStats with transformation
testname: "testQueryStatsReadTransformedPrivilege",
command: {
aggregate: 1,
pipeline: [
{
$queryStats: {
transformIdentifiers: {
algorithm: "hmac-sha-256",
hmacKey: BinData(8, "MjM0NTY3ODkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjE="),
},
},
},
],
cursor: {},
},
skipSharded: false,
testcases: [{runOnDb: adminDbName, roles: roles_monitoring}],
},
{
testname: "top",
command: {top: 1},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["top"]}],
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "unshardCollection",
command: {unshardCollection: "test.x", toShard: "unshard_collection-rs"},
skipUnlessSharded: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagUnshardCollection"),
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["unshardCollection"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "untrackUnshardedCollection",
command: {untrackUnshardedCollection: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "updateRole_authenticationRestrictions",
command: {updateRole: "testRole", authenticationRestrictions: []},
setup: function (db) {
assert.commandWorked(
db.runCommand({
createRole: "testRole",
roles: [],
privileges: [],
authenticationRestrictions: [{clientSource: ["127.0.0.1"]}],
}),
);
},
teardown: function (db) {
db.runCommand({dropRole: "testRole"});
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_userAdminAny,
privileges: [
{resource: {db: "", collection: ""}, actions: ["revokeRole"]},
{
resource: {db: firstDbName, collection: ""},
actions: ["setAuthenticationRestriction"],
},
],
},
{
runOnDb: secondDbName,
roles: roles_userAdminAny,
privileges: [
{resource: {db: "", collection: ""}, actions: ["revokeRole"]},
{
resource: {db: secondDbName, collection: ""},
actions: ["setAuthenticationRestriction"],
},
],
},
],
},
{
testname: "updateUser_authenticationRestrictions",
command: {updateUser: "testUser", authenticationRestrictions: []},
setup: function (db) {
assert.commandWorked(
db.runCommand({
createUser: "testUser",
pwd: "test",
roles: [],
authenticationRestrictions: [{clientSource: ["127.0.0.1"]}],
}),
);
},
teardown: function (db) {
assert.commandWorked(db.runCommand({dropUser: "testUser"}));
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_userAdmin,
privileges: [
{
resource: {db: firstDbName, collection: ""},
actions: ["setAuthenticationRestriction"],
},
],
},
{
runOnDb: secondDbName,
roles: roles_userAdminAny,
privileges: [
{
resource: {db: secondDbName, collection: ""},
actions: ["setAuthenticationRestriction"],
},
],
},
],
},
{
testname: "validate",
command: {validate: "x"},
setup: function (db) {
assert.writeOK(db.x.save({}));
},
teardown: function (db) {
db.x.drop();
},
testcases: [
{
runOnDb: firstDbName,
roles: roles_dbAdmin,
privileges: [{resource: {db: firstDbName, collection: "x"}, actions: ["validate"]}],
},
{
runOnDb: secondDbName,
roles: roles_dbAdminAny,
privileges: [{resource: {db: secondDbName, collection: "x"}, actions: ["validate"]}],
},
],
},
{
// Test that the root role has the privilege to validate any system.* collection
testname: "validate_system",
command: {validate: "system.users"},
testcases: [{runOnDb: adminDbName, roles: {root: 1, __system: 1}}],
},
{
testname: "whatsmyuri",
command: {whatsmyuri: 1},
testcases: [
{runOnDb: adminDbName, roles: roles_all, privileges: []},
{runOnDb: firstDbName, roles: roles_all, privileges: []},
{runOnDb: secondDbName, roles: roles_all, privileges: []},
],
},
{
testname: "_configsvrAddShard",
command: {_configsvrAddShard: "x"},
skipSharded: true,
testcases: [{runOnDb: adminDbName, roles: {__system: 1}, expectFail: true}],
},
{
testname: "addShardToZone",
command: {addShardToZone: shard0name, zone: "z"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
privileges: [{resource: {db: "config", collection: "shards"}, actions: ["update"]}],
expectFail: true, // shard0name doesn't exist
},
{
runOnDb: adminDbName,
roles: {...roles_clusterManager},
expectFail: true, // shard0name doesn't exist
},
{
runOnDb: adminDbName,
privileges: [{resource: {cluster: true}, actions: ["enableSharding"]}],
expectFail: true, // shard0name doesn't exist
},
],
},
{
testname: "_configsvrAddShardToZone",
command: {_configsvrAddShardToZone: shard0name, zone: "z"},
skipSharded: true,
testcases: [{runOnDb: adminDbName, roles: {__system: 1}, expectFail: true}],
},
{
testname: "removeShardFromZone",
command: {removeShardFromZone: shard0name, zone: "z"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
privileges: [
{resource: {db: "config", collection: "shards"}, actions: ["update"]},
{resource: {db: "config", collection: "tags"}, actions: ["find"]},
],
expectFail: true, // shard0name doesn't exist
},
{
runOnDb: adminDbName,
roles: {...roles_clusterManager},
expectFail: true, // shard0name doesn't exist
},
{
runOnDb: adminDbName,
privileges: [{resource: {cluster: true}, actions: ["enableSharding"]}],
expectFail: true, // shard0name doesn't exist
},
],
},
{
testname: "_configsvrRemoveShardFromZone",
command: {_configsvrRemoveShardFromZone: shard0name, zone: "z"},
skipSharded: true,
testcases: [{runOnDb: adminDbName, roles: {__system: 1}, expectFail: true}],
},
{
testname: "updateZoneKeyRange",
command: {updateZoneKeyRange: "test.foo", min: {x: 1}, max: {x: 5}, zone: "z"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
privileges: [
{resource: {db: "config", collection: "shards"}, actions: ["find"]},
{
resource: {db: "config", collection: "tags"},
actions: ["find", "update", "remove"],
},
],
expectFail: true,
},
{
runOnDb: adminDbName,
roles: {...roles_clusterManager},
expectFail: true,
},
{
runOnDb: adminDbName,
privileges: [{resource: {cluster: true}, actions: ["enableSharding"]}],
expectFail: true,
},
],
},
{
testname: "_configsvrUpdateZoneKeyRange",
command: {_configsvrUpdateZoneKeyRange: "test.foo", min: {x: 1}, max: {x: 5}, zone: "z"},
skipSharded: true,
testcases: [{runOnDb: adminDbName, roles: {__system: 1}, expectFail: true}],
},
{
testname: "startSession",
command: {startSession: 1},
privileges: [{resource: {cluster: true}, actions: ["startSession"]}],
testcases: [{runOnDb: adminDbName, roles: roles_all}],
},
{
testname: "refreshLogicalSessionCacheNow",
command: {refreshLogicalSessionCacheNow: 1},
testcases: [{runOnDb: adminDbName, roles: roles_all}],
},
{
testname: "refreshSessions",
command: {refreshSessions: []},
testcases: [{runOnDb: adminDbName, roles: roles_all}],
},
{
testname: "_getNextSessionMods",
command: {_getNextSessionMods: "a-b"},
skipSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "aggregate_$backupCursor",
setup: (db) => {
return {isReplicaSetEndpointEnabled: FeatureFlagUtil.isEnabled(db, "ReplicaSetEndpoint")};
},
runOnDb: (state) => {
const {isReplicaSetEndpointEnabled} = state;
return isReplicaSetEndpointEnabled ? "local" : adminDbName;
},
command: {aggregate: 1, cursor: {}, pipeline: [{$backupCursor: {}}]},
skipSharded: true,
// Only enterprise knows of this aggregation stage.
skipTest: (conn) => !getBuildInfo().modules.includes("enterprise"),
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["fsync"]}],
expectFail: TestData.storageEngine == "inMemory",
},
],
teardown: (db, response) => {
if (response.ok) {
assert.commandWorked(db.runCommand({killCursors: "$cmd.aggregate", cursors: [response.cursor.id]}));
}
},
},
{
testname: "aggregate_$backupCursorExtend",
setup: (db) => {
return {isReplicaSetEndpointEnabled: FeatureFlagUtil.isEnabled(db, "ReplicaSetEndpoint")};
},
runOnDb: (state) => {
const {isReplicaSetEndpointEnabled} = state;
return isReplicaSetEndpointEnabled ? "local" : adminDbName;
},
command: {
aggregate: 1,
pipeline: [
{
$backupCursorExtend: {
backupId: UUID("00000000-0000-0000-0000-000000000000"),
timestamp: new Timestamp(1655722668, 22),
},
},
],
cursor: {},
},
skipSharded: true,
// Only enterprise knows of this aggregation stage.
skipTest: (conn) => !getBuildInfo().modules.includes("enterprise"),
testcases: [
{
runOnDb: adminDbName,
roles: roles_hostManager,
privileges: [{resource: {cluster: true}, actions: ["fsync"]}],
expectFail: true,
},
],
teardown: (db, response) => {
if (response.ok) {
assert.commandWorked(db.runCommand({killCursors: "$cmd.aggregate", cursors: [response.cursor.id]}));
}
},
},
{
testname: "aggregate_$backupFileCursor",
command: {aggregate: 1, cursor: {}, pipeline: [{$_backupFile: {backupId: UUID()}}]},
skipSharded: true,
// Only enterprise knows of this aggregation stage.
skipTest: (conn) => !getBuildInfo().modules.includes("enterprise"),
testcases: [
{
runOnDb: adminDbName,
roles: {backup: 1, root: 1, __system: 1},
privileges: [{resource: {cluster: true}, actions: ["readBackupFile"]}],
expectFail: true,
},
],
},
{
testname: "aggregate_$search",
command: {
aggregate: "foo",
cursor: {},
pipeline: [
{
$search: {
// empty query
},
},
],
},
skipSharded: false,
// Instead of calling to mongot, lets make the search to return EOF early.
disableSearch: true,
testcases: [
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
},
{
runOnDb: secondDbName,
roles: roles_readAny,
privileges: [{resource: {db: secondDbName, collection: "foo"}, actions: ["find"]}],
},
],
},
{
testname: "aggregate_$searchMeta",
command: {
aggregate: "foo",
cursor: {},
pipeline: [{$searchMeta: {}}],
},
testcases: testcases_transformationOnlyExpectFail,
},
{
testname: "aggregate_$vectorSearch",
command: {
aggregate: "foo",
cursor: {},
pipeline: [{$vectorSearch: {}}],
},
skipTest: (_) => _isWindows(),
// Instead of calling to mongot, lets make the search to return EOF early.
disableSearch: true,
testcases: testcases_transformationOnlyExpectFail,
},
{
testname: "getTrafficRecordingStatus",
command: {getTrafficRecordingStatus: 1},
testcases: [{runOnDb: adminDbName, roles: roles_hostManager}],
setup: function (db) {
db.runCommand({stopTrafficRecording: 1});
assert.commandWorked(db.runCommand({startTrafficRecording: 1, destination: "notARealPath"}));
},
teardown: function (db) {
db.runCommand({stopTrafficRecording: 1});
removeFile("notARealPath");
},
},
{
testname: "startTrafficRecording",
command: {startTrafficRecording: 1, destination: "notARealPath"},
testcases: [{runOnDb: adminDbName, roles: roles_hostManager}],
teardown: (db, response) => {
if (response.ok) {
assert.commandWorked(db.runCommand({stopTrafficRecording: 1}));
}
},
},
{
testname: "stopTrafficRecording",
command: {stopTrafficRecording: 1},
testcases: [{runOnDb: adminDbName, roles: roles_hostManager}],
setup: function (db) {
db.runCommand({stopTrafficRecording: 1});
assert.commandWorked(db.runCommand({startTrafficRecording: 1, destination: "notARealPath"}));
},
teardown: function (db) {
db.runCommand({stopTrafficRecording: 1});
removeFile("notARealPath");
},
},
{
// Internal command, renamed to startTrafficRecording. Test case remains for multi-version tests.
testname: "startRecordingTraffic",
skipTest: () => true,
command: {startRecordingTraffic: 1, destination: "notARealPath"},
testcases: [],
},
{
// Internal command, renamed to stopTrafficRecording. Test case remains for multi-version tests.
testname: "stopRecordingTraffic",
skipTest: () => true,
command: {stopRecordingTraffic: 1},
testcases: [],
},
{
testname: "clearJumboFlag",
command: {clearJumboFlag: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {db: "test", collection: "x"}, actions: ["clearJumboFlag"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "_configsvrClearJumboFlag",
command: {_configsvrClearJumboFlag: "x.y", epoch: ObjectId(), minKey: {x: 0}, maxKey: {x: 10}},
skipSharded: true,
expectFail: true,
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
expectFail: true,
},
],
},
{
testname: "balancerCollectionStatus",
command: {shardCollection: "test.x"},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: Object.extend({enableSharding: 1}, roles_clusterManager),
privileges: [{resource: {db: "test", collection: "x"}, actions: ["enableSharding"]}],
expectFail: true,
},
{runOnDb: firstDbName, roles: {}},
{runOnDb: secondDbName, roles: {}},
],
},
{
testname: "aggregate_union_with_basic",
command: {
aggregate: "baseColl",
pipeline: [{$unionWith: "unionColl"}],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("baseColl"));
assert.commandWorked(db.createCollection("unionColl"));
},
teardown: function (db) {
db.baseColl.drop();
db.unionColl.drop();
},
testcases: [
// Missing required privileges on base collection.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "unionColl"}, actions: ["find"]}],
expectAuthzFailure: true,
},
// Missing required privileges on nested collection.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "baseColl"}, actions: ["find"]}],
expectAuthzFailure: true,
},
// All required privileges.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "baseColl"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "unionColl"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_union_with_sub_pipeline",
command: {
aggregate: "baseColl",
pipeline: [
{
$unionWith: {
coll: "unionColl",
pipeline: [
{$lookup: {from: "lookupColl", localField: "_id", foreignField: "_id", as: "results"}},
],
},
},
],
cursor: {},
},
setup: function (db) {
assert.commandWorked(db.createCollection("baseColl"));
assert.commandWorked(db.createCollection("unionColl"));
assert.commandWorked(db.createCollection("lookupColl"));
},
teardown: function (db) {
db.baseColl.drop();
db.unionColl.drop();
db.lookupColl.drop();
},
testcases: [
// Missing required privileges on nested collection.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [{resource: {db: firstDbName, collection: "baseColl"}, actions: ["find"]}],
expectAuthzFailure: true,
},
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "baseColl"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "unionColl"}, actions: ["find"]},
],
expectAuthzFailure: true,
},
// All required privileges.
{
runOnDb: firstDbName,
roles: roles_read,
privileges: [
{resource: {db: firstDbName, collection: "baseColl"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "unionColl"}, actions: ["find"]},
{resource: {db: firstDbName, collection: "lookupColl"}, actions: ["find"]},
],
},
],
},
{
testname: "aggregate_$_internalUnpackBucket",
command: {
aggregate: "foo",
pipeline: [
{
$_internalUnpackBucket: {
timeField: "start",
metaField: "tags",
bucketMaxSpanSeconds: NumberInt(3000),
},
},
],
cursor: {},
},
setup: function (db) {
db.foo.drop(); // empties the collection.
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readWrite: 1,
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
dbOwner: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
},
],
},
{
testname: "aggregate_$_unpackBucket",
command: {
aggregate: "foo",
pipeline: [{$_unpackBucket: {timeField: "start"}}],
cursor: {},
},
setup: function (db) {
db.foo.drop(); // empties the collection.
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readWrite: 1,
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
dbOwner: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
},
],
},
{
testname: "aggregate_$listSearchIndexes",
command: {
aggregate: "foo",
pipeline: [{$listSearchIndexes: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readWrite: 1,
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbOwner: 1,
dbAdminAnyDatabase: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["listSearchIndexes"]}],
expectFail: true, // Expect to fail with SearchNotEnabled.
},
],
},
{
testname: "aggregate_$_internalAllCollectionStats",
command: {
aggregate: 1,
pipeline: [{$_internalAllCollectionStats: {}}],
cursor: {},
},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["allCollectionStats"]}],
},
],
},
{
testname: "aggregate_$_internalChangeStreamAddPostImage",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamAddPostImage: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalChangeStreamAddPreImage",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamAddPreImage: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalChangeStreamCheckInvalidate",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamCheckInvalidate: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalChangeStreamCheckResumability",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamCheckResumability: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalChangeStreamInjectControlEvents",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamInjectControlEvents: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalChangeStreamCheckTopologyChange",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamCheckTopologyChange: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalChangeStreamHandleTopologyChange",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamHandleTopologyChange: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalChangeStreamOplogMatch",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamOplogMatch: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalChangeStreamTransform",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamTransform: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalChangeStreamUnwindTransaction",
command: {
aggregate: 1,
pipeline: [{$_internalChangeStreamUnwindTransaction: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalShardServerInfo",
command: {
aggregate: 1,
pipeline: [{$_internalShardServerInfo: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$listCachedAndActiveUsers",
command: {
aggregate: 1,
pipeline: [{$listCachedAndActiveUsers: {}}],
cursor: {},
},
testcases: [
{
runOnDb: adminDbName,
roles: {userAdminAnyDatabase: 1, root: 1, __system: 1},
privileges: [{resource: {anyResource: true}, actions: ["listCachedAndActiveUsers"]}],
},
{
runOnDb: firstDbName,
roles: {userAdminAnyDatabase: 1, root: 1, __system: 1},
privileges: [{resource: {anyResource: true}, actions: ["listCachedAndActiveUsers"]}],
},
],
},
{
testname: "aggregate_$listCatalog_admin",
command: {
aggregate: 1,
pipeline: [{$listCatalog: {}}],
cursor: {},
},
testcases: [
{
runOnDb: adminDbName,
roles: {
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{resource: {cluster: true}, actions: ["listDatabases"]},
{resource: {db: "", collection: ""}, actions: ["listCollections", "listIndexes"]},
{resource: {db: "", collection: "system.js"}, actions: ["listCollections", "listIndexes"]},
{resource: {db: "", system_buckets: ""}, actions: ["listCollections", "listIndexes"]},
],
},
{
runOnDb: firstDbName,
roles: {
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{resource: {cluster: true}, actions: ["listDatabases"]},
{resource: {db: "", collection: ""}, actions: ["listCollections", "listIndexes"]},
{resource: {db: "", collection: "system.js"}, actions: ["listCollections", "listIndexes"]},
{resource: {db: "", system_buckets: ""}, actions: ["listCollections", "listIndexes"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$listCatalog_normal_resource",
command: {
aggregate: "foo",
pipeline: [{$listCatalog: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {
read: 1,
readWrite: 1,
readAnyDatabase: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
backup: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [
{resource: {db: firstDbName, collection: "foo"}, actions: ["listCollections", "listIndexes"]},
],
},
],
},
{
testname: "aggregate_$listSampledQueries",
command: {
aggregate: 1,
pipeline: [{$listSampledQueries: {}}],
cursor: {},
},
skipUnlessReplicaSet: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["listSampledQueries"]}],
},
{runOnDb: firstDbName, roles: roles_monitoring, expectFail: true},
{runOnDb: secondDbName, roles: roles_monitoring, expectFail: true},
],
},
{
testname: "aggregate_$_addReshardingResumeId",
command: {
aggregate: "foo",
pipeline: [{$_addReshardingResumeId: {}}],
cursor: {},
},
skipSharded: true, // Not available on mongos.
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalApplyOplogUpdate",
command: {
aggregate: "foo",
pipeline: [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: Timestamp(0, 0)}}}}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$_internalBoundedSort",
command: {
aggregate: "foo",
pipeline: [
{$skip: 5}, // Adding $skip because $_internalBoundedSort cannot be the first stage on the merger when running in a sharded cluster.
{$_internalBoundedSort: {sortKey: {bar: 1}, bound: {base: "min"}}},
],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$_internalComputeGeoNearDistance",
command: {
aggregate: "foo",
pipeline: [
{
$_internalComputeGeoNearDistance: {
near: {
type: "Point",
coordinates: [1, 1],
},
key: "loc",
distanceMultiplier: 1,
distanceField: "dist",
},
},
],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$_internalConvertBucketIndexStats",
command: {
aggregate: "foo",
pipeline: [{$_internalConvertBucketIndexStats: {timeField: "bar", metaField: "baz"}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$_internalDensify",
command: {
aggregate: "foo",
pipeline: [{$_internalDensify: {}}],
cursor: {},
},
testcases: testcases_transformationOnlyExpectFail,
},
{
testname: "aggregate_$_internalFindAndModifyImageLookup",
command: {
aggregate: "foo",
pipeline: [{$_internalFindAndModifyImageLookup: {}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalInhibitOptimization",
command: {
aggregate: "foo",
pipeline: [{$_internalInhibitOptimization: {}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$_internalReshardingIterateTransaction",
command: {
aggregate: "foo",
pipeline: [{$_internalReshardingIterateTransaction: {}}],
cursor: {},
},
skipSharded: true, // Not available on mongos.
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalReshardingOwnershipMatch",
command: {
aggregate: "foo",
pipeline: [{$_internalReshardingOwnershipMatch: {}}],
cursor: {},
},
skipSharded: true, // Not available on mongos.
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [
{resource: {db: firstDbName, collection: ""}, actions: ["find"]},
{resource: {cluster: true}, actions: ["internal"]},
],
expectFail: true,
},
],
},
{
testname: "aggregate_$_internalSearchIdLookup",
command: {
aggregate: "foo",
pipeline: [{$_internalSearchIdLookup: {}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$_internalSetWindowFields",
command: {
aggregate: "foo",
pipeline: [{$_internalSetWindowFields: {"output": {"val": {"$locf": "$val"}}}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$_internalShredDocuments",
command: {
aggregate: "foo",
pipeline: [{$_internalShredDocuments: {}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$_internalSplitPipeline",
command: {
aggregate: "foo",
pipeline: [{$_internalSplitPipeline: {mergeType: "anyShard"}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$_internalStreamingGroup",
command: {
aggregate: "foo",
pipeline: [
{$_internalStreamingGroup: {_id: "$_id", value: {$last: "$bar"}, $monotonicIdFields: ["_id"]}},
],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$addFields",
command: {
aggregate: "foo",
pipeline: [{$addFields: {bar: "baz"}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$bucket",
command: {
aggregate: "foo",
pipeline: [{$bucket: {groupBy: "$bar", boundaries: [0, 100], default: "Other"}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$bucketAuto",
command: {
aggregate: "foo",
pipeline: [{$bucketAuto: {groupBy: "$bar", buckets: 4}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$count",
command: {
aggregate: "foo",
pipeline: [{$count: "bar"}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$densify",
command: {
aggregate: "foo",
pipeline: [
{$densify: {field: "val", range: {step: 1, bounds: "partition"}, partitionByFields: ["part"]}},
],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$https",
command: {
aggregate: "foo",
pipeline: [{$https: {}}],
cursor: {},
},
// TODO SERVER-74961: Windows is not yet supported in stream processing.
skipTest: (conn) =>
!isFeatureEnabled(conn, "featureFlagStreams") || _isWindows() || getBuildInfo().version < "8.1",
skipSharded: true,
testcases: testcases_transformationOnlyExpectFail, // Not allowed in user requests.
},
{
testname: "aggregate_$cachedLookup",
command: {
aggregate: "foo",
pipeline: [{$cachedLookup: {}}],
cursor: {},
},
// TODO SERVER-74961: Windows is not yet supported in stream processing.
skipTest: (conn) =>
!isFeatureEnabled(conn, "featureFlagStreams") || _isWindows() || getBuildInfo().version < "8.1",
skipSharded: true,
testcases: testcases_transformationOnlyExpectFail, // Not allowed in user requests.
},
{
testname: "aggregate_$externalFunction",
command: {
aggregate: "foo",
pipeline: [{$externalFunction: {}}],
cursor: {},
},
// TODO SERVER-74961: Windows is not yet supported in stream processing.
skipTest: (conn) =>
!isFeatureEnabled(conn, "featureFlagStreams") || _isWindows() || getBuildInfo().version < "8.1",
skipSharded: true,
testcases: testcases_transformationOnlyExpectFail, // Not allowed in user requests.
},
{
testname: "aggregate_$fill",
command: {
aggregate: "foo",
pipeline: [{$fill: {output: {bar: {value: 0}}}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$group",
command: {
aggregate: "foo",
pipeline: [{$group: {_id: "$bar", count: {$sum: 1}}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$group_$doingMerge",
command: {
aggregate: "foo",
pipeline: [{$group: {_id: "$bar", avg: {$avg: "$b"}, $doingMerge: true}}],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
expectAuthzFailure: true,
},
{
runOnDb: firstDbName,
roles: {__system: 1},
expectFailure: true,
},
],
},
{
testname: "aggregate_$limit",
command: {
aggregate: "foo",
pipeline: [{$limit: 10}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$mergeCursors",
command: {
aggregate: "foo",
pipeline: [
{
$mergeCursors: {
sort: {y: 1, z: 1},
compareWholeSortKey: false,
remotes: [],
nss: "test.mergeCursors",
allowPartialResults: false,
},
},
],
cursor: {},
},
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
// $mergeCursors requires __system role OR a user with internal and find action types as privileges.
expectFail: true,
privileges: [
{resource: {cluster: true}, actions: ["internal"]},
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
],
},
{
runOnDb: firstDbName,
// Find action type as a privilege alone is not sufficient for $mergeCursors.
expectAuthzFailure: true,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
},
],
},
{
testname: "aggregate_$queue",
command: {
aggregate: 1,
pipeline: [{$queue: []}],
cursor: {},
},
testcases: [
{runOnDb: firstDbName, roles: roles_read, expectFail: true},
{runOnDb: secondDbName, roles: roles_readAny, expectFail: true},
],
},
{
testname: "aggregate_$redact",
command: {
aggregate: "foo",
pipeline: [{$redact: {$cond: {if: {$gt: ["$_id", {}]}, then: "$$DESCEND", else: "$$PRUNE"}}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$project",
command: {
aggregate: "foo",
pipeline: [{$project: {baz: 0}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$setVariableFromSubPipeline",
command: {
aggregate: "foo",
pipeline: [
{$setVariableFromSubPipeline: {var: "$$SEARCH_META", pipeline: []}},
{$replaceWith: "$$SEARCH_META"},
],
cursor: {},
},
testcases: testcases_transformationOnlyExpectFail,
},
{
testname: "aggregate_$searchBeta",
command: {
aggregate: "foo",
pipeline: [{$searchBeta: {query: "cakes", path: "title"}}],
cursor: {},
},
// Instead of calling to mongot, lets make the search to return EOF early.
disableSearch: true,
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$replaceRoot",
command: {
aggregate: "foo",
pipeline: [{$replaceRoot: {newRoot: "$bar"}}],
cursor: {},
},
setup: function (db) {
db.foo.drop(); // cleans up the collection to ensure all the documents have object field 'bar'.
assert.commandWorked(db.foo.insert({bar: {baz: 1}}));
assert.commandWorked(db.foo.insert({bar: {baz: 2}}));
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$replaceWith",
command: {
aggregate: "foo",
pipeline: [{$replaceWith: "$bar"}],
cursor: {},
},
setup: function (db) {
db.foo.drop(); // cleans up the collection to ensure all the documents have object field 'bar'.
assert.commandWorked(db.foo.insert({bar: {baz: 1}}));
assert.commandWorked(db.foo.insert({bar: {baz: 2}}));
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$sample",
command: {
aggregate: "foo",
pipeline: [{$sample: {size: 10}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$setWindowFields",
command: {
aggregate: "foo",
pipeline: [
{
$setWindowFields: {
sortBy: {bar: 1},
output: {
cumulativeQuantityForYear: {
$sum: "$baz",
window: {
documents: ["unbounded", "current"],
},
},
},
},
},
],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$shardedDataDistribution",
command: {
aggregate: 1,
pipeline: [{$shardedDataDistribution: {}}],
cursor: {},
},
skipUnlessSharded: true,
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["shardedDataDistribution"]}],
},
{runOnDb: firstDbName, roles: roles_monitoring, expectFail: true},
{runOnDb: secondDbName, roles: roles_monitoring, expectFail: true},
],
},
{
testname: "aggregate_$skip",
command: {
aggregate: "foo",
pipeline: [{$skip: 10}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$sort",
command: {
aggregate: "foo",
pipeline: [{$sort: {a: 1}}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$sortByCount",
command: {
aggregate: "foo",
pipeline: [{$sortByCount: "$a"}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$unset",
command: {
aggregate: "foo",
pipeline: [{$unset: "bar"}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$unwind",
command: {
aggregate: "foo",
pipeline: [{$unwind: "$a"}],
cursor: {},
},
testcases: testcases_transformationOnly,
},
{
testname: "validate_db_metadata_command_specific_db",
command: {
validateDBMetadata: 1,
db: secondDbName,
collection: "test",
apiParameters: {version: "1", strict: true},
},
setup: function (db) {
const collName = "validate_db_metadata_command_specific_db";
assert.commandWorked(db.getSiblingDB(firstDbName).createCollection(collName));
assert.commandWorked(db.getSiblingDB(secondDbName).createCollection(collName));
assert.commandWorked(db.getSiblingDB("ThirdDB").createCollection(collName));
},
teardown: function (db) {
assert.commandWorked(db.getSiblingDB(firstDbName).dropDatabase());
assert.commandWorked(db.getSiblingDB(secondDbName).dropDatabase());
assert.commandWorked(db.getSiblingDB("ThirdDB").dropDatabase());
},
testcases: [
{
runOnDb: secondDbName,
privileges: [{resource: {db: secondDbName, collection: ""}, actions: ["validate"]}],
},
{
// Need to only have permission on secondDbName to be able to the command against
// the db.
runOnDb: firstDbName,
privileges: [{resource: {db: secondDbName, collection: ""}, actions: ["validate"]}],
},
{
runOnDb: firstDbName,
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["validate"]}],
expectAuthzFailure: true,
},
],
},
{
testname: "validate_db_metadata_command_all_dbs",
command: {validateDBMetadata: 1, apiParameters: {version: "1", strict: true}},
setup: function (db) {
const collName = "validate_db_metadata_command_all_dbs";
assert.commandWorked(db.getSiblingDB(firstDbName).createCollection(collName));
assert.commandWorked(db.getSiblingDB(secondDbName).createCollection(collName));
},
teardown: function (db) {
assert.commandWorked(db.getSiblingDB(firstDbName).dropDatabase());
assert.commandWorked(db.getSiblingDB(secondDbName).dropDatabase());
},
testcases: [
{
// Since the command didn't specify a 'db', it validates all dbs and hence require
// permission to run on all dbs.
runOnDb: secondDbName,
privileges: [{resource: {db: "", collection: ""}, actions: ["validate"]}],
},
{
// An exhaustive list on all databases is still not good enough for running to
// command on all dbs.
runOnDb: secondDbName,
privileges: [
{resource: {db: "admin", collection: ""}, actions: ["validate"]},
{resource: {db: "config", collection: ""}, actions: ["validate"]},
{resource: {db: "local", collection: ""}, actions: ["validate"]},
{resource: {db: firstDbName, collection: ""}, actions: ["validate"]},
{resource: {db: secondDbName, collection: ""}, actions: ["validate"]},
],
expectAuthzFailure: true,
},
],
},
{
testname: "query_settings_agg_command",
command: {
aggregate: 1,
pipeline: [{$querySettings: {}}],
cursor: {},
},
skipTest: (conn) => {
return isStandalone(conn);
},
testcases: [
// Tests that a cluster admin can successfully run the `$querySettings` stage as part of
// the aggregation pipeline.
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["querySettings"]}],
},
],
},
{
testname: "set_query_settings_commands",
command: {
setQuerySettings: {
find: "foo",
$db: firstDbName,
},
settings: {
"indexHints": {
"ns": {db: firstDbName, coll: "foo"},
"allowedIndexes": [{"sku": 1}],
},
},
},
skipTest: (conn) => {
return isStandalone(conn);
},
teardown: function (db) {
db.adminCommand({
removeQuerySettings: {
find: "foo",
$db: firstDbName,
},
});
},
testcases: [
// Tests that an admin cluster can successfully run the `setQuerySettings` command.
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["querySettings"]}],
},
],
},
{
testname: "remove_query_settings_commands",
command: {
removeQuerySettings: {
find: "foo",
$db: firstDbName,
},
},
skipTest: (conn) => {
return isStandalone(conn);
},
testcases: [
// Tests that an admin cluster can successfully run the `removeQuerySettings` command.
{
runOnDb: adminDbName,
roles: roles_clusterManager,
privileges: [{resource: {cluster: true}, actions: ["querySettings"]}],
expectAuthzFailure: false, // We expect the request to be authorized.
},
],
},
{
testname: "queryShapeRepresentativeQueries_find",
command: {
find: "queryShapeRepresentativeQueries",
},
skipTest: (conn) => {
return isStandalone(conn) || !TestData.setParameters.featureFlagPQSBackfill;
},
testcases: [
{
runOnDb: configDbName,
roles: {...roles_clusterManager, clusterMonitor: 1, searchCoordinator: 1, backup: 1},
privileges: [
{resource: {db: "config", collection: "queryShapeRepresentativeQueries"}, actions: ["find"]},
],
expectAuthzFailure: false,
},
],
},
{
testname: "queryShapeRepresentativeQueries_insert",
command: {
insert: "queryShapeRepresentativeQueries",
documents: [{a: 1}],
},
skipTest: (conn) => {
return isStandalone(conn) || !TestData.setParameters.featureFlagPQSBackfill;
},
testcases: [
{
runOnDb: configDbName,
roles: {...roles_clusterManager, restore: 1},
privileges: [
{resource: {db: "config", collection: "queryShapeRepresentativeQueries"}, actions: ["insert"]},
],
expectAuthzFailure: false,
},
],
teardown: function (db) {
assert.commandWorked(db.getSiblingDB(configDbName).queryShapeRepresentativeQueries.remove({}));
},
},
{
testname: "queryShapeRepresentativeQueries_update",
command: {
update: "queryShapeRepresentativeQueries",
updates: [
{
q: {a: 1},
u: {a: 2},
},
],
},
skipTest: (conn) => {
return isStandalone(conn) || !TestData.setParameters.featureFlagPQSBackfill;
},
testcases: [
{
runOnDb: configDbName,
roles: {...roles_clusterManager},
privileges: [
{resource: {db: "config", collection: "queryShapeRepresentativeQueries"}, actions: ["update"]},
],
expectAuthzFailure: false,
},
],
setup: function (db) {
assert.commandWorked(db.getSiblingDB(configDbName).queryShapeRepresentativeQueries.insert({a: 1}));
},
teardown: function (db) {
assert.commandWorked(db.getSiblingDB(configDbName).queryShapeRepresentativeQueries.remove({}));
},
},
{
testname: "queryShapeRepresentativeQueries_remove",
command: {
delete: "queryShapeRepresentativeQueries",
deletes: [
{
q: {a: 1},
limit: 0,
},
],
},
skipTest: (conn) => {
return isStandalone(conn) || !TestData.setParameters.featureFlagPQSBackfill;
},
testcases: [
{
runOnDb: configDbName,
roles: {...roles_clusterManager},
privileges: [
{resource: {db: "config", collection: "queryShapeRepresentativeQueries"}, actions: ["remove"]},
],
expectAuthzFailure: false,
},
],
setup: function (db) {
assert.commandWorked(db.getSiblingDB(configDbName).queryShapeRepresentativeQueries.insert({a: 1}));
},
teardown: function (db) {
assert.commandWorked(db.getSiblingDB(configDbName).queryShapeRepresentativeQueries.remove({}));
},
},
{
testname: "aggregate_$rankFusion",
command: {
aggregate: "foo",
cursor: {},
pipeline: [
{
$rankFusion: {
input: {
pipelines: {
geo: [
{
$geoNear: {near: [50, 50], distanceField: "dist"},
},
{
$limit: 2,
},
],
matchPipe: [
{
$match: {a: 1},
},
{
$sort: {x: 1},
},
],
search: [
{
$search: {
/* empty query */
},
},
],
vector: [
{
$vectorSearch: {
/* empty query */
},
},
],
},
},
},
},
],
},
setup: function (db) {
db.createCollection("foo");
assert.commandWorked(db.foo.createIndex({loc: "2d"}));
assert.commandWorked(db.foo.insert({loc: [45.32, 51.12]}));
},
skipSharded: false,
disableSearch: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagRankFusionBasic"),
// Expect this to fail since there's no mongot set up to execute the $search/vectorSearch.
testcases: testcases_transformationOnlyExpectFail,
},
{
testname: "aggregate_$score",
command: {
aggregate: "foo",
cursor: {},
pipeline: [{$score: {score: 10}}],
},
setup: (db) => {
db.createCollection("foo");
},
disableSearch: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagSearchHybridScoringFull"),
testcases: testcases_transformationOnly,
},
{
testname: "aggregate_$setMetadata",
command: {
aggregate: "foo",
cursor: {},
pipeline: [{$setMetadata: {score: 5}}],
},
setup: (db) => {
db.createCollection("foo");
},
disableSearch: true,
testcases: [
{
runOnDb: firstDbName,
roles: {__system: 1},
// $setMetadata requires __system role OR a user with internal and find action types as privileges.
expectFail: true,
privileges: [
{resource: {cluster: true}, actions: ["internal"]},
{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]},
],
},
{
runOnDb: firstDbName,
// Find action type as a privilege alone is not sufficient for $setMetadata.
expectAuthzFailure: true,
privileges: [{resource: {db: firstDbName, collection: "foo"}, actions: ["find"]}],
},
],
},
{
testname: "aggregate_$scoreFusion",
command: {
aggregate: "foo",
cursor: {},
pipeline: [
{
$scoreFusion: {
input: {
pipelines: {
matchScore1: [
{
$match: {a: 1},
},
{
$score: {
score: 5.0,
},
},
],
search1: [
{
$search: {
// empty query
},
},
],
vectorSearch1: [
{
$vectorSearch: {
// empty query
},
},
],
},
normalization: "none",
},
},
},
],
},
setup: function (db) {
db.createCollection("foo");
},
skipSharded: false,
disableSearch: true,
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagSearchHybridScoringFull"),
testcases: testcases_transformationOnlyExpectFail,
},
{
testname: "aggregate_internal_list_collections",
command: {aggregate: 1, pipeline: [{$_internalListCollections: {}}], cursor: {}},
testcases: [
{
runOnDb: adminDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
},
{
runOnDb: firstDbName,
roles: {__system: 1},
privileges: [{resource: {cluster: true}, actions: ["internal"]}],
},
],
},
{
testname: "aggregate_$listClusterCatalog",
command: {aggregate: 1, pipeline: [{$listClusterCatalog: {}}], cursor: {}},
testcases: [
{
runOnDb: adminDbName,
roles: roles_monitoring,
privileges: [{resource: {cluster: true}, actions: ["listClusterCatalog"]}],
},
{
runOnDb: firstDbName,
roles: {
read: 1,
readAnyDatabase: 1,
readWrite: 1,
readWriteAnyDatabase: 1,
dbAdmin: 1,
dbAdminAnyDatabase: 1,
dbOwner: 1,
backup: 1,
restore: 1,
root: 1,
searchCoordinator: 1,
__system: 1,
},
privileges: [{resource: {db: firstDbName, collection: ""}, actions: ["listCollections"]}],
},
{runOnDb: firstDbName, privileges: [], expectAuthzFailure: true},
],
},
{
testname: "aggregate_$listMqlEntities",
command: {
aggregate: 1,
pipeline: [{$listMqlEntities: {entityType: "aggregationStages"}}],
cursor: {},
},
testcases: [
// expectFail is true because $listMqlEntities is only allowed to run on the admin database,
// but this check occurs post-auth.
// A user defined role with no privileges is authorized to run this stage because it is a
// test-only command (enabled only under --enableTestCommands).
{
runOnDb: firstDbName,
roles: roles_all,
privileges: [],
expectFail: true,
},
],
},
{
testname: "aggregate_$listExtensions",
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagExtensionsAPI"),
command: {
aggregate: 1,
pipeline: [{$listExtensions: {}}],
cursor: {},
},
testcases: [
{
runOnDb: adminDbName,
// Roles correspond to roles_monitoring + clusterManager.
roles: {
clusterMonitor: 1,
clusterAdmin: 1,
clusterManager: 1,
searchCoordinator: 1,
root: 1,
__system: 1,
},
privileges: [{resource: {cluster: true}, actions: ["listExtensions"]}],
},
// expectFail is true because $listExtensions is only allowed to run on the admin database.
{
runOnDb: firstDbName,
expectFail: true,
},
{
runOnDb: secondDbName,
expectFail: true,
},
],
},
{
testname: "raw_data",
command: {
count: "raw_data",
rawData: true,
},
setup: function (db) {
const coll = db["raw_data"];
const timeField = "t";
const metaField = "m";
const time = new Date("2024-01-01T00:00:00Z");
assert.commandWorked(
db.createCollection(coll.getName(), {timeseries: {timeField: timeField, metaField: metaField}}),
);
assert.commandWorked(
coll.insert([
{[timeField]: time, [metaField]: 1, a: "a"},
{[timeField]: time, [metaField]: 2, a: "b"},
{[timeField]: time, [metaField]: 2, a: "c"},
]),
);
},
teardown: function (db) {
db.raw_data.drop();
},
skipTest: (conn) => !isFeatureEnabled(conn, "featureFlagRawDataCrudOperations"),
testcases: [
{
runOnDb: firstDbName,
privileges: [
{resource: {db: firstDbName, collection: "raw_data"}, actions: ["performRawDataOperations"]},
{resource: {db: firstDbName, collection: "raw_data"}, actions: ["find"]},
],
},
{
runOnDb: firstDbName,
privileges: [
{resource: {db: firstDbName, collection: "raw_data"}, actions: ["internal"]},
{resource: {db: firstDbName, collection: "raw_data"}, actions: ["find"]},
],
},
],
},
],
/************* SHARED TEST LOGIC ****************/
/**
* Returns true if conn is a connection to mongos,
* and false otherwise.
*/
isMongos: function (conn) {
return FixtureHelpers.isMongos(conn.getDB(adminDbName));
},
/**
* Runs a single test object from the tests array above.
* The actual implementation must be provided in "impls".
*
* Parameters:
* conn -- a connection to either mongod or mongos
* t -- a single test object from the tests array above
*
* Returns:
* An array of strings. Each string in the array reports
* a particular test error.
*/
runOneTest: function (conn, t, impls, options) {
options = options || {};
// A test may provide a secondary connection to be intermittently authed
// with admin privileges for setup/teardown.
const setupConn = "getSideChannel" in impls ? impls.getSideChannel(conn) : conn;
const isMongos = !!options.isMongos || this.isMongos(conn);
if (options.shard0Name) {
shard0name = options.shard0Name;
}
if (t.skipTest && t.skipTest(setupConn)) {
jsTest.log("Skipping test: " + t.testname);
return [];
}
// some tests shouldn't run in a sharded environment
if (t.skipSharded && isMongos) {
jsTest.log("Skipping test against mongos: " + t.testname);
return [];
}
// others shouldn't run in a standalone environment
if (t.skipUnlessSharded && !isMongos) {
jsTest.log("Skipping test against mongod: " + t.testname);
return [];
}
// some tests require replica sets to be disabled.
if (t.skipReplicaSet && FixtureHelpers.isReplSet(conn.getDB(adminDbName))) {
jsTest.log("Skipping test against replica set: " + t.testname);
return [];
}
// some tests require replica sets to be enabled.
if (t.skipUnlessReplicaSet && !FixtureHelpers.isReplSet(conn.getDB(adminDbName))) {
jsTest.log("Skipping test against standalone or cluster: " + t.testname);
return [];
}
jsTest.log("Running test: " + t.testname);
return impls.runOneTest(conn, t);
},
setup: function (conn, t, runOnDb, testcase) {
let adminDb = conn.getDB(adminDbName);
if (t.setup) {
adminDb.auth("admin", "password");
let state = t.setup(runOnDb, testcase);
adminDb.logout();
return state;
}
return {};
},
authenticatedSetup: function (t, runOnDb) {
if (t.authenticatedSetup) {
t.authenticatedSetup(runOnDb);
}
},
teardown: function (conn, t, runOnDb, response) {
let adminDb = conn.getDB(adminDbName);
if (t.teardown) {
adminDb.auth("admin", "password");
t.teardown(runOnDb, response);
adminDb.logout();
}
},
/**
* Top-level test runner
*/
runTests: function (conn, impls, options) {
options = options || {};
options.isMongos = options.isMongos || this.isMongos(conn);
// impls must provide implementations of a few functions
assert("createUsers" in impls);
assert("runOneTest" in impls);
impls.createUsers(conn);
// A test may provide a secondary connection to be intermittently authed
// with admin privileges for setup/teardown.
const setupConn = "getSideChannel" in impls ? impls.getSideChannel(conn) : conn;
checkCommandCoverage(setupConn);
checkAggStageCoverage(setupConn);
let failures = [];
for (let i = 0; i < this.tests.length; i++) {
const res = this.runOneTest(conn, this.tests[i], impls, options);
failures = failures.concat(res);
}
failures.forEach(function (i) {
jsTest.log(i);
});
assert.eq(0, failures.length);
},
};
/**
* Returns true iff the test is ran in a standalone environment.
*/
function isStandalone(conn) {
return FixtureHelpers.isStandalone(conn.getDB(adminDbName));
}
function isFeatureEnabled(conn, ...features) {
const adminDb = conn.getDB(adminDbName);
const authed = adminDb.auth("admin", "password");
const request = Object.fromEntries(features.map((k) => [k, 1]));
const res = assert.commandWorked(adminDb.runCommand({getParameter: 1, ...request}));
if (authed) {
adminDb.logout();
}
return features.every((key) => res[key]?.value);
}
/**
* Checks the test coverage on aggregation stages. If it finds any aggregation stage misses
* authorization testing, it throws an error to remind developers to add them.
*/
function checkAggStageCoverage(conn) {
const adminDb = conn.getDB(adminDbName);
// Ensures to login as admin.
assert(adminDb.auth("admin", "password"));
const aggStages = adminDb
.aggregate([{$listMqlEntities: {entityType: "aggregationStages"}}])
.toArray()
.map((obj) => obj.name);
adminDb.logout();
const unvisited = {};
for (let aggStage of aggStages) {
// Tracks 'aggStage' unless listed in the exception list 'skippedAuthTestingAggStages'.
if (!skippedAuthTestingAggStages.includes(aggStage)) {
unvisited[aggStage] = 1;
}
}
for (let test of authCommandsLib.tests) {
if (!("aggregate" in test.command)) {
continue;
}
for (let stage of test.command.pipeline) {
let stageName = Object.keys(stage)[0];
delete unvisited[stageName];
}
}
const unvisitedList = Object.keys(unvisited);
assert.eq(
unvisitedList.length,
0,
`'authCommandsLib.tests' misses auth testing for ${
unvisitedList.length
} aggregation stages: ${unvisitedList.join(", ")}`,
);
}
/**
* Checks the test coverage on all database commands. If it finds any command that lacks
* authorization testing, it throws an error to remind developers to add them.
*/
function checkCommandCoverage(conn) {
const adminDb = conn.getDB(adminDbName);
assert(adminDb.auth("admin", "password"));
// Get all commands.
const res = assert.commandWorked(adminDb.runCommand({listCommands: 1}));
const allCommands = Object.keys(res.commands);
adminDb.logout();
const unvisited = {};
for (let cmd of allCommands) {
if (!testOnlyCommands.includes(cmd) && !skippedAuthTestingCommands.includes(cmd) && !cmd.startsWith("_")) {
unvisited[cmd] = 1;
}
}
for (let test of authCommandsLib.tests) {
const keys = Object.keys(test.command);
const commandName = keys[0];
if (commandName && commandName in unvisited) {
delete unvisited[commandName];
}
}
const unvisitedList = Object.keys(unvisited);
assert.eq(
unvisitedList.length,
0,
`'authCommandsLib.tests' misses auth testing for ${
unvisitedList.length
} commands: ${unvisitedList.join(", ")}. ` +
`Add tests for these commands or add them to 'skippedAuthTestingCommands' with justification.`,
);
}