1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Page 1 of 2

この記事で起きたこと

macOS 26.5.1 (Tahoe) アップデート直後、メニューバーから時計が消えた。

設定値を全部確認した。defaults read com.apple.controlcenterNSStatusItem Visible Clock1_HIHideMenuBar0、ステージマネージャは無効、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つの性質がある。

  1. 全文目で追える分量: 後述するコードは package.json と extension.js の合計で50行未満。1分で読み切れる
  2. 外部依存ゼロ: vscode API (= VSCode 本体が提供) と Node 標準ライブラリしか使わない。npm install で別パッケージを引き込まない
  3. ローカル運用: 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作者乗っ取り事件」のニュースを見たときに自分のマシンが安全だと言い切れる範囲が広がる。

参考

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?