Token Expiry Check #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Token Expiry Check | |
| on: | |
| schedule: | |
| - cron: "0 9 * * 1" | |
| workflow_dispatch: | |
| env: | |
| NPM_TOKEN_EXPIRES: "2026-05-17" | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check expiry date | |
| id: expiry | |
| run: | | |
| EXPIRES=$(date -d "$NPM_TOKEN_EXPIRES" +%s) | |
| NOW=$(date +%s) | |
| DAYS_LEFT=$(( (EXPIRES - NOW) / 86400 )) | |
| echo "days_left=$DAYS_LEFT" >> "$GITHUB_OUTPUT" | |
| if [ "$DAYS_LEFT" -le 14 ]; then | |
| echo "::warning::NPM_TOKEN expires in ${DAYS_LEFT} days (${NPM_TOKEN_EXPIRES})" | |
| echo "needs_rotation=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "Token OK — ${DAYS_LEFT} days remaining" | |
| echo "needs_rotation=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Verify token is functional | |
| if: steps.expiry.outputs.needs_rotation == 'false' | |
| id: token_check | |
| continue-on-error: true | |
| run: | | |
| STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ | |
| -H "Authorization: Bearer ${{ secrets.NPM_TOKEN }}" \ | |
| https://registry.npmjs.org/-/npm/v1/user) | |
| if [ "$STATUS" != "200" ]; then | |
| echo "::error::NPM_TOKEN returned HTTP $STATUS" | |
| exit 1 | |
| fi | |
| - name: Create rotation issue | |
| if: steps.expiry.outputs.needs_rotation == 'true' || steps.token_check.outcome == 'failure' | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const existing = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| labels: 'token-rotation', | |
| state: 'open' | |
| }); | |
| if (existing.data.length > 0) return; | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: '🔑 NPM_TOKEN expires ${{ env.NPM_TOKEN_EXPIRES }}', | |
| body: [ | |
| '## Action Required', | |
| '', | |
| 'The fine-grained npm token expires on **${{ env.NPM_TOKEN_EXPIRES }}** (${{ steps.expiry.outputs.days_left }} days remaining).', | |
| '', | |
| '### Steps', | |
| '1. Go to [npmjs.com/settings/tokens](https://www.npmjs.com/settings/~/tokens)', | |
| '2. Create new fine-grained token: write access to `dubstack`, "Bypass 2FA" enabled', | |
| '3. Update `NPM_TOKEN` at [org secrets](https://github.com/organizations/wiseiodev/settings/secrets/actions)', | |
| '4. Update `NPM_TOKEN_EXPIRES` in `.github/workflows/token-check.yml`', | |
| '5. Close this issue' | |
| ].join('\n'), | |
| labels: ['token-rotation'] | |
| }); |