クソ半日無駄にした問題。ホスティングされたアプリがアクセスするのに使っていたアクセスユーザーのクレデンシャルの問題でしたわ。途方に暮れていて不意に目にした警告に書かれた「QA」の文字で、現在ターゲットにしている開発用のSTG環境との違和感を感じたらあとは10分だった。
functions: Your GOOGLE_APPLICATION_CREDENTIALS environment variable points to /Users/naisho/myWebapp-QA-07051e041f75.json. Non-emulated services will access production using these credentials. Be careful!
解決策
すっかり忘れてたけど、STGで開発していて、お客さんのデモ用にクリーンな環境を準備するためにFirebase上で別プロジェクトとしてQAプロジェクト作ってたんだよね。両方のプロジェクトでリソースにアクセスするためのサービスアカウントの証明書が異なっていて、それを環境変数 GOOGLE_APPLICATION_CREDENTIALS で指定するやり方を取っていたんだけど、3歩歩くと忘れる俺には無理な管理方法だった。
環境デプロイするときに必ず編集しなきゃいけないファイルを集めたフォルダにサービスアカウントの証明書集めて、どの証明書を使うのかをソースコードから指定するようにしたよ。環境変数よさらば。
const admin = require('firebase-admin');
let serviceAccount = require('./google_app_credentials.json');
admin.initializeApp({credential: admin.credential.cert(serviceAccount)});
とはいえ。これってホスティング側でデプロイする際に、そのフォルダに証明書アップロードされちゃってるってことかな。そうだったらセキュリティ的に問題ありなので対策打たなきゃだな。
時間を無駄にしないために
(node:57693) UnhandledPromiseRejectionWarning: Error: 7 PERMISSION_DENIED: Missing or insufficient permissions.
... (snip) ...
(node:57693) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 6)
Firestore の「ルール」ガー、って記事も散見したので、いろいろ記述見直したり比較してみたけど、まあ変わらなかったよね。
rules_version = ‘2’;
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}