Can't Deploy to Firebase Hosting with GitHub Actions

Hi!

I’m having some difficulty deploying to firebase hosting with GitHub Actions. It’s my first time using Actions, but I’ve used similar CI/CD tools in the past. 

The deployment fails on the final action “Connect and Deploy”:

workflow "Deploy" {
  on = "push"
  resolves = [
    "Connect and Deploy",
    "Build",
  ]
}

action "Install Dependencies" {
  uses = "nuxt/actions-yarn@node-11"
  args = "install"
}

action "Build" {
  uses = "nuxt/actions-yarn@node-11"
  needs = ["Install Dependencies"]
  args = "run generate"
}

action "Connect and Deploy" {
  uses = "docker://devillex/docker-firebase:latest"
  runs = "firebase"
  args = "deploy --token=\"${FIREBASE_TOKEN}\" --only=hosting --message=\"${GITHUB_REF}\" --debug"
  env = {
    APP = "cmot-app"
  }
  needs = ["Build"]
  secrets = ["FIREBASE_TOKEN"]
}

Output: 

### STARTED Connect and Deploy 15:30:58Z

Already have image (with digest): gcr.io/github-actions-images/action-runner:latest
Unable to find image 'devillex/docker-firebase:latest' locally
latest: Pulling from devillex/docker-firebase
cd8eada9c7bb: Already exists
c2677faec825: Already exists
fcce419a96b1: Already exists
045b51e26e75: Already exists
3b969ad6f147: Already exists
a81151df0bcd: Already exists
da110374024c: Pulling fs layer
382c7798d45f: Pulling fs layer
b8bb8d0bb27a: Pulling fs layer
7b130670245b: Pulling fs layer
7b130670245b: Waiting
b8bb8d0bb27a: Verifying Checksum
b8bb8d0bb27a: Download complete
382c7798d45f: Verifying Checksum
382c7798d45f: Download complete
da110374024c: Verifying Checksum
da110374024c: Download complete
7b130670245b: Verifying Checksum
7b130670245b: Download complete
da110374024c: Pull complete
382c7798d45f: Pull complete
b8bb8d0bb27a: Pull complete
7b130670245b: Pull complete
Digest: sha256:6057d8c491dbd7272adfcc83a28c17cfed188f07f3396cbd9983760e07625f99
Status: Downloaded newer image for devillex/docker-firebase:latest
[2019-01-18T15:31:05.006Z] ----------------------------------------------------------------------
[2019-01-18T15:31:05.010Z] Command: /usr/local/bin/node /home/node/.npm-global/bin/firebase deploy --token="${FIREBASE_TOKEN}" --only=hosting --message="${GITHUB_REF}" --debug
[2019-01-18T15:31:05.011Z] CLI Version: 6.2.2
[2019-01-18T15:31:05.011Z] Platform: linux
[2019-01-18T15:31:05.012Z] Node Version: v10.15.0
[2019-01-18T15:31:05.023Z] Time: Fri Jan 18 2019 15:31:05 GMT+0000 (Coordinated Universal Time)
[2019-01-18T15:31:05.024Z] ----------------------------------------------------------------------

[2019-01-18T15:31:05.038Z] > command requires scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
[2019-01-18T15:31:05.039Z] > authorizing via --token option
[2019-01-18T15:31:05.040Z] [iam] checking project cmot-app for permissions ["firebase.projects.get","firebasehosting.sites.update"]
[2019-01-18T15:31:05.041Z] > refreshing access token with scopes: ["email","openid","https://www.googleapis.com/auth/cloudplatformprojects.readonly","https://www.googleapis.com/auth/firebase","https://www.googleapis.com/auth/cloud-platform"]
[2019-01-18T15:31:05.042Z] >>> HTTP REQUEST POST https://www.googleapis.com/oauth2/v3/token
 <request body omitted>
[2019-01-18T15:31:05.119Z] <<< HTTP RESPONSE 400 content-type=application/json; charset=utf-8, vary=X-Origin, Referer, Origin,Accept-Encoding, date=Fri, 18 Jan 2019 15:31:05 GMT, server=ESF, cache-control=private, x-xss-protection=1; mode=block, x-frame-options=SAMEORIGIN, x-content-type-options=nosniff, accept-ranges=none, connection=close
[2019-01-18T15:31:05.120Z] >>> HTTP REQUEST POST https://cloudresourcemanager.googleapis.com/v1/projects/cmot-app:testIamPermissions
 permissions=[firebase.projects.get, firebasehosting.sites.update]
[2019-01-18T15:31:05.137Z] <<< HTTP RESPONSE 401 www-authenticate=Bearer realm="https://accounts.google.com/", error="invalid_token", vary=X-Origin, Referer, Origin,Accept-Encoding, content-type=application/json; charset=UTF-8, date=Fri, 18 Jan 2019 15:31:05 GMT, server=ESF, cache-control=private, x-xss-protection=1; mode=block, x-frame-options=SAMEORIGIN, x-content-type-options=nosniff, accept-ranges=none, connection=close
[2019-01-18T15:31:05.138Z] <<< HTTP RESPONSE BODY code=401, message=Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project., status=UNAUTHENTICATED

Error: HTTP Error: 401, Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.
[2019-01-18T15:31:05.142Z] Error Context: {
  "body": {
    "error": {
      "code": 401,
      "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
      "status": "UNAUTHENTICATED"
    }
  },
  "response": {
    "statusCode": 401,
    "body": {
      "error": {
        "code": 401,
        "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
        "status": "UNAUTHENTICATED"
      }
    },
    "headers": {
      "www-authenticate": "Bearer realm=\"https://accounts.google.com/\", error=\"invalid_token\"",
      "vary": "X-Origin, Referer, Origin,Accept-Encoding",
      "content-type": "application/json; charset=UTF-8",
      "date": "Fri, 18 Jan 2019 15:31:05 GMT",
      "server": "ESF",
      "cache-control": "private",
      "x-xss-protection": "1; mode=block",
      "x-frame-options": "SAMEORIGIN",
      "x-content-type-options": "nosniff",
      "accept-ranges": "none",
      "connection": "close"
    },
    "request": {
      "uri": {
        "protocol": "https:",
        "slashes": true,
        "auth": null,
        "host": "cloudresourcemanager.googleapis.com",
        "port": 443,
        "hostname": "cloudresourcemanager.googleapis.com",
        "hash": null,
        "search": null,
        "query": null,
        "pathname": "/v1/projects/cmot-app:testIamPermissions",
        "path": "/v1/projects/cmot-app:testIamPermissions",
        "href": "https://cloudresourcemanager.googleapis.com/v1/projects/cmot-app:testIamPermissions"
      },
      "method": "POST"
    }
  }
}

### FAILED Connect and Deploy 15:31:09Z (11.744s)

The response indicates an invalid token, but I can run the exact same command on my local machine without trouble. Perhaps I’m not setting (or passing) the value of $FIREBASE_TOKEN properly?

Thanks!

Update

If I hardcode the value of $FIREBASE_TOKEN into args the deployment works flawlessly.

Screenshot 2019-01-18 14.50.10.png

Still doesn’t work if I swap in $FIREBASE_TOKEN.

Hello,

This is a problem with parameter expansion. The firebase command doesn’t expand the parameters, the easiest way to fix this is to wrap your execution in a shell, which will expand paramters.

This is probably more easily shown with some examples. First we tell docker to executed echo $FOO and then we tell it to execute sh -c "echo $FOO":

$ docker run --rm devillex/docker-firebase:latest echo \$FOO
$FOO
$ docker run --rm -e "FOO=b" --entrypoint=sh devillex/docker-firebase:latest -c "echo \$FOO"
b

Confusingly I have to escape $FOO in these examples otherwise my terminal will expand the parameter before it’s passed to docker:

$ FOO=a && docker run --rm -e "FOO=b" devillex/docker-firebase:latest echo $FOO
a

So to put this to work in Actions, this is what we need to do:

uses = "docker://devillex/docker-firebase:latest"
runs = "sh -c"
args = ["echo $FOO"]
env = {
  FOO = "bar"
} 

So here’s what I think your action should look like:

action "Connect and Deploy" {
  uses = "docker://devillex/docker-firebase:latest"
  runs = "sh -c"
  args = ["firebase deploy --token=\"${FIREBASE_TOKEN}\" --only=hosting --message=\"${GITHUB_REF}\" --debug"]
  env = {
    APP = "cmot-app"
  }
  needs = ["Build"]
  secrets = ["FIREBASE_TOKEN"]
}
2 Likes

Thank you, @hfaulds!! That did the trick.

Screenshot 2019-01-22 13.21.05.png

2 Likes