Compare commits

...

93 Commits

Author SHA1 Message Date
mr-tz
48fc4a54de add gemini cli workflows 2025-08-08 09:24:35 +00:00
Capa Bot
eb0afc806e Sync capa rules submodule 2025-08-04 18:41:07 +00:00
dependabot[bot]
9a09f667bf build(deps): bump flake8 from 7.2.0 to 7.3.0 (#2697)
Bumps [flake8](https://github.com/pycqa/flake8) from 7.2.0 to 7.3.0.
- [Commits](https://github.com/pycqa/flake8/compare/7.2.0...7.3.0)

---
updated-dependencies:
- dependency-name: flake8
  dependency-version: 7.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-24 09:30:33 -06:00
dependabot[bot]
15a1dc3409 build(deps): bump ruff from 0.11.0 to 0.12.0 (#2698)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.11.0 to 0.12.0.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.11.0...0.12.0)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-24 09:30:20 -06:00
Capa Bot
a18fe34d01 Sync capa rules submodule 2025-06-20 16:16:27 +00:00
Capa Bot
edcea18c52 Sync capa-testfiles submodule 2025-06-17 19:17:09 +00:00
dependabot[bot]
92f0306f96 build(deps): bump mypy from 1.15.0 to 1.16.0 (#2696)
Bumps [mypy](https://github.com/python/mypy) from 1.15.0 to 1.16.0.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.15.0...v1.16.0)

---
updated-dependencies:
- dependency-name: mypy
  dependency-version: 1.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-16 12:00:21 -06:00
dependabot[bot]
f2ed75c339 build(deps): bump protobuf from 6.30.1 to 6.31.1 (#2686)
Bumps [protobuf](https://github.com/protocolbuffers/protobuf) from 6.30.1 to 6.31.1.
- [Release notes](https://github.com/protocolbuffers/protobuf/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf/blob/main/protobuf_release.bzl)
- [Commits](https://github.com/protocolbuffers/protobuf/compare/v6.30.1...v6.31.1)

---
updated-dependencies:
- dependency-name: protobuf
  dependency-version: 6.31.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-06-11 16:28:23 -06:00
dependabot[bot]
6e18657ca7 build(deps): bump types-protobuf from 5.29.1.20241207 to 6.30.2.20250516 (#2687)
Bumps [types-protobuf](https://github.com/typeshed-internal/stub_uploader) from 5.29.1.20241207 to 6.30.2.20250516.
- [Commits](https://github.com/typeshed-internal/stub_uploader/commits)

---
updated-dependencies:
- dependency-name: types-protobuf
  dependency-version: 6.30.2.20250516
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-06-11 16:28:11 -06:00
dependabot[bot]
8ba48d11d0 build(deps): bump pyinstaller from 6.12.0 to 6.14.1 (#2688)
Bumps [pyinstaller](https://github.com/pyinstaller/pyinstaller) from 6.12.0 to 6.14.1.
- [Release notes](https://github.com/pyinstaller/pyinstaller/releases)
- [Changelog](https://github.com/pyinstaller/pyinstaller/blob/develop/doc/CHANGES.rst)
- [Commits](https://github.com/pyinstaller/pyinstaller/compare/v6.12.0...v6.14.1)

---
updated-dependencies:
- dependency-name: pyinstaller
  dependency-version: 6.14.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-06-11 16:27:52 -06:00
Mike Hunhoff
d6f442b5bd ci: remove redundant "test_run" action (#2692)
* ci: remove redundant "test_run" action

* update CHANGELOG
2025-06-10 16:43:10 -06:00
Spencer Heywood
0da5d7c5b5 add support for arm64 binary releases (#2691) 2025-06-10 15:52:55 -06:00
Mike Hunhoff
fa5d9a9302 v9.2.1 (#2685) 2025-06-06 14:16:25 -06:00
Mike Hunhoff
30fb4751f6 fix build issues discovered during and after v9.2.0 release (#2684)
* ci: downgrade Ubuntu version to accommodate older GLIBC versions

* ci: upgrade Windows version to avoid deprecation

* ci: exclude pkg_resources from PyInstaller build

* update CHANGELOG

* update spec file

* ci: check if build runs without warnings or errors

* update CHANGELOG

* update build commands

* update build commands

* update build commands

* update build commands

* update build commands
2025-06-06 12:02:06 -06:00
Mike Hunhoff
a8eab7ddf0 update "publish package" worflow to 1.12.4 (#2680) 2025-06-05 13:44:30 -06:00
Mike Hunhoff
5ad1dda918 v9.2.0 (#2677) 2025-06-05 09:03:56 -06:00
Capa Bot
eabb2cc809 Sync capa rules submodule 2025-06-02 19:16:57 +00:00
Capa Bot
a34c3ecc57 Sync capa rules submodule 2025-06-02 18:47:17 +00:00
dependabot[bot]
d22de5cf7f build(deps): bump rich from 13.9.2 to 14.0.0 (#2675)
Bumps [rich](https://github.com/Textualize/rich) from 13.9.2 to 14.0.0.
- [Release notes](https://github.com/Textualize/rich/releases)
- [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Textualize/rich/compare/v13.9.2...v14.0.0)

---
updated-dependencies:
- dependency-name: rich
  dependency-version: 14.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 12:39:31 -06:00
dependabot[bot]
8f78834cae build(deps): bump setuptools from 78.1.1 to 80.9.0 (#2674)
Bumps [setuptools](https://github.com/pypa/setuptools) from 78.1.1 to 80.9.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v78.1.1...v80.9.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-version: 80.9.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 12:39:08 -06:00
dependabot[bot]
08dbb0e02d build(deps): bump flake8-simplify from 0.21.0 to 0.22.0 (#2673)
Bumps [flake8-simplify](https://github.com/MartinThoma/flake8-simplify) from 0.21.0 to 0.22.0.
- [Release notes](https://github.com/MartinThoma/flake8-simplify/releases)
- [Changelog](https://github.com/MartinThoma/flake8-simplify/blob/main/CHANGELOG.md)
- [Commits](https://github.com/MartinThoma/flake8-simplify/commits)

---
updated-dependencies:
- dependency-name: flake8-simplify
  dependency-version: 0.22.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-02 12:38:41 -06:00
Mike Hunhoff
98725c52dc vmray: do not restrict analysis to PE and ELF files, e.g. docx (#2672)
* vmray: do not restrict analysis to PE and ELF files, e.g. docx

* update CHANGELOG
2025-05-30 13:53:12 -06:00
dependabot[bot]
eb87153064 build(deps): bump setuptools from 76.0.0 to 78.1.1 (#2667)
Bumps [setuptools](https://github.com/pypa/setuptools) from 76.0.0 to 78.1.1.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v76.0.0...v78.1.1)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-version: 78.1.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Moritz <mr-tz@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-05-30 12:35:35 -06:00
dependabot[bot]
56aa7176b0 build(deps): bump pip from 25.0 to 25.1.1 (#2666)
Bumps [pip](https://github.com/pypa/pip) from 25.0 to 25.1.1.
- [Changelog](https://github.com/pypa/pip/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/pip/compare/25.0...25.1.1)

---
updated-dependencies:
- dependency-name: pip
  dependency-version: 25.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Moritz <mr-tz@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-05-30 12:35:15 -06:00
dependabot[bot]
8b41671409 build(deps): bump flake8 from 7.1.1 to 7.2.0 (#2648)
* build(deps): bump flake8 from 7.1.1 to 7.2.0

Bumps [flake8](https://github.com/pycqa/flake8) from 7.1.1 to 7.2.0.
- [Commits](https://github.com/pycqa/flake8/compare/7.1.1...7.2.0)

---
updated-dependencies:
- dependency-name: flake8
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix lints (#2671)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-05-30 12:09:16 -06:00
dependabot[bot]
5dbbc2b468 build(deps): bump pre-commit from 4.1.0 to 4.2.0 (#2646)
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 4.1.0 to 4.2.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v4.1.0...v4.2.0)

---
updated-dependencies:
- dependency-name: pre-commit
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-05-30 11:28:19 -06:00
Mike Hunhoff
96d1eb64c3 update binja core version (#2670)
* update binja core version

* update CHANGELOG
2025-05-30 10:52:56 -06:00
Capa Bot
9234b33051 Sync capa rules submodule 2025-05-28 20:44:44 +00:00
Capa Bot
51f5114ad7 Sync capa rules submodule 2025-05-22 18:53:54 +00:00
Capa Bot
4b72f8a872 Sync capa-testfiles submodule 2025-05-22 17:48:58 +00:00
Moritz
8206a97b0f Merge pull request #2659 from mandiant/dependabot/npm_and_yarn/web/explorer/vite-6.3.4
build(deps-dev): bump vite from 6.2.3 to 6.3.4 in /web/explorer
2025-05-20 16:47:50 +02:00
Capa Bot
5a33b4b2a8 Sync capa rules submodule 2025-05-19 18:21:38 +00:00
Capa Bot
fcfdeec377 Sync capa rules submodule 2025-05-19 18:21:13 +00:00
Capa Bot
37a63a751c Sync capa-testfiles submodule 2025-05-19 18:12:00 +00:00
zdw@
3a9f2136bb lint: log the failed example+rule (#2661)
* lint: log the failed example+rule

* Update scripts/lint.py

Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>

* fix lint

---------

Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-05-12 15:11:22 -06:00
Capa Bot
390e2a6315 Sync capa-testfiles submodule 2025-05-12 16:17:27 +00:00
Capa Bot
6a43084915 Sync capa-testfiles submodule 2025-05-12 16:06:51 +00:00
dependabot[bot]
6d7ca57fa9 build(deps): bump pydantic from 2.10.1 to 2.11.4 (#2660)
Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.10.1 to 2.11.4.
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.10.1...v2.11.4)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-version: 2.11.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-12 09:48:46 -06:00
Ana María Martínez Gómez
d1090e8391 ci: Update Ubuntu version in actions (#2656)
ubuntu-20.04 has been deprecated causing several GH actions to fail:
https://github.com/actions/runner-images/issues/11101
2025-05-09 15:40:59 -06:00
dependabot[bot]
b07efe773b build(deps-dev): bump vite from 6.2.3 to 6.3.4 in /web/explorer
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.3 to 6.3.4.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.3.4/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.3.4
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-30 18:53:28 +00:00
Moritz
9d3d3be21d Merge pull request #2644 from mandiant/dependabot/npm_and_yarn/web/explorer/vite-6.2.3 2025-03-25 22:06:15 +01:00
dependabot[bot]
8251a4c16f build(deps-dev): bump vite from 6.2.2 to 6.2.3 in /web/explorer
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.2 to 6.2.3.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.3/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.3/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-25 15:30:15 +00:00
Mike Hunhoff
7407cb39ca add lint for registry control set regex that is not complete (#2643)
* add lint for registry control set regex that is not complete

* update CHANGELOG
2025-03-24 12:17:12 -06:00
Capa Bot
0162e447fd Sync capa rules submodule 2025-03-24 16:38:44 +00:00
Capa Bot
829dae388f Sync capa rules submodule 2025-03-21 16:15:53 +00:00
Capa Bot
2a4d0ae080 Sync capa rules submodule 2025-03-21 14:40:08 +00:00
Capa Bot
d9a754730c Sync capa rules submodule 2025-03-20 15:06:54 +00:00
Capa Bot
4acacba9d6 Sync capa rules submodule 2025-03-20 15:00:54 +00:00
Capa Bot
d00f172973 Sync capa rules submodule 2025-03-19 17:29:32 +00:00
Mike Hunhoff
1572dd87ed lint: add WARN for regex features that contain unescaped dot (#2635)
* lint: add WARN for regex features that contain unescaped dot

* refactor comments

* update CHANGELOG

* address PR feedback

* Update scripts/lint.py

Co-authored-by: Willi Ballenthin <wballenthin@google.com>

* Update scripts/lint.py

Co-authored-by: Willi Ballenthin <wballenthin@google.com>

---------

Co-authored-by: Willi Ballenthin <wballenthin@google.com>
2025-03-18 15:05:57 -06:00
Capa Bot
23a88fae70 Sync capa rules submodule 2025-03-18 21:02:03 +00:00
dependabot[bot]
474e64cd32 build(deps): bump esbuild, @vitejs/plugin-vue, vite, vite-plugin-singlefile and vitest
Bumps [esbuild](https://github.com/evanw/esbuild) to 0.25.1 and updates ancestor dependencies [esbuild](https://github.com/evanw/esbuild), [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/HEAD/packages/plugin-vue), [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite), [vite-plugin-singlefile](https://github.com/richardtallent/vite-plugin-singlefile) and [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest). These dependencies need to be updated together.


Updates `esbuild` from 0.21.5 to 0.25.1
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2024.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.21.5...v0.25.1)

Updates `@vitejs/plugin-vue` from 5.0.5 to 5.2.3
- [Release notes](https://github.com/vitejs/vite-plugin-vue/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-vue/blob/main/packages/plugin-vue/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-vue/commits/plugin-vue@5.2.3/packages/plugin-vue)

Updates `vite` from 5.4.14 to 6.2.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.2/packages/vite)

Updates `vite-plugin-singlefile` from 2.0.2 to 2.2.0
- [Release notes](https://github.com/richardtallent/vite-plugin-singlefile/releases)
- [Changelog](https://github.com/richardtallent/vite-plugin-singlefile/blob/main/CHANGELOG.md)
- [Commits](https://github.com/richardtallent/vite-plugin-singlefile/commits)

Updates `vitest` from 1.6.1 to 3.0.9
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v3.0.9/packages/vitest)

---
updated-dependencies:
- dependency-name: esbuild
  dependency-type: indirect
- dependency-name: "@vitejs/plugin-vue"
  dependency-type: direct:development
- dependency-name: vite
  dependency-type: direct:development
- dependency-name: vite-plugin-singlefile
  dependency-type: direct:development
- dependency-name: vitest
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-18 09:53:20 -06:00
Willi Ballenthin
c664dc662f changelog 2025-03-18 08:21:51 -06:00
Willi Ballenthin
c1c71613a9 cape: make some pe fields optional
closes #2632

but, pe.imagebase is required, so keeping that (so test field will
continue to fail).
2025-03-18 08:21:51 -06:00
Willi Ballenthin
fa90aae3dc cape: make behavior.summary optional
closes #2631
2025-03-18 08:21:51 -06:00
Capa Bot
7ba02c424e Sync capa rules submodule 2025-03-18 14:02:02 +00:00
dependabot[bot]
f238708ab8 build(deps): bump ruff from 0.9.2 to 0.11.0 (#2629)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.9.2 to 0.11.0.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.9.2...0.11.0)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 16:05:18 -06:00
dependabot[bot]
9c639005ee build(deps): bump protobuf from 5.29.3 to 6.30.1 (#2630)
Bumps [protobuf](https://github.com/protocolbuffers/protobuf) from 5.29.3 to 6.30.1.
- [Release notes](https://github.com/protocolbuffers/protobuf/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf/blob/main/protobuf_release.bzl)
- [Commits](https://github.com/protocolbuffers/protobuf/compare/v5.29.3...v6.30.1)

---
updated-dependencies:
- dependency-name: protobuf
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-17 16:05:05 -06:00
Capa Bot
c37b04fa5f Sync capa rules submodule 2025-03-16 15:15:38 +00:00
Capa Bot
dadd536498 Sync capa rules submodule 2025-03-15 13:04:10 +00:00
Capa Bot
f3b07dba14 Sync capa rules submodule 2025-03-14 17:46:00 +00:00
Capa Bot
66158db197 Sync capa rules submodule 2025-03-14 17:41:46 +00:00
Capa Bot
a4285c013e Sync capa-testfiles submodule 2025-03-11 16:13:03 +00:00
Capa Bot
6924974b6b Sync capa rules submodule 2025-03-11 15:56:55 +00:00
Capa Bot
dc153c4763 Sync capa rules submodule 2025-03-10 20:39:14 +00:00
dependabot[bot]
71a28e4482 build(deps): bump types-psutil from 6.1.0.20241102 to 7.0.0.20250218 (#2617)
Bumps [types-psutil](https://github.com/python/typeshed) from 6.1.0.20241102 to 7.0.0.20250218.
- [Commits](https://github.com/python/typeshed/commits)

---
updated-dependencies:
- dependency-name: types-psutil
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-03-10 14:27:28 -06:00
dependabot[bot]
f6ed36fa0f build(deps): bump pyelftools from 0.31 to 0.32 (#2616)
Bumps [pyelftools](https://github.com/eliben/pyelftools) from 0.31 to 0.32.
- [Changelog](https://github.com/eliben/pyelftools/blob/main/CHANGES)
- [Commits](https://github.com/eliben/pyelftools/compare/v0.31...v0.32)

---
updated-dependencies:
- dependency-name: pyelftools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-03-10 14:26:54 -06:00
Capa Bot
6e68034d57 Sync capa rules submodule 2025-03-10 20:19:50 +00:00
Capa Bot
0df50f5d54 Sync capa-testfiles submodule 2025-03-10 19:51:07 +00:00
Capa Bot
f1131750cc Sync capa rules submodule 2025-03-10 19:48:37 +00:00
dependabot[bot]
077082a376 build(deps): bump humanize from 4.10.0 to 4.12.0 (#2606)
Bumps [humanize](https://github.com/python-humanize/humanize) from 4.10.0 to 4.12.0.
- [Release notes](https://github.com/python-humanize/humanize/releases)
- [Commits](https://github.com/python-humanize/humanize/compare/4.10.0...4.12.0)

---
updated-dependencies:
- dependency-name: humanize
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-03-10 13:03:59 -06:00
dependabot[bot]
86318093da build(deps-dev): bump vitest from 1.6.0 to 1.6.1 in /web/explorer (#2608)
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v1.6.1/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-03-10 12:45:16 -06:00
dependabot[bot]
4ee8a7c6b1 build(deps): bump setuptools from 75.8.0 to 76.0.0 (#2621)
Bumps [setuptools](https://github.com/pypa/setuptools) from 75.8.0 to 76.0.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v75.8.0...v76.0.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 12:44:49 -06:00
Capa Bot
151d30bec6 Sync capa rules submodule 2025-03-05 20:56:46 +00:00
Willi Ballenthin
3bd339522e v9.1.0 (#2614)
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-03-04 13:24:03 -07:00
Mike Hunhoff
7ecf292095 render: don't assume prior matches exist within thread (#2612)
* render: don't assume prior matches exist within thread

* update CHANGELOG

* update comments
2025-03-03 17:49:03 -07:00
Capa Bot
45ea683d19 Sync capa-testfiles submodule 2025-02-26 08:56:48 +00:00
Capa Bot
2b95fa089d Sync capa rules submodule 2025-02-25 15:59:41 +00:00
Mike Hunhoff
d3d71f97c8 vmray: only verify process OS and monitor ID match (#2613) 2025-02-24 14:14:05 -07:00
Willi Ballenthin
4c9d81072a main: don't require rules to render result document directly (#2611) 2025-02-24 17:47:00 +01:00
Capa Bot
a94c68377a Sync capa rules submodule 2025-02-22 19:41:30 +00:00
Capa Bot
14e076864c Sync capa-testfiles submodule 2025-02-22 19:13:14 +00:00
Capa Bot
6684f9f890 Sync capa rules submodule 2025-02-21 19:37:24 +00:00
dependabot[bot]
e622989eeb build(deps): bump psutil from 6.1.0 to 7.0.0 (#2605)
Bumps [psutil](https://github.com/giampaolo/psutil) from 6.1.0 to 7.0.0.
- [Changelog](https://github.com/giampaolo/psutil/blob/master/HISTORY.rst)
- [Commits](https://github.com/giampaolo/psutil/compare/release-6.1.0...release-7.0.0)

---
updated-dependencies:
- dependency-name: psutil
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-02-21 10:26:04 -07:00
Capa Bot
9c9dd15bf9 Sync capa rules submodule 2025-02-21 16:29:46 +00:00
Capa Bot
06fad4a89e Sync capa-testfiles submodule 2025-02-21 12:17:50 +00:00
Capa Bot
e06a0ab75f Sync capa rules submodule 2025-02-21 12:16:25 +00:00
Capa Bot
0371ade358 Sync capa rules submodule 2025-02-20 22:18:12 +00:00
dependabot[bot]
80b5a116a5 build(deps): bump pygithub from 2.5.0 to 2.6.0 (#2604)
Bumps [pygithub](https://github.com/pygithub/pygithub) from 2.5.0 to 2.6.0.
- [Release notes](https://github.com/pygithub/pygithub/releases)
- [Changelog](https://github.com/PyGithub/PyGithub/blob/main/doc/changes.rst)
- [Commits](https://github.com/pygithub/pygithub/compare/v2.5.0...v2.6.0)

---
updated-dependencies:
- dependency-name: pygithub
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-02-20 12:50:10 -07:00
dependabot[bot]
9a270e6bdd build(deps): bump pyinstaller from 6.11.1 to 6.12.0 (#2602)
Bumps [pyinstaller](https://github.com/pyinstaller/pyinstaller) from 6.11.1 to 6.12.0.
- [Release notes](https://github.com/pyinstaller/pyinstaller/releases)
- [Changelog](https://github.com/pyinstaller/pyinstaller/blob/develop/doc/CHANGES.rst)
- [Commits](https://github.com/pyinstaller/pyinstaller/compare/v6.11.1...v6.12.0)

---
updated-dependencies:
- dependency-name: pyinstaller
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-02-19 20:35:07 +01:00
dependabot[bot]
8773bc77ab build(deps): bump mypy from 1.14.1 to 1.15.0 (#2601)
Bumps [mypy](https://github.com/python/mypy) from 1.14.1 to 1.15.0.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.14.1...v1.15.0)

---
updated-dependencies:
- dependency-name: mypy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Hunhoff <mike.hunhoff@gmail.com>
2025-02-19 20:34:51 +01:00
Mike Hunhoff
a278bf593a cape: models: parse minimum fields required for analysis (#2607)
* cape: models: parse minimum fields required for analysis

* update CHANGELOG
2025-02-19 08:55:12 -07:00
Capa Bot
f85cd80d90 Sync capa rules submodule 2025-02-11 09:25:04 +00:00
26 changed files with 2168 additions and 943 deletions

View File

@@ -74,6 +74,9 @@ a = Analysis(
# only be installed locally.
"binaryninja",
"ida",
# remove once https://github.com/mandiant/capa/issues/2681 has
# been addressed by PyInstaller
"pkg_resources",
],
)

View File

@@ -9,6 +9,7 @@ on:
- '**.md'
release:
types: [edited, published]
workflow_dispatch: # manual trigger for testing
permissions:
contents: write
@@ -22,24 +23,38 @@ jobs:
fail-fast: true
matrix:
include:
- os: ubuntu-20.04
- os: ubuntu-22.04
# use old linux so that the shared library versioning is more portable
artifact_name: capa
asset_name: linux
python_version: '3.10'
- os: ubuntu-20.04
- os: ubuntu-22.04-arm
artifact_name: capa
asset_name: linux-arm64
python_version: '3.10'
- os: ubuntu-22.04
artifact_name: capa
asset_name: linux-py312
python_version: '3.12'
- os: windows-2019
- os: windows-2022
artifact_name: capa.exe
asset_name: windows
python_version: '3.10'
# Windows 11 ARM64 complains of conflicting package version
# Additionally, there is no ARM64 build of Python for Python 3.10 on Windows 11 ARM: https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json
#- os: windows-11-arm
# artifact_name: capa.exe
# asset_name: windows-arm64
# python_version: '3.12'
- os: macos-13
# use older macOS for assumed better portability
artifact_name: capa
asset_name: macos
python_version: '3.10'
- os: macos-14
artifact_name: capa
asset_name: macos-arm64
python_version: '3.10'
steps:
- name: Checkout capa
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
@@ -49,7 +64,7 @@ jobs:
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
python-version: ${{ matrix.python_version }}
- if: matrix.os == 'ubuntu-20.04'
- if: matrix.os == 'ubuntu-22.04' || matrix.os == 'ubuntu-22.04-arm'
run: sudo apt-get install -y libyaml-dev
- name: Upgrade pip, setuptools
run: python -m pip install --upgrade pip setuptools
@@ -59,6 +74,28 @@ jobs:
pip install -e .[build]
- name: Build standalone executable
run: pyinstaller --log-level DEBUG .github/pyinstaller/pyinstaller.spec
- name: Does it run without warnings or errors?
shell: bash
run: |
if [[ "${{ matrix.os }}" == "windows-2022" ]] || [[ "${{ matrix.os }}" == "windows-11-arm" ]]; then
EXECUTABLE=".\\dist\\capa"
else
EXECUTABLE="./dist/capa"
fi
output=$(${EXECUTABLE} --version 2>&1)
exit_code=$?
echo "${output}"
echo "${exit_code}"
if echo "${output}" | grep -iE 'error|warning'; then
exit 1
fi
if [[ "${exit_code}" -ne 0 ]]; then
exit 1
fi
- name: Does it run (PE)?
run: dist/capa -d "tests/data/Practical Malware Analysis Lab 01-01.dll_"
- name: Does it run (Shellcode)?
@@ -74,34 +111,6 @@ jobs:
name: ${{ matrix.asset_name }}
path: dist/${{ matrix.artifact_name }}
test_run:
name: Test run on ${{ matrix.os }} / ${{ matrix.asset_name }}
runs-on: ${{ matrix.os }}
needs: [build]
strategy:
matrix:
include:
# OSs not already tested above
- os: ubuntu-22.04
artifact_name: capa
asset_name: linux
- os: ubuntu-22.04
artifact_name: capa
asset_name: linux-py312
- os: windows-2022
artifact_name: capa.exe
asset_name: windows
steps:
- name: Download ${{ matrix.asset_name }}
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2
with:
name: ${{ matrix.asset_name }}
- name: Set executable flag
if: matrix.os != 'windows-2022'
run: chmod +x ${{ matrix.artifact_name }}
- name: Run capa
run: ./${{ matrix.artifact_name }} -h
zip_and_upload:
# upload zipped binaries to Release page
if: github.event_name == 'release'
@@ -113,12 +122,18 @@ jobs:
include:
- asset_name: linux
artifact_name: capa
- asset_name: linux-arm64
artifact_name: capa
- asset_name: linux-py312
artifact_name: capa
- asset_name: windows
artifact_name: capa.exe
#- asset_name: windows-arm64
# artifact_name: capa.exe
- asset_name: macos
artifact_name: capa
- asset_name: macos-arm64
artifact_name: capa
steps:
- name: Download ${{ matrix.asset_name }}
uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2

304
.github/workflows/gemini-cli.yml vendored Normal file
View File

@@ -0,0 +1,304 @@
name: '💬 Gemini CLI'
on:
pull_request_review_comment:
types:
- 'created'
pull_request_review:
types:
- 'submitted'
issue_comment:
types:
- 'created'
concurrency:
group: '${{ github.workflow }}-${{ github.event.issue.number }}'
cancel-in-progress: |-
${{ github.event.sender.type == 'User' && ( github.event.issue.author_association == 'OWNER' || github.event.issue.author_association == 'MEMBER' || github.event.issue.author_association == 'COLLABORATOR') }}
defaults:
run:
shell: 'bash'
permissions:
contents: 'write'
id-token: 'write'
pull-requests: 'write'
issues: 'write'
jobs:
gemini-cli:
# This condition is complex to ensure we only run when explicitly invoked.
if: |-
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'issues' && github.event.action == 'opened' &&
contains(github.event.issue.body, '@gemini-cli') &&
!contains(github.event.issue.body, '@gemini-cli /review') &&
!contains(github.event.issue.body, '@gemini-cli /triage') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.issue.author_association)
) ||
(
(
github.event_name == 'issue_comment' ||
github.event_name == 'pull_request_review_comment'
) &&
contains(github.event.comment.body, '@gemini-cli') &&
!contains(github.event.comment.body, '@gemini-cli /review') &&
!contains(github.event.comment.body, '@gemini-cli /triage') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
) ||
(
github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@gemini-cli') &&
!contains(github.event.review.body, '@gemini-cli /review') &&
!contains(github.event.review.body, '@gemini-cli /triage') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)
)
timeout-minutes: 10
runs-on: 'ubuntu-latest'
steps:
- name: 'Generate GitHub App Token'
id: 'generate_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
- name: 'Get context from event'
id: 'get_context'
env:
EVENT_NAME: '${{ github.event_name }}'
EVENT_PAYLOAD: '${{ toJSON(github.event) }}'
run: |-
set -euo pipefail
USER_REQUEST=""
ISSUE_NUMBER=""
IS_PR="false"
if [[ "${EVENT_NAME}" == "issues" ]]; then
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.body)
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
elif [[ "${EVENT_NAME}" == "issue_comment" ]]; then
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .comment.body)
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .issue.number)
if [[ $(echo "${EVENT_PAYLOAD}" | jq -r .issue.pull_request) != "null" ]]; then
IS_PR="true"
fi
elif [[ "${EVENT_NAME}" == "pull_request_review" ]]; then
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .review.body)
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .pull_request.number)
IS_PR="true"
elif [[ "${EVENT_NAME}" == "pull_request_review_comment" ]]; then
USER_REQUEST=$(echo "${EVENT_PAYLOAD}" | jq -r .comment.body)
ISSUE_NUMBER=$(echo "${EVENT_PAYLOAD}" | jq -r .pull_request.number)
IS_PR="true"
fi
# Clean up user request
USER_REQUEST=$(echo "${USER_REQUEST}" | sed 's/.*@gemini-cli//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
{
echo "user_request=${USER_REQUEST}"
echo "issue_number=${ISSUE_NUMBER}"
echo "is_pr=${IS_PR}"
} >> "${GITHUB_OUTPUT}"
- name: 'Set up git user for commits'
run: |-
git config --global user.name 'gemini-cli[bot]'
git config --global user.email 'gemini-cli[bot]@users.noreply.github.com'
- name: 'Checkout PR branch'
if: |-
${{ steps.get_context.outputs.is_pr == 'true' }}
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
with:
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
repository: '${{ github.repository }}'
ref: 'refs/pull/${{ steps.get_context.outputs.issue_number }}/head'
fetch-depth: 0
- name: 'Checkout main branch'
if: |-
${{ steps.get_context.outputs.is_pr == 'false' }}
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
with:
token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
repository: '${{ github.repository }}'
fetch-depth: 0
- name: 'Acknowledge request'
env:
GITHUB_ACTOR: '${{ github.actor }}'
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
REPOSITORY: '${{ github.repository }}'
REQUEST_TYPE: '${{ steps.get_context.outputs.request_type }}'
run: |-
set -euo pipefail
MESSAGE="@${GITHUB_ACTOR} I've received your request and I'm working on it now! 🤖"
if [[ -n "${MESSAGE}" ]]; then
gh issue comment "${ISSUE_NUMBER}" \
--body "${MESSAGE}" \
--repo "${REPOSITORY}"
fi
- name: 'Get description'
id: 'get_description'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
run: |-
set -euo pipefail
if [[ "${IS_PR}" == "true" ]]; then
DESCRIPTION=$(gh pr view "${ISSUE_NUMBER}" --json body --template '{{.body}}')
else
DESCRIPTION=$(gh issue view "${ISSUE_NUMBER}" --json body --template '{{.body}}')
fi
{
echo "description<<EOF"
echo "${DESCRIPTION}"
echo "EOF"
} >> "${GITHUB_OUTPUT}"
- name: 'Get comments'
id: 'get_comments'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
run: |-
set -euo pipefail
if [[ "${IS_PR}" == "true" ]]; then
COMMENTS=$(gh pr view "${ISSUE_NUMBER}" --json comments --template '{{range .comments}}{{.author.login}}: {{.body}}{{"\n"}}{{end}}')
else
COMMENTS=$(gh issue view "${ISSUE_NUMBER}" --json comments --template '{{range .comments}}{{.author.login}}: {{.body}}{{"\n"}}{{end}}')
fi
{
echo "comments<<EOF"
echo "${COMMENTS}"
echo "EOF"
} >> "${GITHUB_OUTPUT}"
- name: 'Run Gemini'
id: 'run_gemini'
uses: 'google-github-actions/run-gemini-cli@v0'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
REPOSITORY: '${{ github.repository }}'
USER_REQUEST: '${{ steps.get_context.outputs.user_request }}'
ISSUE_NUMBER: '${{ steps.get_context.outputs.issue_number }}'
IS_PR: '${{ steps.get_context.outputs.is_pr }}'
with:
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"maxSessionTurns": 50,
"telemetry": {
"enabled": false,
"target": "gcp"
}
}
prompt: |-
## Role
You are a helpful AI assistant invoked via a CLI interface in a GitHub workflow. You have access to tools to interact with the repository and respond to the user.
## Context
- **Repository**: `${{ github.repository }}`
- **Triggering Event**: `${{ github.event_name }}`
- **Issue/PR Number**: `${{ steps.get_context.outputs.issue_number }}`
- **Is this a PR?**: `${{ steps.get_context.outputs.is_pr }}`
- **Issue/PR Description**:
`${{ steps.get_description.outputs.description }}`
- **Comments**:
`${{ steps.get_comments.outputs.comments }}`
## User Request
The user has sent the following request:
`${{ steps.get_context.outputs.user_request }}`
## How to Respond to Issues, PR Comments, and Questions
This workflow supports three main scenarios:
1. **Creating a Fix for an Issue**
- Carefully read the user request and the related issue or PR description.
- Use available tools to gather all relevant context (e.g., `gh issue view`, `gh pr view`, `gh pr diff`, `cat`, `head`, `tail`).
- Identify the root cause of the problem before proceeding.
- **Show and maintain a plan as a checklist**:
- At the very beginning, outline the steps needed to resolve the issue or address the request and post them as a checklist comment on the issue or PR (use GitHub markdown checkboxes: `- [ ] Task`).
- Example:
```
### Plan
- [ ] Investigate the root cause
- [ ] Implement the fix in `file.py`
- [ ] Add/modify tests
- [ ] Update documentation
- [ ] Verify the fix and close the issue
```
- Use: `gh pr comment "${ISSUE_NUMBER}" --body "<plan>"` or `gh issue comment "${ISSUE_NUMBER}" --body "<plan>"` to post the initial plan.
- As you make progress, keep the checklist visible and up to date by editing the same comment (check off completed tasks with `- [x]`).
- To update the checklist:
1. Find the comment ID for the checklist (use `gh pr comment list "${ISSUE_NUMBER}"` or `gh issue comment list "${ISSUE_NUMBER}"`).
2. Edit the comment with the updated checklist:
- For PRs: `gh pr comment --edit <comment-id> --body "<updated plan>"`
- For Issues: `gh issue comment --edit <comment-id> --body "<updated plan>"`
3. The checklist should only be maintained as a comment on the issue or PR. Do not track or update the checklist in code files.
- If the fix requires code changes, determine which files and lines are affected. If clarification is needed, note any questions for the user.
- Make the necessary code or documentation changes using the available tools (e.g., `write_file`). Ensure all changes follow project conventions and best practices. Reference all shell variables as `"${VAR}"` (with quotes and braces) to prevent errors.
- Run any relevant tests or checks to verify the fix works as intended. If possible, provide evidence (test output, screenshots, etc.) that the issue is resolved.
- **Branching and Committing**:
- **NEVER commit directly to the `main` branch.**
- If you are working on a **pull request** (`IS_PR` is `true`), the correct branch is already checked out. Simply commit and push to it.
- `git add .`
- `git commit -m "feat: <describe the change>"`
- `git push`
- If you are working on an **issue** (`IS_PR` is `false`), create a new branch for your changes. A good branch name would be `issue/${ISSUE_NUMBER}/<short-description>`.
- `git checkout -b issue/${ISSUE_NUMBER}/my-fix`
- `git add .`
- `git commit -m "feat: <describe the fix>"`
- `git push origin issue/${ISSUE_NUMBER}/my-fix`
- After pushing, you can create a pull request: `gh pr create --title "Fixes #${ISSUE_NUMBER}: <short title>" --body "This PR addresses issue #${ISSUE_NUMBER}."`
- Summarize what was changed and why in a markdown file: `write_file("response.md", "<your response here>")`
- Post the response as a comment:
- For PRs: `gh pr comment "${ISSUE_NUMBER}" --body-file response.md`
- For Issues: `gh issue comment "${ISSUE_NUMBER}" --body-file response.md`
2. **Addressing Comments on a Pull Request**
- Read the specific comment and the context of the PR.
- Use tools like `gh pr view`, `gh pr diff`, and `cat` to understand the code and discussion.
- If the comment requests a change or clarification, follow the same process as for fixing an issue: create a checklist plan, implement, test, and commit any required changes, updating the checklist as you go.
- **Committing Changes**: The correct PR branch is already checked out. Simply add, commit, and push your changes.
- `git add .`
- `git commit -m "fix: address review comments"`
- `git push`
- If the comment is a question, answer it directly and clearly, referencing code or documentation as needed.
- Document your response in `response.md` and post it as a PR comment: `gh pr comment "${ISSUE_NUMBER}" --body-file response.md`
3. **Answering Any Question on an Issue**
- Read the question and the full issue context using `gh issue view` and related tools.
- Research or analyze the codebase as needed to provide an accurate answer.
- If the question requires code or documentation changes, follow the fix process above, including creating and updating a checklist plan and **creating a new branch for your changes as described in section 1.**
- Write a clear, concise answer in `response.md` and post it as an issue comment: `gh issue comment "${ISSUE_NUMBER}" --body-file response.md`
## Guidelines
- **Be concise and actionable.** Focus on solving the user's problem efficiently.
- **Always commit and push your changes if you modify code or documentation.**
- **If you are unsure about the fix or answer, explain your reasoning and ask clarifying questions.**
- **Follow project conventions and best practices.**

View File

@@ -0,0 +1,130 @@
name: '🏷️ Gemini Automated Issue Triage'
on:
issues:
types:
- 'opened'
- 'reopened'
issue_comment:
types:
- 'created'
workflow_dispatch:
inputs:
issue_number:
description: 'issue number to triage'
required: true
type: 'number'
concurrency:
group: '${{ github.workflow }}-${{ github.event.issue.number }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
permissions:
contents: 'read'
id-token: 'write'
issues: 'write'
statuses: 'write'
jobs:
triage-issue:
if: |-
github.event_name == 'issues' ||
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'issue_comment' &&
contains(github.event.comment.body, '@gemini-cli /triage') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
)
timeout-minutes: 5
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout repository'
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
- name: 'Generate GitHub App Token'
id: 'generate_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
- name: 'Run Gemini Issue Triage'
uses: 'google-github-actions/run-gemini-cli@v0'
id: 'gemini_issue_triage'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
ISSUE_TITLE: '${{ github.event.issue.title }}'
ISSUE_BODY: '${{ github.event.issue.body }}'
ISSUE_NUMBER: '${{ github.event.issue.number }}'
REPOSITORY: '${{ github.repository }}'
with:
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"maxSessionTurns": 25,
"coreTools": [
"run_shell_command(echo)",
"run_shell_command(gh label list)",
"run_shell_command(gh issue edit)"
],
"telemetry": {
"enabled": false,
"target": "gcp"
}
}
prompt: |-
## Role
You are an issue triage assistant. Analyze the current GitHub issue
and apply the most appropriate existing labels. Use the available
tools to gather information; do not ask for information to be
provided.
## Steps
1. Run: `gh label list` to get all available labels.
2. Review the issue title and body provided in the environment
variables: "${ISSUE_TITLE}" and "${ISSUE_BODY}".
3. Select the most relevant labels from the existing labels. If
available, set labels that follow the `kind/*`, `area/*`, and
`priority/*` patterns.
4. Apply the selected labels to this issue using:
`gh issue edit "${ISSUE_NUMBER}" --add-label "label1,label2"`
5. If the "status/needs-triage" label is present, remove it using:
`gh issue edit "${ISSUE_NUMBER}" --remove-label "status/needs-triage"`
## Guidelines
- Only use labels that already exist in the repository
- Do not add comments or modify the issue content
- Triage only the current issue
- Assign all applicable labels based on the issue content
- Reference all shell variables as "${VAR}" (with quotes and braces)
- name: 'Post Issue Triage Failure Comment'
if: |-
${{ failure() && steps.gemini_issue_triage.outcome == 'failure' }}
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
script: |-
github.rest.issues.createComment({
owner: '${{ github.repository }}'.split('/')[0],
repo: '${{ github.repository }}'.split('/')[1],
issue_number: '${{ github.event.issue.number }}',
body: 'There is a problem with the Gemini CLI issue triaging. Please check the [action logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.'
})

View File

@@ -0,0 +1,123 @@
name: '📋 Gemini Scheduled Issue Triage'
on:
schedule:
- cron: '0 * * * *' # Runs every hour
workflow_dispatch:
concurrency:
group: '${{ github.workflow }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
permissions:
contents: 'read'
id-token: 'write'
issues: 'write'
statuses: 'write'
jobs:
triage-issues:
timeout-minutes: 5
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout repository'
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
- name: 'Generate GitHub App Token'
id: 'generate_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
- name: 'Find untriaged issues'
id: 'find_issues'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
GITHUB_REPOSITORY: '${{ github.repository }}'
GITHUB_OUTPUT: '${{ github.output }}'
run: |-
set -euo pipefail
echo '🔍 Finding issues without labels...'
NO_LABEL_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue no:label' --json number,title,body)"
echo '🏷️ Finding issues that need triage...'
NEED_TRIAGE_ISSUES="$(gh issue list --repo "${GITHUB_REPOSITORY}" \
--search 'is:open is:issue label:"status/needs-triage"' --json number,title,body)"
echo '🔄 Merging and deduplicating issues...'
ISSUES="$(echo "${NO_LABEL_ISSUES}" "${NEED_TRIAGE_ISSUES}" | jq -c -s 'add | unique_by(.number)')"
echo '📝 Setting output for GitHub Actions...'
echo "issues_to_triage=${ISSUES}" >> "${GITHUB_OUTPUT}"
ISSUE_COUNT="$(echo "${ISSUES}" | jq 'length')"
echo "✅ Found ${ISSUE_COUNT} issues to triage! 🎯"
- name: 'Run Gemini Issue Triage'
if: |-
${{ steps.find_issues.outputs.issues_to_triage != '[]' }}
uses: 'google-github-actions/run-gemini-cli@v0'
id: 'gemini_issue_triage'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
ISSUES_TO_TRIAGE: '${{ steps.find_issues.outputs.issues_to_triage }}'
REPOSITORY: '${{ github.repository }}'
with:
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"maxSessionTurns": 25,
"coreTools": [
"run_shell_command(echo)",
"run_shell_command(gh label list)",
"run_shell_command(gh issue edit)",
"run_shell_command(gh issue list)"
],
"telemetry": {
"enabled": false,
"target": "gcp"
}
}
prompt: |-
## Role
You are an issue triage assistant. Analyze issues and apply
appropriate labels. Use the available tools to gather information;
do not ask for information to be provided.
## Steps
1. Run: `gh label list`
2. Check environment variable: "${ISSUES_TO_TRIAGE}" (JSON array
of issues)
3. For each issue, apply labels:
`gh issue edit "${ISSUE_NUMBER}" --add-label "label1,label2"`.
If available, set labels that follow the `kind/*`, `area/*`,
and `priority/*` patterns.
4. For each issue, if the `status/needs-triage` label is present,
remove it using:
`gh issue edit "${ISSUE_NUMBER}" --remove-label "status/needs-triage"`
## Guidelines
- Only use existing repository labels
- Do not add comments
- Triage each issue independently
- Reference all shell variables as "${VAR}" (with quotes and braces)

456
.github/workflows/gemini-pr-review.yml vendored Normal file
View File

@@ -0,0 +1,456 @@
name: '🧐 Gemini Pull Request Review'
on:
pull_request:
types:
- 'opened'
- 'reopened'
issue_comment:
types:
- 'created'
pull_request_review_comment:
types:
- 'created'
pull_request_review:
types:
- 'submitted'
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to review'
required: true
type: 'number'
concurrency:
group: '${{ github.workflow }}-${{ github.head_ref || github.ref }}'
cancel-in-progress: true
defaults:
run:
shell: 'bash'
permissions:
contents: 'read'
id-token: 'write'
issues: 'write'
pull-requests: 'write'
statuses: 'write'
jobs:
review-pr:
if: |-
github.event_name == 'workflow_dispatch' ||
(
github.event_name == 'pull_request' &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.pull_request.author_association)
) ||
(
(
(
github.event_name == 'issue_comment' &&
github.event.issue.pull_request
) ||
github.event_name == 'pull_request_review_comment'
) &&
contains(github.event.comment.body, '@gemini-cli /review') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
) ||
(
github.event_name == 'pull_request_review' &&
contains(github.event.review.body, '@gemini-cli /review') &&
contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)
)
timeout-minutes: 5
runs-on: 'ubuntu-latest'
steps:
- name: 'Checkout PR code'
uses: 'actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683' # ratchet:actions/checkout@v4
- name: 'Generate GitHub App Token'
id: 'generate_token'
if: |-
${{ vars.APP_ID }}
uses: 'actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e' # ratchet:actions/create-github-app-token@v2
with:
app-id: '${{ vars.APP_ID }}'
private-key: '${{ secrets.APP_PRIVATE_KEY }}'
- name: 'Get PR details (pull_request & workflow_dispatch)'
id: 'get_pr'
if: |-
${{ github.event_name == 'pull_request' || github.event_name == 'workflow_dispatch' }}
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
EVENT_NAME: '${{ github.event_name }}'
WORKFLOW_PR_NUMBER: '${{ github.event.inputs.pr_number }}'
PULL_REQUEST_NUMBER: '${{ github.event.pull_request.number }}'
run: |-
set -euo pipefail
if [[ "${EVENT_NAME}" = "workflow_dispatch" ]]; then
PR_NUMBER="${WORKFLOW_PR_NUMBER}"
else
PR_NUMBER="${PULL_REQUEST_NUMBER}"
fi
echo "pr_number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}"
# Get PR details
PR_DATA="$(gh pr view "${PR_NUMBER}" --json title,body,additions,deletions,changedFiles,baseRefName,headRefName)"
echo "pr_data=${PR_DATA}" >> "${GITHUB_OUTPUT}"
# Get file changes
CHANGED_FILES="$(gh pr diff "${PR_NUMBER}" --name-only)"
{
echo "changed_files<<EOF"
echo "${CHANGED_FILES}"
echo "EOF"
} >> "${GITHUB_OUTPUT}"
- name: 'Get PR details (issue_comment)'
id: 'get_pr_comment'
if: |-
${{ github.event_name == 'issue_comment' }}
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
COMMENT_BODY: '${{ github.event.comment.body }}'
PR_NUMBER: '${{ github.event.issue.number }}'
run: |-
set -euo pipefail
echo "pr_number=${PR_NUMBER}" >> "${GITHUB_OUTPUT}"
# Extract additional instructions from comment
ADDITIONAL_INSTRUCTIONS="$(
echo "${COMMENT_BODY}" | sed 's/.*@gemini-cli \/review//' | xargs
)"
echo "additional_instructions=${ADDITIONAL_INSTRUCTIONS}" >> "${GITHUB_OUTPUT}"
# Get PR details
PR_DATA="$(gh pr view "${PR_NUMBER}" --json title,body,additions,deletions,changedFiles,baseRefName,headRefName)"
echo "pr_data=${PR_DATA}" >> "${GITHUB_OUTPUT}"
# Get file changes
CHANGED_FILES="$(gh pr diff "${PR_NUMBER}" --name-only)"
{
echo "changed_files<<EOF"
echo "${CHANGED_FILES}"
echo "EOF"
} >> "${GITHUB_OUTPUT}"
- name: 'Run Gemini PR Review'
uses: 'google-github-actions/run-gemini-cli@v0'
id: 'gemini_pr_review'
env:
GITHUB_TOKEN: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
PR_NUMBER: '${{ steps.get_pr.outputs.pr_number || steps.get_pr_comment.outputs.pr_number }}'
PR_DATA: '${{ steps.get_pr.outputs.pr_data || steps.get_pr_comment.outputs.pr_data }}'
CHANGED_FILES: '${{ steps.get_pr.outputs.changed_files || steps.get_pr_comment.outputs.changed_files }}'
ADDITIONAL_INSTRUCTIONS: '${{ steps.get_pr.outputs.additional_instructions || steps.get_pr_comment.outputs.additional_instructions }}'
REPOSITORY: '${{ github.repository }}'
with:
gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
settings: |-
{
"maxSessionTurns": 20,
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"includeTools": [
"create_pending_pull_request_review",
"add_comment_to_pending_review",
"submit_pending_pull_request_review"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
}
}
},
"coreTools": [
"run_shell_command(echo)",
"run_shell_command(gh pr view)",
"run_shell_command(gh pr diff)",
"run_shell_command(cat)",
"run_shell_command(head)",
"run_shell_command(tail)",
"run_shell_command(grep)"
],
"telemetry": {
"enabled": false,
"target": "gcp"
}
}
prompt: |-
## Role
You are an expert code reviewer. You have access to tools to gather
PR information and perform the review on GitHub. Use the available tools to
gather information; do not ask for information to be provided.
## Requirements
1. All feedback must be left on GitHub.
2. Any output that is not left in GitHub will not be seen.
## Steps
Start by running these commands to gather the required data:
1. Run: echo $"{REPOSITORY}" to get the github repository in <OWNER>/<REPO> format
2. Run: echo "${PR_DATA}" to get PR details (JSON format)
3. Run: echo "${CHANGED_FILES}" to get the list of changed files
4. Run: echo "${PR_NUMBER}" to get the PR number
5. Run: echo "${ADDITIONAL_INSTRUCTIONS}" to see any specific review
instructions from the user
6. Run: gh pr diff "${PR_NUMBER}" to see the full diff and reference
Context section to understand it
7. For any specific files, use: cat filename, head -50 filename, or
tail -50 filename
8. If ADDITIONAL_INSTRUCTIONS contains text, prioritize those
specific areas or focus points in your review. Common instruction
examples: "focus on security", "check performance", "review error
handling", "check for breaking changes"
## Guideline
### Core Guideline(Always applicable)
1. Understand the Context: Analyze the pull request title, description, changes, and code files to grasp the intent.
2. Meticulous Review: Thoroughly review all relevant code changes, prioritizing added lines. Consider the specified
focus areas and any provided style guide.
3. Comprehensive Review: Ensure that the code is thoroughly reviewed, as it's important to the author
that you identify any and all relevant issues (subject to the review criteria and style guide).
Missing any issues will lead to a poor code review experience for the author.
4. Constructive Feedback:
* Provide clear explanations for each concern.
* Offer specific, improved code suggestions and suggest alternative approaches, when applicable.
Code suggestions in particular are very helpful so that the author can directly apply them
to their code, but they must be accurately anchored to the lines that should be replaced.
5. Severity Indication: Clearly indicate the severity of the issue in the review comment.
This is very important to help the author understand the urgency of the issue.
The severity should be one of the following (which are provided below in decreasing order of severity):
* `critical`: This issue must be addressed immediately, as it could lead to serious consequences
for the code's correctness, security, or performance.
* `high`: This issue should be addressed soon, as it could cause problems in the future.
* `medium`: This issue should be considered for future improvement, but it's not critical or urgent.
* `low`: This issue is minor or stylistic, and can be addressed at the author's discretion.
6. Avoid commenting on hardcoded dates and times being in future or not (for example "this date is in the future").
* Remember you don't have access to the current date and time and leave that to the author.
7. Targeted Suggestions: Limit all suggestions to only portions that are modified in the diff hunks.
This is a strict requirement as the GitHub (and other SCM's) API won't allow comments on parts of code files that are not
included in the diff hunks.
8. Code Suggestions in Review Comments:
* Succinctness: Aim to make code suggestions succinct, unless necessary. Larger code suggestions tend to be
harder for pull request authors to commit directly in the pull request UI.
* Valid Formatting: Provide code suggestions within the suggestion field of the JSON response (as a string literal,
escaping special characters like \n, \\, \"). Do not include markdown code blocks in the suggestion field.
Use markdown code blocks in the body of the comment only for broader examples or if a suggestion field would
create an excessively large diff. Prefer the suggestion field for specific, targeted code changes.
* Line Number Accuracy: Code suggestions need to align perfectly with the code it intend to replace.
Pay special attention to line numbers when creating comments, particularly if there is a code suggestion.
Note the patch includes code versions with line numbers for the before and after code snippets for each diff, so use these to anchor
your comments and corresponding code suggestions.
* Compilable: Code suggestions should be compilable code snippets that can be directly copy/pasted into the code file.
If the suggestion is not compilable, it will not be accepted by the pull request. Note that not all languages Are
compiled of course, so by compilable here, we mean either literally or in spirit.
* Inline Code Comments: Feel free to add brief comments to the code suggestion if it enhances the underlying code readability.
Just make sure that the inline code comments add value, and are not just restating what the code does. Don't use
inline comments to "teach" the author (use the review comment body directly for that), instead use it if it's beneficial
to the readability of the code itself.
10. Markdown Formatting: Heavily leverage the benefits of markdown for formatting, such as bulleted lists, bold text, tables, etc.
11. Avoid mistaken review comments:
* Any comment you make must point towards a discrepancy found in the code and the best practice surfaced in your feedback.
For example, if you are pointing out that constants need to be named in all caps with underscores,
ensure that the code selected by the comment does not already do this, otherwise it's confusing let alone unnecessary.
12. Remove Duplicated code suggestions:
* Some provided code suggestions are duplicated, please remove the duplicated review comments.
13. Don't Approve The Pull Request
14. Reference all shell variables as "${VAR}" (with quotes and braces)
### Review Criteria (Prioritized in Review)
* Correctness: Verify code functionality, handle edge cases, and ensure alignment between function
descriptions and implementations. Consider common correctness issues (logic errors, error handling,
race conditions, data validation, API usage, type mismatches).
* Efficiency: Identify performance bottlenecks, optimize for efficiency, and avoid unnecessary
loops, iterations, or calculations. Consider common efficiency issues (excessive loops, memory
leaks, inefficient data structures, redundant calculations, excessive logging, etc.).
* Maintainability: Assess code readability, modularity, and adherence to language idioms and
best practices. Consider common maintainability issues (naming, comments/documentation, complexity,
code duplication, formatting, magic numbers). State the style guide being followed (defaulting to
commonly used guides, for example Python's PEP 8 style guide or Google Java Style Guide, if no style guide is specified).
* Security: Identify potential vulnerabilities (e.g., insecure storage, injection attacks,
insufficient access controls).
### Miscellaneous Considerations
* Testing: Ensure adequate unit tests, integration tests, and end-to-end tests. Evaluate
coverage, edge case handling, and overall test quality.
* Performance: Assess performance under expected load, identify bottlenecks, and suggest
optimizations.
* Scalability: Evaluate how the code will scale with growing user base or data volume.
* Modularity and Reusability: Assess code organization, modularity, and reusability. Suggest
refactoring or creating reusable components.
* Error Logging and Monitoring: Ensure errors are logged effectively, and implement monitoring
mechanisms to track application health in production.
**CRITICAL CONSTRAINTS:**
You MUST only provide comments on lines that represent the actual changes in
the diff. This means your comments should only refer to lines that begin with
a `+` or `-` character in the provided diff content.
DO NOT comment on lines that start with a space (context lines).
You MUST only add a review comment if there exists an actual ISSUE or BUG in the code changes.
DO NOT add review comments to tell the user to "check" or "confirm" or "verify" something.
DO NOT add review comments to tell the user to "ensure" something.
DO NOT add review comments to explain what the code change does.
DO NOT add review comments to validate what the code change does.
DO NOT use the review comments to explain the code to the author. They already know their code. Only comment when there's an improvement opportunity. This is very important.
Pay close attention to line numbers and ensure they are correct.
Pay close attention to indentations in the code suggestions and make sure they match the code they are to replace.
Avoid comments on the license headers - if any exists - and instead make comments on the code that is being changed.
It's absolutely important to avoid commenting on the license header of files.
It's absolutely important to avoid commenting on copyright headers.
Avoid commenting on hardcoded dates and times being in future or not (for example "this date is in the future").
Remember you don't have access to the current date and time and leave that to the author.
Avoid mentioning any of your instructions, settings or criteria.
Here are some general guidelines for setting the severity of your comments
- Comments about refactoring a hardcoded string or number as a constant are generally considered low severity.
- Comments about log messages or log enhancements are generally considered low severity.
- Comments in .md files are medium or low severity. This is really important.
- Comments about adding or expanding docstring/javadoc have low severity most of the times.
- Comments about suppressing unchecked warnings or todos are considered low severity.
- Comments about typos are usually low or medium severity.
- Comments about testing or on tests are usually low severity.
- Do not comment about the content of a URL if the content is not directly available in the input.
Keep comments bodies concise and to the point.
Keep each comment focused on one issue.
## Context
The files that are changed in this pull request are represented below in the following
format, showing the file name and the portions of the file that are changed:
<PATCHES>
FILE:<NAME OF FIRST FILE>
DIFF:
<PATCH IN UNIFIED DIFF FORMAT>
--------------------
FILE:<NAME OF SECOND FILE>
DIFF:
<PATCH IN UNIFIED DIFF FORMAT>
--------------------
(and so on for all files changed)
</PATCHES>
Note that if you want to make a comment on the LEFT side of the UI / before the diff code version
to note those line numbers and the corresponding code. Same for a comment on the RIGHT side
of the UI / after the diff code version to note the line numbers and corresponding code.
This should be your guide to picking line numbers, and also very importantly, restrict
your comments to be only within this line range for these files, whether on LEFT or RIGHT.
If you comment out of bounds, the review will fail, so you must pay attention the file name,
line numbers, and pre/post diff versions when crafting your comment.
Here are the patches that were implemented in the pull request, per the
formatting above:
The get the files changed in this pull request, run:
"$(gh pr diff "${PR_NUMBER}" --patch)" to get the list of changed files PATCH
## Review
Once you have the information and are ready to leave a review on GitHub, post the review to GitHub using the GitHub MCP tool by:
1. Creating a pending review: Use the mcp__github__create_pending_pull_request_review to create a Pending Pull Request Review.
2. Adding review comments:
2.1 Use the mcp__github__add_comment_to_pending_review to add comments to the Pending Pull Request Review. Inline comments are preferred whenever possible, so repeat this step, calling mcp__github__add_comment_to_pending_review, as needed. All comments about specific lines of code should use inline comments. It is preferred to use code suggestions when possible, which include a code block that is labeled "suggestion", which contains what the new code should be. All comments should also have a severity. The syntax is:
Normal Comment Syntax:
<COMMENT>
{{SEVERITY}} {{COMMENT_TEXT}}
</COMMENT>
Inline Comment Syntax: (Preferred):
<COMMENT>
{{SEVERITY}} {{COMMENT_TEXT}}
```suggestion
{{CODE_SUGGESTION}}
```
</COMMENT>
Prepend a severity emoji to each comment:
- 🟢 for low severity
- 🟡 for medium severity
- 🟠 for high severity
- 🔴 for critical severity
- 🔵 if severity is unclear
Including all of this, an example inline comment would be:
<COMMENT>
🟢 Use camelCase for function names
```suggestion
myFooBarFunction
```
</COMMENT>
A critical severity example would be:
<COMMENT>
🔴 Remove storage key from GitHub
```suggestion
```
3. Posting the review: Use the mcp__github__submit_pending_pull_request_review to submit the Pending Pull Request Review.
3.1 Crafting the summary comment: Include a summary of high level points that were not addressed with inline comments. Be concise. Do not repeat details mentioned inline.
Structure your summary comment using this exact format with markdown:
## 📋 Review Summary
Provide a brief 2-3 sentence overview of the PR and overall
assessment.
## 🔍 General Feedback
- List general observations about code quality
- Mention overall patterns or architectural decisions
- Highlight positive aspects of the implementation
- Note any recurring themes across files
## Final Instructions
Remember, you are running in a VM and no one reviewing your output. Your review must be posted to GitHub using the MCP tools to create a pending review, add comments to the pending review, and submit the pending review.
- name: 'Post PR review failure comment'
if: |-
${{ failure() && steps.gemini_pr_review.outcome == 'failure' }}
uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea'
with:
github-token: '${{ steps.generate_token.outputs.token || secrets.GITHUB_TOKEN }}'
script: |-
github.rest.issues.createComment({
owner: '${{ github.repository }}'.split('/')[0],
repo: '${{ github.repository }}'.split('/')[1],
issue_number: '${{ steps.get_pr.outputs.pr_number || steps.get_pr_comment.outputs.pr_number }}',
body: 'There is a problem with the Gemini CLI PR review. Please check the [action logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details.'
})

View File

@@ -35,7 +35,7 @@ jobs:
with:
path: dist/*
- name: publish package
uses: pypa/gh-action-pypi-publish@f5622bde02b04381239da3573277701ceca8f6a0 # release/v1
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # release/v1.12.4
with:
skip-existing: true
verbose: true

View File

@@ -88,16 +88,16 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-20.04, windows-2019, macos-13]
os: [ubuntu-22.04, windows-2022, macos-13]
# across all operating systems
python-version: ["3.10", "3.11"]
include:
# on Ubuntu run these as well
- os: ubuntu-20.04
- os: ubuntu-22.04
python-version: "3.10"
- os: ubuntu-20.04
- os: ubuntu-22.04
python-version: "3.11"
- os: ubuntu-20.04
- os: ubuntu-22.04
python-version: "3.12"
steps:
- name: Checkout capa with submodules
@@ -109,7 +109,7 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
- name: Install pyyaml
if: matrix.os == 'ubuntu-20.04'
if: matrix.os == 'ubuntu-22.04'
run: sudo apt-get install -y libyaml-dev
- name: Install capa
run: |
@@ -168,7 +168,7 @@ jobs:
ghidra-tests:
name: Ghidra tests for ${{ matrix.python-version }}
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs: [tests]
strategy:
fail-fast: false

View File

@@ -3,11 +3,14 @@
## master (unreleased)
### New Features
- ci: add support for arm64 binary releases
### Breaking Changes
### New Rules (0)
### New Rules (2)
- anti-analysis/anti-vm/vm-detection/detect-mouse-movement-via-activity-checks-on-windows tevajdr@gmail.com
- nursery/create-executable-heap moritz.raabe@mandiant.com
-
### Bug Fixes
@@ -18,9 +21,95 @@
### Development
- ci: remove redundant "test_run" action from build workflow @mike-hunhoff #2692
### Raw diffs
- [capa v9.0.0...master](https://github.com/mandiant/capa/compare/v9.0.0...master)
- [capa-rules v9.0.0...master](https://github.com/mandiant/capa-rules/compare/v9.0.0...master)
- [capa v9.2.1...master](https://github.com/mandiant/capa/compare/v9.2.1...master)
- [capa-rules v9.2.1...master](https://github.com/mandiant/capa-rules/compare/v9.2.1...master)
## v9.2.1
This point release fixes bugs including removing an unnecessary PyInstaller warning message and enabling the standalone binary to execute on systems running older versions of glibc.
### Bug Fixes
- ci: exclude pkg_resources from PyInstaller build @mike-hunhoff #2684
- ci: downgrade Ubuntu version to accommodate older glibc versions @mike-hunhoff #2684
### Development
- ci: upgrade Windows version to avoid deprecation @mike-hunhoff #2684
- ci: check if build runs without warnings or errors @mike-hunhoff #2684
### Raw diffs
- [capa v9.2.0...v9.2.1](https://github.com/mandiant/capa/compare/v9.2.0...v9.2.1)
- [capa-rules v9.2.0...v9.2.1](https://github.com/mandiant/capa-rules/compare/v9.2.0...v9.2.1)
## v9.2.0
This release improves a few aspects of dynamic analysis, including relaxing our validation on fields across many CAPE versions and processing additional VMRay submission file types, for example.
It also includes an updated rule pack containing new rules and rule fixes.
### New Features
- vmray: do not restrict analysis to PE and ELF files, e.g. docx @mike-hunhoff #2672
### Breaking Changes
### New Rules (22)
- communication/socket/connect-socket moritz.raabe@mandiant.com joakim@intezer.com mrhafizfarhad@gmail.com
- communication/socket/udp/connect-udp-socket mrhafizfarhad@gmail.com
- nursery/enter-debug-mode-in-dotnet @v1bh475u
- nursery/decrypt-data-using-tripledes-in-dotnet 0xRavenspar
- nursery/encrypt-data-using-tripledes-in-dotnet 0xRavenspar
- nursery/disable-system-features-via-registry-on-windows mehunhoff@google.com
- data-manipulation/encryption/chaskey/encrypt-data-using-chaskey still@teamt5.org
- data-manipulation/encryption/speck/encrypt-data-using-speck still@teamt5.org
- load-code/dotnet/load-assembly-via-iassembly still@teamt5.org
- malware-family/donut-loader/load-shellcode-via-donut still@teamt5.org
- nursery/disable-device-guard-features-via-registry-on-windows mehunhoff@google.com
- nursery/disable-firewall-features-via-registry-on-windows mehunhoff@google.com
- nursery/disable-system-restore-features-via-registry-on-windows mehunhoff@google.com
- nursery/disable-windows-defender-features-via-registry-on-windows mehunhoff@google.com
- host-interaction/file-system/write/clear-file-content jakeperalta7
- host-interaction/filter/unload-minifilter-driver JakePeralta7
- exploitation/enumeration/make-suspicious-ntquerysysteminformation-call zdw@google.com
- exploitation/gadgets/load-ntoskrnl zdw@google.com
- exploitation/gadgets/resolve-ntoskrnl-gadgets zdw@google.com
- exploitation/spraying/make-suspicious-ntfscontrolfile-call zdw@google.com
- anti-analysis/anti-forensic/unload-sysmon JakePeralta7
### Bug Fixes
- cape: make some fields optional @williballenthin #2631 #2632
- lint: add WARN for regex features that contain unescaped dot #2635
- lint: add ERROR for incomplete registry control set regex #2643
- binja: update unit test core version #2670
### Raw diffs
- [capa v9.1.0...v9.2.0](https://github.com/mandiant/capa/compare/v9.1.0...v9.2.0)
- [capa-rules v9.1.0...v9.2.0](https://github.com/mandiant/capa-rules/compare/v9.1.0...v9.2.0)
## v9.1.0
This release improves a few aspects of dynamic analysis, relaxing our validation on fields across many CAPE versions, for example.
It also includes an updated rule pack in which many dynamic rules make better use of the "span of calls" scope.
### New Rules (3)
- host-interaction/registry/change-registry-key-timestamp wballenthin@google.com
- host-interaction/mutex/check-mutex-and-terminate-process-on-windows @_re_fox moritz.raabe@mandiant.com mehunhoff@google.com
- anti-analysis/anti-forensic/clear-logs/clear-windows-event-logs-remotely 99.elad.levi@gmail.com
### Bug Fixes
- only parse CAPE fields required for analysis @mike-hunhoff #2607
- main: render result document without needing associated rules @williballenthin #2610
- vmray: only verify process OS and monitor IDs match @mike-hunhoff #2613
- render: don't assume prior matches exist within a thread @mike-hunhoff #2612
### Raw diffs
- [capa v9.0.0...v9.1.0](https://github.com/mandiant/capa/compare/v9.0.0...v9.1.0)
- [capa-rules v9.0.0...v9.1.0](https://github.com/mandiant/capa-rules/compare/v9.0.0...v9.1.0)
## v9.0.0

View File

@@ -54,7 +54,8 @@ class CapeExtractor(DynamicFeatureExtractor):
def get_base_address(self) -> Union[AbsoluteVirtualAddress, _NoAddress, None]:
# value according to the PE header, the actual trace may use a different imagebase
assert self.report.static is not None and self.report.static.pe is not None
assert self.report.static is not None
assert self.report.static.pe is not None
return AbsoluteVirtualAddress(self.report.static.pe.imagebase)
def extract_global_features(self) -> Iterator[tuple[Feature, Address]]:

View File

@@ -88,31 +88,49 @@ def extract_file_strings(report: CapeReport) -> Iterator[tuple[Feature, Address]
def extract_used_regkeys(report: CapeReport) -> Iterator[tuple[Feature, Address]]:
if not report.behavior.summary:
return
for regkey in report.behavior.summary.keys:
yield String(regkey), NO_ADDRESS
def extract_used_files(report: CapeReport) -> Iterator[tuple[Feature, Address]]:
if not report.behavior.summary:
return
for file in report.behavior.summary.files:
yield String(file), NO_ADDRESS
def extract_used_mutexes(report: CapeReport) -> Iterator[tuple[Feature, Address]]:
if not report.behavior.summary:
return
for mutex in report.behavior.summary.mutexes:
yield String(mutex), NO_ADDRESS
def extract_used_commands(report: CapeReport) -> Iterator[tuple[Feature, Address]]:
if not report.behavior.summary:
return
for cmd in report.behavior.summary.executed_commands:
yield String(cmd), NO_ADDRESS
def extract_used_apis(report: CapeReport) -> Iterator[tuple[Feature, Address]]:
if not report.behavior.summary:
return
for symbol in report.behavior.summary.resolved_apis:
yield String(symbol), NO_ADDRESS
def extract_used_services(report: CapeReport) -> Iterator[tuple[Feature, Address]]:
if not report.behavior.summary:
return
for svc in report.behavior.summary.created_services:
yield String(svc), NO_ADDRESS
for svc in report.behavior.summary.started_services:

View File

@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Any, Union, Literal, Optional, Annotated, TypeAlias
from typing import Any, Union, Optional, Annotated, TypeAlias
from pydantic import Field, BaseModel, ConfigDict
from pydantic.functional_validators import BeforeValidator
@@ -75,34 +75,37 @@ class Info(FlexibleModel):
version: str
class ImportedSymbol(ExactModel):
class ImportedSymbol(FlexibleModel):
address: HexInt
name: Optional[str] = None
class ImportedDll(ExactModel):
class ImportedDll(FlexibleModel):
dll: str
imports: list[ImportedSymbol]
class DirectoryEntry(ExactModel):
"""
class DirectoryEntry(FlexibleModel):
name: str
virtual_address: HexInt
size: HexInt
"""
class Section(ExactModel):
class Section(FlexibleModel):
name: str
raw_address: HexInt
# raw_address: HexInt
virtual_address: HexInt
virtual_size: HexInt
size_of_data: HexInt
characteristics: str
characteristics_raw: HexInt
entropy: float
# virtual_size: HexInt
# size_of_data: HexInt
# characteristics: str
# characteristics_raw: HexInt
# entropy: float
class Resource(ExactModel):
"""
class Resource(FlexibleModel):
name: str
language: Optional[str] = None
sublanguage: str
@@ -140,7 +143,7 @@ class DigitalSigner(FlexibleModel):
extensions_subjectKeyIdentifier: Optional[str] = None
class AuxSigner(ExactModel):
class AuxSigner(FlexibleModel):
name: str
issued_to: str = Field(alias="Issued to")
issued_by: str = Field(alias="Issued by")
@@ -148,7 +151,7 @@ class AuxSigner(ExactModel):
sha1_hash: str = Field(alias="SHA1 hash")
class Signer(ExactModel):
class Signer(FlexibleModel):
aux_sha1: Optional[str] = None
aux_timestamp: Optional[str] = None
aux_valid: Optional[bool] = None
@@ -157,60 +160,61 @@ class Signer(ExactModel):
aux_signers: Optional[list[AuxSigner]] = None
class Overlay(ExactModel):
class Overlay(FlexibleModel):
offset: HexInt
size: HexInt
class KV(ExactModel):
class KV(FlexibleModel):
name: str
value: str
"""
class ExportedSymbol(ExactModel):
class ExportedSymbol(FlexibleModel):
address: HexInt
name: str
ordinal: int
# ordinal: int
class PE(ExactModel):
peid_signatures: TODO
class PE(FlexibleModel):
# peid_signatures: TODO
imagebase: HexInt
entrypoint: HexInt
reported_checksum: HexInt
actual_checksum: HexInt
osversion: str
pdbpath: Optional[str] = None
timestamp: str
# entrypoint: HexInt
# reported_checksum: HexInt
# actual_checksum: HexInt
# osversion: str
# pdbpath: Optional[str] = None
# timestamp: str
# list[ImportedDll], or dict[basename(dll), ImportedDll]
imports: Union[list[ImportedDll], dict[str, ImportedDll]]
imported_dll_count: Optional[int] = None
imphash: str
imports: list[ImportedDll] | dict[str, ImportedDll] = Field(default_factory=list) # type: ignore
# imported_dll_count: Optional[int] = None
# imphash: str
exported_dll_name: Optional[str] = None
exports: list[ExportedSymbol]
# exported_dll_name: Optional[str] = None
exports: list[ExportedSymbol] = Field(default_factory=list)
dirents: list[DirectoryEntry]
sections: list[Section]
# dirents: list[DirectoryEntry]
sections: list[Section] = Field(default_factory=list)
ep_bytes: Optional[HexBytes] = None
# ep_bytes: Optional[HexBytes] = None
overlay: Optional[Overlay] = None
resources: list[Resource]
versioninfo: list[KV]
# overlay: Optional[Overlay] = None
# resources: list[Resource]
# versioninfo: list[KV]
# base64 encoded data
icon: Optional[str] = None
# icon: Optional[str] = None
# MD5-like hash
icon_hash: Optional[str] = None
# icon_hash: Optional[str] = None
# MD5-like hash
icon_fuzzy: Optional[str] = None
# icon_fuzzy: Optional[str] = None
# short hex string
icon_dhash: Optional[str] = None
# icon_dhash: Optional[str] = None
digital_signers: list[DigitalSigner]
guest_signers: Signer
# digital_signers: list[DigitalSigner]
# guest_signers: Signer
# TODO(mr-tz): target.file.dotnet, target.file.extracted_files, target.file.extracted_files_tool,
@@ -218,48 +222,49 @@ class PE(ExactModel):
# https://github.com/mandiant/capa/issues/1814
class File(FlexibleModel):
type: str
cape_type_code: Optional[int] = None
cape_type: Optional[str] = None
# cape_type_code: Optional[int] = None
# cape_type: Optional[str] = None
pid: Optional[Union[int, Literal[""]]] = None
name: Union[list[str], str]
path: str
guest_paths: Union[list[str], str, None]
timestamp: Optional[str] = None
# pid: Optional[Union[int, Literal[""]]] = None
# name: Union[list[str], str]
# path: str
# guest_paths: Union[list[str], str, None]
# timestamp: Optional[str] = None
#
# hashes
#
crc32: str
# crc32: str
md5: str
sha1: str
sha256: str
sha512: str
sha3_384: Optional[str] = None
ssdeep: str
# sha512: str
# sha3_384: Optional[str] = None
# ssdeep: str
# unsure why this would ever be "False"
tlsh: Optional[Union[str, bool]] = None
rh_hash: Optional[str] = None
# tlsh: Optional[Union[str, bool]] = None
# rh_hash: Optional[str] = None
#
# other metadata, static analysis
#
size: int
# size: int
pe: Optional[PE] = None
ep_bytes: Optional[HexBytes] = None
entrypoint: Optional[int] = None
data: Optional[str] = None
strings: Optional[list[str]] = None
# ep_bytes: Optional[HexBytes] = None
# entrypoint: Optional[int] = None
# data: Optional[str] = None
# strings: Optional[list[str]] = None
#
# detections (skip)
#
yara: Skip = None
cape_yara: Skip = None
clamav: Skip = None
virustotal: Skip = None
# yara: Skip = None
# cape_yara: Skip = None
# clamav: Skip = None
# virustotal: Skip = None
"""
class ProcessFile(File):
#
# like a File, but also has dynamic analysis results
@@ -272,35 +277,36 @@ class ProcessFile(File):
target_pid: Optional[Union[int, str]] = None
target_path: Optional[str] = None
target_process: Optional[str] = None
"""
class Argument(ExactModel):
class Argument(FlexibleModel):
name: str
# unsure why empty list is provided here
value: Union[HexInt, int, str, EmptyList]
pretty_value: Optional[str] = None
class Call(ExactModel):
timestamp: str
class Call(FlexibleModel):
# timestamp: str
thread_id: int
category: str
# category: str
api: str
arguments: list[Argument]
status: bool
# status: bool
return_: HexInt = Field(alias="return")
pretty_return: Optional[str] = None
repeated: int
# repeated: int
# virtual addresses
caller: HexInt
parentcaller: HexInt
# caller: HexInt
# parentcaller: HexInt
# index into calls array
id: int
# id: int
# FlexibleModel to account for extended fields
@@ -310,14 +316,15 @@ class Process(FlexibleModel):
process_id: int
process_name: str
parent_id: int
module_path: str
first_seen: str
# module_path: str
# first_seen: str
calls: list[Call]
threads: list[int]
environ: dict[str, str]
class ProcessTree(ExactModel):
"""
class ProcessTree(FlexibleModel):
name: str
pid: int
parent_id: int
@@ -325,17 +332,18 @@ class ProcessTree(ExactModel):
threads: list[int]
environ: dict[str, str]
children: list["ProcessTree"]
"""
class Summary(ExactModel):
class Summary(FlexibleModel):
files: list[str]
read_files: list[str]
write_files: list[str]
delete_files: list[str]
# read_files: list[str]
# write_files: list[str]
# delete_files: list[str]
keys: list[str]
read_keys: list[str]
write_keys: list[str]
delete_keys: list[str]
# read_keys: list[str]
# write_keys: list[str]
# delete_keys: list[str]
executed_commands: list[str]
resolved_apis: list[str]
mutexes: list[str]
@@ -343,7 +351,8 @@ class Summary(ExactModel):
started_services: list[str]
class EncryptedBuffer(ExactModel):
"""
class EncryptedBuffer(FlexibleModel):
process_name: str
pid: int
@@ -351,38 +360,41 @@ class EncryptedBuffer(ExactModel):
buffer: str
buffer_size: Optional[int] = None
crypt_key: Optional[Union[HexInt, str]] = None
"""
class Behavior(ExactModel):
summary: Summary
class Behavior(FlexibleModel):
summary: Summary | None = None
# list of processes, of threads, of calls
processes: list[Process]
# tree of processes
processtree: list[ProcessTree]
# processtree: list[ProcessTree]
anomaly: list[str]
encryptedbuffers: list[EncryptedBuffer]
# anomaly: list[str]
# encryptedbuffers: list[EncryptedBuffer]
# these are small objects that describe atomic events,
# like file move, registry access.
# we'll detect the same with our API call analysis.
enhanced: Skip = None
# enhanced: Skip = None
class Target(ExactModel):
category: str
class Target(FlexibleModel):
# category: str
file: File
# pe: Optional[PE] = None
class Static(FlexibleModel):
pe: Optional[PE] = None
# flare_capa: Skip = None
class Static(ExactModel):
pe: Optional[PE] = None
flare_capa: Skip = None
class Cape(ExactModel):
"""
class Cape(FlexibleModel):
payloads: list[ProcessFile]
configs: Skip = None
"""
# flexible because there may be more sorts of analysis
@@ -405,15 +417,14 @@ class CapeReport(FlexibleModel):
# post-processed results: process tree, anomalies, etc
behavior: Behavior
# post-processed results: payloads and extracted configs
CAPE: Optional[Union[Cape, list]] = None
dropped: Optional[list[File]] = None
procdump: Optional[list[ProcessFile]] = None
procmemory: Optional[ListTODO] = None
# =========================================================================
# information we won't use in capa
#
# post-processed results: payloads and extracted configs
# CAPE: Optional[Union[Cape, list]] = None
# dropped: Optional[list[File]] = None
# procdump: Optional[list[ProcessFile]] = None
# procmemory: Optional[ListTODO] = None
#
# NBIs and HBIs
@@ -422,32 +433,32 @@ class CapeReport(FlexibleModel):
#
# if we come up with a future use for this, go ahead and re-enable!
#
network: Skip = None
suricata: Skip = None
curtain: Skip = None
sysmon: Skip = None
url_analysis: Skip = None
# network: Skip = None
# suricata: Skip = None
# curtain: Skip = None
# sysmon: Skip = None
# url_analysis: Skip = None
# screenshot hash values
deduplicated_shots: Skip = None
# deduplicated_shots: Skip = None
# k-v pairs describing the time it took to run each stage.
statistics: Skip = None
# statistics: Skip = None
# k-v pairs of ATT&CK ID to signature name or similar.
ttps: Skip = None
# ttps: Skip = None
# debug log messages
debug: Skip = None
# debug: Skip = None
# various signature matches
# we could potentially extend capa to use this info one day,
# though it would be quite sandbox-specific,
# and more detection-oriented than capability detection.
signatures: Skip = None
malfamily_tag: Optional[str] = None
malscore: float
detections: Skip = None
detections2pid: Optional[dict[int, list[str]]] = None
# signatures: Skip = None
# malfamily_tag: Optional[str] = None
# malscore: float
# detections: Skip = None
# detections2pid: Optional[dict[int, list[str]]] = None
# AV detections for the sample.
virustotal: Skip = None
# virustotal: Skip = None
@classmethod
def from_buf(cls, buf: bytes) -> "CapeReport":

View File

@@ -96,14 +96,7 @@ class VMRayAnalysis:
% (self.submission_name, self.submission_type)
)
if self.submission_static is not None:
if self.submission_static.pe is None and self.submission_static.elf is None:
# we only support static analysis for PE and ELF files for now
raise UnsupportedFormatError(
"archive does not contain a supported file format (submission_name: %s, submission_type: %s)"
% (self.submission_name, self.submission_type)
)
else:
if self.submission_static is None:
# VMRay may not record static analysis for certain file types, e.g. MSI, but we'd still like to match dynamic
# execution so we continue without and accept that the results may be incomplete
logger.warning(
@@ -223,16 +216,15 @@ class VMRayAnalysis:
# we expect monitor processes recorded in both SummaryV2.json and flog.xml to equal
# to ensure this, we compare the pid, monitor_id, and origin_monitor_id
# for the other fields we've observed cases with slight deviations, e.g.,
# the ppid for a process in flog.xml is not set correctly, all other data is equal
# the ppid, origin monitor id, etc. for a process in flog.xml is not set correctly, all other
# data is equal
sv2p = self.monitor_processes[monitor_process.process_id]
if self.monitor_processes[monitor_process.process_id] != vmray_monitor_process:
logger.debug("processes differ: %s (sv2) vs. %s (flog)", sv2p, vmray_monitor_process)
assert (sv2p.pid, sv2p.monitor_id, sv2p.origin_monitor_id) == (
vmray_monitor_process.pid,
vmray_monitor_process.monitor_id,
vmray_monitor_process.origin_monitor_id,
)
# we need, at a minimum, for the process id and monitor id to match, otherwise there is likely a bug
# in the way that VMRay tracked one of the processes
assert (sv2p.pid, sv2p.monitor_id) == (vmray_monitor_process.pid, vmray_monitor_process.monitor_id)
def _compute_monitor_threads(self):
for monitor_thread in self.flog.analysis.monitor_threads:

View File

@@ -995,7 +995,27 @@ def main(argv: Optional[list[str]] = None):
handle_common_args(args)
ensure_input_exists_from_cli(args)
input_format = get_input_format_from_cli(args)
rules = get_rules_from_cli(args)
except ShouldExitError as e:
return e.status_code
if input_format == FORMAT_RESULT:
# render the result document immediately,
# no need to load the rules or do other processing.
result_doc = capa.render.result_document.ResultDocument.from_file(args.input_file)
if args.json:
print(result_doc.model_dump_json(exclude_none=True))
elif args.vverbose:
print(capa.render.vverbose.render_vverbose(result_doc))
elif args.verbose:
print(capa.render.verbose.render_verbose(result_doc))
else:
print(capa.render.default.render_default(result_doc))
return 0
try:
rules: RuleSet = get_rules_from_cli(args)
found_limitation = False
file_extractors = get_file_extractors_from_cli(args, input_format)
if input_format in STATIC_FORMATS:
@@ -1003,45 +1023,30 @@ def main(argv: Optional[list[str]] = None):
found_limitation = find_static_limitations_from_cli(args, rules, file_extractors)
if input_format in DYNAMIC_FORMATS:
found_limitation = find_dynamic_limitations_from_cli(args, rules, file_extractors)
backend = get_backend_from_cli(args, input_format)
sample_path = get_sample_path_from_cli(args, backend)
if sample_path is None:
os_ = "unknown"
else:
os_ = capa.loader.get_os(sample_path)
extractor: FeatureExtractor = get_extractor_from_cli(args, input_format, backend)
except ShouldExitError as e:
return e.status_code
meta: rdoc.Metadata
capabilities: Capabilities
capabilities: Capabilities = find_capabilities(rules, extractor, disable_progress=args.quiet)
if input_format == FORMAT_RESULT:
# result document directly parses into meta, capabilities
result_doc = capa.render.result_document.ResultDocument.from_file(args.input_file)
meta, capabilities = result_doc.to_capa()
meta: rdoc.Metadata = capa.loader.collect_metadata(
argv, args.input_file, input_format, os_, args.rules, extractor, capabilities
)
meta.analysis.layout = capa.loader.compute_layout(rules, extractor, capabilities.matches)
else:
# all other formats we must create an extractor
# and use that to extract meta and capabilities
try:
backend = get_backend_from_cli(args, input_format)
sample_path = get_sample_path_from_cli(args, backend)
if sample_path is None:
os_ = "unknown"
else:
os_ = capa.loader.get_os(sample_path)
extractor = get_extractor_from_cli(args, input_format, backend)
except ShouldExitError as e:
return e.status_code
capabilities = find_capabilities(rules, extractor, disable_progress=args.quiet)
meta = capa.loader.collect_metadata(
argv, args.input_file, input_format, os_, args.rules, extractor, capabilities
)
meta.analysis.layout = capa.loader.compute_layout(rules, extractor, capabilities.matches)
if found_limitation:
# bail if capa's static feature extractor encountered file limitation e.g. a packed binary
# or capa's dynamic feature extractor encountered some limitation e.g. a dotnet sample
# do show the output in verbose mode, though.
if not (args.verbose or args.vverbose or args.json):
return E_FILE_LIMITATION
if found_limitation:
# bail if capa's static feature extractor encountered file limitation e.g. a packed binary
# or capa's dynamic feature extractor encountered some limitation e.g. a dotnet sample
# do show the output in verbose mode, though.
if not (args.verbose or args.vverbose or args.json):
return E_FILE_LIMITATION
if args.json:
print(capa.render.json.render(meta, rules, capabilities.matches))

View File

@@ -418,8 +418,9 @@ class Match(FrozenModel):
and a.id <= location.id
]
)
_, most_recent_match = matches_in_thread[-1]
children.append(Match.from_capa(rules, capabilities, most_recent_match))
if matches_in_thread:
_, most_recent_match = matches_in_thread[-1]
children.append(Match.from_capa(rules, capabilities, most_recent_match))
else:
children.append(Match.from_capa(rules, capabilities, rule_matches[location]))
@@ -478,8 +479,11 @@ class Match(FrozenModel):
and a.id <= location.id
]
)
_, most_recent_match = matches_in_thread[-1]
children.append(Match.from_capa(rules, capabilities, most_recent_match))
# namespace matches may not occur within the same thread as the result, so only
# proceed if a match within the same thread is found
if matches_in_thread:
_, most_recent_match = matches_in_thread[-1]
children.append(Match.from_capa(rules, capabilities, most_recent_match))
else:
if location in rule_matches:
children.append(Match.from_capa(rules, capabilities, rule_matches[location]))

View File

@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
__version__ = "9.0.0"
__version__ = "9.2.1"
def get_major_version():

View File

@@ -121,11 +121,11 @@ dev = [
# we want all developer environments to be consistent.
# These dependencies are not used in production environments
# and should not conflict with other libraries/tooling.
"pre-commit==4.1.0",
"pre-commit==4.2.0",
"pytest==8.0.0",
"pytest-sugar==1.0.0",
"pytest-instafail==0.5.0",
"flake8==7.1.1",
"flake8==7.3.0",
"flake8-bugbear==24.12.12",
"flake8-encodings==0.5.1",
"flake8-comprehensions==3.16.0",
@@ -133,22 +133,22 @@ dev = [
"flake8-no-implicit-concat==0.3.5",
"flake8-print==5.0.0",
"flake8-todos==0.3.1",
"flake8-simplify==0.21.0",
"flake8-simplify==0.22.0",
"flake8-use-pathlib==0.3.0",
"flake8-copyright==0.2.4",
"ruff==0.9.2",
"ruff==0.12.0",
"black==25.1.0",
"isort==6.0.0",
"mypy==1.14.1",
"mypy==1.16.0",
"mypy-protobuf==3.6.0",
"PyGithub==2.5.0",
"PyGithub==2.6.0",
# type stubs for mypy
"types-backports==0.1.3",
"types-colorama==0.4.15.11",
"types-PyYAML==6.0.8",
"types-psutil==6.1.0.20241102",
"types-psutil==7.0.0.20250218",
"types_requests==2.32.0.20240712",
"types-protobuf==5.29.1.20241207",
"types-protobuf==6.30.2.20250516",
"deptry==0.23.0"
]
build = [
@@ -156,13 +156,13 @@ build = [
# we want all developer environments to be consistent.
# These dependencies are not used in production environments
# and should not conflict with other libraries/tooling.
"pyinstaller==6.11.1",
"setuptools==75.8.0",
"pyinstaller==6.14.1",
"setuptools==80.9.0",
"build==1.2.2"
]
scripts = [
"jschema_to_python==1.2.3",
"psutil==6.1.0",
"psutil==7.0.0",
"stix2==3.0.1",
"sarif_om==1.0.4",
"requests==2.32.3",

View File

@@ -12,7 +12,7 @@ cxxfilt==0.3.0
dncil==1.0.2
dnfile==0.15.0
funcy==2.0
humanize==4.10.0
humanize==4.12.0
ida-netnode==3.0
ida-settings==2.1.0
intervaltree==3.1.0
@@ -21,25 +21,25 @@ mdurl==0.1.2
msgpack==1.0.8
networkx==3.4.2
pefile==2024.8.26
pip==25.0
protobuf==5.29.3
pip==25.1.1
protobuf==6.31.1
pyasn1==0.5.1
pyasn1-modules==0.3.0
pycparser==2.22
pydantic==2.10.1
pydantic==2.11.4
# pydantic pins pydantic-core,
# but dependabot updates these separately (which is broken) and is annoying,
# so we rely on pydantic to pull in the right version of pydantic-core.
# pydantic-core==2.23.4
xmltodict==0.14.2
pyelftools==0.31
pyelftools==0.32
pygments==2.19.1
python-flirt==0.9.2
pyyaml==6.0.2
rich==13.9.2
rich==14.0.0
ruamel-yaml==0.18.6
ruamel-yaml-clib==0.2.8
setuptools==75.8.0
setuptools==80.9.0
six==1.17.0
sortedcontainers==2.4.0
viv-utils==0.8.0

2
rules

Submodule rules updated: 79afc557f1...2f09b4d471

View File

@@ -175,8 +175,6 @@ def convert_rule(rule, rulename, cround, depth):
depth += 1
logger.info("recursion depth: %d", depth)
global var_names
def do_statement(s_type, kid):
yara_strings = ""
yara_condition = ""

View File

@@ -49,7 +49,7 @@ import capa.helpers
import capa.features.insn
import capa.capabilities.common
from capa.rules import Rule, RuleSet
from capa.features.common import OS_AUTO, String, Feature, Substring
from capa.features.common import OS_AUTO, Regex, String, Feature, Substring
from capa.render.result_document import RuleMetadata
logger = logging.getLogger("lint")
@@ -406,6 +406,7 @@ class DoesntMatchExample(Lint):
return True
if rule.name not in capabilities:
logger.info('rule "%s" does not match for sample %s', rule.name, example_id)
return True
@@ -721,6 +722,76 @@ class FeatureStringTooShort(Lint):
return False
class FeatureRegexRegistryControlSetMatchIncomplete(Lint):
name = "feature regex registry control set match incomplete"
recommendation = (
'use "(ControlSet\\d{3}|CurrentControlSet)" to match both indirect references '
+ 'via "CurrentControlSet" and direct references via "ControlSetXXX"'
)
def check_features(self, ctx: Context, features: list[Feature]):
for feature in features:
if not isinstance(feature, (Regex,)):
continue
assert isinstance(feature.value, str)
pat = feature.value.lower()
if "system\\\\" in pat and "controlset" in pat or "currentcontrolset" in pat:
if "system\\\\(controlset\\d{3}|currentcontrolset)" not in pat:
return True
return False
class FeatureRegexContainsUnescapedPeriod(Lint):
name = "feature regex contains unescaped period"
recommendation_template = 'escape the period in "{:s}" unless it should be treated as a regex dot operator'
level = Lint.WARN
def check_features(self, ctx: Context, features: list[Feature]):
for feature in features:
if isinstance(feature, (Regex,)):
assert isinstance(feature.value, str)
pat = feature.value.removeprefix("/")
pat = pat.removesuffix("/i").removesuffix("/")
index = pat.find(".")
if index == -1:
return False
if index < len(pat) - 1:
if pat[index + 1] in ("*", "+", "?", "{"):
# like "/VB5!.*/"
return False
if index == 0:
# like "/.exe/" which should be "/\.exe/"
self.recommendation = self.recommendation_template.format(feature.value)
return True
if pat[index - 1] != "\\":
# like "/test.exe/" which should be "/test\.exe/"
self.recommendation = self.recommendation_template.format(feature.value)
return True
if pat[index - 1] == "\\":
for i, char in enumerate(pat[0:index][::-1]):
if char == "\\":
continue
if i % 2 == 0:
# like "/\\\\.\\pipe\\VBoxTrayIPC/"
self.recommendation = self.recommendation_template.format(feature.value)
return True
break
return False
class FeatureNegativeNumber(Lint):
name = "feature value is negative"
recommendation = "specify the number's two's complement representation"
@@ -931,7 +1002,13 @@ def lint_meta(ctx: Context, rule: Rule):
return run_lints(META_LINTS, ctx, rule)
FEATURE_LINTS = (FeatureStringTooShort(), FeatureNegativeNumber(), FeatureNtdllNtoskrnlApi())
FEATURE_LINTS = (
FeatureStringTooShort(),
FeatureNegativeNumber(),
FeatureNtdllNtoskrnlApi(),
FeatureRegexContainsUnescapedPeriod(),
FeatureRegexRegistryControlSetMatchIncomplete(),
)
def lint_features(ctx: Context, rule: Rule):

View File

@@ -70,4 +70,4 @@ def test_standalone_binja_backend():
@pytest.mark.skipif(binja_present is False, reason="Skip binja tests if the binaryninja Python API is not installed")
def test_binja_version():
version = binaryninja.core_version_info()
assert version.major == 4 and version.minor == 2
assert version.major == 5 and version.minor == 0

File diff suppressed because it is too large Load Diff

View File

@@ -26,15 +26,15 @@
},
"devDependencies": {
"@rushstack/eslint-patch": "^1.8.0",
"@vitejs/plugin-vue": "^5.0.5",
"@vitejs/plugin-vue": "^5.2.3",
"@vue/eslint-config-prettier": "^9.0.0",
"@vue/test-utils": "^2.4.6",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"jsdom": "^24.1.0",
"prettier": "^3.2.5",
"vite": "^5.4.14",
"vite-plugin-singlefile": "^2.0.2",
"vitest": "^1.6.0"
"vite": "^6.3.4",
"vite-plugin-singlefile": "^2.2.0",
"vitest": "^3.0.9"
}
}

View File

@@ -210,27 +210,25 @@
<div class="row flex-lg-row-reverse align-items-center g-5">
<h1>What's New</h1>
<h2 class="mt-3">Rule Updates</h2>
<ul class="mt-2 ps-5">
<!-- TODO(williballenthin): add date -->
<li>
added:
<a href="./rules/use bigint function/">
use bigint function
</a>
</li>
<li>
added:
<a href="./rules/encrypt data using RSA via embedded library/">
encrypt data using RSA via embedded library
</a>
</li>
</ul>
<h2 class="mt-3">Tool Updates</h2>
<h3 class="mt-2">v9.2.1 (<em>2025-06-06</em>)</h3>
<p class="mt-0">
This point release fixes bugs including removing an unnecessary PyInstaller warning message and enabling the standalone binary to execute on systems running older versions of glibc.
</p>
<h3 class="mt-2">v9.2.0 (<em>2025-06-03</em>)</h3>
<p class="mt-0">
This release improves a few aspects of dynamic analysis, including relaxing our validation on fields across many CAPE versions and processing additional VMRay submission file types, for example.
It also includes an updated rule pack containing new rules and rule fixes.
</p>
<h3 class="mt-2">v9.1.0 (<em>2025-03-02</em>)</h3>
<p class="mt-0">
This release improves a few aspects of dynamic analysis, relaxing our validation on fields across many CAPE versions, for example.
It also includes an updated rule pack in which many dynamic rules make better use of the "span of calls" scope.
</p>
<h3 class="mt-2">v9.0.0 (<em>2025-02-05</em>)</h3>
<p class="mt-0">
This release introduces a new scope for dynamic analysis, "span of calls",