Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Pin Sanitize's substitution and what it leaves alone

オープン 初心者向け
#119 コメント 3 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@soyeladice-svg がすでに取り組んでいます。

2026年9月29日 から。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
82/100
issue の種類
機能追加
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
go
領域
testing

調査の方向性

まず internal/display/sanitize_test.go と、issue に記載されている Sanitize の動作を確認します。正確な出力を検証するテーブル駆動のケースに加え、ルーン数と冪等性のケースを追加します。env GO111MODULE=on go test ./internal/display と、受け入れ基準に記載されているミューテーションチェックを実行します。これらのチェックで指定された変更を検出でき、リポジトリ全体に必要なテスト、vet、フォーマットチェックが通れば完了です。

索引モデルが issue の本文から書いたものです。

説明

go good first 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 if with the whole suite still green;
  • nothing pins the far side of the boundary. The existing case does show the ASCII runs safe and text surviving, 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.go only.
  • Table-driven, t.Run per 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 the if fails a case in your new file. Both of those pass the whole suite as it stands today — and deleting the unicode.Zp predicate is caught by nothing at all — so a criterion met only by the existing test does not count.
  • env GO111MODULE=on go test ./internal/display and env 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

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

Judgment-Pack/judgment-pack-runtime のほかの issue

Judgment-Pack/judgment-pack-runtime の issue をすべて見る

似ている issue

Go の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。