技術仕様・ライセンス・セキュリティモデル
主張はすべてリポジトリで検証できます。数字は手で書かず、計測した値だけを載せています。
スタック
エンジンは Rust の17クレートからなるワークスペースです。テンプレートの二段階パース、CSSライクなボックスモデル、レイアウトツリー(レイアウトと描画の唯一の契約)、PDF/PNGの2バックエンド、署名・検証、そして CLI・MCP・ブラウザWASM・C ABI・N-API の5つのホストが、同じ一つのエンジンを包みます。レイアウトは描画せず、レンダラは測り直さない。この分離がクレート境界で強制されているから、どのホストでも同じバイト列が出ます。
Designer は TypeScript + React で、エンジンにはWASM越しに触ります。エンジン側は「ロケール非依存」を保ち、日付・通貨・単位・和暦はロケールデータ(ja-JP と en-US はビルトイン、その他は packs/locale/ のパック)から、フォントは packs/fonts/ のパックから来ます。
品質ゲート
CIは開発者がローカルで打つのと同じ make ターゲットをそのまま走らせます。二重定義はありません。
- 行カバレッジ100%(ブロッキング) — エンジン全ワークスペース。99%では落ちます
clippy -D warnings・rustfmt・1ファイル300行上限(GUI側は実効150行)- 同梱例は全部レンダリングされ、コミット済み出力とバイト比較されます。決定性が主張ではなくゲートです
- Designer側も typecheck / lint 警告ゼロ / カバレッジ100%×4
依存関係とSBOM
- cargo-deny がアドバイザリとライセンスをゲートし、アドバイザリの ignore はゼロです。ignore を足さないと通らない依存は、採用しません
- CycloneDX SBOM をリポジトリにコミットしています(sbom/)。現在 engine 235 / gui 258 / sdk-js 127 コンポーネント。ロックファイルが動くたびに再生成されます
- npm側の防御:pnpm の
minimumReleaseAgeを7日に設定(公開後7日未満のパッケージはインストール自体が失敗する。侵害されたリリースが取り下げられる前に入ることを防ぐ)。postinstall スクリプトは明示的な許可リスト制です
ライセンス
コードは Apache-2.0 / MIT / BSD 3-Clause のトリプルライセンスで、利用側がどれかを選べます。同梱フォントは BIZ UD・Noto ファミリが SIL OFL 1.1、IPAmj明朝が IPAフォントライセンスです。各パックはライセンス全文を同梱し、フォントの再配布可否は manifest.yml に明記されています。
セキュリティモデル
入力はすべて敵対的とみなします。 テンプレート・params・フォント・画像・検証対象のPDFは、信頼できない入力として書かれたパーサが読みます。
- フォントは顔ごとの sha256 をロード時に検証し、OS/2 の埋め込み権利ビット(fsType)を確認します。制限付きフォントは明示の宣言なしには拒否されます
- 画像アセットはルート外へのパスを拒否(
asset_traversal)。リモートURLは拒否します — レンダリングパスにネットワークI/Oは存在しません - テンプレートの解決がテンプレートルートを出れば
template_escapes_rootで拒否。paramsからの動的画像はホストのポリシー(allow/denyリスト)で明示的に許可された項目だけが通ります - パーサは libFuzzer でファジングされます(オンデマンドの
make fuzz。過去にクラッシュした入力はコーパスとして保存され、回帰として再生されます)
レンダリング・署名・検証はネットワークを使いません。 設定ではなく設計です。ソケットを開くコードが該当クレートにありません。
検証は「していないこと」を報告します。 署名が実際に覆うバイト範囲を報告し、不完全な範囲上の正しい署名を偽造として扱います。信頼アンカーは呼び出しごとに明示指定で、マシンの証明書ストアには触れません。
このサイト自体も同じ姿勢です。レンダリングはあなたのタブの中のWASMで行われ、何もアップロードされません。CSPはインラインスクリプト禁止(ビルド時にsha256ハッシュで実出力だけを許可)、アナリティクスはクッキーレスです。
報告窓口: SECURITY.md — kengo+shojiku@kengos.jp