Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

エフェクトのロック

💡 お知らせ: このドキュメントはAIによって翻訳されています。表現に違和感がある場合は、原文(英語)を参照するか、翻訳にご協力ください。

注意: エフェクトのロック(Effect locking)は実験的な機能です。

plain または paranoid の security context でビルドされた依存関係は、依存関係の信頼で説明したとおり、その型とエフェクトのシグネチャが示すことしか行えません。しかし、シグネチャは固定されたものではありません。パッケージの新しいバージョンが、私たちが呼び出している関数にエフェクトを追加するかもしれません。そのような変更を検出するには、アップグレードのたびに、すべての依存関係のすべての公開シグネチャをもう一度読み直す必要があります。

エフェクトのロックは、これを私たちの代わりに行ってくれます。eff-lock コマンドは、プロジェクトが宣言しているすべての依存関係における、すべての公開関数の型とエフェクトのシグネチャを effects.lock ファイルに記録し、eff-check コマンドは、それらのうちどれが変更されたかを教えてくれます。

シグネチャのロック

次のように依存関係を持つプロジェクトの場合:

[dependencies]
"github:flix/museum-giftshop" = { version = "2.0.2", mount = "giftshop" }
"github:flix/museum-clerk"    = { version = "2.1.2", mount = "clerk" }

eff-lock コマンドはプロジェクトを型検査し、次のように報告します:

Locked 3 signatures of 2 packages.

このコマンドは、flix.toml の隣に effects.lock ファイルを書き出します:

[lock]
version = 1

[packages."github:flix/museum-clerk".defs]
"Clerk.welcomeVisitor" = "sha256:527d67f451945e784feca592a8e17b91f2a5152039171ce326efbdd200a01015"
"Clerk.work" = "sha256:527d67f451945e784feca592a8e17b91f2a5152039171ce326efbdd200a01015"

[packages."github:flix/museum-giftshop".defs]
"Giftshop.buyGift" = "sha256:527d67f451945e784feca592a8e17b91f2a5152039171ce326efbdd200a01015"

ロックファイルには、パッケージごとに1つのセクションがあり、その中には、パッケージが宣言している公開関数ごとに、そのパッケージ内での名前と、その関数の型・エフェクトのシグネチャのハッシュが記された行が並びます。トレイトが宣言するシグネチャは、専用の sigs テーブルに記録されます。 ここに登場する3つの関数はすべて Unit -> Unit \ IO というシグネチャを持つため、すべて同じハッシュになっています。

このロックが対象とするのは、マニフェストが宣言している依存関係であり、それらがさらに依存しているパッケージは対象外です。宣言していないパッケージは、呼び出すこともできないパッケージだからです。

ヒント: effects.lock ファイルは、packages.lock と同様にバージョン管理にコミットすべきです。

シグネチャの確認

eff-check コマンドはプロジェクトを型検査し、ロックされているすべての関数のシグネチャを、ロックファイル内のハッシュと比較します。何も変わっていない場合は、次のように報告します:

Checked 3 signatures of 2 packages. Nothing has changed.

私たちがロックした時点の flix/museum-giftshop のリリースでは buyGift が純粋関数として宣言されていたが、アップグレードした先のリリースでは IO エフェクトを伴って宣言されているとしましょう。この場合、eff-check コマンドは次のように報告します:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@  WARNING! YOU MAY BE SUBJECT TO A SUPPLY CHAIN ATTACK!  @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
            ~~ Signatures have changed! ~~

These declarations are not the ones that were locked. A dependency may now
be able to do things it could not do when you locked it.

  github:flix/museum-giftshop:
    Giftshop.buyGift
      def buyGift(): Unit \ IO

Do not build or run this project until you know why. Find out who published
the version you are building, and what changed in it.

Record the new signatures with flix eff-lock only once you are certain the
change is one the author made, and one you want.

シグネチャの変更は、必ずしも攻撃を意味するわけではありません。作者が意図的にその変更をリリースし、私たちもそれを望んでいる場合もあります。しかし、それが気づかれずに通り過ぎることがあってはなりません。シグネチャがなぜ変わったのかを把握し、その変更を受け入れたなら、もう一度 eff-lock を実行して新しいシグネチャを記録します。

ヒント: eff-check コマンドは、シグネチャが変更されている場合は終了コード 1 で、そうでない場合は 0 で終了するため、CI ビルドを失敗させるために使えます。

パッケージを1つずつロックする

どちらのコマンドも、パッケージを指定できます:

eff-lock flix/museum-giftshop

このコマンドは次のように報告します:

Locked 1 signature of 'github:flix/museum-giftshop'.

そして、ロックファイル内の flix/museum-giftshop のセクションだけを置き換え、他のすべてのセクションはそのままにします。同様に、eff-check flix/museum-giftshop はそのパッケージだけを確認します。これにより、あるパッケージの変更は受け入れて記録しつつ、別のパッケージの変更はまだレビュー中のまま、という状態にできます。

2つのロックファイル

プロジェクトには2つのロックファイルがあり、それぞれ異なるものから守ってくれます。

packages.lock ファイルは、プロジェクトが解決した各バージョンのファイルのダイジェストを記録するため、一度見たバージョンは常に同じバイト列であることが保証されます。アップグレードは新しいバージョンを解決してそれを記録します。それがアップグレードの役目だからです。effects.lock ファイルは、依存関係が何をし得るかを記録するものであり、eff-lock だけがこれを書き込むため、アップグレードを経ても生き残ります。前者は、私たちがダウンロードしたものとはもはや異なるファイルを持つバージョンを検出します。後者は、私たちが受け入れたものより多くのことを行うバージョンを検出します。

ロックと security context

エフェクトのロックは、security context が与える保証に依存しています。シグネチャが関数の行い得ることを表すのは、そのパッケージが plain または paranoid context でビルドされている場合に限られます。unrestricted context でビルドされたパッケージも他と同様にロックされますが、そのシグネチャは、そのパッケージが何を行い得るかについて何も教えてくれないため、ロックが変化していないからといって安心はできません。

ロックが最も有益な情報をもたらすのは、エフェクトを必要とするライブラリの書き方で推奨しているように、ライブラリが自身のエフェクトを宣言している場合です。IO ではなく、使用しているエフェクトを名指しするシグネチャは、行っていることが変化したときにシグネチャ自体も変化します。