こんにちは、こちらはCircleCI Advent Calendar 2023の23日目、Perfumeはかしゆかの生誕祭をお祝いする記事になります。
悲しいことに1日遅れになってしまいました。よよよ。それでもゆかちゃん誕生日おめでとう🎉良い35歳を過ごしてください。
ということでSalesforceの開発をCircleCIで自動化していきます。
なぜ今更?
CircleCI + Salesforce の自動化記事は世に沢山あります。しかし残念ながら、どれもこれも古いsfdx
コマンドを使ったもので、やがてなくなっていくコマンドを使って自動化しています。
ここはやはり、Salesforceの中の人として、salesforce cli
を使った自動化を実現しなければならないと今回の記事を生成しました。が、結構大変でゆかちゃんの誕生日に間に合いませんでした。ホント残念です。
が、Salesforce CLIを使った自動化方法は完全にできあがりましたので、1日遅れで公開していきます。
事前準備
Salesforce CLIを使って自動化したバッチ処理を行う場合には、JWTを使った認証が必要となります。
まず、こちらの記事を元にして証明書の作成と、Salesforce組織側の設定を行っておく必要があります。
暗号化した証明書の準備
下地ができあがりましたら、今度は外部に公開してぶちまけてしまっても安全な証明書を準備して、CircleCIを設定していきます。
事前に準備したserver.key
が必要です。
パスフレーズを暗号化する
まず証明書を暗号化するために必要なパスフレーズを準備します。そのパスフレーズでしか復号化できないようにするためです。とは言え、パスフレーズをそのままどこかに記してしまったら不安全で仕方ありません。念には念を入れて、このパスフレーズをまず暗号化していきます。
<パスフレーズ>
には、好きなパスフレーズを指定してください。なんでも良いです。
実行するとkey
とiv
が出力されます。このパスフレーズを暗号化した情報源です。やったぜ。
> openssl enc -aes-256-cbc -k <パスフレーズ> -P -md sha1 -nosalt -iter 10000
key=7F045E41781E5E49A48AE86716375E4ED5FB9D4325F39CB3D2385C007755F945
iv =11650FF4873F3A391729991E53FD588C
この暗号化されたパスフレーズ情報を元にして、server.key
を暗号化します。
> openssl enc -nosalt -aes-256-cbc -in ./foo/server.key -out server.key.enc -base64 -K 7F045E41781E5E49A48AE86716375E4ED5FB9D4325F39CB3D2385C007755F945 -iv 11650FF4873F3A391729991E53FD588C
これで、先ほどの暗号化されたパスフレーズ情報を元に、証明書を暗号化した外部に公開されちゃっても安全な証明書ファイルができました。実際に利用するときは、この暗号化された証明書を復号化して利用します。このままでは利用できません。
Salesforce DXプロジェクトに、暗号化された証明書を配置する
今回はYUKAちゃん誕生日おめでとうFY23ソースコードサンプルをベースに進めていきます。
今回は、Salesforce DXプロジェクトのルートディレクトリに assets
というフォルダを準備して進めます。その配下に、先ほど準備した暗号化された証明書server.key.enc
を配置します。それ以外の証明書関係のファイルはプロジェクトディレクトリには配置しないでください。ヤバイです。情報漏洩です。
暗号化されたパスフレーズなどもファイルに残したりしないでください。なお、上記のkey
とiv
情報は私は使っていないので、これを使ってもなりすましは不可能です。フフフ。
と言うことで、ファイルを配置できたら、準備は完了です。あとはCircleCI側の設定です。
CircleCIを設定する
該当のGitHubリポジトリとCircleCIを連携してプロジェクトを準備してください。ここでは割愛します
環境変数を設定する
プロジェクトを準備したら、次の4項目の環境変数を作成してください。Project Settings
からEnvironment Variables
を辿ってください。
そこからAdd Environment Variable
で4つの環境変数を作成します。
- CONSUMER_KEY ... Salesforce組織の接続アプリケーションで作成された「コンシューマー鍵」を定義します
- DECRYPTION_IV ... 先ほど作成した暗号化されたパスフレーズの
iv
情報をここに記します - DECRYPTION_KEY ... 先ほど作成した暗号化されたパスフレーズの
key
情報をここに記します - USERNAME ... Salesforce組織へ接続するときのユーザー名(メールアドレス形式のアレ)を指定します
これらを環境変数として持つことで、外部に公開されているソースコードも安全に運用が可能というわけです。
config.yml を準備する
全体像はこちらです。ゆかちゃんの誕生日にあわせてyuka-birthday
というジョブとワークフローを設定しました。名前は好きにしてください。
特徴としては、Salesforceが提供するSalesforce CLIおよびnpmパッケージを含むDockerイメージを利用しています。これにより古いsfdx
コマンドを使わずに、常に最新のsalesforce cli
が利用できます。
参考:Docker イメージを使用した Salesforce CLI の実行 | Salesforce CLI 設定ガイド | Salesforce Developers
また、先ほど設定した「暗号化された証明書」を復号化してJWTの鍵として利用しています。
version: 2.1
jobs:
yuka-birthday:
docker:
- image: salesforce/cli:latest-full
steps:
- checkout
- run:
name: "Create a server.key"
command: |
openssl enc -nosalt -aes-256-cbc -d -in assets/server.key.enc -out assets/server.key -base64 -K $DECRYPTION_KEY -iv $DECRYPTION_IV
- run:
name: "Authenticate and create Scratch org to Salesforce DevHub"
command: |
sf force auth jwt grant -i $CONSUMER_KEY -f assets/server.key --username $USERNAME -d
sf org create scratch -f config/project-scratch-def.json -a circle_build_$CIRCLE_BUILD_NUM
sf project deploy start -o circle_build_$CIRCLE_BUILD_NUM
- run:
name: "Run LWC tests"
command: |
npm install
npm test
- run:
name: "Run Apex tests"
command: |
sf force apex test run --result-format human --code-coverage -o circle_build_$CIRCLE_BUILD_NUM
- run:
name: "Delete useless Scratch org"
command: |
sf org delete scratch -p -o circle_build_$CIRCLE_BUILD_NUM
workflows:
version: 2
yuka-birthday:
jobs:
- yuka-birthday
各所のポイントを説明します。
証明書の復号化
暗号化された証明書server.key.enc
とDECRYPTION_KEY
、DECRYPTION_IV
を利用して、証明書を復号化しています。複合に必要な情報を環境変数として定義していることで、ソースコード内に漏洩したら困るような情報の排除が可能となっています。やるじゃん。
openssl enc -nosalt -aes-256-cbc -d -in assets/server.key.enc -out assets/server.key -base64 -K $DECRYPTION_KEY -iv $DECRYPTION_IV
base64化した秘密鍵を環境変数に入れるという方法もとれるだろうと思いつつも、公式に従ってこの方法をとりました。興味がある方は次の記事を参考に頑張ってみてください。できたら教えてほしい。
[RS256] JWTでRSA秘密鍵を環境変数で処理したい [Javascript] #JavaScript - Qiita
JWT認証とスクラッチ組織作成とデプロイ
sf force auth jwt grant
コマンドでCONSUMER_KEY
と、復号化したserver.key
を使ってDevHub組織の認証を行っています。
sf org create scratch
コマンドでスクラッチ組織を作成します。ここで-a circle_build_$CIRCLE_BUILD_NUM
で別名を割り当てています。最後にスクラッチ組織を削除するために別名を割り当てています。
sf project deploy start
で該当のスクラッチ組織へデプロイしています。
sf force auth jwt grant -i $CONSUMER_KEY -f assets/server.key --username $USERNAME -d
sf org create scratch -f config/project-scratch-def.json -a circle_build_$CIRCLE_BUILD_NUM
sf project deploy start -o circle_build_$CIRCLE_BUILD_NUM
参考:CircleCI を DevHub に接続 | Salesforce DX 開発者ガイド | Salesforce Developers
Lightning Web Componentのテスト
Lightning Web Component(LWC)は、Jestを使ってテストをすることが推奨されています。Jest のインストールを参考にしてJestでテスト実行できる環境を設定しておく必要があります。
LWCのテストは、通常のJavaScriptのテストと同じです。npm install
で必要なパッケージをインストールしてnpm test
でテスト実行です。
npm install
npm test
参考:Lightning Web コンポーネントのテスト | Lightning Web Components 開発者ガイド | Salesforce Developers
参考: Jest のインストール | Lightning Web Components 開発者ガイド | Salesforce Developers
Apexのテスト
Salesforce Apexのテストも勿論実行可能です。
--result-format human
や--code-coverage
を付けていますが、成功したときは何も表示されないので付ける意味はあまり感じていません。実際のテスト結果の詳細は、実行結果内で示唆されるsf apex get test -i 707H3000000xVjq -o test-xxxxxxxxxxx@example.com
で確認が可能なので、これをうまく拾えたら良いんでしょうね。どうやったらいいんだろう。
sf force apex test run --result-format human --code-coverage -o circle_build_$CIRCLE_BUILD_NUM
スクラッチ組織の削除
最後にテストを実行したスクラッチ組織を削除します。作成可能な下図などに上限がありますので、一般的には削除運用が望ましいです。
sf org delete scratch -p -o circle_build_$CIRCLE_BUILD_NUM
スクラッチ組織を使い回すという考え方もあるでしょう。使い回しても良いかどうかは開発する内容にもよりますので一概には言えませんが、考慮しても良いかもしれません。
参考:sfdx-circleci/.circleci/config.yml at master · forcedotcom/sfdx-circleci
CircleCIで実行してみる。
YUKAちゃん誕生日おめでとうFY23ソースコードサンプルを元にCircleCIでテストを実行すると、次のような結果となります。ご参考に。
今年もお世話になりました🙏