Skip to content

v0.6.22 — 前の版で直したつもりの欠陥が、2 か所残っていました

Choose a tag to compare

@Driedsandwich Driedsandwich released this 15 Aug 12:00
· 20 commits to main since this release

v0.6.22 — 前の版で直したつもりの欠陥が、2 か所残っていました

⚠ 先に読むところ

1. 同じ根が 3 か所ありました。前の版で直したのは 1 か所です

v0.6.21 で「oneOf の枝が $ref のとき参照先の変更が見えない」を直しました。
外部監査が、同じ根の反例を 2 件返してきました。

原因は 1 つです。判定器は「節の文字列が変わっていない」を
意味が変わっていない」の証拠にしていました。$ref は参照先を指すだけなので、
指す先が変われば、文字列は同じまま意味が変わります。

その置き方が 3 か所ありました。

場所 直した版 見つけた人
oneOf の枝の比較 v0.6.21 こちらの property-based 試験
同上・枝に sibling がある形 この版 外部監査
allowlist ゲート(未対応 keyword が $ref を包む) この版 外部監査
anyOf / allOf の早期 continue この版 こちら

3 つ目は監査の指摘にありません。直す前に
「文字列の一致を意味の一致と置いた箇所」を数え直したときに出ました。
1 件目だけ直して終わりにすると、次の監査で同じものが返ってきます。

2. どちらも危険側です。受け手が拒む向きの誤りです

反例1  oneOf の枝が { $ref: '#/definitions/d0', description: 'branch' }
       旧 d0.type = 'string'  →  新 d0.type = ['string','null']

反例2  definitions.outer = { not: { $ref: '#/definitions/inner' } }   ← 新旧まったく同じ
       旧 inner.type = ['string','null']  →  新 inner.type = 'string'

どちらも ajv  {"x":null} が旧 invalid → 新 valid  = **言語が広がっている**
        判定  HOLD(据え置き可)                  ← **上げるべきなのに上げない**

反例 2 は not の中が狭まると外は広がる形です。

**受け手への影響。**版が据え置かれると、受け手は旧 schema を pin したままになります。
新しい版が null を出した瞬間、受け手の検証が落ちます。

現行 schema への影響はありません。$ref + sibling は現行 schema に 3 件
evidenceGrade が 3 版すべてでこの形)ありますが、いずれも properties の位置で、
そこは前から正しく判定していました。
実 schema 194 対(現行 25 schema × 直近 8 tag)で判定は 1 件も変わっていません。

3. 回帰テストを先に入れてから直しました

v0.5.1 / v0.5.2 / v0.6.21 と同じ順序です。

① 回帰テストを入れる(条文 ①-c4 / ①-c5)  → 2 件とも落ちることを実測
② 判定器を直す
③ 通ることを確認
④ 直した 3 か所を 1 つずつ戻す           → A 落ちる / B 落ちる / **C 落ちない**
⑤ C 用のテスト(①-c6)を足す            → C も落ちるようになった

④ で 1 か所が「外しても落ちない行」になっていました。
anyOf/allOf の経路に実害のある反例が在ることを ajv で確かめてから、
テストを足しています。変異で落ちない修正は、入れた証拠がありません。

4. 前の版の試験が見逃した理由は 2 つで、どちらも「0 件」でした

v0.6.21 の notes に、こう書きました。

値は schema 対から作りますが、作れない値があれば広がりを見逃します。

そこがそのまま当たりました。

                                    v0.6.21   v0.6.22
枝・property 位置の $ref + sibling     0 件      20 件   ← 形を作れていなかった
候補値のうち「property が null」        0 件      85 件   ← 証人を作れていなかった

監査の反例 2 件は、どちらも証人が {"x": null} です。
当時の生成器は 300 種を作ってその形を 1 件も含めず
証人合成は 6,219 候補を作って**「1 つの key だけが null」を 1 件も作りません**でした。
どちらか片方でも 0 なら、判定器を直しても試験は自力で見つけられません。

補強したうえで v0.6.21 の判定器に対して回すと、自力で反例を出しました
(seed 266・枝が {$ref, description}・参照先の type が広がった形)。
手書きの反例を抜いた状態での実測です。

5. schemaId を名乗りながら、その schema を配っていませんでした

release-stage-attestation.v1.json(最終関門の記録)は前から
schemaId: trs-jack-3d-release-stage-attestation.v1 と名乗っていましたが、
**対応する schema を配っていませんでした。**受け手は名乗っている形を検証できません。

記録の中身は正しいものでした。欠けていたのは確かめる手段です。
検査していたのは stageRelease.mjs文字列だけで
(「exitCode: と書いてあるか」)、生成された実物は見ていませんでした。

この版で schemas/release-stage-attestation.v1.schema.json を配ります。
release:stage記録を書く前に実 object を検証し、
合わなければ記録も SHA256SUMS も出さずに止まります
(書いてから検証すると、落ちたときに「途中まで正しく見える記録」が残ります)。

testEvidenceCrossBound を必須欄へ入れました——それまで必須一覧にありませんでした。

6. tag の中の SECURITY.md が、恒久的に 1 版古くなっていました

v0.6.18 の tag → 「現時点では v0.6.17」
v0.6.19 の tag → 「現時点では v0.6.18」
v0.6.20 の tag → 「現時点では v0.6.19」
v0.6.21 の tag → 「現時点では v0.6.20」     4/4 tag で実測

**工程上どうやっても直りません。**release を作る commit の時点では、
その版はまだ公開されていないので、書ける最新は 1 つ前です。

検査は手元の控えの最大版数でこの行を縛っていたので main では常に正しく、
だからこそ誰も気づきませんでした。受け手が読むのは tag の中身です。

版数を書かず「GitHub Releases で Latest と表示されている 1 本」を指す形へ変え、
版数を書き足したら止まる検査を入れました。

版数を上げていない根拠(すべて実測)

toolVersion 20 / CLI 結果契約 schemaVersion 2 / profile schemaVersion 3 のままです。

判定器は配布物か        **違う**(releaseAssets に 0 回)
配る検算ツール          v0.6.20・v0.6.21 と **byte 一致**
実 schema での判定       **194 対中 0 件が変化**(現行 25 schema × 直近 8 tag)
CLI 出力の 10 経路       基準と byte 一致
profile のモデル数値     **0 件が変化**(葉 2267 / 3130 のうち、動いたのは由来 8 件だけ)

⚠️ **「何も変わらない」ではありません。**上の 3 つの形では判定が HOLD → BUMP へ変わります。
**それが今回直した欠陥です。**現行 schema にその形が無いので、
実 schema での判定が変わらなかっただけです。

配る asset は 27 件 → 28 件になりました(attestation の schema を足したため)。
足したのは schema だけで、記録そのものは索引の外のままです(自己参照を避けるため)。

依存の advisory(踏む経路つき)

npm audit が high を 1 件出します。踏む経路は無いと測りました。

nanoid 3.3.16 (<3.3.18)  GHSA-2v37-7h3g-55p8
経路    vite → postcss → nanoid(推移依存)
区分    **dev のみ**(npm ls nanoid --omit=dev が空。対照として three は解決する)
出荷物  **入っていない**(dist/assets/*.js に nanoid が 0 件。対照として three は 1 件)

**まだ上げていません。**詳しくは SECURITY.md に書きました。

まだやっていないこと

  • **実測が 1 件も来ていません。**接点位置は全部仮定のままで、
    導通測定も音響測定もしていません(verifiedPhysicalfalse)。
  • property-based 試験が見ているのは 1 つの性質だけです
    (「新だけが通す値が実在するなら BUMP」)。今回その限界がそのまま当たりました。
    補強しましたが、次に見逃す形も、いまは 0 件に見えます。
  • BusyBox を oracle に足すこと(開発機にも CI にもありません)。
  • annotated tag への署名(v0.6.22 も署名なしです)。
  • 公開済み asset の定期確認(npm run check:published-assets は在りますが、
    定期実行にはしていません)。

数えたもの

v0.6.21 v0.6.22
単体テスト 1410 1433(skip 0 / 失敗 0)
配る asset 27 28(attestation の schema)
schema 25 26
検算ツール toolVersion 20 変わらず 20
CLI 結果契約 schemaVersion 2 変わらず 2
止め方の名前(catalog) 82 種類 変わらず 82
出力の基準(経路) 10 変わらず 10(全件 byte 一致)
検証対象(validate:profiles 14 14
記録された入力 32 32
区間 / event TRS 23/32・TRRS 30/36 変わらず

変わっていないもの

  • **モデルの数値。**接点位置も走査結果も同じです。
  • verifiedPhysicalfalse。実測記録は依然 0 件です。
  • IV028 は 13.30–13.52 mm / ASSUMPTION / ground-open-differential /
    RETURN_OPEN_L_AND_R_ON_DISTINCT_CONDUCTORS のままです。
  • toolVersion 20 / CLI 結果契約 schemaVersion 2 / profile schemaVersion 3 / catalog 82 種類。
  • 止め方の名前の一覧・archivePolicy・status・終了コードの意味。