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

CP-8108: Use AWS Secrets Manager to store envs #1194

Merged
merged 7 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions .github/workflows/bitrise-envs-sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Bitrise Envs Sync

on:
workflow_dispatch:

jobs:
upload-envs-to-bitrise:
name: Upload envs to Bitrise
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read

steps:
- name: Check out repo
uses: actions/checkout@v3

- name: Configure AWS credentials
uses: aws-actions/[email protected]
with:
aws-region: us-east-2
role-to-assume: arn:aws:iam::975050371175:role/github-sa-role
role-session-name: githubsa

- name: Get envs from AWS
uses: aws-actions/aws-secretsmanager-get-secrets@v1
with:
secret-ids: |
ENV_DEV, core/dev/mobile/.env.development
ENV_DEV_E2E, core/dev/mobile/.env.development.e2e
ENV_PROD, core/dev/mobile/.env.production
ENV_PROD_E2E, core/dev/mobile/.env.production.e2e

- name: Write envs to files
working-directory: packages/core-mobile/scripts/github
run: |
../common/writeEnvsToFile.sh "$ENV_DEV" ".env.development"
../common/writeEnvsToFile.sh "$ENV_DEV_E2E" ".env.development.e2e"
../common/writeEnvsToFile.sh "$ENV_PROD" ".env.production"
../common/writeEnvsToFile.sh "$ENV_PROD_E2E" ".env.production.e2e"

- name: Upload envs to Bitrise
working-directory: packages/core-mobile/scripts/github
run: |
./uploadEnvsToBitrise.sh ${{ secrets.BITRISE_ACCESS_TOKEN }}
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ Ava Labs Mobile

This repository is a monorepo that we manage using [Yarn workspaces](https://yarnpkg.com/features/workspaces).

| Package | Description |
| :--- | :--- |
| [@avalabs/core-mobile](https://github.com/ava-labs/avalanche-wallet-apps/tree/develop/packages/core-mobile) | Core Mobile app |
| [@avalabs/k2-mobile](https://github.com/ava-labs/avalanche-wallet-apps/tree/develop/packages/k2-mobile) | Mobile Design System (under 🚧👷‍♂️🚧) |
| [eslint-plugin-avalabs-mobile](https://github.com/ava-labs/avalanche-wallet-apps/tree/develop/packages/eslint-mobile) | Shared Eslint plugin |
| [@avalabs/tsconfig-mobile](https://github.com/ava-labs/avalanche-wallet-apps/tree/develop/packages/tsconfig-mobile) | Shared Typescript config |
| Package | Description |
| :-------------------------------------------------------------------------------------------------------------------- | :---------------------------------- |
| [@avalabs/core-mobile](https://github.com/ava-labs/avalanche-wallet-apps/tree/develop/packages/core-mobile) | Core Mobile app |
| [@avalabs/k2-mobile](https://github.com/ava-labs/avalanche-wallet-apps/tree/develop/packages/k2-mobile) | Mobile Design System (under 🚧👷‍♂️🚧) |
| [eslint-plugin-avalabs-mobile](https://github.com/ava-labs/avalanche-wallet-apps/tree/develop/packages/eslint-mobile) | Shared Eslint plugin |
| [@avalabs/tsconfig-mobile](https://github.com/ava-labs/avalanche-wallet-apps/tree/develop/packages/tsconfig-mobile) | Shared Typescript config |

## ⚡ Quickstart

Expand All @@ -25,12 +25,18 @@ This repository is a monorepo that we manage using [Yarn workspaces](https://yar
```
brew install yarn
```
4. Install required dependencies for all packages
3. Set up `$NPM_TOKEN`

To install all dependencies, you will need to generate an `NPM token` from your NPM.js account and add that as an environment variable named `NPM_TOKEN` on your machine (for example, `.zshenv` if using zsh or `.bash_profile` if not).

4. Install dependencies for all packages

In the root directory, run:

```
yarn install && yarn setup
```

5. Follow the specific instructions in each package to build/run it

## 📖 Tips
Expand All @@ -47,4 +53,4 @@ This repository is a monorepo that we manage using [Yarn workspaces](https://yar
2. To quickly remove all the node_modules folders, you can run
```
./scripts/remove-node-modules.sh
```
```
104 changes: 38 additions & 66 deletions packages/core-mobile/README.md
Original file line number Diff line number Diff line change
@@ -1,108 +1,80 @@
# Core X Mobile
# Core Mobile

## Setup dev environment

Follow [these](https://reactnative.dev/docs/environment-setup) steps to setup dev environment; make sure to select
**React Native CLI Quickstart** tab and select appropriate Development & Target OS.
1. Set up [React Native environment](https://reactnative.dev/docs/environment-setup)

## Getting Started
2. Set up [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)

### 1. Clone the repo.
3. Run `yarn envs` to fetch and create all the necessary .env files

```zsh
git clone [email protected]:ava-labs/avalanche-wallet-apps.git
cd avalanche-wallet-apps/
```
4. Run `yarn install && yarn setup` if you haven't

**NOTE:** If you're using IDE to initiate this action you will need `github access token` registered with Jumpcloud SSO.
To do that, go to https://github.com/settings/tokens, generate access token and authorize it with Jumpcloud. Finally, import that token to your favorite IDE.
## Build the app

### 2. Setup environment.
1. To access all project's dependencies you will need to generate an `NPM token` from your npmjs account and add that as an environment variable named `NPM_TOKEN` on your mac (for example, `.zshenv` if using zsh or `.bash_profile` if not).
2. Create a `.env.development` file in the root of the project. The contents of the .env file is in 1Password. Ask permission to access it (the vault name is Mobile team). Once access is given copy and paste the contents from the 1Password Secure Note into your local .env file.
3. Download `keystore.properties` from 1Password and place it in the `android` folder
#### For iOS

**IMPORTANT:** the `.env` files are never to be committed to the repo, and are already added to .gitignore.
1. Install iOS dependencies:

```zsh
yarn podInstall
```

### 3. Install the dependencies.
2. Launch iOS simulator and build

```zsh
yarn setup
```
```zsh
yarn ios
```

### 4. Launch the app

#### For iOS

First install iOS dependencies:
```zsh
yarn podInstall
```
#### For Android

Now you can run the app
Launch android emulator and build

```zsh
# launch iOS simulator and start the app
yarn ios
yarn android
```

**Note:** if you run into `"Your session has expired. Please log in."` issue, go to `XCode > Preferences > Accounts` and sign in with your account.
## Common commands

#### For Android
```zsh
# launch android emulator and start the app
yarn android
```
# run unit tests
yarn test

## Tests
# run typescript check
yarn tsc

You can run the test suite with
# run lint check
yarn lint

```zsh
yarn test
# fetch envs from aws and populate .env files
# do this when you first set up the project and whenever you need to sync the .env files
yarn envs
```

## Custom fonts

To add custom font, add it to src/assets folder and then run:
To add custom fonts, add it to `app/assets/fonts` folder and then run:

```zsh
yarn link
```

## Env Workflows

[Documentation](https://ava-labs.atlassian.net/wiki/spaces/EN/pages/2500493313/Env+Workflows)

## Navigation System

https://whimsical.com/mobile-navigation-system-4WaXLt2DgAutCmbfFF6wpS
[Documentation](https://whimsical.com/mobile-navigation-system-4WaXLt2DgAutCmbfFF6wpS)

## Wallet Connect Flows

https://whimsical.com/wallet-connect-flows-9QqTTDNdktBePx6vDR9oeX
[Documentation](https://whimsical.com/wallet-connect-flows-9QqTTDNdktBePx6vDR9oeX)

## App Signing

[Documentation](docs/app_signing.md)

## Release Process
[Documentation](docs/release_process.md)

## Known issues
### Apple M1 chips

Exclude arch `arm64`

Prefix all comands with `arch -x86_64`

Examples:
```zsh
arch -x86_64 pod install
```

```zsh
arch -x86_64 yarn ios
```

### `pod install` fails on Apple M1 chips

Install ffi
```zsh
sudo arch -x86_64 gem install ffi
```
[Documentation](docs/release_process.md)
1 change: 1 addition & 0 deletions packages/core-mobile/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"private": true,
"scripts": {
"setup": "yarn allow-scripts",
"envs": "./scripts/getEnvs.sh",
"android": "ENVFILE=.env.development react-native run-android --variant=internalDebug",
"podInstall": "bundle _2.1.4_ install && cd ios && bundle exec pod install",
"ios": "ENVFILE=.env.development react-native run-ios",
Expand Down
32 changes: 32 additions & 0 deletions packages/core-mobile/scripts/common/writeEnvsToFile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/bash
set -e

# Check if the correct number of parameters are provided
if [ "$#" -ne 2 ]; then
echo "Usage: $0 <env_var> <output_filename>"
exit 1
fi

# Retrieve the env value and assign it to the data variable
data=$1

output_file=$2

# Check if the secret value is empty
if [ -z "$data" ]; then
echo "Error: Failed to retrieve secret value"
exit 1
fi

# Parse the string to extract key-value pairs
pairs=$(echo "$data" | sed 's/[{}"]//g' | tr ',' '\n' | sed 's/:/=/')

# Erase the content of the output file
> "$output_file"

# Write the key-value pairs to the output file
echo "$pairs" | while IFS= read -r line; do
echo "$line" | sed 's/\\//g' >> "$output_file"
done

echo "envs saved to $output_file"
54 changes: 54 additions & 0 deletions packages/core-mobile/scripts/getEnvs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/bash

PROFILE_NAME="sso"

# Retrieve secret by id from AWS Secrets Manager
getSecretFromAWS() {
local secret_id="$1"
sudo aws --profile $PROFILE_NAME secretsmanager get-secret-value --secret-id "$secret_id" | grep SecretString | sed 's/.*"SecretString": "\(.*\)".*/\1/'
}

# Check if a AWS profile exists
awsConfigurationExists() {
local profile_name="${1}"
local profile_status=$( (sudo aws configure --profile ${1} list) 2>&1)

if [[ $profile_status = *'could not be found'* ]]; then
return 1
else
return 0
fi
}

# Check if profile "default" exists. If not, ask to create one
if ! $(awsConfigurationExists $PROFILE_NAME); then
echo "Profile '$PROFILE_NAME' does not exist. Please create one first!"
sudo aws configure sso --profile $PROFILE_NAME
fi

# Check if the session is still valid. If not, ask to re-login
ACCOUNT=$(sudo aws --profile $PROFILE_NAME sts get-caller-identity --query "Account")

# Account is valid if account is a 12 digit account number plus surrounding double-quotes
if [ ${#ACCOUNT} -ne 14 ]; then
echo "logging in with profile '$PROFILE_NAME'"
sudo aws sso login --profile $PROFILE_NAME
fi

# Retrieve all envs from AWS
echo "retrieving envs from AWS Secrets Manager..."
ENV_DEV=$(getSecretFromAWS "core/dev/mobile/.env.development")
ENV_DEV_E2E=$(getSecretFromAWS "core/dev/mobile/.env.development.e2e")
ENV_PROD=$(getSecretFromAWS "core/dev/mobile/.env.production")
ENV_PROD_E2E=$(getSecretFromAWS "core/dev/mobile/.env.production.e2e")

# Write to .env files
./scripts/common/writeEnvsToFile.sh "$ENV_DEV" ".env.development"
./scripts/common/writeEnvsToFile.sh "$ENV_DEV_E2E" ".env.development.e2e"
./scripts/common/writeEnvsToFile.sh "$ENV_PROD" ".env.production"
./scripts/common/writeEnvsToFile.sh "$ENV_PROD_E2E" ".env.production.e2e"

# Use .env.development as the default
cp .env.development .env
echo ".env.development copied to .env"
echo "envs successfully retrieved and saved 🥳"
61 changes: 61 additions & 0 deletions packages/core-mobile/scripts/github/uploadEnvsToBitrise.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash
set -e

# Get the value of a key
function getJsonVal () {
python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))";
}

# Search for a value when key matches the provided condition
function searchJsonVal () {
python -c "
import json, sys

# Load JSON data from stdin
data = json.load(sys.stdin)['data']

# Filter data based on the provided condition
filtered_data = [x for x in data if x.get('$1') == '$2']

# Print the filtered data as JSON
sys.stdout.write(json.dumps(filtered_data))
"
}

# Check if the correct number of parameters are provided
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <bitrise_access_token>"
exit 1
fi

app_slug="7d7ca5af7066e290"
file_name="env-files.zip"
bitrise_file_name=ENV_FILES
access_token=$1
base_url="https://api.bitrise.io/v0.1/apps/$app_slug"

# get all generic profile files
# if the bitrise_file_name already exists, delete it
all_files=$(curl -X GET -H "Authorization: $access_token" "$base_url/generic-project-files")
existing_file_slug=$( echo $all_files | searchJsonVal "user_env_key" $bitrise_file_name | getJsonVal "[0]['slug']" | tr -d '"')
curl -X DELETE "$base_url/generic-project-files/$existing_file_slug" -H "Authorization: $access_token"

# compress all env files into a single zip file
zip $file_name .env.*

# upload the zip file to bitrise https://devcenter.bitrise.io/en/api/managing-files-in-generic-file-storage.html

# 1. create a temporary pre-signed upload URL
file_size=$(ls -l $file_name | awk '{print $5}')
response_1=$(curl -H "Authorization: $access_token" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"upload_file_name\": \"$file_name\", \"upload_file_size\": $file_size, \"user_env_key\": \"$bitrise_file_name\"}" -X POST "$base_url/generic-project-files")

# 2. upload the file to the pre-signed URL
upload_url=$( echo $response_1 | getJsonVal "['data']['upload_url']" | tr -d '"' )

curl -T $file_name $upload_url

# 3. confirm the file upload
file_slug=$( echo $response_1 | getJsonVal "['data']['slug']" | tr -d '"' )
curl -X POST -H "Authorization: $access_token" "$base_url/generic-project-files/$file_slug/uploaded"

echo "envs uploaded to bitrise successfully"
Loading