Compare commits

...

100 Commits

Author SHA1 Message Date
Ben Hirschberg
d5bd3708b8 Merge pull request #1836 from slashben/feature/mcpserver-v1
Feature/mcpserver v1
2025-06-24 16:29:16 +03:00
Ben
2bd686131e Incorporating review
Signed-off-by: Ben <ben@armosec.io>
2025-06-10 14:32:26 +03:00
Ben
1ea4e0c304 Add configuration scan tools and resource handling
Implemented two new tools: 'list_configuration_security_scan_manifests' for listing available configuration scan manifests and 'get_configuration_security_scan_manifest' for retrieving details of a specific manifest. Added a resource template for configuration manifests and integrated these tools into the mcpserver.

Signed-off-by: Ben <ben@armosec.io>
2025-06-09 09:11:28 +03:00
Matthias Bertschy
b3251306d0 Merge pull request #1837 from ian-fox/master
Make a second sigint terminate kubescape immediately
2025-06-03 12:54:02 +02:00
Ian Fox
91ecdaba4e Make a second sigint terminate immediately
Right now, sending a sigint will start a graceful shutdown, which can take quite a while.
By calling stop() in the signal handler it unregisters the handler so that a subsequent
sigint received during a graceful shutdown will kill the process immediately.

Signed-off-by: Ian Fox <code@whatthefox.dev>
2025-06-02 19:12:45 +02:00
Matthias Bertschy
fa05dcd00d go.mod massaging
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-05-23 16:02:15 +02:00
Ben
1c2c928732 Failing build
Signed-off-by: Ben <ben@armosec.io>
2025-05-23 15:13:22 +03:00
Ben
69ac490006 Failing build
Signed-off-by: Ben <ben@armosec.io>
2025-05-23 15:13:12 +03:00
Matthias Bertschy
b67b9f3af2 Merge pull request #1835 from pixel365/cancel
Ensure context cancellation on command execution failure
2025-05-16 21:20:16 +02:00
Ruslan Semagin
628ed4a374 Ensure context cancellation on command execution failure
Signed-off-by: Ruslan Semagin <pixel.365.24@gmail.com>
2025-05-16 10:11:06 +03:00
Matthias Bertschy
a6fe34b466 add workflow_dispatch to pr scanner
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-05-02 16:36:27 +02:00
Matthias Bertschy
2e9406d96a Merge pull request #1828 from rash1411/patch-1
Update dir.go
2025-04-29 21:44:09 +02:00
Matthias Bertschy
6b1bf07f7f Merge pull request #1827 from shangchengbabaiban/master
fix: Fix stdin restoration in TestUserConfirmed
2025-04-29 21:40:30 +02:00
Matthias Bertschy
318c2c7ae6 Merge pull request #1829 from kubescape/dependabot/go_modules/golang.org/x/net-0.38.0
Bump golang.org/x/net from 0.37.0 to 0.38.0
2025-04-28 14:19:13 +02:00
dependabot[bot]
45f60b6fe0 Bump golang.org/x/net from 0.37.0 to 0.38.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.37.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.37.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-28 14:03:44 +02:00
rash1411
20557bc721 Update dir.go
Fix: Correct runtime.Caller usage and handle error in CurrentDir()

- Changed runtime.Caller(1) to runtime.Caller(0) to correctly fetch the current file's directory.
- Added proper check for the 'ok' value returned by runtime.Caller.
- Improved robustness by panicking if runtime information retrieval fails.


Signed-off-by: rash1411 <107741585+rash1411@users.noreply.github.com>
2025-04-27 01:29:04 +05:30
shangchengbabaiban
d8bfb27bc3 fix: Fix stdin restoration in TestUserConfirmed
Signed-off-by: shangchengbabaiban <shuang.cui@live.cn>
2025-04-19 10:51:09 +08:00
Matthias Bertschy
9776691816 Merge pull request #1824 from kubescape/dependabot/go_modules/helm.sh/helm/v3-3.17.3
Bump helm.sh/helm/v3 from 3.14.4 to 3.17.3
2025-04-15 12:41:19 +02:00
dependabot[bot]
80e419df24 Bump helm.sh/helm/v3 from 3.14.4 to 3.17.3
Bumps [helm.sh/helm/v3](https://github.com/helm/helm) from 3.14.4 to 3.17.3.
- [Release notes](https://github.com/helm/helm/releases)
- [Commits](https://github.com/helm/helm/compare/v3.14.4...v3.17.3)

---
updated-dependencies:
- dependency-name: helm.sh/helm/v3
  dependency-version: 3.17.3
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-15 12:22:19 +02:00
Matthias Bertschy
143f831f5b Merge pull request #1822 from kubescape/mergelabels
merge labels and annotations in RetryOnConflict
2025-04-14 16:26:47 +02:00
Matthias Bertschy
a4897304e8 merge labels and annotations in RetryOnConflict
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-04-14 15:36:34 +02:00
Matthias Bertschy
80d1165e2c Merge pull request #1820 from kubescape/opav1
upgrade open-policy-agent to 1.x
2025-04-14 14:13:23 +02:00
Matthias Bertschy
31ed7d5160 upgrade open-policy-agent to 1.x
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-04-10 17:17:08 +02:00
Matthias Bertschy
d62e9ce207 Merge pull request #1814 from pixel365/tests
test: increase test coverage
2025-04-07 09:17:27 +02:00
Ruslan Semagin
3b10443ff5 fix: goimports
Signed-off-by: Ruslan Semagin <pixel.365.24@gmail.com>
2025-04-01 12:26:15 +03:00
Ruslan Semagin
218e3914b1 test: increase test coverage
Signed-off-by: Ruslan Semagin <pixel.365.24@gmail.com>
2025-04-01 10:12:35 +03:00
Matthias Bertschy
2b07fbe782 Merge pull request #1813 from kubescape/merge
check for nil map in merge methods
2025-03-31 11:18:05 +02:00
Matthias Bertschy
0655d0496b check for nil map in merge methods
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-03-28 12:10:38 +01:00
Matthias Bertschy
02bf31fbc9 Merge pull request #1812 from kubescape/dependabot/go_modules/github.com/golang-jwt/jwt/v5-5.2.2
Bump github.com/golang-jwt/jwt/v5 from 5.2.1 to 5.2.2
2025-03-28 11:03:59 +01:00
dependabot[bot]
4d8a3f51e3 Bump github.com/golang-jwt/jwt/v5 from 5.2.1 to 5.2.2
Bumps [github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt) from 5.2.1 to 5.2.2.
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md)
- [Commits](https://github.com/golang-jwt/jwt/compare/v5.2.1...v5.2.2)

---
updated-dependencies:
- dependency-name: github.com/golang-jwt/jwt/v5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-28 10:30:02 +01:00
Matthias Bertschy
43d29f7b8b Merge pull request #1811 from kubescape/prerequisites
feat: enhance prerequisites UI with new review-values and improved pr…
2025-03-24 12:44:42 +01:00
David Alima
ee0d4cba98 feat: enhance prerequisites UI with new review-values and improved prerequisites report
Signed-off-by: David Alima <davida@armosec.io>
2025-03-24 13:10:58 +02:00
Matthias Bertschy
d860c0234a Merge pull request #1809 from kubescape/dependabot/go_modules/golang.org/x/net-0.36.0
Bump golang.org/x/net from 0.33.0 to 0.36.0
2025-03-20 13:35:08 +01:00
Matthias Bertschy
f13ded61bf Bump github.com/containerd/containerd to 1.7.27
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-03-20 13:05:17 +01:00
dependabot[bot]
fe8fc700f4 Bump golang.org/x/net from 0.33.0 to 0.36.0
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-20 09:59:07 +00:00
Matthias Bertschy
47b670637b Merge pull request #1808 from kubescape/prereq
updating prerequisites to support custom kubeconfig
2025-03-19 09:37:57 +01:00
Matthias Bertschy
97c83a652b updating prerequisites to support custom kubeconfig
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-03-18 10:02:17 +01:00
Matthias Bertschy
a089831720 upload everything in dist
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-03-10 10:32:00 +01:00
Matthias Bertschy
e4f1720a0c bump goreleaser action in the other file too
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-03-10 09:52:42 +01:00
Matthias Bertschy
233eb2134c bump goreleaser action
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-03-10 09:19:48 +01:00
Matthias Bertschy
06da926455 Merge pull request #1806 from kubescape/goreleaser
generate checksums for all artifacts
2025-03-10 08:56:35 +01:00
Amit Schendel
37f6193fe0 Merge pull request #1807 from kubescape/Bump-license-date
Update README.md
2025-03-09 17:08:09 +02:00
Amit Schendel
27ac036b7d Update README.md
Signed-off-by: Amit Schendel <58078857+amitschendel@users.noreply.github.com>
2025-03-09 17:04:32 +02:00
Matthias Bertschy
321d335b39 generate checksums for all artifacts
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-03-09 12:37:21 +01:00
Matthias Bertschy
91b7d8fc2b Merge pull request #1803 from kubescape/dependabot/go_modules/github.com/go-jose/go-jose/v3-3.0.4
Bump github.com/go-jose/go-jose/v3 from 3.0.3 to 3.0.4
2025-03-04 10:38:44 +01:00
dependabot[bot]
2b28911db0 Bump github.com/go-jose/go-jose/v3 from 3.0.3 to 3.0.4
Bumps [github.com/go-jose/go-jose/v3](https://github.com/go-jose/go-jose) from 3.0.3 to 3.0.4.
- [Release notes](https://github.com/go-jose/go-jose/releases)
- [Changelog](https://github.com/go-jose/go-jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-jose/go-jose/compare/v3.0.3...v3.0.4)

---
updated-dependencies:
- dependency-name: github.com/go-jose/go-jose/v3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-03-04 09:28:14 +01:00
Amir Malka
667e5e8258 fix score calculation for framework with all controls in status irrelevant (#1802)
Signed-off-by: Amir Malka <amirm@armosec.io>
2025-03-03 15:20:14 +02:00
Matthias Bertschy
728b341048 Merge pull request #1797 from kubescape/prereq
update prerequisites command
2025-02-26 11:51:42 +01:00
Matthias Bertschy
75b295d579 update prerequisites command
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-26 11:20:33 +01:00
Matthias Bertschy
75298eabf2 Merge pull request #1796 from kubescape/dependabot/go_modules/httphandler/github.com/go-jose/go-jose/v4-4.0.5
Bump github.com/go-jose/go-jose/v4 from 4.0.2 to 4.0.5 in /httphandler
2025-02-25 08:45:31 +01:00
dependabot[bot]
2458f2ceb9 Bump github.com/go-jose/go-jose/v4 from 4.0.2 to 4.0.5
Bumps [github.com/go-jose/go-jose/v4](https://github.com/go-jose/go-jose) from 4.0.2 to 4.0.5.
- [Release notes](https://github.com/go-jose/go-jose/releases)
- [Changelog](https://github.com/go-jose/go-jose/blob/main/CHANGELOG.md)
- [Commits](https://github.com/go-jose/go-jose/compare/v4.0.2...v4.0.5)

---
updated-dependencies:
- dependency-name: github.com/go-jose/go-jose/v4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-25 07:58:42 +01:00
Amir Malka
f57948ad97 deprecate control name in exception policies (#1795)
* deprecate control name in posture exception policies

Signed-off-by: Amir Malka <amirm@armosec.io>

* deprecate control name in posture exception policies

Signed-off-by: Amir Malka <amirm@armosec.io>

* deprecate control name in posture exception policies

Signed-off-by: Amir Malka <amirm@armosec.io>

* deprecate control name in posture exception policies

Signed-off-by: Amir Malka <amirm@armosec.io>

---------

Signed-off-by: Amir Malka <amirm@armosec.io>
2025-02-20 10:27:27 +02:00
Matthias Bertschy
d0befc5f16 Merge pull request #1792 from kubescape/colors
removing enable/disable colors, as not compatible with all loggers
2025-02-18 12:11:40 +01:00
Matthias Bertschy
5d4bd2e94e removing enable/disable colors, as not compatible with all loggers
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-18 11:38:47 +01:00
Matthias Bertschy
ae37fdc295 fix go tidy
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-14 16:19:42 +01:00
Matthias Bertschy
3dd95ff3a3 Merge pull request #1791 from kubescape/prereq
update prerequisites
2025-02-14 16:12:03 +01:00
Matthias Bertschy
daadb5b804 update prerequisites
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-14 16:10:31 +01:00
Matthias Bertschy
d250017faf Merge pull request #1790 from pixel365/err
fix: add error handling and context propagation
2025-02-12 10:56:03 +01:00
Ruslan Semagin
835bcbeb12 fix: format imports with goimports
Signed-off-by: Ruslan Semagin <pixel.365.24@gmail.com>
2025-02-12 12:15:14 +03:00
Ruslan Semagin
2e4f7c4477 fix: add error handling and context propagation
Signed-off-by: Ruslan Semagin <pixel.365.24@gmail.com>
2025-02-12 09:02:01 +03:00
Matthias Bertschy
66bf93eb0c Merge pull request #1789 from pixel365/ctx
Refactor: propagate context from main to avoid redundant context creation
2025-02-11 21:27:48 +01:00
Matthias Bertschy
3a036ed0e3 remove test resources saved by accident
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-11 21:26:26 +01:00
Ruslan Semagin
fe7dad4560 Refactor: propagate context from main to avoid redundant context creation
- Introduced a single context in main() to handle interrupt signals (os.Interrupt, syscall.SIGTERM).
- Removed repetitive context creation in the program by reusing the propagated context.
- Improved code readability and maintainability by centralizing context management.
- Ensured consistent handling of graceful shutdown across the program.

Signed-off-by: Ruslan Semagin <pixel.365.24@gmail.com>
2025-02-11 19:52:48 +03:00
Matthias Bertschy
fb36b09f3a remove mv kubescape arm64 binary step
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-11 09:49:17 +01:00
Matthias Bertschy
e71b0c75a9 fix downloaded artifacts path
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-11 08:55:43 +01:00
Matthias Bertschy
d615099ce1 try fixing download-artifacts action for release
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-11 07:42:30 +01:00
Matthias Bertschy
f265b91939 Merge pull request #1788 from kubescape/sarif
do not skip on location resolver error
2025-02-10 13:40:59 +01:00
Matthias Bertschy
825694ade1 do not skip on location resolver error
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-10 10:25:44 +01:00
Matthias Bertschy
979a30aea7 Merge pull request #1591 from Sanskarzz/scanapiexception
added support for exception rules in Scan API ( As a HTTP request)
2025-02-07 13:32:42 +01:00
Matthias Bertschy
39c4aa4faa Merge pull request #1568 from VaibhavMalik4187/feature-exceptions
Feature: Added exceptions flag in scan image cmd
2025-02-07 12:40:24 +01:00
Matthias Bertschy
475b672a7a add fixed grypeDB for tests
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-07 12:34:11 +01:00
Matthias Bertschy
815c87b532 implement reviews from DW
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-07 12:16:35 +01:00
Sanskarzz
82120f9d31 added support for exception rules
Signed-off-by: Sanskarzz <sanskar.gur@gmail.com>
2025-02-07 12:15:56 +01:00
VaibhavMalik4187
0545818f82 Added tests and improvements for image exceptions
Signed-off-by: VaibhavMalik4187 <vaibhavmalik2018@gmail.com>
2025-02-07 10:26:53 +01:00
VaibhavMalik4187
046da1940c Added support for targets in image exceptions
This commit introduces the ability to specify targets in image
exceptions. Each target will have the following 4 attributes:

1. Registry
2. Organization
3. ImageName
4. ImageTag

These attributes will be used to match against the canonical image name
of the image to be scanned. The vulnerabilites and the severities
specified in the VulnerabilitiesIgnorePolicy object will be considered
only if the image to be scanned matches the targets specified for that
policy. Regular expressions can also be used to specify the image
attributes.

Signed-off-by: VaibhavMalik4187 <vaibhavmalik2018@gmail.com>
2025-02-07 10:26:53 +01:00
VaibhavMalik4187
a31154897f Added support for severity exceptions in imagescan
This commit add relevant functions to support severity exceptions during
image scan.

Signed-off-by: VaibhavMalik4187 <vaibhavmalik2018@gmail.com>
2025-02-07 10:26:53 +01:00
VaibhavMalik4187
199c57be30 WIP: Load image exceptions from file
Added initial commit to start loading image exceptions from json files.

Currently, it supports vulnerability exceptions using their CVE-IDs.

Signed-off-by: VaibhavMalik4187 <vaibhavmalik2018@gmail.com>
2025-02-07 10:26:53 +01:00
VaibhavMalik4187
7d55c79f11 Feature: Added exceptions flag in scan image cmd
This commit introduces the "exceptions" flag in the scan image command.
Users can pass a list of vulnerabilities they ignore while scanning an
image using this flag. Also added tests for the same.

Fixes: https://github.com/kubescape/kubescape/issues/1564

Signed-off-by: VaibhavMalik4187 <vaibhavmalik2018@gmail.com>
2025-02-07 10:26:53 +01:00
Matthias Bertschy
ee76364371 fix scorecard-action version
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-07 09:23:28 +01:00
Matthias Bertschy
4f2c7ac1de Merge pull request #1787 from kubescape/bump
bump all CI actions
2025-02-07 09:09:44 +01:00
Matthias Bertschy
00340827be bump all CI actions
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-07 08:00:19 +01:00
Matthias Bertschy
708fe64240 Merge pull request #1786 from Fernando-hub527/refactor/maroto-version-v2
Refactor: maroto version v2
2025-02-07 07:33:34 +01:00
Fernando-hub527
8985bbe3a9 refactor: update Maroto configuration file location
Signed-off-by: Fernando-hub527 <fernandocoelhosaraivanando@gmail.com>
2025-02-06 18:07:57 -03:00
Matthias Bertschy
1ffca5648e delete TableObject.getSeverityColor to please CI
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-02-06 07:56:07 +01:00
Fernando-hub527
76b1ecb022 refactor: create a method that returns the pdf row
Return a struct with the data for ease of use

Signed-off-by: Fernando-hub527 <fernandocoelhosaraivanando@gmail.com>
2025-02-05 21:52:50 -03:00
Fernando-hub527
fc69a3692e refactor: remove unused code
Signed-off-by: Fernando-hub527 <fernandocoelhosaraivanando@gmail.com>
2025-02-05 21:47:28 -03:00
Fernando-hub527
e159458129 test:validate creation of report pdf
Signed-off-by: Fernando-hub527 <fernandocoelhosaraivanando@gmail.com>
2025-02-05 21:45:01 -03:00
Fernando-hub527
b259f117ff refactor: create a report template with maroto/v2
Separate template creation from application logic

Signed-off-by: Fernando-hub527 <fernandocoelhosaraivanando@gmail.com>
2025-02-05 21:36:39 -03:00
Fernando-hub527
13cf34bffd refactor: update Maroto version to v2
Signed-off-by: Fernando-hub527 <fernandocoelhosaraivanando@gmail.com>
2025-02-05 21:31:22 -03:00
Matthias Bertschy
0300fee38b bump actions/download-artifact@v4
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-01-31 16:38:01 +01:00
Matthias Bertschy
d61d641e81 bump actions/upload-artifact@v4
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-01-31 16:09:16 +01:00
Matthias Bertschy
2added0f7c use go 1.23, disable cache
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-01-31 16:06:13 +01:00
Matthias Bertschy
b6f6573ed8 Merge pull request #1785 from kubescape/sarif
fix helm detection in sarif printer
2025-01-31 16:04:36 +01:00
Matthias Bertschy
4215771134 fix helm detection in sarif printer
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-01-31 15:23:15 +01:00
Amit Schendel
fd37446e1b Merge pull request #1784 from kubescape/feature/incubating-logo
Changing README of Kubescape from Sandbox to Incubating
2025-01-27 14:01:09 +02:00
Amit Schendel
351498aac5 Changing README of Kubescape from Sandbox to Incubating
Signed-off-by: Amit Schendel <amitschendel@gmail.com>
2025-01-27 13:47:16 +02:00
Eng Zer Jun
2005010568 Replace golang.org/x/exp/slices with slices from stdlib (#1783) 2025-01-17 20:51:08 +02:00
Matthias Bertschy
e16c4cc9b4 fix go.mod for httphandler
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-01-16 15:20:58 +01:00
Matthias Bertschy
544ba9831a Merge pull request #1782 from kubescape/prereq
add prerequisites command
2025-01-16 14:50:28 +01:00
Matthias Bertschy
b6c919feb1 add prerequisites command
Signed-off-by: Matthias Bertschy <matthias.bertschy@gmail.com>
2025-01-16 14:10:40 +01:00
81 changed files with 4456 additions and 2045 deletions

View File

@@ -1,6 +1,7 @@
name: 00-pr_scanner
permissions: read-all
on:
workflow_dispatch: {}
pull_request:
types: [opened, reopened, synchronize, ready_for_review]
paths-ignore:
@@ -65,7 +66,7 @@ jobs:
COMPONENT_NAME: kubescape
CGO_ENABLED: 0
GO111MODULE: ""
GO_VERSION: "1.21"
GO_VERSION: "1.23"
RELEASE: "latest"
CLIENT: test
secrets: inherit

View File

@@ -37,7 +37,7 @@ jobs:
COMPONENT_NAME: kubescape
CGO_ENABLED: 0
GO111MODULE: ""
GO_VERSION: "1.21"
GO_VERSION: "1.23"
RELEASE: ${{ needs.retag.outputs.NEW_TAG }}
CLIENT: release
secrets: inherit

View File

@@ -39,7 +39,6 @@ jobs:
name: Installing go
with:
go-version: ${{ inputs.GO_VERSION }}
cache: true
- name: Test core pkg
run: ${{ env.DOCKER_CMD }} go test -v ./...
@@ -52,7 +51,7 @@ jobs:
- uses: anchore/sbom-action/download-syft@v0.15.2
name: Setup Syft
- uses: goreleaser/goreleaser-action@v5
- uses: goreleaser/goreleaser-action@v6
name: Build
with:
distribution: goreleaser
@@ -93,8 +92,7 @@ jobs:
- uses: actions/setup-go@v4
name: Installing go
with:
go-version: '1.21'
cache: true
go-version: "1.23"
- name: Scanning - Forbidden Licenses (go-licenses)
id: licenses-scan
continue-on-error: true
@@ -107,7 +105,7 @@ jobs:
if: ${{ env.GITGUARDIAN_API_KEY }}
continue-on-error: true
id: credentials-scan
uses: GitGuardian/ggshield-action@4ab2994172fadab959240525e6b833d9ae3aca61 # ratchet:GitGuardian/ggshield-action@master
uses: GitGuardian/ggshield-action@master
with:
args: -v --all-policies
env:
@@ -120,7 +118,7 @@ jobs:
if: ${{ env.SNYK_TOKEN }}
id: vulnerabilities-scan
continue-on-error: true
uses: snyk/actions/golang@806182742461562b67788a64410098c9d9b96adb # ratchet:snyk/actions/golang@master
uses: snyk/actions/golang@master
with:
command: test --all-projects
env:
@@ -142,7 +140,7 @@ jobs:
- name: Comment results to PR
continue-on-error: true # Warning: This might break opening PRs from forks
uses: peter-evans/create-or-update-comment@5adcb0bb0f9fb3f95ef05400558bdb3f329ee808 # ratchet:peter-evans/create-or-update-comment@v2.1.0
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
body: |

View File

@@ -163,7 +163,6 @@ jobs:
name: Installing go
with:
go-version: ${{ inputs.GO_VERSION }}
cache: true
- name: (debug) Step 3 - Check disk space before build
run: df -h
@@ -182,13 +181,13 @@ jobs:
- name: (debug) Step 5 - Check disk space before setting up Syft
run: df -h
- uses: anchore/sbom-action/download-syft@v0.15.2
- uses: anchore/sbom-action/download-syft@v0
name: Setup Syft
- name: (debug) Step 6 - Check disk space before goreleaser
run: df -h
- uses: goreleaser/goreleaser-action@v5
- uses: goreleaser/goreleaser-action@v6
name: Build
with:
distribution: goreleaser
@@ -224,11 +223,11 @@ jobs:
- name: (debug) Step 9 - Check disk space before uploading artifacts
run: df -h
- uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb # ratchet:actions/upload-artifact@v3.1.1
- uses: actions/upload-artifact@v4
name: Upload artifacts
with:
name: kubescape
path: dist/kubescape*
path: dist/*
if-no-files-found: error
- name: (debug) Step 10 - Check disk space after uploading artifacts
@@ -290,7 +289,7 @@ jobs:
if: ${{ (needs.wf-preparation.outputs.is-secret-set == 'true') && (always() && (contains(needs.*.result, 'success') || contains(needs.*.result, 'skipped')) && !(contains(needs.*.result, 'failure')) && !(contains(needs.*.result, 'cancelled'))) }}
runs-on: ubuntu-latest # This cannot change
steps:
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
- uses: actions/download-artifact@v4
id: download-artifact
with:
name: kubescape
@@ -307,7 +306,7 @@ jobs:
repository: armosec/system-tests
path: .
- uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # ratchet:actions/setup-python@v4
- uses: actions/setup-python@v4
with:
python-version: '3.8.13'
cache: 'pip'
@@ -352,7 +351,7 @@ jobs:
deactivate
- name: Test Report
uses: mikepenz/action-junit-report@6e9933f4a97f4d2b99acef4d7b97924466037882 # ratchet:mikepenz/action-junit-report@v3.6.1
uses: mikepenz/action-junit-report@v5
if: always() # always run even if the previous step fails
with:
github_token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -33,7 +33,7 @@ jobs:
CGO_ENABLED: 0
GO111MODULE: "on"
BUILD_PLATFORM: ${{ inputs.PLATFORMS && 'linux/amd64,linux/arm64' || 'linux/amd64' }}
GO_VERSION: "1.21"
GO_VERSION: "1.23"
REQUIRED_TESTS: '[]'
COSIGN: ${{ inputs.CO_SIGN }}
HELM_E2E_TEST: false

View File

@@ -27,14 +27,15 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
- uses: actions/download-artifact@v4
id: download-artifact
with:
name: kubescape
path: .
# TODO: kubescape-windows-latest is deprecated and should be removed
- name: Get kubescape.exe from kubescape-windows-latest.exe
run: cp ${{steps.download-artifact.outputs.download-path}}/kubescape/kubescape-${{ env.WINDOWS_OS }}.exe ${{steps.download-artifact.outputs.download-path}}/kubescape/kubescape.exe
run: cp ${{steps.download-artifact.outputs.download-path}}/kubescape-${{ env.WINDOWS_OS }}.exe ${{steps.download-artifact.outputs.download-path}}/kubescape.exe
- name: Set release token
id: set-token
@@ -50,7 +51,7 @@ jobs:
find . -type f -print
- name: Release
uses: softprops/action-gh-release@975c1b265e11dd76618af1c374e7981f9a6ff44a
uses: softprops/action-gh-release@v2
with:
token: ${{ steps.set-token.outputs.token }}
name: ${{ inputs.RELEASE_NAME }}
@@ -60,32 +61,26 @@ jobs:
prerelease: false
fail_on_unmatched_files: true
files: |
./kubescape/kubescape-${{ env.MAC_OS }}
./kubescape/kubescape-${{ env.MAC_OS }}.sbom
./kubescape/kubescape-${{ env.MAC_OS }}.sha256
./kubescape/kubescape-${{ env.MAC_OS }}.tar.gz
./kubescape/kubescape-${{ env.UBUNTU_OS }}
./kubescape/kubescape-${{ env.UBUNTU_OS }}.sbom
./kubescape/kubescape-${{ env.UBUNTU_OS }}.sha256
./kubescape/kubescape-${{ env.UBUNTU_OS }}.tar.gz
./kubescape/kubescape-${{ env.WINDOWS_OS }}.exe
./kubescape/kubescape-${{ env.WINDOWS_OS }}.exe.sbom
./kubescape/kubescape-${{ env.WINDOWS_OS }}.exe.sha256
./kubescape/kubescape-${{ env.WINDOWS_OS }}.tar.gz
./kubescape/kubescape-arm64-${{ env.MAC_OS }}
./kubescape/kubescape-arm64-${{ env.MAC_OS }}.sbom
./kubescape/kubescape-arm64-${{ env.MAC_OS }}.sha256
./kubescape/kubescape-arm64-${{ env.MAC_OS }}.tar.gz
./kubescape/kubescape-arm64-${{ env.UBUNTU_OS }}
./kubescape/kubescape-arm64-${{ env.UBUNTU_OS }}.sbom
./kubescape/kubescape-arm64-${{ env.UBUNTU_OS }}.sha256
./kubescape/kubescape-arm64-${{ env.UBUNTU_OS }}.tar.gz
./kubescape/kubescape-arm64-${{ env.WINDOWS_OS }}.exe
./kubescape/kubescape-arm64-${{ env.WINDOWS_OS }}.exe.sbom
./kubescape/kubescape-arm64-${{ env.WINDOWS_OS }}.exe.sha256
./kubescape/kubescape-arm64-${{ env.WINDOWS_OS }}.tar.gz
./kubescape/kubescape-riscv64-${{ env.UBUNTU_OS }}
./kubescape/kubescape-riscv64-${{ env.UBUNTU_OS }}.sbom
./kubescape/kubescape-riscv64-${{ env.UBUNTU_OS }}.sha256
./kubescape/kubescape-riscv64-${{ env.UBUNTU_OS }}.tar.gz
./kubescape/kubescape.exe
./checksums.sha256
./kubescape-${{ env.MAC_OS }}
./kubescape-${{ env.MAC_OS }}.sbom
./kubescape-${{ env.MAC_OS }}.tar.gz
./kubescape-${{ env.UBUNTU_OS }}
./kubescape-${{ env.UBUNTU_OS }}.sbom
./kubescape-${{ env.UBUNTU_OS }}.tar.gz
./kubescape-${{ env.WINDOWS_OS }}.exe
./kubescape-${{ env.WINDOWS_OS }}.exe.sbom
./kubescape-${{ env.WINDOWS_OS }}.tar.gz
./kubescape-arm64-${{ env.MAC_OS }}
./kubescape-arm64-${{ env.MAC_OS }}.sbom
./kubescape-arm64-${{ env.MAC_OS }}.tar.gz
./kubescape-arm64-${{ env.UBUNTU_OS }}
./kubescape-arm64-${{ env.UBUNTU_OS }}.sbom
./kubescape-arm64-${{ env.UBUNTU_OS }}.tar.gz
./kubescape-arm64-${{ env.WINDOWS_OS }}.exe
./kubescape-arm64-${{ env.WINDOWS_OS }}.exe.sbom
./kubescape-arm64-${{ env.WINDOWS_OS }}.tar.gz
./kubescape-riscv64-${{ env.UBUNTU_OS }}
./kubescape-riscv64-${{ env.UBUNTU_OS }}.sbom
./kubescape-riscv64-${{ env.UBUNTU_OS }}.tar.gz
./kubescape.exe

View File

@@ -63,22 +63,21 @@ jobs:
with:
submodules: recursive
- name: Set up QEMU
uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # ratchet:docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f03ac48505955848960e80bbb68046aa35c7b9e7 # ratchet:docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to Quay.io
env:
QUAY_PASSWORD: ${{ secrets.QUAYIO_REGISTRY_PASSWORD }}
QUAY_USERNAME: ${{ secrets.QUAYIO_REGISTRY_USERNAME }}
run: docker login -u="${QUAY_USERNAME}" -p="${QUAY_PASSWORD}" quay.io
- uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # ratchet:actions/download-artifact@v3.0.2
- uses: actions/download-artifact@v4
id: download-artifact
with:
name: kubescape
path: .
- name: mv kubescape amd64 binary
run: mv ${{steps.download-artifact.outputs.download-path}}/kubescape/kubescape-ubuntu-latest kubescape-amd64-ubuntu-latest
- name: mv kubescape arm64 binary
run: mv ${{steps.download-artifact.outputs.download-path}}/kubescape/kubescape-arm64-ubuntu-latest kubescape-arm64-ubuntu-latest
run: mv kubescape-ubuntu-latest kubescape-amd64-ubuntu-latest
- name: chmod +x
run: chmod +x -v kubescape-a*
- name: Build and push images
@@ -106,4 +105,3 @@ jobs:
# Verify the image
echo "$COSIGN_PUBLIC_KEY" > cosign.pub
cosign verify -key cosign.pub ${{ inputs.image_name }}:${{ inputs.image_tag }}

View File

@@ -32,12 +32,12 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
uses: actions/checkout@v4
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
uses: ossf/scorecard-action@v2.4.0
with:
results_file: results.sarif
results_format: sarif
@@ -59,7 +59,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@3cea5372237819ed00197afe530f5a7ea3e805c8 # v3.1.0
uses: actions/upload-artifact@v4
with:
name: SARIF file
path: results.sarif
@@ -67,6 +67,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@17573ee1cc1b9d061760f3a006fc4aac4f944fd5 # v2.2.4
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif

View File

@@ -7,14 +7,14 @@ jobs:
if: github.event.label.name == 'typo'
runs-on: ubuntu-latest
steps:
- uses: ben-z/actions-comment-on-issue@10be23f9c43ac792663043420fda29dde07e2f0f # ratchet:ben-z/actions-comment-on-issue@1.0.2
- uses: ben-z/actions-comment-on-issue@1.0.2
with:
message: "Hello! :wave:\n\nThis issue is being automatically closed, Please open a PR with a relevant fix."
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
auto_close_issues:
runs-on: ubuntu-latest
steps:
- uses: lee-dohm/close-matching-issues@e9e43aad2fa6f06a058cedfd8fb975fd93b56d8f # ratchet:lee-dohm/close-matching-issues@v2
- uses: lee-dohm/close-matching-issues@v2
with:
query: 'label:typo'
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,16 +1,29 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
# The lines bellow are called `modelines`. See `:help modeline`
# The lines below are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/need to use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
version: 2
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
archives:
- id: binaries
formats:
- binary
name_template: >-
{{ .Binary }}
- id: default
formats:
- tar.gz
name_template: >-
{{ .Binary }}
builds:
- goos:
- linux
@@ -33,15 +46,6 @@ builds:
{{- else }}{{ .Os }}{{ end }}-latest
no_unique_dist_dir: true
archives:
- format: binary
id: binaries
name_template: >-
{{ .Binary }}
- format: tar.gz
name_template: >-
{{ .Binary }}
changelog:
sort: asc
filters:
@@ -50,9 +54,7 @@ changelog:
- "^test:"
checksum:
ids:
- binaries
split: true
name_template: "checksums.sha256"
sboms:
- artifacts: binary

View File

@@ -3,7 +3,7 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/kubescape/kubescape)](https://goreportcard.com/report/github.com/kubescape/kubescape)
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/kubescape/kubescape)
[![GitHub](https://img.shields.io/github/license/kubescape/kubescape)](https://github.com/kubescape/kubescape/blob/master/LICENSE)
[![CNCF](https://shields.io/badge/CNCF-Sandbox%20project-blue?logo=linux-foundation&style=flat)](https://landscape.cncf.io/card-mode?project=sandbox&selected=kubescape)
[![CNCF](https://shields.io/badge/CNCF-Incubating%20project-blue?logo=linux-foundation&style=flat)](https://landscape.cncf.io/?item=provisioning--security-compliance--kubescape)
[![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/kubescape)](https://artifacthub.io/packages/search?repo=kubescape)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fkubescape%2Fkubescape.svg?type=shield&issueType=license)](https://app.fossa.com/projects/git%2Bgithub.com%2Fkubescape%2Fkubescape?ref=badge_shield&issueType=license)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/6944/badge)](https://www.bestpractices.dev/projects/6944)
@@ -26,7 +26,7 @@ Kubescape is an open-source Kubernetes security platform that provides comprehen
Kubescape scans clusters, YAML files, and Helm charts. It detects misconfigurations according to multiple frameworks (including [NSA-CISA](https://www.armosec.io/blog/kubernetes-hardening-guidance-summary-by-armo/?utm_source=github&utm_medium=repository), [MITRE ATT&CK®](https://www.armosec.io/glossary/mitre-attck-framework/?utm_source=github&utm_medium=repository) and the [CIS Benchmark](https://www.armosec.io/blog/cis-kubernetes-benchmark-framework-scanning-tools-comparison/?utm_source=github&utm_medium=repository)).
Kubescape was created by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository) and is a [Cloud Native Computing Foundation (CNCF) sandbox project](https://www.cncf.io/sandbox-projects/).
Kubescape was created by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository) and is a [Cloud Native Computing Foundation (CNCF) incubating project](https://www.cncf.io/projects/).
_Please [star ⭐](https://github.com/kubescape/kubescape/stargazers) the repo if you want us to continue developing and improving Kubescape! 😀_
@@ -112,10 +112,10 @@ Kubescape changes are tracked on the [release](https://github.com/kubescape/kube
## License
Copyright 2021-2024, the Kubescape Authors. All rights reserved. Kubescape is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
Copyright 2021-2025, the Kubescape Authors. All rights reserved. Kubescape is released under the Apache 2.0 license. See the [LICENSE](LICENSE) file for details.
Kubescape is a [Cloud Native Computing Foundation (CNCF) sandbox project](https://www.cncf.io/sandbox-projects/) and was contributed by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository).
Kubescape is a [Cloud Native Computing Foundation (CNCF) incubating project](https://www.cncf.io/projects/kubescape/) and was contributed by [ARMO](https://www.armosec.io/?utm_source=github&utm_medium=repository).
<div align="center">
<img src="https://raw.githubusercontent.com/cncf/artwork/master/other/cncf-sandbox/horizontal/color/cncf-sandbox-horizontal-color.svg" width="300" alt="CNCF Sandbox Project">
<img src="https://raw.githubusercontent.com/cncf/artwork/refs/heads/main/other/cncf-member/incubating/color/cncf-incubating-color.svg" width="300" alt="CNCF Incubating Project">
</div>

View File

@@ -1,8 +1,6 @@
package config
import (
"context"
"github.com/kubescape/go-logger"
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
@@ -15,7 +13,7 @@ func getDeleteCmd(ks meta.IKubescape) *cobra.Command {
Short: "Delete cached configurations",
Long: ``,
Run: func(cmd *cobra.Command, args []string) {
if err := ks.DeleteCachedConfig(context.TODO(), &v1.DeleteConfig{}); err != nil {
if err := ks.DeleteCachedConfig(&v1.DeleteConfig{}); err != nil {
logger.L().Fatal(err.Error())
}
},

View File

@@ -1,9 +1,9 @@
package download
import (
"context"
"fmt"
"path/filepath"
"slices"
"strings"
"github.com/kubescape/go-logger"
@@ -12,7 +12,6 @@ import (
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"
"golang.org/x/exp/slices"
)
var (
@@ -74,11 +73,9 @@ func GetDownloadCmd(ks meta.IKubescape) *cobra.Command {
downloadInfo.Target = args[0]
if len(args) >= 2 {
downloadInfo.Identifier = args[1]
}
if err := ks.Download(context.TODO(), &downloadInfo); err != nil {
if err := ks.Download(&downloadInfo); err != nil {
logger.L().Fatal(err.Error())
}
return nil

View File

@@ -1,7 +1,6 @@
package fix
import (
"context"
"errors"
"fmt"
@@ -35,7 +34,7 @@ func GetFixCmd(ks meta.IKubescape) *cobra.Command {
}
fixInfo.ReportFile = args[0]
return ks.Fix(context.TODO(), &fixInfo)
return ks.Fix(&fixInfo)
},
}

View File

@@ -1,9 +1,9 @@
package list
import (
"context"
"errors"
"fmt"
"slices"
"strings"
"github.com/kubescape/go-logger"
@@ -12,7 +12,6 @@ import (
"github.com/kubescape/kubescape/v3/core/meta"
v1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/spf13/cobra"
"golang.org/x/exp/slices"
)
var (
@@ -62,7 +61,7 @@ func GetListCmd(ks meta.IKubescape) *cobra.Command {
listPolicies.Target = args[0]
if err := ks.List(context.TODO(), &listPolicies); err != nil {
if err := ks.List(&listPolicies); err != nil {
logger.L().Fatal(err.Error())
}
return nil

466
cmd/mcpserver/mcpserver.go Normal file
View File

@@ -0,0 +1,466 @@
package mcpserver
import (
"context"
"encoding/json"
"fmt"
"log"
"strings"
"time"
"github.com/kubescape/go-logger"
helpersv1 "github.com/kubescape/k8s-interface/instanceidhandler/v1/helpers"
"github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
spdxv1beta1 "github.com/kubescape/storage/pkg/generated/clientset/versioned/typed/softwarecomposition/v1beta1"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type KubescapeMcpserver struct {
s *server.MCPServer
ksClient spdxv1beta1.SpdxV1beta1Interface
}
func createVulnerabilityToolsAndResources(ksServer *KubescapeMcpserver) {
// Tool to list vulnerability manifests
listManifestsTool := mcp.NewTool(
"list_vulnerability_manifests",
mcp.WithDescription("Discover available vulnerability manifests at image and workload levels"),
mcp.WithString("namespace",
mcp.Description("Filter by namespace (optional)"),
),
mcp.WithString("level",
mcp.Description("Type of vulnerability manifests to list"),
mcp.Enum("image", "workload", "both"),
),
)
ksServer.s.AddTool(listManifestsTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return ksServer.CallTool("list_vulnerability_manifests", request.Params.Arguments.(map[string]interface{}))
})
listVulnerabilitiesTool := mcp.NewTool(
"list_vulnerabilities_in_manifest",
mcp.WithDescription("List all vulnerabilities in a given manifest"),
mcp.WithString("namespace",
mcp.Description("Filter by namespace (optional)"),
),
mcp.WithString("manifest_name",
mcp.Required(),
mcp.Description("Name of the manifest to list vulnerabilities from"),
),
)
ksServer.s.AddTool(listVulnerabilitiesTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return ksServer.CallTool("list_vulnerabilities_in_manifest", request.Params.Arguments.(map[string]interface{}))
})
listVulnerabilityMatchesForCVE := mcp.NewTool(
"list_vulnerability_matches_for_cve",
mcp.WithDescription("List all vulnerability matches for a given CVE in a given manifest"),
mcp.WithString("namespace",
mcp.Description("Filter by namespace (optional)"),
),
mcp.WithString("manifest_name",
mcp.Required(),
mcp.Description("Name of the manifest to list vulnerabilities from"),
),
mcp.WithString("cve_id",
mcp.Required(),
mcp.Description("ID of the CVE to list matches for"),
),
)
ksServer.s.AddTool(listVulnerabilityMatchesForCVE, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return ksServer.CallTool("list_vulnerability_matches_for_cve", request.Params.Arguments.(map[string]interface{}))
})
vulnerabilityManifestTemplate := mcp.NewResourceTemplate(
"kubescape://vulnerability-manifests/{namespace}/{manifest_name}",
"Vulnerability Manifest",
mcp.WithTemplateDescription("Complete vulnerability manifest either for a specific workload or image. Use 'list_vulnerability_manifests' tool to discover available manifests."),
mcp.WithTemplateMIMEType("application/json"),
)
ksServer.s.AddResourceTemplate(vulnerabilityManifestTemplate, ksServer.ReadResource)
}
func createConfigurationsToolsAndResources(ksServer *KubescapeMcpserver) {
// Tool to list configuration manifests
listConfigsTool := mcp.NewTool(
"list_configuration_security_scan_manifests",
mcp.WithDescription("Discover available security configuration scan results at workload level (this returns a list of manifests, not the scan results themselves, to get the scan results, use the get_configuration_security_scan_manifest tool)"),
mcp.WithString("namespace",
mcp.Description("Filter by namespace (optional)"),
),
)
ksServer.s.AddTool(listConfigsTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return ksServer.CallTool("list_configuration_security_scan_manifests", request.Params.Arguments.(map[string]interface{}))
})
getConfigDetailsTool := mcp.NewTool(
"get_configuration_security_scan_manifest",
mcp.WithDescription("Get details of a specific security configuration scan result"),
mcp.WithString("namespace",
mcp.Description("Namespace of the manifest (optional, defaults to 'kubescape')"),
),
mcp.WithString("manifest_name",
mcp.Required(),
mcp.Description("Name of the configuration manifest to get details for (get this from the list_configuration_security_scan_manifests tool)"),
),
)
ksServer.s.AddTool(getConfigDetailsTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
return ksServer.CallTool("get_configuration_security_scan_manifest", request.Params.Arguments.(map[string]interface{}))
})
configManifestTemplate := mcp.NewResourceTemplate(
"kubescape://configuration-manifests/{namespace}/{manifest_name}",
"Configuration Security Scan Manifest",
mcp.WithTemplateDescription("Complete configuration scan manifest for a specific workload. Use 'list_configuration_security_scan_manifests' tool to discover available manifests."),
mcp.WithTemplateMIMEType("application/json"),
)
ksServer.s.AddResourceTemplate(configManifestTemplate, ksServer.ReadConfigurationResource)
}
func (ksServer *KubescapeMcpserver) ReadResource(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
uri := request.Params.URI
// Validate the URI and check if it starts with kubescape://vulnerability-manifests/
if !strings.HasPrefix(uri, "kubescape://vulnerability-manifests/") {
return nil, fmt.Errorf("invalid URI: %s", uri)
}
// Verify that the URI is either the CVE list or CVE details
if !strings.HasSuffix(uri, "/cve_list") && !strings.Contains(uri, "/cve_details/") {
return nil, fmt.Errorf("invalid URI: %s", uri)
}
// Split the URI into namespace and manifest name
parts := strings.Split(uri, "/")
if len(parts) != 4 && len(parts) != 5 {
return nil, fmt.Errorf("invalid URI: %s", uri)
}
namespace := parts[1]
manifestName := parts[2]
cveID := ""
if len(parts) == 5 {
cveID = parts[3]
}
// Get the vulnerability manifest
manifest, err := ksServer.ksClient.VulnerabilityManifests(namespace).Get(ctx, manifestName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get vulnerability manifest: %s", err)
}
var responseJson []byte
if cveID == "" {
// CVE list
var cveList []v1beta1.Vulnerability
for _, match := range manifest.Spec.Payload.Matches {
cveList = append(cveList, match.Vulnerability)
}
responseJson, err = json.Marshal(cveList)
if err != nil {
return nil, fmt.Errorf("failed to marshal cve list: %s", err)
}
} else {
// CVE details
var match []v1beta1.Match
for _, m := range manifest.Spec.Payload.Matches {
if m.Vulnerability.ID == cveID {
match = append(match, m)
}
}
responseJson, err = json.Marshal(match)
if err != nil {
return nil, fmt.Errorf("failed to marshal cve details: %s", err)
}
}
return []mcp.ResourceContents{mcp.TextResourceContents{
URI: uri,
Text: string(responseJson),
}}, nil
}
func (ksServer *KubescapeMcpserver) ReadConfigurationResource(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
uri := request.Params.URI
if !strings.HasPrefix(uri, "kubescape://configuration-manifests/") {
return nil, fmt.Errorf("invalid URI: %s", uri)
}
parts := strings.Split(uri[len("kubescape://configuration-manifests/"):], "/")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid URI: %s", uri)
}
namespace := parts[0]
manifestName := parts[1]
manifest, err := ksServer.ksClient.WorkloadConfigurationScans(namespace).Get(ctx, manifestName, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get configuration manifest: %s", err)
}
responseJson, err := json.Marshal(manifest)
if err != nil {
return nil, fmt.Errorf("failed to marshal configuration manifest: %s", err)
}
return []mcp.ResourceContents{mcp.TextResourceContents{
URI: uri,
Text: string(responseJson),
}}, nil
}
func (ksServer *KubescapeMcpserver) CallTool(name string, arguments map[string]interface{}) (*mcp.CallToolResult, error) {
switch name {
case "list_vulnerability_manifests":
//namespace, ok := arguments["namespace"]
//if !ok {
// namespace = ""
//}
level, ok := arguments["level"]
if !ok {
level = "both"
}
result := map[string]interface{}{
"vulnerability_manifests": map[string]interface{}{},
}
// Get workload-level manifests
labelSelector := ""
if level == "workload" {
labelSelector = "kubescape.io/context=filtered"
} else if level == "image" {
labelSelector = "kubescape.io/context=non-filtered"
}
var manifests *v1beta1.VulnerabilityManifestList
var err error
if labelSelector == "" {
manifests, err = ksServer.ksClient.VulnerabilityManifests(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{})
} else {
manifests, err = ksServer.ksClient.VulnerabilityManifests(metav1.NamespaceAll).List(context.Background(), metav1.ListOptions{
LabelSelector: labelSelector,
})
}
if err != nil {
return nil, err
}
log.Printf("Found %d manifests", len(manifests.Items))
vulnerabilityManifests := []map[string]interface{}{}
for _, manifest := range manifests.Items {
isImageLevel := manifest.Annotations[helpersv1.WlidMetadataKey] == ""
manifestMap := map[string]interface{}{
"type": "workload",
"namespace": manifest.Namespace,
"manifest_name": manifest.Name,
"image-level": isImageLevel,
"workload-level": !isImageLevel,
"image-id": manifest.Annotations[helpersv1.ImageIDMetadataKey],
"image-tag": manifest.Annotations[helpersv1.ImageTagMetadataKey],
"workload-id": manifest.Annotations[helpersv1.WlidMetadataKey],
"workload-container-name": manifest.Annotations[helpersv1.ContainerNameMetadataKey],
"resource_uri": fmt.Sprintf("kubescape://vulnerability-manifests/%s/%s",
manifest.Namespace, manifest.Name),
}
vulnerabilityManifests = append(vulnerabilityManifests, manifestMap)
}
result["vulnerability_manifests"].(map[string]interface{})["manifests"] = vulnerabilityManifests
// Add template information
result["available_templates"] = map[string]string{
"vulnerability_manifest_cve_list": "kubescape://vulnerability-manifests/{namespace}/{manifest_name}/cve_list",
"vulnerability_manifest_cve_details": "kubescape://vulnerability-manifests/{namespace}/{manifest_name}/cve_details/{cve_id}",
}
content, _ := json.Marshal(result)
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.TextContent{
Type: "text",
Text: string(content),
},
},
}, nil
case "list_vulnerabilities_in_manifest":
namespace, ok := arguments["namespace"]
if !ok {
namespace = "kubescape"
}
manifestName, ok := arguments["manifest_name"]
if !ok {
return nil, fmt.Errorf("manifest_name is required")
}
manifest, err := ksServer.ksClient.VulnerabilityManifests(namespace.(string)).Get(context.Background(), manifestName.(string), metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get vulnerability manifest: %s", err)
}
var cveList []v1beta1.Vulnerability
for _, match := range manifest.Spec.Payload.Matches {
cveList = append(cveList, match.Vulnerability)
}
responseJson, err := json.Marshal(cveList)
if err != nil {
return nil, fmt.Errorf("failed to marshal cve list: %s", err)
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.TextContent{
Type: "text",
Text: string(responseJson),
},
},
}, nil
case "list_vulnerability_matches_for_cve":
namespace, ok := arguments["namespace"]
if !ok {
namespace = "kubescape"
}
manifestName, ok := arguments["manifest_name"]
if !ok {
return nil, fmt.Errorf("manifest_name is required")
}
cveID, ok := arguments["cve_id"]
if !ok {
return nil, fmt.Errorf("cve_id is required")
}
manifest, err := ksServer.ksClient.VulnerabilityManifests(namespace.(string)).Get(context.Background(), manifestName.(string), metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get vulnerability manifest: %s", err)
}
var match []v1beta1.Match
for _, m := range manifest.Spec.Payload.Matches {
if m.Vulnerability.ID == cveID.(string) {
match = append(match, m)
}
}
responseJson, err := json.Marshal(match)
if err != nil {
return nil, fmt.Errorf("failed to marshal cve details: %s", err)
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.TextContent{
Type: "text",
Text: string(responseJson),
},
},
}, nil
case "list_configuration_security_scan_manifests":
namespace, ok := arguments["namespace"]
if !ok {
namespace = "kubescape"
}
manifests, err := ksServer.ksClient.WorkloadConfigurationScans(namespace.(string)).List(context.Background(), metav1.ListOptions{})
if err != nil {
return nil, err
}
log.Printf("Found %d configuration manifests", len(manifests.Items))
configManifests := []map[string]interface{}{}
for _, manifest := range manifests.Items {
item := map[string]interface{}{
"namespace": manifest.Namespace,
"manifest_name": manifest.Name,
"resource_uri": fmt.Sprintf("kubescape://configuration-manifests/%s/%s", manifest.Namespace, manifest.Name),
}
configManifests = append(configManifests, item)
}
result := map[string]interface{}{
"configuration_manifests": map[string]interface{}{
"manifests": configManifests,
},
"available_templates": map[string]string{
"configuration_manifest_details": "kubescape://configuration-manifests/{namespace}/{manifest_name}",
},
}
content, _ := json.Marshal(result)
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.TextContent{
Type: "text",
Text: string(content),
},
},
}, nil
case "get_configuration_security_scan_manifest":
namespace, ok := arguments["namespace"]
if !ok {
namespace = "kubescape"
}
manifestName, ok := arguments["manifest_name"]
if !ok {
return nil, fmt.Errorf("manifest_name is required")
}
manifest, err := ksServer.ksClient.WorkloadConfigurationScans(namespace.(string)).Get(context.Background(), manifestName.(string), metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get configuration manifest: %s", err)
}
responseJson, err := json.Marshal(manifest)
if err != nil {
return nil, fmt.Errorf("failed to marshal configuration manifest: %s", err)
}
return &mcp.CallToolResult{
Content: []mcp.Content{
mcp.TextContent{
Type: "text",
Text: string(responseJson),
},
},
}, nil
default:
return nil, fmt.Errorf("unknown tool: %s", name)
}
}
func mcpServerEntrypoint() error {
logger.L().Info("Starting MCP server...")
// Create a kubernetes client and verify it's working
client, err := CreateKsObjectConnection("default", 10*time.Second)
if err != nil {
return fmt.Errorf("failed to create kubernetes client: %v", err)
}
// Create a new MCP server
s := server.NewMCPServer(
"Kubescape MCP Server",
"0.0.1",
server.WithToolCapabilities(false),
server.WithRecovery(),
)
ksServer := &KubescapeMcpserver{
s: s,
ksClient: client,
}
// Creating Kubescape tools and resources
createVulnerabilityToolsAndResources(ksServer)
createConfigurationsToolsAndResources(ksServer)
// Start the server
if err := server.ServeStdio(s); err != nil {
return fmt.Errorf("Server error: %v\n", err)
}
return nil
}
func GetMCPServerCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "mcpserver",
Short: "Start the Kubescape MCP server",
Long: `Start the Kubescape MCP server`,
RunE: func(cmd *cobra.Command, args []string) error {
return mcpServerEntrypoint()
},
}
return cmd
}

14
cmd/mcpserver/storage.go Normal file
View File

@@ -0,0 +1,14 @@
package mcpserver
import (
"time"
"github.com/kubescape/kubescape/v3/pkg/ksinit"
spdxv1beta1 "github.com/kubescape/storage/pkg/generated/clientset/versioned/typed/softwarecomposition/v1beta1"
)
// CreateKsObjectConnection delegates to the shared ksinit package
func CreateKsObjectConnection(namespace string, maxElapsedTime time.Duration) (spdxv1beta1.SpdxV1beta1Interface, error) {
return ksinit.CreateKsObjectConnection(namespace, maxElapsedTime)
}

View File

@@ -1,7 +1,6 @@
package patch
import (
"context"
"errors"
"fmt"
"strings"
@@ -50,7 +49,7 @@ func GetPatchCmd(ks meta.IKubescape) *cobra.Command {
return err
}
results, err := ks.Patch(context.Background(), &patchInfo, &scanInfo)
results, err := ks.Patch(&patchInfo, &scanInfo)
if err != nil {
return err
}

View File

@@ -3,6 +3,8 @@ package patch
import (
"testing"
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
"github.com/kubescape/kubescape/v3/core/mocks"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
@@ -50,3 +52,18 @@ func TestGetPatchCmdWithNonExistentImage(t *testing.T) {
assert.Error(t, err)
assert.Equal(t, expectedErrorMessage, err.Error())
}
func Test_validateImagePatchInfo_EmptyImage(t *testing.T) {
patchInfo := &metav1.PatchInfo{}
err := validateImagePatchInfo(patchInfo)
assert.NotNil(t, err)
assert.Equal(t, "image tag is required", err.Error())
}
func Test_validateImagePatchInfo_Image(t *testing.T) {
patchInfo := &metav1.PatchInfo{
Image: "testing",
}
err := validateImagePatchInfo(patchInfo)
assert.Nil(t, err)
}

View File

@@ -0,0 +1,51 @@
package prerequisites
import (
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/kubescape/sizing-checker/pkg/checks/connectivitycheck"
"github.com/kubescape/sizing-checker/pkg/checks/ebpfcheck"
"github.com/kubescape/sizing-checker/pkg/checks/pvcheck"
"github.com/kubescape/sizing-checker/pkg/checks/sizing"
"github.com/kubescape/sizing-checker/pkg/common"
"github.com/spf13/cobra"
)
func GetPreReqCmd(ks meta.IKubescape) *cobra.Command {
var kubeconfigPath *string
// preReqCmd represents the prerequisites command
preReqCmd := &cobra.Command{
Use: "prerequisites",
Short: "Check prerequisites for installing Kubescape Operator",
Run: func(cmd *cobra.Command, args []string) {
clientSet, inCluster := common.BuildKubeClient(*kubeconfigPath)
if clientSet == nil {
logger.L().Fatal("Could not create kube client. Exiting.")
}
// 1) Collect cluster data
clusterData, err := common.CollectClusterData(ks.Context(), clientSet)
if err != nil {
logger.L().Error("Failed to collect cluster data", helpers.Error(err))
}
// 2) Run checks
sizingResult := sizing.RunSizingChecker(clusterData)
pvResult := pvcheck.RunPVProvisioningCheck(ks.Context(), clientSet, clusterData, inCluster)
connectivityResult := connectivitycheck.RunConnectivityChecks(ks.Context(), clientSet, clusterData, inCluster)
ebpfResult := ebpfcheck.RunEbpfCheck(ks.Context(), clientSet, clusterData, inCluster)
// 3) Build and export the final ReportData
finalReport := common.BuildReportData(clusterData, sizingResult, pvResult, connectivityResult, ebpfResult)
finalReport.InCluster = inCluster
common.GenerateOutput(finalReport, inCluster)
},
}
kubeconfigPath = preReqCmd.PersistentFlags().String("kubeconfig", "", "Path to the kubeconfig file. If not set, in-cluster config is used or $HOME/.kube/config if outside a cluster.")
return preReqCmd
}

View File

@@ -1,6 +1,7 @@
package cmd
import (
"context"
"fmt"
"strings"
@@ -12,8 +13,10 @@ import (
"github.com/kubescape/kubescape/v3/cmd/download"
"github.com/kubescape/kubescape/v3/cmd/fix"
"github.com/kubescape/kubescape/v3/cmd/list"
"github.com/kubescape/kubescape/v3/cmd/mcpserver"
"github.com/kubescape/kubescape/v3/cmd/operator"
"github.com/kubescape/kubescape/v3/cmd/patch"
"github.com/kubescape/kubescape/v3/cmd/prerequisites"
"github.com/kubescape/kubescape/v3/cmd/scan"
"github.com/kubescape/kubescape/v3/cmd/update"
"github.com/kubescape/kubescape/v3/cmd/vap"
@@ -41,8 +44,8 @@ var ksExamples = fmt.Sprintf(`
%[1]s config view
`, cautils.ExecName())
func NewDefaultKubescapeCommand() *cobra.Command {
ks := core.NewKubescape()
func NewDefaultKubescapeCommand(ctx context.Context) *cobra.Command {
ks := core.NewKubescape(ctx)
return getRootCmd(ks)
}
@@ -83,8 +86,6 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
rootCmd.PersistentFlags().StringVarP(&rootInfo.Logger, "logger", "l", helpers.InfoLevel.String(), fmt.Sprintf("Logger level. Supported: %s [$KS_LOGGER]", strings.Join(helpers.SupportedLevels(), "/")))
rootCmd.PersistentFlags().StringVar(&rootInfo.CacheDir, "cache-dir", getter.DefaultLocalStore, "Cache directory [$KS_CACHE_DIR]")
rootCmd.PersistentFlags().BoolVarP(&rootInfo.DisableColor, "disable-color", "", false, "Disable color output for logging")
rootCmd.PersistentFlags().BoolVarP(&rootInfo.EnableColor, "enable-color", "", false, "Force enable color output for logging")
rootCmd.PersistentFlags().StringVarP(&rootInfo.KubeContext, "kube-context", "", "", "Kube context. Default will use the current-context")
// Supported commands
@@ -92,13 +93,15 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
rootCmd.AddCommand(download.GetDownloadCmd(ks))
rootCmd.AddCommand(list.GetListCmd(ks))
rootCmd.AddCommand(completion.GetCompletionCmd())
rootCmd.AddCommand(version.GetVersionCmd())
rootCmd.AddCommand(version.GetVersionCmd(ks))
rootCmd.AddCommand(config.GetConfigCmd(ks))
rootCmd.AddCommand(update.GetUpdateCmd())
rootCmd.AddCommand(update.GetUpdateCmd(ks))
rootCmd.AddCommand(fix.GetFixCmd(ks))
rootCmd.AddCommand(patch.GetPatchCmd(ks))
rootCmd.AddCommand(vap.GetVapHelperCmd())
rootCmd.AddCommand(operator.GetOperatorCmd(ks))
rootCmd.AddCommand(prerequisites.GetPreReqCmd(ks))
rootCmd.AddCommand(mcpserver.GetMCPServerCmd())
// deprecated commands
rootCmd.AddCommand(&cobra.Command{
@@ -113,7 +116,7 @@ func getRootCmd(ks meta.IKubescape) *cobra.Command {
return rootCmd
}
func Execute() error {
ks := NewDefaultKubescapeCommand()
func Execute(ctx context.Context) error {
ks := NewDefaultKubescapeCommand(ctx)
return ks.Execute()
}

24
cmd/root_test.go Normal file
View File

@@ -0,0 +1,24 @@
package cmd
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
)
func TestNewDefaultKubescapeCommand(t *testing.T) {
t.Run("NewDefaultKubescapeCommand", func(t *testing.T) {
cmd := NewDefaultKubescapeCommand(context.Background())
assert.NotNil(t, cmd)
})
}
func TestExecute(t *testing.T) {
t.Run("Execute", func(t *testing.T) {
err := Execute(context.Background())
if err != nil {
assert.EqualErrorf(t, err, "unknown command \"^\\\\QTestExecute\\\\E$\" for \"kubescape\"", err.Error())
}
})
}

View File

@@ -18,9 +18,6 @@ import (
)
func initLogger() {
logger.DisableColor(rootInfo.DisableColor)
logger.EnableColor(rootInfo.EnableColor)
if rootInfo.LoggerName == "" {
if l := os.Getenv("KS_LOGGER_NAME"); l != "" {
rootInfo.LoggerName = l
@@ -34,8 +31,8 @@ func initLogger() {
}
logger.InitLogger(rootInfo.LoggerName)
}
func initLoggerLevel() {
if rootInfo.Logger == helpers.InfoLevel.String() {
} else if l := os.Getenv("KS_LOGGER"); l != "" {

View File

@@ -1,7 +1,6 @@
package scan
import (
"context"
"fmt"
"io"
"os"
@@ -96,12 +95,11 @@ func getControlCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comman
return err
}
ctx := context.TODO()
results, err := ks.Scan(ctx, scanInfo)
results, err := ks.Scan(scanInfo)
if err != nil {
logger.L().Fatal(err.Error())
}
if err := results.HandleResults(ctx); err != nil {
if err := results.HandleResults(ks.Context()); err != nil {
logger.L().Fatal(err.Error())
}
if !scanInfo.VerboseMode {

View File

@@ -1,11 +1,11 @@
package scan
import (
"context"
"errors"
"fmt"
"io"
"os"
"slices"
"strings"
"github.com/kubescape/go-logger"
@@ -18,7 +18,6 @@ import (
reporthandlingapis "github.com/kubescape/opa-utils/reporthandling/apis"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
"github.com/spf13/cobra"
"golang.org/x/exp/slices"
)
var (
@@ -113,13 +112,12 @@ func getFrameworkCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comm
scanInfo.SetPolicyIdentifiers(frameworks, apisv1.KindFramework)
ctx := context.TODO()
results, err := ks.Scan(ctx, scanInfo)
results, err := ks.Scan(scanInfo)
if err != nil {
logger.L().Fatal(err.Error())
}
if err = results.HandleResults(ctx); err != nil {
if err = results.HandleResults(ks.Context()); err != nil {
logger.L().Fatal(err.Error())
}

View File

@@ -1,7 +1,6 @@
package scan
import (
"context"
"fmt"
"github.com/kubescape/go-logger"
@@ -24,12 +23,17 @@ var (
# Scan the 'nginx' image and see the full report
%[1]s scan image "nginx" -v
# Scan the 'nginx' image and use exceptions
%[1]s scan image "nginx" --exceptions exceptions.json
`, cautils.ExecName())
)
// getImageCmd returns the scan image command
func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command {
var imgCredentials shared.ImageCredentials
var exceptions string
cmd := &cobra.Command{
Use: "image <image>:<tag> [flags]",
Short: "Scan an image for vulnerabilities",
@@ -50,12 +54,13 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command
}
imgScanInfo := &metav1.ImageScanInfo{
Image: args[0],
Username: imgCredentials.Username,
Password: imgCredentials.Password,
Image: args[0],
Username: imgCredentials.Username,
Password: imgCredentials.Password,
Exceptions: exceptions,
}
results, err := ks.ScanImage(context.Background(), imgScanInfo, scanInfo)
results, err := ks.ScanImage(imgScanInfo, scanInfo)
if err != nil {
return err
}
@@ -68,6 +73,8 @@ func getImageCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Command
},
}
// The exceptions flag
cmd.PersistentFlags().StringVarP(&exceptions, "exceptions", "", "", "Path to the exceptions file")
cmd.PersistentFlags().StringVarP(&imgCredentials.Username, "username", "u", "", "Username for registry login")
cmd.PersistentFlags().StringVarP(&imgCredentials.Password, "password", "p", "", "Password for registry login")

View File

@@ -1,7 +1,6 @@
package scan
import (
"context"
"flag"
"fmt"
"strings"
@@ -135,15 +134,12 @@ func setSecurityViewScanInfo(args []string, scanInfo *cautils.ScanInfo) {
}
func securityScan(scanInfo cautils.ScanInfo, ks meta.IKubescape) error {
ctx := context.TODO()
results, err := ks.Scan(ctx, &scanInfo)
results, err := ks.Scan(&scanInfo)
if err != nil {
return err
}
if err = results.HandleResults(ctx); err != nil {
if err = results.HandleResults(ks.Context()); err != nil {
return err
}

View File

@@ -1,7 +1,6 @@
package scan
import (
"context"
"errors"
"fmt"
"strings"
@@ -66,13 +65,12 @@ func getWorkloadCmd(ks meta.IKubescape, scanInfo *cautils.ScanInfo) *cobra.Comma
setWorkloadScanInfo(scanInfo, kind, name)
// todo: add api version if provided
ctx := context.TODO()
results, err := ks.Scan(ctx, scanInfo)
results, err := ks.Scan(scanInfo)
if err != nil {
logger.L().Fatal(err.Error())
}
if err = results.HandleResults(ctx); err != nil {
if err = results.HandleResults(ks.Context()); err != nil {
logger.L().Fatal(err.Error())
}

View File

@@ -94,3 +94,17 @@ func TestGetWorkloadCmd_ChartPathAndFilePathEmpty(t *testing.T) {
expectedErrorMessage = "invalid workload identifier"
assert.Equal(t, expectedErrorMessage, err.Error())
}
func Test_parseWorkloadIdentifierString_Empty(t *testing.T) {
t.Run("empty identifier", func(t *testing.T) {
_, _, err := parseWorkloadIdentifierString("")
assert.Error(t, err)
})
}
func Test_parseWorkloadIdentifierString_NoError(t *testing.T) {
t.Run("valid identifier", func(t *testing.T) {
_, _, err := parseWorkloadIdentifierString("default/Deployment")
assert.NoError(t, err)
})
}

View File

@@ -5,10 +5,11 @@ package update
// kubescape update
import (
"context"
"fmt"
"strings"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/kubescape/backend/pkg/versioncheck"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
@@ -25,17 +26,18 @@ var updateCmdExamples = fmt.Sprintf(`
%[1]s update
`, cautils.ExecName())
func GetUpdateCmd() *cobra.Command {
func GetUpdateCmd(ks meta.IKubescape) *cobra.Command {
updateCmd := &cobra.Command{
Use: "update",
Short: "Update to latest release version",
Long: ``,
Example: updateCmdExamples,
RunE: func(_ *cobra.Command, args []string) error {
ctx := context.TODO()
v := versioncheck.NewVersionCheckHandler()
versionCheckRequest := versioncheck.NewVersionCheckRequest("", versioncheck.BuildNumber, "", "", "update", nil)
v.CheckLatestVersion(ctx, versionCheckRequest)
if err := v.CheckLatestVersion(ks.Context(), versionCheckRequest); err != nil {
return err
}
//Checking the user's version of kubescape to the latest release
if versioncheck.BuildNumber == "" || strings.Contains(versioncheck.BuildNumber, "rc") {

18
cmd/update/update_test.go Normal file
View File

@@ -0,0 +1,18 @@
package update
import (
"context"
"testing"
"github.com/kubescape/kubescape/v3/core/core"
"github.com/stretchr/testify/assert"
)
func TestGetUpdateCmd(t *testing.T) {
ks := core.NewKubescape(context.TODO())
cmd := GetUpdateCmd(ks)
assert.NotNil(t, cmd)
err := cmd.RunE(cmd, []string{})
assert.Nil(t, err)
}

View File

@@ -1,23 +1,26 @@
package version
import (
"context"
"fmt"
"github.com/kubescape/kubescape/v3/core/meta"
"github.com/kubescape/backend/pkg/versioncheck"
"github.com/spf13/cobra"
)
func GetVersionCmd() *cobra.Command {
func GetVersionCmd(ks meta.IKubescape) *cobra.Command {
versionCmd := &cobra.Command{
Use: "version",
Short: "Get current version",
Long: ``,
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.TODO()
v := versioncheck.NewIVersionCheckHandler(ctx)
v := versioncheck.NewIVersionCheckHandler(ks.Context())
versionCheckRequest := versioncheck.NewVersionCheckRequest("", versioncheck.BuildNumber, "", "", "version", nil)
v.CheckLatestVersion(ctx, versionCheckRequest)
if err := v.CheckLatestVersion(ks.Context(), versionCheckRequest); err != nil {
return err
}
fmt.Fprintf(cmd.OutOrStdout(),
"Your current version is: %s\n",
versionCheckRequest.ClientVersion,

View File

@@ -2,9 +2,12 @@ package version
import (
"bytes"
"context"
"io"
"testing"
"github.com/kubescape/kubescape/v3/core/core"
"github.com/kubescape/backend/pkg/versioncheck"
"github.com/stretchr/testify/assert"
)
@@ -30,7 +33,8 @@ func TestGetVersionCmd(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
versioncheck.BuildNumber = tt.buildNumber
if cmd := GetVersionCmd(); cmd != nil {
ks := core.NewKubescape(context.TODO())
if cmd := GetVersionCmd(ks); cmd != nil {
buf := bytes.NewBufferString("")
cmd.SetOut(buf)
cmd.Execute()

View File

@@ -7,6 +7,7 @@ import (
"fmt"
"os"
"path/filepath"
"slices"
"strings"
"github.com/kubescape/go-logger"
@@ -14,7 +15,6 @@ import (
"github.com/kubescape/k8s-interface/workloadinterface"
"github.com/kubescape/opa-utils/objectsenvelopes"
"github.com/kubescape/opa-utils/objectsenvelopes/localworkload"
"golang.org/x/exp/slices"
"gopkg.in/yaml.v3"
)

View File

@@ -10,8 +10,6 @@ type RootInfo struct {
Logger string // logger level
LoggerName string // logger name ("pretty"/"zap"/"none")
CacheDir string // cached dir
DisableColor bool // Disable Color
EnableColor bool // Force enable Color
DiscoveryServerURL string // Discovery Server URL (See https://github.com/kubescape/backend/tree/main/pkg/servicediscovery)
KubeContext string // context name
}

View File

@@ -1,7 +1,6 @@
package core
import (
"context"
"fmt"
"github.com/kubescape/kubescape/v3/core/cautils"
@@ -35,8 +34,8 @@ func (ks *Kubescape) ViewCachedConfig(viewConfig *metav1.ViewConfig) error {
return nil
}
func (ks *Kubescape) DeleteCachedConfig(ctx context.Context, deleteConfig *metav1.DeleteConfig) error {
func (ks *Kubescape) DeleteCachedConfig(deleteConfig *metav1.DeleteConfig) error {
tenant := cautils.GetTenantConfig("", "", "", "", nil) // change k8sinterface
return tenant.DeleteCachedConfig(ctx)
return tenant.DeleteCachedConfig(ks.Context())
}

View File

@@ -44,12 +44,12 @@ func DownloadSupportCommands() []string {
return commands
}
func (ks *Kubescape) Download(ctx context.Context, downloadInfo *metav1.DownloadInfo) error {
func (ks *Kubescape) Download(downloadInfo *metav1.DownloadInfo) error {
setPathAndFilename(downloadInfo)
if err := os.MkdirAll(downloadInfo.Path, os.ModePerm); err != nil {
return err
}
if err := downloadArtifact(ctx, downloadInfo, downloadFunc); err != nil {
if err := downloadArtifact(ks.Context(), downloadInfo, downloadFunc); err != nil {
return err
}
return nil

View File

@@ -1,7 +1,6 @@
package core
import (
"context"
"fmt"
"strings"
@@ -16,14 +15,14 @@ const (
confirmationQuestion = "Would you like to apply the changes to the files above? [y|n]: "
)
func (ks *Kubescape) Fix(ctx context.Context, fixInfo *metav1.FixInfo) error {
func (ks *Kubescape) Fix(fixInfo *metav1.FixInfo) error {
logger.L().Info("Reading report file...")
handler, err := fixhandler.NewFixHandler(fixInfo)
if err != nil {
return err
}
resourcesToFix := handler.PrepareResourcesToFix(ctx)
resourcesToFix := handler.PrepareResourcesToFix(ks.Context())
if len(resourcesToFix) == 0 {
logger.L().Info(noResourcesToFix)
@@ -42,12 +41,12 @@ func (ks *Kubescape) Fix(ctx context.Context, fixInfo *metav1.FixInfo) error {
return nil
}
updatedFilesCount, errors := handler.ApplyChanges(ctx, resourcesToFix)
updatedFilesCount, errors := handler.ApplyChanges(ks.Context(), resourcesToFix)
logger.L().Info(fmt.Sprintf("Fixed resources in %d files.", updatedFilesCount))
if len(errors) > 0 {
for _, err := range errors {
logger.L().Ctx(ctx).Warning(err.Error())
logger.L().Ctx(ks.Context()).Warning(err.Error())
}
return fmt.Errorf("Failed to fix some resources, check the logs for more details")
}

View File

@@ -33,10 +33,11 @@ func TestUserConfirmed(t *testing.T) {
for _, tt := range tests {
t.Run(string(tt.input), func(t *testing.T) {
originalStdin := os.Stdin
r, w, _ := os.Pipe()
os.Stdin = r
defer func() {
os.Stdin = os.Stdin
os.Stdin = originalStdin
}()
go func() {

View File

@@ -1,8 +1,11 @@
package core
import (
"context"
"encoding/json"
"fmt"
"os"
"regexp"
"strings"
"github.com/anchore/grype/grype/presenter/models"
"github.com/kubescape/go-logger"
@@ -12,7 +15,153 @@ import (
"github.com/kubescape/kubescape/v3/pkg/imagescan"
)
func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
// Data structure to represent attributes
type Attributes struct {
Registry string `json:"registry"`
Organization string `json:"organization,omitempty"`
ImageName string `json:"imageName"`
ImageTag string `json:"imageTag,omitempty"`
}
// Data structure for a target
type Target struct {
DesignatorType string `json:"designatorType"`
Attributes Attributes `json:"attributes"`
}
// Data structure for metadata
type Metadata struct {
Name string `json:"name"`
}
// Data structure for vulnerabilities and severities
type VulnerabilitiesIgnorePolicy struct {
Metadata Metadata `json:"metadata"`
Kind string `json:"kind"`
Targets []Target `json:"targets"`
Vulnerabilities []string `json:"vulnerabilities"`
Severities []string `json:"severities"`
}
// Loads excpetion policies from exceptions json object.
func GetImageExceptionsFromFile(filePath string) ([]VulnerabilitiesIgnorePolicy, error) {
// Read the JSON file
jsonFile, err := os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("error reading exceptions file: %w", err)
}
// Unmarshal the JSON data into an array of VulnerabilitiesIgnorePolicy
var policies []VulnerabilitiesIgnorePolicy
err = json.Unmarshal(jsonFile, &policies)
if err != nil {
return nil, fmt.Errorf("error unmarshaling exceptions file: %w", err)
}
return policies, nil
}
// This function will identify the registry, organization and image tag from the image name
func getAttributesFromImage(imgName string) (Attributes, error) {
canonicalImageName, err := cautils.NormalizeImageName(imgName)
if err != nil {
return Attributes{}, err
}
tokens := strings.Split(canonicalImageName, "/")
registry := tokens[0]
organization := tokens[1]
imageNameAndTag := strings.Split(tokens[2], ":")
imageName := imageNameAndTag[0]
// Intialize the image tag with default value
imageTag := "latest"
if len(imageNameAndTag) > 1 {
imageTag = imageNameAndTag[1]
}
attributes := Attributes{
Registry: registry,
Organization: organization,
ImageName: imageName,
ImageTag: imageTag,
}
return attributes, nil
}
// Checks if the target string matches the regex pattern
func regexStringMatch(pattern, target string) bool {
re, err := regexp.Compile(pattern)
if err != nil {
logger.L().StopError(fmt.Sprintf("Failed to generate regular expression: %s", err))
return false
}
if re.MatchString(target) {
return true
}
return false
}
// Compares the registry, organization, image name, image tag against the targets specified
// in the exception policy object to check if the image being scanned qualifies for an
// exception policy.
func isTargetImage(targets []Target, attributes Attributes) bool {
for _, target := range targets {
return regexStringMatch(target.Attributes.Registry, attributes.Registry) && regexStringMatch(target.Attributes.Organization, attributes.Organization) && regexStringMatch(target.Attributes.ImageName, attributes.ImageName) && regexStringMatch(target.Attributes.ImageTag, attributes.ImageTag)
}
return false
}
// Generates a list of unique CVE-IDs and the severities which are to be excluded for
// the image being scanned.
func getUniqueVulnerabilitiesAndSeverities(policies []VulnerabilitiesIgnorePolicy, image string) ([]string, []string) {
// Create maps with slices as values to store unique vulnerabilities and severities (case-insensitive)
uniqueVulns := make(map[string][]string)
uniqueSevers := make(map[string][]string)
imageAttributes, err := getAttributesFromImage(image)
if err != nil {
logger.L().StopError(fmt.Sprintf("Failed to generate image attributes: %s", err))
}
// Iterate over each policy and its vulnerabilities/severities
for _, policy := range policies {
// Include the exceptions only if the image is one of the targets
if isTargetImage(policy.Targets, imageAttributes) {
for _, vulnerability := range policy.Vulnerabilities {
// Add to slice directly
vulnerabilityUppercase := strings.ToUpper(vulnerability)
uniqueVulns[vulnerabilityUppercase] = append(uniqueVulns[vulnerabilityUppercase], vulnerability)
}
for _, severity := range policy.Severities {
// Add to slice directly
severityUppercase := strings.ToUpper(severity)
uniqueSevers[severityUppercase] = append(uniqueSevers[severityUppercase], severity)
}
}
}
// Extract unique keys (which are unique vulnerabilities/severities) and their slices
uniqueVulnsList := make([]string, 0, len(uniqueVulns))
for vuln := range uniqueVulns {
uniqueVulnsList = append(uniqueVulnsList, vuln)
}
uniqueSeversList := make([]string, 0, len(uniqueSevers))
for sever := range uniqueSevers {
uniqueSeversList = append(uniqueSeversList, sever)
}
return uniqueVulnsList, uniqueSeversList
}
func (ks *Kubescape) ScanImage(imgScanInfo *ksmetav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
logger.L().Start(fmt.Sprintf("Scanning image %s...", imgScanInfo.Image))
dbCfg, _ := imagescan.NewDefaultDBConfig()
@@ -23,7 +172,19 @@ func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageS
Password: imgScanInfo.Password,
}
scanResults, err := svc.Scan(ctx, imgScanInfo.Image, creds)
var vulnerabilityExceptions []string
var severityExceptions []string
if imgScanInfo.Exceptions != "" {
exceptionPolicies, err := GetImageExceptionsFromFile(imgScanInfo.Exceptions)
if err != nil {
logger.L().StopError(fmt.Sprintf("Failed to load exceptions from file: %s", imgScanInfo.Exceptions))
return nil, err
}
vulnerabilityExceptions, severityExceptions = getUniqueVulnerabilitiesAndSeverities(exceptionPolicies, imgScanInfo.Image)
}
scanResults, err := svc.Scan(ks.Context(), imgScanInfo.Image, creds, vulnerabilityExceptions, severityExceptions)
if err != nil {
logger.L().StopError(fmt.Sprintf("Failed to scan image: %s", imgScanInfo.Image))
return nil, err
@@ -33,9 +194,9 @@ func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageS
scanInfo.SetScanType(cautils.ScanTypeImage)
outputPrinters := GetOutputPrinters(scanInfo, ctx, "")
outputPrinters := GetOutputPrinters(scanInfo, ks.Context(), "")
uiPrinter := GetUIPrinter(ctx, scanInfo, "")
uiPrinter := GetUIPrinter(ks.Context(), scanInfo, "")
resultsHandler := resultshandling.NewResultsHandler(nil, outputPrinters, uiPrinter)
@@ -46,5 +207,5 @@ func (ks *Kubescape) ScanImage(ctx context.Context, imgScanInfo *ksmetav1.ImageS
},
}
return scanResults, resultsHandler.HandleResults(ctx)
return scanResults, resultsHandler.HandleResults(ks.Context())
}

View File

@@ -0,0 +1,420 @@
package core
import (
"sort"
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetImageExceptionsFromFile(t *testing.T) {
tests := []struct {
filePath string
expectedPolicies []VulnerabilitiesIgnorePolicy
expectedErr error
}{
{
filePath: "./testdata/exceptions.json",
expectedPolicies: []VulnerabilitiesIgnorePolicy{
{
Metadata: Metadata{
Name: "medium-severity-vulnerabilites-exceptions",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "docker.io",
Organization: "",
ImageName: "",
ImageTag: "",
},
},
},
Vulnerabilities: []string{},
Severities: []string{"medium"},
},
{
Metadata: Metadata{
Name: "exclude-allowed-hostPath-control",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "",
Organization: "",
ImageName: "",
ImageTag: "",
},
},
},
Vulnerabilities: []string{"CVE-2023-42366", "CVE-2023-42365"},
Severities: []string{"critical", "low"},
},
{
Metadata: Metadata{
Name: "regex-example",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "quay.*",
Organization: "kube*",
ImageName: "kubescape*",
ImageTag: "v2*",
},
},
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "docker.io",
Organization: ".*",
ImageName: "kube*",
ImageTag: "v3*",
},
},
},
Vulnerabilities: []string{"CVE-2023-6879", "CVE-2023-44487"},
Severities: []string{"critical", "low"},
},
},
expectedErr: nil,
},
{
filePath: "./testdata/empty_exceptions.json",
expectedPolicies: []VulnerabilitiesIgnorePolicy{},
expectedErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.filePath, func(t *testing.T) {
policies, err := GetImageExceptionsFromFile(tt.filePath)
assert.Equal(t, tt.expectedPolicies, policies)
assert.Equal(t, tt.expectedErr, err)
})
}
}
func TestGetAttributesFromImage(t *testing.T) {
tests := []struct {
imageName string
expectedAttributes Attributes
expectedErr error
}{
{
imageName: "quay.io/kubescape/kubescape-cli:v3.0.0",
expectedAttributes: Attributes{
Registry: "quay.io",
Organization: "kubescape",
ImageName: "kubescape-cli",
ImageTag: "v3.0.0",
},
expectedErr: nil,
},
{
imageName: "alpine",
expectedAttributes: Attributes{
Registry: "docker.io",
Organization: "library",
ImageName: "alpine",
ImageTag: "latest",
},
expectedErr: nil,
},
}
for _, tt := range tests {
t.Run(tt.imageName, func(t *testing.T) {
attributes, err := getAttributesFromImage(tt.imageName)
assert.Equal(t, tt.expectedErr, err)
assert.Equal(t, tt.expectedAttributes, attributes)
})
}
}
func TestRegexStringMatch(t *testing.T) {
tests := []struct {
pattern string
target string
expected bool
}{
{
pattern: ".*",
target: "quay.io",
expected: true,
},
{
pattern: "kubescape",
target: "kubescape",
expected: true,
},
{
pattern: "kubescape*",
target: "kubescape-cli",
expected: true,
},
{
pattern: "",
target: "v3.0.0",
expected: true,
},
{
pattern: "docker.io",
target: "quay.io",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.target+"/"+tt.pattern, func(t *testing.T) {
assert.Equal(t, tt.expected, regexStringMatch(tt.pattern, tt.target))
})
}
}
func TestIsTargetImage(t *testing.T) {
tests := []struct {
targets []Target
attributes Attributes
expected bool
}{
{
targets: []Target{
{
Attributes: Attributes{
Registry: "docker.io",
Organization: ".*",
ImageName: ".*",
ImageTag: "",
},
},
},
attributes: Attributes{
Registry: "quay.io",
Organization: "kubescape",
ImageName: "kubescape-cli",
ImageTag: "v3.0.0",
},
expected: false,
},
{
targets: []Target{
{
Attributes: Attributes{
Registry: "quay.io",
Organization: "kubescape",
ImageName: "kubescape*",
ImageTag: "",
},
},
},
attributes: Attributes{
Registry: "quay.io",
Organization: "kubescape",
ImageName: "kubescape-cli",
ImageTag: "v3.0.0",
},
expected: true,
},
{
targets: []Target{
{
Attributes: Attributes{
Registry: "docker.io",
Organization: "library",
ImageName: "alpine",
ImageTag: "",
},
},
},
attributes: Attributes{
Registry: "docker.io",
Organization: "library",
ImageName: "alpine",
ImageTag: "latest",
},
expected: true,
},
}
for _, tt := range tests {
t.Run(tt.attributes.Registry+"/"+tt.attributes.ImageName, func(t *testing.T) {
assert.Equal(t, tt.expected, isTargetImage(tt.targets, tt.attributes))
})
}
}
func TestGetVulnerabilitiesAndSeverities(t *testing.T) {
tests := []struct {
policies []VulnerabilitiesIgnorePolicy
image string
expectedVulnerabilities []string
expectedSeverities []string
}{
{
policies: []VulnerabilitiesIgnorePolicy{
{
Metadata: Metadata{
Name: "vulnerabilites-exceptions",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "",
Organization: "kubescape*",
ImageName: "",
ImageTag: "",
},
},
},
Vulnerabilities: []string{"CVE-2023-42365"},
Severities: []string{},
},
{
Metadata: Metadata{
Name: "exclude-allowed-hostPath-control",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "docker.io",
Organization: "",
ImageName: "",
ImageTag: "",
},
},
},
Vulnerabilities: []string{"CVE-2023-42366", "CVE-2023-42365"},
Severities: []string{"critical", "low"},
},
},
image: "quay.io/kubescape/kubescape-cli:v3.0.0",
expectedVulnerabilities: []string{"CVE-2023-42365"},
expectedSeverities: []string{},
},
{
policies: []VulnerabilitiesIgnorePolicy{
{
Metadata: Metadata{
Name: "medium-severity-vulnerabilites-exceptions",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "",
Organization: "",
ImageName: "",
ImageTag: "",
},
},
},
Vulnerabilities: []string{},
Severities: []string{"medium"},
},
{
Metadata: Metadata{
Name: "exclude-allowed-hostPath-control",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "quay.io",
Organization: "",
ImageName: "",
ImageTag: "",
},
},
},
Vulnerabilities: []string{"CVE-2023-42366", "CVE-2023-42365"},
Severities: []string{},
},
},
image: "alpine",
expectedVulnerabilities: []string{},
expectedSeverities: []string{"MEDIUM"},
},
{
policies: []VulnerabilitiesIgnorePolicy{
{
Metadata: Metadata{
Name: "regex-example",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "quay.io",
Organization: "kube*",
ImageName: "kubescape*",
ImageTag: ".*",
},
},
},
Vulnerabilities: []string{},
Severities: []string{"critical"},
},
{
Metadata: Metadata{
Name: "only-for-docker-registry",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
Registry: "docker.io",
ImageTag: "v3*",
},
},
},
Vulnerabilities: []string{"CVE-2023-42366", "CVE-2022-28391"},
Severities: []string{"high"},
},
{
Metadata: Metadata{
Name: "exclude-allowed-hostPath-control",
},
Kind: "VulnerabilitiesIgnorePolicy",
Targets: []Target{
{
DesignatorType: "Attributes",
Attributes: Attributes{
ImageTag: "v3*",
},
},
},
Vulnerabilities: []string{"CVE-2022-30065", "CVE-2022-28391"},
Severities: []string{},
},
},
image: "quay.io/kubescape/kubescape-cli:v3.0.0",
expectedVulnerabilities: []string{"CVE-2022-30065", "CVE-2022-28391"},
expectedSeverities: []string{"CRITICAL"},
},
}
for _, tt := range tests {
t.Run(tt.image, func(t *testing.T) {
vulnerabilities, severities := getUniqueVulnerabilitiesAndSeverities(tt.policies, tt.image)
sort.Strings(tt.expectedVulnerabilities)
sort.Strings(vulnerabilities)
assert.Equal(t, tt.expectedVulnerabilities, vulnerabilities)
assert.Equal(t, tt.expectedSeverities, severities)
})
}
}

View File

@@ -1,7 +1,17 @@
package core
type Kubescape struct{}
import (
"context"
)
func NewKubescape() *Kubescape {
return &Kubescape{}
type Kubescape struct {
Ctx context.Context
}
func (ks *Kubescape) Context() context.Context {
return ks.Ctx
}
func NewKubescape(ctx context.Context) *Kubescape {
return &Kubescape{Ctx: ctx}
}

View File

@@ -1,6 +1,7 @@
package core
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
@@ -8,7 +9,8 @@ import (
// The function should return a non-nil pointer.
func TestNewKubescape_ReturnsNonNilPointer(t *testing.T) {
k := NewKubescape()
ctx := context.TODO()
k := NewKubescape(ctx)
assert.NotNil(t, k)
}
@@ -19,5 +21,6 @@ func TestNewKubescape_DoesNotPanic(t *testing.T) {
t.Errorf("Function panicked: %v", r)
}
}()
NewKubescape()
ctx := context.TODO()
NewKubescape(ctx)
}

View File

@@ -38,16 +38,16 @@ func ListSupportActions() []string {
sort.Strings(commands)
return commands
}
func (ks *Kubescape) List(ctx context.Context, listPolicies *metav1.ListPolicies) error {
func (ks *Kubescape) List(listPolicies *metav1.ListPolicies) error {
if policyListerFunc, ok := listFunc[listPolicies.Target]; ok {
policies, err := policyListerFunc(ctx, listPolicies)
policies, err := policyListerFunc(ks.Context(), listPolicies)
if err != nil {
return err
}
policies = naturalSortPolicies(policies)
if listFormatFunction, ok := listFormatFunc[listPolicies.Format]; ok {
listFormatFunction(ctx, listPolicies.Target, policies)
listFormatFunction(ks.Context(), listPolicies.Target, policies)
} else {
return fmt.Errorf("Invalid format \"%s\", Supported formats: 'pretty-print'/'json' ", listPolicies.Format)
}

View File

@@ -24,7 +24,7 @@ import (
log "github.com/sirupsen/logrus"
)
func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
func (ks *Kubescape) Patch(patchInfo *ksmetav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
// ===================== Scan the image =====================
logger.L().Start(fmt.Sprintf("Scanning image: %s", patchInfo.Image))
@@ -37,7 +37,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
Password: patchInfo.Password,
}
// Scan the image
scanResults, err := svc.Scan(ctx, patchInfo.Image, creds)
scanResults, err := svc.Scan(ks.Context(), patchInfo.Image, creds, nil, nil)
if err != nil {
return nil, err
}
@@ -52,7 +52,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
fileName := fmt.Sprintf("%s:%s.json", patchInfo.ImageName, patchInfo.ImageTag)
fileName = strings.ReplaceAll(fileName, "/", "-")
writer := printer.GetWriter(ctx, fileName)
writer := printer.GetWriter(ks.Context(), fileName)
if err = pres.Present(writer); err != nil {
return nil, err
@@ -68,7 +68,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
disableCopaLogger()
}
if err = copaPatch(ctx, patchInfo.Timeout, patchInfo.BuildkitAddress, patchInfo.Image, fileName, patchedImageName, "", patchInfo.IgnoreError, patchInfo.BuildKitOpts); err != nil {
if err = copaPatch(ks.Context(), patchInfo.Timeout, patchInfo.BuildkitAddress, patchInfo.Image, fileName, patchedImageName, "", patchInfo.IgnoreError, patchInfo.BuildKitOpts); err != nil {
return nil, err
}
@@ -81,7 +81,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
logger.L().Start(fmt.Sprintf("Re-scanning image: %s", patchedImageName))
scanResultsPatched, err := svc.Scan(ctx, patchedImageName, creds)
scanResultsPatched, err := svc.Scan(ks.Context(), patchedImageName, creds, nil, nil)
if err != nil {
return nil, err
}
@@ -96,8 +96,8 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
// ===================== Results Handling =====================
scanInfo.SetScanType(cautils.ScanTypeImage)
outputPrinters := GetOutputPrinters(scanInfo, ctx, "")
uiPrinter := GetUIPrinter(ctx, scanInfo, "")
outputPrinters := GetOutputPrinters(scanInfo, ks.Context(), "")
uiPrinter := GetUIPrinter(ks.Context(), scanInfo, "")
resultsHandler := resultshandling.NewResultsHandler(nil, outputPrinters, uiPrinter)
resultsHandler.ImageScanData = []cautils.ImageScanData{
{
@@ -106,7 +106,7 @@ func (ks *Kubescape) Patch(ctx context.Context, patchInfo *ksmetav1.PatchInfo, s
},
}
return scanResultsPatched, resultsHandler.HandleResults(ctx)
return scanResultsPatched, resultsHandler.HandleResults(ks.Context())
}
func disableCopaLogger() {

View File

@@ -3,6 +3,7 @@ package core
import (
"context"
"fmt"
"slices"
"github.com/kubescape/backend/pkg/versioncheck"
"github.com/kubescape/go-logger"
@@ -23,7 +24,6 @@ import (
apisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
"github.com/kubescape/opa-utils/resources"
"go.opentelemetry.io/otel"
"golang.org/x/exp/slices"
"k8s.io/client-go/kubernetes"
)
@@ -121,8 +121,8 @@ func GetOutputPrinters(scanInfo *cautils.ScanInfo, ctx context.Context, clusterN
return outputPrinters
}
func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
ctxInit, spanInit := otel.Tracer("").Start(ctx, "initialization")
func (ks *Kubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
ctxInit, spanInit := otel.Tracer("").Start(ks.Context(), "initialization")
logger.L().Start("Kubescape scanner initializing...")
// ===================== Initialization =====================
@@ -148,7 +148,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
// remove host scanner components
defer func() {
if err := interfaces.hostSensorHandler.TearDown(); err != nil {
logger.L().Ctx(ctx).StopError("Failed to tear down host scanner", helpers.Error(err))
logger.L().Ctx(ks.Context()).StopError("Failed to tear down host scanner", helpers.Error(err))
}
}()
@@ -177,7 +177,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
spanInit.End()
// ========================= opa testing =====================
ctxOpa, spanOpa := otel.Tracer("").Start(ctx, "opa testing")
ctxOpa, spanOpa := otel.Tracer("").Start(ks.Context(), "opa testing")
defer spanOpa.End()
deps := resources.NewRegoDependenciesData(k8sinterface.GetK8sConfig(), interfaces.tenantConfig.GetContextName())
@@ -191,7 +191,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
if scanInfo.PrintAttackTree || isPrioritizationScanType(scanInfo.ScanType) {
_, spanPrioritization := otel.Tracer("").Start(ctxOpa, "prioritization")
if priotizationHandler, err := resourcesprioritization.NewResourcesPrioritizationHandler(ctxOpa, scanInfo.Getters.AttackTracksGetter, scanInfo.PrintAttackTree); err != nil {
logger.L().Ctx(ctx).Warning("failed to get attack tracks, this may affect the scanning results", helpers.Error(err))
logger.L().Ctx(ks.Context()).Warning("failed to get attack tracks, this may affect the scanning results", helpers.Error(err))
} else if err := priotizationHandler.PrioritizeResources(scanData); err != nil {
return resultsHandling, fmt.Errorf("%w", err)
}
@@ -202,7 +202,7 @@ func (ks *Kubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*res
}
if scanInfo.ScanImages {
scanImages(scanInfo.ScanType, scanData, ctx, resultsHandling)
scanImages(scanInfo.ScanType, scanData, ks.Context(), resultsHandling)
}
// ========================= results handling =====================
resultsHandling.SetData(scanData)
@@ -257,7 +257,7 @@ func scanImages(scanType cautils.ScanTypes, scanData *cautils.OPASessionObj, ctx
func scanSingleImage(ctx context.Context, img string, svc imagescan.Service, resultsHandling *resultshandling.ResultsHandler) error {
scanResults, err := svc.Scan(ctx, img, imagescan.RegistryCredentials{})
scanResults, err := svc.Scan(ctx, img, imagescan.RegistryCredentials{}, nil, nil)
if err != nil {
return err
}

View File

@@ -0,0 +1,67 @@
[
{
"metadata": {
"name": "alpine-exceptions"
},
"kind": "VulnerabilitiesIgnorePolicy",
"targets": [
{
"designatorType": "Attributes",
"attributes": {
"imageName": "alpine*"
}
}
],
"severities": [
"medium"
]
},
{
"metadata": {
"name": "nginx-exceptions"
},
"kind": "VulnerabilitiesIgnorePolicy",
"targets": [
{
"designatorType": "Attributes",
"attributes": {
"imageName": "nginx*"
}
}
],
"vulnerabilities": [
"invalid-cve",
"CVE-2023-45853",
"CVE-2023-49463"
],
"severities": [
"critical",
"medium",
"invalid-severity"
]
},
{
"metadata": {
"name": "applicable-only-to-quay-registry-images"
},
"kind": "VulnerabilitiesIgnorePolicy",
"targets": [
{
"designatorType": "Attributes",
"attributes": {
"registry": "quay.io"
}
}
],
"vulnerabilities": [
"CVE-2023-42365"
],
"severities": [
"critical",
"medium",
"high",
"low"
]
}
]

View File

@@ -0,0 +1 @@
[]

78
core/core/testdata/exceptions.json vendored Normal file
View File

@@ -0,0 +1,78 @@
[
{
"metadata": {
"name": "medium-severity-vulnerabilites-exceptions"
},
"kind": "VulnerabilitiesIgnorePolicy",
"targets": [
{
"designatorType": "Attributes",
"attributes": {
"Registry": "docker.io",
"Organization": "",
"ImageName": ""
}
}
],
"vulnerabilities": [
],
"severities": [
"medium"
]
},
{
"metadata": {
"name": "exclude-allowed-hostPath-control"
},
"kind": "VulnerabilitiesIgnorePolicy",
"targets": [
{
"designatorType": "Attributes",
"attributes": {
}
}
],
"vulnerabilities": [
"CVE-2023-42366",
"CVE-2023-42365"
],
"severities": [
"critical",
"low"
]
},
{
"metadata": {
"name": "regex-example"
},
"kind": "VulnerabilitiesIgnorePolicy",
"targets": [
{
"designatorType": "Attributes",
"attributes": {
"Registry": "quay.*",
"Organization": "kube*",
"ImageName": "kubescape*",
"ImageTag": "v2*"
}
},
{
"designatorType": "Attributes",
"attributes": {
"Registry": "docker.io",
"Organization": ".*",
"ImageName": "kube*",
"ImageTag": "v3*"
}
}
],
"vulnerabilities": [
"CVE-2023-6879",
"CVE-2023-44487"
],
"severities": [
"critical",
"low"
]
}
]

View File

@@ -1,7 +1,8 @@
package v1
type ImageScanInfo struct {
Username string
Password string
Image string
Username string
Password string
Image string
Exceptions string
}

View File

@@ -10,23 +10,25 @@ import (
)
type IKubescape interface {
Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) // TODO - use scanInfo from v1
Context() context.Context
Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) // TODO - use scanInfo from v1
// policies
List(ctx context.Context, listPolicies *metav1.ListPolicies) error // TODO - return list response
Download(ctx context.Context, downloadInfo *metav1.DownloadInfo) error // TODO - return downloaded policies
List(listPolicies *metav1.ListPolicies) error // TODO - return list response
Download(downloadInfo *metav1.DownloadInfo) error // TODO - return downloaded policies
// config
SetCachedConfig(setConfig *metav1.SetConfig) error
ViewCachedConfig(viewConfig *metav1.ViewConfig) error
DeleteCachedConfig(ctx context.Context, deleteConfig *metav1.DeleteConfig) error
DeleteCachedConfig(deleteConfig *metav1.DeleteConfig) error
// fix
Fix(ctx context.Context, fixInfo *metav1.FixInfo) error
Fix(fixInfo *metav1.FixInfo) error
// patch
Patch(ctx context.Context, patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error)
Patch(patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error)
// scan image
ScanImage(ctx context.Context, imgScanInfo *metav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error)
ScanImage(imgScanInfo *metav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error)
}

View File

@@ -11,15 +11,19 @@ import (
type MockIKubescape struct{}
func (m *MockIKubescape) Scan(ctx context.Context, scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
func (m *MockIKubescape) Context() context.Context {
return context.TODO()
}
func (m *MockIKubescape) Scan(scanInfo *cautils.ScanInfo) (*resultshandling.ResultsHandler, error) {
return nil, nil
}
func (m *MockIKubescape) List(ctx context.Context, listPolicies *metav1.ListPolicies) error {
func (m *MockIKubescape) List(listPolicies *metav1.ListPolicies) error {
return nil
}
func (m *MockIKubescape) Download(ctx context.Context, downloadInfo *metav1.DownloadInfo) error {
func (m *MockIKubescape) Download(downloadInfo *metav1.DownloadInfo) error {
return nil
}
@@ -31,18 +35,18 @@ func (m *MockIKubescape) ViewCachedConfig(viewConfig *metav1.ViewConfig) error {
return nil
}
func (m *MockIKubescape) DeleteCachedConfig(ctx context.Context, deleteConfig *metav1.DeleteConfig) error {
func (m *MockIKubescape) DeleteCachedConfig(deleteConfig *metav1.DeleteConfig) error {
return nil
}
func (m *MockIKubescape) Fix(ctx context.Context, fixInfo *metav1.FixInfo) error {
func (m *MockIKubescape) Fix(fixInfo *metav1.FixInfo) error {
return nil
}
func (m *MockIKubescape) Patch(ctx context.Context, patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
func (m *MockIKubescape) Patch(patchInfo *metav1.PatchInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
return nil, nil
}
func (m *MockIKubescape) ScanImage(ctx context.Context, imgScanInfo *metav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
func (m *MockIKubescape) ScanImage(imgScanInfo *metav1.ImageScanInfo, scanInfo *cautils.ScanInfo) (*models.PresenterConfig, error) {
return nil, nil
}

View File

@@ -3,6 +3,7 @@ package opaprocessor
import (
"context"
"fmt"
"slices"
"strings"
"sync"
@@ -18,12 +19,11 @@ import (
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
"github.com/kubescape/opa-utils/resources"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/storage"
opaprint "github.com/open-policy-agent/opa/topdown/print"
"github.com/open-policy-agent/opa/v1/ast"
"github.com/open-policy-agent/opa/v1/rego"
"github.com/open-policy-agent/opa/v1/storage"
opaprint "github.com/open-policy-agent/opa/v1/topdown/print"
"go.opentelemetry.io/otel"
"golang.org/x/exp/slices"
)
const ScoreConfigPath = "/resources/config"
@@ -324,6 +324,7 @@ func (opap *OPAProcessor) runRegoOnK8s(ctx context.Context, rule *reporthandling
// NOTE: OPA module compilation is the most resource-intensive operation.
compiled, err := ast.CompileModulesWithOpt(modules, ast.CompileOpts{
EnablePrintStatements: opap.printEnabled,
ParserOptions: ast.ParserOptions{RegoVersion: ast.RegoV0},
})
if err != nil {
return nil, fmt.Errorf("in 'runRegoOnK8s', failed to compile rule, name: %s, reason: %w", rule.Name, err)
@@ -351,6 +352,7 @@ func (opap *OPAProcessor) Print(ctx opaprint.Context, str string) error {
func (opap *OPAProcessor) regoEval(ctx context.Context, inputObj []map[string]interface{}, compiledRego *ast.Compiler, store *storage.Store) ([]reporthandling.RuleResponse, error) {
rego := rego.New(
rego.SetRegoVersion(ast.RegoV0),
rego.Query("data.armo_builtins"), // get package name from rule
rego.Compiler(compiledRego),
rego.Input(inputObj),

View File

@@ -2,6 +2,7 @@ package opaprocessor
import (
"fmt"
"slices"
"strings"
"github.com/kubescape/go-logger"
@@ -10,11 +11,10 @@ import (
"github.com/kubescape/opa-utils/reporthandling"
"github.com/kubescape/opa-utils/reporthandling/apis"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/rego"
"github.com/open-policy-agent/opa/topdown/builtins"
"github.com/open-policy-agent/opa/types"
"golang.org/x/exp/slices"
"github.com/open-policy-agent/opa/v1/ast"
"github.com/open-policy-agent/opa/v1/rego"
"github.com/open-policy-agent/opa/v1/topdown/builtins"
"github.com/open-policy-agent/opa/v1/types"
)
// convertFrameworksToPolicies convert list of frameworks to list of policies

View File

@@ -3,78 +3,39 @@ package printer
import (
"fmt"
"sort"
"strings"
"github.com/jwalton/gchalk"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/opa-utils/reporthandling/apis"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
"github.com/olekukonko/tablewriter"
)
const (
columnSeverity = iota
columnRef = iota
columnName = iota
columnCounterFailed = iota
columnCounterAll = iota
columnComplianceScore = iota
_rowLen = iota
controlNameMaxLength = 70
)
const controlNameMaxLength = 70
func generateRow(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars, verbose bool) []string {
row := make([]string, _rowLen)
// ignore passed results
if !verbose && (controlSummary.GetStatus().IsPassed()) {
return []string{}
}
row[columnSeverity] = getSeverityColumn(controlSummary)
if len(controlSummary.GetName()) > controlNameMaxLength {
row[columnName] = controlSummary.GetName()[:controlNameMaxLength] + "..."
} else {
row[columnName] = controlSummary.GetName()
}
row[columnCounterFailed] = fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed())
row[columnCounterAll] = fmt.Sprintf("%d", controlSummary.NumberOfResources().All())
row[columnComplianceScore] = getComplianceScoreColumn(controlSummary, infoToPrintInfo)
if row[columnComplianceScore] == "-1%" {
row[columnComplianceScore] = "N/A"
}
return row
type TableRow struct {
ref string
name string
counterFailed string
counterAll string
severity string
complianceScore string
}
func shortFormatRow(dataRows [][]string) [][]string {
rows := [][]string{}
for _, dataRow := range dataRows {
rows = append(rows, []string{fmt.Sprintf("Severity"+strings.Repeat(" ", 11)+": %+v\nControl Name"+strings.Repeat(" ", 7)+": %+v\nFailed Resources"+strings.Repeat(" ", 3)+": %+v\nAll Resources"+strings.Repeat(" ", 6)+": %+v\n%% Compliance-Score"+strings.Repeat(" ", 1)+": %+v", dataRow[columnSeverity], dataRow[columnName], dataRow[columnCounterFailed], dataRow[columnCounterAll], dataRow[columnComplianceScore])})
// generateTableRow is responsible for generating the row that will be printed in the table
func generateTableRow(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars) *TableRow {
tableRow := &TableRow{
ref: controlSummary.GetID(),
name: controlSummary.GetName(),
counterFailed: fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed()),
counterAll: fmt.Sprintf("%d", controlSummary.NumberOfResources().All()),
severity: apis.ControlSeverityToString(controlSummary.GetScoreFactor()),
complianceScore: getComplianceScoreColumn(controlSummary, infoToPrintInfo),
}
return rows
}
func generateRowPdf(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars, verbose bool) []string {
row := make([]string, _rowLen)
// ignore passed results
if !verbose && (controlSummary.GetStatus().IsPassed()) {
return []string{}
}
row[columnSeverity] = apis.ControlSeverityToString(controlSummary.GetScoreFactor())
row[columnRef] = controlSummary.GetID()
if len(controlSummary.GetName()) > controlNameMaxLength {
row[columnName] = controlSummary.GetName()[:controlNameMaxLength] + "..."
} else {
row[columnName] = controlSummary.GetName()
tableRow.name = controlSummary.GetName()[:controlNameMaxLength] + "..."
}
row[columnCounterFailed] = fmt.Sprintf("%d", controlSummary.NumberOfResources().Failed())
row[columnCounterAll] = fmt.Sprintf("%d", controlSummary.NumberOfResources().All())
row[columnComplianceScore] = getComplianceScoreColumn(controlSummary, infoToPrintInfo)
return row
return tableRow
}
func getInfoColumn(controlSummary reportsummary.IControlSummary, infoToPrintInfo []infoStars) string {
@@ -90,7 +51,12 @@ func getComplianceScoreColumn(controlSummary reportsummary.IControlSummary, info
if controlSummary.GetStatus().IsSkipped() {
return fmt.Sprintf("%s %s", "Action Required", getInfoColumn(controlSummary, infoToPrintInfo))
}
return fmt.Sprintf("%d", cautils.Float32ToInt(controlSummary.GetComplianceScore())) + "%"
if compliance := cautils.Float32ToInt(controlSummary.GetComplianceScore()); compliance < 0 {
return "N/A"
} else {
return fmt.Sprintf("%d", cautils.Float32ToInt(controlSummary.GetComplianceScore())) + "%"
}
}
func getSeverityColumn(controlSummary reportsummary.IControlSummary) string {
@@ -124,45 +90,3 @@ func getSortedControlsIDs(controls reportsummary.ControlSummaries) [][]string {
}
return controlIDs
}
/* unused for now
func getSortedControlsNames(controls reportsummary.ControlSummaries) [][]string {
controlNames := make([][]string, 5)
for k := range controls {
c := controls[k]
i := apis.ControlSeverityToInt(c.GetScoreFactor())
controlNames[i] = append(controlNames[i], c.GetName())
}
for i := range controlNames {
sort.Strings(controlNames[i])
}
return controlNames
}
*/
func getControlTableHeaders(short bool) []string {
var headers []string
if short {
headers = make([]string, 1)
headers[0] = "Controls"
} else {
headers = make([]string, _rowLen)
headers[columnRef] = "Control reference"
headers[columnName] = "Control name"
headers[columnCounterFailed] = "Failed resources"
headers[columnCounterAll] = "All resources"
headers[columnSeverity] = "Severity"
headers[columnComplianceScore] = "Compliance score"
}
return headers
}
func getColumnsAlignments() []int {
alignments := make([]int, _rowLen)
alignments[columnName] = tablewriter.ALIGN_LEFT
alignments[columnCounterFailed] = tablewriter.ALIGN_CENTER
alignments[columnCounterAll] = tablewriter.ALIGN_CENTER
alignments[columnSeverity] = tablewriter.ALIGN_LEFT
alignments[columnComplianceScore] = tablewriter.ALIGN_CENTER
return alignments
}

View File

@@ -23,45 +23,43 @@ func Test_generateRowPdf(t *testing.T) {
infoToPrintInfoMap := mapInfoToPrintInfo(mockSummary.Controls)
sortedControlIDs := getSortedControlsIDs(mockSummary.Controls)
var results [][]string
var rows []TableRow
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
for _, c := range sortedControlIDs[i] {
result := generateRowPdf(mockSummary.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfoMap, true)
if len(result) > 0 {
results = append(results, result)
}
row := *generateTableRow(mockSummary.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfoMap)
rows = append(rows, row)
}
}
for _, c := range results {
for _, row := range rows {
//validating severity column
if c[0] != "Low" && c[0] != "Medium" && c[0] != "High" && c[0] != "Critical" {
t.Errorf("got %s, want either of these: %s", c[0], "Low, Medium, High, Critical")
if row.severity != "Low" && row.severity != "Medium" && row.severity != "High" && row.severity != "Critical" {
t.Errorf("got %s, want either of these: %s", row.severity, "Low, Medium, High, Critical")
}
// Validating length of control ID
if len(c[1]) > 6 {
t.Errorf("got %s, want %s", c[1], "less than 7 characters")
if len(row.ref) > 6 {
t.Errorf("got %s, want %s", row.ref, "less than 7 characters")
}
// Validating length of control name
if len(c[2]) > controlNameMaxLength {
t.Errorf("got %s, want %s", c[1], fmt.Sprintf("less than %d characters", controlNameMaxLength))
if len(row.name) > controlNameMaxLength {
t.Errorf("got %s, want %s", row.name, fmt.Sprintf("less than %d characters", controlNameMaxLength))
}
// Validating numeric fields
_, err := strconv.Atoi(c[3])
_, err := strconv.Atoi(row.counterFailed)
if err != nil {
t.Errorf("got %s, want an integer %s", c[2], err)
t.Errorf("got %s, want an integer %s", row.counterFailed, err)
}
_, err = strconv.Atoi(c[4])
_, err = strconv.Atoi(row.counterAll)
if err != nil {
t.Errorf("got %s, want an integer %s", c[3], err)
t.Errorf("got %s, want an integer %s", row.counterAll, err)
}
assert.NotEmpty(t, c[5], "expected a non-empty string")
assert.NotEmpty(t, row.complianceScore, "expected a non-empty string")
}

View File

@@ -3,21 +3,18 @@ package printer
import (
"context"
_ "embed"
b64 "encoding/base64"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/johnfercher/maroto/pkg/color"
"github.com/johnfercher/maroto/pkg/consts"
"github.com/johnfercher/maroto/pkg/pdf"
"github.com/johnfercher/maroto/pkg/props"
"github.com/johnfercher/maroto/v2/pkg/props"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer"
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/pdf"
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/prettyprinter/tableprinter/utils"
"github.com/kubescape/opa-utils/reporthandling/results/v1/reportsummary"
)
@@ -27,11 +24,6 @@ const (
pdfOutputExt = ".pdf"
)
var (
//go:embed pdf/logo.png
kubescapeLogo []byte
)
var _ printer.IPrinter = &PdfPrinter{}
type PdfPrinter struct {
@@ -66,219 +58,79 @@ func (pp *PdfPrinter) Score(score float32) {
fmt.Fprintf(os.Stderr, "\nOverall compliance-score (100- Excellent, 0- All failed): %d\n", cautils.Float32ToInt(score))
}
func (pp *PdfPrinter) printInfo(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, infoMap []infoStars) {
emptyRowCounter := 1
for i := range infoMap {
if infoMap[i].info != "" {
m.Row(5, func() {
m.Col(12, func() {
m.Text(fmt.Sprintf("%v %v", infoMap[i].stars, infoMap[i].info), props.Text{
Style: consts.Bold,
Align: consts.Left,
Size: 8,
Extrapolate: false,
Color: color.Color{
Red: 0,
Green: 0,
Blue: 255,
},
})
})
})
if emptyRowCounter < len(infoMap) {
m.Row(2.5, func() {})
emptyRowCounter++
}
}
}
}
func (pp *PdfPrinter) PrintNextSteps() {
}
// ActionPrint is responsible for generating a report in pdf format
func (pp *PdfPrinter) ActionPrint(ctx context.Context, opaSessionObj *cautils.OPASessionObj, imageScanData []cautils.ImageScanData) {
if opaSessionObj == nil {
logger.L().Ctx(ctx).Error("failed to print results, missing data")
return
}
sortedControlIDs := getSortedControlsIDs(opaSessionObj.Report.SummaryDetails.Controls)
infoToPrintInfo := mapInfoToPrintInfo(opaSessionObj.Report.SummaryDetails.Controls)
m := pdf.NewMaroto(consts.Portrait, consts.A4)
pp.printHeader(m)
pp.printFramework(m, opaSessionObj.Report.SummaryDetails.ListFrameworks())
pp.printTable(m, &opaSessionObj.Report.SummaryDetails, sortedControlIDs)
pp.printFinalResult(m, &opaSessionObj.Report.SummaryDetails)
pp.printInfo(m, &opaSessionObj.Report.SummaryDetails, infoToPrintInfo)
// Extrat output buffer.
outBuff, err := m.Output()
outBuff, err := pp.generatePdf(&opaSessionObj.Report.SummaryDetails)
if err != nil {
logger.L().Ctx(ctx).Error("failed to generate pdf format", helpers.Error(err))
return
}
if _, err := pp.writer.Write(outBuff.Bytes()); err != nil {
if _, err := pp.writer.Write(outBuff); err != nil {
logger.L().Ctx(ctx).Error("failed to write results", helpers.Error(err))
return
}
printer.LogOutputFile(pp.writer.Name())
}
// printHeader prints the Kubescape logo and report date
func (pp *PdfPrinter) printHeader(m pdf.Maroto) {
// Retrieve current time (we need it for the report timestamp).
t := time.Now()
// Enconde PNG into Base64 to embed it into the pdf.
kubescapeLogoEnc := b64.StdEncoding.EncodeToString(kubescapeLogo)
func (pp *PdfPrinter) generatePdf(summaryDetails *reportsummary.SummaryDetails) ([]byte, error) {
sortedControlIDs := getSortedControlsIDs(summaryDetails.Controls)
infoToPrintInfo := mapInfoToPrintInfo(summaryDetails.Controls)
m.SetPageMargins(10, 15, 10)
m.Row(40, func() {
//m.Text(fmt.Sprintf("Security Assessment"), props.Text{
// Align: consts.Center,
// Size: 24,
// Family: consts.Arial,
// Style: consts.Bold,
//})
_ = m.Base64Image(kubescapeLogoEnc, consts.Png, props.Rect{
Center: true,
Percent: 100,
})
})
m.Row(6, func() {
m.Text(fmt.Sprintf("Report date: %d-%02d-%02dT%02d:%02d:%02d",
t.Year(),
t.Month(),
t.Day(),
t.Hour(),
t.Minute(),
t.Second()), props.Text{
Align: consts.Left,
Size: 6.0,
Style: consts.Bold,
Family: consts.Arial,
})
})
m.Line(1)
template := pdf.NewReportTemplate()
template.GenerateHeader(utils.FrameworksScoresToString(summaryDetails.ListFrameworks()), time.Now().Format(time.DateTime))
err := template.GenerateTable(pp.getTableObjects(summaryDetails, sortedControlIDs),
summaryDetails.NumberOfResources().Failed(), summaryDetails.NumberOfResources().All(), summaryDetails.ComplianceScore)
if err != nil {
return nil, err
}
template.GenerateInfoRows(pp.getFormattedInformation(infoToPrintInfo))
return template.GetPdf()
}
// printFramework prints the PDF frameworks after the PDF header
func (pp *PdfPrinter) printFramework(m pdf.Maroto, frameworks []reportsummary.IFrameworkSummary) {
m.Row(10, func() {
m.Text(utils.FrameworksScoresToString(frameworks), props.Text{
Align: consts.Center,
Size: 8,
Family: consts.Arial,
Style: consts.Bold,
})
})
}
// printTable creates the PDF table
func (pp *PdfPrinter) printTable(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) {
headers := getControlTableHeaders(false)
infoToPrintInfoMap := mapInfoToPrintInfo(summaryDetails.Controls)
var controls [][]string
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
for _, c := range sortedControlIDs[i] {
row := generateRowPdf(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfoMap, true)
if len(row) > 0 {
controls = append(controls, row)
}
func (pp *PdfPrinter) getFormattedInformation(infoMap []infoStars) []string {
rows := make([]string, 0, len(infoMap))
for i := range infoMap {
if infoMap[i].info != "" {
rows = append(rows, fmt.Sprintf("%v %v", infoMap[i].stars, infoMap[i].info))
}
}
size := 6.0
gridSize := []uint{1, 1, 6, 1, 1, 2}
m.TableList(headers, controls, props.TableList{
HeaderProp: props.TableListContent{
Family: consts.Arial,
Style: consts.Bold,
Size: size,
GridSizes: gridSize,
},
ContentProp: props.TableListContent{
Family: consts.Courier,
Style: consts.Normal,
Size: size,
GridSizes: gridSize,
CellTextColorChangerColumnIndex: 0,
CellTextColorChangerFunc: func(cellValue string) color.Color {
if cellValue == "Critical" {
return color.Color{
Red: 255,
Green: 0,
Blue: 0,
}
} else if cellValue == "High" {
return color.Color{
Red: 0,
Green: 0,
Blue: 255,
}
} else if cellValue == "Medium" {
return color.Color{
Red: 252,
Green: 186,
Blue: 3,
}
}
return color.NewBlack()
},
},
Align: consts.Left,
AlternatedBackground: &color.Color{
Red: 224,
Green: 224,
Blue: 224,
},
HeaderContentSpace: 2.0,
Line: false,
})
m.Line(1)
m.Row(2, func() {})
return rows
}
// printFinalResult adds the final results
func (pp *PdfPrinter) printFinalResult(m pdf.Maroto, summaryDetails *reportsummary.SummaryDetails) {
m.Row(_rowLen, func() {
m.Col(1, func() {
})
m.Col(5, func() {
m.Text("Resource summary", props.Text{
Align: consts.Left,
Size: 8.0,
Style: consts.Bold,
Family: consts.Arial,
})
})
m.Col(2, func() {
m.Text(fmt.Sprintf("%d", summaryDetails.NumberOfResources().Failed()), props.Text{
Align: consts.Left,
Size: 8.0,
Style: consts.Bold,
Family: consts.Arial,
})
})
m.Col(2, func() {
m.Text(fmt.Sprintf("%d", summaryDetails.NumberOfResources().All()), props.Text{
Align: consts.Left,
Size: 8.0,
Style: consts.Bold,
Family: consts.Arial,
})
})
m.Col(2, func() {
m.Text(fmt.Sprintf("%.2f%s", summaryDetails.ComplianceScore, "%"), props.Text{
Align: consts.Left,
Size: 8.0,
Style: consts.Bold,
Family: consts.Arial,
})
})
})
// getTableData is responsible for getting the table data in a standardized format
func (pp *PdfPrinter) getTableObjects(summaryDetails *reportsummary.SummaryDetails, sortedControlIDs [][]string) *[]pdf.TableObject {
infoToPrintInfoMap := mapInfoToPrintInfo(summaryDetails.Controls)
var controls []pdf.TableObject
for i := len(sortedControlIDs) - 1; i >= 0; i-- {
for _, c := range sortedControlIDs[i] {
row := generateTableRow(summaryDetails.Controls.GetControl(reportsummary.EControlCriteriaID, c), infoToPrintInfoMap)
controls = append(controls, *pdf.NewTableRow(
row.ref, row.name, row.counterFailed, row.counterAll, row.severity, row.complianceScore, getSeverityColor,
))
}
}
return &controls
}
func getSeverityColor(severity string) *props.Color {
if severity == "Critical" {
return &props.Color{Red: 255, Green: 0, Blue: 0}
} else if severity == "High" {
return &props.Color{Red: 0, Green: 0, Blue: 255}
} else if severity == "Medium" {
return &props.Color{Red: 252, Green: 186, Blue: 3}
}
return &props.BlackColor
}

View File

@@ -0,0 +1 @@
test_path: "testStructure/"

View File

@@ -0,0 +1,195 @@
package pdf
import (
_ "embed"
"fmt"
"github.com/johnfercher/go-tree/node"
"github.com/johnfercher/maroto/v2"
"github.com/johnfercher/maroto/v2/pkg/components/image"
"github.com/johnfercher/maroto/v2/pkg/components/line"
"github.com/johnfercher/maroto/v2/pkg/components/list"
"github.com/johnfercher/maroto/v2/pkg/components/row"
"github.com/johnfercher/maroto/v2/pkg/components/text"
"github.com/johnfercher/maroto/v2/pkg/config"
"github.com/johnfercher/maroto/v2/pkg/consts/align"
"github.com/johnfercher/maroto/v2/pkg/consts/extension"
"github.com/johnfercher/maroto/v2/pkg/consts/fontfamily"
"github.com/johnfercher/maroto/v2/pkg/consts/fontstyle"
"github.com/johnfercher/maroto/v2/pkg/consts/orientation"
"github.com/johnfercher/maroto/v2/pkg/consts/pagesize"
"github.com/johnfercher/maroto/v2/pkg/core"
"github.com/johnfercher/maroto/v2/pkg/props"
)
var (
//go:embed logo.png
kubescapeLogo []byte
)
type getTextColorFunc func(severity string) *props.Color
type Template struct {
maroto core.Maroto
}
// New Report Template is responsible for creating an object that generates a report with the submitted data
func NewReportTemplate() *Template {
return &Template{
maroto: maroto.New(
config.NewBuilder().
WithPageSize(pagesize.A4).
WithOrientation(orientation.Vertical).
WithLeftMargin(10).
WithTopMargin(15).
WithRightMargin(10).
Build()),
}
}
// GetPdf is responsible for generating the pdf and returning the file's bytes
func (t *Template) GetPdf() ([]byte, error) {
doc, err := t.maroto.Generate()
if err != nil {
return nil, err
}
return doc.GetBytes(), nil
}
// printHeader prints the Kubescape logo, report date and framework
func (t *Template) GenerateHeader(scoreOfScannedFrameworks, reportDate string) *Template {
t.maroto.AddRow(40, image.NewFromBytesCol(12, kubescapeLogo, extension.Png, props.Rect{
Center: true,
Percent: 100,
}))
t.maroto.AddRow(6, text.NewCol(12, fmt.Sprintf("Report date: %s", reportDate),
props.Text{
Align: align.Left,
Size: 6.0,
Style: fontstyle.Bold,
Family: fontfamily.Arial,
}))
t.maroto.AddAutoRow(line.NewCol(12, props.Line{Thickness: 0.3, SizePercent: 100}))
t.maroto.AddRow(10, text.NewCol(12, scoreOfScannedFrameworks, props.Text{
Align: align.Center,
Size: 8,
Family: fontfamily.Arial,
Style: fontstyle.Bold,
}))
return t
}
// GenerateTable is responsible for adding data in table format to the pdf
func (t *Template) GenerateTable(tableRows *[]TableObject, totalFailed, total int, score float32) error {
rows, err := list.Build[TableObject](*tableRows)
if err != nil {
return err
}
t.maroto.AddRows(rows...)
t.maroto.AddRows(
line.NewAutoRow(props.Line{Thickness: 0.3, SizePercent: 100}),
row.New(2),
)
t.generateTableTableResult(totalFailed, total, score)
return nil
}
// GenerateInfoRows is responsible for adding the information in pdf
func (t *Template) GenerateInfoRows(rows []string) *Template {
for _, row := range rows {
t.maroto.AddAutoRow(text.NewCol(12, row, props.Text{
Style: fontstyle.Bold,
Align: align.Left,
Top: 2.5,
Size: 8,
Color: &props.Color{
Red: 0,
Green: 0,
Blue: 255,
},
}))
}
return t
}
func (t *Template) generateTableTableResult(totalFailed, total int, score float32) {
defaultProps := props.Text{
Align: align.Left,
Size: 8,
Style: fontstyle.Bold,
Family: fontfamily.Arial,
}
t.maroto.AddRow(10,
text.NewCol(5, "Resource summary", defaultProps),
text.NewCol(2, fmt.Sprintf("%d", totalFailed), defaultProps),
text.NewCol(2, fmt.Sprintf("%d", total), defaultProps),
text.NewCol(2, fmt.Sprintf("%.2f%s", score, "%"), defaultProps),
)
}
func (t *Template) GetStructure() *node.Node[core.Structure] {
return t.maroto.GetStructure()
}
// TableObject is responsible for mapping the table data, it will be sent to Maroto and will make it possible to generate the table
type TableObject struct {
ref string
name string
counterFailed string
counterAll string
severity string
complianceScore string
getTextColor getTextColorFunc
}
func NewTableRow(ref, name, counterFailed, counterAll, severity, score string, getTextColor getTextColorFunc) *TableObject {
return &TableObject{
ref: ref,
name: name,
counterFailed: counterFailed,
counterAll: counterAll,
severity: severity,
complianceScore: score,
getTextColor: getTextColor,
}
}
func (t TableObject) GetHeader() core.Row {
return row.New(10).Add(
text.NewCol(1, "Severity", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
text.NewCol(1, "Control reference", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
text.NewCol(6, "Control name", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
text.NewCol(1, "Failed resources", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
text.NewCol(1, "All resources", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
text.NewCol(2, "Compliance score", props.Text{Size: 6, Family: fontfamily.Arial, Style: fontstyle.Bold}),
)
}
func (t TableObject) GetContent(i int) core.Row {
r := row.New(3).Add(
text.NewCol(1, t.severity, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6, Color: t.getTextColor(t.severity)}),
text.NewCol(1, t.ref, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6, Color: &props.Color{}}),
text.NewCol(6, t.name, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6}),
text.NewCol(1, t.counterFailed, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6}),
text.NewCol(1, t.counterAll, props.Text{Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6}),
text.NewCol(2, t.complianceScore, props.Text{VerticalPadding: 1, Style: fontstyle.Normal, Family: fontfamily.Courier, Size: 6}),
)
if i%2 == 0 {
r.WithStyle(&props.Cell{
BackgroundColor: &props.Color{
Red: 224,
Green: 224,
Blue: 224,
},
})
}
return r
}

View File

@@ -0,0 +1,58 @@
package pdf_test
import (
"testing"
"github.com/johnfercher/maroto/v2/pkg/props"
"github.com/johnfercher/maroto/v2/pkg/test"
"github.com/kubescape/kubescape/v3/core/pkg/resultshandling/printer/v2/pdf"
"github.com/stretchr/testify/assert"
)
func TestGetPdf(t *testing.T) {
t.Run("when GetPdf is called, it should return pdf bytes", func(t *testing.T) {
template := pdf.NewReportTemplate().GenerateHeader("Framework test 1, Framework test 2", "2024-04-01 20:31:00")
bytes, err := template.GetPdf()
assert.Nil(t, err)
assert.NotNil(t, bytes)
})
}
func TestGenerateHeader(t *testing.T) {
t.Run("when generateHeader is called, it should set the header in the pdf", func(t *testing.T) {
template := pdf.NewReportTemplate().GenerateHeader("Framework test 1, Framework test 2", "2024-04-01 20:31:00")
node := template.GetStructure()
assert.NotNil(t, node)
test.New(t).Assert(node).Equals("headerTemplate.json")
})
}
func TestGenerateTable(t *testing.T) {
t.Run("when generateTable is called, it should set the table in the pdf", func(t *testing.T) {
TableObjectMock := pdf.NewTableRow(
"ref", "name", "failed", "all", "severity", "score",
func(severity string) *props.Color { return &props.Color{Red: 0, Blue: 0, Green: 0} },
)
template := pdf.NewReportTemplate()
err := template.GenerateTable(&[]pdf.TableObject{*TableObjectMock}, 100, 10, 10.0)
assert.Nil(t, err)
test.New(t).Assert(template.GetStructure()).Equals("tableTemplate.json")
})
}
func TestGenerateInfoRows(t *testing.T) {
t.Run("when generateInfoRows is called, it should set the info rows in the pdf", func(t *testing.T) {
template := pdf.NewReportTemplate().GenerateInfoRows([]string{"row info 1", "row info 2", "row info 3"})
assert.NotNil(t, template)
test.New(t).Assert(template.GetStructure()).Equals("infoTemplate.json")
})
}

View File

@@ -0,0 +1,127 @@
{
"type": "maroto",
"details": {
"chunk_workers": 1,
"config_margin_bottom": 20.0025,
"config_margin_left": 10,
"config_margin_right": 10,
"config_margin_top": 15,
"config_max_grid_sum": 12,
"config_provider_type": "gofpdf",
"generation_mode": "sequential",
"maroto_dimension_height": 297,
"maroto_dimension_width": 210,
"prop_font_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 10
},
"nodes": [
{
"type": "page",
"nodes": [
{
"value": 40,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col",
"nodes": [
{
"value": "iVBORw0KGgoAAA==",
"type": "bytesImage",
"details": {
"bytes_size": 54270,
"extension": "png",
"prop_center": true,
"prop_percent": 100
}
}
]
}
]
},
{
"value": 6,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col",
"nodes": [
{
"value": "Report date: 2024-04-01 20:31:00",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 6,
"prop_font_style": "B"
}
}
]
}
]
},
{
"value": 0.3,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col",
"nodes": [
{
"type": "line",
"details": {
"prop_offset_percent": 5,
"prop_orientation": "horizontal",
"prop_size_percent": 100,
"prop_style": "solid",
"prop_thickness": 0.3
}
}
]
}
]
},
{
"value": 10,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col",
"nodes": [
{
"value": "Framework test 1, Framework test 2",
"type": "text",
"details": {
"prop_align": "C",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 8,
"prop_font_style": "B"
}
}
]
}
]
},
{
"value": 205.6975,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col"
}
]
}
]
}
]
}

View File

@@ -0,0 +1,110 @@
{
"type": "maroto",
"details": {
"chunk_workers": 1,
"config_margin_bottom": 20.0025,
"config_margin_left": 10,
"config_margin_right": 10,
"config_margin_top": 15,
"config_max_grid_sum": 12,
"config_provider_type": "gofpdf",
"generation_mode": "sequential",
"maroto_dimension_height": 297,
"maroto_dimension_width": 210,
"prop_font_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 10
},
"nodes": [
{
"type": "page",
"nodes": [
{
"value": 5.322222222222223,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col",
"nodes": [
{
"value": "row info 1",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 255)",
"prop_font_family": "arial",
"prop_font_size": 8,
"prop_font_style": "B",
"prop_top": 2.5
}
}
]
}
]
},
{
"value": 5.322222222222223,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col",
"nodes": [
{
"value": "row info 2",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 255)",
"prop_font_family": "arial",
"prop_font_size": 8,
"prop_font_style": "B",
"prop_top": 2.5
}
}
]
}
]
},
{
"value": 5.322222222222223,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col",
"nodes": [
{
"value": "row info 3",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 255)",
"prop_font_family": "arial",
"prop_font_size": 8,
"prop_font_style": "B",
"prop_top": 2.5
}
}
]
}
]
},
{
"value": 246.03083333333333,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col"
}
]
}
]
}
]
}

View File

@@ -0,0 +1,377 @@
{
"type": "maroto",
"details": {
"chunk_workers": 1,
"config_margin_bottom": 20.0025,
"config_margin_left": 10,
"config_margin_right": 10,
"config_margin_top": 15,
"config_max_grid_sum": 12,
"config_provider_type": "gofpdf",
"generation_mode": "sequential",
"maroto_dimension_height": 297,
"maroto_dimension_width": 210,
"prop_font_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 10
},
"nodes": [
{
"type": "page",
"nodes": [
{
"value": 10,
"type": "row",
"nodes": [
{
"value": 1,
"type": "col",
"nodes": [
{
"value": "Severity",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 6,
"prop_font_style": "B"
}
}
]
},
{
"value": 1,
"type": "col",
"nodes": [
{
"value": "Control reference",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 6,
"prop_font_style": "B"
}
}
]
},
{
"value": 6,
"type": "col",
"nodes": [
{
"value": "Control name",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 6,
"prop_font_style": "B"
}
}
]
},
{
"value": 1,
"type": "col",
"nodes": [
{
"value": "Failed resources",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 6,
"prop_font_style": "B"
}
}
]
},
{
"value": 1,
"type": "col",
"nodes": [
{
"value": "All resources",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 6,
"prop_font_style": "B"
}
}
]
},
{
"value": 2,
"type": "col",
"nodes": [
{
"value": "Compliance score",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 6,
"prop_font_style": "B"
}
}
]
}
]
},
{
"value": 3,
"type": "row",
"details": {
"prop_background_color": "RGB(224, 224, 224)"
},
"nodes": [
{
"value": 1,
"type": "col",
"nodes": [
{
"value": "severity",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "courier",
"prop_font_size": 6
}
}
]
},
{
"value": 1,
"type": "col",
"nodes": [
{
"value": "ref",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "courier",
"prop_font_size": 6
}
}
]
},
{
"value": 6,
"type": "col",
"nodes": [
{
"value": "name",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "courier",
"prop_font_size": 6
}
}
]
},
{
"value": 1,
"type": "col",
"nodes": [
{
"value": "failed",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "courier",
"prop_font_size": 6
}
}
]
},
{
"value": 1,
"type": "col",
"nodes": [
{
"value": "all",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "courier",
"prop_font_size": 6
}
}
]
},
{
"value": 2,
"type": "col",
"nodes": [
{
"value": "score",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "courier",
"prop_font_size": 6,
"prop_vertical_padding": 1
}
}
]
}
]
},
{
"value": 0.3,
"type": "row",
"nodes": [
{
"value": 0,
"type": "col",
"details": {
"is_max": true
},
"nodes": [
{
"type": "line",
"details": {
"prop_offset_percent": 5,
"prop_orientation": "horizontal",
"prop_size_percent": 100,
"prop_style": "solid",
"prop_thickness": 0.3
}
}
]
}
]
},
{
"value": 2,
"type": "row",
"nodes": [
{
"value": 0,
"type": "col",
"details": {
"is_max": true
}
}
]
},
{
"value": 10,
"type": "row",
"nodes": [
{
"value": 5,
"type": "col",
"nodes": [
{
"value": "Resource summary",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 8,
"prop_font_style": "B"
}
}
]
},
{
"value": 2,
"type": "col",
"nodes": [
{
"value": "100",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 8,
"prop_font_style": "B"
}
}
]
},
{
"value": 2,
"type": "col",
"nodes": [
{
"value": "10",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 8,
"prop_font_style": "B"
}
}
]
},
{
"value": 2,
"type": "col",
"nodes": [
{
"value": "10.00%",
"type": "text",
"details": {
"prop_align": "L",
"prop_breakline_strategy": "empty_space_strategy",
"prop_color": "RGB(0, 0, 0)",
"prop_font_family": "arial",
"prop_font_size": 8,
"prop_font_style": "B"
}
}
]
}
]
},
{
"value": 236.6975,
"type": "row",
"nodes": [
{
"value": 12,
"type": "col"
}
]
}
]
}
]
}

View File

@@ -201,7 +201,7 @@ func (sp *SARIFPrinter) printConfigurationScan(ctx context.Context, opaSessionOb
}
// If the fileType is helm chart
if templateNodes, ok := opaSessionObj.TemplateMapping[resourceID]; ok {
if templateNodes, ok := opaSessionObj.TemplateMapping[resourceID]; ok && len(templateNodes.Nodes) > 0 {
mappingnodes = templateNodes.Nodes
helmChartFileType = true
}
@@ -209,8 +209,7 @@ func (sp *SARIFPrinter) printConfigurationScan(ctx context.Context, opaSessionOb
rsrcAbsPath := path.Join(basePath, filepath)
locationResolver, err := locationresolver.NewFixPathLocationResolver(rsrcAbsPath) //
if err != nil && !helmChartFileType {
logger.L().Debug("failed to create location resolver", helpers.Error(err))
continue
logger.L().Debug("failed to create location resolver, will use default location", helpers.Error(err))
}
for _, toPin := range result.AssociatedControls {

View File

@@ -10,13 +10,14 @@ import (
)
func main() {
ks := core.NewKubescape()
ctx := context.TODO()
ks := core.NewKubescape(ctx)
downloads := []metav1.DownloadInfo{
{Target: "artifacts"}, // download all artifacts
{Target: "framework", Identifier: "security"}, // force add the "security" framework
}
for _, download := range downloads {
if err := ks.Download(context.Background(), &download); err != nil {
if err := ks.Download(&download); err != nil {
logger.L().Error("failed to download artifact", helpers.Error(err), helpers.String("target", download.Target))
}
}

445
go.mod
View File

@@ -1,19 +1,19 @@
module github.com/kubescape/kubescape/v3
go 1.22.5
go 1.23.6
toolchain go1.23.1
toolchain go1.24.2
require (
github.com/adrg/xdg v0.4.0
github.com/anchore/clio v0.0.0-20240209204744-cb94e40a4f65
github.com/anchore/grype v0.77.1
github.com/anchore/stereoscope v0.0.3-0.20240423181235-8b297badafd5
github.com/anchore/syft v1.3.0
github.com/adrg/xdg v0.5.3
github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837
github.com/anchore/grype v0.81.0
github.com/anchore/stereoscope v0.0.11
github.com/anchore/syft v1.18.1
github.com/anubhav06/copa-grype v1.0.3-alpha.1
github.com/armosec/armoapi-go v0.0.330
github.com/armosec/utils-go v0.0.57
github.com/armosec/utils-k8s-go v0.0.26
github.com/armosec/armoapi-go v0.0.562
github.com/armosec/utils-go v0.0.58
github.com/armosec/utils-k8s-go v0.0.30
github.com/briandowns/spinner v1.23.1
github.com/chainguard-dev/git-urls v1.0.2
github.com/distribution/reference v0.6.0
@@ -21,96 +21,105 @@ require (
github.com/enescakir/emoji v1.0.0
github.com/francoispqt/gojay v1.2.13
github.com/go-git/go-git/v5 v5.13.0
github.com/google/go-containerregistry v0.19.1
github.com/google/go-containerregistry v0.20.3
github.com/google/uuid v1.6.0
github.com/johnfercher/maroto v1.0.0
github.com/johnfercher/go-tree v1.1.0
github.com/johnfercher/maroto/v2 v2.2.2
github.com/json-iterator/go v1.1.12
github.com/jwalton/gchalk v1.3.0
github.com/kubescape/backend v0.0.20
github.com/kubescape/go-git-url v0.0.30
github.com/kubescape/go-logger v0.0.23
github.com/kubescape/k8s-interface v0.0.174
github.com/kubescape/opa-utils v0.0.284
github.com/kubescape/k8s-interface v0.0.195
github.com/kubescape/opa-utils v0.0.288
github.com/kubescape/rbac-utils v0.0.21-0.20230806101615-07e36f555520
github.com/kubescape/regolibrary/v2 v2.0.1
github.com/kubescape/sizing-checker v0.0.0-20250323151332-73a18561dc73
github.com/kubescape/storage v0.0.184
github.com/mark3labs/mcp-go v0.29.0
github.com/maruel/natural v1.1.1
github.com/matthyx/go-gitlog v0.0.0-20231005131906-9ffabe3c5bcd
github.com/mattn/go-isatty v0.0.20
github.com/mikefarah/yq/v4 v4.29.1
github.com/olekukonko/tablewriter v0.0.6-0.20230417144759-edd1a71a5576
github.com/open-policy-agent/opa v0.68.0
github.com/open-policy-agent/opa v1.3.0
github.com/owenrumney/go-sarif/v2 v2.2.0
github.com/project-copacetic/copacetic v0.4.1-0.20231017020916-013c118454b8
github.com/schollz/progressbar/v3 v3.13.0
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
github.com/sigstore/cosign/v2 v2.2.4
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.1
github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0
go.opentelemetry.io/otel v1.30.0
go.opentelemetry.io/otel/metric v1.30.0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/mod v0.19.0
golang.org/x/term v0.27.0
go.opentelemetry.io/otel v1.35.0
go.opentelemetry.io/otel/metric v1.35.0
golang.org/x/mod v0.24.0
golang.org/x/term v0.31.0
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.14.4
k8s.io/api v0.30.0
k8s.io/apimachinery v0.30.0
k8s.io/client-go v0.30.0
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3
helm.sh/helm/v3 v3.17.3
k8s.io/api v0.32.3
k8s.io/apimachinery v0.32.3
k8s.io/client-go v0.32.3
k8s.io/utils v0.0.0-20241210054802-24370beab758
sigs.k8s.io/kustomize/api v0.18.0
sigs.k8s.io/kustomize/kyaml v0.18.1
sigs.k8s.io/yaml v1.4.0
)
require github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
require (
cloud.google.com/go v0.112.1 // indirect
cloud.google.com/go/compute/metadata v0.5.0 // indirect
cloud.google.com/go/container v1.33.0 // indirect
cloud.google.com/go/iam v1.1.6 // indirect
cloud.google.com/go/storage v1.39.1 // indirect
dario.cat/mergo v1.0.0 // indirect
cel.dev/expr v0.19.1 // indirect
cloud.google.com/go v0.118.3 // indirect
cloud.google.com/go/auth v0.15.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/container v1.42.2 // indirect
cloud.google.com/go/iam v1.4.1 // indirect
cloud.google.com/go/monitoring v1.24.0 // indirect
cloud.google.com/go/storage v1.50.0 // indirect
dario.cat/mergo v1.0.1 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.1.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.29 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/CycloneDX/cyclonedx-go v0.8.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/CycloneDX/cyclonedx-go v0.9.1 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/Microsoft/hcsshim v0.11.7 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/ProtonMail/go-crypto v1.1.3 // indirect
github.com/Microsoft/hcsshim v0.12.9 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
github.com/a8m/envsubst v1.3.0 // indirect
github.com/acobaugh/osrelease v0.1.0 // indirect
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/alecthomas/participle/v2 v2.0.0-beta.5 // indirect
github.com/agnivade/levenshtein v1.2.1 // indirect
github.com/alecthomas/participle/v2 v2.1.0 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect
github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect
@@ -122,89 +131,93 @@ require (
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/aliyun/credentials-go v1.3.1 // indirect
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b // indirect
github.com/anchore/archiver/v3 v3.5.3-0.20241210171143-5b1d8d1c7c51 // indirect
github.com/anchore/fangs v0.0.0-20241014201141-b6e4b3469f10 // indirect
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537 // indirect
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a // indirect
github.com/anchore/go-logger v0.0.0-20241205183533-4fc29b5832e7 // indirect
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb // indirect
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect
github.com/anchore/packageurl-go v0.1.1-0.20240312213626-055233e539b4 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f // indirect
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
github.com/armosec/gojay v1.2.15 // indirect
github.com/armosec/gojay v1.2.17 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go v1.55.6-0.20240912145455-7112c0a0c2d0 // indirect
github.com/aws/aws-sdk-go-v2 v1.30.5 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.35 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.33 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go v1.55.6 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.10 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.63 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ecr v1.34.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.7 // indirect
github.com/aws/aws-sdk-go-v2/service/eks v1.48.5 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.35.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect
github.com/aws/aws-sdk-go-v2/service/kms v1.35.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.8 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.8 // indirect
github.com/aws/smithy-go v1.20.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect
github.com/aws/smithy-go v1.22.2 // indirect
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/bmatcuk/doublestar/v2 v2.0.4 // indirect
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
github.com/boombuler/barcode v1.0.2 // indirect
github.com/bugsnag/bugsnag-go/v2 v2.3.0 // indirect
github.com/bugsnag/panicwrap v1.3.4 // indirect
github.com/buildkite/agent/v3 v3.62.0 // indirect
github.com/buildkite/go-pipeline v0.3.2 // indirect
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charmbracelet/lipgloss v0.10.0 // indirect
github.com/charmbracelet/lipgloss v1.0.0 // indirect
github.com/charmbracelet/x/ansi v0.4.5 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
github.com/cilium/cilium v1.16.9 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cloudflare/circl v1.3.8 // indirect
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/containerd/containerd v1.7.21 // indirect
github.com/containerd/containerd/api v1.7.19 // indirect
github.com/containerd/continuity v0.4.2 // indirect
github.com/containerd/errdefs v0.1.0 // indirect
github.com/containerd/cgroups/v3 v3.0.5 // indirect
github.com/containerd/console v1.0.4 // indirect
github.com/containerd/containerd v1.7.27 // indirect
github.com/containerd/containerd/api v1.8.0 // indirect
github.com/containerd/continuity v0.4.4 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect
github.com/containerd/ttrpc v1.2.5 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
github.com/coreos/go-oidc/v3 v3.10.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
github.com/containerd/typeurl/v2 v2.2.3 // indirect
github.com/containers/common v0.63.0 // indirect
github.com/coreos/go-oidc/v3 v3.14.1 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/cpuguy83/go-docker v0.2.1 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da // indirect
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/docker/buildx v0.11.2 // indirect
github.com/docker/cli v26.1.0+incompatible // indirect
github.com/docker/docker v26.1.5+incompatible // indirect
github.com/docker/docker-credential-helpers v0.8.0 // indirect
github.com/docker/cli v27.5.0+incompatible // indirect
github.com/docker/docker v28.0.4+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.5.0 // indirect
@@ -214,17 +227,20 @@ require (
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/elliotchance/orderedmap v1.5.0 // indirect
github.com/elliotchance/phpserialize v1.4.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/f-amaral/go-async v0.3.0 // indirect
github.com/facebookincubator/nvdtools v0.1.5 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/felixge/fgprof v0.9.3 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/github/go-spdx/v2 v2.2.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
github.com/github/go-spdx/v2 v2.3.2 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/glebarez/sqlite v1.11.0 // indirect
github.com/go-chi/chi v4.1.2+incompatible // indirect
@@ -233,63 +249,64 @@ require (
github.com/go-git/go-billy/v5 v5.6.0 // indirect
github.com/go-gota/gota v0.12.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/errors v0.22.1 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/loads v0.22.0 // indirect
github.com/go-openapi/runtime v0.28.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/swag v0.23.1 // indirect
github.com/go-openapi/validate v0.24.0 // indirect
github.com/go-piv/piv-go v1.11.0 // indirect
github.com/go-restruct/restruct v1.2.0-alpha // indirect
github.com/go-test/deep v1.1.0 // indirect
github.com/go-test/deep v1.1.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/goccy/go-yaml v1.9.6 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/gofrs/uuid v4.3.1+incompatible // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/certificate-transparency-go v1.1.8 // indirect
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/certificate-transparency-go v1.3.1 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-github/v55 v55.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/licensecheck v0.3.1 // indirect
github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/gorilla/mux v1.8.1 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.5 // indirect
github.com/hashicorp/go-getter v1.7.6 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
github.com/hhrutter/lzw v1.0.0 // indirect
github.com/hhrutter/tiff v1.0.1 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/in-toto/in-toto-golang v0.9.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
@@ -297,26 +314,27 @@ require (
github.com/jinzhu/copier v0.4.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/jung-kurt/gofpdf v1.16.2 // indirect
github.com/jwalton/go-supportscolor v1.1.0 // indirect
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f // indirect
github.com/knqyf263/go-deb-version v0.0.0-20230223133812-3ed183d23422 // indirect
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075 // indirect
github.com/knqyf263/go-rpmdb v0.1.0 // indirect
github.com/knqyf263/go-rpmdb v0.1.1 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 // indirect
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mackerelio/go-osstat v0.2.5 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mholt/archiver/v3 v3.5.1 // indirect
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032 // indirect
@@ -332,11 +350,11 @@ require (
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/sys/mountinfo v0.7.1 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/sys/mountinfo v0.7.2 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect
github.com/moby/sys/user v0.3.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -344,73 +362,77 @@ require (
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/mozillazg/docker-credential-acr-helper v0.3.0 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/oleiade/reflections v1.0.1 // indirect
github.com/olvrng/ujson v1.1.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/opencontainers/runtime-spec v1.1.0 // indirect
github.com/opencontainers/selinux v1.11.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runtime-spec v1.2.1 // indirect
github.com/opencontainers/selinux v1.12.0 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/openvex/go-vex v0.2.5 // indirect
github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554 // indirect
github.com/package-url/packageurl-go v0.1.2-0.20230812223828-f8bb31c1f10b // indirect
github.com/pborman/indent v1.2.1 // indirect
github.com/pborman/uuid v1.2.1 // indirect
github.com/pdfcpu/pdfcpu v0.9.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/profile v1.7.0 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pquerna/cachecontrol v0.2.0 // indirect
github.com/prometheus/client_golang v1.20.2 // indirect
github.com/prometheus/client_golang v1.21.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 // indirect
github.com/saferwall/pe v1.5.2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/saferwall/pe v1.5.6 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
github.com/sassoftware/go-rpmutils v0.3.0 // indirect
github.com/sasha-s/go-deadlock v0.3.5 // indirect
github.com/sassoftware/go-rpmutils v0.4.0 // indirect
github.com/sassoftware/relic v7.2.1+incompatible // indirect
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect
github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect
github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d // indirect
github.com/seccomp/libseccomp-golang v0.10.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sigstore/fulcio v1.4.5 // indirect
github.com/sigstore/rekor v1.3.6 // indirect
github.com/sigstore/sigstore v1.8.3 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sigstore/fulcio v1.6.6 // indirect
github.com/sigstore/protobuf-specs v0.4.1 // indirect
github.com/sigstore/rekor v1.3.10 // indirect
github.com/sigstore/sigstore v1.9.3 // indirect
github.com/sigstore/timestamp-authority v1.2.2 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spdx/tools-golang v0.5.4 // indirect
github.com/spdx/tools-golang v0.5.5 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.18.2 // indirect
github.com/spiffe/go-spiffe/v2 v2.2.0 // indirect
github.com/stripe/stripe-go/v74 v74.28.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/spf13/viper v1.19.0 // indirect
github.com/spiffe/go-spiffe/v2 v2.4.0 // indirect
github.com/stripe/stripe-go/v74 v74.30.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/sylabs/sif/v2 v2.11.5 // indirect
github.com/sylabs/squashfs v0.6.1 // indirect
github.com/sylabs/sif/v2 v2.21.1 // indirect
github.com/sylabs/squashfs v1.0.4 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/tchap/go-patricia/v2 v2.3.2 // indirect
github.com/thales-e-security/pool v0.0.2 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/theupdateframework/go-tuf v0.7.0 // indirect
@@ -421,16 +443,19 @@ require (
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea // indirect
github.com/tonistiigi/vt100 v0.0.0-20230623042737-f9a4f7ef6531 // indirect
github.com/transparency-dev/merkle v0.0.2 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect
github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 // indirect
github.com/uptrace/opentelemetry-go-extra/otelzap v0.3.2 // indirect
github.com/uptrace/uptrace-go v1.30.1 // indirect
github.com/vbatts/go-mtree v0.5.3 // indirect
github.com/vbatts/tar-split v0.11.5 // indirect
github.com/vbatts/go-mtree v0.5.4 // indirect
github.com/vbatts/tar-split v0.12.1 // indirect
github.com/vifraa/gopom v1.0.0 // indirect
github.com/vishvananda/netlink v1.3.1-0.20241022031324-976bd8de7d81 // indirect
github.com/vishvananda/netns v0.0.5 // indirect
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 // indirect
github.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b // indirect
github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/go-gitlab v0.102.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
@@ -438,68 +463,74 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
github.com/yl2chen/cidranger v1.0.2 // indirect
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
github.com/zclconf/go-cty v1.14.0 // indirect
github.com/zeebo/errs v1.3.0 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
go.mongodb.org/mongo-driver v1.17.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.44.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/contrib/instrumentation/runtime v0.55.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.6.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.41.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.41.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.30.0 // indirect
go.opentelemetry.io/otel/log v0.6.0 // indirect
go.opentelemetry.io/otel/sdk v1.30.0 // indirect
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.6.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect
go.opentelemetry.io/otel/trace v1.30.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
go.step.sm/crypto v0.44.2 // indirect
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.step.sm/crypto v0.60.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
golang.org/x/image v0.24.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/oauth2 v0.29.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
gonum.org/v1/gonum v0.9.1 // indirect
google.golang.org/api v0.172.0 // indirect
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.67.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect
google.golang.org/api v0.228.0 // indirect
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
google.golang.org/grpc v1.71.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gorm.io/gorm v1.25.10 // indirect
k8s.io/apiextensions-apiserver v0.29.0 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
modernc.org/libc v1.49.3 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.29.8 // indirect
sigs.k8s.io/controller-runtime v0.15.0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/release-utils v0.7.7 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
gorm.io/gorm v1.25.12 // indirect
k8s.io/apiextensions-apiserver v0.32.2 // indirect
k8s.io/apiserver v0.32.3 // indirect
k8s.io/component-base v0.32.3 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
modernc.org/libc v1.61.13 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.8.2 // indirect
modernc.org/sqlite v1.36.2 // indirect
sigs.k8s.io/controller-runtime v0.18.4 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/release-utils v0.9.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
)
// Using the forked version of tablewriter
@@ -512,3 +543,9 @@ replace github.com/google/go-containerregistry => github.com/matthyx/go-containe
replace github.com/docker/distribution v2.8.3+incompatible => github.com/docker/distribution v2.8.2+incompatible
replace github.com/mholt/archiver/v3 v3.5.1 => github.com/anchore/archiver/v3 v3.5.2
replace github.com/docker/docker => github.com/docker/docker v26.1.5+incompatible
replace github.com/docker/cli => github.com/docker/cli v26.1.0+incompatible
replace github.com/sylabs/squashfs => github.com/sylabs/squashfs v0.6.1

1091
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -1,93 +1,99 @@
module github.com/kubescape/kubescape/v3/httphandler
go 1.22.5
go 1.23.6
toolchain go1.23.1
toolchain go1.24.2
replace github.com/kubescape/kubescape/v3 => ../
require (
github.com/armosec/armoapi-go v0.0.330
github.com/armosec/utils-go v0.0.57
github.com/armosec/utils-k8s-go v0.0.26
github.com/armosec/armoapi-go v0.0.562
github.com/armosec/utils-go v0.0.58
github.com/armosec/utils-k8s-go v0.0.30
github.com/go-openapi/runtime v0.28.0
github.com/google/uuid v1.6.0
github.com/gorilla/mux v1.8.1
github.com/gorilla/schema v1.4.1
github.com/kubescape/backend v0.0.20
github.com/kubescape/go-logger v0.0.23
github.com/kubescape/k8s-interface v0.0.174
github.com/kubescape/k8s-interface v0.0.195
github.com/kubescape/kubescape/v3 v3.0.4
github.com/kubescape/opa-utils v0.0.284
github.com/kubescape/storage v0.0.111
github.com/spf13/viper v1.18.2
github.com/kubescape/opa-utils v0.0.288
github.com/kubescape/storage v0.0.184
github.com/spf13/viper v1.19.0
github.com/stretchr/testify v1.10.0
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.45.0
go.opentelemetry.io/otel v1.30.0
k8s.io/apimachinery v0.30.0
k8s.io/client-go v0.30.0
k8s.io/utils v0.0.0-20231127182322-b307cd553661
go.opentelemetry.io/otel v1.35.0
k8s.io/apimachinery v0.32.3
k8s.io/client-go v0.32.3
k8s.io/utils v0.0.0-20241210054802-24370beab758
)
require (
go.opentelemetry.io/otel/trace v1.30.0
go.opentelemetry.io/otel/trace v1.35.0
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.22.0 // indirect
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect
google.golang.org/grpc v1.67.0 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/oauth2 v0.29.0 // indirect
google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/grpc v1.71.0 // indirect
)
require (
cloud.google.com/go v0.112.1 // indirect
cloud.google.com/go/compute/metadata v0.5.0 // indirect
cloud.google.com/go/container v1.33.0 // indirect
cloud.google.com/go/iam v1.1.6 // indirect
cloud.google.com/go/storage v1.39.1 // indirect
dario.cat/mergo v1.0.0 // indirect
cel.dev/expr v0.19.1 // indirect
cloud.google.com/go v0.118.3 // indirect
cloud.google.com/go/auth v0.15.0 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.6.0 // indirect
cloud.google.com/go/container v1.42.2 // indirect
cloud.google.com/go/iam v1.4.1 // indirect
cloud.google.com/go/monitoring v1.24.0 // indirect
cloud.google.com/go/storage v1.50.0 // indirect
dario.cat/mergo v1.0.1 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect
github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 // indirect
github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.6.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.8.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization v1.0.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization/v2 v2.1.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v2 v2.4.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.29 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.23 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.12 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 // indirect
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/CycloneDX/cyclonedx-go v0.8.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.3 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/CycloneDX/cyclonedx-go v0.9.1 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.49.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.49.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/Microsoft/hcsshim v0.12.5 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
github.com/ProtonMail/go-crypto v1.1.3 // indirect
github.com/Microsoft/hcsshim v0.12.9 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
github.com/a8m/envsubst v1.3.0 // indirect
github.com/acobaugh/osrelease v0.1.0 // indirect
github.com/adrg/xdg v0.4.0 // indirect
github.com/adrg/xdg v0.5.3 // indirect
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect
github.com/agnivade/levenshtein v1.1.1 // indirect
github.com/alecthomas/participle/v2 v2.0.0-beta.5 // indirect
github.com/agnivade/levenshtein v1.2.1 // indirect
github.com/alecthomas/participle/v2 v2.1.0 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect
github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect
github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect
@@ -99,83 +105,87 @@ require (
github.com/alibabacloud-go/tea-utils v1.4.5 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/aliyun/credentials-go v1.3.1 // indirect
github.com/anchore/clio v0.0.0-20240209204744-cb94e40a4f65 // indirect
github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b // indirect
github.com/anchore/archiver/v3 v3.5.3-0.20241210171143-5b1d8d1c7c51 // indirect
github.com/anchore/clio v0.0.0-20241115144204-29e89f9fa837 // indirect
github.com/anchore/fangs v0.0.0-20241014201141-b6e4b3469f10 // indirect
github.com/anchore/go-collections v0.0.0-20240216171411-9321230ce537 // indirect
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a // indirect
github.com/anchore/go-logger v0.0.0-20241205183533-4fc29b5832e7 // indirect
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb // indirect
github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect
github.com/anchore/go-version v1.2.2-0.20210903204242-51efa5b487c4 // indirect
github.com/anchore/grype v0.77.1 // indirect
github.com/anchore/packageurl-go v0.1.1-0.20240312213626-055233e539b4 // indirect
github.com/anchore/stereoscope v0.0.3-0.20240423181235-8b297badafd5 // indirect
github.com/anchore/syft v1.3.0 // indirect
github.com/andybalholm/brotli v1.0.4 // indirect
github.com/anchore/grype v0.81.0 // indirect
github.com/anchore/packageurl-go v0.1.1-0.20241018175412-5c22e6360c4f // indirect
github.com/anchore/stereoscope v0.0.11 // indirect
github.com/anchore/syft v1.18.1 // indirect
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/anubhav06/copa-grype v1.0.3-alpha.1 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 // indirect
github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 // indirect
github.com/armosec/gojay v1.2.15 // indirect
github.com/armosec/gojay v1.2.17 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/aws/aws-sdk-go v1.55.6-0.20240912145455-7112c0a0c2d0 // indirect
github.com/aws/aws-sdk-go-v2 v1.30.5 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.35 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.33 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go v1.55.6 // indirect
github.com/aws/aws-sdk-go-v2 v1.36.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.29.10 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.63 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.30 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect
github.com/aws/aws-sdk-go-v2/service/ecr v1.34.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.7 // indirect
github.com/aws/aws-sdk-go-v2/service/eks v1.48.5 // indirect
github.com/aws/aws-sdk-go-v2/service/iam v1.35.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.8 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.30.8 // indirect
github.com/aws/smithy-go v1.20.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.25.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect
github.com/aws/smithy-go v1.22.2 // indirect
github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/becheran/wildmatch-go v1.0.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/bmatcuk/doublestar/v2 v2.0.4 // indirect
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
github.com/boombuler/barcode v1.0.2 // indirect
github.com/briandowns/spinner v1.23.1 // indirect
github.com/buildkite/agent/v3 v3.62.0 // indirect
github.com/buildkite/go-pipeline v0.3.2 // indirect
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 // indirect
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chainguard-dev/git-urls v1.0.2 // indirect
github.com/charmbracelet/lipgloss v0.10.0 // indirect
github.com/charmbracelet/lipgloss v1.0.0 // indirect
github.com/charmbracelet/x/ansi v0.4.5 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
github.com/cilium/cilium v1.16.9 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cloudflare/circl v1.3.8 // indirect
github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
github.com/containerd/cgroups/v3 v3.0.3 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/containerd/containerd v1.7.21 // indirect
github.com/containerd/containerd/api v1.7.19 // indirect
github.com/containerd/continuity v0.4.2 // indirect
github.com/containerd/errdefs v0.1.0 // indirect
github.com/containerd/cgroups/v3 v3.0.5 // indirect
github.com/containerd/console v1.0.4 // indirect
github.com/containerd/containerd v1.7.27 // indirect
github.com/containerd/containerd/api v1.8.0 // indirect
github.com/containerd/continuity v0.4.4 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
github.com/containerd/ttrpc v1.2.5 // indirect
github.com/containerd/typeurl/v2 v2.1.1 // indirect
github.com/containers/common v0.60.4 // indirect
github.com/coreos/go-oidc v2.2.1+incompatible // indirect
github.com/coreos/go-oidc/v3 v3.10.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
github.com/containerd/typeurl/v2 v2.2.3 // indirect
github.com/containers/common v0.63.0 // indirect
github.com/coreos/go-oidc/v3 v3.14.1 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/cpuguy83/go-docker v0.2.1 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20231217050601-ba74d44ecf5f // indirect
github.com/cyphar/filepath-securejoin v0.3.1 // indirect
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da // indirect
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
@@ -183,10 +193,10 @@ require (
github.com/dimchansky/utfbom v1.1.1 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/buildx v0.11.2 // indirect
github.com/docker/cli v26.1.0+incompatible // indirect
github.com/docker/cli v27.5.0+incompatible // indirect
github.com/docker/distribution v2.8.3+incompatible // indirect
github.com/docker/docker v27.1.1+incompatible // indirect
github.com/docker/docker-credential-helpers v0.8.2 // indirect
github.com/docker/docker v28.0.4+incompatible // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-connections v0.5.0 // indirect
github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect
@@ -197,19 +207,22 @@ require (
github.com/edsrzf/mmap-go v1.1.0 // indirect
github.com/elliotchance/orderedmap v1.5.0 // indirect
github.com/elliotchance/phpserialize v1.4.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/enescakir/emoji v1.0.0 // indirect
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/f-amaral/go-async v0.3.0 // indirect
github.com/facebookincubator/nvdtools v0.1.5 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/felixge/fgprof v0.9.3 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/github/go-spdx/v2 v2.2.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.7 // indirect
github.com/github/go-spdx/v2 v2.3.2 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/glebarez/sqlite v1.11.0 // indirect
github.com/go-chi/chi v4.1.2+incompatible // indirect
@@ -219,62 +232,63 @@ require (
github.com/go-git/go-git/v5 v5.13.0 // indirect
github.com/go-gota/gota v0.12.0 // indirect
github.com/go-ini/ini v1.67.0 // indirect
github.com/go-jose/go-jose/v3 v3.0.3 // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-openapi/analysis v0.23.0 // indirect
github.com/go-openapi/errors v0.22.0 // indirect
github.com/go-openapi/errors v0.22.1 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/loads v0.22.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/strfmt v0.23.0 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/go-openapi/swag v0.23.1 // indirect
github.com/go-openapi/validate v0.24.0 // indirect
github.com/go-piv/piv-go v1.11.0 // indirect
github.com/go-restruct/restruct v1.2.0-alpha // indirect
github.com/go-test/deep v1.1.0 // indirect
github.com/go-test/deep v1.1.1 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/goccy/go-yaml v1.9.6 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/gogo/googleapis v1.4.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.1 // indirect
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/certificate-transparency-go v1.1.8 // indirect
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-containerregistry v0.20.0 // indirect
github.com/google/certificate-transparency-go v1.3.1 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/go-containerregistry v0.20.3 // indirect
github.com/google/go-github/v55 v55.0.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/licensecheck v0.3.1 // indirect
github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.3 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gorilla/websocket v1.5.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.7.5 // indirect
github.com/hashicorp/go-getter v1.7.6 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.6.0 // indirect
github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
github.com/hhrutter/lzw v1.0.0 // indirect
github.com/hhrutter/tiff v1.0.1 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/in-toto/in-toto-golang v0.9.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
@@ -282,8 +296,9 @@ require (
github.com/jinzhu/copier v0.4.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/johnfercher/maroto v1.0.0 // indirect
github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 // indirect
github.com/johnfercher/go-tree v1.1.0 // indirect
github.com/johnfercher/maroto/v2 v2.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jung-kurt/gofpdf v1.16.2 // indirect
@@ -291,20 +306,21 @@ require (
github.com/jwalton/go-supportscolor v1.1.0 // indirect
github.com/kastenhq/goversion v0.0.0-20230811215019-93b2f8823953 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.17.9 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/pgzip v1.2.6 // indirect
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f // indirect
github.com/knqyf263/go-deb-version v0.0.0-20230223133812-3ed183d23422 // indirect
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075 // indirect
github.com/knqyf263/go-rpmdb v0.1.0 // indirect
github.com/knqyf263/go-rpmdb v0.1.1 // indirect
github.com/kubescape/go-git-url v0.0.30 // indirect
github.com/kubescape/rbac-utils v0.0.21-0.20230806101615-07e36f555520 // indirect
github.com/kubescape/regolibrary/v2 v2.0.1 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/letsencrypt/boulder v0.0.0-20240418210053-89b07f4543e0 // indirect
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mackerelio/go-osstat v0.2.5 // indirect
github.com/magiconair/properties v1.8.9 // indirect
github.com/mailru/easyjson v0.9.0 // indirect
github.com/maruel/natural v1.1.1 // indirect
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 // indirect
github.com/matthyx/go-gitlog v0.0.0-20231005131906-9ffabe3c5bcd // indirect
@@ -327,11 +343,11 @@ require (
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/locker v1.0.1 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/sys/mountinfo v0.7.2 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/sys/signal v0.7.0 // indirect
github.com/moby/sys/user v0.3.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -339,82 +355,85 @@ require (
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/mozillazg/docker-credential-acr-helper v0.3.0 // indirect
github.com/muesli/reflow v0.3.0 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/nwaples/rardecode v1.1.3 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/oleiade/reflections v1.0.1 // indirect
github.com/olekukonko/tablewriter v0.0.6-0.20230417144759-edd1a71a5576 // indirect
github.com/olvrng/ujson v1.1.0 // indirect
github.com/open-policy-agent/opa v0.68.0 // indirect
github.com/open-policy-agent/opa v1.3.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/opencontainers/runtime-spec v1.2.0 // indirect
github.com/opencontainers/selinux v1.11.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/opencontainers/runtime-spec v1.2.1 // indirect
github.com/opencontainers/selinux v1.12.0 // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/openvex/go-vex v0.2.5 // indirect
github.com/owenrumney/go-sarif v1.1.2-0.20231003122901-1000f5e05554 // indirect
github.com/owenrumney/go-sarif/v2 v2.3.0 // indirect
github.com/package-url/packageurl-go v0.1.2 // indirect
github.com/pborman/indent v1.2.1 // indirect
github.com/pborman/uuid v1.2.1 // indirect
github.com/pdfcpu/pdfcpu v0.9.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/petermattis/goid v0.0.0-20241211131331-93ee7e083c43 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/profile v1.7.0 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/pquerna/cachecontrol v0.2.0 // indirect
github.com/project-copacetic/copacetic v0.4.1-0.20231017020916-013c118454b8 // indirect
github.com/prometheus/client_golang v1.20.2 // indirect
github.com/prometheus/client_golang v1.21.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.55.0 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245 // indirect
github.com/saferwall/pe v1.5.2 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/saferwall/pe v1.5.6 // indirect
github.com/sagikazarmark/locafero v0.6.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
github.com/sassoftware/go-rpmutils v0.3.0 // indirect
github.com/sasha-s/go-deadlock v0.3.5 // indirect
github.com/sassoftware/go-rpmutils v0.4.0 // indirect
github.com/sassoftware/relic v7.2.1+incompatible // indirect
github.com/schollz/progressbar/v3 v3.13.0 // indirect
github.com/scylladb/go-set v1.0.3-0.20200225121959-cc7b2070d91e // indirect
github.com/secDre4mer/pkcs7 v0.0.0-20240322103146-665324a4461d // indirect
github.com/seccomp/libseccomp-golang v0.10.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.8.0 // indirect
github.com/secure-systems-lab/go-securesystemslib v0.9.0 // indirect
github.com/segmentio/ksuid v1.0.4 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/sigstore/cosign/v2 v2.2.4 // indirect
github.com/sigstore/fulcio v1.4.5 // indirect
github.com/sigstore/rekor v1.3.6 // indirect
github.com/sigstore/sigstore v1.8.4 // indirect
github.com/sigstore/fulcio v1.6.6 // indirect
github.com/sigstore/protobuf-specs v0.4.1 // indirect
github.com/sigstore/rekor v1.3.10 // indirect
github.com/sigstore/sigstore v1.9.3 // indirect
github.com/sigstore/timestamp-authority v1.2.2 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spdx/tools-golang v0.5.4 // indirect
github.com/spdx/tools-golang v0.5.5 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spiffe/go-spiffe/v2 v2.2.0 // indirect
github.com/stripe/stripe-go/v74 v74.28.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/cobra v1.9.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/spiffe/go-spiffe/v2 v2.4.0 // indirect
github.com/stripe/stripe-go/v74 v74.30.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/sylabs/sif/v2 v2.18.0 // indirect
github.com/sylabs/squashfs v0.6.1 // indirect
github.com/sylabs/sif/v2 v2.21.1 // indirect
github.com/sylabs/squashfs v1.0.4 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect
github.com/tchap/go-patricia/v2 v2.3.1 // indirect
github.com/tchap/go-patricia/v2 v2.3.2 // indirect
github.com/thales-e-security/pool v0.0.2 // indirect
github.com/therootcompany/xz v1.0.1 // indirect
github.com/theupdateframework/go-tuf v0.7.0 // indirect
@@ -429,12 +448,15 @@ require (
github.com/uptrace/opentelemetry-go-extra/otelutil v0.3.2 // indirect
github.com/uptrace/opentelemetry-go-extra/otelzap v0.3.2 // indirect
github.com/uptrace/uptrace-go v1.30.1 // indirect
github.com/vbatts/go-mtree v0.5.3 // indirect
github.com/vbatts/tar-split v0.11.5 // indirect
github.com/vbatts/go-mtree v0.5.4 // indirect
github.com/vbatts/tar-split v0.12.1 // indirect
github.com/vifraa/gopom v1.0.0 // indirect
github.com/vishvananda/netlink v1.3.1-0.20241022031324-976bd8de7d81 // indirect
github.com/vishvananda/netns v0.0.5 // indirect
github.com/wagoodman/go-partybus v0.0.0-20230516145632-8ccac152c651 // indirect
github.com/wagoodman/go-presenter v0.0.0-20211015174752-f9c01afc824b // indirect
github.com/wagoodman/go-progress v0.0.0-20230925121702-07e42b3cdba0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/go-gitlab v0.102.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
@@ -442,67 +464,72 @@ require (
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yashtewari/glob-intersection v0.2.0 // indirect
github.com/yl2chen/cidranger v1.0.2 // indirect
github.com/zclconf/go-cty v1.14.4 // indirect
github.com/zeebo/errs v1.3.0 // indirect
go.mongodb.org/mongo-driver v1.14.0 // indirect
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 // indirect
go.mongodb.org/mongo-driver v1.17.1 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.34.0 // indirect
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.44.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/contrib/instrumentation/runtime v0.55.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.6.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.41.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.41.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.30.0 // indirect
go.opentelemetry.io/otel/log v0.6.0 // indirect
go.opentelemetry.io/otel/metric v1.30.0 // indirect
go.opentelemetry.io/otel/sdk v1.30.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
go.opentelemetry.io/otel/sdk/log v0.6.0 // indirect
go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
go.step.sm/crypto v0.44.2 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.27.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
go.step.sm/crypto v0.60.0 // indirect
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/image v0.24.0 // indirect
golang.org/x/sync v0.13.0 // indirect
golang.org/x/sys v0.32.0 // indirect
golang.org/x/term v0.31.0 // indirect
golang.org/x/text v0.24.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect
gonum.org/v1/gonum v0.9.1 // indirect
google.golang.org/api v0.172.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/protobuf v1.34.2 // indirect
google.golang.org/api v0.228.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
gorm.io/gorm v1.25.10 // indirect
helm.sh/helm/v3 v3.14.4 // indirect
k8s.io/api v0.30.0 // indirect
k8s.io/apiextensions-apiserver v0.29.0 // indirect
gorm.io/gorm v1.25.12 // indirect
helm.sh/helm/v3 v3.17.3 // indirect
k8s.io/api v0.32.3 // indirect
k8s.io/apiextensions-apiserver v0.32.2 // indirect
k8s.io/apiserver v0.32.3 // indirect
k8s.io/component-base v0.32.3 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
modernc.org/libc v1.49.3 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.29.8 // indirect
sigs.k8s.io/controller-runtime v0.15.0 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/release-utils v0.7.7 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 // indirect
modernc.org/libc v1.61.13 // indirect
modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.8.2 // indirect
modernc.org/sqlite v1.36.2 // indirect
sigs.k8s.io/controller-runtime v0.18.4 // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/kustomize/api v0.18.0 // indirect
sigs.k8s.io/kustomize/kyaml v0.18.1 // indirect
sigs.k8s.io/release-utils v0.9.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.5.0 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
@@ -514,3 +541,9 @@ replace github.com/docker/distribution v2.8.3+incompatible => github.com/docker/
replace github.com/docker/docker v27.1.1+incompatible => github.com/docker/docker v26.1.5+incompatible
replace github.com/mholt/archiver/v3 v3.5.1 => github.com/anchore/archiver/v3 v3.5.2
replace github.com/docker/docker => github.com/docker/docker v26.1.5+incompatible
replace github.com/docker/cli => github.com/docker/cli v26.1.0+incompatible
replace github.com/sylabs/squashfs => github.com/sylabs/squashfs v0.6.1

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,15 @@
package v1
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/armosec/armoapi-go/armotypes"
"github.com/kubescape/go-logger"
"github.com/kubescape/go-logger/helpers"
"github.com/kubescape/kubescape/v3/core/cautils"
"github.com/kubescape/kubescape/v3/core/cautils/getter"
apisv1 "github.com/kubescape/opa-utils/httpserver/apis/v1"
@@ -67,6 +74,15 @@ func ToScanInfo(scanRequest *utilsmetav1.PostScanRequest) *cautils.ScanInfo {
scanInfo.IsDeletedScanObject = *scanRequest.IsDeletedScanObject
}
if scanRequest.Exceptions != nil {
path, err := saveExceptions(scanRequest.Exceptions)
if err != nil {
logger.L().Warning("failed to save exceptions, scanning without them", helpers.Error(err))
} else {
scanInfo.UseExceptions = path
}
}
return scanInfo
}
@@ -92,3 +108,15 @@ func setTargetInScanInfo(scanRequest *utilsmetav1.PostScanRequest, scanInfo *cau
scanInfo.ScanAll = true
}
}
func saveExceptions(exceptions []armotypes.PostureExceptionPolicy) (string, error) {
exceptionsJSON, err := json.Marshal(exceptions)
if err != nil {
return "", fmt.Errorf("failed to marshal exceptions: %w", err)
}
exceptionsPath := filepath.Join("/tmp", "exceptions.json") // FIXME potential race condition
if err := os.WriteFile(exceptionsPath, exceptionsJSON, 0644); err != nil {
return "", fmt.Errorf("failed to write exceptions file to disk: %w", err)
}
return exceptionsPath, nil
}

View File

@@ -66,7 +66,7 @@ func scan(ctx context.Context, scanInfo *cautils.ScanInfo, scanID string) (*repo
ctx, spanScan := otel.Tracer("").Start(ctx, "kubescape.scan")
defer spanScan.End()
ks := core.NewKubescape()
ks := core.NewKubescape(ctx)
spanScan.AddEvent("scanning metadata",
trace.WithAttributes(attribute.String("version", versioncheck.BuildNumber)),
@@ -79,7 +79,7 @@ func scan(ctx context.Context, scanInfo *cautils.ScanInfo, scanID string) (*repo
trace.WithAttributes(attribute.String("hostSensorYamlPath", scanInfo.HostSensorYamlPath)),
)
result, err := ks.Scan(ctx, scanInfo)
result, err := ks.Scan(scanInfo)
if err != nil {
return nil, writeScanErrorToFile(err, scanID)
}

View File

@@ -19,7 +19,7 @@ import (
_ "github.com/kubescape/kubescape/v3/httphandler/docs"
"github.com/kubescape/kubescape/v3/httphandler/listener"
"github.com/kubescape/kubescape/v3/httphandler/storage"
"k8s.io/client-go/rest"
"github.com/kubescape/kubescape/v3/pkg/ksinit"
)
const (
@@ -68,19 +68,13 @@ func initializeStorage(clusterName string, cfg config.Config) {
namespace := getNamespace(cfg)
logger.L().Debug("initializing storage", helpers.String("namespace", namespace))
// for local storage, use the k8s config
var config *rest.Config
if os.Getenv("LOCAL_STORAGE") == "true" {
config = k8sinterface.GetK8sConfig()
} else {
var err error
config, err = rest.InClusterConfig()
if err != nil {
logger.L().Fatal("storage initialization error", helpers.Error(err))
}
// Use shared ksinit logic for storage connection
ksClient, err := ksinit.CreateKsObjectConnection(namespace, 0)
if err != nil {
logger.L().Fatal("storage initialization error", helpers.Error(err))
}
s, err := storage.NewAPIServerStorage(clusterName, namespace, config)
s, err := storage.NewAPIServerStorage(clusterName, namespace, ksClient)
if err != nil {
logger.L().Fatal("storage initialization error", helpers.Error(err))
}

View File

@@ -19,12 +19,10 @@ import (
"github.com/kubescape/opa-utils/reporthandling/results/v1/resourcesresults"
v2 "github.com/kubescape/opa-utils/reporthandling/v2"
"github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
"github.com/kubescape/storage/pkg/generated/clientset/versioned"
spdxv1beta1 "github.com/kubescape/storage/pkg/generated/clientset/versioned/typed/softwarecomposition/v1beta1"
"go.opentelemetry.io/otel"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/util/retry"
)
@@ -54,19 +52,9 @@ func GetStorage() *APIServerStore {
}
// NewAPIServerStorage initializes the APIServerStore struct
func NewAPIServerStorage(clusterName string, namespace string, config *rest.Config) (*APIServerStore, error) {
// disable rate limiting
config.QPS = 0
config.RateLimiter = nil
// force GRPC
config.AcceptContentTypes = "application/vnd.kubernetes.protobuf"
config.ContentType = "application/vnd.kubernetes.protobuf"
clientset, err := versioned.NewForConfig(config)
if err != nil {
return nil, err
}
func NewAPIServerStorage(clusterName string, namespace string, ksClient spdxv1beta1.SpdxV1beta1Interface) (*APIServerStore, error) {
return &APIServerStore{
StorageClient: clientset.SpdxV1beta1(),
StorageClient: ksClient,
clusterName: clusterName,
namespace: namespace,
}, nil
@@ -178,15 +166,6 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResult(ctx context.Contex
},
}
// This is a workaround for the fact that the apiserver does not return already exist error on Create
existing, err := a.StorageClient.WorkloadConfigurationScans(namespace).Get(context.Background(), manifest.Name, metav1.GetOptions{})
if err == nil {
logger.L().Debug("found existing WorkloadConfigurationScan manifest in storage - merging manifests", helpers.String("name", manifest.Name))
manifest.Annotations = existing.Annotations
manifest.Labels = existing.Labels
manifest.Spec = mergeWorkloadConfigurationScanSpec(existing.Spec, manifest.Spec)
}
_, err = a.StorageClient.WorkloadConfigurationScans(namespace).Create(context.Background(), &manifest, metav1.CreateOptions{})
switch {
case errors.IsAlreadyExists(err):
@@ -198,8 +177,8 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResult(ctx context.Contex
return getErr
}
// update the workload configuration scan manifest
result.Annotations = manifest.Annotations
result.Labels = manifest.Labels
mergeMaps(result.Annotations, manifest.Annotations)
mergeMaps(result.Labels, manifest.Labels)
result.Spec = mergeWorkloadConfigurationScanSpec(result.Spec, manifest.Spec)
// try to send the updated workload configuration scan manifest
_, updateErr := a.StorageClient.WorkloadConfigurationScans(namespace).Update(context.Background(), result, metav1.UpdateOptions{})
@@ -221,6 +200,9 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResult(ctx context.Contex
}
func mergeWorkloadConfigurationScanSpec(existingSpec v1beta1.WorkloadConfigurationScanSpec, newSpec v1beta1.WorkloadConfigurationScanSpec) v1beta1.WorkloadConfigurationScanSpec {
if existingSpec.Controls == nil {
existingSpec.Controls = make(map[string]v1beta1.ScannedControl)
}
for ctrlID := range newSpec.Controls {
newCtrl := newSpec.Controls[ctrlID]
_, found := existingSpec.Controls[ctrlID]
@@ -241,6 +223,9 @@ func mergeWorkloadConfigurationScanSpec(existingSpec v1beta1.WorkloadConfigurati
}
func mergeWorkloadConfigurationScanSummarySpec(existingSpec v1beta1.WorkloadConfigurationScanSummarySpec, newSpec v1beta1.WorkloadConfigurationScanSummarySpec) v1beta1.WorkloadConfigurationScanSummarySpec {
if existingSpec.Controls == nil {
existingSpec.Controls = make(map[string]v1beta1.ScannedControlSummary)
}
for ctrlID := range newSpec.Controls {
newCtrl := newSpec.Controls[ctrlID]
_, found := existingSpec.Controls[ctrlID]
@@ -280,16 +265,7 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResultSummary(ctx context
},
}
// This is a workaround for the fact that the apiserver does not return already exist error on Create
existing, err := a.StorageClient.WorkloadConfigurationScanSummaries(namespace).Get(context.Background(), manifest.Name, metav1.GetOptions{})
if err == nil {
logger.L().Debug("found existing WorkloadConfigurationScanSummary manifest in storage - merging manifests", helpers.String("name", manifest.Name))
manifest.Annotations = existing.Annotations
manifest.Labels = existing.Labels
manifest.Spec = mergeWorkloadConfigurationScanSummarySpec(existing.Spec, manifest.Spec)
}
_, err = a.StorageClient.WorkloadConfigurationScanSummaries(namespace).Create(context.Background(), &manifest, metav1.CreateOptions{})
_, err := a.StorageClient.WorkloadConfigurationScanSummaries(namespace).Create(context.Background(), &manifest, metav1.CreateOptions{})
switch {
case errors.IsAlreadyExists(err):
retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
@@ -300,8 +276,8 @@ func (a *APIServerStore) StoreWorkloadConfigurationScanResultSummary(ctx context
return getErr
}
// update the manifest
result.Annotations = manifest.Annotations
result.Labels = manifest.Labels
mergeMaps(result.Annotations, manifest.Annotations)
mergeMaps(result.Labels, manifest.Labels)
result.Spec = mergeWorkloadConfigurationScanSummarySpec(result.Spec, manifest.Spec)
// try to send the updated manifest
_, updateErr := a.StorageClient.WorkloadConfigurationScanSummaries(namespace).Update(context.Background(), result, metav1.UpdateOptions{})
@@ -544,3 +520,10 @@ func parseWorkloadScanRelatedObjectList(relatedObjects []workloadinterface.IMeta
}
return r
}
// mergeMaps merges new into existing, overwriting existing keys with new values
func mergeMaps(existing, new map[string]string) {
for k, v := range new {
existing[k] = v
}
}

View File

@@ -484,5 +484,51 @@ func Test_RoleBindingResourceTripletToSlug(t *testing.T) {
assert.ElementsMatch(t, tt.expectedSlugs, slugs)
})
}
}
func TestMergeMaps(t *testing.T) {
tests := []struct {
name string
existing map[string]string
new map[string]string
expected map[string]string
}{
{
name: "merge with no conflicts",
existing: map[string]string{"key1": "value1"},
new: map[string]string{"key2": "value2"},
expected: map[string]string{"key1": "value1", "key2": "value2"},
},
{
name: "merge with conflicts",
existing: map[string]string{"key1": "value1"},
new: map[string]string{"key1": "newValue1", "key2": "value2"},
expected: map[string]string{"key1": "newValue1", "key2": "value2"},
},
{
name: "merge with empty new map",
existing: map[string]string{"key1": "value1"},
new: map[string]string{},
expected: map[string]string{"key1": "value1"},
},
{
name: "merge with empty existing map",
existing: map[string]string{},
new: map[string]string{"key1": "value1"},
expected: map[string]string{"key1": "value1"},
},
{
name: "merge with both maps empty",
existing: map[string]string{},
new: map[string]string{},
expected: map[string]string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mergeMaps(tt.existing, tt.new)
assert.Equal(t, tt.expected, tt.existing)
})
}
}

View File

@@ -5,8 +5,11 @@ import (
"runtime"
)
// CurrentDir returns the directory of the file where this function is defined.
func CurrentDir() string {
_, filename, _, _ := runtime.Caller(1)
_, filename, ok := runtime.Caller(0)
if !ok {
panic("failed to get current file info")
}
return filepath.Dir(filename)
}

16
main.go
View File

@@ -1,6 +1,7 @@
package main
import (
"context"
"os"
"os/signal"
"syscall"
@@ -11,21 +12,20 @@ import (
func main() {
// Capture interrupt signal
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
// Handle interrupt signal
go func() {
<-signalChan
<-ctx.Done()
// Perform cleanup or graceful shutdown here
logger.L().StopError("Received interrupt signal, exiting...")
// Exit the program with proper exit code for SIGINT
os.Exit(130)
// Clear the signal handler so that a second interrupt signal shuts down immediately
stop()
}()
if err := cmd.Execute(); err != nil {
if err := cmd.Execute(ctx); err != nil {
stop()
logger.L().Fatal(err.Error())
}
}

View File

@@ -5,11 +5,13 @@ import (
"errors"
"fmt"
"path/filepath"
"strings"
"github.com/adrg/xdg"
"github.com/anchore/grype/grype"
"github.com/anchore/grype/grype/db"
"github.com/anchore/grype/grype/grypeerr"
"github.com/anchore/grype/grype/match"
"github.com/anchore/grype/grype/matcher"
"github.com/anchore/grype/grype/matcher/dotnet"
"github.com/anchore/grype/grype/matcher/golang"
@@ -116,9 +118,67 @@ type Service struct {
dbCfg db.Config
}
func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCredentials) (*models.PresenterConfig, error) {
var err error
func getIgnoredMatches(vulnerabilityExceptions []string, store *store.Store, packages []pkg.Package, pkgContext pkg.Context) (*match.Matches, []match.IgnoredMatch, error) {
if vulnerabilityExceptions == nil {
vulnerabilityExceptions = []string{}
}
var ignoreRules []match.IgnoreRule
for _, exception := range vulnerabilityExceptions {
rule := match.IgnoreRule{
Vulnerability: exception,
}
ignoreRules = append(ignoreRules, rule)
}
matcher := grype.VulnerabilityMatcher{
Store: *store,
Matchers: getMatchers(),
IgnoreRules: ignoreRules,
}
remainingMatches, ignoredMatches, err := matcher.FindMatches(packages, pkgContext)
if err != nil {
if !errors.Is(err, grypeerr.ErrAboveSeverityThreshold) {
return nil, nil, err
}
}
return remainingMatches, ignoredMatches, nil
}
// Filter the remaing matches based on severity exceptions.
func filterMatchesBasedOnSeverity(severityExceptions []string, remainingMatches match.Matches, store *store.Store) match.Matches {
if severityExceptions == nil {
return remainingMatches
}
filteredMatches := match.NewMatches()
for m := range remainingMatches.Enumerate() {
metadata, err := store.GetMetadata(m.Vulnerability.ID, m.Vulnerability.Namespace)
if err != nil {
continue
}
// Skip this match if the severity of this match is present in severityExceptions.
excludeSeverity := false
for _, sever := range severityExceptions {
if strings.ToUpper(metadata.Severity) == sever {
excludeSeverity = true
continue
}
}
if !excludeSeverity {
filteredMatches.Add(m)
}
}
return filteredMatches
}
func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCredentials, vulnerabilityExceptions, severityExceptions []string) (*models.PresenterConfig, error) {
store, status, dbCloser, err := NewVulnerabilityDB(s.dbCfg, true)
if err = validateDBLoad(err, status); err != nil {
return nil, err
@@ -133,20 +193,15 @@ func (s *Service) Scan(ctx context.Context, userInput string, creds RegistryCred
defer dbCloser.Close()
}
matcher := grype.VulnerabilityMatcher{
Store: *store,
Matchers: getMatchers(),
remainingMatches, ignoredMatches, err := getIgnoredMatches(vulnerabilityExceptions, store, packages, pkgContext)
if err != nil {
return nil, err
}
remainingMatches, ignoredMatches, err := matcher.FindMatches(packages, pkgContext)
if err != nil {
if !errors.Is(err, grypeerr.ErrAboveSeverityThreshold) {
return nil, err
}
}
filteredMatches := filterMatchesBasedOnSeverity(severityExceptions, *remainingMatches, store)
pb := models.PresenterConfig{
Matches: *remainingMatches,
Matches: filteredMatches,
IgnoredMatches: ignoredMatches,
Packages: packages,
Context: pkgContext,

View File

@@ -2,9 +2,12 @@ package imagescan
import (
"errors"
"net/http"
"path"
"testing"
"time"
"github.com/adrg/xdg"
"github.com/anchore/grype/grype/db"
grypedb "github.com/anchore/grype/grype/db/v5"
"github.com/anchore/grype/grype/match"
@@ -16,63 +19,71 @@ import (
"github.com/stretchr/testify/assert"
)
// import (
// "context"
// "testing"
func TestVulnerabilityAndSeverityExceptions(t *testing.T) {
go func() {
_ = http.ListenAndServe(":8000", http.FileServer(http.Dir("testdata"))) //nolint:gosec
}()
dbCfg := db.Config{
DBRootDir: path.Join(xdg.CacheHome, "grype-light", "db"),
ListingURL: "http://localhost:8000/listing.json",
}
svc := NewScanService(dbCfg)
creds := RegistryCredentials{}
// "github.com/anchore/grype/grype/db"
// grypedb "github.com/anchore/grype/grype/db/v5"
// "github.com/anchore/grype/grype/match"
// "github.com/anchore/grype/grype/pkg"
// "github.com/anchore/grype/grype/presenter/models"
// "github.com/anchore/grype/grype/vulnerability"
// syftPkg "github.com/anchore/syft/syft/pkg"
// "github.com/google/uuid"
// "github.com/stretchr/testify/assert"
// )
tests := []struct {
name string
image string
vulnerabilityExceptions []string
ignoredLen int
severityExceptions []string
filteredLen int
}{
{
name: "alpine:3.19.1 without medium vulnerabilities",
image: "alpine:3.19.1",
ignoredLen: 0,
severityExceptions: []string{"MEDIUM"},
filteredLen: 0,
},
{
name: "alpine:3.9.6",
image: "alpine:3.9.6",
vulnerabilityExceptions: []string{"CVE-2020-1971", "CVE-2020-28928", "CVE-2021-23840"},
ignoredLen: 6,
severityExceptions: []string{"HIGH", "MEDIUM"},
filteredLen: 8,
},
{
name: "alpine:3.9.6 with invalid vulnerability and severity exceptions",
image: "alpine:3.9.6",
vulnerabilityExceptions: []string{"invalid-cve", "CVE-2020-28928", "CVE-2021-23840"},
ignoredLen: 4,
severityExceptions: []string{"CRITICAL", "MEDIUM", "invalid-severity"},
filteredLen: 10,
},
}
// func TestNewScanService(t *testing.T) {
// dbCfg, _ := NewDefaultDBConfig()
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
store, status, dbCloser, err := NewVulnerabilityDB(svc.dbCfg, true)
assert.NoError(t, validateDBLoad(err, status))
// svc := NewScanService(dbCfg)
packages, pkgContext, _, err := pkg.Provide(tc.image, getProviderConfig(creds))
assert.NoError(t, err)
// assert.IsType(t, Service{}, svc)
// }
if dbCloser != nil {
defer dbCloser.Close()
}
// func TestScan(t *testing.T) {
// tt := []struct {
// name string
// image string
// creds RegistryCredentials
// }{
// {
// name: "Valid image name produces a non-nil scan result",
// image: "nginx",
// },
// {
// name: "Scanning a valid image with provided credentials should produce a non-nil scan result",
// image: "nginx",
// creds: RegistryCredentials{
// Username: "test",
// Password: "password",
// },
// },
// }
remainingMatches, ignoredMatches, err := getIgnoredMatches(tc.vulnerabilityExceptions, store, packages, pkgContext)
assert.NoError(t, err)
assert.Equal(t, tc.ignoredLen, len(ignoredMatches))
// for _, tc := range tt {
// t.Run(tc.name, func(t *testing.T) {
// ctx := context.Background()
// dbCfg, _ := NewDefaultDBConfig()
// svc := NewScanService(dbCfg)
// creds := RegistryCredentials{}
// scanResults, err := svc.Scan(ctx, tc.image, creds)
// assert.NoError(t, err)
// assert.IsType(t, &models.PresenterConfig{}, scanResults)
// })
// }
// }
filteredMatches := filterMatchesBasedOnSeverity(tc.severityExceptions, *remainingMatches, store)
assert.Equal(t, tc.filteredLen, filteredMatches.Count())
})
}
}
// fakeMetaProvider is a test double that fakes an actual MetadataProvider
type fakeMetaProvider struct {

12
pkg/imagescan/testdata/listing.json vendored Normal file
View File

@@ -0,0 +1,12 @@
{
"available": {
"5": [
{
"built": "2023-12-13T01:27:01Z",
"version": 5,
"url": "http://localhost:8000/vulnerability-db_v5_2023-03-24T06_54_57Z_fab15e5405c096d82dfd.tar.gz",
"checksum": "sha256:99ad9fd54be5295351555a02a0fb6986a461a9d23eb8ae3b34ea892c252a8c80"
}
]
}
}

40
pkg/ksinit/ksinit.go Normal file
View File

@@ -0,0 +1,40 @@
package ksinit
import (
"os"
"path/filepath"
"time"
spdxv1beta1 "github.com/kubescape/storage/pkg/generated/clientset/versioned/typed/softwarecomposition/v1beta1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
// CreateKsObjectConnection initializes a KS object connection, shared by mcpserver and httphandler
func CreateKsObjectConnection(namespace string, maxElapsedTime time.Duration) (spdxv1beta1.SpdxV1beta1Interface, error) {
var cfg *rest.Config
var err error
if kubeconfig := os.Getenv("KUBECONFIG"); kubeconfig != "" {
cfg, err = clientcmd.BuildConfigFromFlags("", kubeconfig)
} else {
home := os.Getenv("HOME")
kubeconfigPath := filepath.Join(home, ".kube", "config")
cfg, err = clientcmd.BuildConfigFromFlags("", kubeconfigPath)
if err != nil {
cfg, err = rest.InClusterConfig()
}
}
if err != nil {
return nil, err
}
// disable rate limiting
cfg.QPS = 0
cfg.RateLimiter = nil
// force GRPC
cfg.AcceptContentTypes = "application/vnd.kubernetes.protobuf"
cfg.ContentType = "application/vnd.kubernetes.protobuf"
return spdxv1beta1.NewForConfig(cfg)
}