Scheduled watch
A check only helps when someone runs it. The scheduled watch runs the CLI every 4 hours in your CI and opens an issue when a heads-up, an alert or a security release is new for your stack. Quiet runs cost nothing and open nothing.
The profile
The watch reads .stackalarm.yaml at the root of the project. The skill writes it at the end of a /stackalarm run
when you accept the watch, and refreshes it on later runs.
# Written by the stackalarm skill, refreshed on each /stackalarm run.
tags: [php, symfony, composer, gitlab, docker]
keywords: [frankenphp]
packages: [symfony/http-kernel, twig/twig]
stack:
- {name: php, version: "8.3", precision: branch, from: Dockerfile}
- {name: gitlab, version: unknown, precision: unknown, from: git remote}
| Field | Use |
|---|---|
tags | Technologies to watch, as in --tag. |
keywords | Words searched in the general sources, as in --keyword. |
packages | Package names from the lockfile, as in --package. |
stack | What the skill found, with the version, its precision (exact, branch, range, unknown) and the file it came from. Shown in reports, never used to filter. |
The file is committed and may be public: it never holds host names, internal URLs, IP addresses or secrets (gitlab, not
gitlab.acme.internal). Check it with stackalarm news --profile .stackalarm.yaml --since 24h.
GitHub Actions
Copy ci/github/stackalarm.yml to .github/workflows/:
name: stackalarm
on:
schedule:
- cron: "17 */4 * * *"
workflow_dispatch:
permissions:
contents: read
jobs:
watch:
runs-on: ubuntu-latest
permissions:
contents: read
issues: write
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: yoanbernabeu/stackalarm@v0.6.0
with:
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
nvd-api-key: ${{ secrets.NVD_API_KEY }}
No token to create: the workflow's automatic github.token opens the issue and lifts the GitHub API cap. The optional secrets
are ANTHROPIC_API_KEY (the triage, below) and NVD_API_KEY.
The workflow uses the yoanbernabeu/stackalarm action, which you can also call from your own workflows. Its inputs and outputs,
as declared in action.yml:
| Input | Default | Description |
|---|---|---|
profile | .stackalarm.yaml | The project profile written by the stackalarm skill. |
since | 48h | How far back to look. Longer than the schedule interval, so a delayed run misses nothing; the state removes the duplicates. |
fail-on | heads-up,alert,release | The stages that wake the watch up (heads-up, alert, release, advisory, news). |
anthropic-api-key | empty | Optional. With it, Claude runs the stackalarm skill on the new items, and an issue is opened only when the project is concerned. Without it, every new item opens an issue. |
issue | true | Open an issue ("true" or "false"). |
label | stackalarm | The label of the issues, created if missing. |
install | true | Install stackalarm ("true"), or use the one already on the PATH ("false"). |
version | empty | The stackalarm version to install (v0.5.0). Empty means the version of this action when it is pinned to a release, the latest release otherwise. |
github-token | ${{ github.token }} | Token used to open the issue and to raise the GitHub API rate limit of the CLI. |
nvd-api-key | empty | Optional NVD API key, to search the NVD faster. |
| Output | Description |
|---|---|
found | "true" when new items with one of the fail-on stages were found. |
decision | What decided the issue: act, prepare or none (from the triage), exploited (an exploited vulnerability overrode "none"), untriaged (no key, or the triage failed). Empty when nothing was found. |
report | Path of the Markdown report. |
issue-url | URL of the issue opened, if any. |
Triage by Claude
Raw news is not a verdict: a Go release the project already runs is news, not a reason to act. With the ANTHROPIC_API_KEY
secret, when the CLI finds something new, Claude runs the skill in triage mode and the issue depends on
its decision. Claude is called only on the runs that find something new.
| The run finds | What happens |
|---|---|
| Nothing new | Nothing is opened. Claude is not called. |
New items, decision act | An issue "stackalarm: act now", verdict first, the raw news folded below. |
New items, decision prepare | An issue "stackalarm: prepare", same layout. |
New items, decision none | No issue. The verdict stays in the run summary. |
Decision none, but the report holds an item from CISA KEV or the EUVD exploited list | An issue anyway: a vulnerability exploited in the wild that names a watched technology always reaches a person. |
| New items, the triage fails | An issue with the raw news, saying the triage did not complete. |
| New items, no API key | An issue with the raw news. Judge it with /stackalarm triage <issue link> in your agent. |
Claude reads text written by others, so it runs locked down. It cannot open issues, push or change the project's files: it can only write
its verdict and its decision, and the action opens the issue from them. The tools it is allowed, read from action.yml:
SkillReadGlobGrepWebSearchWebFetchEdit(./.stackalarm-triage/**)Bash(stackalarm:*)Bash(git remote:*)Bash(go list:*)Bash(composer audit:*)Bash(npm audit:*)Bash(pnpm audit:*)
GitLab CI
Include the job in .gitlab-ci.yml:
include:
- remote: https://raw.githubusercontent.com/yoanbernabeu/stackalarm/main/ci/gitlab/stackalarm.yml
Then two steps only you can do:
-
Add a masked CI/CD variable
STACKALARM_GITLAB_TOKEN: a project access token with theapiscope and the Reporter role, to open the issues. - Create a pipeline schedule (Build > Pipeline schedules), every 4 hours:
17 */4 * * *. The job runs only on schedules.
Two optional variables, read by the CLI as on your machine:
| Variable | Why |
|---|---|
GITHUB_TOKEN |
Recommended on shared runners. The GitHub advisory sources allow 60 anonymous requests per hour per IP, and shared runners share their IP with many other jobs: without a token, those sources often fail. Use a GitHub token with no permission at all (a fine-grained token with public repositories, read-only), masked. |
NVD_API_KEY | Faster NVD searches. Free. |
The job's variables, which you can override:
| Variable | Default |
|---|---|
STACKALARM_PROFILE | .stackalarm.yaml |
STACKALARM_SINCE | 48h |
STACKALARM_FAIL_ON | heads-up,alert,release |
STACKALARM_LABEL | stackalarm |
GitLab has no triage by Claude: every new heads-up, alert or security release opens an issue with the raw news, to judge with
/stackalarm triage <issue link>. Without the token, the job fails instead of staying silent.
Each item reported once
The CI cache keeps a state file of the items already handled. It is saved only once the run has dealt with them (issue opened, or none needed): if the issue cannot be opened, the next run reports the items again. An item may be reported twice, never missed. On GitLab runners without a shared cache, a few items may be reported twice.
The watch looks back 48 hours by default, longer than the 4-hour schedule, so a delayed or failed run misses nothing; the state removes the duplicates.
Next: Sources