nix: add config defaults and temp keystore generation

Changes:
* Create `nix/config.nix` with `config` defaults
* Add `nix/tools/gradlePropParser.nix` for reading `gradle.properties`
* Add `nix/mobile/android/keystore.nix` for generating a keystore
* Load keystore generation in `nix/mobile/android/default.nix`
* Use generated keystore if it's not provided via `config`
* Add `-deststoretype pkcs12` in `scripts/generate-keystore.sh`
* Add `nix/lib/assertEnvVarSet.nix` for checking if env var is set

Signed-off-by: Jakub Sokołowski <jakub@status.im>
This commit is contained in:
Jakub Sokołowski 2020-06-03 21:47:01 +02:00
parent b39d26ed4c
commit f2c96dcd3b
No known key found for this signature in database
GPG Key ID: 4EF064D0E6D63020
12 changed files with 133 additions and 22 deletions

View File

@ -31,6 +31,7 @@ config = {
}; };
}; };
``` ```
You can see the defaults in [`nix/config.nix`](./config.nix).
## Shell ## Shell

22
nix/config.nix Normal file
View File

@ -0,0 +1,22 @@
# Status defaults for config
{
status-im = {
build-type = "pr"; # Build type (influences which .env file gets used for feature flags)
build-number = 9999; # Used for versionCode and CFBundleVersion in Android and iOS respectively
android = {
gradle-opts = null; # Gradle options passed for Android builds
keystore-path = null; # Path to keystore for signing the APK
abi-split = false; # If APKs should be split based on architectures
abi-include = "armeabi-v7a;arm64-v8a;x86"; # Android architectures to build for
};
nimbus = { src-override = null; };
status-go = { src-override = null; };
};
# Android SDK requires an accepted license
android_sdk.accept_license = true;
# Android Env still needs old OpenSSL
permittedInsecurePackages = [ "openssl-1.0.2u" ];
}

View File

@ -0,0 +1,7 @@
# Helper for verifying an environment variable is set
name: ''
if [[ -z ''$${name} ]]; then
echo 'Not env var set: ${name}' >&2
exit 1
fi
''

View File

@ -4,4 +4,5 @@
getConfig = import ./getConfig.nix { inherit lib config; }; getConfig = import ./getConfig.nix { inherit lib config; };
mkFilter = import ./mkFilter.nix { inherit lib; }; mkFilter = import ./mkFilter.nix { inherit lib; };
mergeSh = import ./mergeSh.nix { inherit lib; }; mergeSh = import ./mergeSh.nix { inherit lib; };
assertEnvVarSet = import ./assertEnvVarSet.nix;
} }

View File

@ -2,6 +2,9 @@
, status-go, androidPkgs, androidShell }: , status-go, androidPkgs, androidShell }:
let let
# For generating a temporary keystore for local development
keystore = callPackage ./keystore.nix { };
# Import a jsbundle compiled out of clojure codebase # Import a jsbundle compiled out of clojure codebase
jsbundle = callPackage ./jsbundle { }; jsbundle = callPackage ./jsbundle { };
@ -10,12 +13,12 @@ let
# TARGETS # TARGETS
release = callPackage ./release.nix { release = callPackage ./release.nix {
inherit jsbundle status-go watchmanFactory; inherit keystore jsbundle status-go watchmanFactory;
}; };
in { in {
# TARGETS # TARGETS
inherit release jsbundle; inherit keystore release jsbundle;
shell = mkShell { shell = mkShell {
buildInputs = with pkgs; [ buildInputs = with pkgs; [

View File

@ -22,9 +22,9 @@ stdenv.mkDerivation {
ignoreVCS = false; ignoreVCS = false;
include = [ include = [
"VERSION" "BUILD_NUMBER" "scripts/version/.*" "VERSION" "BUILD_NUMBER" "scripts/version/.*"
"src/.*" "shadow-cljs.edn" "index.js"
# I want to avoid including the whole .git directory # I want to avoid including the whole .git directory
".git/HEAD" ".git/objects" ".git/refs/heads/.*" ".git/HEAD" ".git/objects" ".git/refs/heads/.*"
"src/.*" "shadow-cljs.edn" "index.js"
# shadow-cljs expects these for deps resolution # shadow-cljs expects these for deps resolution
"mobile/js_files/package.json" "mobile/js_files/yarn.lock" "mobile/js_files/package.json" "mobile/js_files/yarn.lock"
# build stat's images to check if they exist # build stat's images to check if they exist

View File

@ -0,0 +1,44 @@
#
# Generates an ad-hoc and temporary keystore for signing debug/pr builds.
#
# WARNING: Do NOT use this to make a keystore that needs to be secret!
# Using a derivation will store the inputs in a .drv file.
#
{ stdenv, lib, pkgs }:
let
inherit (lib) getAttr;
gradleProps = pkgs.gradlePropParser ../../../android/gradle.properties;
# Loading defaults from gradle.properties which should be safe.
KEYSTORE_ALIAS = getAttr "KEYSTORE_ALIAS" gradleProps;
KEYSTORE_PASSWORD = getAttr "KEYSTORE_PASSWORD" gradleProps;
KEYSTORE_KEY_PASSWORD = getAttr "KEYSTORE_KEY_PASSWORD" gradleProps;
in stdenv.mkDerivation {
name = "status-react-android-keystore";
buildInputs = [ pkgs.openjdk8 ];
phases = [ "generatePhase" ];
generatePhase = ''
keytool -genkey -v \
-keyalg RSA \
-keysize 2048 \
-validity 10000 \
-deststoretype pkcs12 \
-dname "CN=, OU=, O=, L=, S=, C=" \
-keystore "$out" \
-alias "${KEYSTORE_ALIAS}" \
-storepass "${KEYSTORE_PASSWORD}" \
-keypass "${KEYSTORE_KEY_PASSWORD}" \
>&2
'';
shellHook = ''
export KEYSTORE_ALIAS="${KEYSTORE_ALIAS}"
export KEYSTORE_PASSWORD="${KEYSTORE_PASSWORD}"
export KEYSTORE_KEY_PASSWORD="${KEYSTORE_KEY_PASSWORD}"
'';
}

View File

@ -1,22 +1,30 @@
{ stdenv, pkgs, deps, lib, config, callPackage, { stdenv, pkgs, deps, lib, config, callPackage,
watchmanFactory, androidPkgs, patchMavenSources, watchmanFactory, androidPkgs, patchMavenSources,
jsbundle, status-go }: keystore, jsbundle, status-go }:
{ {
buildEnv ? "prod", # Value for BUILD_ENV checked by Clojure code at compile time # Value for BUILD_ENV checked by Clojure code at compile time
secretsFile ? "", # Path to the file containing secret environment variables buildEnv ? "prod",
watchmanSockPath ? "", # Path to the socket file exposed by an external watchman instance (workaround needed for building Android on macOS) # Path to the file containing secret environment variables
secretsFile ? "",
# Path to the socket file exposed by an external watchman instance
# (workaround needed for building Android on macOS)
watchmanSockPath ? "",
}: }:
assert (lib.stringLength watchmanSockPath) > 0 -> stdenv.isDarwin; assert (lib.stringLength watchmanSockPath) > 0 -> stdenv.isDarwin;
let let
inherit (lib) toLower optionalString stringLength getConfig makeLibraryPath; inherit (lib)
toLower optionalString stringLength
getConfig makeLibraryPath assertEnvVarSet;
buildType = getConfig "build-type" "prod"; buildType = getConfig "build-type" "prod";
buildNumber = getConfig "build-number" 9999; buildNumber = getConfig "build-number" 9999;
gradleOpts = getConfig "android.gradle-opts" null; gradleOpts = getConfig "android.gradle-opts" null;
keystorePath = getConfig "android.keystore-path" null; # Keystore can be provided via config and extra-sandbox-paths.
# If it is not we use an ad-hoc one generated with default password.
keystorePath = getConfig "android.keystore-path" keystore;
baseName = "release-android"; baseName = "release-android";
name = "status-react-build-${baseName}"; name = "status-react-build-${baseName}";
@ -73,7 +81,8 @@ in stdenv.mkDerivation rec {
STATUS_GO_ANDROID_LIBDIR = "${status-go}"; STATUS_GO_ANDROID_LIBDIR = "${status-go}";
phases = [ phases = [
"unpackPhase" "secretPhase" "buildPhase" "checkPhase" "installPhase" "unpackPhase" "secretsPhase" "secretsCheckPhase"
"buildPhase" "checkPhase" "installPhase"
]; ];
unpackPhase = '' unpackPhase = ''
@ -81,7 +90,9 @@ in stdenv.mkDerivation rec {
chmod u+w -R ./ chmod u+w -R ./
runHook postUnpack runHook postUnpack
''; '';
postUnpack = assert lib.assertMsg (keystorePath != null) "keystore-file has to be set!"; '' postUnpack =
assert lib.assertMsg (keystorePath != null) "keystore-file has to be set!";
''
# Keep the same keystore path for determinism # Keep the same keystore path for determinism
export KEYSTORE_PATH="$PWD/status-im.keystore" export KEYSTORE_PATH="$PWD/status-im.keystore"
cp -a --no-preserve=ownership "${keystorePath}" "$KEYSTORE_PATH" cp -a --no-preserve=ownership "${keystorePath}" "$KEYSTORE_PATH"
@ -107,8 +118,14 @@ in stdenv.mkDerivation rec {
# Patch build.gradle to use local repo # Patch build.gradle to use local repo
${patchMavenSources} ./android/build.gradle ${patchMavenSources} ./android/build.gradle
''; '';
secretPhase = optionalString (secretsFile != "") '' # if secretsFile is not set we use generate keystore
secretsPhase = if (secretsFile != "") then ''
source "${secretsFile}" source "${secretsFile}"
'' else keystore.shellHook;
secretsCheckPhase = ''
${assertEnvVarSet "KEYSTORE_ALIAS"}
${assertEnvVarSet "KEYSTORE_PASSWORD"}
${assertEnvVarSet "KEYSTORE_KEY_PASSWORD"}
''; '';
buildPhase = let buildPhase = let
adhocEnvVars = optionalString stdenv.isLinux adhocEnvVars = optionalString stdenv.isLinux

View File

@ -28,8 +28,8 @@ in {
react-native = callPackage ./deps/react-native { }; react-native = callPackage ./deps/react-native { };
}; };
# For patching Node.js modules with Gradle repo path # For parsing gradle.properties into an attrset
patchNodeModules = callPackage ./tools/patchNodeModules.nix { }; gradlePropParser = callPackage ./tools/gradlePropParser.nix { };
# Package version adjustments # Package version adjustments
xcodeWrapper = super.xcodeenv.composeXcodeWrapper { version = "11.4.1"; }; xcodeWrapper = super.xcodeenv.composeXcodeWrapper { version = "11.4.1"; };

View File

@ -19,16 +19,11 @@ let
# nix-prefetch-url --unpack https://github.com/${ORG}/nixpkgs/archive/${REV}.tar.gz # nix-prefetch-url --unpack https://github.com/${ORG}/nixpkgs/archive/${REV}.tar.gz
}; };
# Status specific configuration defaults
defaultConfig = import ./config.nix;
# Override some packages and utilities # Override some packages and utilities
pkgsOverlay = import ./overlay.nix; pkgsOverlay = import ./overlay.nix;
# we want these packages easily available via callPackage
defaultConfig = {
android_sdk.accept_license = true;
# Android Env still needs old OpenSSL
permittedInsecurePackages = [ "openssl-1.0.2u" ];
};
in in
# import nixpkgs with a config override # import nixpkgs with a config override
(import nixpkgsSrc) { (import nixpkgsSrc) {

View File

@ -0,0 +1,20 @@
# Parser for android/gradle.properties file.
# Returns an attrset with keys and values from it.
{ lib }:
gradlePropsFile:
let
inherit (lib) head last filter listToAttrs splitString nameValuePair hasPrefix readFile;
# Read lines
lines = splitString "\n" (readFile gradlePropsFile);
isKeyValueLine = line: line != "" && !hasPrefix "#" line;
cleanup = lines: filter isKeyValueLine lines;
extractKeyValues = line:
let flag = splitString "=" line;
in nameValuePair (head flag) (last flag);
parseAttrs = lines: listToAttrs (map extractKeyValues lines);
in
parseAttrs (cleanup lines)

View File

@ -45,6 +45,7 @@ keytool -genkey -v \
-keyalg RSA \ -keyalg RSA \
-keysize 2048 \ -keysize 2048 \
-validity 10000 \ -validity 10000 \
-deststoretype pkcs12 \
-dname "CN=, OU=, O=, L=, S=, C=" \ -dname "CN=, OU=, O=, L=, S=, C=" \
-keystore "${KEYSTORE_PATH}" \ -keystore "${KEYSTORE_PATH}" \
-alias "${KEYSTORE_ALIAS}" \ -alias "${KEYSTORE_ALIAS}" \