Web Scratch
フィード

automerge-gate: GitHubのAuto Mergeをひとつの必須チェックに集約するGitHub Action
Web Scratch
GitHubのAuto Mergeをひとつの必須チェックに集約するためのGitHub Action automerge-gate を作ったので紹介します。GitHub: pkgdeps/automerge-gate背景: GitHubの必須チェック設定はPRごとの揺らぎに弱い前提として、GitHubのAuto Mergeを使うには、必須チェック未達成のPRをマージできない状態にするBranch protection ruleやRulesetの設定が必要です。これらの保護機能でPRがブロックされる状態を作ったうえで、すべての必須チェックが成功した時点でAuto Mergeが発火する、という仕組みになっています。逆に言うと、Auto Mergeを使うには何かしらのステータスチェックを必ず必須に入れる必要があります。そして、Branch protection ruleやRulesetは、マージに必要なステータスチェックを名前で列挙する形式です。この方式は次のような場面で壊れやすいという問題があります。RenovateやDependabotなど外部のGitHub Appが追加するチェックは、PRごとにあったりなかったりするmonorepoでパスフィルタを使っていると、ワークフローがPRによってスキップされたりされなかったりする新しいワークフローを追加する度に、Rulesetを書き換える必要があるGitHubのRulesetは複数の必須チェックをANDでつなぐ(全部成功すること)しか表現できないため、「チェック群のうちどれかが走っていればよい」みたいな条件は書けません。そのため、PRごとに発火するチェックが違うケースだと、片方のPRでは存在しないチェックを必須にしてしまい、いつまでもマージできないという状態が発生します。この問題への対処として、必須チェックを1つのステータスに集約するupsidr/merge-gatekeeperを使っているケースも多いです。自分もtextlintなどのオープンソースプロジェクトや、プライベートリポジトリで使っていました。CI: add Merge Gatekeeper workflow for pull requests by azu · Pull Request #1577 · textlint/textlint最近はmerge-gatek
5時間前

Secretlint v13.0.0リリース: .gitignore済みをデフォルトで無視、Tailscale/Stripe/Cloudflareの検出に対応
Web Scratch
ソースコードや設定ファイルに含まれるAPIトークンやパスワードなどの機密情報を見つけるSecretlintのv13.0.0をリリースしました。Release v13.0.0 · secretlint/secretlintこのバージョンの主な変更点は次の3つです。ファイル探索時に.gitignoreをデフォルトで尊重するように変更(Breaking Change)グロブメタ文字を含むパスが実在する場合はリテラルとして扱うように変更Tailscale/Stripeの検出ルールを新規追加、CloudflareをcanaryからrecommendへPromoteBreaking Change: .gitignoreをデフォルトで尊重v13.0.0では、ファイル探索時に.gitignoreの内容をデフォルトで尊重するようになりました。ripgrepと同じ挙動で、ネストされた.gitignoreファイルもサブディレクトリへカスケードして適用されます。深い階層のネガティブルール(!)で上位の判定を上書きできます。feat!: respect .gitignore by default via @secretlint/walker by azu · Pull Request #1530.gitignoreに一致したファイルはスキャン対象から除外されます。そのため、これまでdist/や生成物などを意図的にスキャンしていたプロジェクトでは、出力されるファイル数が減ります。.secretlintignoreはこれまで通り併用できます。v12までの挙動に戻したい場合は、--no-gitignoreオプションを指定します。secretlint --no-gitignore "**/*".gitignoreに一致しているはずのファイルが結果に含まれている場合は、Issueで報告してください。Issues · secretlint/secretlint実装: @secretlint/walkerv13.0.0では、ファイル探索の実装をglobbyから、新しく追加した@secretlint/walkerへ置き換えました。設計はplanドキュメントとしてリポジトリにコミットされています。docs/superpowers/plans/2026-05-03-walker-gitignore-cascad
9日前

JavaScript PrimerのES2026対応を手伝ってくれるContributorとSponsorを募集しています
Web Scratch
JavaScript Primer (https://jsprimer.net/) では、毎年ECMAScriptの新しい仕様への追従を行っています。ES2026は2026年6月に正式リリースされる予定です。TC39ではすでにFeature Freezeが行われ、ES2026に入る予定の機能が確定しています。TC39 Process今年もES2026で追加される機能についての対応Issueを作成しました。これらのIssueを一緒に進めてくれるContributorと、JavaScript Primerの活動を支援してくれるSponsorを募集しています。次のDiscussionにコメントをください募集しているDiscussion: ES2026に対応するIssueへのContributorを募集しています · js-primer/js-primer · DiscussionsES2026対応のIssueES2026のMeta Issueとして次のIssueがあります。ES2026の対応 · Issue #1869 · js-primer/js-primer具体的に対応するものとして次のIssueを作成しています。ES2026: Error.isError · Issue #1872 · js-primer/js-primer見積もり: 2 pointES2026: Map.prototype.getOrInsert / getOrInsertComputed (Upsert) · Issue #1873 · js-primer/js-primer見積もり: 3 pointES2026: JSON.rawJSON (JSON.parse source text access) · Issue #1874 · js-primer/js-primer見積もり: 2 pointES2026: Iterator.concat (Iterator Sequencing) · Issue #1875 · js-primer/js-primer見積もり: 2 point各Issueには、作業量の見積もりとしてpointを付与しています。(これは感覚値なのであんまり正確ではないです。実際にやってみたら変わる可能性もあります)このpointは、作業の難易度や必要な調査量などを考慮して設
13日前

Secretlint v12.0.0リリース: Groq、Hugging Face、Notion、GitLab、Grafana、HashiCorp Vault、Vercel、Databricks、Docker、Figmaの検出に対応
Web Scratch
ソースコードや設定ファイルに含まれるAPIトークンやパスワードなどの機密情報を見つけるSecretlintのv12.0.0をリリースしました。Release v12.0.0 · secretlint/secretlintこのバージョンでは、次のように追加で検知できるようになったサービスが10個あります。Groq、Hugging Face、Notion、GitLab、Grafana、HashiCorp Vault、Vercel、Databricks、Docker、Figmaあわせて、@secretlint/secretlint-rule-preset-recommendのパッケージサイズを約80%削減しています。新しく追加された検出ルール@secretlint/secretlint-rule-preset-recommendに、次の10個のサービスのAPIトークンなどを検出するルールが追加されました。Groq - gsk_から始まるAPIキーHugging Face - hf_から始まるUser Access TokenNotion - secret_/ntn_から始まるIntegration TokenGitLab - Personal Access Token、Pipeline Trigger Token、Runner Registration TokenなどGrafana - Service Account TokenやCloud Access Policy TokenHashiCorp Vault - hvs./hvb.から始まるトークンVercel - Access TokenDatabricks - dapiから始まるPersonal Access TokenDocker - dckr_pat_から始まるPersonal Access TokenとDocker Hub認証情報Figma - figd_/figu_/figoa_などで始まるトークン@secretlint/secretlint-rule-preset-recommendを使っている場合は、v12.0.0にアップデートすると自動的にこれらのルールも有効になります。今回追加したトークンは、GitHubのSecret scanning partnerのリストを参照することで、確度の高いパターンを持つ
24日前

SecureClipboard: クリップボードに入った機密情報を自動でマスクするmacOSアプリ
Web Scratch
クリップボードを監視して、機密情報やAPIトークンが入ったら自動的にマスクするmacOSアプリ SecureClipboard を作りました。GitHub: secretlint/secure-clipboardテキストだけでなく画像にも対応していて、スクリーンショットに写り込んだトークンなどもVision frameworkでOCRしてマスクします。内部ではsecretlintを使って、AWS、GitHub、Slack、GCP、Azure、npm、Dockerなどのトークンを検出します。スキャン処理はすべてローカルで完結するmacOSアプリケーションなので、クリップボードの内容が外部に送信されることはありません。なぜ作ったかAPI Tokenをコピーして.envへ貼り付けたあと、そのトークンがクリップボード上に残り続けることがあります。そのまま別のウィンドウで⌘+Vしてしまい、Slackのメッセージ欄やLinearのIssueタイトル、ブラウザの検索バーなどに意図せずペーストしてしまう事故が起きやすいです。ペーストするまでクリップボードに何が入っているかは目に見えないので、気づきにくいというのも問題です。SecureClipboardはコピーされた瞬間にマスクするため、誤ってペーストしても安全になります。本物のトークンが必要なときはメニューから”Copy Original Text”を選ぶと取り出せますが、90秒後に自動でクリップボードから消えるようになっています。これは1Passwordのクリップボードクリアと同じ仕組みです。画像の場合も同様で、スクリーンショットを撮ってどこかに貼り付けるときに、意図しない映り込みを自動で防止します。たとえばClaude Codeのターミナル画面をスクリーンショットしたときに、たまたまAPIキーや隠したいコードネームなどが含まれていた、というケースを防げます。主な機能SecureClipboardの主な機能は次のとおりです。クリップボードを監視して、自動的にマスキングテキスト:secretlintでスキャンして、検出した機密情報を***に置換画像:Vision frameworkでOCRして、検出した領域だけをcrystallize + blurでマスク検出時はメニューバーアイコンが赤くなり、macOSの通知を表示“Copy O
25日前

dockerfile-pin: DockerfileやComposeのイメージをSHA256でピン留めするCLIツールを作った
Web Scratch
DockerfileやComposeファイルのイメージ参照に@sha256:<digest>を自動で追加するCLIツール dockerfile-pin を作りました。GitHub: azu/dockerfile-pinなぜ作ったかtrivyへのサプライチェーン攻撃などの事件を見ていると、次に狙われるのはDocker Hubかなと思ったのがきっかけです。CIでDocker Hubへのpushをしているケースは多いので、そこに悪意あるコードが混入する事件は今後も起きるだろうと思っています。Dockerイメージのタグ(例:node:20)はデフォルトで可変(mutable)です。同じタグ名で中身を上書きできるため、悪意ある第三者がレジストリへのアクセスを得た場合、既存タグに対して改竄されたイメージをpushできます。Can a Docker Hub tag have its content changed? - Docker Community ForumsDocker Hubなどのレジストリは安全とは限りません。npmのようにトークンの制限が厳しくなっていたり、デフォルトでタグがimmutableな場所であっても、axiosのように問題が起きることはあります。Docker HubにはImmutable tagsという機能がありますが、これはリポジトリオーナー側が設定するもので、イメージを利用する側がコントロールできるものではありません。@sha256:<digest>を付与することで、イメージの不変性を保証できます。digestはイメージのコンテンツハッシュなので、内容が異なればdigestも変わり、改竄を検知できます。npmのlockfileがパッケージのintegrityをハッシュで固定するのと同じ考え方です。# Before: タグのみ(可変)FROM node:20.11.1# After: タグ + digest(不変)FROM node:20.11.1@sha256:e06aae17c40c7a6b5296ca6f942a02e6737ae61bbbf3e2158624bb0f887991b5タグとdigestを両方残す形式にしておくと便利です。タグは人間が読むため、digestは不変性の保証のために残します。Renovateはこの形式でタグとdigestの
1ヶ月前

design-loop: Claude Codeを使ったブラウザベースのビジュアル編集ツール
Web Scratch
Claude Codeを使ったブラウザベースのビジュアル編集ツールとして、design-loopを作りました。GitHub: https://github.com/azu/design-loop左パネルに開発中のサイトのプレビュー、右パネルにClaude Codeのターミナルが表示されます。プレビュー上の要素をクリックすると、その要素のコンポーネント情報やスタイルがClaude Codeに渡されます。インストールcurl -fsSL https://raw.githubusercontent.com/azu/design-loop/main/install.sh | sh使い方ソースコードがあるディレクトリで、開発サーバーがすでに起動している場合は、--urlでURLを指定するだけで起動できます。design-loop --url http://localhost:3000--commandオプションを使うと、開発サーバーの起動もdesign-loopに任せられます。開発サーバーが起動してからプロキシが自動的に接続します。design-loop --url http://localhost:3000 --command "npm run dev"起動すると、プレビューとClaude Codeのターミナルを統合したブラウザUIが開きます。プレビュー上の要素をクリックすると、コンポーネント名やファイルパス、スタイルなどのコンテキストがClaude Codeへの指示に含まれます。Design Modev1.3.0で、ブラウザ上でページを直接編集できるDesign Modeを追加しました。要素をクリックして「どこを変えたい」と伝えるだけでなく、テキストを直接書き換えたり、要素をドラッグ&ドロップで並べ替えたりできます。変更はログとして蓄積され、「Apply Changes」ボタンでまとめてClaude Codeに送信します。Claude Codeが変更内容を解釈し、実際のソースコードに反映します。テキスト編集: 見出し・段落・ボタンなどのテキストをクリックして直接編集(IME対応)ドラッグ&ドロップ: 要素を親コンテナ内でドラッグして並び替えUndo: Cmd+Z / Ctrl+Zで変更を取り消し要素の選択モード(Select Element)とDesign Modeは排他
3ヶ月前

launchd-ui: macOSのlaunchdを使ったcron処理をGUIで管理するアプリを作った
Web Scratch
macOSのlaunchdエージェント・デーモンをGUIで管理できるアプリ launchd-ui を作りました。GitHub: azu/launchd-uiなぜ作ったかmacOSでcron的な定期処理をやろうとすると、launchdを使うことになります。自分の場合は、git pullを定期的に実行してリポジトリを同期する仕組みや、claude --remoteでClaude Codeを起動してスクリプトを実行する処理をlaunchdで管理しています。たとえば、chronixdで収集したアクティビティデータを元に、寝る前にclaude --remoteでその日の活動をまとめる処理を自動実行しています。Claude Code on the webで実行することで、自動で処理が走りつつ、気になったことがあればスマホからでも対話的に追記できます。こういった定期処理をlaunchdで管理しているのですが、launchdの操作は基本的にCLIです。launchctl loadやlaunchctl unloadといったコマンドを毎回調べながら打つのは面倒で、今どのエージェントが動いているか、次回いつ実行されるかといった情報も確認しにくいです。GUIツールはLaunchControlなどの有料ツールが多く、探すのも面倒だったので自分で作ることにしました。主な機能launchd-uiには次の機能があります。ユーザーエージェント(~/Library/LaunchAgents/)、システムエージェント、システムデーモンの一覧と検索エージェントの開始・停止・再起動・即時実行(テストラン)スケジュール設定と次回実行日時のプレビュー毎日n時に実行とか、何時間ごとに実行とかができるstdout/stderrログの表示plistファイルの詳細表示ユーザーエージェントの作成・編集・削除Finderでファイルを表示システムエージェントとデーモンは読み取り専用で、変更操作はユーザーエージェントのみに限定しています。技術スタックlaunchd-uiはTauriで作っています。バックエンドがRust、フロントエンドがReact + TypeScript + Viteという構成です。UIにはTailwind CSS v4とshadcn/uiを使っています。Tauriを選んだ理由は主に2つあります。1つ目は、l
3ヶ月前

Photo Cleaner: iPhoneの古い写真をまとめて削除できるiOSアプリを作った
Web Scratch
iPhoneから古い写真をまとめて削除するためのiOSアプリ Photo Cleaner を作りました。GitHub: azu/photo-cleanerAmazon Photosなどにバックアップ済みの古い写真をiPhoneから削除して、ストレージを解放するためのアプリです。なぜ作ったかiPhoneの写真が増えすぎてストレージが足りなくなったとき、古い写真をまとめて削除したいことがあります。しかし、標準の写真アプリでは大量の写真を効率的に選択・削除する機能がなく、一枚ずつ選択するのは現実的ではありません。既存のアプリを探しても、数万枚の写真を処理できるものが見つかりませんでした。そこで、シンプルに古い写真をまとめて削除できるアプリを作ることにしました。実際に数万枚の写真を削除してみましたが、問題なく動作しています。主な機能Photo Cleanerには次の機能があります。指定した期間より古い写真を自動で抽出して削除お気に入りに設定した写真は自動的に保護特定のアルバムを保護対象として設定可能削除前に月ごとのコンタクトシート(まとめ画像)を生成動画は削除対象から除外コンタクトシート機能Photo Cleanerは実際に写真を削除する前にコンタクトシートを生成する機能があります。コンタクトシートは、月ごとの写真をグリッド状にまとめた一枚の画像です。削除してしまう前に、その月にどんな写真があったかを一覧で残しておけます。生成したコンタクトシートは指定したアルバムに保存されるため、後から振り返ることができます。設定項目次の項目を設定できます。項目デフォルト値バックアップ猶予期間730日(2年)保護対象アルバムKeepコンタクトシート生成ONコンタクトシート保存先Keepインストールと使い方Photo CleanerはApp Storeで配布していないため、Xcodeでビルドしてインストールする必要があります。なぜApp Storeで配布しないのかAltStore PALやSideStoreなどのサードパーティストアでの配布も検討しましたが、現状では課題が多いです。AltStore PALで配布するにはAppleの公証(Notarization)が必要です。公証にはAppleの承認プロセスがあり、個人開発のアプリには負担が大きいです。SideStoreはApple IDとパス
4ヶ月前

mubook-hon v2: EPUBビューアーをfoliate-jsに移行、Cloudflare Workersへ移行
Web Scratch
mubook-honは、Dropboxに保存したEPUB/PDFファイルをブラウザで読めるウェブアプリです。Notionと連携して、読書メモや進捗をNotionに記録できます。mubook-hon: https://mubook-hon.jser.workers.dev/GitHub: https://github.com/azu/mubook-honURLが https://mubook-hon.vercel.app/ から https://mubook-hon.jser.workers.dev/ に変更されました。前回の記事から約2年半が経ち、大きな変更をしたので紹介します。mubook-hon: Dropboxに保存したepubやPDFを読むビューア、Notionにメモや読んでいる位置を記録できるMobile/PC対応のウェブアプリ | Web ScratchEPUBビューアーをBibiからfoliate-jsに移行EPUBの表示エンジンをBibiからfoliate-jsに移行しました。feat: replace Bibi with foliate-js for EPUB viewer by azu · Pull Request #28foliate-jsはFoliateというLinux向けの電子書籍リーダーのJavaScript実装です。Web Componentベースで実装されており、カスタマイズ性の高い点が特徴です。Bibiと比較して、次の点が改善されました。初期化の高速化 - インクリメンタルパースにより、EPUBファイルの読み込みが高速化メモリ消費の削減 - メモリ管理の改善により、メモリ使用量が減少仕組みの簡素化 - Bibiの時はMSWでService Workerプロキシを実装してBibiの求める形式/URLのパスで返す必要があり複雑だった。foliate-jsではこの回り道が不要になりシンプルに9ゾーンタップ設定画面を3x3の9ゾーンに分割し、各ゾーンにアクションを割り当てられるようになりました。feat: add customizable 9-zone tap settings for EPUB viewer by azu · Pull Request #32設定画面から、各ゾーンに「次ページ」「前ページ」「メニュー」「閉じる」「なし」を割
4ヶ月前