@cupel-sh/cli
v0.6.0
Published
Reachability-first SCA — verdict + call path + confidence for every finding.
Maintainers
Readme
cupel
Reachability-first SCA. Every finding gets a verdict, a call path, and a confidence — so you can tell the advisories your code can actually reach from the ones it cannot.
npx @cupel-sh/cli scan .Verdicts
cupel answers with one of six verdicts, and unknown is one of them:
| Verdict | Meaning |
| ------------------------------------- | --------------------------------------------------------- |
| not-affected | the advisory does not apply to this version |
| not-reachable | no call path from your code reaches the vulnerable symbol |
| reachable-low / -medium / -high | a call path exists; confidence rises with the evidence |
| unknown | cupel could not decide, and says why |
unknown is never folded into the other verdicts to make a number look
better. Every unknown carries a named reason and an owner.
An empty result is not a clean bill of health. It is the set of advisories cupel could enumerate for the packages it could see.
Usage
cupel scan <dir> [--shard <npm.sqlite>] [--sarif <file>]
[--fail-on-reachable] [--fail-on-unknown]| Flag | Effect |
| --------------------- | ------------------------------------------------------- |
| --shard | path to the npm symbol shard (or set CUPEL_SHARD_NPM) |
| --sarif | also write a SARIF 2.1.0 report |
| --fail-on-reachable | exit 2 when any reachable finding is present |
| --fail-on-unknown | exit 2 when any unknown verdict is present |
Requires Node 22 or newer.
Signing in
A scan needs an advisory database. On GitHub Actions there is nothing to set up — the workflow authenticates with a token GitHub signs for each run, and holds no secret of ours.
Anywhere else — a laptop, GitLab, Jenkins — sign in once with a delivery token from app.cupel.sh (Settings → Tokens):
cupel login # paste the token; input is hidden, and it is never an argument
cupel logout # forget itThe token is stored in your OS config directory, readable by you alone
(CUPEL_CONFIG_DIR moves it). In CI, set CUPEL_DELIVERY_TOKEN from your
secret store instead — it takes precedence over the stored one.
Neither is needed when you pass --shard <npm.sqlite>: a shard already on
disk is opened without asking anybody, which is what keeps air-gapped and
offline use working.
Your code never leaves your machine
cupel analyses your source locally. It uploads no source, no ASTs, and no archives. When results are pushed to a cupel account, what travels is the findings payload: advisory ids, package names and versions, verdicts, and path anchors.
Licence
Proprietary — see LICENSE. Not open source.
https://cupel.sh
