Skip to content

Conversation

@AliSoftware
Copy link
Contributor

@AliSoftware AliSoftware commented Nov 14, 2025

Closes: AINFRA-1533

What

This PR migrates the repo to use git-crypt instead of configure_apply, so that the usage of secrets in the repo gets easier and more transparent for developers.

How

  • 🗑️ Delete .configure and .configure-files/*.enc files
  • Add files that were listed in .configure as encrypted files in the repo instead, by also adding their path as entries in the .gitattributes with filter=git-crypt diff=git-crypt—so they get encrypted by git-crypt on push
  • Update .gradle files and Fastfile to account for new file paths
  • Update .gradle code to account for the fact that now the files are present (but encrypted) after cloning the repo—as opposed to being absent when we didn't run configure_apply in the old way.
  • Replace calls to bundle exec fastlane run configure_apply in .buildkite/* commands—and calls to configure_apply(force: true) in Fastfile—with calls to .buildkite/commands/git-crypt-unlock.sh, and bump ci-toolkit plugin to point to Add git-crypt wrapper Automattic/a8c-ci-toolkit-buildkite-plugin#195
  • 📚 Updated documentation

Note

ℹ️ About the git-crypt helper from ci-toolkit

Currently, none of our CI agent have git-crypt pre-installed. Besides, it might get tricky to have a git-crypt binary for all needed architectures/platforms; in particular, compiling git-crypt for Windows seems tricky (and not that well documented) and the author admits the tool hasn't been tested as thoroughly on Windows.

To account for that, ci-toolkit provides a git-crypt wrapper script, that takes care of running git-crypt from within a docker container. This involves some sugarcoating (handle .git/objects/info/alternates used by git-mirrors on CI, etc) which is ultimately hidden to the caller by that wrapper script, to allow you to call this git-crypt wrapper exactly the same way you'd call the real one.

Future Directions

Before merging:

  • We should add the Buildkite steps in a8c-ci-toolkit-buildkite-plugin's .buildkite/pipeline.yml so that it docker build and docker push the git-crypt docker image to our AWS ECR, so that CI agents won't have to rebuild the image from scratch each.
  • Then we need to merge Add git-crypt wrapper Automattic/a8c-ci-toolkit-buildkite-plugin#195, create a new ci-toolkit version/tag, then update this PR's shared-pipeline-vars to point to it

In the longer term:

  • We might consider pre-installing the git-crypt binary directly into our various CI agents1, so that when they'll call git-crypt the pre-installed binary that appears earlier in the $PATH would then supersede the wrapper script from ci-toolkit (thus bypassing the need for wrapping the execution inside docker run)

Merge timing

Important

Do not merge this PR until (1) we have all the documentation / FAQ ready for all devs to follow in FG and (2) we have validated similar PRs in other repos—especially ones using macOS/Windows and Tumblr CI agents—work too. Indeed, if the adoption of git-crypt works well in macOS and in Android agents but doesn't work on some other agents (like Windows instances or Tumblr k8s agents), this is going to be a blocker for adoption after all.

Test Steps

General check

  • Verify CI is green
  • Checkout this branch and validate that all the secret files added to the repo in this PR are encrypted and unreadable:
    • WooCommerce/google-services.json
    • WooCommerce/upload.jks
    • debug.keystore
    • firebase.secrets.json
    • google-upload-credentials.json
    • secrets.properties
    • sentry.properties
  • Review the documentation updates
  • Review and ensure all the changes necessary in *.gradle files to reflect the new setup are covered by this PR (path updates to .properties or keystore files, code updates around logic that was based on if a secret file exists or not, …)

Follow the README.md instructions as an Automattician

  • Clone the repo from scratch in a new directory on your Mac, then checkout this PR's branch
  • Copy the git-crypt encryption key from our Secret Store in your clipboard, then run git-crypt unlock <(pbpaste | base64 -d) at the root of your new clone's directory
  • Validate that after this step, you are able to read the content of secret files like secrets.properties in clear now
  • Build and Run the project, validating everything works as expected (including e.g. Google login to validate google-services.json is taken into account, etc)

Note

ℹ️ The real migration won't require devs to clone the repo from scratch; this is just for the testing steps of this PR

Above I suggest to test this scenario in a fresh clone of the repo rather than your everyday working copy, especially to avoid risking to leave your git repo in a state that is setup for git-crypt while you were just testing and the PR is not merged yet.

In practice, once the PR is merged in trunk, devs won't need to clone the repo fresh to migrate to git-crypt though.
They will just have to run git-crypt unlock <(pbpaste | base64 -d) on their existing working copy and nothing else.

Though at some point I'd still highly recommend for them also get rid of the old files that were installed by their previous setup with configure (rm -rf ~/.configure/woocommerce-android and git clean -dxi -e .DS_Store -e .idea -e local.properties), to avoid confusion and risking relying on obsolete files.

Follow the README.md instructions as an external contributor

  • Clone the repo from scratch in a new directory on your Mac, then checkout this PR's branch
  • Validate files like secrets.properties show as encrypted garbage
  • Edit defaults.properties to add the relevant values for wp.oauth.*
  • Overwrite WooCommerce/google-services.json encrypted file with WooCommerce/google-services.json-example
  • Build and Run the project, validating everything works as expected (except Google login)

Footnotes

  1. At least the Mac Minis and the custom AMI for android; might be more cumbersome for Windows as running git-crypt's make to compile it for Windows is quite more involved and not well documented

@AliSoftware AliSoftware force-pushed the AINFRA-882-adopt-git-crypt branch 5 times, most recently from dc6517c to 703d297 Compare November 14, 2025 21:28
@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Nov 14, 2025

📲 You can test the changes from this Pull Request in WooCommerce-Wear Android by scanning the QR code below to install the corresponding build.
App NameWooCommerce-Wear Android
Platform⌚️ Wear OS
FlavorJalapeno
Build TypeDebug
Commit3a21aac
Direct Downloadwoocommerce-wear-prototype-build-pr14979-3a21aac.apk

@wpmobilebot
Copy link
Collaborator

wpmobilebot commented Nov 15, 2025

📲 You can test the changes from this Pull Request in WooCommerce Android by scanning the QR code below to install the corresponding build.

App NameWooCommerce Android
Platform📱 Mobile
FlavorJalapeno
Build TypeDebug
Commit3a21aac
Direct Downloadwoocommerce-prototype-build-pr14979-3a21aac.apk

@AliSoftware AliSoftware force-pushed the AINFRA-882-adopt-git-crypt branch from e8ca34f to 79cf715 Compare November 15, 2025 02:09
 - Replace calls to `configure_apply` with calls to `.buildkite/git-crypt/unlock.sh`
 - Commit the prebuilt binary to use on our EC2 images on CI(1), alongside the Dockerfile that was used to create it(2)

(1) In the future we'll probably pre-provision our custom Android AMI with it instead of shipping it inside each repo
(2) In theory we could use `docker run --rm -v …` to run `git-crypt` from within the Docker container, instead of extracting the binary from the Docker image and committing that binary. But for this to work, that requires to not only map the repo's dir as volume in the container, but also map the repo mirror dir used during `git clone --reference` / listed in `.git/objects/info/alternates`; so that can get tricky in CI that uses that git mirrors mechanism. Besides, the binary is pretty small (200KB) and being able to run it directly without Docker is not only simpler but avoids pulling the docker image in the CI agent before we can run it.
@AliSoftware AliSoftware force-pushed the AINFRA-882-adopt-git-crypt branch 2 times, most recently from a79527b to be5c217 Compare November 15, 2025 03:16
 - Now that we migrated to `git-crypt`, the `WooCommerce/google-services.json` file _always_ exists in the repo (albeit encrypted if the repo was not git-crypt-unlocked after being cloned), the logic to decide when to copy the `google-services.json-example` file had to be adjusted
 - Also updated the `README.md` accordingly—to suggest external contributors to copy the example file
@AliSoftware AliSoftware force-pushed the AINFRA-882-adopt-git-crypt branch from be5c217 to 0509840 Compare November 15, 2025 03:36
@AliSoftware AliSoftware requested a review from wzieba November 15, 2025 04:38
@AliSoftware AliSoftware added the category: tooling Anything that involves building & maintaining the project, including scripts, `Fastfile`, etc. label Nov 15, 2025
@AliSoftware AliSoftware self-assigned this Nov 15, 2025
@AliSoftware AliSoftware marked this pull request as ready for review November 15, 2025 04:43
@AliSoftware AliSoftware changed the title [AINFRA-882] Adopt git-crypt in this repo [AINFRA-1533] Adopt git-crypt in this repo Nov 15, 2025
@AliSoftware AliSoftware added this to the 23.8 milestone Nov 15, 2025
Since that command switched branches, we don't want it to fail or to encounter a case of modified files if the `.gitattributes` changed between the 2 branches and some git-crypt'ed files end up being marked as modified during the switch because of it.

I an hoping that we shouldn't really require access to any secret when computing manifest diff (even if that involves calling a `./gradlew process{variant}Manifest` task)… let's test
Comment on lines -17 to -19
echo "--- :closed_lock_with_key: Installing Secrets"
bundle exec fastlane run configure_apply

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having the repo git-crypt-unlocked during the branch dance that is done internally by comment_with_manifest_diff caused Your local changes to the following files would be overwritten by checkoutissues, especially if the git-crypt'd files listed in .gitattributes on the HEAD branch are not the same as the ones in the BASE branch1

Since we don't need any secret in practice to generate the manifest and call process{variant}Manifest, the solution is simple: just don't bother unlocking the repo's secrets for that task.


A better long-term solution to make comment_with_manifest_diff more resilient to situations like this would be to make it use git worktree instead of switching branches in-place:

  1. Generate base manifest: git worktree add $TMP_DIR_FOR_BASE $BASE_BRANCH && cd $TMP_DIR_FOR_BASE then run ./gradlew process{variant}Manifest there
  2. Generate head manifest: cd $CHECKOUT_DIR && rm $TMP_DIR_FOR_BASE && git worktree prune then run ./gradlew process{variant}Manifest there

That way each checkout is done in independent folders, eliminating the risk of conflicts during the branch dance.

Footnotes

  1. like will be the case during that transition to git-crypt, or when we'll add a new secret file, especially if that secret file previously existed unencrypted in the BASE branch as an example file for external contributors I think?

Comment on lines -6 to +7
export CI_TOOLKIT="automattic/a8c-ci-toolkit#5.4.0"
# "git-crypt-unlock" branch / https://github.com/Automattic/a8c-ci-toolkit-buildkite-plugin/pull/195
export CI_TOOLKIT="automattic/a8c-ci-toolkit#0a3f10921096cee57c18ac5667fc64c1aaad4a7d"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎗️ TODO: Revert back to pointing to a tag version once Automattic/a8c-ci-toolkit-buildkite-plugin#195 is merged and we have an official new version of the ci-toolkit

@AliSoftware AliSoftware added the status: do not merge Dependent on another PR, ready for review but not ready for merge. label Nov 17, 2025
@dangermattic
Copy link
Collaborator

1 Error
🚫 This PR is tagged with status: do not merge label(s).

Generated by 🚫 Danger

Copy link
Contributor

@wzieba wzieba left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ The real migration won't require devs to clone the repo from scratch; this is just for the testing steps of this PR

Hm, I don't know why exactly, but ~/woocommerce-android/.configure-files/firebase.secrets.json is not respected in .gitignore on this branch.

So, as a result, I could by mistake include the firebase.secrets.json in my git commit. To reproduce:

  • gco trunk
  • bundle exec fastlane run configure_apply
  • gco AINFRA-882-adopt-git-crypt
  • git status -u

Comment on lines +500 to 502
if (!googleServicesFile.exists() || isFileEncrypted(googleServicesFile)) {
tasks.copyGoogleServicesExampleFile.copy()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If google-services.json is encrypted, we'll copy the example file. Then why do we require to

  1. cp WooCommerce/google-services.json-example WooCommerce/google-services.json (to replace that encrypted file with placeholder content)

in the docs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I updated the docs before first, then later realized I had to update the .gradle file to make CI work… and didn't get back to review the docs again after doing the .gradle change 😅

Good point then, we should indeed remove that extra step from the docs.


If you are a developer working at Automattic, ensure you followed those instructions once after cloning the repo:
1. Make sure you have `git-crypt` installed (`brew install git-crypt`)
1. Search for "WooCommerce Android git-crypt encryption key" in our Secret Store, and copy the Base64 value in your clipboard
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I wonder, is it okay to provide a direct link to Secret Store? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I hesistated on this too. It's probably OK I guess because it's just a link that won't be accessible by anyone outside Automattic, and those links just contain ?id=<number> so it doesn't really reveal anything in the link URL either…

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I also had second thoughts before suggesting this, but actually our security doesn't rely on obscurity of a url. I think it's fine to share the link here, MC requires multpile security measures anyway to get anything from it.

@AliSoftware
Copy link
Contributor Author

ℹ️ The real migration won't require devs to clone the repo from scratch; this is just for the testing steps of this PR

Hm, I don't know why exactly, but ~/woocommerce-android/.configure-files/firebase.secrets.json is not respected in .gitignore on this branch.

So, as a result, I could by mistake include the firebase.secrets.json in my git commit. To reproduce:

  • gco trunk
  • bundle exec fastlane run configure_apply
  • gco AINFRA-882-adopt-git-crypt
  • git status -u

This is a very good and important point, thanks for raising it!

This PR indeed removed those files from .gitignore to clean things up, but in retrospect, we should keep them around especially to avoid legacy files (since deleted in this branch, but that could have been leftovers from switching to old branches) from being accidentally committed indeed 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category: tooling Anything that involves building & maintaining the project, including scripts, `Fastfile`, etc. status: do not merge Dependent on another PR, ready for review but not ready for merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants