├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── Dockerfile ├── Dockerfile_debug ├── LICENSE ├── README.md ├── alcide-skan-viewer ├── .babelrc ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public │ └── index.html ├── src │ ├── AlcideSkanViewer.js │ ├── App.js │ ├── Check.js │ ├── DataLoader.js │ ├── SeverityDropDown.js │ ├── Skan.js │ ├── SkanViewer.module.scss │ ├── State.js │ ├── ToggleSwitch.js │ ├── ToggleSwitch.module.scss │ ├── fontawesome.js │ ├── index.css │ ├── index.js │ ├── index.test.js │ ├── setupTests.js │ └── utils.js └── webpack.config.js ├── img ├── alcidesKan2x.png ├── alcidesKan3x.png ├── skan-html-report-secret.png ├── skan-html-report.png └── skan.png └── skan-download.sh /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: gadinaor 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[ENHANCEMENT]" 5 | labels: enhancement 6 | assignees: gadinaor 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest AS build 2 | RUN apk --no-cache --update add wget ca-certificates 3 | 4 | FROM scratch 5 | 6 | WORKDIR / 7 | COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt 8 | COPY skan /skan 9 | 10 | ENTRYPOINT ["/skan"] -------------------------------------------------------------------------------- /Dockerfile_debug: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | RUN apk --no-cache --update add bash wget ca-certificates 3 | 4 | WORKDIR / 5 | COPY skan /skan 6 | 7 | ENTRYPOINT ["/skan"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![release](https://img.shields.io/github/v/release/alcideio/skan?sort=semver) 2 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 3 | ![Tweet](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Fgithub.com%2Falcideio%2Fskan) 4 | 5 | skan 6 | 7 | ###### s**K**an is powered by the [Alcide Advisor](https://www.alcide.io/kubernetes-advisor) scan engine and [Open Policy Agent (OPA)](https://www.openpolicyagent.org) 8 | 9 | # s**K**an 10 | 11 | s**K**an is a tailor made Kubernetes configuration files and resources scanner that enables developers and devops team members to check whether their work is compliant with security & ops best practices. 12 | 13 | skan 14 | 15 | # Install s**K**an 16 | 17 | s**K**an supports Linux, Mac & Windows and the latest release is available [here](https://github.com/alcideio/skan/releases/latest). 18 | 19 | Or use 20 | 21 | ```sh 22 | $ curl https://raw.githubusercontent.com/alcideio/skan/master/skan-download.sh | bash 23 | ``` 24 | 25 | # s**K**an Kubernetes file 26 | 27 | ```sh 28 | $ skan manifest --report-passed -f kaudit_for_eks.yaml 29 | ``` 30 | 31 | ```sh 32 | [skan-this] Analyzing resources from '1' files/directories. 33 | [skan-this] Loaded '9' objects 34 | [skan-this] Ops Conformance | Workload Readiness & Liveness 35 | [skan-this] Ops Conformance | Workload Capacity Planning 36 | [skan-this] Workload Software Supply Chain | Image Registry Whitelist 37 | [skan-this] Ingress Controllers & Services | Ingress Security & Hardening Configuration 38 | [skan-this] Ingress Controllers & Services | Ingress Controller (nginx) 39 | [skan-this] Ingress Controllers & Services | Service Resource Checks 40 | [skan-this] Pod Security | Workload Hardening 41 | [skan-this] API Server Access Privileges | Privileged Kubernetes API Server Access 42 | [skan-this] Secret Hunting | Find Secrets in ConfigMaps 43 | [skan-this] Secret Hunting | Find Secrets in Pod Environment Variables 44 | [skan-this] Admission Controllers | Validating Admission Controllers 45 | [skan-this] Admission Controllers | Mutating Admission Controllers 46 | [skan-this] Generating report (html) and saving as 'skan-result.html' 47 | [skan-this] Summary: 48 | [skan-this] Critical .... 0 49 | [skan-this] High ........ 4 50 | [skan-this] Medium ...... 2 51 | [skan-this] Low ......... 0 52 | [skan-this] Pass ........ 21 53 | ``` 54 | 55 | ```sh 56 | $ open skan-result.html 57 | ``` 58 | 59 | ## s**K**an **Helm Chart** 60 | 61 | ```sh 62 | $ helm template kaudit deploy/charts/kaudit --set k8sAuditEnvironment=eks | skan manifest -f - 63 | ``` 64 | ## s**K**an **Kustomized Resources** 65 | 66 | ```sh 67 | kubectl kustomize helloWorld | skan manifest -f - 68 | ``` 69 | 70 | ### Command Line Example 71 | 72 | ```sh 73 | Validate Kubernetes resource(s) handed as YAML. 74 | 75 | YAML file with multiple resources are supported. 76 | By default a HTML report is generated. To generate YAML based outformat use --output flag 77 | 78 | skan manifest -f mydeployment.yaml 79 | 80 | Usage: 81 | skan manifest [flags] 82 | 83 | Aliases: 84 | manifest, file, Files, m, manifests, validate 85 | 86 | Examples: 87 | 88 | # Validate a YAML file. Multiple YAML files separated with '---' is supported 89 | skan manifest -f mydeployment.yaml -f myotherdeployment.yaml 90 | 91 | # Validate all the resources found under the namespace 'myns' of a cluster with 'kubectl get' 92 | kubectl get all -n myns -o yaml | skan manifest --report-passed -f - 93 | 94 | # Validate resource kustomization 95 | kubectl kustomize helloWorld | skan manifest -f - 96 | 97 | # Validate Helm Chart 98 | helm template kaudit deploy/charts/kaudit --set k8sAuditEnvironment=eks | skan manifest -f - 99 | 100 | 101 | Flags: 102 | -d, --debug Debug trace level 103 | -f, --filename strings One or more file names (or directories) that contain the configuration to sKan 104 | -h, --help help for manifest 105 | -o, --output string output format. Supported formats are html, yaml and json (default "html") 106 | --outputfile string OutputFormat file (default "skan-result.html") 107 | -p, --report-passed Report passed checks 108 | ``` 109 | 110 | ## Contributing 111 | 112 | ### Bugs 113 | 114 | If you think you have found a bug please follow the instructions below. 115 | 116 | - Please spend a small amount of time giving due diligence to the issue tracker. Your issue might be a duplicate. 117 | - Open a [new issue](https://github.com/alcideio/skan/issues/new) if a duplicate doesn't already exist. 118 | 119 | ### Features 120 | 121 | If you have an idea to enhance rbac-tool follow the steps below. 122 | 123 | - Open a [new issue](https://github.com/alcideio/skan/issues/new). 124 | - Remember users might be searching for your issue in the future, so please give it a meaningful title to helps others. 125 | - Clearly define the use case, using concrete examples. 126 | - Feel free to include any technical design for your feature. 127 | 128 | [![Stargazers over time](https://starchart.cc/alcideio/skan.svg)](https://starchart.cc/alcideio/skan) 129 | -------------------------------------------------------------------------------- /alcide-skan-viewer/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ "@babel/preset-env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": [ 7 | "last 2 Chrome versions", 8 | "last 2 Firefox versions", 9 | "last 2 Safari versions", 10 | "last 2 iOS versions", 11 | "last 1 Android version", 12 | "last 1 ChromeAndroid version", 13 | "ie 11" 14 | ] 15 | } 16 | } ], 17 | "@babel/preset-react" 18 | ], 19 | "plugins": [ "@babel/plugin-proposal-class-properties" ] 20 | } -------------------------------------------------------------------------------- /alcide-skan-viewer/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /dist 6 | 7 | /.pnp 8 | .pnp.js 9 | 10 | # testing 11 | /coverage 12 | 13 | # production 14 | /build 15 | 16 | # misc 17 | .DS_Store 18 | .env.local 19 | .env.development.local 20 | .env.test.local 21 | .env.production.local 22 | 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | -------------------------------------------------------------------------------- /alcide-skan-viewer/README.md: -------------------------------------------------------------------------------- 1 | skan 2 | 3 | ###### s**K**an is powered by the [Alcide Advisor](https://www.alcide.io/kubernetes-advisor) scan engine and [Open Policy Agent (OPA)](https://www.openpolicyagent.org) 4 | 5 | See [https://github.com/alcideio/skan](https://github.com/alcideio/skan) -------------------------------------------------------------------------------- /alcide-skan-viewer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@alcideio/alcide-skan-viewer", 3 | "version": "0.2.2", 4 | "private": false, 5 | "keywords": [ 6 | "kubernetes", 7 | "security", 8 | "skan", 9 | "compliance", 10 | "config-scan", 11 | "rapid7", 12 | "insightcloudsec", 13 | "helm" 14 | ], 15 | "author": "Rapid7", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/alcideio/skan/issues" 19 | }, 20 | "homepage": "https://github.com/alcideio/skan", 21 | "dependencies": { 22 | "@fortawesome/fontawesome-svg-core": "^6.1.1", 23 | "@fortawesome/free-brands-svg-icons": "^6.1.1", 24 | "@fortawesome/free-solid-svg-icons": "^6.1.1", 25 | "@fortawesome/react-fontawesome": "^0.1.18", 26 | "@testing-library/jest-dom": "^5.16.4", 27 | "@testing-library/react": "^13.2.0", 28 | "@testing-library/user-event": "^14.2.0", 29 | "bootstrap": "^5.1.3", 30 | "bootstrap-switch-button-react": "^1.2.0", 31 | "css-loader": "^6.7.1", 32 | "file-loader": "^6.2.0", 33 | "log-timestamp": "^0.3.0", 34 | "node-sass": "^7.0.1", 35 | "react": "^18.1.0", 36 | "react-bootstrap": "^2.4.0", 37 | "react-dom": "^18.1.0", 38 | "react-scripts": "^2.1.3", 39 | "react-select": "^5.3.2", 40 | "react-spinners": "^0.12.0", 41 | "style-loader": "^3.3.1" 42 | }, 43 | "scripts": { 44 | "webpack-dev-server": "webpack-dev-server", 45 | "dev": "webpack-dev-server --mode=development", 46 | "prod": "webpack --mode=production" 47 | }, 48 | "eslintConfig": { 49 | "extends": "react-app" 50 | }, 51 | "browserslist": { 52 | "production": [ 53 | ">0.2%", 54 | "not dead", 55 | "not op_mini all" 56 | ], 57 | "development": [ 58 | "last 1 chrome version", 59 | "last 1 firefox version", 60 | "last 1 safari version" 61 | ] 62 | }, 63 | "files": [ 64 | "dist" 65 | ], 66 | "devDependencies": { 67 | "@babel/core": "^7.18.2", 68 | "@babel/plugin-proposal-class-properties": "^7.17.12", 69 | "@babel/preset-env": "^7.18.2", 70 | "@babel/preset-react": "^7.17.12", 71 | "babel-loader": "^8.2.5", 72 | "html-webpack-plugin": "^5.5.0", 73 | "mini-css-extract-plugin": "^2.6.0", 74 | "path": "^0.12.7", 75 | "webpack": "^5.72.1", 76 | "webpack-cli": "^4.9.2", 77 | "webpack-dev-server": "^4.9.0" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /alcide-skan-viewer/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | [InsightCloudSec] Mimics .. Kubernetes Manifest & Helm Resource Scanner 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 85 |
86 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /alcide-skan-viewer/src/AlcideSkanViewer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Skan from './Skan' 4 | 5 | const AlcideSkanViewer = ({ data }) => { 6 | console.log("InsightCloudSec Resource Scanner data", data); 7 | return 8 | } 9 | 10 | export default AlcideSkanViewer; -------------------------------------------------------------------------------- /alcide-skan-viewer/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useContext} from 'react'; 3 | 4 | import Container from 'react-bootstrap/Container'; 5 | import Navbar from 'react-bootstrap/Navbar'; 6 | import Nav from 'react-bootstrap/Nav'; 7 | import NavItem from 'react-bootstrap/NavItem'; 8 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 9 | 10 | import SeverityDropDown from './SeverityDropDown'; 11 | import {prepareData} from './DataLoader'; 12 | import { ComponentContext, DataContext } from './State'; 13 | import ToggleSwitch from './ToggleSwitch'; 14 | 15 | import './fontawesome'; 16 | import Fetcher from './DataLoader'; 17 | import styles from './SkanViewer.module.scss'; 18 | import Row from 'react-bootstrap/esm/Row'; 19 | import Col from 'react-bootstrap/esm/Col'; 20 | 21 | function App() { 22 | var { state } = useContext(ComponentContext); 23 | var report = useContext(DataContext); 24 | 25 | function prepareReport(report, sevrityFilter, groupBy) { 26 | const checkGroups = prepareData(report, sevrityFilter, groupBy); 27 | return checkGroups; 28 | } 29 | 30 | //console.log(">>> App", report); 31 | 32 | return ( 33 | 34 | 35 | 36 | 37 | {return prepareReport(report, state.sevrityFilter, state.groupByToggle)} 40 | } 41 | > 42 | 43 | 44 | 45 | 46 | 47 | ); 48 | } 49 | 50 | function SkanHeader() { 51 | 52 | return ( 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | ); 74 | 75 | } 76 | 77 | function SkanFooter() { 78 | return ( 79 |
80 |
81 |
82 |
83 |
84 | 85 |

86 | Brought to you by

InsightCloudSec

87 |

88 |
89 |
90 |
91 |
92 |
93 |
94 | 95 | ); 96 | } 97 | 98 | 99 | 100 | export default App; -------------------------------------------------------------------------------- /alcide-skan-viewer/src/Check.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Accordion from 'react-bootstrap/Accordion'; 3 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 4 | import Button from 'react-bootstrap/Button'; 5 | import Card from 'react-bootstrap/Card'; 6 | import Table from 'react-bootstrap/Table'; 7 | import * as utils from './utils'; 8 | 9 | import styles from './SkanViewer.module.scss'; 10 | 11 | function Checks({checkGroups}) { 12 | 13 | //console.log("checkGroups", checkGroups); 14 | // const { state, dispatch } = useContext(ComponentContext); 15 | // let checkGroups = prepareData(state.report, state.sevrityFilter, state.groupByToggle); 16 | 17 | let groups = Array.from(checkGroups.keys()); 18 | let checks = Array.from(checkGroups.values()); 19 | 20 | //console.log("filterData@state", state); 21 | //console.log("filterData@checkGroups", checkGroups); 22 | //console.log("filterData@groups", groups); 23 | 24 | const cards = Array.from(groups.keys()).map((groupName, index) => { 25 | return ( 26 | 27 | 28 | 29 | {groups[index]} 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {checks[index].map((check, index) => 39 | 40 | 43 | 44 | )} 45 | 46 |
41 | 42 |
47 |
48 |
49 |
50 | 51 |
52 | ); 53 | }) 54 | 55 | //console.log("cards", cards); 56 | 57 | return ( 58 | 59 | {cards} 60 | 61 | ); 62 | } 63 | 64 | function CheckHeaderPill(props) { 65 | return ( 66 | 69 | ); 70 | } 71 | 72 | function CheckBodyTextItem(props) { 73 | return ( 74 |
  • 75 | {props.children} 76 |
  • 77 | ); 78 | } 79 | 80 | function Check({ check }) { 81 | let iconUrl = utils.platformLogo(check.Resource.Kind.toString()) 82 | let urlRefs = []; 83 | 84 | if (check.References !== undefined && check.References.length > 0) { 85 | urlRefs.push(( 86 |
  • 87 |

    References

    88 |
  • 89 | )); 90 | 91 | check.References.forEach((refUrl, index) => { 92 | urlRefs.push(( 93 |
  • 94 | {refUrl} 95 |
  • 96 | )); 97 | }) 98 | 99 | //console.log("urlRefs", urlRefs); 100 | } 101 | 102 | let nameSpacePill = "" 103 | if (check.Resource.Namespace !== null && check.Resource.Namespace !== undefined && check.Resource.Namespace.length > 0) { 104 | nameSpacePill = ( 105 | 106 | ); 107 | } 108 | 109 | return ( 110 |
    111 | 141 | 142 | 158 |
    159 | 160 | ); 161 | } 162 | 163 | export default Checks; -------------------------------------------------------------------------------- /alcide-skan-viewer/src/DataLoader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropagateLoader from "react-spinners/PropagateLoader"; 3 | import Container from 'react-bootstrap/Container' 4 | import Fade from 'react-bootstrap/Fade' 5 | import Col from 'react-bootstrap/Col' 6 | import Row from 'react-bootstrap/Row' 7 | import Checks from './Check' 8 | 9 | import { useContext, useEffect, useState } from 'react'; 10 | import { actionTypes, ComponentContext } from './State'; 11 | 12 | 13 | //var log = require('log-timestamp'); 14 | 15 | // This functions prepare the data for the view 16 | // {groupName: []} 17 | // 18 | export function prepareData(data, currentSeverityFilter, groupByCategory) { 19 | var checks = new Map(); 20 | var severityFilter = new Map(); 21 | var obj = data.Reports; 22 | 23 | //console.log(`prepareData: [currentSeverityFilter=${currentSeverityFilter}][groupByCategory=${groupByCategory}]`) 24 | 25 | currentSeverityFilter.forEach((s) => severityFilter.set(s)); 26 | 27 | Object.keys(obj).forEach((key, i) => { 28 | var groupChecks = null; 29 | var groupName; 30 | let check = obj[key]; 31 | 32 | check.Results.forEach((oneResult) => { 33 | if (!severityFilter.has(oneResult.Severity.toLowerCase())) { 34 | return; 35 | } 36 | 37 | if (groupByCategory) { 38 | groupName = key; 39 | } else { 40 | let gvk = ((oneResult.Resource.Group !== undefined && oneResult.Resource.Group !== "") ? oneResult.Resource.Group + '.' : "") + 41 | oneResult.Resource.Kind; 42 | 43 | groupName = (oneResult.Resource.Namespace !== undefined || oneResult.Resource.Namespace === "") ? `${oneResult.Resource.Namespace}/${oneResult.Resource.Name} (${gvk})`: `${oneResult.Resource.Name} (${gvk})`; 44 | } 45 | 46 | if (!checks.has(groupName)) { 47 | checks.set(groupName, []); 48 | } 49 | 50 | groupChecks = checks.get(groupName); 51 | groupChecks.push(oneResult); 52 | }) 53 | 54 | if (groupChecks !== null) { 55 | checks.set(groupName, groupChecks); 56 | } 57 | 58 | }); 59 | 60 | return checks; 61 | } 62 | 63 | function useFetcher(action, state, dispatch) { 64 | const [data, setData] = useState(null); 65 | const dataRef = React.useRef(data); 66 | 67 | useEffect(() => { 68 | console.log(`[useFetcher.useLayoutEffect] [isLoading=${state.isLoading}]`); 69 | async function loadData() { 70 | 71 | if (!state.isLoading) { 72 | return; 73 | } 74 | 75 | try { 76 | //setLoading(true); 77 | //isLoadingRef.current = true; 78 | console.log(`[Load Data] [isLoading=${state.isLoading}]`); 79 | //isLoadingRef.current = true; 80 | 81 | //Perform the fetch action 82 | 83 | await new Promise(r => setTimeout(r, 700)); 84 | //console.log("before"); 85 | var actionData = action(); 86 | //console.log("after", actionData); 87 | setData(actionData); 88 | dataRef.current = actionData; 89 | } catch (e) { 90 | console.log("loadData failed", e); 91 | setData(null); 92 | } finally { 93 | //setLoading(false); 94 | dispatch({ type: actionTypes.dataLoadSuccess }); 95 | //console.log("<<< loadData.completed"); 96 | } 97 | } 98 | 99 | loadData(); 100 | 101 | }, [action, state.isLoading]); 102 | 103 | console.log(`[useFetcher] [isLoading=${state.isLoading}][groupByModule=${state.groupByToggle}]`); 104 | return [dataRef.current, state.isLoading]; 105 | } 106 | 107 | const Fetcher = ({ action, children }) => { 108 | const { state, dispatch } = useContext(ComponentContext); 109 | const [data, isLoading] = useFetcher(action, state, dispatch); 110 | 111 | console.log(`[Fetcher][isLoading=${isLoading}][data=${data}]`, data); 112 | 113 | var view 114 | 115 | if (!state.isLoading && data) { 116 | //console.log(`Fetcher data`, { checkGroups: data }); 117 | view = ( 118 | 119 | 120 | 121 | ); 122 | //setData(null); 123 | 124 | } else { 125 | view = ( 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 138 | 139 | 140 | 141 | 142 | 143 | ); 144 | } 145 | return view; 146 | }; 147 | 148 | export default Fetcher; 149 | -------------------------------------------------------------------------------- /alcide-skan-viewer/src/SeverityDropDown.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import makeAnimated from 'react-select/animated'; 3 | import { actionTypes, ComponentContext } from './State'; 4 | 5 | import Select from 'react-select' 6 | 7 | const options = [ 8 | { value: 'critical', label: 'Critical' }, 9 | { value: 'high', label: 'High' }, 10 | { value: 'medium', label: 'Medium' }, 11 | { value: 'low', label: 'Low' }, 12 | { value: 'info', label: 'Info' }, 13 | { value: 'pass', label: 'Pass' }, 14 | ] 15 | 16 | const animatedComponents = makeAnimated(); 17 | 18 | const customStyles = { 19 | option: (provided, state) => ({ 20 | ...provided, 21 | borderBottom: '1px dotted pink', 22 | color: state.isSelected ? 'red' : 'blue', 23 | padding: 20, 24 | }), 25 | // control: () => ({ 26 | // // none of react-select's styles are passed to 27 | // width: auto, 28 | // }), 29 | } 30 | 31 | function SeverityDropDown() { 32 | const { dispatch } = React.useContext(ComponentContext); 33 | 34 | return ( 35 |