Skip to content

[eas-cli] Write credentials.json files into the project directory - #4477

Open
breken-ai wants to merge 2 commits into
expo:mainfrom
breken-ai:fix/credentials-json-paths-project-dir
Open

breken-ai wants to merge 2 commits into
expo:mainfrom
breken-ai:fix/credentials-json-paths-project-dir

Conversation

@breken-ai

Copy link
Copy Markdown

Why

EAS CLI finds the project root by walking up from the working directory to the nearest package.json, so eas credentials works from a subdirectory such as my-app/src. In that case, "Download credentials from EAS to credentials.json" breaks the local credentials.

updateFileAsync in packages/eas-cli/src/credentials/credentialsJson/update.ts resolves the target against projectDir and deletes the existing file there. It then calls mkdirp and writeFile with the relative filePath, which Node resolves against process.cwd(). The result:

  • the existing keystore (or distribution certificate and provisioning profile on iOS) in the project is deleted
  • the downloaded copy is written to <cwd>/credentials/..., outside the project root
  • credentials.json is written to the project root and points at a path that no longer exists, so the next build with credentialsSource: "local" fails to read the file

The existing tests use projectDir: '.', so they never caught this.

How

updateFileAsync now creates the directory and writes the file at absolutePath, the same path it already checks and removes. read.ts resolves these paths against projectDir in the same way, so reads and writes now match.

Test Plan

I added two tests to credentials/credentialsJson/__tests__/update-test.ts with projectDir: '/app', which is different from the process working directory:

  • Android: /app/keystore.jks exists and is referenced from /app/credentials.json. After the update it must hold the downloaded keystore, and no keystore.jks may appear in the working directory.
  • iOS: the dist cert and profile must be written to /app/credentials/ios/... and not to <cwd>/credentials.

On main both fail. The Android test fails with ENOENT: no such file or directory, open '/app/keystore.jks' because the file was deleted and written elsewhere. The iOS test fails with ENOENT ... '/app/credentials/ios/dist-cert.p12'. With the fix, all 10 tests in the file pass.

yarn jest --config jest.config.ts src/credentials/credentialsJson   # 22 passed
yarn jest --config jest.config.ts src/credentials                    # 231 tests passed

I also ran tsc --noEmit for packages/eas-cli, oxfmt --check and oxlint on the changed files. My install was a partial yarn workspaces focus, so 4 iOS action suites could not load minimatch types there. They fail the same way on main, which makes this an environment issue and not a result of this change.

I used an AI coding agent (Claude Code) to find this bug and write the fix. I reviewed the change and ran the tests above.

breken-ai and others added 2 commits September 25, 2026 21:15
updateFileAsync removed the file at the project-relative path but then
created and wrote the new file relative to process.cwd(). Running
`eas credentials` from a subdirectory of the project deleted the local
keystore, certificate or provisioning profile and wrote the downloaded
copy into the working directory, leaving credentials.json pointing at a
missing file.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Subscribed to pull request

File Patterns Mentions
packages/eas-cli/** @douglowder

Generated by CodeMention

Warning: The preamble and epilogue options in commentConfiguration are deprecated. Use template instead.

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

Successfully merging this pull request may close these issues.

1 participant