Last active
July 7, 2024 13:43
-
-
Save breathe/5b73c82f3ef3564b8b8f0641bf3e0a11 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// this workaround is needed for this issue ... | |
// https://github.com/firebase/firebase-admin-node/issues/1377 | |
// workaround from here: https://gist.github.com/k2wanko/289f5cf231ca80da099c7414dceb465d | |
// This allows us to use federated identity when running build in ci and otherwise uses normal auth mechanism | |
import { GoogleOAuthAccessToken } from "firebase-admin"; // version 11.10.1 | |
import { getAuth } from "firebase-admin/auth"; | |
import { | |
getApps, | |
Credential, | |
applicationDefault, | |
initializeApp, | |
} from "firebase-admin/app"; | |
import { ComputeEngineCredential } from "../../../node_modules/firebase-admin/lib/app/credential-internal.js"; | |
import { ExternalAccountClient } from "google-auth-library"; // version 9.0.0 | |
import fs from "fs/promises"; | |
import { Agent } from "http"; | |
import path from "path"; | |
import os from "os"; | |
const configDir = (() => { | |
// Windows has a dedicated low-rights location for apps at ~/Application Data | |
const sys = os.platform(); | |
if (sys && sys.length >= 3 && sys.substring(0, 3).toLowerCase() === "win") { | |
return process.env.APPDATA; | |
} | |
// On *nix the gcloud cli creates a . dir. | |
return process.env.HOME && path.resolve(process.env.HOME, ".config"); | |
})(); | |
const GCLOUD_CREDENTIAL_SUFFIX = "gcloud/application_default_credentials.json"; | |
const GCLOUD_CREDENTIAL_PATH = | |
configDir && path.resolve(configDir, GCLOUD_CREDENTIAL_SUFFIX); | |
export class ExternalAccountCredential | |
extends ComputeEngineCredential // Inherits this class because it is verified to be an internal class at Firestore initialization. | |
implements Credential | |
{ | |
async getAccessToken(): Promise<GoogleOAuthAccessToken> { | |
const json = JSON.parse( | |
await fs.readFile(GCLOUD_CREDENTIAL_PATH as string, "utf-8") | |
); | |
const client = ExternalAccountClient.fromJSON(json); | |
if (!client) { | |
throw new Error("client is empty"); | |
} | |
const res = await client.getAccessToken(); | |
return { | |
access_token: res.res?.data?.accessToken || "", | |
expires_in: new Date(res.res?.data?.expireTime ?? 1000).getTime() / 1000, | |
}; | |
} | |
} | |
let app; | |
const alreadyCreatedApps = getApps(); | |
if (alreadyCreatedApps.length !== 0) { | |
app = alreadyCreatedApps[0]; | |
} else if (process.env["GITHUB_ACTION"] != null) { | |
// detect if running inside github action -- which uses external account auth ... | |
// external account auth is not supported by firebase cli yet hence this horrible workaround ... | |
// note that the _app_ itself has to launch in ci because that's how nextjs app bundling works ... | |
// bad incidental complexity ... | |
// see: https://github.com/firebase/firebase-admin-node/issues/1377 | |
console.log("using external account credential from", GCLOUD_CREDENTIAL_PATH); | |
const credential = new ExternalAccountCredential(); | |
app = initializeApp( | |
{ | |
credential, | |
}, | |
"WebAppName" | |
); | |
} else { | |
app = initializeApp( | |
{ | |
credential: applicationDefault(), | |
}, | |
"WebAppName" | |
); | |
} | |
const auth = getAuth(app); | |
export { app, auth }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- name: Authenticate with GC | |
# https://cloud.google.com/blog/products/identity-security/enabling-keyless-authentication-from-github-actions | |
id: auth | |
uses: 'google-github-actions/auth@v1' | |
with: | |
project_id: "${{env.GOOGLE_CLOUD_FIREBASE_PROJECT}}" | |
workload_identity_provider: "..." | |
service_account: "[email protected]" | |
create_credentials_file: true | |
token_format: access_token | |
access_token_lifetime: 900s | |
- name: "Adapt federated auth to support firebase cli" | |
run: | | |
echo "SERVICE_ACCOUNT_KEY=$(cat "${{ steps.auth.outputs.credentials_file_path }}" | tr -d '\n')" >> $GITHUB_ENV | |
- uses: actions/setup-node@v3 | |
with: | |
node-version: 20.8.0 | |
- run: npm install | |
- name: Deploy per PR preview of firebase site | |
if: github.ref != 'refs/heads/main' | |
uses: FirebaseExtended/action-hosting-deploy@v0 | |
env: | |
FIREBASE_CLI_EXPERIMENTS: webframeworks | |
with: | |
projectId: "${{env.GOOGLE_CLOUD_FIREBASE_PROJECT}}" | |
firebaseServiceAccount: "${{ env.SERVICE_ACCOUNT_KEY }}" | |
repoToken: "${{ secrets.GITHUB_TOKEN }}" | |
# workaround issue when project name is too long | |
firebaseToolsVersion: [email protected]:breathe/firebase-tools.git | |
expires: 7d | |
- name: Deploy new 'live' version of firebase site | |
if: github.ref == 'refs/heads/main' | |
uses: FirebaseExtended/action-hosting-deploy@v0 | |
env: | |
FIREBASE_CLI_EXPERIMENTS: webframeworks | |
with: | |
projectId: "${{env.GOOGLE_CLOUD_FIREBASE_PROJECT}}" | |
firebaseServiceAccount: "${{ env.SERVICE_ACCOUNT_KEY }}" | |
repoToken: "${{ secrets.GITHUB_TOKEN }}" | |
# workaround issue when project name is too long | |
firebaseToolsVersion: [email protected]:breathe/firebase-tools.git | |
channelId: live |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment