Pin Sanitize's substitution and what it leaves alone
メンテナーはふだん 1 日以内に返信
@soyeladice-svg がすでに取り組んでいます。
2026年9月29日 から。
評価
調査の方向性
まず internal/display/sanitize_test.go と、issue に記載されている Sanitize の動作を確認します。正確な出力を検証するテーブル駆動のケースに加え、ルーン数と冪等性のケースを追加します。env GO111MODULE=on go test ./internal/display と、受け入れ基準に記載されているミューテーションチェックを実行します。これらのチェックで指定された変更を検出でき、リポジトリ全体に必要なテスト、vet、フォーマットチェックが通れば完了です。
索引モデルが issue の本文から書いたものです。
説明
Goal
Add focused tests for Sanitize in internal/display/sanitize.go.
Why
// Sanitize removes terminal controls and bidi overrides from untrusted labels.
func Sanitize(value string) string {
var output strings.Builder
for _, char := range value {
if unicode.IsControl(char) || unicode.Is(unicode.Cf, char) || unicode.Is(unicode.Zl, char) || unicode.Is(unicode.Zp, char) {
output.WriteRune('?')
continue
}
output.WriteRune(char)
}
return output.String()
}
This is the one place the runtime neutralizes text it did not write. display.Sanitize appears on 296 lines across 20 files, among them the human renderer (internal/cli/render.go), the MCP tool surface (internal/mcp/tools.go), and the carrier decoder (internal/carrier/decode.go). The strings handed to it are pack ids, decision ids, reasons, fact pointers, and diagnostic text — authored elsewhere, so untrusted whenever someone runs jpack against a pack they did not write.
It has one test, and Sanitize sits at 100% statement coverage. Those two facts are not in tension. internal/display/sanitize_test.go is twenty lines and holds a single case that feeds one string and then re-checks the same four Unicode predicates the function itself uses; full coverage of a line says the line ran, not that anything about it is held in place. What that test pins is the class of character removed, and nothing else around it:
- ESC (U+001B), the introducer of an ANSI escape sequence and the most common terminal-injection vector, does not appear anywhere in the test file — nor in any test file in the repository;
- nothing pins what a removed character becomes — only that it is no longer a control, so replacing
'?'with anything, or with nothing, still passes; - nothing pins one-rune-in-one-rune-out, so a change that dropped characters instead of substituting them would pass;
- U+2029 (Zp) appears nowhere, so that predicate can be deleted from the
ifwith the whole suite still green; - nothing pins the far side of the boundary. The existing case does show the ASCII runs
safeandtextsurviving, but nothing shows that an ordinary space, or a non-breaking space (U+00A0, category Zs), survives unchanged — which is what keeps a sanitized label readable rather than mangled.
Behaviour today, for the cases worth pinning:
"\x1b[31mred" -> "?[31mred" // the introducer goes; the rest is inert text
"a\tb\nc" -> "a?b?c" // a label cannot open a new line
"\x7f" -> "?" // DEL
"a b" -> "a b" // an ordinary space survives
"a b" -> "a b" // a non-breaking space survives — Zs, not Cf
"\U0001F600" -> "\U0001F600" // a multi-byte rune survives
Scope
- Change
internal/display/sanitize_test.goonly. - Table-driven,
t.Runper case, asserting the exact output string rather than a property of it. Cover at least: ESC and a full ANSI colour sequence; tab, newline and carriage return; DEL (U+007F); a C1 control (U+009B); a bidi override (U+202E, Cf); a line separator (U+2028, Zl); a paragraph separator (U+2029, Zp); plain ASCII; a string containing an ordinary space; a non-breaking space (U+00A0); a multi-byte character and an emoji; the empty string. - Add one case pinning that the output has the same rune count as the input.
- Add one case pinning idempotency:
Sanitize(Sanitize(s)) == Sanitize(s). - Do not change
Sanitize, and do not change any caller. If the substitution character or the predicate list looks wrong, open a separate issue rather than editing it here.
Acceptance criteria
- Every case asserts the exact expected string.
- ESC (U+001B) has a case, and that case shows what survives it.
- The substitution character is pinned by at least one case.
- At least one case shows a character the function deliberately leaves alone.
- Rune count and idempotency each have a case.
- Mutation check, run locally before opening the pull request and reported in it: changing
'?'to another rune fails a case in your new file, and deleting any one of the four predicates from theiffails a case in your new file. Both of those pass the whole suite as it stands today — and deleting theunicode.Zppredicate is caught by nothing at all — so a criterion met only by the existing test does not count. -
env GO111MODULE=on go test ./internal/displayandenv GO111MODULE=on go test ./...pass;gofmt -l .prints nothing;env GO111MODULE=on go vet ./...is clean. - Every commit includes a DCO sign-off created with
git commit -s.
Contributor learning
Why a tool that prints text it did not author routes all of it through one sanitizer instead of trusting call sites; how to pin a transformation by its output instead of restating its implementation in the assertion; and why 100% statement coverage said nothing about either.
- 主要言語
- Go
- スター
- 2
- フォーク
- 6
- 平均マージ
- 13時間 16分
- マージ済み PR(30日)
- 76
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
Judgment-Pack/judgment-pack-runtime のほかの issue
-
Pin which layer refuses an evaluation-corpus pack path再び着手できるかも @soyeladice-svg が 17 日前に担当しましたが、オープン中のプルリクエストはありません。 オープンgo good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
Judgment-Pack/judgment-pack-runtime#120 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
-
Boundary-test the decimal comparison operand grammar再び着手できるかも @soyeladice-svg が 17 日前に担当しましたが、オープン中のプルリクエストはありません。 オープンgo good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
Judgment-Pack/judgment-pack-runtime#118 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
-
Expose read-only fact-type advice before test expectations are authored対応中かも @kikashy が 3 日前に担当しました。 オープン
Judgment-Pack/judgment-pack-runtime#274 · 担当者 1 名 ·
メンテナーはふだん 1 日以内に返信
-
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
Judgment-Pack/judgment-pack-runtime#272 ·
メンテナーはふだん 1 日以内に返信
-
Assert every refusal the `uri` format checker makes, including a truncated percent escape再び着手できるかも @soyeladice-svg が 17 日前に担当しましたが、オープン中のプルリクエストはありません。 オープンgo good first issue
難易度 3/5 1〜2日 初心者へのやさしさ 57/100
Judgment-Pack/judgment-pack-runtime#173 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
Judgment-Pack/judgment-pack-runtime の issue をすべて見る
似ている issue
-
bug frontend grammar sev-3
難易度 2/5 1〜3時間 初心者へのやさしさ 63/100
-
connector docs good first issue
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
soma-intelligence/open-health-sync#134 ·
メンテナーはふだん 1 日以内に返信
-
bug frontend
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
メンテナーはふだん 3 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 72/100
メンテナーはふだん 1 日以内に返信
-
oss/0 pending team/container-integrations
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
DataDog/datadog-agent#58323 ·
メンテナーはふだん 1 日以内に返信