cdk-preflight 0.0.64 → 0.0.66
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/.claude/skills/add-preflight-rule/SKILL.md +8 -10
- package/.claude/skills/find-preflight-rules/SKILL.md +13 -11
- package/.jsii +2 -2
- package/AGENTS.md +4 -1
- package/docs/rules.md +6 -0
- package/lib/index.js +1 -1
- package/lib/rules.generated.js +67 -1
- package/package.json +1 -1
|
@@ -12,14 +12,11 @@ cdk-preflight のルール追加パイプライン。AGENTS.md の設計原則
|
|
|
12
12
|
## 手順
|
|
13
13
|
|
|
14
14
|
1. **入力の確定**: 追加したい制約を 1 文で書く(対象リソース型、プロパティ、条件、出典 URL または実際に観測したデプロイエラーメッセージ)。制約がまだ特定できていない(「このサービスで何かルールを増やしたい」段階の)場合は、このスキルではなく `find-preflight-rules` を先に使う。
|
|
15
|
-
2. **重複チェック(先にやる)**:
|
|
15
|
+
2. **重複チェック(先にやる)**: 違反最小テンプレートを書き、素のエンジンに直接かける:
|
|
16
16
|
```bash
|
|
17
|
-
npx ts-node --project test/tsconfig.json -
|
|
18
|
-
import { loadEngine } from './src/private/enforce';
|
|
19
|
-
const e = loadEngine();
|
|
20
|
-
const r = new e.RegoEngine({}).validateDetailed(new e.TemplateFile('<template>'), {});
|
|
21
|
-
console.log(JSON.stringify(r.diagnostics, null, 2));"
|
|
17
|
+
npx ts-node --transpile-only --project test/tsconfig.json scripts/rule-check.ts guard <dir>
|
|
22
18
|
```
|
|
19
|
+
出力は 1 件 1 行(`BLOCK <file> <ruleId>/<severity>` か `clean <file>`)。
|
|
23
20
|
ERROR/FATAL(source: SCHEMA / CFN_LINT)が既に出るなら**ルールは書かない**。終了し、その旨を報告する。
|
|
24
21
|
判定の全体像(WARN クラスのみ出るがデプロイは失敗するグレーゾーン、L2/cfn-lint/サーバー側検証との棲み分け)は AGENTS.md の「Where this pack sits among validation layers」に従う。L2 (aws-cdk-lib) が同じ検証を持っていても不採用理由にならず、既存ルールの廃止理由にもならない(原則 5)。廃止の引き金は同梱エンジン(か CFN サーバー側検証)がカバーしたときだけで、そのとき重複ガードが自動で赤くなる。
|
|
25
22
|
3. **ルール作成**: `rules/<service>/<rule-id>/` に 4 ファイル。規約:
|
|
@@ -27,7 +24,7 @@ cdk-preflight のルール追加パイプライン。AGENTS.md の設計原則
|
|
|
27
24
|
- ヘルパーは `_pf_<短縮名>_` プレフィックスで一意に
|
|
28
25
|
- `walk` ビルトインは無い。`to_number`/`object.get`/`flatten_list`/`resolve` で明示的に書く
|
|
29
26
|
- fail テンプレートはこのルール**だけ**に違反、pass テンプレートは完全クリーン
|
|
30
|
-
4. **ローカルゲート**: `npx projen bundle-rules && npx jest test/rules.test.ts test/structure.test.ts`
|
|
27
|
+
4. **ローカルゲート**: まず `npx ts-node --transpile-only --project test/tsconfig.json scripts/rule-check.ts check <service|rule-id>...` を回す。`rules/` を直接読んで 1 エンジンに全ルールを載せ、fail が自分のルールで鳴るか / pass が全ルール無音か / どちらも組み込みエンジンに止められないかを返す(`bundle-rules` も meta.yaml の evidence も要らないので、実機ゲート前の直しはここで回す。80 本で数秒)。全部 `ok` になってから `npx projen bundle-rules && npx jest test/rules.test.ts test/structure.test.ts`。**jest は `-t` で対象を絞る**。フルスイートは PR 直前の 1 回だけでよく、実測では 401 回中 73 回がフル実行で合計 5.8 時間を溶かしている。
|
|
31
28
|
5. **実機再現ゲート**: `bash bench/verify-rule.sh <rule-id>`(要 AWS 認証)。観測したエラーメッセージと日付を `meta.yaml#repro.evidence` に記録。
|
|
32
29
|
- fail テンプレートがデプロイに**成功**したら、それはドキュメント側の誤り(BROKEN-EXPECTATION)。ルールを削除し、証拠を issue に残して終了する。CloudFront では明文化された制約 9 件中 3 件がこれだった(2026-09-02)
|
|
33
30
|
- **予想と違う理由**で失敗した場合(他アカウントの ARN、ドメイン所有権の検証など)は証拠にならない。サービスエラーが対象の制約そのものを名指しするまでテンプレートを作り直すか、除去できない交絡は `evidence` に明記する
|
|
@@ -36,7 +33,7 @@ cdk-preflight のルール追加パイプライン。AGENTS.md の設計原則
|
|
|
36
33
|
|
|
37
34
|
## セッションの切り方(コンテキスト予算)
|
|
38
35
|
|
|
39
|
-
API コストは **`往復回数 × 平均コンテキスト長`** でほぼ決まる(実測 2026-09-
|
|
36
|
+
API コストは **`往復回数 × 平均コンテキスト長`** でほぼ決まる(実測 2026-09-08、全 16 セッション集計: cache_read が入力の 98%、平均 258k tok/往復。平均 372k のセッションはルール 1 本 $5.2、213k で切ったセッションは $1.7)。**1 サービスぶんを 1 セッションで通さない**。`find-preflight-rules` から `candidates.json` を受け取り、下の境界で `/clear` して scratchpad の `<service>/` 配下のファイルだけを引き継ぐ:
|
|
40
37
|
|
|
41
38
|
| フェーズ | 入口 | 出口 |
|
|
42
39
|
|---|---|---|
|
|
@@ -46,7 +43,8 @@ API コストは **`往復回数 × 平均コンテキスト長`** でほぼ決
|
|
|
46
43
|
|
|
47
44
|
守ること:
|
|
48
45
|
|
|
49
|
-
- **rule.rego と fail/pass テンプレートを 1 本ずつヒアドキュメントで書かない**。`candidates.json` を読むジェネレータ(`rgen.py` 相当)を 1
|
|
50
|
-
- **書いたファイルを `cat` で読み返さない**。確認は `
|
|
46
|
+
- **rule.rego と fail/pass テンプレートを 1 本ずつヒアドキュメントで書かない**。`candidates.json` を読むジェネレータ(`rgen.py` 相当)を 1 個置き、直しはジェネレータ側に入れて再生成する。実測では打ち込んだコマンド文字列(2.22 Mtok)が Bash 出力(2.52 Mtok)とほぼ同額で、その **63% が 416 回の 4k 超コマンド**
|
|
47
|
+
- **書いたファイルを `cat` で読み返さない**。確認は `scripts/rule-check.ts check` と `npx jest` の結果だけで足りる
|
|
48
|
+
- **独立した呼び出しは 1 レスポンスにまとめる**(実測 3,352 往復の 55% がツール 1 個だけ)。`git status` / `log` / `diff` の確認ループも同様で、1,592 回・3.4 時間かかっている
|
|
51
49
|
- **実機ゲートは 1 本ずつ対話で回さない**。`pending.txt` を回す 1 スクリプトをバックグラウンドで走らせ、ログは `bench-out/<rule-id>.log` に書かせて、戻すのは 1 行のサマリだけにする。完了待ちのポーリングを 1 往復 1 回やらない(1 往復 ≒ 平均コンテキスト長ぶんの再読み込み)
|
|
52
50
|
- ⑤ で候補が数十本あるなら、ジェネレータの入力(`candidates.json`)を直すサイクルに寄せる。個別ルールのデバッグは失敗した数本に絞る
|
|
@@ -78,14 +78,11 @@ EOL ランタイム、廃止インスタンスタイプ、リージョン非対
|
|
|
78
78
|
|
|
79
79
|
1. **制約の棚卸し**。そのサービスについて、次の順で拾う。ユーザーガイドの Limits / Quotas ページ、API リファレンスのパラメータ制約、CloudFormation リソースタイプのドキュメント(スキーマではなく散文の方)、実際のデプロイ失敗エラーメッセージ。数値・順序・組み合わせ・排他・命名・リージョン依存に印を付ける。サービスが作成時バリデータを無料 API で公開している場合(Step Functions の `validate-state-machine-definition` は CreateStateMachine と同じバリデータで `--type` も取る)、定義レベルの仮説はまずそれに掛けて一次選別する(2026-09-05、100 件を数分で判定)。ここで拾ったドキュメントの 1 文は**仮説であって証拠ではない**。CloudFront の棚卸し(2026-09-02)では明文化された制約 9 件のうち 3 件が実機でそのままデプロイできた(BROKEN-EXPECTATION)。候補リストは「実機ゲートに掛ける仮説の列」として書き、ドキュメントの断言を根拠に採用を確定させない
|
|
80
80
|
2. **6 レンズで狩り場を回る**。レンズ 3 と 4 から始めると当たりが早い。**レンズに当てはまらない制約もここでは捨てない** — 足切りは次の重複ガードと、実装側の実機ゲートだけ
|
|
81
|
-
3.
|
|
81
|
+
3. **重複ガード**。残った候補ごとに最小の違反テンプレートを 1 つのディレクトリへジェネレータで吐き、素のエンジンに**全件まとめて**かける。1 枚ずつ `ts-node -e` で回さない(エンジン初期化が毎回効いて実測 51 秒/回、しかもコマンド文字列を打ち直すぶん課金される)
|
|
82
82
|
```bash
|
|
83
|
-
npx ts-node --project test/tsconfig.json -
|
|
84
|
-
import { loadEngine } from './src/private/enforce';
|
|
85
|
-
const e = loadEngine();
|
|
86
|
-
const r = new e.RegoEngine({}).validateDetailed(new e.TemplateFile('<template>'), {});
|
|
87
|
-
console.log(JSON.stringify(r.diagnostics, null, 2));"
|
|
83
|
+
npx ts-node --transpile-only --project test/tsconfig.json scripts/rule-check.ts guard <dir>
|
|
88
84
|
```
|
|
85
|
+
出力は 1 件 1 行(`BLOCK <file> <ruleId>/<severity>` か `clean <file>`)。
|
|
89
86
|
`ERROR` / `FATAL`(`source` が `SCHEMA` か `CFN_LINT`)が出たら**その候補は捨てる**。`WARN` クラスだけ、あるいは `INFO` だけならグレーゾーンなので、上流に severity の issue を出す候補として記録し、つなぎで実装するなら `upstream: pending-engine` を付ける
|
|
90
87
|
- **CLI のサービスモデルが API より古いことがある**(2026-09-05、`aws wafv2` は `Monetize` と `PreParseTextTransformations` を知らず ParamValidation で落ちた)。CLI が拒否するフィールドだけスタックを立てる。名前が scope / region 単位で一意なサービス(WAFv2)は、並列 bench のフィクスチャ名にルール ID を混ぜる
|
|
91
88
|
- **`--cli-input-json` の blob は base64**(`SearchString` を平文で書くとクライアント側で "Invalid base64" になり、サーバに届かないまま全滅する)
|
|
@@ -95,7 +92,11 @@ EOL ランタイム、廃止インスタンスタイプ、リージョン非対
|
|
|
95
92
|
|
|
96
93
|
## セッションの切り方(コンテキスト予算)
|
|
97
94
|
|
|
98
|
-
このパイプラインの API コストは **`往復回数 × 平均コンテキスト長`**
|
|
95
|
+
このパイプラインの API コストは **`往復回数 × 平均コンテキスト長`** でほぼ決まる。2026-09-08 に本プロジェクトの全トランスクリプトを集計した実測(16 セッション / 3,352 往復 / cache_read 850 Mtok / 概算 $1.9k):
|
|
96
|
+
|
|
97
|
+
- **cache_read が入力トークンの 98%**。**1 往復あたりの固定費がコンテキスト長に比例する**ので、長いセッションを続けること自体が課金される
|
|
98
|
+
- 全体平均 258k tok/往復。平均 **372k** で通したセッションはルール 1 本あたり **$5.2**、**213k** で切ったセッションは **$1.7** — 同じ「1 サービス調査 → PR」の仕事で 3 倍差
|
|
99
|
+
- コンテキストに居座っている中身は **Bash の結果 41% + 打ったコマンド 32% = 73%**、ドキュメント取得の結果 12%、thinking 5%。削る先はこの 3 つしかない
|
|
99
100
|
|
|
100
101
|
後段が必要とするのは前段の**成果ファイルだけ**で会話履歴ではない。フェーズ境界で `/clear` し、受け渡しは scratchpad の `<service>/` 配下のファイルに限る:
|
|
101
102
|
|
|
@@ -110,10 +111,11 @@ EOL ランタイム、廃止インスタンスタイプ、リージョン非対
|
|
|
110
111
|
|
|
111
112
|
守ること:
|
|
112
113
|
|
|
113
|
-
- **ドキュメント本文をコンテキストに残さない**。`read_documentation` / WebFetch は 1 ページ 20〜30k
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
114
|
+
- **ドキュメント本文をコンテキストに残さない**。`read_documentation` / WebFetch は 1 ページ 20〜30k 文字がそのまま以後の全往復ぶん再読みされる(占有シェア 12%、実測で 1 セッション 53 回・$122 相当)。ファイルに落として grep で必要な段落だけ読む。AWS のドキュメントは URL に `.md` を付ければ markdown で落ちる
|
|
115
|
+
- **4k 文字超のコマンドを打たない**。打ち込んだコマンド 2.22 Mtok のうち **63% がたった 416 回の 4k 超コマンド**(ジェネレータや rego をヒアドキュメントで流し込んだもの)。スクリプトは一度ファイルに書いて、以後は `node gen.js` と数語で呼ぶ
|
|
116
|
+
- **同じテキストを二度載せない**。書く → `cat` で確認 → diff で再表示、で 3 倍払う。確認は `wc -l` / `md5` / `assert` で済ませる
|
|
117
|
+
- 候補テンプレートを 1 件ずつ手書きしない。`candidates.json` からジェネレータで吐き、重複ガードは `scripts/rule-check.ts guard <dir>` で全件 1 プロセス。返ってくるのは 1 件 1 行
|
|
118
|
+
- **独立した呼び出しは 1 レスポンスにまとめる**(実測 3,352 往復の **55% がツール 1 個だけ**。ここは丸ごと空いている削り代)
|
|
117
119
|
|
|
118
120
|
## issue コメントの書式
|
|
119
121
|
|
package/.jsii
CHANGED
|
@@ -9599,6 +9599,6 @@
|
|
|
9599
9599
|
"symbolId": "src/index:PreflightOptions"
|
|
9600
9600
|
}
|
|
9601
9601
|
},
|
|
9602
|
-
"version": "0.0.
|
|
9603
|
-
"fingerprint": "
|
|
9602
|
+
"version": "0.0.66",
|
|
9603
|
+
"fingerprint": "E/AJjnWQnQQBzEEa+66DGuXFmNoN5Q3eFhyDAgYRsS8="
|
|
9604
9604
|
}
|
package/AGENTS.md
CHANGED
|
@@ -93,6 +93,7 @@ src/index.ts # Preflight.apply / PreflightOptions (jsii surface
|
|
|
93
93
|
src/private/enforce.ts # enforce-mode plugin (calls the engine directly)
|
|
94
94
|
src/rules.generated.ts # GENERATED from rules/ — never edit; run `npx projen bundle-rules`
|
|
95
95
|
scripts/bundle-rules.ts # generator + structural validation
|
|
96
|
+
scripts/rule-check.ts # one-process local gates: `guard` (bare engine) and `check` (fixtures, pre-bundle)
|
|
96
97
|
test/ # 4 layers: rules / loader / structure / cli
|
|
97
98
|
bench/ # real-deploy verification (needs an AWS account; not part of CI)
|
|
98
99
|
```
|
|
@@ -114,7 +115,7 @@ bench/ # real-deploy verification (needs an AWS account; no
|
|
|
114
115
|
- Helper rules must use a unique `_pf_<rule>_...` prefix (all rules share one package).
|
|
115
116
|
- A helper several rules of one service need (parsing an opaque DSL, enumerating nested scopes) goes in `rules/_lib/<service>.rego` with a `_pf_<service>lib_` prefix (`rules/_lib/sfn.rego` is the reference: ASL from `DefinitionString` *or* the L1 `Definition` object, nested Parallel/Map scopes to depth 3, effective QueryLanguage). Rules never reference another rule's helpers — `exclude` can unload any rule, a lib is always loaded.
|
|
116
117
|
- **Cheap screen for definition-level constraints**: some services expose their create-time validator as a free API (`aws stepfunctions validate-state-machine-definition --type STANDARD|EXPRESS` is the same validator CreateStateMachine runs). Use it to triage doc hypotheses before spending a CloudFormation deploy on each — 100 Step Functions hypotheses took minutes (2026-09-05). The real-deploy gate stays.
|
|
117
|
-
3. `npx projen bundle-rules`
|
|
118
|
+
3. `npx ts-node --transpile-only --project test/tsconfig.json scripts/rule-check.ts check <service|rule-id>` while iterating: it reads `rules/` straight from disk into a single engine (no bundle, no meta validation, no jest) and reports, per rule, whether the fail template fires its own rule, the pass template is silent for every rule, and neither trips a built-in ERROR/FATAL. Then `npx projen bundle-rules` and `npx jest test/rules.test.ts test/structure.test.ts` — the duplication guard and fixture checks run there for real. Prefer `jest -t` while iterating; the full suite is 3,228 tests / ~2 min (measured 2026-09-08), so keep it for the pre-PR run.
|
|
118
119
|
4. **Real-deploy gate**: `bash bench/verify-rule.sh <rule-id>` deploys the fail template (expects CREATE to fail; records the service error message) and, where cheap, the pass template (expects success, then deletes). Paste the observed error into `meta.yaml#repro.evidence` with the date. Only `doc-only` rules may skip this, with justification.
|
|
119
120
|
5. Update nothing else by hand — `docs/rules.md` and `src/rules.generated.ts` are generated.
|
|
120
121
|
|
|
@@ -122,6 +123,8 @@ bench/ # real-deploy verification (needs an AWS account; no
|
|
|
122
123
|
|
|
123
124
|
| Task | Command |
|
|
124
125
|
|---|---|
|
|
126
|
+
| Local rule gates, one process (pre-bundle) | `npx ts-node --transpile-only --project test/tsconfig.json scripts/rule-check.ts check [service\|rule-id]` |
|
|
127
|
+
| Duplication guard for candidate templates | `... scripts/rule-check.ts guard <dir>` |
|
|
125
128
|
| Regenerate bundle + docs | `npx projen bundle-rules` |
|
|
126
129
|
| Unit tests | `npx jest` |
|
|
127
130
|
| Full build (jsii, lint, tests, package) | `npx projen build` |
|
package/docs/rules.md
CHANGED
|
@@ -324,6 +324,8 @@
|
|
|
324
324
|
| `pf-events-bus-dlq-arn-type` | AWS::Events::EventBus | An event bus dead-letter queue must be an SQS queue | none |
|
|
325
325
|
| `pf-events-bus-name` | AWS::Events::EventBus | An event bus name may not be 'default' or contain '/', and a partner bus must match its source | none |
|
|
326
326
|
| `pf-events-connection-auth-parameters` | AWS::Events::Connection | AuthParameters must carry the block that AuthorizationType names, and OAuth endpoints must be HTTPS | none |
|
|
327
|
+
| `pf-events-endpoint-buses` | AWS::Events::Endpoint | A global endpoint needs two same-named buses in two Regions | none |
|
|
328
|
+
| `pf-events-endpoint-replication-role` | AWS::Events::Endpoint | Endpoint replication needs a RoleArn | none |
|
|
327
329
|
| `pf-events-input-path-jsonpath` | AWS::Events::Rule | Input paths must start at $ and avoid quoted bracket notation | none |
|
|
328
330
|
| `pf-events-input-transformer-json-var` | AWS::Events::Rule | <aws.events.event.json> needs a JSON object InputTemplate | none |
|
|
329
331
|
| `pf-events-input-transformer-limits` | AWS::Events::Rule | InputPathsMap is capped at 100 entries and may not use reserved variable names | none |
|
|
@@ -333,6 +335,10 @@
|
|
|
333
335
|
| `pf-events-pattern-operator` | AWS::Events::Rule<br>AWS::Events::Archive | Event pattern matchers must name a real operator and give it the right shape | none |
|
|
334
336
|
| `pf-events-pattern-or-exclusive` | AWS::Events::Rule<br>AWS::Events::Archive | $or cannot share an object with other keys | none |
|
|
335
337
|
| `pf-events-pattern-scalar-value` | AWS::Events::Rule<br>AWS::Events::Archive | Event pattern values must be arrays or objects, not scalars | none |
|
|
338
|
+
| `pf-events-rule-cron-fields` | AWS::Events::Rule | cron() fields must stay in range and keep | none |
|
|
339
|
+
| `pf-events-rule-name-duplicate` | AWS::Events::Rule | Two rules in one template may not share a name | none |
|
|
340
|
+
| `pf-events-rule-pattern-size` | AWS::Events::Rule | An event pattern may not exceed 2048 bytes | none |
|
|
341
|
+
| `pf-events-rule-schedule-default-bus` | AWS::Events::Rule | A scheduled rule only works on the default event bus | none |
|
|
336
342
|
| `pf-events-target-batch-parameters` | AWS::Events::Rule | Batch array size and retry attempts have service-stated bounds | none |
|
|
337
343
|
| `pf-events-target-dlq` | AWS::Events::Rule | A target dead-letter queue must be a standard SQS queue in the rule's Region | none |
|
|
338
344
|
| `pf-events-target-ecs-parameters` | AWS::Events::Rule | EcsParameters must match the launch type and stay inside its size caps | none |
|
package/lib/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const rules_generated_1 = require("./rules.generated");
|
|
|
17
17
|
* Preflight.apply(app);
|
|
18
18
|
*/
|
|
19
19
|
class Preflight {
|
|
20
|
-
static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-preflight.Preflight", version: "0.0.
|
|
20
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-preflight.Preflight", version: "0.0.66" };
|
|
21
21
|
/**
|
|
22
22
|
* Register the cdk-preflight rules on an App or Stage.
|
|
23
23
|
*/
|