Reputation: 331
so we stumbled over the issue that we hit the quota limit for stored firestore security rules of 2500. During deployment the CLI asks us if we want to delete the oldest 10 rules. Since we want to automate our deployment reacting to a console prompt is not exactly what we want.
Anyone knows how to mass delete the complete firestore security rule history without having to do it manually one by one trough firebase?
I couldn't find any info on that whatsoever from Googles side...
Upvotes: 0
Views: 226
Reputation: 81
I had a couple of issues using @Farid's solution. I wrote it up as a Cloud Function if anyone want to use it:
const admin = require("firebase-admin");
const { onRequest } = require("firebase-functions/v2/https");
exports.cleanRuleSets = onRequest(
{ memory: "256MiB", timeoutSeconds: 60 * 60 },
async (req, res) => {
// GATHER ALL RULESETS
let newToken;
let allRulesets = [];
while (true) {
let result;
if (!newToken) {
result = await admin.securityRules().listRulesetMetadata();
} else {
// THE DOCUMENTATION SAYS PAGE SIZE IS OPTIONAL, BUT THAT'S ONLY ON FIRST CALL
result = await admin.securityRules().listRulesetMetadata(100, newToken);
}
allRulesets.push(...result.rulesets);
newToken = result.nextPageToken;
if (!newToken) {
break;
}
}
// SET LOOK-BACK PERIOD. YOU MAY NEED TO SET THIS TO A HIGHER NUMBER AT FIRST AND THEN PROGRESSIVELY LOWER IF YOU HAVE A LOT OF RULESETS. I WAS GETTING RATE-LIMITED WITH TOO MANY API CALLS.
// I ALSO HIT THE MEMORY LIMIT OF 256MiB WITH TOO MANY RULESETS TO DELETE THE FIRST TIME I RAN IT, YOU CAN ADD MORE MEMORY IN THE CONFIG OBJECT
const daysToLookBack = 30; // MAKE SURE THIS NUMBER IS GREATER THAN THE DATE OF AT LEAST THREE DEPLOYMENTS TO AVOID DELETING CURRENT/TOO RECENT RULESETS
const daysInMilliseconds = daysToLookBack * 24 * 60 * 60 * 1000;
const daysAgo = new Date(Date.now() - daysInMilliseconds);
const promises = [];
allRulesets.forEach((el) => {
if (new Date(el.createTime) < daysAgo) {
// PUSH THE DELETE PROMISE TO TO PROMISES ARRAY FOR RULESETS OLDER THAN THE LOOK BACK PERIOD
if (el.name?.length > 0) {
promises.push(admin.securityRules().deleteRuleset(el.name));
}
}
});
// I GOT SOME ERRORS THAT WERE BLOCKING. USING ALLSETTLED TO CATCH ERRORS AND CONTINUE DELETING RULESETS.
const report = await Promise.allSettled(promises);
let successCount = 0;
let failedCount = 0;
report.forEach((el) => {
if (el.status === "rejected") {
failedCount++;
} else {
successCount++;
}
});
console.log(
`Successfully deleted ${promises.length} rulesets. Failed to delete ${failedCount} rulesets.`
);
res.status(200).send("Cleaned Rulesets");
}
);
Remember to delete/disable when done to avoid accidental deletion of rules!
Upvotes: 0
Reputation: 1420
Not sure if you can delete all security rules at once, but as per the documentation, you can avoid manual work by creating a logic to delete the oldest rules:
For example, to delete ALL rule sets deployed for longer than 30 days:
const thirtyDays = new Date(Date.now() - THIRTY_DAYS_IN_MILLIS); const promises = []; allRulesets.forEach((rs) => { if (new Date(rs.crateTime) < thirtyDays) { promises.push(admin.securityRules().deleteRuleset(rs.name)); } }); await Promise.all(promises); console.log(`Deleted ${promises.length} rulesets.`);
Upvotes: 3