Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

question(createTestEnvFile): can't access SERVICE_ACCOUNT env var on CircleCI #23

Closed
Xiaochi-Li opened this issue May 9, 2019 · 17 comments

Comments

@Xiaochi-Li
Copy link

I've been trying to run cypress-firebase on CI, but keep getting this error:

✖ Error: STAGE_FIREBASE_PRIVATE_KEY not found, make sure it is set within environment variables.
✖ Error: Test env file could not be created:
Service Account is missing parameters: private_key_id, private_key, client_email, client_id, client_x509_cert_url

I tried different things:

  1. p a STAGE_FIREBASE_PRIVATE_KEY env var with firebase private key in it
  2. wrap serviceAccount object in ""
  3. unwrap serviceAccount object

none of them works.

@prescottprue
Copy link
Owner

Did you try the SERVICE_ACCOUNT environment variable as a string? It should be documented better, but that is also an option. I will look into trying to reproduce, thanks for reporting

@prescottprue
Copy link
Owner

Ping - wondering version you were running and if you got a chance to try the SERVICE_ACCOUNT environment variable.

@orthodoc
Copy link

orthodoc commented Jun 20, 2019

I am running into the same problem.

@prescottprue, I am able to run the tests locally. But at circleci, I am lost.
What is the meaning of Step 6? Do I do this?
SERVICE_ACCOUNT: "serviceAccount.json"

This is the workaround I am following:

  1. Encode the serviceAccount.json with jq '.' serviceAccount.json | base 64
  2. Save the output as an env var in circleci DEV_SERVICE_ACCOUNT
  3. Decode the env var with the command: echo $DEV_SERVICE_ACCOUNT | base64 --decode > serviceAccount.json

I am using the dev branch to do all the testing and keep master read only.

This way I am able to avoid committing the json file to git and recover the structure of the json file

@prescottprue
Copy link
Owner

The purpose is to actually assign the whole service account object as an environment variable string i.e.:

export SERVICE_ACCOUNT="{ \"type\": "service-account", ... }"

Thanks for posting what you are doing in the mean time

@ralphsmith80
Copy link

@prescottprue I'm running into the same issue on Gitlab.

I have the SERVICE_ACCOUNT and FIREBASE_TOKEN environment variables set. I do have the variable scoped to an environment but I've tried enabling for all environments too.

I converted the contents of serviceAccount.json to a string using JSON.stringify. That does not include the escape characters. I noticed in your example you only escaped the key and not the value. I'm guessing that's a typo.

Example from chrome dev tools:

o = {"type": "service_account"}
# > {type: "service_account"}
JSON.stringify(o)
# > "{"type":"service_account"}"

I tested both with and without the escape characters but I'm still getting the following error.

ℹ Generating custom auth token for Firebase project with projectId: keepify-dev
ℹ Service account does not exist at path: "serviceAccount.json" falling back to environment variables...
✖ Error: DEV_FIREBASE_PRIVATE_KEY not found, make sure it is set within environment variables.
✖ Error: Test env file could not be created:
Service Account is missing parameters: private_key_id, private_key, client_email, client_id, client_x509_cert_url

Here's my gitlab-ci.yml scripts for this portion.

e2e_dev:
  stage: e2e
  script:
    - npm run e2e
  only:
    - master
  environment:
    name: dev
  allow_failure: true

And finally the e2e script from my package.json.

"e2e": "npm run e2e:testConfig && cypress run",
"e2e:testConfig": "cypress-firebase createTestEnvFile",

@prescottprue
Copy link
Owner

prescottprue commented Sep 19, 2019

@ralphsmith80 I am able to put the SERVICE_ACCOUNT directly into Gitlab without having to do any delimiting or wrapping the value in a string, did you give that a try? Like so:

image

@orthodoc what you are doing should work fine, but if you assign the SERVICE_ACCOUNT environment variable to a string containing the service account object, that should also work

@ralphsmith80
Copy link

@prescottprue I did try that. No dice. I believe this error is the most telling.

✖ Error: DEV_FIREBASE_PRIVATE_KEY not found, make sure it is set within environment variables.

I'm not setting this value anywhere DEV_FIREBASE_PRIVATE_KEY. Also my project is based off of create-react-app which means I'm not using NODE_ENV anywhere explicitly.

https://create-react-app.dev/docs/adding-custom-environment-variables#docsNav

Note: You must create custom environment variables beginning with REACT_APP_. Any other variables except NODE_ENV will be ignored to avoid accidentally exposing a private key on the machine that could have the same name.

I do have a dev environment in Gitlab which is where I'm testing this but I didn't seen anything about that in the docs or code.
dev-env

Is there a case where DEV_FIREBASE_PRIVATE_KEY would by dynamically expected instead of SERVICE_ACCOUNT?

I did try defining DEV_FIREBASE_PRIVATE_KEY in the environment variables but that didn't work either.

@prescottprue
Copy link
Owner

prescottprue commented Oct 1, 2019

@ralphsmith80 Interesting, thanks for the info. Can you confirm again which version you are using? 0.2.5 ?

SERVICE_ACCOUNT and DEV_SERVICE_ACCOUNT (environment specific service account) should come before looking for FIREBASE_PRIVATE_KEY and DEV_FIREBASE_PRIVATE_KEY (the environment specific version of the key). This line is where the service account is loaded if the local file is not found, but it seems like we are getting passed that logic to where we try to load from separate environment variables.

Something to note: by default, when calling createTestEnvFile, it is assumed that you are doing it for the environment associated with the branch you are on. If no environment is set, then it falls back to the branch name. This can be overridden by passing in an argument with createTestEnvFile: createTestEnvFile master - this should load from the master environment/project regardless of branch/environments.

@ralphsmith80
Copy link

@prescottprue I'm using version 2.5.0

I did try setting the branch explicitly as you noted ( createTestEnvFile master) with no luck.

One thing I forgot to mention/question previously regarding how to set the SERVICE_ACCOUNT environment variable. In the README.md for the pre-setup you called out the following.

Set service account as the SERVICE_ACCOUNT environment variable within your CI (make sure to wrap it in ")

What does "make sure to wrap it in "" mean?

Is that still relevant. That's what lead me to try JSON.stringify with escape characters previously. Maybe I'm overlooking something there still.

@prescottprue
Copy link
Owner

@ralphsmith80 2.5.0 isn't a version of cypress-firebase, I am guessing you meant 0.2.5?

What was meant by that is that some provider do not allow you to set an object to the value of an environment variable unless it is wrapped in " (i.e. a string). That isn't an issue for me on Gitlab, and since I believe that is what you are using, you should also be fine.

Are you able to run the tests locally? Using the ./serviceAccount.json file method? We could probably use that to override the current behaivor as well (meaning in CI you could do - $SERVICE_ACCOUNT > ./serviceAccount.json and add that file to your git ignore).

Other than that though, I am still kinda stumped as to why the variables wouldn't be getting picked up. Did you maybe mark them as "protected" in the variables page? That could be protecting your brach from accessing it maybe?

@ralphsmith80
Copy link

ralphsmith80 commented Oct 3, 2019

@prescottprue bah! yes I meant 0.2.5. Trying to type too fast.

It works fine locally with the ./serviceAccount.json file. If I remove that file then I get an error similar to the on in gitlab but with a different env slug.

i Service account does not exist at path: "C:\Users\ralph\Workspace\divvy\serviceAccount.json" falling back to environment variables...
× Error: STAGE_FIREBASE_PRIVATE_KEY not found, make sure it is set within environment variables.
× Error: Test env file could not be created:
Service Account is missing parameters: private_key_id, private_key, client_email, client_id, client_x509_cert_url

I did mark them as protected but my branches are also protected. I ran into that issue sometime back and it took me a while to find the documentation that a protected branch can only access protected variables. Also I'm using other environment variable to continuously deploy to firebase and that is working without issue.

I just published a forked version of this package with a bit more logging to see what environment variables are coming in. I might have to iterate on that a bit to figure it out but using the redirect method ($SERVICE_ACCOUNT > ./serviceAccount.json) would make me sad.

Although if this first test doesn't work I'll probably try that out just to see if it does work as a fallback.

@ralphsmith80
Copy link

While I'm working through this it looks like the expectation is that all values are expected to be present in the cypress\config.json if that file exists.

I only have the values noted from step 4 in the setup in the config file and checked into source control.

The script is hitting this return path for every environment variable.

What values are expected to be defined in the CI environment variables?

  • SERVICE_ACCOUNT ✔️

What files should be checked in to source?

  • cypress.env.json ❌
  • serviceAccount.json ❌
  • cypress/config.json ✔️

@ralphsmith80
Copy link

Based on the last test I ran I see the SERVICE_ACCOUNT is read when using process.env[varNameRoot] but as noted above I'm not getting there because I have the cypress/config.json checked into source.

I believe the following is the correct:

Values expected to be defined in the CI environment variables:

  • SERVICE_ACCOUNT ✔️
  • TEST_UID ✔️
  • FIREBASE_API_KEY ✔️
  • FIREBASE_PROJECT_ID ✔️

Files that should be checked into source:

  • cypress.env.json ❌
  • serviceAccount.json ❌
  • cypress/config.json ❌

It past my bedtime so I'll have to continue testing this theory tomorrow. @prescottprue if you have definitive answers I appreciate know them. Also if this is the problem then I think the documentation could be cleared up a bit around this.

@prescottprue
Copy link
Owner

prescottprue commented Oct 3, 2019

@ralphsmith80 That may be the case cypress/config.json is mean to be used to set your TEST_UID and FIREBASE_PROJECT_ID when developing locally, and that info is used to generate the cypress.env.json file. Since in the CI setup those settings presumably come from environment variables, it could cause an issue if it is there - this logic should for sure be changed.

Totally agree that the instructions should be more clear, and there should be more info about what not to check into src as you are saying. Thanks for continuing to try to debug, really hoping to solve this so other folks don't bump into the same thing.

@ralphsmith80
Copy link

@prescottprue with those changes it looks like everything is working from the cypress-firebase side.

I'm still having problems getting cypress to actually run. Would you mind sharing your .gitlab-ci.yaml or a subset of it?

After reviewing the cypress docs I added the following parts which partially addressed errors I was seeing.

# to cache both npm modules and Cypress binary we use environment variables
# to point at the folders we can list as paths in "cache" job settings
variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"
  CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/cache/Cypress"

This is the error I'm seeing now:

✔ cypress.env.json updated successfully
It looks like this is your first time using Cypress: 3.4.1

[22:29:06]  Verifying Cypress can run /builds/divvy-it/divvy/cache/Cypress/3.4.1/Cypress [started]
[22:29:06]  Verifying Cypress can run /builds/divvy-it/divvy/cache/Cypress/3.4.1/Cypress [failed]
Your system is missing the dependency: Xvfb

Install Xvfb and run Cypress again.

Read our documentation on dependencies for more information:

https://on.cypress.io/required-dependencies

If you are using Docker, we provide containers with all required dependencies installed.

----------

Error: spawn Xvfb ENOENT

----------

This is my .gitlab-ci.yml minus some repeated steps for different branches/environments:

image: node:10.3.0

stages:
  - install
  - test
  - build
  - deploy
  - e2e

# to cache both npm modules and Cypress binary we use environment variables
# to point at the folders we can list as paths in "cache" job settings
variables:
  npm_config_cache: "$CI_PROJECT_DIR/.npm"
  CYPRESS_CACHE_FOLDER: "$CI_PROJECT_DIR/cache/Cypress"

cache:
  #  jobs of each branch always use the same cache
  key: ${CI_COMMIT_REF_SLUG}
  paths:
    - .npm
    - cache/Cypress
    - node_modules
    - functions/node_modules

install_functions:
  stage: install
  script:
    - cd ./functions && npm install
  only:
    - master
    - staging
    - production
    - paid
  artifacts:
    paths:
      - functions/node_modules

install_client:
  stage: install
  script:
    - npm ci
  only:
    - master
    - staging
    - production
    - paid
  artifacts:
    paths:
      - node_modules

test_client:
  stage: test
  script:
    - npm run test
  only:
    - master
    - staging
    - production
    - paid
  dependencies:
    - install_client

coverage_client:
  stage: test
  script:
    - npm run coverage
  only:
    - master
  dependencies:
    - install_client
  artifacts:
    paths:
      - coverage/

build_dev:
  stage: build
  script:
    - REACT_APP_ENV=development npm run build
  only:
    - master
  dependencies:
    - install_client
  artifacts:
    paths:
      - build

deploy_dev:
  stage: deploy
  script:
    - npm install -g firebase-tools
    - firebase deploy --project default --token $FIREBASE_DEPLOY_KEY -m "Pipeline $CI_PIPELINE_ID, build $CI_BUILD_ID"
  only:
    - master
  environment:
    name: dev
  dependencies:
    - install_functions
    - build_dev

e2e_dev:
  stage: e2e
  script:
     # print CI environment variables for reference
    - $(npm bin)/print-env CI
    # - $(npm bin)/cypress run
    # start the server in the backgro
    - npm run e2e
  only:
    - master
  environment:
    name: dev
  allow_failure: true

Note that I'm defining one docker image to use at the top. I'm going to try and use the cypress docker image just for the e2e stage. e.g. image: cypress/base:10. I'll post back the results.

@prescottprue
Copy link
Owner

prescottprue commented Oct 4, 2019

Here is the gitlab config from fireadmin, which is a project I created for managing Firebase projects as "environments" and copying data across different projects. A key piece is to use the cypress image for those tests so that you have all of the necessary dependencies for running Cypress. I personally also like to run $(npm bin)/cypress verify to confirm that it cypress is installed correctly and ready to use.

I think it would be good to include that link and other Gitlab setup examples in the docs, so thanks for asking!

Great to hear that things are working as expected now - still planning on updating the logic to fall back to other options if the value itself does not exist.

prescottprue pushed a commit that referenced this issue Oct 5, 2019
prescottprue added a commit that referenced this issue Oct 5, 2019
* feat(core): add unit tests
* fix(callFirestore): fix `get` action passing invalid arguments
* fix(callRtdb): fix do not add project flag unless project is defined
* fix(createTestEnvFile): improve fallbacks for loading variables config/environment - #23
@prescottprue prescottprue changed the title Can't access SERVICE_ACCOUNT env var on CircleCI question(createTestEnvFile): can't access SERVICE_ACCOUNT env var on CircleCI Oct 7, 2019
prescottprue added a commit that referenced this issue Oct 9, 2019
* fix(cy.callRtdb): only add `-d` flag when data is an object
* fix(cy.callFirestore): fixture path no longer stringified - #39
* feat(cy.callRtdb): fix writing a non object value with `set` - #60
* feat(tests): add tests for string value - #39
* feat(docs): add note to README about adding files to `.gitignore` - #23
prescottprue added a commit that referenced this issue Oct 12, 2019
* feat(core): switch to typescript - #47
* fix(callFirestore): fix `get` action passing invalid arguments
* fix(callRtdb): fix do not add project flag unless project is defined
* fix(createTestEnvFile): improve fallbacks for loading variables config/environment - #23
* feat(core): switch to yarn over npm for install + lock file
* feat(core): separate utils which require node into `node-utils.ts` - #47
* fix(cy.callRtdb): only add `-d` flag when data is an object
* fix(cy.callFirestore): fixture path no longer stringified - #39
* feat(cy.callRtdb): fix writing a non object value with `set` - #60
* feat(tests): add tests for string value - #39
* feat(docs): add note to README about adding files to `.gitignore` - #23
* feat(core): add unit tests
@prescottprue
Copy link
Owner

In v0.3.0 there was logic added to check for the existence of the value within the local file so that even if the file is there it won't override all environment variables, just the ones located in the file. Also, there is a note in the README now about adding cypress/config.json as mentioned by @ralphsmith80.

This should handle the issue being described, but if anyone is still experiencing an issue, feel free to reach out. Thanks to all for the input!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants