Web Scratch
フィード
LDRライクなRSSリーダのIrodrをReact 19 + Vite+で書き直して、iPhone Duoにも対応した
27
Web Scratch
Inoreaderのフロントエンドとして動くLDRライクなRSSリーダのIrodrを、React 19 + Vite+で書き直しました。Rebuild irodr as a React 19 SPA on Vite+ by azu · Pull Request #127 · azu/irodrIrodrは2017年にLDRが終了するときに作ったもので、そこから9年ぐらい毎日使っています。今回の書き直しでも見た目とキー操作(j/k/s/aなど)は変えていません。中身は全部書き直していて、InoreaderとGitHub Notificationsを同じ「ソース」として扱う作りになっています。JSのサイズはgzip後で397kBから150kBになりました。Irodrについては次の記事で書いています。LDRがサービス終了のため、Inoreader/Feedlyをバックエンドに動くRSSリーダを書いている | Web ScratchLDRライクなRSSリーダのIrodr 1.0.0をリリースした | Web Scratchきっかけきっかけは、InoreaderのProプランのフィード数の上限です。ProプランはRSSフィードの購読数が2500までに制限されていて、自分の購読数がこれを超えそうになっていました。GitHubでWatchしているリポジトリのリリースは、watch-rssを使ってRSSフィードとしてInoreaderに購読しています。(私のJavaScriptの情報収集法 2024年版でも書いています)この仕組みで購読しているGitHubリポジトリのフィードが2000以上あって、購読数の大半はこれでした。GitHubリポジトリのリリースは、GitHubのWatch(Releasesのみ)でも受け取れます。これをGitHub Notificationsに逃がせば、Inoreaderのフィード数を2000ほど減らせます。ただ、GitHub Notificationsの画面はRSSリーダのようには読めないので、IrodrでGitHub Notificationsをリポジトリ単位のフィードとして読めるようにしました。feat: support GitHub Notifications as repository feeds by azu · Pull Request #1
1日前

Chizu 🧀: リンクをルールに応じてブラウザとプロファイルへ振り分けるmacOSアプリ
Web Scratch
macOSの既定のブラウザとして登録しておき、開いたリンクを設定ファイルのルールに応じて、指定したブラウザとプロファイルへ振り分けるアプリ Chizu 🧀 を作りました。GitHub: azu/chizuChizuには、ブラウザを選ぶ画面や設定画面はありません。振り分けのルールは~/.config/chizu/config.jsoncというJSONCファイルに書き、リンクを開くたびにこのファイルを読み直します。行き先にはブラウザのプロファイルも指定でき、現時点ではDia、Google Chrome、Firefoxのプロファイル指定に対応しています。インストール動作環境は次のとおりです。Apple SiliconのMac + macOS 14以降次のコマンドでインストールし、ChizuをmacOSの既定のブラウザに設定できます。いつも通りnotarizationはしてないので、自己判断でご自由にどうぞ。curl -fL https://github.com/azu/chizu/releases/latest/download/chizu-macos-arm64.zip -o "$TMPDIR/chizu-macos-arm64.zip" &&curl -fL https://github.com/azu/chizu/releases/latest/download/chizu-macos-arm64.zip.sha256 -o "$TMPDIR/chizu-macos-arm64.zip.sha256" &&(cd "$TMPDIR" && shasum -a 256 -c chizu-macos-arm64.zip.sha256) &&mkdir -p "$HOME/Applications" &&ditto -x -k "$TMPDIR/chizu-macos-arm64.zip" "$HOME/Applications" &&xattr -dr com.apple.quarantine "$HOME/Applications/Chizu.app" &&/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -...
11日前

Quick Input Translator: 書いた文章を入力欄中でインライン翻訳するmacOSアプリ
Web Scratch
入力欄に日本語で文章を書いてから、末尾に...を入力すると、その場で英語に翻訳して置き換えるmacOSアプリ Quick Input Translator を作りました。GitHub: azu/quick-input-translator翻訳にはmacOSのTranslation frameworkを使っていて、翻訳はMac上(オンデバイス)で行われます。外部の翻訳APIを呼び出さないので、APIキーは不要で、言語モデルを一度ダウンロードしておけばオフラインでも素早く翻訳できます。インストール動作環境Apple SiliconのMac + macOS 26以降次のコマンドでインストールできます。notarizationはしてないので自己判断でお願いします。curl -fL https://github.com/azu/quick-input-translator/releases/latest/download/quick-input-translator-macos-arm64.zip -o "$TMPDIR/quick-input-translator.zip" &&ditto -x -k "$TMPDIR/quick-input-translator.zip" /Applications &&xattr -dr com.apple.quarantine "/Applications/Quick Input Translator.app" &&open "/Applications/Quick Input Translator.app"アプリは自己署名で、Appleの公証(notarization)はしていないため、xattrでquarantine属性を解除してから起動しています。v1.1.1以降はSparkleによる自動アップデートに対応しているので、2回目以降はアプリ内で更新できます。初回の設定と言語モデルのダウンロードアプリを起動すると設定画面が開きます。翻訳には言語モデルが必要なので、最初に設定画面からダウンロードしておきます。FromとToに翻訳元と翻訳先の言語を設定する(たとえば Japanese → English)Prepare Languagesボタンを押すmacOSの言語モデルのダウンロードダイアログが表示されるので、ダウンロードを完了させる
16日前

「OSS開発者は今何をするべきか?ソフトウェアサプライチェーン侵害対策を考える」で「Hardening npm Publishing」という発表をしました
Web Scratch
2026年6月23日に、GMO Flatt Security主催の「OSS開発者は今何をするべきか?ソフトウェアサプライチェーン侵害対策を考える」で「Hardening npm Publishing」というタイトルで、npmパッケージの公開フローをどう守るかについて話しました。スライド: Hardening npm Publishingローカルのトークン管理やnpm Trusted Publishingについては、以前の記事で書きました。1Passwordを使って、ローカルにファイル(~/.configや.env)として置かれてる生のパスワードなどを削除した | Web Scratchパスワード管理/MFA管理の戦略 | Web Scratchnpm Trusted PublishingでOIDCを使ってトークンレスでCIからnpmパッケージを公開するこの記事ではそれらを前提に、GitHub Environmentsとnpm staged publishingをどこに入れるかの話をスライドベースでかいています。サプライチェーン攻撃をすべての侵害を防ぐのは難しいです。それでも、ローカル、CI、GitHub Actions、npm registryのそれぞれに止める場所を作ると、攻撃者が1つの権限を取っただけでは公開まで進みにくくできます。公開フローをどこで止めるかnpmパッケージの公開フローでは、開発者のローカル環境、GitHubリポジトリ、GitHub Actions、npm registry、利用者のインストール環境がつながっています。攻撃者の入口も1つではなく、ローカルのnpmトークン、GitHub Actionsのworkflow、CI上の認証情報、install時に実行される悪性コードなど、いくつかの場所に分かれます。そのため、対策も1つでは足りません。自分は次のように、公開フローを段階ごとに分けて考えています。ローカルに強いトークンを置かないCIからnpmへ公開するときは長期npmトークンを使わないGitHub Actionsからnpmへ権限が広がる手前にGitHub EnvironmentsのDeployment protection rulesを置くnpm staged publishingでregistry公開前にもう一度止める重要なのは、それぞれの
5ヶ月前

automerge-gate: GitHubのAuto Mergeをひとつの必須チェックに集約するGitHub Action
Web Scratch
GitHubのAuto Mergeをひとつの必須チェックに集約するためのGitHub Action automerge-gate を作ったので紹介します。GitHub: pkgdeps/automerge-gate背景: GitHub Auto Mergeは集約するアクションなしだと使いにくい前提として、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最近はme
6ヶ月前

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
6ヶ月前

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は、作業の難易度や必要な調査量などを考慮して設
6ヶ月前

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のリストを参照することで、確度の高いパターンを持つ
7ヶ月前

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
7ヶ月前

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の
7ヶ月前