{"id":46638441,"url":"https://github.com/moolen/patchpilot","last_synced_at":"2026-04-23T08:02:07.237Z","repository":{"id":342917557,"uuid":"1175602348","full_name":"moolen/PatchPilot","owner":"moolen","description":"Bump just the CVEs","archived":false,"fork":false,"pushed_at":"2026-03-13T15:53:56.000Z","size":728,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-13T20:25:12.343Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/moolen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-03-07T23:30:21.000Z","updated_at":"2026-03-13T15:54:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/moolen/PatchPilot","commit_stats":null,"previous_names":["moolen/patchpilot"],"tags_count":53,"template":false,"template_full_name":null,"purl":"pkg:github/moolen/PatchPilot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moolen%2FPatchPilot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moolen%2FPatchPilot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moolen%2FPatchPilot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moolen%2FPatchPilot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moolen","download_url":"https://codeload.github.com/moolen/PatchPilot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moolen%2FPatchPilot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32171223,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-23T02:19:40.750Z","status":"ssl_error","status_checked_at":"2026-04-23T02:17:55.737Z","response_time":53,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2026-03-08T02:14:45.670Z","updated_at":"2026-04-23T08:02:07.227Z","avatar_url":"https://github.com/moolen.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PatchPilot\n\n`PatchPilot` is a Go CLI that fixes known vulnerabilities in a source repository by upgrading only the minimal dependency versions required by `grype` findings.\n\nIt uses existing security tooling for discovery and keeps remediation narrow: no custom CVE database, no feature-chasing upgrades, and no unnecessary version bumps.\n\n## Commands\n\n- `patchpilot scan [repo]`: generate an SBOM with `syft`, scan it with `grype`, and write normalized findings to `\u003crepo\u003e/.patchpilot/`.\n- `patchpilot fix [repo]`: scan, apply minimal dependency fixes, run standard verification across discovered Go modules, re-scan, and write summaries into `\u003crepo\u003e/.patchpilot/`.\n- `patchpilot verify [repo]`: re-run the scan and standard verification checks, then compare against the saved baselines.\n- `patchpilot schema`: print the JSON schema for `.patchpilot.yaml` (useful for editor validation/CI checks).\n\nGlobal flags:\n\n- `--dir \u003cpath\u003e`: use a specific local directory as the working repository.\n- `--repo-url \u003cgit-url\u003e`: clone a repository into a temporary directory and use that clone as the working repository.\n- `--policy \u003cpath\u003e`: load a central policy file and combine it with `\u003crepo\u003e/.patchpilot.yaml` when present.\n- `--policy-mode \u003cmerge|override\u003e`: policy layering strategy when `--policy` is set.\n  `merge`: deep-merge central + in-repo policy (in-repo values take precedence for scalar fields; list fields are combined).\n  `override`: if `\u003crepo\u003e/.patchpilot.yaml` exists, use it instead of the central policy; otherwise use the central policy.\n- `--json`: emit structured JSON progress logs with `run_id`, `command`, and `repo`.\n\nExit codes for CI:\n\n- `20`: scan failed (SBOM generation or vulnerability scan failed)\n- `21`: patch failed (dependency patch application failed)\n- `22`: verification regressed (a previously passing verification check now fails/timeouts)\n- `23`: vulnerabilities remain after command completion\n\nWhen multiple failure conditions apply, precedence is: scan/patch failures first, then verification regressions, then vulnerabilities remaining.\n\n## How it works\n\n1. Generate an SBOM with `syft` into `.patchpilot/sbom.json`.\n2. Scan the SBOM with `grype` into `.patchpilot/vulns.json`.\n3. Normalize only findings that include a known fix version.\n4. Apply direct Go fixes with `golang.org/x/mod/modfile`.\n5. Apply transitive Go fixes with `go list -m all` plus `go get module@fixedVersion` when a vulnerable module is present in the module build list.\n6. Automatically bump each `go.mod` `go` directive to the latest supported patch release on the same Go major/minor line (or the oldest currently supported line if the current line is no longer supported).\n7. Parse Dockerfiles and update each `FROM` base image according to `oci.policies`; container OS package remediation is handled through agent mode.\n8. Patch `package.json` dependencies for npm findings and automatically sync `package-lock.json` / `npm-shrinkwrap.json` when present.\n9. Patch `requirements*.txt` entries for Python/PyPI findings.\n10. Patch `pom.xml` and `build.gradle*` dependency versions for Maven/Gradle findings.\n11. Patch `Cargo.toml` dependencies for Cargo findings.\n12. Patch `.csproj` package references for NuGet findings.\n13. Patch `composer.json` requirements for Composer findings.\n14. Run standard verification checks: Go build/test-compile for discovered Go modules plus manifest syntax/parse checks for npm, pip, Maven, Gradle, Cargo, NuGet, and Composer.\n15. Re-scan and report before/fixed/remaining counts plus any verification regressions.\n\nWhen `.patchpilot.yaml` is present, scan/fix/verify also apply repo-specific policy.\nIn enterprise setups, `--policy` can provide a central baseline policy that is layered with the in-repo file:\n\n- `--policy-mode merge` (default): central baseline plus repo-specific adjustments.\n- `--policy-mode override`: repo file fully replaces central baseline.\n\nRepo-local policy always has precedence over central policy when both are considered.\n\nPolicy controls include:\n\n- vulnerability/CVE excludes,\n- skip-paths for scanning/module discovery/fixers,\n- registry cache/auth configuration for Docker tag/digest resolution,\n- Docker base-image allow/deny policy, patch toggles, and rule-driven tag selection for `FROM` images,\n- container image target mapping (static or command-discovered),\n- Go runtime remediation policy (`disabled`, `toolchain`, `minimum`),\n- Dependabot-style deterministic fixer toggles per ecosystem (`fix.updates`, default `github-actions` disabled),\n- custom prompt snippets for agent remediation loops and failure points.\n\n## Requirements\n\n- `syft`\n- `grype`\n- Go toolchain\n\n## GitHub Integrations\n\n- GitHub App service docs: `docs/github-app.md`\n- Observability docs: `docs/observability.md`\n- Reusable GitHub Action docs: `docs/github-action.md`\n- Action tag sync workflow: `.github/workflows/action-tags.yml`\n\nBuild both binaries locally:\n\n```bash\nmake build\n```\n\n- `bin/patchpilot`: PatchPilot CLI binary\n- `bin/patchpilot-app`: scheduler service for GitHub App automation\n\nBuild the GitHub App container image locally:\n\n```bash\ndocker build -f Dockerfile.patchpilot-app -t patchpilot-app:dev .\ndocker run --rm \\\n  -p 8080:8080 \\\n  -e PP_APP_ID=123 \\\n  -e PP_PRIVATE_KEY_PATH=/run/secrets/patchpilot.pem \\\n  -v \"$PWD/private-key.pem:/run/secrets/patchpilot.pem:ro\" \\\n  patchpilot-app:dev\n```\n\nThe app image includes `patchpilot-app`, `patchpilot`, `git`, `syft`, `grype`, `go`, `node`, `npm`, and `cargo` so the default local job runner can scan and remediate repositories without additional sidecar tooling.\nThe scheduler service can also run in explicit-allowlist token mode with `PP_GITHUB_AUTH_MODE=token`, `PP_GITHUB_TOKEN`, and `PP_GITHUB_TOKEN_REPOSITORIES`.\nFor operator-managed external OCI mappings (and optional app-level remediation settings), point `PP_GITHUB_APP_CONFIG_FILE` or `PP_OCI_MAPPING_FILE` at a YAML file.\nSet `PP_FORCE_RECONCILE_ON_START=true` or run `./bin/patchpilot-app run --force-reconcile-on-start` to force one immediate reconciliation cycle at process start.\n\nGitHub App utility commands:\n\n- `./bin/patchpilot-app doctor`: validate environment and dependencies.\n- `./bin/patchpilot-app manifest`: emit a starter GitHub App manifest JSON.\n\n## Example\n\n```bash\npatchpilot scan ~/dev/external-secrets/external-secrets\npatchpilot fix ~/dev/external-secrets/external-secrets\npatchpilot verify ~/dev/external-secrets/external-secrets\npatchpilot scan --dir ~/dev/external-secrets/external-secrets\npatchpilot fix --repo-url https://github.com/external-secrets/external-secrets.git\npatchpilot fix --dir ~/dev/external-secrets/external-secrets --policy ~/policies/org-baseline.yaml --policy-mode merge\npatchpilot fix --dir ~/dev/external-secrets/external-secrets --policy ~/policies/org-baseline.yaml --policy-mode override\n```\n\n## Agent Artifacts\n\nWhen agent mode is enabled, PatchPilot stores per-attempt artifacts that include:\n\n- `prompt.txt` (input prompt sent to the external agent)\n- `agent.log` (captured stdout/stderr from the agent command)\n- `validation.log` (post-attempt validation output)\n- `summary.json` (attempt success and vulnerability delta)\n\nDefaults and controls:\n\n- default artifact path: `\u003crepo\u003e/.patchpilot/agent`\n- override path: `--agent-artifact-dir \u003cpath\u003e`\n- default non-interactive command: `codex exec ... \u003c \"$PATCHPILOT_PROMPT_FILE\"`\n\n## Policy File\n\nCreate `\u003crepo\u003e/.patchpilot.yaml` to control behavior per repository.\nUse `--policy` to add a central baseline policy on top.\n\nFull example (`.patchpilot.yaml`, all supported top-level keys):\n\n```yaml\nversion: 1\n\nexclude:\n  cves:\n    - CVE-2025-12345\n  cve_rules:\n    - id: CVE-2025-22222\n      package: github.com/example/legacy-lib\n      ecosystem: golang\n      path: services/api/go.mod\n      reason: pending upstream patch\n      owner: team-security\n      expires_at: 2026-12-31\n  vulnerabilities:\n    - id: GHSA-xxxx-yyyy-zzzz\n      package: openssl\n      ecosystem: deb\n      path: images/Dockerfile\n      reason: accepted temporary risk\n      owner: team-platform\n      expires_at: 2026-06-30\n\nscan:\n  cron: \"0 3 * * *\"\n  timezone: Europe/Berlin\n  skip_paths:\n    - vendor/**\n    - examples/legacy/**\n    - third_party/**\n\nregistry:\n  cache:\n    dir: .patchpilot-cache/registry\n    ttl: 4h\n  auth:\n    mode: bearer # auto | none | bearer\n    token_env: REGISTRY_TOKEN # required when mode=bearer\n\noci:\n  policies:\n    - name: golang-alpine-stable\n      source: docker.io/library/golang\n      tags:\n        allow:\n          - '^v?\\d+\\.\\d+\\.\\d+-alpine$'\n        semver:\n          - range:\n              - \"\u003e=1.24.3 \u003c2.0.0\"\n            includePrerelease: false\n            prereleaseAllow: []\n        deny:\n          - '.*-debug$'\n  external_images:\n    - source: ghcr.io/external-secrets/external-secrets\n      dockerfiles:\n        - Dockerfile\n      tag: latest-semver\n\ngo:\n  patching:\n    runtime: minimum # disabled | toolchain | minimum\n\nfix:\n  updates:\n    - package-ecosystem: \"*\" # applies to all deterministic fix ecosystems\n      enabled: true\n    - package-ecosystem: github-actions\n      enabled: false # default unless explicitly enabled\n    - package-ecosystem: gomod\n      enabled: true\n\nagent:\n  remediation_prompts:\n    all:\n      - mode: extend # extend | replace\n        template: |\n          follow org policy for upgrades and changelog notes\n    baseline_scan_repair:\n      all:\n        - mode: extend\n          template: |\n            keep baseline scan behavior intact; fix root causes\n      generate_baseline_sbom:\n        - mode: extend\n          template: |\n            if syft fails, fix manifest or build tooling issues first\n      scan_baseline:\n        - mode: extend\n          template: |\n            keep artifact scans enabled; fix docker/build context issues instead\n    fix_vulnerabilities:\n      all:\n        - mode: extend\n          template: |\n            prefer smallest safe change set\n      deterministic_fix_failed:\n        - mode: extend\n          template: |\n            do not bypass lockfile updates to silence deterministic engine errors\n      validation_failed:\n        - mode: extend\n          template: |\n            make validation pass without disabling checks\n      vulnerabilities_remaining:\n        - mode: extend\n          template: |\n            focus on findings that still have fix versions\n      verification_regressed:\n        - mode: extend\n          template: |\n            restore previous verification behavior before finalizing\n```\n\nRemediation prompt templates receive the current prompt context, including fields such as `RepoPath`, `AttemptNumber`, `TaskKind`, `Goal`, `FailureStage`, `FailureError`, `CurrentState`, `ValidationPlan`, `Constraints`, `DefaultPrompt`, and `PromptSoFar`. `extend` appends rendered output to the current prompt; `replace` replaces the current prompt with the rendered output.\n\nUse `go.patching.runtime: toolchain` for OSS libraries that want to prefer a patched local toolchain without hard-raising the declared minimum Go version. Use `minimum` for applications or enterprise environments that want to require the patched Go version everywhere.\n\nPolicy parsing is strict after applying built-in legacy migrations (for example top-level `skip_paths` -\u003e `scan.skip_paths`). Unknown keys still fail fast to avoid silent misconfiguration.\n\n### OCI v2 Migration Notes\n\nRemoved configuration keys:\n\n- `.patchpilot.yaml`: `docker`, `artifacts`, `pre_execution`, `verification`, `post_execution`\n- app runtime config: `repositories`\n\nReplacement keys:\n\n- `.patchpilot.yaml`: `oci.policies`, `oci.external_images`\n- app/runtime mapping file: `oci.mappings`\n\nIf removed keys are still present, policy parsing fails fast with an unknown-field validation error.\n\n## OCI Base Image Policies\n\nPatchPilot uses `oci.policies` to decide how each `FROM \u003cimage\u003e` should be bumped.\n\n```yaml\noci:\n  policies:\n    - name: kyverno-stable\n      source: ghcr.io/kyverno/**\n      tags:\n        allow:\n          - '^v?\\d+\\.\\d+\\.\\d+(-alpine\\d+\\.\\d+)?$'\n        semver:\n          - range:\n              - \"\u003e=1.15.0 \u003c2.0.0\"\n            includePrerelease: false\n            prereleaseAllow: []\n        deny:\n          - '.*-debug$'\n```\n\nBehavior:\n\n- `source` supports doublestar wildcard matching (`**`).\n- First matching policy wins. If multiple policies match, PatchPilot logs a warning and still uses the first.\n- Filter order is `allow -\u003e semver/prerelease -\u003e deny`.\n- If no policy matches, PatchPilot picks latest semver by default.\n- If current tag has a prerelease/suffix family, default mode keeps that exact family.\n- If the `FROM` reference is digest-pinned, PatchPilot updates both tag and digest.\n\n## External OCI Image Scanning\n\nExternal image scanning is configured via `oci.external_images` in `.patchpilot.yaml`:\n\n```yaml\noci:\n  external_images:\n    - source: ghcr.io/external-secrets/external-secrets\n      dockerfiles:\n        - Dockerfile\n      tag: latest-semver\n```\n\nYou can also provide an operator-managed mapping file and select by repository:\n\n```yaml\noci:\n  mappings:\n    - repo: external-secrets/external-secrets\n      images:\n        - source: ghcr.io/external-secrets/external-secrets\n          dockerfiles:\n            - Dockerfile\n          tag: latest-semver\n```\n\nCLI usage:\n\n```bash\npatchpilot scan --dir \u003crepo\u003e --repository-key external-secrets/external-secrets --oci-mapping-file ./oci-mappings.yaml\npatchpilot fix --dir \u003crepo\u003e --repository-key external-secrets/external-secrets --oci-mapping-file ./oci-mappings.yaml\n```\n\nBehavior:\n\n- No local image build step is performed for external OCI scanning.\n- PatchPilot pulls each mapped image, generates an SBOM, and scans it.\n- Only container ecosystems (`deb`, `apk`, `rpm`) are mapped back to configured Dockerfiles.\n- Repo-local `.patchpilot.yaml` mappings take precedence over mapping-file entries for the same image source.\n\n## Output\n\nEach run writes state into `\u003crepo\u003e/.patchpilot/`, including:\n\n- `sbom.json`\n- `vulns.json`\n- `findings.json`\n- `findings.sarif`\n- `baseline-findings.json`\n- `summary.json`\n- `run.json`\n- `verification-baseline.json`\n- `verification.json`\n\n`run.json` contains staged telemetry for scan/fix/verify:\n\n- run metadata (`run_id`, command, start/end timestamps, duration),\n- per-stage timings and errors,\n- machine-readable failure taxonomy (`policy_violation`, `scan_failed`, `no_automated_fix_available`, `partial_fix_applied`, `verification_regressed`, ...),\n- counters (before/fixed/after, regressions).\n\n## Proof Of Work\n\nAgainst `~/dev/external-secrets/external-secrets`, the tool reduced the source-focused fixable vulnerability count from `22` to `0` after the direct and transitive Go-module passes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoolen%2Fpatchpilot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoolen%2Fpatchpilot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoolen%2Fpatchpilot/lists"}