Git core.askPass config variable does not work

My eas-build-pre-install hook points to a script that, among other things, sets the core.askPass git config option. I do this as one of my dependencies is a private git repo. Unfortunately, it appears this is never run when installing dependencies. Why is this the case?

It is executed you can see it in logs just before install deps section

Script 'eas-build-pre-install' is present in package.json, running it...
yarn run v1.22.17
$ yarn ci_preinstall
$ ./scripts/ci/preinstall.sh
Done in 0.51s.

I noticed that the only secret you are passing is NPM_TOKEN, you are not configuring any credentials to access that private repo, so it’s falling back to prompt

check out this example Integrating with third-party tooling - Expo Documentation

First off, I meant the script pointed to by core.askPass, not the prebuild script. Apologies for not being as clear.

Second off, we are not using Git submodules, so your link does not include relevant instructions to help us.

Third, I am indeed configuring credentials. That’s what the core.askPass config option is for. It bypasses the password prompt and echos a password for it (see #2 here). It works exactly as I expect it to locally. But, for some reason the EAS container does not make use of it as a password echoer as my local machine does.

Why?

Second off, we are not using Git submodules, so your link does not include relevant instructions to help us.

it does, just skip the part about submodules and only use how to configure ssh key on the worker

Third, I am indeed configuring credentials. That’s what the core.askPass config option is for. It bypasses the password prompt and echos a password for it

using askPass sounds like a valid approach but how are you passing actual credentials to eas build instance? are you saying that you have committed that password in plain text in your repo inside .scripts/ci/echoGitCredential.sh ?

also note that path with working dir is different for android and ios dir

It’s a private repo on a private org. That script just generates a new SSH key. The private org’s auth won’t accept it as access.

No. That file is dynamically generated by my preinstall.sh script. It was originally committed as a file that echoed an environment variable that was previously set in my preinstall.sh script, but as I expressed in another thread: for some reason any environment variables I set via that preinstall.sh script clear themselves and are inaccessible in the install step.

So, I made a workaround to make the file be dynamically generated.

Again, I want to note that the script works exactly as expected on my local machine. How and why EAS handles it differently is beyond my understanding, which is why I posted here.

Is this documented anywhere?

It’s a private repo on a private org. That script just generates a new SSH key. The private org’s auth won’t accept it as access.

No, that script is taking env variable and serializes it as private ssh key and after that generates public key from the private one

So, I made a workaround to make the file be dynamically generated.

if file is in gitignore it won’t be uploaded to eas worker fyi/eas-build-archive.md at main · expo/fyi · GitHub

Is this documented anywhere?

I’m not sure, but it should be expected that macos has a different directory structure than linux

It seems to me your preinstall script would run in its own shell. If it sets environment variables, those would be discarded as soon as the script, and therefore the shell, exits. Then the install process would run in a different shell and the environment variables would not exist.

But can’t you use EAS secrets for the credentials? They are set as environment variables during the build.

I’m trying to make the prebuild.sh script work in multiple CI environments (namely EAS and GitHub Actions). We’ll be using GitHub Actions to then call an EAS build, and I don’t want to have to duplicate secrets across both CI environments where possible.

I understand the point about the environment variables being cleared. That makes sense. But I can set the core.askPass config and echo it out using yarn’s normal preinstall script, meaning it survives past the preinstall.sh script, but it is still not called when it tries to install our private git dependencies.

Can you post some example script(s), environment variables and package.json config so we can see exactly what you’re talking about?

My preinstall.sh script for CI environments.

#!/bin/bash
if [[ ! -z "${GITHUB_PAT}" ]]; then # GitHub Action
  export PKG_TOKEN=$GITHUB_PAT; 
  export APP_ROOT=$GITHUB_WORKSPACE;
fi;
if [[ ! -z "${NPM_TOKEN}" ]]; then # EAS Build
  export PKG_TOKEN=$NPM_TOKEN;
  export APP_ROOT="/home/expo/workingdir/build";
fi;
npm config set -g //npm.pkg.github.com/:_authToken=$PKG_TOKEN;
git config --global credential.https://github.com.username user;
export GIT_ASKPASS_FILE="$APP_ROOT/scripts/ci/echoGitCredential.sh";
touch $GIT_ASKPASS_FILE;
echo "echo $PKG_TOKEN" > $GIT_ASKPASS_FILE;
chmod +x $GIT_ASKPASS_FILE;
git config --global core.askPass $GIT_ASKPASS_FILE;

Relevant bit of package.json (inside the scripts property):

...
    "ci_preinstall": "./scripts/ci/preinstall.sh",
    "eas-build-pre-install": "yarn ci_preinstall",
...

If I were to add:

    "preinstall": "git config --global --list --show-origin",

I would see the correct core.askPass config value echoed out in the “Installing dependencies” section. But then it immediately fails saying prompts are disabled, meaning it didn’t execute that script and instead fell back to the prompt.

The only way I’m able to get the “ask pass” functionality to work is if I use the GIT_ASKPASS environment variable inside eas.json. But again:

  • that’s something I want to avoid, if possible
  • per the git documentation, there should be little to no difference between the environment variable and the config value
  • it works as expected on my machine

This is a problem with git is on the machine not utilizing the core.askPass config value when it should. Full stop. Unless I’ve missed something over the dozens of times and ways I’ve tired this, git is simply showing unexpected behavior.

OK, but we aren’t using SSH auth, so that’s kind of a non-starter. Especially when all I am trying to do here is to git to work as it is documented to work, not go and use an entirely different authentication method.

You’re right. It gets dynamically generated at preinstall time. No need for it to be committed.

Makes sense. That does seem like something that should be documented.

Did a lot of research. Found a few things:

  1. The latest build image for Android builds is based off Ubuntu 20.04 (source: Build server infrastructure - Expo Documentation)
  2. The version of Git that comes with Ubuntu 20.04 (codename: Focal Fossa) is 2.25.1 (source: Ubuntu – Details of package git in focal)
  3. In October of 2020 (after Ubuntu 20.04 was released), it was found that some internal part of Git was not honoring the core.askPass config value and a patch was made (source: [PATCH] credential: load default config - Thomas Koutcher via GitGitGadget)
  4. This patch was released in Git version 1.30.0 (source: [ANNOUNCE] Git v2.30.0 - Junio C Hamano)

Thus, I think I can conclude this is an upstream bug in Git that was patched, but EAS does not have the patch. Perhaps, at some point, EAS will offer newer container images with patched versions of Git.

1 Like

OK, but we aren’t using SSH auth, so that’s kind of a non-starter

yes, it’s fine if you don’t want to use it, but using ssh on CI is very standard approach, so I would still recommend considering that option

Perhaps, at some point, EAS will offer newer container images with patched versions of Git.

We will probably add images with latest ubuntu LTS soon, but you still need to make sure that echoGitCredential.sh script is uploaded to eas, all the info about the upload and packaging process is in the link in my last comment

OK, so I suppose you’ll define the GitHub credentials somewhere such that the GitHub action has access to it in some way, e.g. as an environment variable? And you want to pass this along to EAS Build. I think you could do that by generating eas.json from a template in your GitHub Action :thinking:

I assume this was an anonymisation typo? :slight_smile: Otherwise that “root” path is not defined anywhere.

What does $PKG_TOKEN (or $NPM_TOKEN) look like? Just based on the name it doesn’t seem like the contents of a script.

If the NPM_TOKEN environment variable doesn’t exist, the script will be a zero length file, which would run, but not do anything/produce any output. So I would guess that is what’s happening.
Maybe you could do something like this to see what’s happening:

# [...]
export GIT_ASKPASS_FILE="$APP_ROOT/scripts/ci/echoGitCredential.sh"
cat >"$GIT_ASKPASS_FILE" <<EOF
#!/bin/sh

# Echo something to stderr
echo "Git credentials script running: $@" 1>&2

$PKG_TOKEN
EOF
chmod +x $GIT_ASKPASS_FILE
git config --global core.askPass $GIT_ASKPASS_FILE

(btw, semicolons in shell scripts are command separators. Not terminators. So you only need them if you have more than one command on the same line and only to separate them. You don’t need them at the ends of the lines.) :slight_smile:

Could you just use something like . instead of the full path?

If not, try running env in a hook or your preinstall script to print out the environment variables and current working directory. I suspect you could use something based on $HOME or maybe $PWD.

1 Like

Understandable, but at this point, I’m just trying to get it to work.

Again, it does not exist until prebuild.sh runs and creates it. The fact that it is not uploaded is not the issue. The issue is that Git is not running as documented.

That is a fascinating idea. I may look into it.

Thanks, lol!

Yep! Please ignore, I just fixed it in my original message.

It’s a GitHub Personal Access Token (PAT). Its purpose is two-fold:

  1. Authenticate with Git to pull down Git dependency
  2. Authenticate with GitHub packages to pull down private NPM packages

@wkozyra this is why I didn’t bother to set up SSH because the PAT serves two purposes ^. Plus, our Git dependency is (hopefully) temporary anyway.

No, it would just be echo , as that is what the token is prefixed with:

echo "echo $PKG_TOKEN" > $GIT_ASKPASS_FILE;

The prebuild.sh script, for some reason, does not appear to run within that folder to begin with. If it did, that point would be moot, but I did try relative paths at first and it failed.

Again, to close, it appears this was a bug with the version of Git in the container, and I have already found a workaround. But I thank you for your message and suggestions :slight_smile:

Right, sorry, I missed the second echo in that command :sweat_smile:

So your script most likely just contains “echo”, which would be like just pressing Enter when prompted for the password. So it’s no wonder it doesn’t work :slight_smile:

But of course it might also have been the Git version as you said. :man_shrugging:

Well, no, because it explicitly shows an error “prompts are disabled”, so it still trying to show the prompt instead of using the file. If it were using it, the error would be something akin to “incorrect password”. I am fairly certain it is the Git version.

1 Like

Update: GitHub Actions seemed to have issues with that config value as well, despite using a newer version of Git. Ended up having to use the GIT_ASKPASS variable anyway.

Update 2: Using the new 22.04 images and I am still experiencing the same issues. Will investigate further.