これは browser-flow における最も強いポータビリティの主張です。コンパイル済みのFlowSpec、その固定されたPack、そして任意で記録済みJournalをネットワーク分離環境へ持ち込み、接続性ゼロで結果を再現できます。Registryへの呼び出しも、モデルも、外向きリクエストもありません。同じRider、同じdigest、同じ答えです(Launcherとポータビリティ)。

エアギャップが特別な出来事ではない理由

このエンジンは注入されたcapabilityに対する純粋関数です(原則 T2/T4)。クラウドSDKをインポートせず、ambient globalを読まず、時計、RNG、ネットワーク、ファイルシステム、シークレットにはRunDepsを通じてのみ触れます(実行)。FlowSpecとそのPackはcontent-addressedなので、接続されたノートPCで検証済みのFlowは、境界内でもバイト単位で再現されます。FlowSpecとPackのdigestが同一だからです(原則 T3)。 したがって、境界を越えるものは、自己完結しdigestで検証された次の3つの成果物だけです。
成果物含むもの必須
FlowSpecコンパイル済みFlow(*.flow.json、例: sha256:7f3a…はい
Pack(s)Flowが参照する固定済みTool実装はい
Journalhermetic replay / 監査のための記録済みRun任意
このページ全体で使う実行例はdaily-price-watchです。ブラウザTool(search-price@1.2.0)が価格を読み取り、transformがその形を変え、条件付きのhttp.postがシークレットwebhookに通知します。
シークレットがこれらの成果物に含まれて移動することはありません。daily-price-watchのwebhook認証情報は、実行時に分離環境自身のSecrets providerによって新しく解決されます。記録されることも、バンドルされることもありません。シークレットを参照してください。

手順

1

接続された側で自己完結したPackをエクスポートする

Registryに到達できるマシンで、固定済みPackを単一のdigest検証済みバンドルとしてエクスポートします。正確なバージョンを固定してください。digestが契約です。
browserflow pack export @acme/pricing@2.3.0 --out pricing.pack
生成されるpricing.packは自己完結しています。daily-price-watch Flowが参照するTool実装(search-price@1.2.0を含む)を含み、digestで検証されます。FlowSpecがまだPackの横に置かれていない場合は、同じ方法でFlowSpecもエクスポートします。
2

境界を越えて移動する

境界が許可する任意の方法で成果物を運びます。USBメディア、内部ミラー、一方向のファイルドロップなどです。話すべきプロトコルはありません。これは通常のファイルです。FlowSpecと、監査グレードの再現をしたい場合はJournalも、同じ方法で移動します。
3

境界内でインストールして実行する

分離された側でバンドルをインストールし、Flowを実行します。インストール時には、何かを信頼する前にdigestが再検証されます。
browserflow install ./pricing.pack
browserflow run @acme/pricing#daily-price-watch --input query="wireless headphones"
CLI Launcherにインフラは不要です。SQLiteストア、ファイルシステム上の成果物、ブラウザTool用のローカルChromium、そして環境自身のシークレットプロバイダーだけで動きます(Launcher)。daily-price-watchが条件付きのhttp.postに到達すると、webhook認証情報は呼び出しの瞬間にそのローカルSecrets providerから供給されます。運び込んだ何かから供給されるわけではありません。
4

Journalで監査グレードの結果を再現する

外部には一切触れない決定論的な再現のために、記録済みJournalも運び込み、hermeticにリプレイします。デフォルトモードはいかなる種類の外部呼び出しも行わずシークレットも必要としません。記録済みのすべてのnetclockrandomfs read、browser effectはJournalから提供されます(実行)。
browserflow replay <run-id> --verify
--verifyは、すべての手順出力が記録済みdigestと一致することを表明します。そのため、エアギャップ環境での再現は、接続された側で記録されたものと同じRunであることを証明できます。

シークレットを境界の外に置いたままにできる理由

シークレットは式レイヤーを通過しません。静的に強制されるtaint ruleによって締め出されます。そのため、シークレット値が実体化する唯一の場所は、解決を行うToolの内側です。そこはeffectを記録するレイヤーでもあります。Recorderはどのバイトがシークレット由来かを把握し、それらをredactします。シークレットを含むヘッダー、クエリパラメーター、bodyフィールドは、値そのものではなく、安定したプレースホルダー({secret:<slot>})としてJournalに記録されます(実行)。
journaled http.post (redacted)
  POST https://hooks.internal/notify
  Authorization: {secret:webhook_token}
  body: { "price": 129.0, "query": "wireless headphones" }
hermetic replayでは、記録済みのレスポンスは、redact済みリクエストの形と冪等性キーを組み合わせてキー化されます。そのため、シークレットは必要なく、Journal内にも存在しません。effectが記録されていても境界の不変条件が保たれるため、Journalをエアギャップ越しに安全に移動できます。
hermeticなreplay / --verifyは、何にも触れないため、エアギャップに適したToolです。オプトインの--rerunモードは異なります。effectをライブで再実行するため、条件付きのhttp.postは実際に再度発火し、関連するシークレットを実行時に再解決する必要があります。境界内のライブシステムに対してFlowを再駆動する意図がある場合にのみ、--rerunを使ってください。

よくある質問

いいえ。Journalが必要なのはhermetic replay(記録済みの特定のRunを監査グレードで再現すること)だけです。境界内でFlowを新しく実行するには、FlowSpecと固定済みPackが必要です。ブラウザとネットワークのcapabilityはローカルで実行され、シークレットは環境自身のproviderから取得されます。
retryの扱いは変わりません。各手順呼び出しは安定した冪等性キー(hash(run_id, step_id, inputs_digest))を持ちます。このキーは意図的に試行回数を除外するため、webhookへのhttp.postはそれを渡すことができ(例: Idempotency-Keyヘッダーとして)、retryされたRunが二重に発火することはありません(実行)。
はい。再開はJournalからコンテキストを再構築します。完了済みの手順は記録済み出力を返し、記録済みeffectは記録済み結果を返すため、外部のものが再発火することはありません(原則 T7)。シークレットだけは例外です。再開時にライブで再解決され、Journalから読まれることはありません(実行)。

Registryを複製する

境界の内側にある内部RegistryへPackとFlowをミラーします。

テストとリプレイ

Journalをfixtureとして固定し、--verifyでToolアップグレードをゲートします。

シークレット

分離環境自身のproviderが実行時に認証情報を供給する仕組みです。