投稿日:

一年ぶりくらいにGitHub Actionsを使ってnpmパッケージを更新しようとしたら何かこけたので、通るようにした時にやったこと。

事象

なんかこんな感じのエラーが出てnpm publishに失敗した。

npm notice 1.6kB package.json
npm notice Tarball Details
npm notice name: @lycolia/ts-boilerplate-generator-cli
npm notice version: 0.28.1
npm notice filename: lycolia-ts-boilerplate-generator-cli-0.28.1.tgz
npm notice package size: 14.8 kB
npm notice unpacked size: 79.1 kB
npm notice shasum: 2ba5920ab2b46695bd996e86bf67b6a7cdb980cd
npm notice integrity: sha512-YHU4X10pXE7HP[...]RKmFhCpP4Gnmw==
npm notice total files: 25
npm notice
npm notice Publishing to https://registry.npmjs.org/ with tag latest and default access
npm notice Access token expired or revoked. Please try logging in again.
npm error code E404
npm error 404 Not Found - PUT https://registry.npmjs.org/@lycolia%2fts-boilerplate-generator-cli - Not found
npm error 404
npm error 404
npm error 404
npm error 404 Note that you can also install from a
npm error 404 tarball, folder, http url, or git url.

npm error A complete log of this run can be found in: /home/runner/.npm/_logs/2026-01-27T00_45_59_837Z-debug-0.log
Error: Process completed with exit code 1.

'@lycolia/ts-boilerplate-generator-cli@0.28.1' is not in this registry.

起きていたこと

  1. npmjsにあるAccess Tokensが全部消えてた
  2. Trusted publishing for npm packagesという話で、OIDC[1]を使ってGitHubと連携しないとGitHubなどのCI/CD、つまり自動化処理・バッチ処理からnpm publishできなくなっていた
  3. これに対応するためにはnpm CLI version 11.5.1か、それ以降が必要
  4. またnpmjsのOIDC連携をするためには2FA認証が必須で、そのためにはパスキーが必要
  5. Access Tokenは最大90日までになり、無制限のものはなくなった
    • Access Tokenでnpm publishを行う場合、2FAしていないとできない

対応に必要なこと

  1. npmjsに2FA登録する。要パスキー
  2. npmjsからGitHubリポジトリへのOIDC連携
  3. GitHubリポジトリにあるnpm publishしているyamlの修正
  4. npmのバージョンアップ

やったこと

  1. npmjsにパスキーを登録
  2. npmjsからGitHubリポジトリへのOIDC連携
    1. パッケージのSettingsタブを開き、Trusted publisherにリポジトリ情報を登録する
      Enviroment nameは第三者向けの項目[2]なので、設定しなくていい
    2. Set up connectionボタンを押して連携する
  3. GitHub Actionsのワークフローを直す
    1. permissionsの部分を足し、npm publishenvは不要なので削除
       name: npm publish on push to main
       on:
       push:
           branches:
           - main
      +permissions:
      +  id-token: write
      +  contents: read
       jobs:
       publish-to-npm:
           runs-on: ubuntu-latest
           steps:
           - uses: actions/checkout@v4
           - uses: actions/setup-node@v4
               with:
               node-version-file: '.nvmrc'
               cache: npm
               cache-dependency-path: package-lock.json
               registry-url: 'https://registry.npmjs.org'
           - name: npm continuous install
               run: npm ci
           - name: npm build
               run: npm run build
           - name: run publish
               run: npm publish
      -        env:
      -          NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH }}
      
  4. .nvmrcのNode.jsのバージョンをv24.13.0にした
    • このバージョンにすると自動的にnpmのバージョンが適合したため
  5. この後、GitHub Actionsを使ってnpm publishに成功すると、パッケージページやバージョン履歴ページには次のような表示が出るようになる

パスキー使いたくない問題

パスキーは端末依存で環境間共有の面倒さやGoogle縛りになるのが嫌などで入れたくない人も少なくないだろう。私もそう思う。正直パスキーありきのサービスは困る。

取り敢えず私の場合はEdgeを使っていて、Android Edgeへのパスキー共有はできないものの、いったんpublishするだけなら問題ないので、Edgeのパスキーを使うことにした。

どうしてもパスキーを使いたい、ほかの環境でも同期したいが、Googleに頼りたくない場合はKeePassXCというOSSを使うのが一つの手だ。

KeePassXCは暗号化されたデータベースファイルにIDとパスワードや、パスキーを記録するソフトウェアだ。複数環境への同期はNASなりSSHなり、クラウドストレージなどに鍵DBを保存して、それぞれの環境から読み書きすることで実現できる。

KeePassXCにはEdgeの拡張もあり、PCの中でKeePassXCを起動していればEdgeの拡張と同期してIDパスワードやパスキーを上手く管理してくれるようだった。ただ拡張機能が起動する前にKeePassXCが起動していないと手動で接続しないといけないなど、地味に面倒だった。

ただ調べた限りKeePassXCには公式のAndroidアプリがなく、サードパーティーアプリは毎回鍵ファイルを読みに行く実装のようで、オフライン時にも使うことのあるスマホでは運用に厳しさを感じた。逆に完全オフライン版もあるが、これはこれでAndroid側でDBを更新した時に別環境に飛ばすのが手間になるだろうからイマイチだ。

もう一つの選択肢としてはBitwardenを使う方法もある。こちらは公式がAndroidアプリを出しているほか、同期用のストレージを自前で用意する手間もかからない。

Bitwardenは、いわば1Passwordの無料版みたいな感じと言えるだろう。なお、BitwardenにはOSS版もあるので、セルフホスト運用もできるようだが、詳しくは調べていない。

私はBitwardenを軽く試してみたが、Edgeの自動入力機能に干渉しており、EdgeのパスワードDBを消し去らないとEdgeとBitwarden両方のパスワード入力補助が出てきて非常に邪魔だったことや、アニメーション設定をOFFにしても入力フィールドが飛び跳ねるアニメーションが出てきて嫌だったので、結局諦めた。せめて独立して動いてほしかった。

トラブルシューティング

Edgeで2FA認証しようとしたらパスキーがこけた

画像のような状態になった場合、何度かやり直すといけた。

「Two-factor authentication or granular access token with bypass 2fa enabled is required to publish packages.」と言われる

パスキーを使った2FAを登録することで解決した。

「npm error code EOTP」と言われる

npm notice Publishing to https://registry.npmjs.org/ with tag latest and default access
npm error code EOTP
npm error This operation requires a one-time password from your authenticator.
npm error You can provide a one-time password by passing --otp=<code> to the command you ran.
npm error If you already provided a one-time password then it is likely that you either typoed
npm error it, or it timed out. Please try again.

このようなエラーが出る場合、GitHub ActionsのWorkflowsのyamlファイルのルートに以下の記述が足りないので足す。

permissions:
  id-token: write  # Required for OIDC
  contents: read

「npm error code ENEEDAUTH」と言われる

npm error code ENEEDAUTH
npm error need auth This command requires you to be logged in to https://registry.npmjs.org/
npm error need auth You need to authorize this machine using `npm adduser`

このようなエラーが出る場合、npmのバージョンが古いので11.5.1以上にすることで解決する。

あとがき

正直npmjsを利用するのはもうやめようかと思う。ぶっちゃけもうNode.jsと積極的に関わりたくないし、代替技術を探したいと感じた。少なくともプライベートではそう思う。

TypeScriptに限界を感じてきたでも書いたが、Node.jsのエコシステム周りには甚だうんざりしてきており、今回の件でより、さらに、もっと嫌になった。

取り敢えず静的解析とかそういうのは欲しいし、テストもしたい、ほんでLinuxフレンドリーで、Windowsでも動いてくれるとなおよい。簡単なツールを書くことが多いのもありコンパイル言語よりはインタプリタ言語のほうが好ましい。

そう考えるとやはり浮かんでくるのはPHPになってくるあたり、21年前に触れた私の初めてのプログラミング言語との出会いに戻ってくるあたりが面白い。PHPerはPHPerから逃れられない宿命でもあるのかもしれない。

今は肩書上フロントエンドエンジニアとかいうのを仕事にしているが、そこまで性に合っていない気もしてきているし、Web系のバックエンドではPHPの仕事もまだまだあるので、これを機にPHPに戻るのも一つありだとは思った。

関係ない話、何ならadiaryのせいでTypeScriptよりPerlの方が好感を持ててきているまであるので、私はたぶんどうかしているのだと思う。


  1. OpenID Connectの略。いわゆるOAuthを使って別サービスのアカウントで連携処理を行うもの。
  2. OIDC連携はnpmjsのアカウントとリポジトリを紐づけるためのもので、publisher以外の人間が作業する場合に必要になるものと思われるが詳しくは調べていない。
投稿日:

なんか突如としてGitHubにHTTP経由で繋ぐのが面倒くさくなったのでSSHで繋げるようにしたときのメモ。

確認環境

  • Ubuntu 24.04.3 LTS
  • RLogin 2.30.8

やり方

SSH鍵の作成

  1. RLoginを開き、サーバーに接続→新規→サーバー→プロトコルを開く
  2. 認証キーボタンを押しED25519辺りで適当な名前で鍵を作成する
  3. 適当な場所に秘密鍵をエクスポートする
  4. 鍵を右クリックし、公開鍵をコピーして、どっかにメモっておく

GitHubへの登録

  1. GitHubを開き、アカウント設定に移動、SSH and GPG keysを開く
  2. SSH keys→New SSH Keyを開く
  3. Titleに適当な名前を設定
  4. Key typeはAuthentication Keyにする
  5. RLoginで作った
  6. コピーした公開鍵をKeyに貼り付ける
  7. Add SSH keyボタンを押す

SSH Configを書く

  1. 作成したSSH鍵を~/.ssh/github.secとか適当なパスに置く
  2. chmod 600 ~/.ssh/github.secとかして自分しか見れないようにする
  3. ~/.ssh/configを開き、次の内容を記述
    Host github.com
    User <ユーザーID>
    Hostname github.com
    IdentityFile ~/.ssh/github.sec
    

既存のリポジトリをSSH対応にする

ここではoriginがリモートであるとして進める。

  1. git remote -vでリモートリポジトリの状況を確認
  2. git remote remove originでHTTP通信になってるのを消す
  3. git remote add origin git@github.com:Hoge/piyo.gitでSSH通信に書き換える
  4. git fetchが通ればOK

Node.jsのスクリプトを適当に書き次のようなWorkflowsを記述することで実行できる。勿論Dockerイメージを作ってそこから立ち上げることもできるので好みの問題。直に呼べる分、取り回しは楽だと思う

name: hoge
description: hoge
inputs:
  GITHUB_TOKEN:
    description: 'Workflowsを実行するリポジトリのGITHUB_TOKEN'
    required: true
on:
  workflow_call:
runs:
  using: node20
  main: dist/index.js

inputs:outputs:を記述すれば入出力の引数も定義できる。

inputs.GITHUB_TOKENについて

これを書いておくとoctokitを使ってGitHubのAPIを叩けるようになる。普通は何かAPIを叩くはずなので書いておいた方が良い。

以下は一例。

const github = require('@actions/github');
const core = require('@actions/core');

async function run() {
    const token = core.getInput('GITHUB_TOKEN');
    const octokit = github.getOctokit(token);

    const { data: pullRequest } = await octokit.rest.pulls.get({
        owner: 'octokit',
        repo: 'rest.js',
        pull_number: 123,
        mediaType: {
          format: 'diff'
        }
    });

    console.log(pullRequest);
}

参考

投稿日:

久々にGitHub Projectsを見たら以前より格段に機能が増えて便利になっていた。

様々なProjectsテンプレートが選べるようになっている

まず、プロジェクトの作成時に様々な機能からテンプレートを選べるようになっており、大まかな機能は作ってくれるようになっているようだ。

バックログやカンバン、イテレーションボード、ロードマップ(ガントチャート)、自分のタスク一覧など、様々なタブが作れるようになっており以前より格段に便利になったと思う。

以前はイテレーションボードがなく、カンバンをしていると無限にタスクがたまっていく問題があり難儀していた。当時はどうしようもなかったのでToDo, WIP, Doneのバックログタブを作り、巨大なカンバンとして利用していたように思うが、イテレーションで絞り込むのが地味に怠く、難儀した記憶がある。

ただWorkflowがまだイマイチだ。Item added to projectではIssueとPullRequestでワークフローを分けられないので、IssueはToDoとして追加し、PullRequestはWIPとして追加するみたいなのが出来ないし、Auto-add to projectも複数リポジトリを対象にできないので、単一リポジトリからのIssue, PullRequestしか自動追加に対応できず、折角リポジトリを跨いだ管理ができる利点を損ねている。

ただまだ発展途上に見えるので、これからに期待したいところだ。例えばタブをダブルクリックしてリネームしてもリロードすると元に戻るが、オプションから明示的にリネームするとできるなど、バグのような挙動も見られる。この事からまだBetaくらいだと思っていたほうがよさそうだ。Beta外れてるように見えるけど()

参考までに今回適当に作ったやつを貼っておく。

バックログ

バックログ

これは以前からあった機能で特に進化していないと思う。ごく普通のバックログだ。カラムの値でグループ化して区切れたりして地味に便利な奴だ。

カンバン

これも以前からあったやつで特に進化していないと思う。ごく普通のカンバンだ。昔はこれでイテレーション管理しようとして無理で諦めた。

カンバン

イテレーション

以前はなかったが増えてたやつだ。スプリントとかをやるときに便利かもしれない。イテレーションはバックログに列を追加すると、そこから設定可能なようだ。

イテレーション

ロードマップ

いわゆるガントチャートが引けるやつだ。詳しく見てないのでWBS的な使い方ができるのかは謎だが、ないよりマシくらいな機能感は見える。恐らく予実管理には向かないだろう。

ロードマップ

自分のタスク

自分のタスクだけが見れる奴だと思う。バックログでも見れるのでありがたみは薄いが、面倒くさがりや、ライトユーザーには嬉しい機能かもしれない。

自分のタスク

その他

タブをカスタマイズするオプションが豊富にあり、色々出来そうな気配を感じた。

タブのカスタマイズオプション

更新日:
投稿日:

この記事ではGitHub ActionsのCustom actionをJavaScriptで実装するJavaScript actionをTypeScriptとSWCを使って実装した方法を書いてます。

モチベーション

  • GitHub ActionsのWorkflowsを共通化したい
  • TypeScriptでロジックを書きたい
  • SWCを使いたい(nccはtscを使うので避けたい
  • github-scriptは一定以上のボリュームがあるものには向かない
    • これを使いつつUTを書いたりするとなると結構面倒になると思う

今回作るもの

Custom actionのうちJavaScript actionを作成します。
実装コードはTypeScript、トランスパイラはSWC、バンドラはwebpackを利用します。
バンドラを利用するのは、node_modules/をGitで管理したくないためです。
ビルド成果物であるdist/は実行時に必要なため、Gitで管理します。
(CI上でビルドしてキャッシュさせておくことも出来ると思いますが、今回は扱いません)

確認環境

Env Ver
@actions/core 1.10.0
@actions/github 5.1.1
@swc/cli 0.1.57
@swc/core 1.3.26
swc-loader 0.2.3
typescript 4.9.5
webpack 5.75.0
webpack-cli 5.0.1

サンプルコード

Custom Actions本体

Custom action本体のサンプルコードです。以下に一式があります。
https://github.com/Lycolia/typescript-code-examples/tree/main/swc-ts-custom-actions

ディレクトリ構成

dist/配下を叩くため、ここはGit管理に含めます。バンドルするのでnode_modules/はGit管理から外して問題ありません。

├─dist/
│ └─index.js        # Custom Actionsとして実行するファイル本体
├─node_modules/
├─src/
│ └─index.ts        # TypeScript実装
├─action.yaml       # Custom Actionsの定義
├─package-lock.json
├─package.json
├─swcrc-base.js     # SWCの設定
├─tsconfig.json     # tscの設定
└─webpack.config.js # webpackの設定
swcrc-base.js

SWCの設定例。特にJavaScript actionのための設定はなく、CLI向けのトランスパイルが出来る設定ならおk。
ファイル名は何でも大丈夫ですが、この場では.swcrcにしないことで、直接SWCで利用しないことを判りやすくするために違う名前にしています。

module.exports = {
    module: {
        type: 'commonjs',
    },
    jsc: {
        target: 'es2020',
        parser: {
            syntax: 'typescript',
            tsx: false,
            decorators: false,
            dynamicImport: false,
        },
        baseUrl: '.',
        paths: {
            'src/*': ['src/*'],
        },
    },
};
webpack.config.js

SWCを使って.tsファイルをバンドルするための設定。これがないとimportの解決ができずにコケます。
node_modules/配下をGit管理に含める場合は不要かもしれませんが、それをするのは微妙だと思います。

const path = require('path');
const swcrcBase = require(path.resolve(__dirname, 'swcrc-base'));

module.exports = {
    // エントリポイント
    entry: path.resolve(__dirname, 'src/index.ts'),
    // 出力設定
    output: {
        // クリーンアップ後に出力
        clean: true,
        // 出力ファイル名
        filename: 'index.js',
        // 出力パス
        path: path.resolve(__dirname, 'dist'),
    },
    // 設定必須なので何か指定しておく
    mode: 'production',
    // 指定してないとNode.jsのネイティブAPIが呼べない
    target: ['node'],
    module: {
        // swc-loaderの設定
        rules: [
            {
                test: /\.ts$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'swc-loader',
                    // swcrcの設定
                    options: {
                        ...swcrcBase,
                    },
                },
            },
        ],
    },
    resolve: {
        // import時のファイル拡張子を省略してる場合にパスを解決するための設定
        extensions: ['', '.ts', '.js'],
    },
};
src/index.ts

最低限これだけ確認できれば応用して実装できるだろうという程度のサンプルコード。

@actions/*系の使い方は以下のリンクから確認できます。
actions/toolkit: The GitHub ToolKit for developing GitHub Actions.

import * as core from '@actions/core';
import * as github from '@actions/github';

const githubToken = core.getInput('GITHUB_TOKEN', { required: true });
const octokit = github.getOctokit(githubToken);

console.log('octokit', octokit);
console.log('context', github.context);
core.setOutput('RESULT_MESSAGE', 'test result message');
action.yaml

実装の参考例として引数と出力を定義してます。特に不要な場合は書かなくてもいいです。
Node.jsのバージョンを詳細に指定したい場合は、composite action にすれば可能だとは思いますが、試してない。
composite actionにしてnvmか何かでインストールしてやれば恐らく可能。

構文は以下のページで確認できます。
GitHub Actions のメタデータ構文 - GitHub Docs

name: example
description: custom actions example
inputs:
  GITHUB_TOKEN:
    description: 'Repogitory GITHUB_TOKEN'
    required: true
outputs:
  RESULT_MESSAGE:
    description: 'Result message'
on:
  workflow_call:
runs:
  using: node16
  main: dist/index.js

Custom actionを使う側

Custom actionを使うWorkflowのサンプルコードです。以下にソースがあります。
https://github.com/Lycolia/custom-actions-usage-example

.github/workflows/example.yaml

usesのところにはリポジトリの組織名と、リポジトリ名、action.yamlが配置されているディレクトリまでのパスを書きます。ルートディレクトリにある場合はパスを書かなくてOK
最後に@sha-hashでコミットハッシュかタグを付けてやれば呼べるようになります。
動作確認中はハッシュが頻繁に変わるので、最新のハッシュを取得してきて設定されるようにしておくと便利かもしれません。

name: run example
on:
  workflow_dispatch:
jobs:
  example:
    runs-on: ubuntu-latest
    steps:
      - name: run custom actions
        id: test
        uses: org-name/repo-name/path/to/file@sha-hash
        with:
          # Custom action側で定義されている引数(input)の設定
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: show custom actions output
        # Custom action側で定義されている出力(output)の取得
        run: echo ${{ steps.test.outputs.RESULT_MESSAGE }}

参考資料