この記事で起きたこと
macOS 26.5.1 (Tahoe) アップデート直後、メニューバーから時計が消えた。
設定値を全部確認した。defaults read com.apple.controlcenter の NSStatusItem Visible Clock は 1、_HIHideMenuBar は 0、ステージマネージャは無効、MDMプロファイルも無し。設定はすべて正しい。それでも描画されない。
サードパーティの時計アプリ (Itsycal) を入れようとしたが、そもそもメニューバー自体が出ない状態では意味がない。Marketplaceの時計拡張も検討したが、2024年以降のVSCode拡張サプライチェーン攻撃を踏まえると、よくわからない作者の拡張を入れる気にはなれなかった。
最終的に、vscode API と Node 標準だけで書いた 50行未満の自前拡張 をローカルに配置して解決した。所要時間は30分。
この記事では、その判断の根拠と、誰でも真似できる実装手順を残す。
環境
| 項目 | 値 |
|---|---|
| macOS | 26.5.1 (Build 25F80) |
| VSCode | 1.80以上 |
| Node.js | 任意 (拡張は vsce パッケージング不要なので不問) |
なぜサードパーティ拡張を避けたか
VSCode の Marketplace は npm と同じく publisher 審査が緩い。Apple App Store のような事前審査がなく、ダウンロード数の偽装も指摘されている。実害が出た事例:
-
2024-05: 偽の
Prettier拡張が PowerShell バックドアを仕込んで配布されていた -
2024-10: 数百万ダウンロードを持つ
Material Themeの作者アカウントが乗っ取られ、悪意あるコードが混入したバージョンが公開された - 2025年に入っても、VS Code Marketplace に対する偽装・タイポスクワッティング (typosquatting / 正規パッケージ名に似せた偽パッケージ) の事例は止まっていない
時計の表示という機能の小ささに対して、Publisher の素性確認・ソースコードレビュー・更新ごとの再レビュー の運用コストが見合わない。「verified バッジ」も完全な保証ではない (作者アカウント自体が乗っ取られるケースを防げない)。
「個人開発者の善意で動いているOSS」が、ある日 1コミットの差し替えで攻撃ベクタになりうる。これは VSCode 拡張に限った話ではなく、npm の event-stream 事件 (2018) や PyPI の度重なるタイポスクワッティング事件と同じ構造の問題 (= サプライチェーン攻撃)。
なぜ自作なら安全と言えるか
自前拡張には、サードパーティ拡張にはない3つの性質がある。
- 全文目で追える分量: 後述するコードは package.json と extension.js の合計で50行未満。1分で読み切れる
-
外部依存ゼロ:
vscodeAPI (= VSCode 本体が提供) と Node 標準ライブラリしか使わない。npm installで別パッケージを引き込まない -
ローカル運用: Marketplace に公開せず、自分のマシンの
~/.vscode/extensions/に置くだけ。配布経路がそもそも存在しないので、サプライチェーン攻撃の入口がない
「自分が書いたコードしか動かない」という状態は、サードパーティ拡張では絶対に作れない。これが自作の最大の利点。
実装: package.json (20行)
package.json は拡張のメタデータ。vscode の最小バージョン、エントリーポイント、設定スキーマを宣言する。
{
"name": "statusbar-clock",
"displayName": "Statusbar Clock",
"description": "Show current date/time in VSCode status bar (local-only, zero dependencies)",
"version": "0.1.0",
"publisher": "nomuraya-local",
"private": true,
"engines": {
"vscode": "^1.80.0"
},
"main": "./src/extension.js",
"activationEvents": [
"onStartupFinished"
],
"contributes": {
"configuration": {
"title": "Statusbar Clock",
"properties": {
"statusbarClock.format": {
"type": "string",
"default": "yyyy-MM-dd (EEE) HH:mm:ss",
"description": "Display format. Tokens: yyyy MM dd HH mm ss EEE(weekday)"
}
}
}
}
}
ポイント:
-
activationEvents: ["onStartupFinished"]: VSCode 起動完了後にロードされる。起動を遅らせない -
contributes.configuration: VSCode 設定画面に項目を出す宣言。これだけで Cmd+, から書式を変更できるようになる -
publisher: "nomuraya-local": ローカル用の任意名。Marketplace に出さないので衝突を気にしなくてよい
実装: extension.js (30行)
VSCode拡張は activate(context) 関数を export すれば動く。ステータスバーアイテムを1つ作って、setIntervalで毎秒テキストを更新するだけ。
const vscode = require('vscode');
const WEEKDAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
function pad(n) { return String(n).padStart(2, '0'); }
function formatDate(fmt, d) {
return fmt
.replace('yyyy', d.getFullYear())
.replace('MM', pad(d.getMonth() + 1))
.replace('dd', pad(d.getDate()))
.replace('HH', pad(d.getHours()))
.replace('mm', pad(d.getMinutes()))
.replace('ss', pad(d.getSeconds()))
.replace('EEE', WEEKDAYS[d.getDay()]);
}
let statusBarItem;
let timer;
function activate(context) {
// ステータスバー右側にアイテムを1つ作る。第2引数 priority=1000 で右端寄り
statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 1000);
statusBarItem.show();
context.subscriptions.push(statusBarItem);
// 1秒ごとに表示を更新
const update = () => {
const fmt = vscode.workspace.getConfiguration('statusbarClock').get('format');
statusBarItem.text = formatDate(fmt, new Date());
};
update();
timer = setInterval(update, 1000);
// 拡張がdeactivateされたときに setInterval を止める
context.subscriptions.push({ dispose: () => clearInterval(timer) });
}
function deactivate() {
if (timer) clearInterval(timer);
if (statusBarItem) statusBarItem.dispose();
}
module.exports = { activate, deactivate };
使っている VSCode API は3つだけ:
| API | 役割 |
|---|---|
vscode.window.createStatusBarItem(alignment, priority) |
ステータスバーに表示枠を作る |
statusBarItem.text = "..." |
表示文字列を更新する |
vscode.workspace.getConfiguration("ns").get("key") |
設定画面で書いた値を読み取る |
ネットワークアクセス・ファイル読み書き・child_process の呼び出しは一切無い。この拡張ができることは「ステータスバーに文字を表示する」だけ。仮に私のコードがバグっていてもセキュリティ事故にはならない、という安心感がある。
配布: vsixビルド不要、symlink 1本で完了
通常のVSCode拡張は vsce package で .vsix を作って code --install-extension で入れる。が、私の環境では node 24 の npm が壊れていて vsce が動かなかった (CJS ローダーの MODULE_NOT_FOUND)。
代わりに、~/.vscode/extensions/ に symlink を貼るだけで開発モード拡張として認識される。
EXT_DIR="$HOME/.vscode/extensions/nomuraya-local.statusbar-clock-0.1.0"
mkdir -p "$HOME/.vscode/extensions"
ln -s ~/workspace-ai/nomuraya-tools/vscode-statusbar-clock "$EXT_DIR"
ディレクトリ名の規約は <publisher>.<name>-<version>。package.json の publisher, name, version と一致させる。
配置後、VSCode を Cmd+Q で完全終了して再起動すれば、ステータスバー右下に 2026-06-09 (Tue) 07:23:45 が秒単位で表示される。
動作確認後の状態
- VSCodeを開いている間は常時時刻が見える (= メニューバーが死んでいても問題ない)
- 設定 (Cmd+,) で
statusbarClock.formatを変更すれば書式変更可。例:"HH:mm"(時刻だけ) /"MM/dd HH:mm"(短縮形) - アンインストールしたければ symlink を
rmするだけ。レジストリ汚染も settings.json の残骸も無い
まとめ: 「動くものを書ける」スキルがセキュリティの最終防衛線
サプライチェーン攻撃の流れは止まらない。npm, PyPI, VSCode Marketplace, Chrome Web Store のどれもが、過去数年で実害のある事故を経験している。「verified バッジ」も「ダウンロード数」も完全な保証ではない。
最終的に確実なのは、自分が読めるサイズのコードを自分で書くこと。
50行の拡張を書くために必要な VSCode API は、createStatusBarItem と setText と getConfiguration の3つだけだった。30分で動いた。これは特別なスキルではなく、ドキュメントを読みながら書ける範囲の話だ。
メニューバーが沈黙したから、ステータスバーに時計を出した。それだけの話だが、サードパーティ拡張に頼らない選択肢を1つ持っておくと、「Material Theme作者乗っ取り事件」のニュースを見たときに自分のマシンが安全だと言い切れる範囲が広がる。