{"id":51637248,"url":"https://github.com/igorjs/sentinel","last_synced_at":"2026-07-13T15:32:32.871Z","repository":{"id":368828666,"uuid":"1275220434","full_name":"igorjs/sentinel","owner":"igorjs","description":"Generic GitHub Action that opens auto-PRs for OSV-driven dependency bumps across rust, go, javascript, python","archived":false,"fork":false,"pushed_at":"2026-07-02T10:42:17.000Z","size":235,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-02T12:24:57.966Z","etag":null,"topics":["automation","dependencies","github-actions","osv","security","supply-chain"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/igorjs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING-RULES.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["igorjs"],"buy_me_a_coffee":"igorjs"}},"created_at":"2026-06-20T12:08:35.000Z","updated_at":"2026-07-02T10:42:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/igorjs/sentinel","commit_stats":null,"previous_names":["igorjs/sentinel"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/igorjs/sentinel","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorjs%2Fsentinel","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorjs%2Fsentinel/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorjs%2Fsentinel/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorjs%2Fsentinel/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/igorjs","download_url":"https://codeload.github.com/igorjs/sentinel/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/igorjs%2Fsentinel/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35427834,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-13T02:00:06.543Z","response_time":119,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","dependencies","github-actions","osv","security","supply-chain"],"created_at":"2026-07-13T15:32:32.016Z","updated_at":"2026-07-13T15:32:32.862Z","avatar_url":"https://github.com/igorjs.png","language":"Python","funding_links":["https://github.com/sponsors/igorjs","https://buymeacoffee.com/igorjs"],"categories":[],"sub_categories":[],"readme":"# Sentinel\n\n\u003e Auto-PRs that patch vulnerable dependencies, driven by the [OSV](https://osv.dev) database, across Rust, Go, JavaScript, and Python.\n\n[![CI](https://github.com/igorjs/sentinel/actions/workflows/ci.yml/badge.svg)](https://github.com/igorjs/sentinel/actions/workflows/ci.yml)\n[![Release](https://img.shields.io/github/v/release/igorjs/sentinel?sort=semver)](https://github.com/igorjs/sentinel/releases)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/igorjs/sentinel/badge)](https://securityscorecards.dev/viewer/?uri=github.com/igorjs/sentinel)\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)\n\nSentinel watches your dependencies with OSV. When a fix lands for a known advisory, it opens a pull request that bumps to the minimum version closing it. You review, you merge, nothing auto-merges. It covers what Dependabot's security updates leave out: OSV's wider advisory set (RUSTSEC, Go, and PyPI natively), language-runtime pins, vendored release pins, and self-cleaning suppression lists.\n\n## Highlights\n\n- **OSV-driven security bumps** across Rust, Go, npm, and PyPI, to the minimum version that closes the advisory.\n- **More than dep versions**: raises end-of-life language runtimes, Docker base images, and CI version matrices, and re-pins vendored release artefacts.\n- **Self-cleaning**: strips stale `osv-scanner.toml` / `deny.toml` ignore entries once a bump retires them.\n- **Safe by default**: every change is a PR you review, and a `min_severity` gate keeps the noise down.\n- **No Dependabot overlap**: security-fix bumps only; routine freshness stays Dependabot's job, or opt in per scope.\n\n## Quick start\n\nCreate `.github/workflows/sentinel.yml`:\n\n```yaml\nname: Sentinel\non:\n  schedule:\n    - cron: \"0 6 * * 1\"   # Mondays 06:00 UTC\n  workflow_dispatch:\n    inputs:\n      dry_run:\n        type: boolean\n        default: false\n\npermissions:\n  contents: write\n  pull-requests: write\n  issues: write\n\nconcurrency:\n  group: sentinel\n  cancel-in-progress: true\n\njobs:\n  discover:\n    runs-on: ubuntu-latest\n    outputs:\n      scopes: ${{ steps.s.outputs.scopes }}\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: igorjs/sentinel/discover@v1\n        id: s\n\n  run:\n    needs: discover\n    if: needs.discover.outputs.scopes != '[]'\n    runs-on: ubuntu-latest\n    strategy:\n      fail-fast: false\n      matrix:\n        scope: ${{ fromJson(needs.discover.outputs.scopes) }}\n    steps:\n      - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n      - uses: igorjs/sentinel@v1\n        with:\n          scope: ${{ matrix.scope }}\n          dry_run: ${{ inputs.dry_run || false }}\n```\n\nNo config file needed for a default repo layout. The `discover` job auto-detects which scopes apply and fans the `run` job out over them.\n\n## Scopes\n\nSentinel picks the scopes that apply from the files in your repo.\n\n| Scope | Detected by | What it bumps | Runtime EOL |\n|---|---|---|---|\n| `rust` | `Cargo.lock` | Cargo deps via `cargo update --precise`, self-cleans `osv-scanner.toml` / `deny.toml` | N/A |\n| `go` | `go.mod` | Module deps via `go get` + `go mod tidy`, optionally the `go \u003cversion\u003e` directive | On by default |\n| `javascript` | `package.json` | npm deps via npm / pnpm / yarn (lockfile-detected) | Opt-in |\n| `python` | `pyproject.toml`, `requirements.txt`, or a lockfile | PyPI deps via poetry / uv / pipenv (lockfile-detected) | Opt-in |\n| `docker` | `Dockerfile` (recursive) | EOL `python` / `node` base-image tags | Opt-in |\n| `ci` | `.github/workflows/*.yml` | EOL `python-version` / `node-version` matrices and runner OS labels | Opt-in |\n\nA repo without a lockfile gets a \"no lockfile\" issue instead of a risky bump.\n\n## Configuration\n\nEverything below is optional and lives in `.github/sentinel.toml`.\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eSeverity gating\u003c/b\u003e\u003c/summary\u003e\n\nBy default Sentinel acts on every fixable advisory. To act only at or above a severity, set `min_severity` (`none`, `low`, `medium`, `high`, `critical`) globally or per scope:\n\n```toml\n[defaults]\nmin_severity = \"high\"      # global floor\n\n[scopes.javascript]\nmin_severity = \"critical\"  # stricter for one scope\n```\n\nSeverity comes from the CVSS score `osv-scanner` reports. Advisories with no severity data are bumped anyway (the PR says so), so a serious-but-unscored CVE is never silently skipped. `gh-release-pin` scopes are freshness-driven and aren't gated.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eRuntime EOL bumps (opt-in)\u003c/b\u003e\u003c/summary\u003e\n\nSet `update_runtime = true` on a scope to open PRs that raise an end-of-life (or near-EOL) runtime to the oldest still-supported version. EOL dates come from [endoflife.date](https://endoflife.date), and these PRs ignore `min_severity`. `runtime_eol_lead_days` (default `30`) opens the PR that many days before the EOL date.\n\n- **Python** reads `requires-python`, `.python-version`, `.tool-versions`, and mise configs.\n- **Node** reads `engines.node`, `.nvmrc`, `.node-version`, `.tool-versions`, and mise configs.\n- **Docker** (`[scopes.docker]`) raises EOL `python` / `node` base-image tags, preserving the variant suffix (`-slim`, `-alpine`, ...); digest-pinned bases are reported in an issue, not edited.\n- **CI** (`[scopes.ci]`) rewrites EOL `python-version` / `node-version` matrices and EOL runner OS labels (`runs-on:`, `strategy.matrix.os:`), preserving quoting and comments; `*-latest` and `${{ ... }}` are left alone.\n\nWhen a floor bump touches `requires-python` or `engines.node`, Sentinel refreshes the matching lockfile so the recorded constraint stays consistent, or opens an issue if the package manager isn't available.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eVersion freshness (opt-in)\u003c/b\u003e\u003c/summary\u003e\n\nSet `update_freshness = true` on the `javascript` scope to bump outdated npm deps to the newest version within their declared range. It runs separately from security bumps, on the `sentinel/javascript/freshness` branch.\n\n- `freshness_level`: `range` (default) stays within the constraint; `major` crosses it to the absolute latest.\n- `freshness_group`: `scope` (default) is one PR; `dependency` is one PR per dep.\n- `freshness_include` / `freshness_exclude`: dependency-name globs (exclude wins) to avoid overlapping with Dependabot.\n\nIf `.github/dependabot.yml` exists, the PR notes it. Slice 1 covers npm; pnpm/yarn and the other ecosystems follow.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eCustom vendor pins (gh-release-pin)\u003c/b\u003e\u003c/summary\u003e\n\nFor a vendored artefact pinned in a workflow YAML, declare a `gh-release-pin` custom scope:\n\n```toml\n[[custom]]\nname = \"libkrun-bottle\"\nkind = \"gh-release-pin\"\nupstream_repo = \"igorjs/libkrun-builds\"\ntarget_file = \".github/workflows/release.yml\"\ntarget_kind = \"yaml-env-var\"\nenv_var = \"LIBKRUN_BOTTLE_VERSION\"\n# env_path = \"jobs.publish.env\"   # optional; default \"env\" (top-level)\n```\n\nSentinel opens a PR when upstream cuts a newer release.\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eSuppression recovery\u003c/b\u003e\u003c/summary\u003e\n\n`osv-scanner` hides advisories listed in `osv-scanner.toml`'s `IgnoredVulns`, so Sentinel runs a second scan that bypasses the ignore list. If an advisory you suppressed (say, when no fix existed) now has one, Sentinel opens a normal bump PR, and the `rust` scope's PR strips the now-removable `osv-scanner.toml` / `deny.toml` entry. A human still reviews it, so a deliberately-kept suppression can be declined.\n\u003c/details\u003e\n\n## Sentinel vs Dependabot\n\nDependabot already does CVE-driven security updates to the minimum patched version. Sentinel overlaps there and differs on the rest:\n\n| Dimension | Dependabot | Sentinel |\n|---|---|---|\n| Advisory source | GitHub Advisory Database | OSV (RUSTSEC, Go, PyPI, npm, crates.io, ...) |\n| Freshness updates | Yes, picks latest | No, left to Dependabot (or opt in) |\n| Security updates | Yes, minimum patched version | Yes, minimum version that closes the OSV advisory |\n| Beyond dep versions | None | Language-runtime pins + `gh-release-pin` vendor pins |\n| Suppression lists | Manual `dependabot.yml` block | Reads and self-cleans `osv-scanner.toml` / `deny.toml` |\n| Severity gating | Not configurable per run | `min_severity` (global and per-scope) |\n\n## License\n\n[Apache-2.0](LICENSE).\n\u003c/content\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorjs%2Fsentinel","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Figorjs%2Fsentinel","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Figorjs%2Fsentinel/lists"}