Workflow Expiry - dated GitHub Actions breakage

Finds the lines in .github/workflows that are valid today and fail on a date GitHub has already published.

Every workflow in the repo, in one pass

This page checks the one file you pasted. The full version scans every workflow in the repository at once, exports the dated audit as CSV/JSON/HTML, applies the replacement line for you, and emits JSON a CI step can fail on — so an expiring line cannot merge.

Get the full version — $29

$29 once · one licence key per person or team seat · 7-day full refund. Upwork lists DevOps engineers at $40-$100/hour, median $60.

Get the complete version $29

This page is the working piece. The full pack has everything below.

Finds the lines in .github/workflows that are valid today and stop working on a date GitHub has already published.

Upwork lists DevOps engineers at $40-$100/hour, median $60.

Buy the full version — $29
Want the full version?
Enter your email and we send the download link.
ENDEJAESPT

Find a tool

· ReadyStack

Worked example

Real numbers from this tool, line by line.

There is a category of CI failure that no linter warns you about, because nothing is wrong yet.

On 2026-09-08, this is a completely valid workflow. actionlint passes it. The official GitHub Actions VS Code extension passes it. The schema is correct, the labels exist, the actions resolve.

name: ci
on: [push]
jobs:
  build:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - uses: actions/upload-artifact@v4

Every line in it has a published expiry date.

The two dates in September 2026

2026-09-17 - ubuntu-22.04 and ubuntu-22.04-arm begin deprecation. Full removal is 2027-04-17, and GitHub runs brownout windows before that in which jobs on the image simply fail. Right now the label is valid, so a validity check has nothing to report.

2026-09-23 - Node 20 is removed from the runner. Runners have defaulted to Node 24 since 2026-06-16. Any action whose action.yml declares runs.using: 'node20' stops executing that day, and that includes actions/checkout@v4, actions/setup-node@v4 and v5, and the v4/v5 artifact actions. The ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION escape hatch expires on the same date.

Why a linter cannot tell you this

A linter answers "is this valid?" A calendar answers "is this still valid in three weeks?" Those are different questions and the second one is the one that pages you at 3am.

actionlint does flag an action whose runner is *already* unsupported - node12 and node16 today. It validates runner labels against the list of labels that *currently* exist. Both checks are correct and both are blind to an announced future date, by design. The information you need is not in the file and not in the schema. It is in a changelog post from last year.

What to change

name: ci
on: [push]
permissions:
  contents: read
jobs:
  build:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v6
      - uses: actions/upload-artifact@v6

While you are in there, three more things carry dates or teeth:

They are ignored, so the value downstream is silently empty. Use >> "$GITHUB_OUTPUT".

runs code in your pipeline with your secrets. Pin the full 40-character commit SHA.

by whoever opened the issue. Pass it through env: and quote "$VAR" in the script.

Checking it

I built a VS Code extension for this, because the check belongs where the file is being edited rather than in a report someone reads quarterly. It carries 29 rules, each one carrying its date and its replacement line, and checking the file you have open is free - all 29 rules, no limit.

There is also a single-page version that runs entirely in the browser: paste a workflow, get the line numbers back. Same rule set, same answers, nothing uploaded.

The thing worth internalising is smaller than the tool: "it passes the linter" and "it will still run next month" are two different claims, and almost nothing in the ecosystem checks the second one.

Questions people ask

What does Workflow Expiry actually do?

It reads a GitHub Actions workflow file and flags the lines that are valid today but stop working on a date GitHub has already published. Each finding gives the line number, the reason, the date, and the replacement line. It covers 29 rules: retiring runner images, the Node 20 removal, shut-down action versions, deleted workflow commands, and script injection.

Who is this for?

The engineer who owns .github/workflows for a team that ships to production, and anyone maintaining a repository with more workflows than they can read by hand. It is aimed at people who find out a pipeline broke when a deploy fails on a Monday morning, rather than when the deprecation notice was published a year earlier.

Does actionlint not already catch this?

actionlint is excellent and checks whether a label is valid right now. That is a different question. On 2026-09-08 ubuntu-22.04 is still a perfectly valid label, so no validity check flags it, yet its deprecation starts 2026-09-17. Workflow Expiry checks the calendar, not the schema, and needs no Go binary installed.

What is free and what needs a licence?

Checking the workflow file you have open is free and complete: every one of the 29 rules, no watermark, no limit on how many times you run it. A licence unlocks a different job, not a bigger one: scanning every workflow in the repository at once, exporting the dated audit as a file, applying fixes, and emitting JSON for a CI gate.

What would this cost me otherwise?

Upwork lists DevOps engineers at $40 to $100 per hour, median $60. Reading forty workflow files against a deprecation calendar by hand is most of a working day, and it has to be redone every time GitHub publishes a new retirement date. The full version is $29 once, with a 7-day full refund.

Ask about this tool

One question, answered by the person who built it. Your email only if you want the answer sent.