@rex0220/print-craft-authoring-tools 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # print-craft authoring tools(開発メモ)
2
2
 
3
- 印刷屋プラグイン(print-craft)の設定 JSON を AI で作る・確かめるための tools。npm パッケージ `@rex0220/print-craft-authoring-tools`(MIT。版は印刷屋プラグインの版と独立。対応する印刷屋の版は `src/meta.ts` の `SUPPORTED_PLUGIN_VERSIONS` で、`version` コマンドが出す)のソース。リポジトリのルートがテンプレート(利用者が "Use this template" で使う側)。計画と決定は print-craft の `docs/authoring-plan.md` 12 章。
3
+ 印刷屋プラグイン(print-craft)の設定 JSON を AI で作る・確かめるための tools。npm パッケージ `@rex0220/print-craft-authoring-tools`(MIT。版は印刷屋プラグインの版と独立。扱う印刷屋はプラグイン ID と版の下限(Ver.6 以降)で決まり、`version` コマンドが出す)のソース。リポジトリのルートがテンプレート(利用者が "Use this template" で使う側)。計画と決定は print-craft の `docs/authoring-plan.md` 12 章。
4
4
 
5
- **tools は印刷屋のコードを含まない。** 計算式エンジン(`desktop_js/KintoneFormulaPCraft.min.js`)と印刷屋の設定画面・帳票のコード + kit(`config_js/print-craft-authoring-api.js`。Ver.6 から zip に同梱。print-craft の `src/authoring/api.ts`)は、利用者の印刷屋 zip(`.env` の `PCRAFT_PLUGIN_ZIP`)から実行のたびにメモリに読む(`src/plugin-zip.ts`、`src/engine.ts`)。zip の中身の SHA-256 が `src/meta.ts` の既知のリリース(4 ファイルの組み合わせ)と違えば実行せずに止まる(fail closed。`SECURITY.md`)。開発中にソースから動かすとき(`node src/cli.ts …`)だけ、環境変数 `PCRAFT_ALLOW_DEV_PLUGIN=1` を置けば隣の print-craft の `prod/` からも読める(この場合は既知でなくても警告で続く。ビルドした `dist/cli.mjs` では読まない)。ビルド(`scripts/build.mjs`)は bundle に印刷屋 / kit のコードが入っていないことを確かめて止まる。
5
+ **tools は印刷屋のコードを含まない。** 計算式エンジン(`desktop_js/KintoneFormulaPCraft.min.js`)と印刷屋の設定画面・帳票のコード + kit(`config_js/print-craft-authoring-api.js`。Ver.6 から zip に同梱。print-craft の `src/authoring/api.ts`)は、利用者の印刷屋 zip(`.env` の `PCRAFT_PLUGIN_ZIP`)から実行のたびにメモリに読む(`src/plugin-zip.ts`、`src/engine.ts`)。zip の `PUBKEY` から出るプラグイン ID が印刷屋のもの(`src/meta.ts` の `PRINT_CRAFT_PLUGIN_ID`)でなければ実行せずに止まる(fail closed。`SIGNATURE` は検証しない。`SECURITY.md`。1.1.0 から。1.0.0 までは 4 ファイルの SHA-256 を既知のリリースと照合していた)。開発中にソースから動かすとき(`node src/cli.ts …`)だけ、環境変数 `PCRAFT_ALLOW_DEV_PLUGIN=1` を置けば隣の print-craft の `prod/` からも読める(この場合はプラグイン ID を確かめず、警告を出して続く。ビルドした `dist/cli.mjs` では読まない)。ビルド(`scripts/build.mjs`)は bundle に印刷屋 / kit のコードが入っていないことを確かめて止まる。
6
6
 
7
- **ビルドとテストには、隣に印刷屋のリポジトリ(非公開)と plugin-config-kit / rexgrid が要る**(`package.json` の devDependencies が `file:` で参照する。型の import と、テストの fixture の zip `print-craft/dist/print-craft-plugin6.zip` のため。公開レジストリの tools を使うだけなら要らない)。zip の読み取りと版の照合のテスト(`test/plugin-zip-synthetic.test.mjs`、`test/engine-contract.test.mjs`)は印刷屋のコードを含まない合成 zip(`test/zip-helper.mjs`)でも動く。
7
+ **ビルドとテストには、隣に印刷屋のリポジトリ(非公開)と plugin-config-kit / rexgrid が要る**(`package.json` の devDependencies が `file:` で参照する。型の import と、テストの fixture の zip `print-craft/dist/print-craft-plugin6.zip`(Ver.7 の `print-craft-plugin7.zip` があればそれも読む)のため。公開レジストリの tools を使うだけなら要らない)。zip の読み取りと版の照合のテスト(`test/plugin-zip-synthetic.test.mjs`、`test/engine-contract.test.mjs`)は印刷屋のコードを含まない合成 zip(`test/zip-helper.mjs`)でも動く。
8
8
 
9
9
  ```
10
10
  Projects/
@@ -17,14 +17,18 @@ Projects/
17
17
 
18
18
  ## 構成
19
19
 
20
- - `src/cli.ts` … `pcraft-authoring <command>`(version / fields / record / pull / normalize / preview / diff / buttons。pull は API ラボのプラグインの設定の GET。fields と record の `--summary` は取得済みのファイルの要約で通信しない。record の要約は値を出さない)。読むのは cwd の中、書くのは fields/ records/ settings/ temp/ out/ の下だけ(`src/safe-path.ts`)。`.env` / policy / zip の場所は固定
20
+ - `src/cli.ts` … `pcraft-authoring <command>`(version / fields / record / pull / normalize / preview / diff / buttons。pull は API ラボのプラグインの設定の GET。fields と record の `--summary` は取得済みのファイルの要約で通信しない。record の要約は値を出さない)。読むのは cwd の中、書くのは fields/ records/ settings/ temp/ out/ kintone/ の下だけ(`src/safe-path.ts`。kintone/ の下は `src/permission.ts` の許可も)。`.env` / policy / zip の場所は固定
21
21
  - `src/plugin-zip.ts` … 印刷屋の zip(contents.zip の 2 層)を Node の zlib だけで読む。大きさ・entry 数・展開後の上限、CRC-32、名前の一致、重複を検査
22
- - `src/engine.ts` … zip のエンジンと authoring API を happy-dom + スタブで動かす。版の照合(印刷屋の版、API の版と pluginVersion、4 ファイルの SHA-256、API のキーと型)
22
+ - `src/engine.ts` … zip のエンジンと authoring API を happy-dom + スタブで動かす。照合(プラグイン ID、印刷屋の版、API の版と pluginVersion、API のキーと型)
23
23
  - `src/kintone-url.ts` … 接続先の検証(`*.cybozu.com` / `*.kintone.com` / `*.cybozu.cn`、ユーザー情報・パス・ポート無し)
24
- - `src/workspace.ts` … 開発と本番(environments.json)、`kintone/<ホスト名>/<番号>-<アプリ名>/` のフォルダー、ダウンロードの名前(`src/commands/take.ts` が inbox から移す)
25
- - `src/env.ts` / `src/kintone-rest.ts` … `.env`(kintone 公式 MCP と同じ `KINTONE_*` + `PCRAFT_PLUGIN_ZIP` + `PCRAFT_ALLOW_UNKNOWN_PLUGIN`)と GET 専用・許可 API 固定・送信先固定の REST
26
- - `src/commands/` … 各コマンド。`src/normalize/` … 派生値の生成、検査(HTML / CSS の allowlist、policy、大きさ)、行の差分。`src/preview/` … 帳票 HTML(sandbox + CSP + DOM の無害化)
27
- - `src/meta.ts` … tools の版、対応する印刷屋の版と API の版、既知の zip の中身の SHA-256(`KNOWN_PLUGIN_HASHES`)、API の契約(`REQUIRED_API`)
24
+ - `src/context.ts` … 作業の文脈(作業フォルダーの実際のパスと環境変数)。CLI は起動時に一度だけ作り、中核には引数で渡す(print-craft MCP も同じ中核を呼ぶ)
25
+ - `src/paths.ts` / `src/dev-paths.ts` … tools の置き場所(環境変数を読まない。中核から使う)/ 開発とビルドのときだけ使う場所の探し方(隣の print-craft、kit、rexgrid。`PCRAFT_PRINT_CRAFT_ROOT` などの環境変数を読む。import するのは `cli.ts` と scripts/・試験だけ)
26
+ - `src/commit-file.ts` … ファイルの確定(新しいファイルはハードリンクで、上書きしない)、所有者の印付きのロック、片付け(save / pull / take が使う)
27
+ - `src/permission.ts` … `kintone/` の下を変える前の許可(`environments.json` の `role`。本番は読み取りだけ、未分類は何も変えない)
28
+ - `src/workspace.ts` … 開発と本番(environments.json。環境の `role`)、`kintone/<ホスト名>/<番号>-<アプリ名>/` のフォルダー、ダウンロードの名前(`src/commands/take.ts` が inbox から移す)
29
+ - `src/env.ts` / `src/kintone-rest.ts` … `.env`(kintone 公式 MCP と同じ `KINTONE_*` + `PCRAFT_PLUGIN_ZIP`)と GET 専用・許可 API 固定・送信先固定の REST
30
+ - `src/commands/` … 各コマンド。`save.ts` は保存の約束(新しい設定の保存、ボタン 1 つの差し替え。print-craft MCP の保存のツールの本体)、`records.ts` はレコードを数件・形だけで見る(print-craft MCP の kintone_list_records)。`src/normalize/` … 派生値の生成、検査(HTML / CSS の allowlist、policy、大きさ)、行の差分。`src/preview/` … 帳票 HTML(sandbox + CSP + DOM の無害化)
31
+ - `src/meta.ts` … tools の版、扱う印刷屋(プラグイン ID `PRINT_CRAFT_PLUGIN_ID`、版の下限 `MIN_PLUGIN_VERSION`)、API の版(`SUPPORTED_API_VERSIONS`)、API の契約(`REQUIRED_API`)
28
32
  - `scripts/vendor.mjs` … moment 2.24.0 を CDN から `vendor/` に取る(`vendor/moment.json` の SHA-256 と照合)
29
33
  - `scripts/build.mjs` … esbuild で `dist/cli.mjs`(Node 20、ESM。印刷屋 / kit のコードが入ったら失敗)
30
34
  - `scripts/gen-schema-manifest.mjs` … `docs/schema-manifest.json` と `docs/defaults/*.json`(API の CONFIG_SCHEMA から)
@@ -48,7 +52,7 @@ npm pack --dry-run # 公開前に中身を確かめる(dist、vendor、LICENS
48
52
  ## 決まり
49
53
 
50
54
  - 印刷屋の関数は `engine.api`(zip の authoring API)経由で使う。`src/` から print-craft を import するのは **型だけ**(`import type`)。実行コードを import すると build が止まる
51
- - 印刷屋の `src/authoring/api.ts` の名前や引数を変えるときは `AUTHORING_API_VERSION` を上げ、tools の `SUPPORTED_API_VERSION` と `REQUIRED_API` を合わせる。印刷屋の zip の中身を変えたら `KNOWN_PLUGIN_RELEASES` にリリースの tuple(エンジン・API・bignumber・moment-timezone の 4 つの SHA-256。zip から計算)を足し、印刷屋の版を上げたら `SUPPORTED_PLUGIN_VERSIONS` に足す(古い版は利用者が残っている間は外さない)。どちらも tools の新しい版として公開する。tools の版は印刷屋の版と独立(semver。2026-10-06 Takashi「B」で 0.1.0 から)
55
+ - 印刷屋の `AUTHORING_API_VERSION` が上がったら、tools の `SUPPORTED_API_VERSIONS` に足し(古い版は利用者が残っている間は外さない)、`REQUIRED_API` を合わせて tools の新しい版として公開する。印刷屋の zip の中身が変わっただけ・版を上げただけなら tools の公開は要らない(1.1.0 から。プラグイン ID で読む)。印刷屋の鍵(`private.ppk`)を変えるとプラグイン ID が変わるので `PRINT_CRAFT_PLUGIN_ID` も変える。tools の版は印刷屋の版と独立(semver。2026-10-06 Takashi「B」で 0.1.0 から)
52
56
  - kintone への書き込みは行わない。HTTP 層は GET 専用で、送れるパスと送信先を固定する
53
57
  - CLI に `.env` / policy / zip の場所を変えるオプションを足さない(AI が書けるファイルを読ませない)。書き込み先を増やすなら `src/safe-path.ts` の `WRITE_ROOTS`
54
58
  - `vendor/*.js`、`dist/`、`out/`、`node_modules/` はコミットしない
package/SECURITY.md CHANGED
@@ -21,21 +21,25 @@
21
21
 
22
22
  ## tools が守ること
23
23
 
24
- - **kintone には GET しか送らない。** 呼べる API は `app`、`app/form/fields`、`app/form/layout`、`record`、`app/plugin/config` と、その preview 版に固定している(ゲストスペースの `/k/guest/<id>/v1/` も同じ一覧)。それ以外のパスやメソッドは送信前に止まる。`app/plugin/config`(`pull`)は kintone の API ラボ「アプリに追加されているプラグインの設定情報を取得する」で、印刷屋のプラグイン ID(zip の公開鍵から)の設定だけを読む。同じ API ラボの設定の変更(PUT)は呼ばない。`pull` は運用中の設定にレコード閲覧+レコード追加、`--preview` にアプリ管理の権限が要るので、使うときだけその権限のトークン(またはログインユーザー)にする
24
+ - **kintone には GET しか送らない。** 呼べる API は `app`、`app/form/fields`、`app/form/layout`、`record`、`records`、`app/plugin/config` と、その preview 版に固定している(ゲストスペースの `/k/guest/<id>/v1/` も同じ一覧)。それ以外のパスやメソッドは送信前に止まる。`app/plugin/config`(`pull`)は kintone の API ラボ「アプリに追加されているプラグインの設定情報を取得する」で、印刷屋のプラグイン ID(zip の公開鍵から)の設定だけを読む。同じ API ラボの設定の変更(PUT)は呼ばない。`pull` は運用中の設定にレコード閲覧(API トークンでも可。資料は「閲覧と追加」だが閲覧だけのトークンで取れた)、`--preview` にアプリ管理の権限が要るので、`--preview` を使うときだけその権限のトークン(またはログインユーザー)にする。`records`(print-craft MCP の kintone_list_records)は query に limit / offset を許さず件数を 5 件に固定し、値・ファイル名・ユーザー名を返さず形だけを返す(返す JSON は UTF-8 で 64 KiB まで。超える前の件で打ち切る)。**受け取る本文に API ごとの上限**(アプリの情報 64 KiB、項目定義・レイアウト・レコード 8 MiB、プラグインの設定 2 MiB)があり、Content-Length か読みながらの大きさで超えたら読み切らずに止める(本文はストリームからだけ読む。ストリームの無い応答は読まない)
25
25
  - **開発と本番(environments.json)でも、場所は CLI から指定できない。** `--env` で選べるのは `environments.json` の環境の名前だけで、認証のファイルの場所(`.env` か `env/<名前>.env` の形だけ)と接続先は `environments.json` に書く。テンプレートでは AI は `environments.json` と `env/` を書けない(`.claude/settings.json`)。このときの認証はその環境の認証のファイルだけから読み、OS の環境変数の `KINTONE_*` / `KSQL_*` は読まない(開発と本番の取り違えを防ぐ)。認証のファイルの `KINTONE_BASE_URL` が `environments.json` の接続先と違えば止まる。iframe の同一オリジンの判定には `environments.json` の接続先を使い、`kintone/<ホスト名>/` のフォルダー名(AI が作れる)は使わない
26
26
  - **送信先は kintone のドメインだけ。** `KINTONE_BASE_URL` は `https://<サブドメイン>.cybozu.com` / `.kintone.com` / `.cybozu.cn`(`*.s.cybozu.com` を含む)だけを受け付け、ユーザー情報(`user@`)・ポート・パス・クエリが付いた URL は使わない。URL は `new URL(path, base)` で組み、送信直前にも origin が同じか確かめる
27
27
  - **kintone 以外とは通信しない。** `normalize` / `preview` / `diff` / `buttons` / `version` と、`fields` / `record` の `--summary` はネットワークを使わない。利用状況の送信(テレメトリ)は無い
28
28
  - **認証情報を出力しない。** `.env` または OS の環境変数から読み、API トークン・パスワード・ユーザー名は画面・ファイル・エラーの文言に出さない。エラーの文言は HTTP の状態と kintone のエラーコードと固定のヒントだけ(サーバーの message は出さない)。出すのは接続先の URL と「API トークン / ログインユーザー」の区別だけ
29
29
  - **レコードの値を標準出力に出さない。** `record` は項目の数とテーブルの行数だけ表示し、値は `records/<app>-<id>.json` に書く(テンプレートの `.gitignore` でコミット対象外)。`--fields-from` で設定が使う項目だけに絞れる。`record --summary` も形(文字数・行数・数値の桁・件数・添付の種類)だけで、値・ファイル名・ユーザー名は出さない
30
- - **印刷屋の zip の中身が既知でなければ実行しない(fail closed)。** 計算式エンジン、authoring API、bignumber、moment-timezone の 4 ファイルの SHA-256 が tools の既知のリリース(`src/meta.ts` の `KNOWN_PLUGIN_RELEASES`。4 つの組み合わせ単位)と一致し、zip の `manifest.json` の版が対応する版で、API の版と印刷屋の版と tools の版が合い、tools が使う API のキーと型がそろっているときだけ実行する。どれか違えば **コードを実行する前に止まる**。zip の読み取りでは、外側と中身の大きさ・entry の数・展開後の大きさの上限、central directory と local header の名前の一致、CRC-32、同名 entry の重複を確かめる(zip bomb と改変の対策)。新しい修正版の zip を使うなど、違いを理解した上で続けるときだけ、**利用者が** `.env` に `PCRAFT_ALLOW_UNKNOWN_PLUGIN=1` を書く(警告を出して続ける。AI は `.env` を書けない)。公開ビルド(npm の `dist/cli.mjs`)が読むのは `PCRAFT_PLUGIN_ZIP` の zip だけで、`node_modules` や隣のフォルダーのファイルは読まない(開発者がソースから動かし、環境変数 `PCRAFT_ALLOW_DEV_PLUGIN=1` を置いたときだけ、隣の print-craft の `prod/` を警告付きで読む)
30
+ - **印刷屋の zip でなければ実行しない(fail closed)。** 外側の zip の `PUBKEY`(kintone のプラグインの公開鍵)から出るプラグイン ID が印刷屋のもの(`src/meta.ts` の `PRINT_CRAFT_PLUGIN_ID`)で、`manifest.json` の版が Ver.6 以上の整数で、authoring API があるときだけ zip のコードを実行する。違えば **コードを実行する前に止まる**。実行した後に、API の版(`SUPPORTED_API_VERSIONS`)、API の印刷屋の版と manifest の版の一致、tools が使う API のキーと型を確かめる。**`SIGNATURE`(kintone の署名)は検証しない**ので、本物の zip の `PUBKEY` を写して中身を差し替えた zip は止められない(1.1.0。2026-10-08。1.0.0 までは 4 ファイルの SHA-256 を既知のリリースと照合していたが、印刷屋の zip が変わるたびに tools の公開が要った)。zip の読み取りでは、外側と中身の大きさ・entry の数・展開後の大きさの上限、central directory と local header の名前の一致、CRC-32、同名 entry の重複を確かめる(zip bomb と改変の対策)。公開ビルド(npm の `dist/cli.mjs`)が読むのは `PCRAFT_PLUGIN_ZIP` の zip だけで、`node_modules` や隣のフォルダーのファイルは読まない(開発者がソースから動かし、環境変数 `PCRAFT_ALLOW_DEV_PLUGIN=1` を置いたときだけ、隣の print-craft の `prod/` を警告付きで読む)
31
31
  - **印刷屋のコードを含まない。** エンジンと API は利用者の zip からメモリへ読むだけで、コピーや書き出しはしない。ビルドは、npm に入る `dist/cli.mjs` に印刷屋 / plugin-config-kit / rexgrid の実行コードが混ざっていないことを検査する
32
32
  - **CLI が読む・書く場所を限る。** 読むのは作業フォルダーの中のファイルだけ(`.env` と `node_modules` は読まない)、書くのは `fields/` `records/` `settings/` `temp/` `out/` `kintone/` の下だけ(realpath で判定。junction / symlink で外へは出られない。Windows の予約名は使わない)。`.env`、`policy/authoring-policy.json`、印刷屋の zip の場所(`PCRAFT_PLUGIN_ZIP`)は作業フォルダーのものに固定で、`--env` / `--policy` / `--plugin-zip` のようなオプションは無い。iframe の同一オリジンの判定は `.env` の `KINTONE_BASE_URL` **だけ**を使い、AI が書き換えられる `fields/*.json` の値は使わない(`.env` に接続先が無ければ iframe は使えない)。パスの検査から書き込みまでの間にリンクが差し替えられる競合(TOCTOU)は残るが、AI と同じ OS ユーザーの範囲の話であり、この tools では防がない
33
+ - **本番の環境は読み取りだけ(`environments.json` の `role`)。** `kintone/` の下を変える直前に `environments.json` を読み直し、本番(`production`)のフォルダーは新しい名前のダウンロード / pull を足すことだけ、開発(`development`)はダウンロード / pull のファイルの書き換えだけを拒否、`role` の無い環境・`environments.json` が無いのに `kintone/` の下・どの環境か決まらないフォルダー(構成 2 で `apps` に無い番号)は何も変えない(`src/permission.ts`)。`--env`(AI が付けられる引数)では決めない
34
+ - **作業フォルダーと環境変数は起動時に一度だけ決める。** 作業フォルダーは実際のパス(symlink / junction を解いたもの)にしてから使い、中核は `process.cwd()` / `process.env` を既定の値として読まない(`src/context.ts`。印刷屋の zip と開発中の読み込み元も引数で受け取る)。環境変数を読むのは `src/cli.ts` と開発用の場所の探し方 `src/dev-paths.ts` だけで、`dev-paths.ts` を import するのは `cli.ts` だけ(`test/core-boundary.test.mjs` で確かめる)。OS の環境変数(print-craft MCP では設定項目)の `PCRAFT_PLUGIN_ZIP` は絶対パスだけ。外側の引用符を外すのは場所と URL だけ(認証情報は外さない)
35
+ - **設定の保存は normalize を通ったときだけ確定する**(`src/commands/save.ts`。print-craft MCP の保存のツールの本体)。normalize → 書く先のパス・`role`・ダウンロードのファイルを確かめる(normalize の間に本番に変わったフォルダーには一時ファイルもロックも作らない)→ 同じフォルダーの一時ファイル → 確定先のロック(隣の `.<名前>.pcraft-lock` に所有者の印。普通のファイルでなければ取らない。60 秒より古いものは固有の名前に付け替えてから回収する。外すのは自分の印のロックだけ)→ 確定の直前に書く先のパス(途中で symlink に差し替えられていないか)・`role`・ダウンロードのファイル・digest・ロックがまだ自分のものかを確かめ直す → 確定。新しい設定は `expectedAbsent: true` が要り、ハードリンクで確定する(同じ名前があれば失敗する = 確かめた後に作られたファイルも上書きしない)。既存の設定は名前の付け替えで確定し、読んだ時点の digest が違えば書かない。項目定義は、アプリのフォルダーの中なら同じフォルダーの `fields.json` だけ(別のファイルを渡すと拒否)。入力(`content` / `replacement`)は UTF-8 で 256 KiB まで。一時ファイルとロックの片付けは別々に試し(Windows の EPERM / EBUSY は短く待ってやり直す)、確定の後の片付けの失敗は保存の失敗にしない(結果に添える)(`src/commit-file.ts`)
36
+ - **ダウンロード / pull のファイルは新しいファイルとしてだけ置く。** `pull`(`environments.json` のときと、`--force` の無いとき。`environments.json` のときは `--force` を使えない)と `take` は、同じフォルダーの一時ファイルからハードリンクで確定し、確定の直前に書く先のパスと許可を確かめ直す(確かめた後に同じ名前のファイルができても上書きしない)。`take` は置けてから inbox の元を消す(消せなければ「置いたが inbox に残った」と返す)
33
37
  - **`normalize` は許可した書き方だけ通す(allowlist)。** 要素は文章・表・画像の要素だけ、属性は共通の属性(class / id / style …)と要素ごとの属性(img の src / srcset / alt、td の colspan …)と `data-*` / `aria-*` だけで、一覧に無い要素・属性、`on*` 属性、インラインの `<svg>` / `<math>`、`<script>` `<object>` `<embed>` `<link>` `<base>` `<meta>` `<form>` 系、`<template>` などはエラー。URL は Chrome の URL パーサーと同じ前処理(タブ・改行・制御文字を捨てる、`\` は `/`)をしてから `https:` / `data:image/` / 置き換えタグ / 相対だけを通す(`a` の `href` は `data:` も不可、`iframe` は利用者の kintone と同じオリジンだけ)。CSS はコメントを外してエスケープを復号してから、`url()` / `image-set()` / `image()` / `src()` / `@import` の URL を分類し、`@import` / `expression(` / `behavior:` / `-moz-binding:` を止める。属性値の `${式}` はエラー。**kintone 以外への読み込みとスクリプトは印刷屋 Ver.6 が描画の前に除く**(共通の設定「外部参照」`externalRefs: "block"`。帳票の HTML / CSS を DOMParser で DOM 化して、外部へ向く URL 属性・CSS の `url()` / `@import`・`script` などの要素・`on*` 属性を外してから画面に入れる)ので、tools はそれを前提にする: `"block"` の設定の HTML / CSS のテンプレートにある外部 URL は**エラー**(帳票に出ない。添付ファイルか `data:image/` にする)。`"allow"`(Ver.5 と同じく何も除かない。自己責任。キーが無い Ver.5 の設定も印刷屋は `allow` で動くので tools も `allow` とみなす)は、利用者が AI の書けない `policy/authoring-policy.json` の `allowExternalRefs` にその設定ファイルを書いていなければ**エラー**。`allow` の設定の外部 URL と、外部参照の設定に関わらず Web フォント(印刷屋は除かない)は `allowExternal`(形を検証する)で承認し、承認済みは情報、無ければ**警告**。帳票の行の**計算式が作る HTML** は静的に追い切れない(計算式のインタープリターを tools に二重に持たない。Codex レビュー 5 回の結論)ので**警告だけ**: HTML を作る関数の使用、`TAG` の要素名や `ATTR` / `STYLE` / `BATTR` の値が定数でない、文字列の定数に HTML / CSS があれば HTML / CSS と同じ検査を警告として出す。`${式}` の安全判定は式全体で行い、`&` でつないだ項がすべて安全なときだけ警告しない。エラーがあれば書き戻さない
34
38
  - **`preview` の HTML は閉じている。** 帳票は `sandbox=""` だけの iframe に `srcdoc` で入れ、外側と帳票の両方の文書に CSP(帳票は `default-src 'none'; img-src data:; style-src 'unsafe-inline'; font-src data:; connect-src 'none'; frame-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'`)。CSS は `<` を CSS のエスケープ(`\3c`)にして `</style>` で文書を壊せないようにし、描いた DOM から `script` / `meta` / `link` / `form` 系 / `iframe` / `object` / `embed` / SVG のアニメーション要素と、`on*` 属性・`href`(文書内の `#` 以外)・`srcdoc` などを外す(レコードの値が `TABLE_HTML` などで HTML として入る経路があるため)。画像は印刷屋のダミー画像。Web フォントは、配信元が承認済み(Google Fonts は既定、他は `policy/authoring-policy.json` の `allowExternal`)のときだけ帳票の文書に `<link>` を入れ、CSP の `style-src` / `font-src` にその配信元(Google Fonts は `fonts.googleapis.com` と `fonts.gstatic.com`)を足す。これが preview の唯一の外部通信で、送るのは設定に書いた固定の URL だけ(レコードの値は入らない)。未承認なら読まない(OS の書体)。出力には**レコードの値が入る**ので `out/` はコミット対象外
35
39
 
36
40
  ## tools がしないこと(利用者が守ること)
37
41
 
38
- - **zip は印刷屋プラグインの配布元から入手したものを使う。** 出所の分からない zip を `PCRAFT_PLUGIN_ZIP` に書かない。`PCRAFT_ALLOW_UNKNOWN_PLUGIN=1` は、tools の既知の一覧より新しい修正版の zip だと分かっているときだけ、理由を理解して書く(その zip のコードがこの PC の権限で動く)
42
+ - **zip は印刷屋プラグインの配布元から入手したものを使う。** 出所の分からない zip を `PCRAFT_PLUGIN_ZIP` に書かない。tools はプラグイン ID だけを見るので、中身を差し替えた zip を見分けられない(その zip のコードがこの PC の権限で動く)
39
43
  - `normalize` は HTML / CSS / 計算式の**静的な**検査で、計算式の**実行結果**(レコードの値が HTML として差し込まれること、関数が組み立てる HTML)は見ない。`TABLE_HTML` などの生の HTML を入れる関数、`TAG` / `ATTR` / `STYLE`、ESC_HTML を通さない `${式}` は警告にとどまる。外部への読み込みとスクリプトを止めるのは印刷屋 Ver.6 の描画前の掃除(`externalRefs: "block"`)で、文章や表の崩れは防げない。`"allow"` の設定ではその掃除も無い(利用者の承認と責任)。**インポートする前に `diff` の差分を人が見る**
40
44
  - preview の「承認した Web フォントの配信元以外と通信・遷移が起きない」ことは、CSP と sandbox と DOM からの除去の組み合わせで担保している。Chromium を自動で動かして確かめる試験はまだ無い(Chrome の DevTools の Network で確かめられる)
41
45
  - kintone への書き込みは、テンプレートの `.claude/settings.json` が kintone MCP の書き込みツール 15 個と読み取り 3 個(検索・スペース・コメント)を拒否し、CLAUDE.md が禁じているが、最終的な担保はサーバー側の権限(**レコード閲覧だけの API トークン**か、閲覧権限だけのアカウント)。設定・権限・API トークンの管理は利用者の責任