StdDSL::Shell 監査
署名および暗号化された loop main スクリプトとして配信される、典型的な DevOps およびシステム管理のワークロードに対する V0.2.1 の stddsl::Shell バンドルの評価。当初の監査では3つの優先度の高いギャップが特定されました。3つすべてが V0.2.1 で解消され、バンドルはデーモンのユースケースに対して現在は十分なものとなっています。スクリプトオーケストレーションの経路に関する後続のレビューでは、shell::arg/arg_count がスクリプト自身の引数ではなくホストプロセスの argv を報告していたこと、および shell::run が捕捉した標準エラー出力を破棄していたことが判明しました。両方とも V0.2.1 で修正されました。本ドキュメントは現在の状態、修正、および残存する制約を記録します。
現在の機能
バンドルは、vm.register_library(stddsl::Shell) を通じて登録される22個のネイティブ関数を提供します。
| ネイティブ | シグネチャ | 目的 |
|---|---|---|
shell::getenv | (name: Text) -> Option<Text> | 環境変数を読み取ります。Some(value) または None |
shell::has_env | (name: Text) -> bool | 環境変数が設定されているかどうかをテストします |
shell::run | (cmd: Text) -> (Word, Text) | sh -c を通じて cmd を実行します。(exit_code, stdout) を返します。捕捉された標準エラー出力は破棄されます。非ゼロの終了コードはエラーではありません |
shell::run_full | (cmd: Text) -> (Word, Text, Text) | sh -c を通じて cmd を実行します。(exit_code, stdout, stderr) を返します |
shell::run_checked | (cmd: Text) -> Text | sh -c を通じて cmd を実行します。stdout を返します。非ゼロの終了コードは NativeError として現れます |
shell::run_timeout | (cmd: Text, ms: Word) -> (Word, Text) | ウォールクロックの期限付きで cmd を実行します。タイムアウト時にはサブプロセスを終了させた後にトラップします |
shell::exit | (code: Word) -> () | 指定された終了コードでホストプロセスを終了します |
shell::sleep_ms | (ms: Word) -> () | サブプロセスを生成することなく、現在のスレッドを ms ミリ秒スリープさせます |
shell::now_unix_ms | () -> Word | 現在の Unix タイムスタンプをミリ秒単位で返します |
shell::read_file | (path: Text) -> Text | ファイルの内容を読み取ります。I/O 障害または非 UTF-8 でトラップします |
shell::write_file | (path: Text, content: Text) -> () | 指定した内容でファイルを置き換えます。入出力の失敗時にはトラップします。 |
shell::append_file | (path: Text, content: Text) -> () | ファイルに追記し、存在しない場合は作成します。入出力の失敗時にはトラップします。 |
shell::file_exists | (path: Text) -> bool | ファイルシステムのエントリが存在するかどうかを判定します。シンボリックリンクをたどります。 |
shell::write_err | (text: Text) -> () | 末尾に改行を付けずに標準エラー出力へ書き込みます。 |
shell::writeln_err | (text: Text) -> () | 末尾に改行を付けて標準エラー出力へ書き込みます。 |
shell::arg_count | () -> Word | スクリプト引数ベクタ(スクリプトパスに加えて位置引数)のエントリ数です。何も設定されていない場合はホストプロセスの argv にフォールバックします。 |
shell::arg | (index: Word) -> Option<Text> | index の位置にあるスクリプト引数です。インデックス 0 はスクリプトパス、1 以降は位置引数です。範囲外または負の場合は None になります。 |
shell::setenv | (name: Text, value: Text) -> () | shell::run を通じて生成されるサブプロセス向けに環境変数を設定します。 |
shell::pid | () -> Word | 現在のプロセス識別子で、pidfile の作成に用います。 |
shell::hostname | () -> Text | オペレーティングシステムが報告するホスト名です。取得できない場合はトラップします。 |
shell::pwd | () -> Text | 現在の作業ディレクトリです。失敗時にはトラップします。 |
shell::cd | (path: Text) -> () | 現在の作業ディレクトリを変更します。失敗時にはトラップします。 |
utility_natives にバンドルされた println と組み合わせることで、スクリプトは出力を生成し、外部プロセスを実行し(標準エラー出力のキャプチャやタイムアウトの有無を選べます)、フォークせずにスリープし、ファイルを直接読み書きし、ログ形式の出力を標準エラー出力へ振り分け、自身の引数を調べ、プロセス環境や作業ディレクトリを操作できます。
解消されたギャップ
初回の監査では、3 つの重大なギャップと 4 つの重要なギャップが特定されました。7 つすべてが V0.2.1 で解消されており、当初の推奨から 1 つの設計調整が加えられています。
| 当初の推奨 | 状態 | 備考 |
|---|---|---|
shell::sleep_ms | 実装済み | 負またはゼロの入力は、拒否するのではなく即座に戻ります。 |
shell::now_unix_ms | 実装済み | Unix タイムスタンプをミリ秒単位で返します。システムクロックが i64 のミリ秒範囲を超える値を返した場合は Word の範囲にクランプされますが、これは実際にはあり得ない状況です。 |
shell::write、shell::writeln、shell::write_err、shell::writeln_err | 一部実装済み | 標準エラー出力向けの変種は存在します。標準出力向けの変種(write と writeln)は追加されませんでした。既存の utility_natives の println が一般的なケースをカバーしており、インライン書き込みのイディオムは十分にまれであるため、後回しにできると判断されたためです。 |
shell::file_exists | 実装済み | シンボリックリンクをたどります。たどらない変種はまだ公開されていませんが、ユースケースが現れれば追加できます。 |
shell::read_file | 実装済み | Text を直接返し、入出力の失敗や非 UTF-8 の内容の場合は NativeError を介してトラップします。これは shell::run_checked のエラーパターンに一致します。当初提案されていた Result<Text> の戻り値型は、言語がまだ汎用の Result 型を備えていないため、単純なトラップに縮小されました。設計上の判断として、ファイル入出力のためだけに Result を導入するのではなく、バンドル全体で一貫したエラー時トラップのパターンを維持することにしました。 |
shell::write_file、shell::append_file | 実装済み | read_file と同じエラー時トラップのパターンです。 |
shell::read_lines | 未実装 | 行単位の反復処理というユースケースは、read_file とホスト側での分割によって満たされます。行単位のエラー時トラップのセマンティクスが実際の要件になった時点で、専用のネイティブ関数を追加できます。 |
shell::arg、shell::arg_count の argv 正確性 | 修正済み | この対はかつて std::env::args を直接読み取っていたため、スクリプトからは自身の引数の前に keleusma、run、およびスクリプトパスが安定したオフセットなしに見えていました。現在は、CLI が設定するスクリプト引数ベクタ(set_script_args)を報告します。インデックス 0 はスクリプトパス、1 以降は位置引数です。CLI は keleusma run とシバン呼び出しの両方で位置引数を収集し、-- ターミネータを尊重します。 |
shell::run の標準エラー出力キャプチャ | 解消済み | shell::run は標準エラー出力をキャプチャして破棄します。新しい shell::run_full は、コマンドの診断ストリームを必要とする呼び出し側のために (exit_code, stdout, stderr) を返します。 |
エラー時トラップの慣習は STANDARD_LIBRARY.md のネイティブごとの契約に記載されています。将来のジェネリックな Result 型またはリファインメント newtype ラッパーがトラップパターンを置き換える可能性があります。それはバンドル設計の問題ではなく言語設計の問題です。
総合評価
現在のバンドルは、単発型とデーモン型の両方のワークロードに対して十分です。V0.2.1 で追加された 3 つの機能(スリープ、時刻、ファイル入出力)は、以前デーモンのユースケースを扱いにくくしていたギャップを解消しました。ループデーモンは、フォークせずに自身のペースを調整し、ファイルから設定を読み取り、ログレコードをファイルや標準エラー出力へ書き込み、経過時間について推論できるようになり、いずれもサブプロセスへ委譲することなく行えます。
署名および暗号化された配信モデルは、今日、アトミックモードと生産的発散モードの両方で完全に利用可能です。
未解決の推奨事項
初回の監査で提案された利便性のためのネイティブ関数(pid、hostname、setenv、pwd、cd、run_timeout)はすべて実装済みで、利用可能な機能の下に記載されています。残る利便性項目は小さく、何も妨げていません。
| 優先度 | ネイティブ | ユースケース |
|---|---|---|
| 低 | shell::read_lines(path: Text) -> Array<Text> | 一般的な行単位の反復処理。現在はスクリプトがファイル全体を読み取り、ホスト側で分割しています。 |
残る制限事項
これらは、欠けているネイティブ関数ではなく、標準バンドルの性質です。Shell バンドルはアンビエントなプロセス権限を付与するため、これらが問題になります。したがって、信頼できないスクリプトに対してこれを提供するホストは、次の注意事項を引き継ぎます。閉じ込めや証明済みの境界を必要とするホストは、バンドル全体ではなく、厳選したサブセットまたは独自のより狭いネイティブ関数を登録すべきです。
- 副作用のあるネイティブ関数では WCET と WCMU は境界付けされません。
shell::run、shell::run_full、shell::run_checked、shell::run_timeoutは任意のサブプロセスを生成しますが、その時間とメモリは検証器がモデル化できません。言語がそれ以外の場面で保証する静的な最悪ケース境界は、これらの呼び出しをまたいでは及びません。shell::run_timeoutは呼び出しごとの実時間に上限を設けますが、メモリには設けず、その上限は静的に検証されるのではなく動的なものです。 - 境界のないホストヒープ割り当て。
read_file、run、run_fullは、スクリプトアリーナの予算の外側にあるホストヒープ上に、ファイルまたはサブプロセスの大きさに応じた出力バッファを割り当てます。大きなファイルや出力の多いサブプロセスは、ホストのメモリを枯渇させる可能性があります。 shell::exitはホストプロセスを終了させます。 これはstd::process::exitを呼び出し、仮想マシンの後始末とホスト側のクリーンアップをすべて回避します。これはスタンドアロンの CLI スクリプトには適切ですが、より大きなプロセス内でスクリプトを実行する埋め込み側にとっては危険です。- 決定性は放棄されます。
getenv、run、now_unix_ms、hostname、pid、pwd、およびファイルシステム関連のネイティブ関数はすべて、可変の外部状態を読み取ります。これらを用いるスクリプトは再現可能ではありません。 read_fileは UTF-8 を必要とします。 非 UTF-8 のファイル内容はバイト列を返すのではなくトラップします。バンドルにはバイナリファイル用のアクセサはありません。set_script_argsはスレッドローカルです。 あるスレッドでset_script_argsを呼び出し、別のスレッドでスクリプトを実行するホストは、設定したベクタではなくstd::env::argsのフォールバックを観測します。CLI は両方をメインスレッドで実行するため、そこでは見えませんが、マルチスレッドの埋め込み側にとっては制約となります。
デーモンのユースケースに関する総合判断
stddsl::Shell は今や、Keleusma で実質的な devops および sysadmin のループデーモンを記述できるほど充実しています。今日機能するユースケースは次のとおりです。運用者が管理するホストへ配備された署名および暗号化済みの成果物、--tick-interval を介した組み込みのレート制限を備えた生産的発散ループでの運用ロジックの実行、設定ファイルの読み取り、ログレコードの標準エラー出力またはディスクへの書き込み、shell::exit を介したクリーンな終了です。入出力の失敗に対するエラー時トラップのパターンは、ホストのファイルシステムが期待と食い違ったときに、デーモンスクリプトへ即座に失敗する振る舞いを与えます。