├── .dockerignore ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ ├── build_test.yml │ ├── codeql.yml │ ├── dependency-review.yml │ ├── deploy-github-pages.yml │ ├── golangci-lint.yml │ ├── pop.yml │ ├── release.yml │ └── scorecards.yml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yaml ├── .poutine.sample.yml ├── .poutine.yml ├── .poutine └── config.rego ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── MAINTAINERS.md ├── Makefile ├── README.md ├── analyze └── analyze.go ├── cmd ├── analyzeLocal.go ├── analyzeOrg.go ├── analyzeRepo.go ├── analyzeRepoStaleBranches.go ├── root.go └── version.go ├── dagger.json ├── dagger ├── .gitattributes ├── .gitignore ├── go.mod └── main.go ├── docs ├── .gitignore ├── .hugo_build.lock ├── archetypes │ └── default.md ├── content.go ├── content │ ├── _index.md │ └── en │ │ └── rules │ │ ├── confused_deputy_auto_merge.md │ │ ├── debug_enabled.md │ │ ├── default_permissions_on_risky_events.md │ │ ├── github_action_from_unverified_creator_used.md │ │ ├── if_always_true.md │ │ ├── img.png │ │ ├── img_1.png │ │ ├── injection.md │ │ ├── job_all_secrets.md │ │ ├── known_vulnerability_in_build_component.md │ │ ├── known_vulnerability_in_build_platform.md │ │ ├── pr_runs_on_self_hosted.md │ │ ├── unpinnable_action.md │ │ ├── untrusted_checkout_exec.md │ │ └── unverified_script_exec.md ├── content_test.go ├── data │ └── menu │ │ ├── extra.yaml │ │ └── more.yaml ├── hugo.toml ├── static │ ├── brand.svg │ ├── custom.css │ └── favicon │ │ └── favicon.svg └── themes │ └── hugo-geekdoc │ ├── LICENSE │ ├── README.md │ ├── VERSION │ ├── archetypes │ ├── docs.md │ └── posts.md │ ├── assets │ ├── search │ │ ├── config.json │ │ └── data.json │ └── sprites │ │ └── geekdoc.svg │ ├── data │ └── assets.json │ ├── i18n │ ├── cs.yaml │ ├── de.yaml │ ├── en.yaml │ ├── es.yaml │ ├── it.yaml │ ├── ja.yaml │ ├── nl.yaml │ └── zh-cn.yaml │ ├── images │ ├── readme.png │ ├── screenshot.png │ └── tn.png │ ├── layouts │ ├── 404.html │ ├── _default │ │ ├── _markup │ │ │ ├── render-codeblock-mermaid.html │ │ │ ├── render-heading.html │ │ │ ├── render-image.html │ │ │ └── render-link.html │ │ ├── baseof.html │ │ ├── list.html │ │ ├── single.html │ │ ├── taxonomy.html │ │ └── terms.html │ ├── partials │ │ ├── foot.html │ │ ├── head │ │ │ ├── custom.html │ │ │ ├── favicons.html │ │ │ ├── meta.html │ │ │ ├── microformats.html │ │ │ ├── others.html │ │ │ └── rel-me.html │ │ ├── language.html │ │ ├── menu-bundle.html │ │ ├── menu-extra.html │ │ ├── menu-filetree.html │ │ ├── menu-nextprev.html │ │ ├── menu.html │ │ ├── microformats │ │ │ ├── opengraph.html │ │ │ ├── schema.html │ │ │ └── twitter_cards.html │ │ ├── page-header.html │ │ ├── pagination.html │ │ ├── posts │ │ │ └── metadata.html │ │ ├── search.html │ │ ├── site-footer.html │ │ ├── site-header.html │ │ ├── svg-icon-symbols.html │ │ └── utils │ │ │ ├── content.html │ │ │ ├── description.html │ │ │ ├── featured.html │ │ │ └── title.html │ ├── posts │ │ ├── list.html │ │ └── single.html │ ├── robots.txt │ └── shortcodes │ │ ├── button.html │ │ ├── columns.html │ │ ├── expand.html │ │ ├── hint.html │ │ ├── icon.html │ │ ├── img.html │ │ ├── include.html │ │ ├── katex.html │ │ ├── mermaid.html │ │ ├── progress.html │ │ ├── propertylist.html │ │ ├── tab.html │ │ ├── tabs.html │ │ ├── toc-tree.html │ │ └── toc.html │ ├── static │ ├── brand.svg │ ├── custom.css │ ├── favicon │ │ ├── android-chrome-144x144.png │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-256x256.png │ │ ├── android-chrome-36x36.png │ │ ├── android-chrome-384x384.png │ │ ├── android-chrome-48x48.png │ │ ├── android-chrome-512x512.png │ │ ├── android-chrome-72x72.png │ │ ├── android-chrome-96x96.png │ │ ├── apple-touch-icon-1024x1024.png │ │ ├── apple-touch-icon-114x114.png │ │ ├── apple-touch-icon-120x120.png │ │ ├── apple-touch-icon-144x144.png │ │ ├── apple-touch-icon-152x152.png │ │ ├── apple-touch-icon-167x167.png │ │ ├── apple-touch-icon-180x180.png │ │ ├── apple-touch-icon-57x57.png │ │ ├── apple-touch-icon-60x60.png │ │ ├── apple-touch-icon-72x72.png │ │ ├── apple-touch-icon-76x76.png │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ ├── apple-touch-startup-image-1125x2436.png │ │ ├── apple-touch-startup-image-1136x640.png │ │ ├── apple-touch-startup-image-1170x2532.png │ │ ├── apple-touch-startup-image-1242x2208.png │ │ ├── apple-touch-startup-image-1242x2688.png │ │ ├── apple-touch-startup-image-1284x2778.png │ │ ├── apple-touch-startup-image-1334x750.png │ │ ├── apple-touch-startup-image-1536x2048.png │ │ ├── apple-touch-startup-image-1620x2160.png │ │ ├── apple-touch-startup-image-1668x2224.png │ │ ├── apple-touch-startup-image-1668x2388.png │ │ ├── apple-touch-startup-image-1792x828.png │ │ ├── apple-touch-startup-image-2048x1536.png │ │ ├── apple-touch-startup-image-2048x2732.png │ │ ├── apple-touch-startup-image-2160x1620.png │ │ ├── apple-touch-startup-image-2208x1242.png │ │ ├── apple-touch-startup-image-2224x1668.png │ │ ├── apple-touch-startup-image-2388x1668.png │ │ ├── apple-touch-startup-image-2436x1125.png │ │ ├── apple-touch-startup-image-2532x1170.png │ │ ├── apple-touch-startup-image-2688x1242.png │ │ ├── apple-touch-startup-image-2732x2048.png │ │ ├── apple-touch-startup-image-2778x1284.png │ │ ├── apple-touch-startup-image-640x1136.png │ │ ├── apple-touch-startup-image-750x1334.png │ │ ├── apple-touch-startup-image-828x1792.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-48x48.png │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── manifest.json │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ └── mstile-70x70.png │ ├── fonts │ │ ├── GeekdocIcons.woff │ │ ├── GeekdocIcons.woff2 │ │ ├── KaTeX_AMS-Regular.woff │ │ ├── KaTeX_AMS-Regular.woff2 │ │ ├── KaTeX_Caligraphic-Bold.woff │ │ ├── KaTeX_Caligraphic-Bold.woff2 │ │ ├── KaTeX_Caligraphic-Regular.woff │ │ ├── KaTeX_Caligraphic-Regular.woff2 │ │ ├── KaTeX_Fraktur-Bold.woff │ │ ├── KaTeX_Fraktur-Bold.woff2 │ │ ├── KaTeX_Fraktur-Regular.woff │ │ ├── KaTeX_Fraktur-Regular.woff2 │ │ ├── KaTeX_Main-Bold.woff │ │ ├── KaTeX_Main-Bold.woff2 │ │ ├── KaTeX_Main-BoldItalic.woff │ │ ├── KaTeX_Main-BoldItalic.woff2 │ │ ├── KaTeX_Main-Italic.woff │ │ ├── KaTeX_Main-Italic.woff2 │ │ ├── KaTeX_Main-Regular.woff │ │ ├── KaTeX_Main-Regular.woff2 │ │ ├── KaTeX_Math-BoldItalic.woff │ │ ├── KaTeX_Math-BoldItalic.woff2 │ │ ├── KaTeX_Math-Italic.woff │ │ ├── KaTeX_Math-Italic.woff2 │ │ ├── KaTeX_SansSerif-Bold.woff │ │ ├── KaTeX_SansSerif-Bold.woff2 │ │ ├── KaTeX_SansSerif-Italic.woff │ │ ├── KaTeX_SansSerif-Italic.woff2 │ │ ├── KaTeX_SansSerif-Regular.woff │ │ ├── KaTeX_SansSerif-Regular.woff2 │ │ ├── KaTeX_Script-Regular.woff │ │ ├── KaTeX_Script-Regular.woff2 │ │ ├── KaTeX_Size1-Regular.woff │ │ ├── KaTeX_Size1-Regular.woff2 │ │ ├── KaTeX_Size2-Regular.woff │ │ ├── KaTeX_Size2-Regular.woff2 │ │ ├── KaTeX_Size3-Regular.woff │ │ ├── KaTeX_Size3-Regular.woff2 │ │ ├── KaTeX_Size4-Regular.woff │ │ ├── KaTeX_Size4-Regular.woff2 │ │ ├── KaTeX_Typewriter-Regular.woff │ │ ├── KaTeX_Typewriter-Regular.woff2 │ │ ├── LiberationMono.woff │ │ ├── LiberationMono.woff2 │ │ ├── LiberationSans-Bold.woff │ │ ├── LiberationSans-Bold.woff2 │ │ ├── LiberationSans-BoldItalic.woff │ │ ├── LiberationSans-BoldItalic.woff2 │ │ ├── LiberationSans-Italic.woff │ │ ├── LiberationSans-Italic.woff2 │ │ ├── LiberationSans.woff │ │ ├── LiberationSans.woff2 │ │ ├── Metropolis.woff │ │ └── Metropolis.woff2 │ ├── img │ │ └── geekdoc-stack.svg │ ├── js │ │ ├── 116-341f79d9.chunk.min.js │ │ ├── 118-f1de6a20.chunk.min.js │ │ ├── 19-86f47ecd.chunk.min.js │ │ ├── 361-f7cd601a.chunk.min.js │ │ ├── 423-897d7f17.chunk.min.js │ │ ├── 430-cc171d93.chunk.min.js │ │ ├── 433-f2655a46.chunk.min.js │ │ ├── 438-760c9ed3.chunk.min.js │ │ ├── 476-86e5cf96.chunk.min.js │ │ ├── 506-6950d52c.chunk.min.js │ │ ├── 519-8d0cec7f.chunk.min.js │ │ ├── 535-dcead599.chunk.min.js │ │ ├── 545-8e970b03.chunk.min.js │ │ ├── 546-560b35c2.chunk.min.js │ │ ├── 579-9222afff.chunk.min.js │ │ ├── 626-1706197a.chunk.min.js │ │ ├── 637-86fbbecd.chunk.min.js │ │ ├── 637-86fbbecd.chunk.min.js.LICENSE.txt │ │ ├── 639-88c6538a.chunk.min.js │ │ ├── 642-12e7dea2.chunk.min.js │ │ ├── 662-17acb8f4.chunk.min.js │ │ ├── 662-17acb8f4.chunk.min.js.LICENSE.txt │ │ ├── 728-5df4a5e5.chunk.min.js │ │ ├── 729-32b017b3.chunk.min.js │ │ ├── 747-b55f0f97.chunk.min.js │ │ ├── 76-732e78f1.chunk.min.js │ │ ├── 771-942a62df.chunk.min.js │ │ ├── 773-8f0c4fb8.chunk.min.js │ │ ├── 81-4e653aac.chunk.min.js │ │ ├── 813-0d3c16f5.chunk.min.js │ │ ├── 940-25dfc794.chunk.min.js │ │ ├── colortheme-d3e4d351.bundle.min.js │ │ ├── katex-d4d5881d.bundle.min.js │ │ ├── main-924a1933.bundle.min.js │ │ ├── main-924a1933.bundle.min.js.LICENSE.txt │ │ ├── mermaid-d305d450.bundle.min.js │ │ ├── search-9719be99.bundle.min.js │ │ └── search-9719be99.bundle.min.js.LICENSE.txt │ ├── katex-66092164.min.css │ ├── main-252d384c.min.css │ ├── mobile-79ddc617.min.css │ └── print-735ccc12.min.css │ └── theme.toml ├── formatters ├── json │ └── json.go ├── pretty │ └── pretty.go └── sarif │ └── sarif.go ├── go.mod ├── go.sum ├── models ├── azure_pipelines.go ├── azure_pipelines_test.go ├── branch_info.go ├── config.go ├── github_actions.go ├── github_actions_test.go ├── gitlab.go ├── gitlab_test.go ├── package_insights.go ├── package_insights_test.go ├── pipeline_as_code_tekton.go ├── purl.go ├── purl_test.go └── tests │ └── actions-checkout-v4.json ├── opa ├── builtins.go ├── capabilities.json ├── models.go ├── opa.go ├── opa_test.go ├── populate_build_platform_vuln_database_test.go ├── poutine_build_platform_advisories.json ├── rego │ ├── external │ │ ├── build_platform.rego │ │ ├── osv.rego │ │ └── reputation.rego │ ├── poutine.rego │ ├── poutine │ │ ├── config.rego │ │ ├── format │ │ │ └── json.rego │ │ ├── inventory │ │ │ ├── azure_pipelines.rego │ │ │ ├── github_actions.rego │ │ │ └── gitlab.rego │ │ ├── queries │ │ │ ├── findings.rego │ │ │ ├── format.rego │ │ │ └── inventory.rego │ │ └── utils.rego │ └── rules │ │ ├── confused_deputy_auto_merge.rego │ │ ├── debug_enabled.rego │ │ ├── default_permissions_on_risky_events.rego │ │ ├── github_action_from_unverified_creator_used.rego │ │ ├── if_always_true.rego │ │ ├── injection.rego │ │ ├── job_all_secrets.rego │ │ ├── known_vulnerability_in_build_component.rego │ │ ├── known_vulnerability_in_build_platform.rego │ │ ├── pr_runs_on_self_hosted.rego │ │ ├── unpinnable_action.rego │ │ ├── untrusted_checkout_exec.rego │ │ └── unverified_script_exec.rego └── testdata │ └── config │ └── sample.rego ├── poutine.go ├── providers ├── github │ ├── client.go │ └── round_tripper_rate_limit.go ├── gitlab │ └── client.go ├── gitops │ ├── gitops.go │ └── gitops_test.go ├── local │ ├── client.go │ └── client_test.go ├── pkgsupply │ ├── models.go │ ├── static.go │ ├── static_test.go │ ├── testdata │ │ └── reputation.json │ └── unpinnable_actions.txt └── scm │ ├── domain │ ├── scm_domain.go │ └── scm_domain_test.go │ └── scm.go ├── results └── results.go └── scanner ├── inventory.go ├── inventory_scanner.go ├── inventory_scanner_mem.go ├── inventory_scanner_test.go ├── inventory_test.go ├── parsers.go └── testdata ├── .azure-pipelines.yml ├── .github ├── action.yaml └── workflows │ ├── allowed_pr_runner.yml │ ├── debug_enabled_valid.yml │ ├── invalid-workflow.yaml │ ├── invalid-yaml.yml │ ├── matrix.yml │ ├── random-file │ ├── reusable.yml │ ├── secrets.yaml │ ├── valid.yml │ ├── workflow_run_reusable.yml │ └── workflow_run_valid.yml ├── .gitlab-ci.yml ├── .local-ci-template.yml ├── .tekton └── pipeline-as-code-tekton.yml ├── action.yml ├── azure-pipelines-1.yml ├── azure-pipelines-2.yml ├── azure-pipelines-3.yml ├── azure-pipelines-4.yml ├── composite └── action.yml └── include.yml /.dockerignore: -------------------------------------------------------------------------------- 1 | .github 2 | .git 3 | docs/themes 4 | Dockerfile 5 | .dockerignore 6 | .env 7 | /*.md 8 | /poutine 9 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @boostsecurityio/security 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 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 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 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 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | - package-ecosystem: "gomod" 8 | directory: "/" 9 | schedule: 10 | interval: "monthly" 11 | -------------------------------------------------------------------------------- /.github/workflows/build_test.yml: -------------------------------------------------------------------------------- 1 | name: Go Build and Test 2 | on: 3 | push: 4 | branches: [ main ] 5 | pull_request: 6 | branches: [ main ] 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | build_test: 12 | strategy: 13 | matrix: 14 | platform: [ ubuntu-latest, macos-latest ] 15 | runs-on: ${{ matrix.platform }} 16 | steps: 17 | - name: Harden Runner 18 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 19 | with: 20 | egress-policy: audit 21 | 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 23 | - name: Setup Go 24 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 25 | with: 26 | go-version: '1.24' 27 | - name: Install dependencies 28 | run: go mod download 29 | - name: Verify dependencies 30 | run: go mod verify 31 | - name: Build 32 | run: go build -v ./... 33 | - name: Test 34 | run: go test -v ./... 35 | -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | # Dependency Review Action 2 | # 3 | # This Action will scan dependency manifest files that change as part of a Pull Request, 4 | # surfacing known-vulnerable versions of the packages declared or updated in the PR. 5 | # Once installed, if the workflow run is marked as required, 6 | # PRs introducing known-vulnerable packages will be blocked from merging. 7 | # 8 | # Source repository: https://github.com/actions/dependency-review-action 9 | name: 'Dependency Review' 10 | on: 11 | pull_request: 12 | paths-ignore: 13 | - 'README.md' 14 | - 'LICENSE' 15 | - 'docs/**' 16 | - '.github/**' 17 | 18 | permissions: 19 | contents: read 20 | 21 | jobs: 22 | dependency-review: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - name: Harden Runner 26 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 27 | with: 28 | egress-policy: audit 29 | 30 | - name: 'Checkout Repository' 31 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 32 | - name: 'Dependency Review' 33 | uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1 34 | -------------------------------------------------------------------------------- /.github/workflows/deploy-github-pages.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Hugo site to Pages 2 | 3 | on: 4 | push: 5 | branches: ["main"] 6 | paths: 7 | - 'docs/**' 8 | workflow_dispatch: 9 | 10 | permissions: {} 11 | 12 | concurrency: 13 | group: "pages" 14 | cancel-in-progress: false 15 | 16 | defaults: 17 | run: 18 | shell: bash 19 | 20 | jobs: 21 | build: 22 | runs-on: ubuntu-latest 23 | permissions: 24 | contents: read 25 | env: 26 | HUGO_VERSION: 0.124.1 27 | steps: 28 | - name: Install Hugo CLI 29 | run: | 30 | wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \ 31 | && sudo dpkg -i ${{ runner.temp }}/hugo.deb 32 | - name: Install Dart Sass 33 | run: sudo snap install dart-sass 34 | - name: Checkout 35 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 36 | with: 37 | submodules: recursive 38 | - name: Setup Pages 39 | id: pages 40 | uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 41 | - name: Install Node.js dependencies 42 | working-directory: ./docs 43 | run: "[[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true" 44 | - name: Build with Hugo 45 | working-directory: ./docs 46 | env: 47 | HUGO_ENVIRONMENT: production 48 | HUGO_ENV: production 49 | run: | 50 | hugo \ 51 | --minify \ 52 | --baseURL "${{ steps.pages.outputs.base_url }}/" 53 | - name: Upload artifact 54 | uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 55 | with: 56 | path: ./docs/public 57 | 58 | deploy: 59 | runs-on: ubuntu-latest 60 | needs: build 61 | environment: 62 | name: github-pages 63 | url: ${{ steps.deployment.outputs.page_url }} 64 | permissions: 65 | contents: read 66 | pages: write 67 | id-token: write 68 | steps: 69 | - name: Deploy to GitHub Pages 70 | id: deployment 71 | uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 72 | -------------------------------------------------------------------------------- /.github/workflows/golangci-lint.yml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | 8 | permissions: 9 | contents: read 10 | pull-requests: read 11 | checks: write 12 | 13 | jobs: 14 | golangci: 15 | name: lint 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 19 | - uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # 5.5.0 20 | with: 21 | go-version: '1.24' 22 | cache: false 23 | - name: golangci-lint 24 | uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd # v7.0.0 25 | with: 26 | version: v2.0 27 | only-new-issues: true 28 | args: --timeout=5m -------------------------------------------------------------------------------- /.github/workflows/pop.yml: -------------------------------------------------------------------------------- 1 | name: POP - poutine on poutine 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - .github/workflows/** 8 | - action.yml 9 | 10 | pull_request: 11 | branches: [ main ] 12 | paths: 13 | - .github/workflows/** 14 | - action.yml 15 | - '!README.md' 16 | - '!LICENSE' 17 | - '!docs/**' 18 | - '!.github/**' 19 | 20 | permissions: {} 21 | 22 | jobs: 23 | pop: 24 | runs-on: ubuntu-latest 25 | permissions: 26 | security-events: write 27 | contents: read 28 | steps: 29 | - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 30 | with: 31 | disable-sudo: true 32 | egress-policy: audit 33 | allowed-endpoints: > 34 | github.com:443 35 | api.github.com:443 36 | codeload.github.com:443 37 | objects.githubusercontent.com:443 38 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 39 | - uses: boostsecurityio/poutine-action@main # Dogfood the latest action 40 | name: "Run poutine on poutine's own codebase" 41 | id: self-test 42 | - name: Upload SARIF file 43 | uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 44 | with: 45 | sarif_file: results.sarif 46 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: goreleaser 2 | 3 | on: 4 | push: 5 | # run only against tags 6 | tags: 7 | - "v0.[0-9]+.[0-9]+" 8 | - "v1.[0-9]+.[0-9]+" 9 | 10 | env: 11 | GO_VERSION: 1.24 12 | GO_RELEASER_VERSION: v2.4.7 13 | 14 | permissions: {} 15 | 16 | jobs: 17 | goreleaser: 18 | runs-on: ubuntu-latest 19 | permissions: 20 | contents: write 21 | packages: write 22 | id-token: write 23 | steps: 24 | - uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 25 | with: 26 | egress-policy: audit 27 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 28 | with: 29 | fetch-depth: 0 30 | - name: Setup Go 31 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 32 | with: 33 | go-version: ${{ env.GO_VERSION }} 34 | cache: false 35 | - uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 36 | - name: Login to GitHub Container Registry to allow cosign signature push 37 | run: echo "$DOCKER_PASSWORD" | docker login ghcr.io --username "$DOCKER_USERNAME" --password-stdin 38 | env: 39 | DOCKER_USERNAME: ${{ github.actor }} 40 | DOCKER_PASSWORD: ${{ secrets.GITHUB_TOKEN }} 41 | - name: Run GoReleaser 42 | uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # v6.3.0 43 | with: 44 | distribution: goreleaser 45 | version: ${{ env.GO_RELEASER_VERSION }} # Not pinnable by hash, nor does it verify its signature 46 | args: release --clean 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 49 | -------------------------------------------------------------------------------- /.github/workflows/scorecards.yml: -------------------------------------------------------------------------------- 1 | name: Scorecard supply-chain security 2 | on: 3 | branch_protection_rule: 4 | schedule: 5 | - cron: '20 7 * * 2' 6 | push: 7 | branches: ["main"] 8 | workflow_dispatch: 9 | 10 | permissions: read-all 11 | 12 | jobs: 13 | analysis: 14 | name: Scorecard analysis 15 | runs-on: ubuntu-latest 16 | permissions: 17 | # Needed to upload the results to code-scanning dashboard. 18 | security-events: write 19 | # Needed to publish results and get a badge (see publish_results below). 20 | id-token: write 21 | contents: read 22 | actions: read 23 | 24 | steps: 25 | - name: Harden Runner 26 | uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0 27 | with: 28 | egress-policy: audit 29 | 30 | - name: "Checkout code" 31 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 32 | with: 33 | persist-credentials: false 34 | 35 | - name: "Run analysis" 36 | uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2 37 | with: 38 | results_file: results.sarif 39 | results_format: sarif 40 | publish_results: true 41 | 42 | - name: "Upload artifact" 43 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 44 | with: 45 | name: SARIF file 46 | path: results.sarif 47 | retention-days: 5 48 | 49 | - name: "Upload to code-scanning" 50 | uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 51 | with: 52 | sarif_file: results.sarif 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /poutine 2 | dist/ 3 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | version: "2" 2 | linters: 3 | default: none 4 | enable: 5 | - copyloopvar 6 | - errcheck 7 | - errorlint 8 | - govet 9 | - ineffassign 10 | - perfsprint 11 | - prealloc 12 | - predeclared 13 | - protogetter 14 | - staticcheck 15 | - testifylint 16 | - unused 17 | - wrapcheck 18 | - zerologlint 19 | exclusions: 20 | generated: lax 21 | presets: 22 | - comments 23 | - common-false-positives 24 | - legacy 25 | - std-error-handling 26 | paths: 27 | - third_party$ 28 | - builtin$ 29 | - examples$ 30 | formatters: 31 | enable: 32 | - gofmt 33 | exclusions: 34 | generated: lax 35 | paths: 36 | - third_party$ 37 | - builtin$ 38 | - examples$ 39 | -------------------------------------------------------------------------------- /.goreleaser.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | project_name: poutine 3 | 4 | before: 5 | hooks: 6 | - go mod verify 7 | 8 | builds: 9 | - env: 10 | - CGO_ENABLED=0 11 | goos: 12 | - linux 13 | - darwin 14 | goarch: 15 | - amd64 16 | - arm64 17 | - arm 18 | flags: 19 | - -trimpath 20 | ldflags: 21 | - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser 22 | goarm: 23 | - '7' 24 | 25 | kos: 26 | - repository: ghcr.io/boostsecurityio/poutine 27 | base_image: 'cgr.dev/chainguard/git:latest@sha256:06119871a608d163eac2daddd0745582e457a29ee8402bd351c13f294ede30e1' 28 | tags: 29 | - '{{.Version}}' 30 | - latest 31 | bare: true 32 | preserve_import_paths: false 33 | platforms: 34 | - linux/amd64 35 | - linux/arm64 36 | 37 | docker_signs: 38 | - artifacts: manifests 39 | args: 40 | - "sign" 41 | - "${artifact}" 42 | - "--yes" # skip user interaction 43 | 44 | signs: 45 | - cmd: cosign 46 | certificate: '${artifact}.pem' 47 | args: 48 | - "sign-blob" 49 | - "--output-certificate=${certificate}" 50 | - "--output-signature=${signature}" 51 | - "${artifact}" 52 | - "--yes" # skip user interaction 53 | artifacts: all 54 | output: true 55 | 56 | archives: 57 | - format: tar.gz 58 | # this name template makes the OS and Arch compatible with the results of `uname`. 59 | name_template: >- 60 | {{ .ProjectName }}_ 61 | {{- title .Os }}_ 62 | {{- if eq .Arch "amd64" }}x86_64 63 | {{- else if eq .Arch "386" }}i386 64 | {{- else }}{{ .Arch }}{{ end }} 65 | {{- if .Arm }}v{{ .Arm }}{{ end }} 66 | # use zip for windows archives 67 | format_overrides: 68 | - goos: windows 69 | format: zip 70 | 71 | changelog: 72 | use: github-native 73 | sort: asc 74 | filters: 75 | exclude: 76 | - "^docs:" 77 | - "^test:" 78 | -------------------------------------------------------------------------------- /.poutine.sample.yml: -------------------------------------------------------------------------------- 1 | # When using analyze_org, ignore forked repositories in the organization 2 | # default: false 3 | ignoreForks: true 4 | 5 | # Set rule configuration options 6 | rulesConfig: 7 | pr_runs_on_self_hosted: 8 | allowed_runners: 9 | - self-hosted 10 | - label:gpu 11 | - group:prdeploy 12 | 13 | 14 | # Skip findings if any rules in this list matches the finding's properties. 15 | # Each rule can have the following keys: job, level, osv_id, path, purl, rule. 16 | # The value of each key is a string or a list of strings. 17 | # default: [] 18 | skip: 19 | 20 | 21 | skipExamples: 22 | # skip findings by rule level (one of: note, warning, error) 23 | - level: note 24 | 25 | # skip findings at a given path 26 | - path: .github/workflows/safe.yml 27 | 28 | # skip findings of a given rule 29 | - rule: unpinnable_action 30 | 31 | # skip findings of a rule at given paths 32 | - rule: pr_runs_on_self_hosted 33 | path: 34 | - .github/workflows/pr.yml 35 | 36 | # skip findings of a rule about a list of packages 37 | - rule: github_action_from_unverified_creator_used 38 | purl: 39 | - pkg:githubactions/dorny/paths-filter 40 | - pkg:githubactions/golangci/golangci-lint-action 41 | 42 | # skip findings of a rule for a list of repositories 43 | - rule: pr_runs_on_self_hosted 44 | purl: 45 | - pkg:github/org/repo 46 | 47 | # skip findings by OSV ID 48 | - osv_id: 49 | - GHSA-mcph-m25j-8j63 50 | 51 | 52 | # includes only this set of rules 53 | allowedRules: 54 | - "pr_runs_on_self_hosted" 55 | - "unpinnable_action" 56 | - "github_action_from_unverified_creator_used" 57 | -------------------------------------------------------------------------------- /.poutine.yml: -------------------------------------------------------------------------------- 1 | include: 2 | - path: .poutine 3 | ignoreForks: true 4 | -------------------------------------------------------------------------------- /.poutine/config.rego: -------------------------------------------------------------------------------- 1 | package poutine.config 2 | 3 | import rego.v1 4 | 5 | skip if { 6 | startswith(finding.meta.path, "scanner/testdata") 7 | } 8 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Poutine 2 | 3 | Thank you for your interest in contributing to `poutine`! We value the contributions of our community members and look forward to your input. 4 | 5 | ## Code of Conduct 6 | 7 | Before you start contributing, please make sure to read and abide by our [Code of Conduct](./CODE_OF_CONDUCT.md). Additionally, we follow the Linux Foundation's guidelines for commit sign-offs. Please sign off your commits using the `-s` or `--signoff` flag. 8 | 9 | ## Getting Started 10 | 11 | ### Environment Setup 12 | 13 | To contribute to Poutine, you'll need the following: 14 | 15 | - [Go toolchain v1.24](https://golang.org/dl/) or higher. 16 | 17 | ### Contributing Process 18 | 19 | 1. **Find an Issue or Feature**: Check our [Roadmap](https://github.com/orgs/boostsecurityio/projects/2) or open [GitHub Issues](https://github.com/boostsecurityio/poutine/issues). Pick an existing issue or propose your feature request there. 20 | 21 | 2. **Get Approval**: For new features, wait for the issue to be labeled `Approved` by the maintainers. 22 | 23 | 3. **Fork and Code**: Fork the repository, make your changes, and ensure your code adheres to the provided coding conventions and quality standards. 24 | 25 | 4. **Submit a Pull Request (PR)**: Once you've completed your changes, submit a PR. Make sure your PR title and description clearly describe the changes. Include the issue number your PR addresses. 26 | 27 | ### Testing and Linting 28 | 29 | - Run `gofmt` to ensure your code is properly formatted. 30 | - Include any tests relevant to the bug or feature you are addressing. 31 | 32 | ### Documentation 33 | 34 | - Update the `README.md` if you introduce or modify any commands. 35 | - If your changes involve adding or altering rules, update the corresponding markdown file in `docs/content/en/rules/[RULE_ID].md`. 36 | 37 | ## Community and Questions 38 | 39 | Currently, we handle all communications through GitHub issues and pull requests. If you have questions or need help with the setup, please open an issue and tag it as a question. 40 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG GIT=cgr.dev/chainguard/git:latest@sha256:06119871a608d163eac2daddd0745582e457a29ee8402bd351c13f294ede30e1 2 | ARG GORELEASER=ghcr.io/goreleaser/goreleaser:v2.3.1@sha256:6835c0b61b746bf4b2e036e262d3c5c32029ebb079eb42911bffa84b1b5c8008 3 | 4 | FROM ${GORELEASER} as goreleaser 5 | WORKDIR /app 6 | COPY . . 7 | RUN goreleaser build --snapshot --single-target 8 | RUN mv dist/*/poutine /usr/bin/poutine 9 | 10 | FROM ${GIT} as base 11 | WORKDIR /src 12 | RUN git config --global --add safe.directory /src 13 | 14 | FROM base as poutine 15 | COPY --from=goreleaser /usr/bin/poutine /usr/bin/poutine 16 | ENTRYPOINT ["/usr/bin/poutine"] 17 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Maintainers 2 | 3 | ## `poutine-maintainers` 4 | 5 | In alphabetical order: 6 | - Alexis-Maurer Fortin ([@SUSTAPLE117](https://github.com/SUSTAPLE117)), BoostSecurity.io 7 | - François Proulx ([@fproulx-boostsecurity](https://github.com/fproulx-boostsecurity)), BoostSecurity.io 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL=/usr/bin/env bash 2 | .SHELLFLAGS=-o pipefail -ec 3 | .DEFAULT_GOAL := test 4 | 5 | .PHONY: build 6 | build: 7 | go build -o poutine . 8 | 9 | ci: fmt test lint 10 | 11 | test: 12 | go test ./... -cover 13 | 14 | fmt: 15 | go fmt ./... 16 | 17 | lint: 18 | golangci-lint run 19 | -------------------------------------------------------------------------------- /cmd/analyzeLocal.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/boostsecurityio/poutine/analyze" 7 | "github.com/boostsecurityio/poutine/providers/gitops" 8 | "github.com/boostsecurityio/poutine/providers/local" 9 | 10 | "github.com/spf13/cobra" 11 | ) 12 | 13 | // analyzeLocalCmd represents the analyzeLocal command 14 | var analyzeLocalCmd = &cobra.Command{ 15 | Use: "analyze_local", 16 | Short: "Analyzes a local repository for supply chain vulnerabilities", 17 | Long: `Analyzes a local repository for supply chain vulnerabilities 18 | Example: poutine analyze_local /path/to/repo`, 19 | Args: cobra.ExactArgs(1), 20 | RunE: func(cmd *cobra.Command, args []string) error { 21 | ctx := cmd.Context() 22 | repoPath := args[0] 23 | 24 | opaClient, err := newOpa(ctx) 25 | if err != nil { 26 | return err 27 | } 28 | 29 | formatter := GetFormatter(opaClient) 30 | 31 | localScmClient, err := local.NewGitSCMClient(ctx, repoPath, nil) 32 | if err != nil { 33 | return fmt.Errorf("failed to create local SCM client: %w", err) 34 | } 35 | 36 | localGitClient := gitops.NewLocalGitClient(nil) 37 | 38 | analyzer := analyze.NewAnalyzer(localScmClient, localGitClient, formatter, config, opaClient) 39 | 40 | _, err = analyzer.AnalyzeLocalRepo(ctx, repoPath) 41 | if err != nil { 42 | return fmt.Errorf("failed to analyze repoPath %s: %w", repoPath, err) 43 | } 44 | 45 | return nil 46 | }, 47 | } 48 | 49 | func init() { 50 | RootCmd.AddCommand(analyzeLocalCmd) 51 | } 52 | -------------------------------------------------------------------------------- /cmd/analyzeOrg.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | "github.com/spf13/viper" 8 | ) 9 | 10 | var threads int 11 | 12 | // analyzeOrgCmd represents the analyzeOrg command 13 | var analyzeOrgCmd = &cobra.Command{ 14 | Use: "analyze_org", 15 | Short: "Analyzes an organization's repositories for supply chain vulnerabilities", 16 | Long: `Analyzes an organization's repositories for supply chain vulnerabilities 17 | Example: poutine analyze_org org --token "$GH_TOKEN" 18 | 19 | Analyze All Projects in a Self-Hosted Gitlab Organization: 20 | poutine analyze_org my-org/project --token "$GL_TOKEN" --scm gitlab --scm-base-uri https://gitlab.example.com 21 | 22 | Note: This command will scan all repositories in the organization except those that are Archived. 23 | `, 24 | Args: cobra.ExactArgs(1), 25 | RunE: func(cmd *cobra.Command, args []string) error { 26 | Token = viper.GetString("token") 27 | ctx := cmd.Context() 28 | analyzer, err := GetAnalyzer(ctx, "analyze_org") 29 | if err != nil { 30 | return err 31 | } 32 | 33 | org := args[0] 34 | 35 | _, err = analyzer.AnalyzeOrg(ctx, org, &threads) 36 | if err != nil { 37 | return fmt.Errorf("failed to analyze org %s: %w", org, err) 38 | } 39 | 40 | return nil 41 | }, 42 | } 43 | 44 | func init() { 45 | RootCmd.AddCommand(analyzeOrgCmd) 46 | 47 | analyzeOrgCmd.Flags().StringVarP(&Token, "token", "t", "", "SCM access token (env: GH_TOKEN)") 48 | 49 | analyzeOrgCmd.Flags().IntVarP(&threads, "threads", "j", 2, "Parallelization factor for scanning organizations") 50 | analyzeOrgCmd.Flags().BoolVarP(&config.IgnoreForks, "ignore-forks", "i", false, "Ignore forked repositories in the organization") 51 | 52 | viper.BindPFlag("token", analyzeOrgCmd.Flags().Lookup("token")) 53 | viper.BindPFlag("ignoreForks", analyzeOrgCmd.Flags().Lookup("ignore-forks")) 54 | viper.BindEnv("token", "GH_TOKEN") 55 | } 56 | -------------------------------------------------------------------------------- /cmd/analyzeRepo.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | "github.com/spf13/viper" 8 | ) 9 | 10 | var ref string 11 | 12 | // analyzeRepoCmd represents the analyzeRepo command 13 | var analyzeRepoCmd = &cobra.Command{ 14 | Use: "analyze_repo", 15 | Short: "Analyzes a remote repository for supply chain vulnerabilities", 16 | Long: `Analyzes a remote repository for supply chain vulnerabilities 17 | Example Scanning a remote Github Repository: poutine analyze_repo org/repo --token "$GH_TOKEN"`, 18 | Args: cobra.ExactArgs(1), 19 | RunE: func(cmd *cobra.Command, args []string) error { 20 | Token = viper.GetString("token") 21 | ctx := cmd.Context() 22 | analyzer, err := GetAnalyzer(ctx, "analyze_repo") 23 | if err != nil { 24 | return err 25 | } 26 | 27 | repo := args[0] 28 | 29 | _, err = analyzer.AnalyzeRepo(ctx, repo, ref) 30 | if err != nil { 31 | return fmt.Errorf("failed to analyze repo %s: %w", repo, err) 32 | } 33 | 34 | return nil 35 | }, 36 | } 37 | 38 | func init() { 39 | RootCmd.AddCommand(analyzeRepoCmd) 40 | 41 | analyzeRepoCmd.Flags().StringVarP(&Token, "token", "t", "", "SCM access token (env: GH_TOKEN)") 42 | analyzeRepoCmd.Flags().StringVarP(&ref, "ref", "r", "HEAD", "Commit or branch to analyze (defaults to HEAD)") 43 | 44 | viper.BindPFlag("token", analyzeOrgCmd.Flags().Lookup("token")) 45 | viper.BindEnv("token", "GH_TOKEN") 46 | } 47 | -------------------------------------------------------------------------------- /cmd/analyzeRepoStaleBranches.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "regexp" 7 | 8 | "github.com/spf13/cobra" 9 | "github.com/spf13/viper" 10 | ) 11 | 12 | var expand bool 13 | var regex string 14 | 15 | var analyzeRepoStaleBranches = &cobra.Command{ 16 | Use: "analyze_repo_stale_branches", 17 | Short: "Analyzes a remote repository for pull_request_target vulnerabilities in stale branches", 18 | Long: `Analyzes a remote repository, looping through all remote branches to find unique GitHub Actions workflows with old pull_request_target vulnerabilities, even though the default branch does not have that vulnerability anymore. 19 | Example Scanning a remote Github Repository: poutine analyze_repo_stale_branches org/repo --token "$GH_TOKEN"`, 20 | Args: cobra.ExactArgs(1), 21 | RunE: func(cmd *cobra.Command, args []string) error { 22 | Token = viper.GetString("token") 23 | ctx := cmd.Context() 24 | analyzer, err := GetAnalyzer(ctx, "analyze_repo_stale_branches") 25 | if err != nil { 26 | return fmt.Errorf("error getting analyzer analyze_repo_stale_branches: %w", err) 27 | } 28 | 29 | if Format == "sarif" { 30 | return errors.New("sarif formatter not supported for analyze_repo_stale_branches") 31 | } 32 | 33 | repo := args[0] 34 | 35 | reg, err := regexp.Compile(regex) 36 | if err != nil { 37 | return fmt.Errorf("error compiling regex: %w", err) 38 | } 39 | 40 | _, err = analyzer.AnalyzeStaleBranches(ctx, repo, &threads, &expand, reg) 41 | if err != nil { 42 | return fmt.Errorf("failed to analyze repo %s: %w", repo, err) 43 | } 44 | 45 | return nil 46 | }, 47 | } 48 | 49 | func init() { 50 | RootCmd.AddCommand(analyzeRepoStaleBranches) 51 | 52 | analyzeRepoStaleBranches.Flags().StringVarP(&Token, "token", "t", "", "SCM access token (env: GH_TOKEN)") 53 | analyzeRepoStaleBranches.Flags().IntVarP(&threads, "threads", "j", 5, "Parallelization factor for scanning stale branches") 54 | analyzeRepoStaleBranches.Flags().BoolVarP(&expand, "expand", "e", false, "Expand the output to the classic representation from analyze_repo") 55 | analyzeRepoStaleBranches.Flags().StringVarP(®ex, "regex", "r", "pull_request_target", "Regex to check if the workflow is accessible in stale branches") 56 | 57 | _ = viper.BindPFlag("token", analyzeRepoStaleBranches.Flags().Lookup("token")) 58 | _ = viper.BindEnv("token", "GH_TOKEN") 59 | } 60 | -------------------------------------------------------------------------------- /cmd/version.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | ) 8 | 9 | // versionCmd represents the version command 10 | var versionCmd = &cobra.Command{ 11 | Use: "version", 12 | Short: "prints the version of poutine", 13 | Run: func(cmd *cobra.Command, args []string) { 14 | fmt.Printf("Version: %s\nCommit: %s\nBuilt At: %s\n", Version, Commit, Date) 15 | return 16 | }, 17 | } 18 | 19 | func init() { 20 | RootCmd.AddCommand(versionCmd) 21 | } 22 | -------------------------------------------------------------------------------- /dagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "poutine", 3 | "sdk": "go", 4 | "source": "dagger", 5 | "engineVersion": "v0.11.6" 6 | } 7 | -------------------------------------------------------------------------------- /dagger/.gitattributes: -------------------------------------------------------------------------------- 1 | /dagger.gen.go linguist-generated 2 | /internal/dagger/** linguist-generated 3 | /internal/querybuilder/** linguist-generated 4 | /internal/telemetry/** linguist-generated 5 | -------------------------------------------------------------------------------- /dagger/.gitignore: -------------------------------------------------------------------------------- 1 | /dagger.gen.go 2 | /internal/dagger 3 | /internal/querybuilder 4 | /internal/telemetry 5 | -------------------------------------------------------------------------------- /dagger/go.mod: -------------------------------------------------------------------------------- 1 | module dagger/poutine 2 | 3 | go 1.24.0 4 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | public/** 2 | -------------------------------------------------------------------------------- /docs/.hugo_build.lock: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/.hugo_build.lock -------------------------------------------------------------------------------- /docs/archetypes/default.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = '{{ replace .File.ContentBaseName "-" " " | title }}' 3 | date = {{ .Date }} 4 | draft = true 5 | +++ 6 | -------------------------------------------------------------------------------- /docs/content.go: -------------------------------------------------------------------------------- 1 | package docs 2 | 3 | import ( 4 | "embed" 5 | "fmt" 6 | "path" 7 | "strings" 8 | ) 9 | 10 | //go:embed content 11 | var content embed.FS 12 | 13 | type Page struct { 14 | Content string `yaml:"-"` 15 | } 16 | 17 | func GetPagesContent() map[string]string { 18 | docs := map[string]string{} 19 | entries, err := content.ReadDir(path.Join("content", "en", "rules")) 20 | if err != nil { 21 | return docs 22 | } 23 | 24 | for _, entry := range entries { 25 | ruleId := strings.TrimSuffix(entry.Name(), ".md") 26 | page, err := GetPage(ruleId) 27 | if err != nil { 28 | continue 29 | } 30 | 31 | docs[ruleId] = page.Content 32 | } 33 | 34 | return docs 35 | } 36 | 37 | func GetPage(ruleId string) (*Page, error) { 38 | doc, err := content.ReadFile( 39 | path.Join("content", "en", "rules", ruleId+".md")) 40 | if err != nil { 41 | return nil, err 42 | } 43 | 44 | parts := strings.SplitAfterN(string(doc), "---\n", 3) 45 | if len(parts) != 3 { 46 | return nil, fmt.Errorf("invalid doc page %s.md", ruleId) 47 | } 48 | 49 | return &Page{Content: strings.TrimSpace(parts[2])}, nil 50 | } 51 | -------------------------------------------------------------------------------- /docs/content/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "poutine" 3 | --- 4 | 5 | This is the documentation for the [poutine](https://github.com/boostsecurityio/poutine) project. -------------------------------------------------------------------------------- /docs/content/en/rules/debug_enabled.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "CI Debug Enabled" 3 | slug: debug_enabled 4 | url: /rules/debug_enabled/ 5 | rule: debug_enabled 6 | severity: note 7 | --- 8 | 9 | ## Description 10 | 11 | The workflow is configured to increase the verbosity of the runner. This can 12 | potentially expose sensitive information. 13 | 14 | ## Remediation 15 | 16 | ### GitHub Actions 17 | 18 | In the workflow file, remove the `ACTIONS_RUNNER_DEBUG` or `ACTIONS_STEP_DEBUG` environment variables. This may also be enabled by setting a secret or variable, so the fact that `poutine` does not detect those variables, does not guarantee it is not enabled otherwise. 19 | 20 | #### Recommended 21 | ```yaml 22 | on: 23 | push: 24 | 25 | jobs: 26 | build: 27 | runs-on: ubuntu-latest 28 | steps: 29 | - id: 1 30 | run: echo Hello 31 | ``` 32 | 33 | #### Anti-Pattern 34 | ```yaml 35 | on: 36 | push: 37 | 38 | env: 39 | ACTIONS_RUNNER_DEBUG: true 40 | 41 | jobs: 42 | build: 43 | runs-on: ubuntu-latest 44 | steps: 45 | - id: 1 46 | env: 47 | ACTIONS_STEP_DEBUG: true 48 | run: echo Hello 49 | ``` 50 | 51 | 52 | ### Gitlab CI 53 | 54 | In the workflow file, remove the `CI_DEBUG_TRACE` or `CI_DEBUG_SERVICES` variable in the `job` definition or set to false. 55 | 56 | #### Recommended 57 | ```yaml 58 | job_name: 59 | variables: 60 | CI_DEBUG_TRACE: "false" # Or, better, simply omit those variables as they default to `false` anyway. 61 | CI_DEBUG_SERVICES: "false" 62 | ``` 63 | 64 | #### Anti-Pattern 65 | ```yaml 66 | job_name: 67 | variables: 68 | CI_DEBUG_TRACE: "true" 69 | CI_DEBUG_SERVICES: "true" 70 | ``` 71 | ### Azure DevOps 72 | 73 | In the pipeline file, remove the `system.debug` variable in the `variables` definition or set to false. 74 | 75 | #### Recommended 76 | ```yaml 77 | variables: 78 | system.debug: 'false' # Or, better, simply omit this variable as they default to `false` anyway. 79 | ``` 80 | 81 | #### Anti-Pattern 82 | ```yaml 83 | variables: 84 | system.debug: 'true' 85 | ``` 86 | 87 | ## See Also 88 | - https://docs.github.com/en/actions/monitoring-and-troubleshooting-workflows/enabling-debug-logging 89 | - https://docs.gitlab.com/ee/ci/variables/index.html#enable-debug-logging 90 | - https://docs.gitlab.com/ee/ci/variables/index.html#mask-a-cicd-variable 91 | - https://learn.microsoft.com/en-us/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemdebug 92 | -------------------------------------------------------------------------------- /docs/content/en/rules/github_action_from_unverified_creator_used.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Github Action from Unverified Creator used" 3 | slug: github_action_from_unverified_creator_used 4 | url: /rules/github_action_from_unverified_creator_used/ 5 | rule: github_action_from_unverified_creator_used 6 | severity: note 7 | --- 8 | 9 | ## Description 10 | 11 | Usage of the following GitHub Actions repositories was detected in workflows 12 | or composite actions, but their owner is not a verified creator. 13 | 14 | ## Remediation 15 | 16 | In the workflow file, replace the action with a verified creator's action if possible. Verified creators can be found in the GitHub Marketplace. 17 | 18 | Even if the action is published by a Verified Creator, it should not imply that the action is secure or still maintained. A popular action (with many stars and/or downloads) neither implies that it is safe. 19 | 20 | Running `poutine` against the org / repo where the action is published can help you in your own risk analysis. 21 | 22 | ## See Also 23 | - [Actions published by Verified Creators on the GitHub Actions Marketplace](https://github.com/marketplace?query=sort%3Apopularity-desc&type=actions&verification=verified_creator) 24 | - [About badges in GitHub Marketplace](https://docs.github.com/en/actions/creating-actions/publishing-actions-in-github-marketplace#about-badges-in-github-marketplace) -------------------------------------------------------------------------------- /docs/content/en/rules/if_always_true.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "If condition always evaluates to true" 3 | slug: if_always_true 4 | url: /rules/if_always_true/ 5 | rule: if_always_true 6 | severity: error 7 | --- 8 | 9 | ## Description 10 | 11 | GitHub Actions expressions used in if condition of jobs or steps 12 | must not contain extra characters or spaces. 13 | Otherwise, the condition is always evaluated to `true`. 14 | 15 | This can lead to logic bugs and possibly expose parts of the workflow only meant to be executed in secure contexts. 16 | 17 | ## Remediation 18 | 19 | #### Recommended 20 | ```yaml 21 | name: Conditionally process PR 22 | 23 | on: 24 | pull_request_target: 25 | types: [opened, synchronize, reopened] 26 | 27 | jobs: 28 | process-pr: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Auto-format markdown files 32 | if: github.actor == 'torvalds' || github.actor == 'dependabot[bot]' 33 | uses: messypoutine/actionable/.github/actions/auto-format@0108c4ec935a308435e665a0e9c2d1bf91e25685 # v1.0.0 34 | ``` 35 | 36 | #### Anti-Pattern 37 | ```yaml 38 | name: Conditionally process PR 39 | 40 | on: 41 | pull_request_target: 42 | types: [opened, synchronize, reopened] 43 | 44 | jobs: 45 | process-pr: 46 | runs-on: ubuntu-latest 47 | steps: 48 | - name: Auto-format markdown files 49 | if: | 50 | ${{ 51 | github.actor == 'torvalds' || 52 | github.actor == 'dependabot[bot]' 53 | }} 54 | uses: messypoutine/actionable/.github/actions/auto-format@0108c4ec935a308435e665a0e9c2d1bf91e25685 # v1.0.0 55 | ``` 56 | 57 | 58 | ## See Also 59 | - [Expression Always True Github Issue](https://github.com/actions/runner/issues/1173) 60 | - [About expressions](https://docs.github.com/en/actions/learn-github-actions/expressions#about-expressions) 61 | - [jobs.if](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idif) -------------------------------------------------------------------------------- /docs/content/en/rules/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/content/en/rules/img.png -------------------------------------------------------------------------------- /docs/content/en/rules/img_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/content/en/rules/img_1.png -------------------------------------------------------------------------------- /docs/content/en/rules/job_all_secrets.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Job uses all secrets" 3 | slug: job_all_secrets 4 | url: /rules/job_all_secrets/ 5 | rule: job_all_secrets 6 | severity: warning 7 | --- 8 | 9 | ## Description 10 | 11 | A GitHub Actions job was found to have access to all secrets. This may be unnecessary and expose sensitive information to the job. 12 | 13 | This can occur when the `secrets` object is serialized to JSON. For example: 14 | ```yaml 15 | env: 16 | ALL_SECRETS: ${{ toJSON(secrets) }} 17 | ``` 18 | 19 | Accessing the `secrets` object using a dynamic key will also expose all secrets to the job. For example: 20 | ```yaml 21 | strategy: 22 | matrix: 23 | env: [PROD, DEV] 24 | env: 25 | GH_TOKEN: ${{ secrets[format('GH_PAT_%s', matrix.env)] }} 26 | ``` 27 | 28 | In this example, both secrets `GH_PAT_DEV` and `GH_PAT_PROD` are made available in each job as the GitHub Actions runner is unable to determine the secrets the job requires. As a result, all repository and organization secrets are retained in memory and may be accessed by the job. 29 | 30 | ## Remediation 31 | 32 | Avoid using `${{ toJSON(secrets) }}` or `${{ secrets[...] }}` and only reference individual secrets that are required for the job. 33 | 34 | To avoid dynamic key access, consider using GitHub Actions environments to restrict the secrets available to the job. This way, the secrets can share the same name, but have different values based on the environment the job uses. Additionally, GitHub Actions environments can benefit from deployment protections rules to further restrict the access to its secrets. The previous matrix workflow can be rewritten as follows: 35 | 36 | ```yaml 37 | build: 38 | runs-on: ubuntu-latest 39 | strategy: 40 | matrix: 41 | env: [PROD, DEV] 42 | environment: ${{ matrix.env }} 43 | env: 44 | GH_TOKEN: ${{ secrets.GH_PAT }} 45 | ``` 46 | 47 | ## See Also 48 | - [GitHub Actions: Using environments for jobs](https://docs.github.com/en/actions/using-jobs/using-environments-for-jobs) 49 | - [GitHub Actions: Deployment protection rules](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules) 50 | - [Leaking Secrets From GitHub Actions: Reading Files And Environment Variables, Intercepting Network/Process Communication, Dumping Memory](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/) 51 | -------------------------------------------------------------------------------- /docs/content/en/rules/known_vulnerability_in_build_component.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Build Component with a Known Vulnerability used" 3 | slug: known_vulnerability_in_build_component 4 | url: /rules/known_vulnerability_in_build_component/ 5 | rule: known_vulnerability_in_build_component 6 | severity: warning 7 | --- 8 | 9 | ## Description 10 | 11 | A CI component was found to be vulnerable to a publicly known security vulnerability from the [Open Source Vulnerability Database (OSV)](https://osv.dev/) 12 | 13 | ### GitHub Actions 14 | 15 | GitHub Actions workflows using third-party GitHub Actions with known vulnerabilities could compromise the security of the workflow and the repository. 16 | 17 | ## Remediation 18 | 19 | Upgrade the affected component to a non-vulnerable version or remove the component from the workflow. 20 | 21 | ## See Also 22 | - [GitHub Docs: Keeping your actions up to date with Dependabot](https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot) 23 | - [GitHub Docs: Exporting a software bill of materials for your repository](https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/exporting-a-software-bill-of-materials-for-your-repository) 24 | -------------------------------------------------------------------------------- /docs/content/en/rules/known_vulnerability_in_build_platform.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Build Platform with a Known Vulnerability used" 3 | slug: known_vulnerability_in_build_platform 4 | url: /rules/known_vulnerability_in_build_platform/ 5 | rule: known_vulnerability_in_build_platform 6 | severity: warning 7 | --- 8 | 9 | ## Description 10 | 11 | A Build/SCM Provider was found to be vulnerable to a publicly known security vulnerability from the [Open Source Vulnerability Database (OSV)](https://osv.dev/) 12 | 13 | ## Remediation 14 | 15 | Upgrade the self-hosted provider to a non-vulnerable version. 16 | 17 | ## See Also 18 | - [Upgrade Gitlab](https://docs.gitlab.com/ee/update/) 19 | - [Upgrade Github Enterprise Server](https://docs.github.com/en/enterprise-server@3.13/admin/overview/about-upgrades-to-new-releases) 20 | -------------------------------------------------------------------------------- /docs/content_test.go: -------------------------------------------------------------------------------- 1 | package docs 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestGetRuleDocs(t *testing.T) { 11 | page, err := GetPage("debug_enabled") 12 | 13 | assert.Nil(t, err) 14 | assert.True(t, 15 | strings.HasPrefix(page.Content, "## Description"), 16 | "content should be trimmed '%s'...", page.Content[0:10], 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /docs/data/menu/extra.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | header: 3 | - name: GitHub 4 | ref: https://github.com/boostsecurityio/poutine 5 | icon: gdoc_github 6 | external: true -------------------------------------------------------------------------------- /docs/data/menu/more.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | more: 3 | - name: Releases 4 | ref: "https://github.com/boostsecurityio/poutine/releases" 5 | external: true 6 | icon: "gdoc_download" 7 | - name: GitHub 8 | ref: "https://github.com/boostsecurityio/poutine" 9 | external: true 10 | icon: "gdoc_github" 11 | -------------------------------------------------------------------------------- /docs/hugo.toml: -------------------------------------------------------------------------------- 1 | baseURL = 'https://boostsecurityio.github.io/poutine/' 2 | languageCode = 'en-us' 3 | title = 'poutine' 4 | theme = "hugo-geekdoc" 5 | 6 | pluralizeListTitles = false 7 | 8 | # Geekdoc required configuration 9 | #pygmentsUseClasses = true 10 | pygmentsUseClasses = false 11 | pygmentsCodeFences = true 12 | disablePathToLower = true 13 | # geekdocFileTreeSortBy = "linkTitle" 14 | 15 | # Required if you want to render robots.txt template 16 | enableRobotsTXT = true 17 | 18 | # Needed for mermaid shortcodes 19 | [markup] 20 | [markup.goldmark.renderer] 21 | # Needed for mermaid shortcode 22 | unsafe = true 23 | [markup.tableOfContents] 24 | startLevel = 1 25 | endLevel = 9 26 | [markup.highlight] 27 | style = 'solarized-dark' 28 | 29 | [taxonomies] 30 | tag = "tags" -------------------------------------------------------------------------------- /docs/static/custom.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Didn't find much time to create a theme yet, 3 | * so there are just a few non-default settings for now. 4 | */ 5 | :root, 6 | :root[color-theme="light"] { 7 | --header-background: #222222; 8 | --footer-background: #e6522c; 9 | --footer-link-color: #ffffff; 10 | --footer-link-color-visited: #ffffff; 11 | } 12 | 13 | @media (prefers-color-scheme: light) { 14 | :root { 15 | --header-background: #222222; 16 | --footer-background: #e6522c; 17 | --footer-link-color: #ffffff; 18 | --footer-link-color-visited: #ffffff; 19 | } 20 | } 21 | 22 | :root[color-theme="dark"] 23 | { 24 | --header-background: #111c24; 25 | --body-background: #1f1f21; 26 | --footer-background: #e6522c; 27 | --footer-link-color: #ffffff; 28 | --footer-link-color-visited: #ffffff; 29 | } 30 | 31 | @media (prefers-color-scheme: dark) { 32 | :root { 33 | --header-background: #111c24; 34 | --body-background: #1f1f21; 35 | --footer-background: #e6522c; 36 | --footer-link-color: #ffffff; 37 | --footer-link-color-visited: #ffffff; 38 | } 39 | } -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Robert Kaussow 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is furnished 10 | to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice (including the next 13 | paragraph) shall be included in all copies or substantial portions of the 14 | Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 19 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 21 | OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/VERSION: -------------------------------------------------------------------------------- 1 | v0.41.1 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/archetypes/docs.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ .Name | humanize | title }}" 3 | weight: 1 4 | # geekdocFlatSection: false 5 | # geekdocToc: 6 6 | # geekdocHidden: false 7 | --- 8 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/archetypes/posts.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | --- 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/assets/search/config.json: -------------------------------------------------------------------------------- 1 | {{- $searchDataFile := printf "search/%s.data.json" .Language.Lang -}} 2 | {{- $searchData := resources.Get "search/data.json" | resources.ExecuteAsTemplate $searchDataFile . | resources.Minify -}} 3 | { 4 | "dataFile": {{ $searchData.RelPermalink | jsonify }}, 5 | "indexConfig": {{ .Site.Params.geekdocSearchConfig | jsonify }}, 6 | "showParent": {{ if .Site.Params.geekdocSearchShowParent }}true{{ else }}false{{ end }}, 7 | "showDescription": {{ if .Site.Params.geekdocSearchshowDescription }}true{{ else }}false{{ end }} 8 | } 9 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/assets/search/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | {{ range $index, $page := (where .Site.Pages "Params.geekdocProtected" "ne" true) }} 3 | {{ if ne $index 0 }},{{ end }} 4 | { 5 | "id": {{ $index }}, 6 | "href": "{{ $page.RelPermalink }}", 7 | "title": {{ (partial "utils/title" $page) | jsonify }}, 8 | "parent": {{ with $page.Parent }}{{ (partial "utils/title" .) | jsonify }}{{ else }}""{{ end }}, 9 | "content": {{ $page.Plain | jsonify }}, 10 | "description": {{ $page.Summary | plainify | jsonify }} 11 | } 12 | {{ end }} 13 | ] 14 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/cs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: Upravit stránku 3 | 4 | nav_navigation: Navigace 5 | nav_tags: Tagy 6 | nav_more: Více 7 | nav_top: Zpět nahoru 8 | 9 | form_placeholder_search: Vyhledat 10 | 11 | error_page_title: Ztracen? Nic se neděje 12 | error_message_title: Ztracen? 13 | error_message_code: Error 404 14 | error_message_text: > 15 | Vypadá to že stránka, kterou hledáte, neexistuje. Nemějte obavy, můžete 16 | se vrátit zpět na domovskou stránku. 17 | 18 | button_toggle_dark: Přepnout tmavý/světlý/automatický režim 19 | button_nav_open: Otevřít navigaci 20 | button_nav_close: Zavřít navigaci 21 | button_menu_open: Otevřít lištu nabídky 22 | button_menu_close: Zavřít lištu nabídky 23 | button_homepage: Zpět na domovskou stránku 24 | 25 | title_anchor_prefix: "Odkaz na:" 26 | 27 | posts_read_more: Přečíst celý příspěvek 28 | posts_read_time: 29 | one: "Doba čtení: 1 minuta" 30 | other: "Doba čtení: {{ . }} minut(y)" 31 | posts_update_prefix: Naposledy upraveno 32 | posts_count: 33 | one: "Jeden příspěvek" 34 | other: "Příspěvků: {{ . }}" 35 | posts_tagged_with: Všechny příspěvky označeny '{{ . }}' 36 | 37 | footer_build_with: > 38 | Vytvořeno za pomocí Hugo a 39 | 40 | footer_legal_notice: Právní upozornění 41 | footer_privacy_policy: Zásady ochrany soukromí 42 | footer_content_license_prefix: > 43 | Obsah licencovaný pod 44 | 45 | language_switch_no_tranlation_prefix: "Stránka není přeložena:" 46 | 47 | propertylist_required: povinné 48 | propertylist_optional: volitené 49 | propertylist_default: výchozí 50 | 51 | pagination_page_prev: předchozí 52 | pagination_page_next: další 53 | pagination_page_state: "{{ .PageNumber }}/{{ .TotalPages }}" 54 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/de.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: Seite bearbeiten 3 | 4 | nav_navigation: Navigation 5 | nav_tags: Tags 6 | nav_more: Weitere 7 | nav_top: Nach oben 8 | 9 | form_placeholder_search: Suchen 10 | 11 | error_page_title: Verlaufen? Keine Sorge 12 | error_message_title: Verlaufen? 13 | error_message_code: Fehler 404 14 | error_message_text: > 15 | Wir können die Seite nach der Du gesucht hast leider nicht finden. Keine Sorge, 16 | wir bringen Dich zurück zur Startseite. 17 | 18 | button_toggle_dark: Wechsel zwischen Dunkel/Hell/Auto Modus 19 | button_nav_open: Navigation öffnen 20 | button_nav_close: Navigation schließen 21 | button_menu_open: Menüband öffnen 22 | button_menu_close: Menüband schließen 23 | button_homepage: Zurück zur Startseite 24 | 25 | title_anchor_prefix: "Link zu:" 26 | 27 | posts_read_more: Ganzen Artikel lesen 28 | posts_read_time: 29 | one: "Eine Minute Lesedauer" 30 | other: "{{ . }} Minuten Lesedauer" 31 | posts_update_prefix: Aktualisiert am 32 | posts_count: 33 | one: "Ein Artikel" 34 | other: "{{ . }} Artikel" 35 | posts_tagged_with: Alle Artikel mit dem Tag '{{ . }}' 36 | 37 | footer_build_with: > 38 | Entwickelt mit Hugo und 39 | 40 | footer_legal_notice: Impressum 41 | footer_privacy_policy: Datenschutzerklärung 42 | footer_content_license_prefix: > 43 | Inhalt lizensiert unter 44 | 45 | language_switch_no_tranlation_prefix: "Seite nicht übersetzt:" 46 | 47 | propertylist_required: erforderlich 48 | propertylist_optional: optional 49 | propertylist_default: Standardwert 50 | 51 | pagination_page_prev: vorher 52 | pagination_page_next: weiter 53 | pagination_page_state: "{{ .PageNumber }}/{{ .TotalPages }}" 54 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/en.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: Edit page 3 | 4 | nav_navigation: Navigation 5 | nav_tags: Tags 6 | nav_more: More 7 | nav_top: Back to top 8 | 9 | form_placeholder_search: Search 10 | 11 | error_page_title: Lost? Don't worry 12 | error_message_title: Lost? 13 | error_message_code: Error 404 14 | error_message_text: > 15 | Seems like what you are looking for can't be found. Don't worry, we can 16 | bring you back to the homepage. 17 | 18 | button_toggle_dark: Toggle Dark/Light/Auto mode 19 | button_nav_open: Open Navigation 20 | button_nav_close: Close Navigation 21 | button_menu_open: Open Menu Bar 22 | button_menu_close: Close Menu Bar 23 | button_homepage: Back to homepage 24 | 25 | title_anchor_prefix: "Anchor to:" 26 | 27 | posts_read_more: Read full post 28 | posts_read_time: 29 | one: "One minute to read" 30 | other: "{{ . }} minutes to read" 31 | posts_update_prefix: Updated on 32 | posts_count: 33 | one: "One post" 34 | other: "{{ . }} posts" 35 | posts_tagged_with: All posts tagged with '{{ . }}' 36 | 37 | footer_build_with: > 38 | Built with Hugo and 39 | 40 | footer_legal_notice: Legal Notice 41 | footer_privacy_policy: Privacy Policy 42 | footer_content_license_prefix: > 43 | Content licensed under 44 | 45 | language_switch_no_tranlation_prefix: "Page not translated:" 46 | 47 | propertylist_required: required 48 | propertylist_optional: optional 49 | propertylist_default: default 50 | 51 | pagination_page_prev: prev 52 | pagination_page_next: next 53 | pagination_page_state: "{{ .PageNumber }}/{{ .TotalPages }}" 54 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/es.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: Editar página 3 | 4 | nav_navigation: Navegación 5 | nav_tags: Etiquetas 6 | nav_more: Más 7 | nav_top: Inicio de la página 8 | 9 | form_placeholder_search: Buscar 10 | 11 | error_page_title: Perdido? No te preocupes 12 | error_message_title: Perdido? 13 | error_message_code: Error 404 14 | error_message_text: > 15 | Al parecer, lo que estás buscando no pudo ser encontrado. No te preocupes, podemos 16 | llevarte de vuelta al inicio. 17 | 18 | button_toggle_dark: Cambiar el modo Oscuro/Claro/Auto 19 | button_nav_open: Abrir la Navegación 20 | button_nav_close: Cerrar la Navegación 21 | button_menu_open: Abrir el Menú Bar 22 | button_menu_close: Cerrar el Menú Bar 23 | button_homepage: Volver al Inicio 24 | 25 | title_anchor_prefix: "Anclado a:" 26 | 27 | posts_read_more: Lee la publicación completa 28 | posts_read_time: 29 | one: "Un minuto para leer" 30 | other: "{{ . }} minutos para leer" 31 | posts_update_prefix: Actualizado en 32 | posts_count: 33 | one: "Una publicación" 34 | other: "{{ . }} publicaciones" 35 | posts_tagged_with: Todas las publicaciones etiquetadas con '{{ . }}' 36 | 37 | footer_build_with: > 38 | Creado con Hugo y 39 | 40 | footer_legal_notice: Aviso Legal 41 | footer_privacy_policy: Política de Privacidad 42 | footer_content_license_prefix: > 43 | Contenido licenciado con 44 | 45 | language_switch_no_tranlation_prefix: "Página no traducida:" 46 | 47 | propertylist_required: requerido 48 | propertylist_optional: opcional 49 | propertylist_default: estándar 50 | 51 | pagination_page_prev: previo 52 | pagination_page_next: siguiente 53 | pagination_page_state: "{{ .PageNumber }}/{{ .TotalPages }}" 54 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/it.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: Modifica la pagina 3 | 4 | nav_navigation: Navigazione 5 | nav_tags: Etichette 6 | nav_more: Altro 7 | nav_top: Torna su 8 | 9 | form_placeholder_search: Cerca 10 | 11 | error_page_title: Perso? Non ti preoccupare 12 | error_message_title: Perso? 13 | error_message_code: Errore 404 14 | error_message_text: > 15 | Sembra che non sia possibile trovare quello che stavi cercando. Non ti preoccupare, 16 | possiamo riportarti alla pagina iniziale. 17 | 18 | button_toggle_dark: Seleziona il tema Chiaro/Scuro/Automatico 19 | button_nav_open: Apri la Navigazione 20 | button_nav_close: Chiudi la Navigazione 21 | button_menu_open: Apri la Barra del Menu 22 | button_menu_close: Chiudi la Barra del Menu 23 | button_homepage: Torna alla pagina iniziale 24 | 25 | title_anchor_prefix: "Ancora a:" 26 | 27 | posts_read_more: Leggi tutto il post 28 | posts_read_time: 29 | one: "Tempo di lettura: un minuto" 30 | other: "Tempo di lettura: {{ . }} minuti" 31 | posts_update_prefix: Aggiornato il 32 | posts_count: 33 | one: "Un post" 34 | other: "{{ . }} post" 35 | posts_tagged_with: Tutti i post etichettati con '{{ . }}' 36 | 37 | footer_build_with: > 38 | Realizzato con Hugo e 39 | 40 | footer_legal_notice: Avviso Legale 41 | footer_privacy_policy: Politica sulla Privacy 42 | footer_content_license_prefix: > 43 | Contenuto sotto licenza 44 | 45 | language_switch_no_tranlation_prefix: "Pagina non tradotta:" 46 | 47 | propertylist_required: richiesto 48 | propertylist_optional: opzionale 49 | propertylist_default: valore predefinito 50 | 51 | pagination_page_prev: precedente 52 | pagination_page_next: prossimo 53 | pagination_page_state: "{{ .PageNumber }}/{{ .TotalPages }}" 54 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/ja.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: ページの編集 3 | 4 | nav_navigation: ナビゲーション 5 | nav_tags: タグ 6 | nav_more: さらに 7 | nav_top: トップへ戻る 8 | 9 | form_placeholder_search: 検索 10 | 11 | error_page_title: お困りですか?ご心配なく 12 | error_message_title: お困りですか? 13 | error_message_code: 404 エラー 14 | error_message_text: > 15 | お探しのものが見つからないようです。トップページ 16 | へ戻ることができるので、ご安心ください。 17 | 18 | button_toggle_dark: モードの切替 ダーク/ライト/自動 19 | button_nav_open: ナビゲーションを開く 20 | button_nav_close: ナビゲーションを閉じる 21 | button_menu_open: メニューバーを開く 22 | button_menu_close: メニューバーを閉じる 23 | button_homepage: トップページへ戻る 24 | 25 | title_anchor_prefix: "アンカー先:" 26 | 27 | posts_read_more: 全投稿を閲覧 28 | posts_read_time: 29 | one: "読むのに 1 分かかります" 30 | other: "読むのに要する時間 {{ . }} (分)" 31 | posts_update_prefix: 更新時刻 32 | posts_count: 33 | one: "一件の投稿" 34 | other: "{{ . }} 件の投稿" 35 | posts_tagged_with: "'{{ . }}'のタグが付いた記事全部" 36 | 37 | footer_build_with: > 38 | Hugo でビルドしています。 39 | 40 | footer_legal_notice: 法的な告知事項 41 | footer_privacy_policy: プライバシーポリシー 42 | footer_content_license_prefix: > 43 | 提供するコンテンツのライセンス 44 | 45 | language_switch_no_tranlation_prefix: "未翻訳のページ:" 46 | 47 | propertylist_required: 必須 48 | propertylist_optional: 任意 49 | propertylist_default: 既定値 50 | 51 | pagination_page_prev: 前 52 | pagination_page_next: 次 53 | pagination_page_state: "{{ .PageNumber }}/{{ .TotalPages }}" 54 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/nl.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: Wijzig pagina 3 | 4 | nav_navigation: Navigatie 5 | nav_tags: Markering 6 | nav_more: Meer 7 | nav_top: Terug naar boven 8 | 9 | form_placeholder_search: Zoek 10 | 11 | error_page_title: Verdwaald? Geen probleem 12 | error_message_title: Verdwaald? 13 | error_message_code: Error 404 14 | error_message_text: > 15 | Het lijkt er op dat wat je zoekt niet gevonden kan worden. Geen probleem, 16 | we kunnen je terug naar de startpagina brengen. 17 | 18 | button_toggle_dark: Wijzig Donker/Licht/Auto weergave 19 | button_nav_open: Open navigatie 20 | button_nav_close: Sluit navigatie 21 | button_menu_open: Open menubalk 22 | button_menu_close: Sluit menubalk 23 | button_homepage: Terug naar startpagina 24 | 25 | title_anchor_prefix: "Link naar:" 26 | 27 | posts_read_more: Lees volledige bericht 28 | posts_read_time: 29 | one: "Een minuut leestijd" 30 | other: "{{ . }} minuten leestijd" 31 | posts_update_prefix: Bijgewerkt op 32 | posts_count: 33 | one: "Een bericht" 34 | other: "{{ . }} berichten" 35 | posts_tagged_with: Alle berichten gemarkeerd met '{{ . }}' 36 | 37 | footer_build_with: > 38 | Gebouwd met Hugo en 39 | 40 | footer_legal_notice: Juridische mededeling 41 | footer_privacy_policy: Privacybeleid 42 | footer_content_license_prefix: > 43 | Inhoud gelicenseerd onder 44 | 45 | language_switch_no_tranlation_prefix: "Pagina niet vertaald:" 46 | 47 | propertylist_required: verplicht 48 | propertylist_optional: optioneel 49 | propertylist_default: standaard 50 | 51 | pagination_page_prev: vorige 52 | pagination_page_next: volgende 53 | pagination_page_state: "{{ .PageNumber }}/{{ .TotalPages }}" 54 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/i18n/zh-cn.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | edit_page: 编辑页面 3 | 4 | nav_navigation: 导航 5 | nav_tags: 标签 6 | nav_more: 更多 7 | nav_top: 回到顶部 8 | 9 | form_placeholder_search: 搜索 10 | 11 | error_page_title: 迷路了? 不用担心 12 | error_message_title: 迷路了? 13 | error_message_code: 错误 404 14 | error_message_text: > 15 | 好像找不到你要找的东西。 别担心,我们可以 16 | 带您回到主页。 17 | 18 | button_toggle_dark: 切换暗/亮/自动模式 19 | button_nav_open: 打开导航 20 | button_nav_close: 关闭导航 21 | button_menu_open: 打开菜单栏 22 | button_menu_close: 关闭菜单栏 23 | button_homepage: 返回首页 24 | 25 | title_anchor_prefix: "锚定到:" 26 | 27 | posts_read_more: 阅读全文 28 | posts_read_time: 29 | one: "一分钟阅读时间" 30 | other: "{{ . }} 分钟阅读时间" 31 | posts_update_prefix: 更新时间 32 | posts_count: 33 | one: 一篇文章 34 | other: "{{ . }} 个帖子" 35 | posts_tagged_with: 所有带有“{{ . }}”标签的帖子。 36 | 37 | footer_build_with: > 38 | 基于 Hugo 39 | 制作 40 | footer_legal_notice: "法律声明" 41 | footer_privacy_policy: "隐私政策" 42 | footer_content_license_prefix: > 43 | 内容许可证 44 | 45 | language_switch_no_tranlation_prefix: "页面未翻译:" 46 | 47 | propertylist_required: 需要 48 | propertylist_optional: 可选 49 | propertylist_default: 默认值 50 | 51 | pagination_page_prev: 以前 52 | pagination_page_next: 下一个 53 | pagination_page_state: "{{ .PageNumber }}/{{ .TotalPages }}" 54 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/images/readme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/images/readme.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/images/screenshot.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/images/tn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/images/tn.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ partial "head/meta" . }} 5 | {{ i18n "error_page_title" }} 6 | 7 | {{ partial "head/favicons" . }} 8 | {{ partial "head/others" . }} 9 | 10 | 11 | 12 | {{ partial "svg-icon-symbols" . }} 13 | 14 | 15 |
16 | 17 | 18 | {{ partial "site-header" (dict "Root" . "MenuEnabled" false) }} 19 | 20 | 21 |
22 |
23 |
24 | 25 |
26 |
27 |
{{ i18n "error_message_title" }}
28 |
{{ i18n "error_message_code" }}
29 |
30 | {{ i18n "error_message_text" .Site.BaseURL | safeHTML }} 31 |
32 |
33 |
34 |
35 | 36 | {{ partial "site-footer" . }} 37 | 38 |
39 | 40 | 41 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/_markup/render-codeblock-mermaid.html: -------------------------------------------------------------------------------- 1 | 2 | {{ if not (.Page.Scratch.Get "mermaid") }} 3 | 4 | 5 | {{ .Page.Scratch.Set "mermaid" true }} 6 | {{ end }} 7 | 8 | 9 |
10 |   {{- .Inner -}}
11 | 
12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/_markup/render-heading.html: -------------------------------------------------------------------------------- 1 | {{- $showAnchor := (and (default true .Page.Params.geekdocAnchor) (default true .Page.Site.Params.geekdocAnchor)) -}} 2 | 3 | 4 | 5 | {{- if $showAnchor -}} 6 |
7 | 11 | {{ .Text | safeHTML }} 12 | 13 | 14 | 15 | 16 |
17 | {{- else -}} 18 |
19 | 23 | {{ .Text | safeHTML }} 24 | 25 |
26 | {{- end -}} 27 | 28 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/_markup/render-image.html: -------------------------------------------------------------------------------- 1 | {{ .Text }} 6 | {{- /* Drop trailing newlines */ -}} 7 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/_markup/render-link.html: -------------------------------------------------------------------------------- 1 | {{- $raw := or (hasPrefix .Text " 12 | {{- .Text | safeHTML -}} 13 | 14 | {{- /* Drop trailing newlines */ -}} 15 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | {{ partial "head/meta" . }} 9 | 10 | {{- if eq .Kind "home" -}} 11 | {{ .Site.Title }} 12 | {{- else -}} 13 | {{ printf "%s | %s" (partial "utils/title" .) .Site.Title }} 14 | {{- end -}} 15 | 16 | 17 | {{ partial "head/favicons" . }} 18 | {{ partial "head/rel-me" . }} 19 | {{ partial "head/microformats" . }} 20 | {{ partial "head/others" . }} 21 | {{ partial "head/custom" . }} 22 | 23 | 24 | 25 | {{ partial "svg-icon-symbols" . }} 26 | 27 | 28 |
31 | 32 | 33 | {{ $navEnabled := default true .Page.Params.geekdocNav }} 34 | {{ partial "site-header" (dict "Root" . "MenuEnabled" $navEnabled) }} 35 | 36 | 37 |
38 | {{ if $navEnabled }} 39 | 42 | {{ end }} 43 | 44 | 45 |
46 | {{ template "main" . }} 47 | 48 | 49 | 52 |
53 |
54 | 55 | {{ partial "site-footer" . }} 56 |
57 | 58 | {{ partial "foot" . }} 59 | 60 | 61 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ partial "page-header" . }} 3 | 4 | 5 |
8 |

{{ partial "utils/title" . }}

9 | {{ partial "utils/content" . }} 10 |
11 | {{ end }} 12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ partial "page-header" . }} 3 | 4 | 5 |
8 |

{{ partial "utils/title" . }}

9 | {{ partial "utils/content" . }} 10 |
11 | {{ end }} 12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/taxonomy.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ range .Paginator.Pages }} 3 | 33 | {{ end }} 34 | {{ partial "pagination.html" . }} 35 | {{ end }} 36 | 37 | {{ define "post-tag" }} 38 | 49 | {{ end }} 50 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/_default/terms.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ range .Paginator.Pages.ByTitle }} 3 |
4 |
5 |

6 | {{ partial "utils/title" . }} 7 |

8 |
9 | 10 |
11 | 12 | {{ $pageCount := len .Pages }} 13 | 14 | 17 | 18 | 19 | 20 | 21 | 22 | {{ $latet := index .Pages.ByDate 0 }} 23 | {{ with $latet }} 24 | {{ partial "utils/title" . }} 25 | {{ end }} 26 | 27 | 28 |
29 |
30 | {{ end }} 31 | {{ partial "pagination.html" . }} 32 | {{ end }} 33 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/foot.html: -------------------------------------------------------------------------------- 1 | {{ if default true .Site.Params.geekdocSearch }} 2 | 3 | {{- $searchConfigFile := printf "search/%s.config.json" .Language.Lang -}} 4 | {{- $searchConfig := resources.Get "search/config.json" | resources.ExecuteAsTemplate $searchConfigFile . | resources.Minify -}} 5 | {{- $searchConfig.Publish -}} 6 | {{ end }} 7 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/custom.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/favicons.html: -------------------------------------------------------------------------------- 1 | 2 | 8 | 14 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/meta.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{ hugo.Generator }} 6 | 7 | {{ $keywords := default .Site.Params.Keywords .Keywords }} 8 | 9 | {{- with partial "utils/description" . }} 10 | 11 | {{- end }} 12 | {{- with $keywords }} 13 | 14 | {{- end }} 15 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/microformats.html: -------------------------------------------------------------------------------- 1 | {{ partial "microformats/opengraph.html" . }} 2 | {{ partial "microformats/twitter_cards.html" . }} 3 | {{ partial "microformats/schema" . }} 4 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/others.html: -------------------------------------------------------------------------------- 1 | {{- if default true .Site.Params.geekdocDarkModeToggle }} 2 | 3 | {{- end }} 4 | 5 | 6 | 13 | 20 | 21 | 26 | 31 | 32 | 37 | 42 | 43 | 48 | 53 | 54 | 59 | 64 | 65 | {{- with .OutputFormats.Get "html" }} 66 | {{ printf `` .Permalink .Rel .MediaType.Type | safeHTML }} 67 | {{- end }} 68 | 69 | {{- if (default false $.Site.Params.geekdocOverwriteHTMLBase) }} 70 | 71 | {{- end }} 72 | 73 | {{ printf "" "Made with Geekdoc theme https://github.com/thegeeklab/hugo-geekdoc" | safeHTML }} 74 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/head/rel-me.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/language.html: -------------------------------------------------------------------------------- 1 | {{ if .Site.IsMultiLingual }} 2 | 3 |
    4 |
  • 5 | {{ range .Site.Languages }} 6 | {{ if eq . $.Site.Language }} 7 | 8 | 9 | {{ .Lang | upper }} 10 | 11 | {{ end }} 12 | {{ end }} 13 | 14 | 15 | 48 |
  • 49 |
50 |
51 | {{ end }} 52 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/menu-extra.html: -------------------------------------------------------------------------------- 1 | {{ $current := .current }} 2 | {{ template "menu-extra" dict "sect" .source "current" $current "site" $current.Site "target" .target }} 3 | 4 | 5 | 6 | {{ define "menu-extra" }} 7 | {{ $current := .current }} 8 | {{ $site := .site }} 9 | {{ $target := .target }} 10 | {{ $sect := .sect }} 11 | 12 | {{ range sort (default (seq 0) $sect) "weight" }} 13 | {{ if isset . "ref" }} 14 | {{ $this := $site.GetPage .ref }} 15 | {{ $isCurrent := eq $current $this }} 16 | {{ $icon := default false .icon }} 17 | 18 | {{ $name := .name }} 19 | {{ if reflect.IsMap .name }} 20 | {{ $name = (index .name $site.Language.Lang) }} 21 | {{ end }} 22 | 23 | {{ if not .icon }} 24 | {{ errorf "Missing 'icon' attribute in data file for '%s' menu item '%s'" $target $name }} 25 | {{ end }} 26 | 27 | {{ if eq $target "header" }} 28 | 29 | 37 | 38 | {{ $name }} 39 | 40 | 41 | 42 | 43 | {{ end }} 44 | {{ end }} 45 | {{ end }} 46 | {{ end }} 47 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/menu.html: -------------------------------------------------------------------------------- 1 | 45 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/microformats/opengraph.html: -------------------------------------------------------------------------------- 1 | {{ $isPage := or (and (ne .Type "posts") (in "section page" .Kind )) (and (eq .Type "posts") (eq .Kind "page")) }} 2 | 3 | {{- if ne .Kind "home" }} 4 | 8 | {{- end }} 9 | {{- with .Site.Title }} 10 | 11 | {{- end }} 12 | {{- with partial "utils/featured" . }} 13 | 14 | {{- end }} 15 | {{- with partial "utils/description" . }} 16 | 17 | {{- end }} 18 | 19 | 20 | {{- with .Params.audio }} 21 | 22 | {{- end }} 23 | {{- with .Params.locale }} 24 | 25 | {{- end }} 26 | {{- with .Params.videos }} 27 | {{- range . }} 28 | 29 | {{- end }} 30 | {{- end }} 31 | 32 | {{- /* If it is part of a series, link to related articles */}} 33 | {{- if .Site.Taxonomies.series }} 34 | {{- $permalink := .Permalink -}} 35 | {{- $siteSeries := .Site.Taxonomies.series -}} 36 | {{- with .Params.series }} 37 | {{- range $name := . }} 38 | {{- $series := index $siteSeries ($name | urlize) }} 39 | {{- range $page := first 6 $series.Pages }} 40 | {{- if ne $page.Permalink $permalink }} 41 | 42 | {{- end }} 43 | {{- end }} 44 | {{- end }} 45 | {{- end }} 46 | {{- end }} 47 | 48 | {{ if $isPage -}} 49 | {{- $iso8601 := "2006-01-02T15:04:05-07:00" -}} 50 | 51 | {{- with .PublishDate }} 52 | 56 | {{- end }} 57 | {{- with .Lastmod }} 58 | 62 | {{- end }} 63 | {{- end }} 64 | 65 | {{- /* Facebook Page Admin ID for Domain Insights */}} 66 | {{- with .Site.Social.facebook_admin }} 67 | 68 | {{- end }} 69 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/microformats/schema.html: -------------------------------------------------------------------------------- 1 | {{ $isPage := or (and (ne .Type "posts") (in "section page" .Kind )) (and (eq .Type "posts") (eq .Kind "page")) }} 2 | {{- if eq .Kind "home" }} 3 | 21 | {{- else if $isPage }} 22 | 70 | {{- end }} 71 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/microformats/twitter_cards.html: -------------------------------------------------------------------------------- 1 | {{- with partial "utils/featured" . }} 2 | 3 | {{- else }} 4 | 5 | {{- end }} 6 | 7 | {{- with partial "utils/featured" . }} 8 | 9 | {{- end }} 10 | {{- with partial "utils/description" . }} 11 | 12 | {{- end }} 13 | {{- with .Site.Social.twitter -}} 14 | 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/pagination.html: -------------------------------------------------------------------------------- 1 | {{ $pag := $.Paginator }} 2 | 3 | 4 | 23 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/posts/metadata.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | {{ $tc := 0 }} 19 | {{ with .Params.tags }} 20 | {{ range sort . }} 21 | {{ $name := . }} 22 | {{ with $.Site.GetPage (printf "/tags/%s" $name | urlize) }} 23 | {{ if eq $tc 0 }} 24 | 25 | 26 | {{ template "post-tag" dict "name" $name "page" . }} 27 | 28 | {{ else }} 29 | 30 | {{ template "post-tag" dict "name" $name "page" . }} 31 | 32 | {{ end }} 33 | {{ end }} 34 | {{ $tc = (add $tc 1) }} 35 | {{ end }} 36 | {{ end }} 37 | 38 | {{ define "post-tag" }} 39 | 48 | {{ end }} 49 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/search.html: -------------------------------------------------------------------------------- 1 | {{ if default true .Site.Params.geekdocSearch }} 2 | 16 | {{ end }} 17 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/site-footer.html: -------------------------------------------------------------------------------- 1 | 46 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/svg-icon-symbols.html: -------------------------------------------------------------------------------- 1 | {{ range resources.Match "sprites/*.svg" }} 2 | {{ printf "" . | safeHTML }} 3 | {{ .Content | safeHTML }} 4 | {{ end }} 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/utils/content.html: -------------------------------------------------------------------------------- 1 | {{ $content := .Content }} 2 | 3 | {{ $content = $content | replaceRE `` `` | safeHTML }} 4 | {{ $content = $content | replaceRE `((?:.|\n)+?
)` `
${1}
` | safeHTML }} 5 | 6 | {{ return $content }} 7 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/utils/description.html: -------------------------------------------------------------------------------- 1 | {{ $isPage := or (and (ne .Type "posts") (in "section page" .Kind )) (and (eq .Type "posts") (eq .Kind "page")) }} 2 | {{ $description := "" }} 3 | 4 | {{ if .Description }} 5 | {{ $description = .Description }} 6 | {{ else }} 7 | {{ if $isPage }} 8 | {{ $description = .Summary }} 9 | {{ else if .Site.Params.description }} 10 | {{ $description = .Site.Params.description }} 11 | {{ end }} 12 | {{ end }} 13 | 14 | {{ return $description }} 15 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/utils/featured.html: -------------------------------------------------------------------------------- 1 | {{ $img := "" }} 2 | 3 | {{ with $source := ($.Resources.ByType "image").GetMatch "{*feature*,*cover*,*thumbnail*}" }} 4 | {{ $featured := .Fill (printf "1200x630 %s" (default "Smart" .Params.anchor)) }} 5 | {{ $img = $featured.Permalink }} 6 | {{ else }} 7 | {{ with default $.Site.Params.images $.Params.images }} 8 | {{ $img = index . 0 | absURL }} 9 | {{ end }} 10 | {{ end }} 11 | 12 | {{ return $img }} 13 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/partials/utils/title.html: -------------------------------------------------------------------------------- 1 | {{ $title := "" }} 2 | 3 | {{ if .Title }} 4 | {{ $title = .Title }} 5 | {{ else if and .IsSection .File }} 6 | {{ $title = path.Base .File.Dir | humanize | title }} 7 | {{ else if and .IsPage .File }} 8 | {{ $title = .File.BaseFileName | humanize | title }} 9 | {{ end }} 10 | 11 | {{ return $title }} 12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/posts/list.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 | {{ range .Paginator.Pages }} 3 | 31 | {{ end }} 32 | {{ partial "pagination.html" . }} 33 | {{ end }} 34 | 35 | {{ define "post-tag" }} 36 | 47 | {{ end }} 48 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/posts/single.html: -------------------------------------------------------------------------------- 1 | {{ define "main" }} 2 |
3 |
4 |

{{ partial "utils/title" . }}

5 | 8 |
9 |
10 | {{ partial "utils/content" . }} 11 |
12 |
13 | {{ end }} 14 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: /tags/* 3 | 4 | Sitemap: {{ "sitemap.xml" | absURL }} 5 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/button.html: -------------------------------------------------------------------------------- 1 | {{- $ref := "" }} 2 | {{- $class := "" }} 3 | {{- $size := default "regular" (.Get "size" | lower) }} 4 | 5 | {{- if not (in (slice "regular" "large") $size) }} 6 | {{- $size = "regular" }} 7 | {{- end }} 8 | 9 | {{- with .Get "href" }} 10 | {{- $ref = . }} 11 | {{- end }} 12 | 13 | {{- with .Get "relref" }} 14 | {{- $ref = relref $ . }} 15 | {{- end }} 16 | 17 | {{- with .Get "class" }} 18 | {{- $class = . }} 19 | {{- end }} 20 | 21 | 22 | 23 | 27 | {{ $.Inner }} 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/columns.html: -------------------------------------------------------------------------------- 1 | {{- $size := default "regular" (.Get "size" | lower) }} 2 | 3 | {{- if not (in (slice "regular" "large" "small") $size) }} 4 | {{- $size = "regular" }} 5 | {{- end }} 6 | 7 | 8 |
9 | {{- range split .Inner "<--->" }} 10 |
11 | {{ . | $.Page.RenderString -}} 12 |
13 | {{- end }} 14 |
15 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/expand.html: -------------------------------------------------------------------------------- 1 | {{ $id := substr (sha1 .Inner) 0 8 }} 2 |
3 | 7 | 8 |
9 | {{ .Inner | $.Page.RenderString }} 10 |
11 |
12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/hint.html: -------------------------------------------------------------------------------- 1 | {{ $type := default "note" (.Get "type") }} 2 | {{ $icon := .Get "icon" }} 3 | {{ $title := default ($type | title) (.Get "title") }} 4 | 5 | 6 |
7 |
8 | {{- with $icon -}} 9 | 10 | {{ $title }} 11 | {{- else -}} 12 | 13 | {{- end -}} 14 |
15 |
{{ .Inner | $.Page.RenderString }}
16 |
17 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/icon.html: -------------------------------------------------------------------------------- 1 | {{ $id := .Get 0 }} 2 | 3 | {{- with $id -}} 4 | 5 | {{- end -}} 6 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/include.html: -------------------------------------------------------------------------------- 1 | {{ $file := .Get "file" }} 2 | {{ $page := .Site.GetPage $file }} 3 | {{ $type := .Get "type" }} 4 | {{ $language := .Get "language" }} 5 | {{ $options :=.Get "options" }} 6 | 7 | 8 |
9 | {{- if (.Get "language") -}} 10 | {{- highlight ($file | readFile) $language (default "linenos=table" $options) -}} 11 | {{- else if eq $type "html" -}} 12 | {{- $file | readFile | safeHTML -}} 13 | {{- else if eq $type "page" -}} 14 | {{- with $page }}{{ .Content }}{{ end -}} 15 | {{- else -}} 16 | {{- $file | readFile | $.Page.RenderString -}} 17 | {{- end -}} 18 |
19 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/katex.html: -------------------------------------------------------------------------------- 1 | 2 | {{ if not (.Page.Scratch.Get "katex") }} 3 | 4 | 8 | 9 | {{ .Page.Scratch.Set "katex" true }} 10 | {{ end }} 11 | 12 | 13 | 14 | {{ cond (in .Params "display") "\\[" "\\(" -}} 15 | {{- trim .Inner "\n" -}} 16 | {{- cond (in .Params "display") "\\]" "\\)" -}} 17 | 18 | {{- /* Drop trailing newlines */ -}} 19 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/mermaid.html: -------------------------------------------------------------------------------- 1 | 2 | {{ if not (.Page.Scratch.Get "mermaid") }} 3 | 4 | 5 | {{ .Page.Scratch.Set "mermaid" true }} 6 | {{ end }} 7 | 8 | 9 |
10 |   {{- .Inner -}}
11 | 
12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/progress.html: -------------------------------------------------------------------------------- 1 | {{- $value := default 0 (.Get "value") -}} 2 | {{- $title := .Get "title" -}} 3 | {{- $icon := .Get "icon" -}} 4 | 5 | 6 |
7 |
8 |
9 | {{ with $icon -}} 10 | 11 | {{- end }} 12 | {{ with $title }}{{ . }}{{ end }} 13 |
14 |
{{ $value }}%
15 |
16 |
17 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/propertylist.html: -------------------------------------------------------------------------------- 1 | {{- $name := .Get "name" -}} 2 | {{- $sort := .Get "sort" -}} 3 | {{- $order := default "asc" (.Get "order") -}} 4 | {{- $showAnchor := (and (default true .Page.Params.geekdocAnchor) (default true .Page.Site.Params.geekdocAnchor)) -}} 5 | 6 | {{- if .Site.Data.properties }} 7 |
8 | {{- with (index .Site.Data.properties (split $name ".")) }} 9 | {{- $properties := .properties }} 10 | {{- with $sort }} 11 | {{- $properties = (sort $properties . $order) }} 12 | {{- end }} 13 | {{- range $properties }} 14 |
15 | {{ .name }} 16 | {{- if .required }} 17 | {{ i18n "propertylist_required" | lower }} 18 | {{- else }} 19 | {{ i18n "propertylist_optional" | lower }} 20 | {{- end }} 21 | {{- with .type }} 22 | {{ . }} 23 | {{- end }} 24 | 25 | {{- with .tags }} 26 | {{- $tags := . }} 27 | {{- if reflect.IsMap $tags }} 28 | {{- $tags = (index $tags $.Site.Language.Lang) }} 29 | {{- end }} 30 | {{- range $tags }} 31 | {{ . }} 32 | {{- end }} 33 | {{- end }} 34 | {{- if $showAnchor }} 35 | 36 | 37 | 38 | {{- end }} 39 |
40 |
41 |
42 | {{- with .description }} 43 | {{- $desc := . }} 44 | {{- if reflect.IsMap $desc }} 45 | {{- $desc = (index $desc $.Site.Language.Lang) }} 46 | {{- end }} 47 | {{ $desc | $.Page.RenderString }} 48 | {{- end }} 49 |
50 |
51 | {{- with default "none" (.defaultValue | string) }} 52 | {{ i18n "propertylist_default" | title }}: 53 | {{ . }} 54 | {{- end }} 55 |
56 |
57 | {{- end }} 58 | {{- end }} 59 |
60 | {{- end }} 61 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/tab.html: -------------------------------------------------------------------------------- 1 | {{- if .Parent }} 2 | {{- $name := .Get 0 }} 3 | {{- $group := printf "tabs-%s" (.Parent.Get 0) }} 4 | 5 | {{- if not (.Parent.Scratch.Get $group) }} 6 | {{- .Parent.Scratch.Set $group slice }} 7 | {{- end }} 8 | 9 | {{- .Parent.Scratch.Add $group (dict "Name" $name "Content" .Inner) }} 10 | {{- else }} 11 | {{ errorf "%q: 'tab' shortcode must be inside 'tabs' shortcode" .Page.Path }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/tabs.html: -------------------------------------------------------------------------------- 1 | {{- if .Inner }}{{ end }} 2 | {{- $id := .Get 0 }} 3 | {{- $group := printf "tabs-%s" $id }} 4 | 5 | 6 |
7 | {{- range $index, $tab := .Scratch.Get $group }} 8 | 15 | 18 |
19 | {{ .Content | $.Page.RenderString }} 20 |
21 | {{- end }} 22 |
23 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/toc-tree.html: -------------------------------------------------------------------------------- 1 | {{- $tocLevels := default (default 6 .Site.Params.geekdocToC) .Page.Params.geekdocToC }} 2 | 3 | {{- if $tocLevels }} 4 |
5 | {{ template "toc-tree" dict "sect" .Page.Pages }} 6 |
7 | {{- end }} 8 | 9 | 10 | 11 | {{- define "toc-tree" }} 12 |
    13 | {{- range .sect.GroupBy "Weight" }} 14 | {{- range .ByTitle }} 15 | {{- if or (not .Params.geekdocHidden) (not (default true .Params.geekdocHiddenTocTree)) }} 16 |
  • 17 | {{- if or .Content .Params.geekdocFlatSection }} 18 | 19 | 20 | {{- partial "utils/title" . }}{{ with .Params.geekdocDescription }}:{{ end }} 21 | 22 | {{- with .Params.geekdocDescription }}{{ . }}{{ end }} 23 | 24 | {{- else -}} 25 | 26 | {{- partial "utils/title" . }}{{ with .Params.geekdocDescription }} 27 | : {{ . }} 28 | {{ end }} 29 | 30 | {{- end -}} 31 | 32 | {{- $numberOfPages := (add (len .Pages) (len .Sections)) }} 33 | {{- if and (ne $numberOfPages 0) (not .Params.geekdocFlatSection) }} 34 | {{- template "toc-tree" dict "sect" .Pages }} 35 | {{- end }} 36 |
  • 37 | {{- end }} 38 | {{- end }} 39 | {{- end }} 40 |
41 | {{- end }} 42 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/layouts/shortcodes/toc.html: -------------------------------------------------------------------------------- 1 | {{- $format := default "html" (.Get "format") }} 2 | {{- $tocLevels := default (default 6 .Site.Params.geekdocToC) .Page.Params.geekdocToC }} 3 | 4 | {{- if and $tocLevels .Page.TableOfContents -}} 5 | {{- if not (eq ($format | lower) "raw") -}} 6 |
7 | {{ .Page.TableOfContents }} 8 |
9 |
10 | {{- else -}} 11 | {{ .Page.TableOfContents }} 12 | {{- end -}} 13 | {{- end -}} 14 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/custom.css: -------------------------------------------------------------------------------- 1 | /* You can add custom styles here. */ 2 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/android-chrome-144x144.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/android-chrome-256x256.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/android-chrome-36x36.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/android-chrome-384x384.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/android-chrome-48x48.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/android-chrome-72x72.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/android-chrome-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/android-chrome-96x96.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-1024x1024.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-114x114.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-144x144.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-167x167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-167x167.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-57x57.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-72x72.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1125x2436.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1125x2436.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1136x640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1136x640.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1170x2532.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1170x2532.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1242x2208.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1242x2208.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1242x2688.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1242x2688.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1284x2778.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1284x2778.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1334x750.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1334x750.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1536x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1536x2048.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1620x2160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1620x2160.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1668x2224.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1668x2224.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1668x2388.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1668x2388.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1792x828.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-1792x828.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2048x1536.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2048x1536.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2048x2732.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2048x2732.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2160x1620.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2160x1620.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2208x1242.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2208x1242.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2224x1668.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2224x1668.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2388x1668.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2388x1668.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2436x1125.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2436x1125.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2532x1170.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2532x1170.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2688x1242.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2688x1242.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2732x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2732x2048.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2778x1284.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-2778x1284.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-640x1136.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-640x1136.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-750x1334.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-750x1334.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-828x1792.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/apple-touch-startup-image-828x1792.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #efefef 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/favicon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/favicon-48x48.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/favicon.ico -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": null, 3 | "short_name": null, 4 | "description": null, 5 | "dir": "auto", 6 | "lang": "en-US", 7 | "display": "standalone", 8 | "orientation": "any", 9 | "scope": "", 10 | "start_url": "/?homescreen=1", 11 | "background_color": "#efefef", 12 | "theme_color": "#efefef", 13 | "icons": [ 14 | { 15 | "src": "/favicon/android-chrome-36x36.png", 16 | "sizes": "36x36", 17 | "type": "image/png", 18 | "purpose": "any" 19 | }, 20 | { 21 | "src": "/favicon/android-chrome-48x48.png", 22 | "sizes": "48x48", 23 | "type": "image/png", 24 | "purpose": "any" 25 | }, 26 | { 27 | "src": "/favicon/android-chrome-72x72.png", 28 | "sizes": "72x72", 29 | "type": "image/png", 30 | "purpose": "any" 31 | }, 32 | { 33 | "src": "/favicon/android-chrome-96x96.png", 34 | "sizes": "96x96", 35 | "type": "image/png", 36 | "purpose": "any" 37 | }, 38 | { 39 | "src": "/favicon/android-chrome-144x144.png", 40 | "sizes": "144x144", 41 | "type": "image/png", 42 | "purpose": "any" 43 | }, 44 | { 45 | "src": "/favicon/android-chrome-192x192.png", 46 | "sizes": "192x192", 47 | "type": "image/png", 48 | "purpose": "any" 49 | }, 50 | { 51 | "src": "/favicon/android-chrome-256x256.png", 52 | "sizes": "256x256", 53 | "type": "image/png", 54 | "purpose": "any" 55 | }, 56 | { 57 | "src": "/favicon/android-chrome-384x384.png", 58 | "sizes": "384x384", 59 | "type": "image/png", 60 | "purpose": "any" 61 | }, 62 | { 63 | "src": "/favicon/android-chrome-512x512.png", 64 | "sizes": "512x512", 65 | "type": "image/png", 66 | "purpose": "any" 67 | } 68 | ] 69 | } -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/mstile-144x144.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/mstile-150x150.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/mstile-310x150.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/mstile-310x310.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/favicon/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/favicon/mstile-70x70.png -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/GeekdocIcons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/GeekdocIcons.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/GeekdocIcons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/GeekdocIcons.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_AMS-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_AMS-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_AMS-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_AMS-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Caligraphic-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Fraktur-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-BoldItalic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Main-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-BoldItalic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Math-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_SansSerif-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Script-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Script-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Script-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Script-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size1-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size1-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size1-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size1-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size2-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size2-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size2-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size2-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size3-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size3-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size3-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size3-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size4-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size4-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size4-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Size4-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Typewriter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Typewriter-Regular.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/KaTeX_Typewriter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/KaTeX_Typewriter-Regular.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationMono.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationMono.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationMono.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationMono.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Bold.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Bold.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-BoldItalic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-BoldItalic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Italic.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationSans-Italic.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationSans.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/LiberationSans.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/LiberationSans.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/Metropolis.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/Metropolis.woff -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/fonts/Metropolis.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/docs/themes/hugo-geekdoc/static/fonts/Metropolis.woff2 -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/js/637-86fbbecd.chunk.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * Wait for document loaded before starting the execution 3 | */ 4 | 5 | /*! @license DOMPurify 3.0.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.0.5/LICENSE */ 6 | 7 | /*! Check if previously processed */ 8 | 9 | /*! js-yaml 4.1.0 https://github.com/nodeca/js-yaml @license MIT */ 10 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/js/662-17acb8f4.chunk.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable 3 | Copyright (c) 2013-2014 Ralf S. Engelschall (http://engelschall.com) 4 | Licensed under The MIT License (http://opensource.org/licenses/MIT) 5 | */ 6 | 7 | /*! Bezier curve function generator. Copyright Gaetan Renaudeau. MIT License: http://en.wikipedia.org/wiki/MIT_License */ 8 | 9 | /*! Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License */ 10 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/js/main-924a1933.bundle.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v2.0.11 3 | * https://clipboardjs.com/ 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/js/search-9719be99.bundle.min.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /**! 2 | * FlexSearch.js v0.7.31 (Compact) 3 | * Copyright 2018-2022 Nextapps GmbH 4 | * Author: Thomas Wilkerling 5 | * Licence: Apache-2.0 6 | * https://github.com/nextapps-de/flexsearch 7 | */ 8 | -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/mobile-79ddc617.min.css: -------------------------------------------------------------------------------- 1 | @media screen and (max-width: 41rem){.gdoc-nav{margin-left:-18rem;font-size:16px}.gdoc-nav__control{display:inline-block}.gdoc-header svg.gdoc-icon{width:1.5rem;height:1.5rem}.gdoc-brand{font-size:1.5rem;line-height:1.5rem}.gdoc-brand__img{display:none}.gdoc-menu-header__items{display:none}.gdoc-menu-header__control,.gdoc-menu-header__home{display:flex}.gdoc-error{padding:6rem 1rem}.gdoc-error svg.gdoc-icon{width:6rem;height:6rem}.gdoc-error__message{padding-left:2rem}.gdoc-error__line{padding:.25rem 0}.gdoc-error__title{font-size:2rem}.gdoc-page__header .breadcrumb,.hidden-mobile{display:none}.flex-mobile-column{flex-direction:column}.flex-mobile-column.gdoc-columns{margin:2rem 0}.flex-mobile-column .gdoc-columns__content{min-width:auto;margin:0}#menu-control:checked~main .gdoc-nav nav,#menu-control:checked~main .gdoc-page{transform:translateX(18rem)}#menu-control:checked~main .gdoc-page{opacity:.25}#menu-control:checked~.gdoc-header .gdoc-nav__control svg.gdoc-icon.gdoc_menu{display:none}#menu-control:checked~.gdoc-header .gdoc-nav__control svg.gdoc-icon.gdoc_arrow_back{display:inline-block}#menu-header-control:checked~.gdoc-header .gdoc-brand{display:none}#menu-header-control:checked~.gdoc-header .gdoc-menu-header__items{display:flex}#menu-header-control:checked~.gdoc-header .gdoc-menu-header__control svg.gdoc-icon.gdoc_keyboard_arrow_left{display:none}} -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/static/print-735ccc12.min.css: -------------------------------------------------------------------------------- 1 | @media print{.gdoc-nav,.gdoc-footer .container span:not(:first-child),.gdoc-paging,.editpage{display:none}.gdoc-footer{border-top:1px solid #dee2e6}.gdoc-markdown pre{white-space:pre-wrap;overflow-wrap:break-word}.chroma code{border:1px solid #dee2e6;padding:.5rem !important;font-weight:normal !important}.gdoc-markdown code{font-weight:bold}a,a:visited{color:inherit !important;text-decoration:none !important}.gdoc-toc{flex:none}.gdoc-toc nav{position:relative;width:auto}.wrapper{display:block}.wrapper main{display:block}} -------------------------------------------------------------------------------- /docs/themes/hugo-geekdoc/theme.toml: -------------------------------------------------------------------------------- 1 | name = "Geekdoc" 2 | license = "MIT" 3 | licenselink = "https://github.com/thegeeklab/hugo-geekdoc/blob/main/LICENSE" 4 | description = "Hugo theme made for documentation" 5 | homepage = "https://geekdocs.de/" 6 | demosite = "https://geekdocs.de/" 7 | tags = ["docs", "documentation", "responsive", "simple"] 8 | min_version = "0.112.0" 9 | 10 | [author] 11 | name = "Robert Kaussow" 12 | homepage = "https://thegeeklab.de/" 13 | -------------------------------------------------------------------------------- /models/branch_info.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type BranchInfo struct { 4 | BranchName string `json:"branch_name"` 5 | FilePath []string `json:"file_path"` 6 | } 7 | 8 | type RepoInfo struct { 9 | Purl string `json:"purl"` 10 | RepoName string `json:"repo_name"` 11 | BranchInfos []BranchInfo `json:"branch_infos"` 12 | } 13 | -------------------------------------------------------------------------------- /models/config.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type ConfigSkip struct { 4 | Purl StringList `json:"purl,omitempty"` 5 | Path StringList `json:"path,omitempty"` 6 | Rule StringList `json:"rule,omitempty"` 7 | OsvId StringList `json:"osv_id,omitempty"` 8 | Job StringList `json:"job,omitempty"` 9 | Level StringList `json:"level,omitempty"` 10 | } 11 | 12 | func (c *ConfigSkip) HasOnlyRule() bool { 13 | return len(c.Purl) == 0 && 14 | len(c.Path) == 0 && 15 | len(c.OsvId) == 0 && 16 | len(c.Job) == 0 && 17 | len(c.Level) == 0 && 18 | len(c.Rule) != 0 19 | } 20 | 21 | type ConfigInclude struct { 22 | Path StringList `json:"path,omitempty"` 23 | } 24 | 25 | type Config struct { 26 | Skip []ConfigSkip `json:"skip"` 27 | AllowedRules []string `json:"allowed_rules"` 28 | Include []ConfigInclude `json:"include"` 29 | IgnoreForks bool `json:"ignore_forks"` 30 | Quiet bool `json:"quiet,omitempty"` 31 | RulesConfig map[string]map[string]interface{} `json:"rules_config"` 32 | } 33 | 34 | func DefaultConfig() *Config { 35 | return &Config{} 36 | } 37 | -------------------------------------------------------------------------------- /models/package_insights_test.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | _ "embed" 5 | "encoding/json" 6 | "github.com/stretchr/testify/assert" 7 | "testing" 8 | ) 9 | 10 | //go:embed tests/actions-checkout-v4.json 11 | var insightsSample []byte 12 | 13 | func TestPackageInsights(t *testing.T) { 14 | pi := PackageInsights{} 15 | 16 | err := json.Unmarshal(insightsSample, &pi) 17 | assert.Nil(t, err) 18 | 19 | assert.Equal(t, "1.0", pi.Version) 20 | assert.Equal(t, "pkg:githubactions/actions/checkout@v4", pi.Purl) 21 | assert.Equal(t, "githubactions", pi.PackageEcosystem) 22 | assert.Equal(t, "checkout", pi.PackageName) 23 | assert.Equal(t, "actions", pi.PackageNamespace) 24 | assert.Equal(t, "v4", pi.PackageVersion) 25 | assert.Equal(t, "github", pi.SourceScmType) 26 | assert.Equal(t, "actions/checkout", pi.SourceGitRepo) 27 | assert.Equal(t, "", pi.SourceGitRepoPath) 28 | assert.Equal(t, "v4", pi.SourceGitRef) 29 | assert.Equal(t, "b4ffde65f46336ab88eb53be808477a3936bae11", pi.SourceGitCommitSha) 30 | assert.Equal(t, 0, len(pi.PackageDependencies)) 31 | assert.Subset(t, []string{ 32 | "pkg:githubactions/actions/setup-node@v1", 33 | "pkg:githubactions/actions/upload-artifact@v2", 34 | "pkg:githubactions/actions/checkout@v3", 35 | "pkg:githubactions/github/codeql-action/analyze@v2", 36 | "pkg:githubactions/github/codeql-action/init@v2", 37 | }, pi.BuildDependencies) 38 | 39 | assert.Equal(t, 5, len(pi.GithubActionsWorkflows)) 40 | assert.Equal(t, 1, len(pi.GithubActionsMetadata)) 41 | } 42 | -------------------------------------------------------------------------------- /models/pipeline_as_code_tekton.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "gopkg.in/yaml.v3" 4 | 5 | type PipelineAsCodeTekton struct { 6 | ApiVersion string `json:"api_version" yaml:"apiVersion"` 7 | Kind string `json:"kind"` 8 | Metadata struct { 9 | Name string `json:"name"` 10 | Annotations map[string]string `json:"annotations"` 11 | } `json:"metadata"` 12 | Spec PipelineRunSpec `json:"spec,omitempty" yaml:"spec"` 13 | 14 | Path string `json:"path" yaml:"-"` 15 | } 16 | 17 | type PipelineRunSpec struct { 18 | PipelineSpec *PipelineSpec `json:"pipeline_spec,omitempty" yaml:"pipelineSpec"` 19 | } 20 | 21 | type PipelineSpec struct { 22 | Tasks []PipelineTask `json:"tasks,omitempty" yaml:"tasks"` 23 | } 24 | 25 | type PipelineTask struct { 26 | Name string `json:"name,omitempty"` 27 | 28 | TaskSpec *TaskSpec `json:"task_spec,omitempty" yaml:"taskSpec"` 29 | } 30 | 31 | type TaskSpec struct { 32 | Steps []Step `json:"steps,omitempty"` 33 | } 34 | 35 | type Step struct { 36 | Name string `json:"name"` 37 | Script string `json:"script,omitempty"` 38 | Lines map[string]int `json:"lines" yaml:"-"` 39 | } 40 | 41 | func (o *Step) UnmarshalYAML(node *yaml.Node) error { 42 | type step Step 43 | var s step 44 | if err := node.Decode(&s); err != nil { 45 | return err 46 | } 47 | 48 | if node.Kind == yaml.MappingNode { 49 | s.Lines = map[string]int{"start": node.Line} 50 | for i := 0; i < len(node.Content); i += 2 { 51 | key := node.Content[i].Value 52 | switch key { 53 | case "script": 54 | s.Lines[key] = node.Content[i+1].Line 55 | } 56 | } 57 | } 58 | 59 | *o = Step(s) 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /opa/builtins.go: -------------------------------------------------------------------------------- 1 | package opa 2 | 3 | import ( 4 | "github.com/boostsecurityio/poutine/models" 5 | "github.com/hashicorp/go-version" 6 | "github.com/open-policy-agent/opa/v1/ast" 7 | "github.com/open-policy-agent/opa/v1/rego" 8 | "github.com/open-policy-agent/opa/v1/types" 9 | ) 10 | 11 | func registerBuiltinFunctions() { 12 | rego.RegisterBuiltin1( 13 | ®o.Function{ 14 | Name: "purl.parse_docker_image", 15 | Decl: types.NewFunction(types.Args(types.S), types.S), 16 | }, 17 | func(_ rego.BuiltinContext, a *ast.Term) (*ast.Term, error) { 18 | var uses string 19 | if err := ast.As(a.Value, &uses); err != nil { 20 | return nil, err 21 | } 22 | 23 | purl, err := models.PurlFromDockerImage(uses) 24 | if err != nil { 25 | return nil, err 26 | } 27 | 28 | return ast.StringTerm(purl.String()), nil 29 | }, 30 | ) 31 | 32 | rego.RegisterBuiltin3( 33 | ®o.Function{ 34 | Name: "purl.parse_github_actions", 35 | Decl: types.NewFunction(types.Args(types.S, types.S, types.S), types.S), 36 | }, 37 | func(_ rego.BuiltinContext, a *ast.Term, b *ast.Term, c *ast.Term) (*ast.Term, error) { 38 | var uses string 39 | if err := ast.As(a.Value, &uses); err != nil { 40 | return nil, err 41 | } 42 | 43 | var sourceGitRepo string 44 | if err := ast.As(b.Value, &sourceGitRepo); err != nil { 45 | return nil, err 46 | } 47 | 48 | var sourceGitRef string 49 | if err := ast.As(c.Value, &sourceGitRef); err != nil { 50 | return nil, err 51 | } 52 | 53 | purl, err := models.PurlFromGithubActions(uses, sourceGitRepo, sourceGitRef) 54 | if err != nil { 55 | return nil, err 56 | } 57 | 58 | return ast.StringTerm(purl.String()), nil 59 | }, 60 | ) 61 | 62 | rego.RegisterBuiltin2( 63 | ®o.Function{ 64 | Name: "semver.constraint_check", 65 | Decl: types.NewFunction(types.Args(types.S, types.S), types.S), 66 | }, 67 | func(_ rego.BuiltinContext, a *ast.Term, b *ast.Term) (*ast.Term, error) { 68 | var constraintsStr string 69 | if err := ast.As(a.Value, &constraintsStr); err != nil { 70 | return nil, err 71 | } 72 | 73 | var versionStr string 74 | if err := ast.As(b.Value, &versionStr); err != nil { 75 | return nil, err 76 | } 77 | 78 | semver, err := version.NewVersion(versionStr) 79 | if err != nil { 80 | print(err) 81 | return nil, err 82 | } 83 | 84 | constraints, err := version.NewConstraint(constraintsStr) 85 | if err != nil { 86 | return nil, err 87 | } 88 | 89 | return ast.BooleanTerm(constraints.Check(semver)), nil 90 | }, 91 | ) 92 | 93 | } 94 | -------------------------------------------------------------------------------- /opa/models.go: -------------------------------------------------------------------------------- 1 | package opa 2 | 3 | type InventoryResult struct { 4 | BuildDependencies []string `json:"build_dependencies"` 5 | PackageDependencies []string `json:"package_dependencies"` 6 | } 7 | -------------------------------------------------------------------------------- /opa/poutine_build_platform_advisories.json: -------------------------------------------------------------------------------- 1 | { 2 | "gitlab": { 3 | "PVE-2024-00001": { 4 | "osv_id": "PVE-2024-00001", 5 | "published": "2024-09-10T18:50:12.965Z", 6 | "aliases": [], 7 | "summary": "Dependencies omniauth-saml and ruby-saml through CVE-2024-45409 do not properly verify the signature of the SAML Response. An unauthenticated attacker with access to any signed saml document (by the IdP) can thus forge a SAML Response/Assertion with arbitrary contents. This would allow the attacker to log in as arbitrary user within the vulnerable system", 8 | "severity": [{ 9 | "type": "CVSS_V3", 10 | "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N" 11 | }], 12 | "cwe_ids": [ 13 | "CWE-347" 14 | ], 15 | "vulnerable_versions": [], 16 | "vulnerable_version_ranges": [ 17 | ">=17.3, <17.3.3", 18 | ">=17.2, <17.2.7", 19 | ">=17.1, <17.1.8", 20 | ">=17.0, <17.0.8", 21 | ">=16.11, <16.11.10" 22 | ], 23 | "vulnerable_commit_shas": [] 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /opa/rego/external/reputation.rego: -------------------------------------------------------------------------------- 1 | package external.reputation 2 | 3 | import rego.v1 4 | 5 | by_purl[pkg.purl] = pkg if { 6 | pkg := input.reputation.packages[_] 7 | } 8 | -------------------------------------------------------------------------------- /opa/rego/poutine.rego: -------------------------------------------------------------------------------- 1 | package poutine 2 | 3 | import rego.v1 4 | 5 | rule(chain) = { 6 | "id": rule_id, 7 | "title": meta.title, 8 | "description": meta.description, 9 | "level": meta.custom.level, 10 | "refs": object.get(meta, "related_resources", []), 11 | "config": _rule_config(rule_id, meta), 12 | } if { 13 | module := chain[1] 14 | module.path[0] == "rules" 15 | rule_id := module.path[1] 16 | meta := object.union( 17 | { 18 | "title": rule_id, 19 | "description": "", 20 | "related_resources": [], 21 | "custom": {"level": "note"}, 22 | }, 23 | module.annotations, 24 | ) 25 | } 26 | 27 | finding(rule, pkg_purl, meta) = { 28 | "rule_id": rule.id, 29 | "purl": pkg_purl, 30 | "meta": meta, 31 | } 32 | 33 | _rule_config(rule_id, meta) = object.union(rule_config, config_values) if { 34 | rule_config := {key: value | 35 | param := meta.custom.config[key] 36 | value := object.union({"value": object.get(param, "default", null)}, param) 37 | } 38 | config_values := {key: {"value": value} | 39 | value := data.config.rules_config[rule_id][key] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /opa/rego/poutine/config.rego: -------------------------------------------------------------------------------- 1 | package poutine.config 2 | 3 | finding := input.finding 4 | 5 | pkg := input.packages[finding.purl] 6 | -------------------------------------------------------------------------------- /opa/rego/poutine/format/json.rego: -------------------------------------------------------------------------------- 1 | package poutine.format.json 2 | 3 | import rego.v1 4 | 5 | dependencies[pkg.purl] contains dep if { 6 | pkg := input.packages[_] 7 | dep := array.concat(pkg.build_dependencies, pkg.package_dependencies)[_] 8 | } 9 | 10 | packages[pkg.purl] = { 11 | "dependencies": object.get(dependencies, pkg.purl, []), 12 | "commit_sha": pkg.source_git_commit_sha, 13 | "ref": pkg.source_git_ref, 14 | } if { 15 | pkg := input.packages[_] 16 | } 17 | 18 | result := json.marshal({ 19 | "rules": input.results.rules, 20 | "findings": input.results.findings, 21 | "packages": packages, 22 | }) 23 | -------------------------------------------------------------------------------- /opa/rego/poutine/inventory/azure_pipelines.rego: -------------------------------------------------------------------------------- 1 | package poutine.inventory 2 | 3 | import rego.v1 4 | 5 | build_dependencies contains dep if { 6 | pkg := input.packages[_] 7 | pipeline := pkg.azure_pipelines[_] 8 | stage := pipeline.stages[_] 9 | job := stage.jobs[_] 10 | step := job.steps[_] 11 | 12 | not contains(step.task, "$") 13 | dep := sprintf("pkg:azurepipelinestask/%s", [step.task]) 14 | } 15 | -------------------------------------------------------------------------------- /opa/rego/poutine/inventory/github_actions.rego: -------------------------------------------------------------------------------- 1 | package poutine.inventory 2 | 3 | import rego.v1 4 | 5 | import data.poutine.utils 6 | 7 | build_dependencies contains dep if { 8 | pkg := input.packages[_] 9 | step := pkg.github_actions_workflows[_].jobs[_].steps[_] 10 | dep := purl.parse_github_actions(step.uses, pkg.source_git_repo, pkg.source_git_ref) 11 | } 12 | 13 | build_dependencies contains dep if { 14 | pkg := input.packages[_] 15 | job := pkg.github_actions_workflows[_].jobs[_] 16 | image := job.container.image 17 | not contains(image, "$") 18 | dep := purl.parse_docker_image(image) 19 | } 20 | 21 | build_dependencies contains dep if { 22 | pkg := input.packages[_] 23 | job := pkg.github_actions_workflows[_].jobs[_] 24 | uses := job.uses 25 | not utils.empty(uses) 26 | dep := purl.parse_github_actions(uses, pkg.source_git_repo, pkg.source_git_ref) 27 | } 28 | 29 | package_dependencies contains dep if { 30 | pkg := input.packages[_] 31 | step := pkg.github_actions_metadata[_].runs.steps[_] 32 | dep := purl.parse_github_actions(step.uses, pkg.source_git_repo, pkg.source_git_ref) 33 | } 34 | 35 | package_dependencies contains dep if { 36 | pkg := input.packages[_] 37 | runs := pkg.github_actions_metadata[_].runs 38 | 39 | runs.using == "docker" 40 | startswith(runs.image, "docker://") 41 | dep := purl.parse_github_actions(runs.image, pkg.source_git_repo, pkg.source_git_ref) 42 | } 43 | -------------------------------------------------------------------------------- /opa/rego/poutine/inventory/gitlab.rego: -------------------------------------------------------------------------------- 1 | package poutine.inventory 2 | 3 | import rego.v1 4 | 5 | build_dependencies contains dep if { 6 | pkg := input.packages[_] 7 | config := pkg.gitlabci_configs[_] 8 | job := config.jobs[_] 9 | image := job.image.name 10 | not contains(image, "$") 11 | 12 | dep := purl.parse_docker_image(image) 13 | } 14 | 15 | build_dependencies contains dep if { 16 | pkg := input.packages[_] 17 | config := pkg.gitlabci_configs[_] 18 | job := config.jobs[_] 19 | image := job.services[_].name 20 | not contains(image, "$") 21 | 22 | dep := purl.parse_docker_image(image) 23 | } 24 | 25 | build_dependencies contains dep if { 26 | pkg := input.packages[_] 27 | config := pkg.gitlabci_configs[_] 28 | include := config.include[_] 29 | ref := object.get(include, "ref", "HEAD") 30 | file := include.file[_] 31 | not contains(ref, "$") 32 | not contains(include.project, "$") 33 | not contains(file, "$") 34 | 35 | dep := sprintf("pkg:gitlabci/include/project?%s", [urlquery.encode_object({ 36 | "file_name": file, 37 | "project": include.project, 38 | "ref": ref, 39 | })]) 40 | } 41 | 42 | build_dependencies contains dep if { 43 | pkg := input.packages[_] 44 | config := pkg.gitlabci_configs[_] 45 | include := config.include[_] 46 | url := include.remote 47 | not contains(url, "$") 48 | 49 | dep := sprintf("pkg:gitlabci/include/remote?download_url=%s", [urlquery.encode(url)]) 50 | } 51 | 52 | build_dependencies contains dep if { 53 | pkg := input.packages[_] 54 | config := pkg.gitlabci_configs[_] 55 | include := config.include[_] 56 | path := include.template 57 | not contains(path, "$") 58 | 59 | dep := sprintf("pkg:gitlabci/include/template?file_name=%s", [urlquery.encode(trim_left(path, "/"))]) 60 | } 61 | 62 | build_dependencies contains dep if { 63 | pkg := input.packages[_] 64 | config := pkg.gitlabci_configs[_] 65 | include := config.include[_] 66 | component = include.component 67 | not contains(component, "$") 68 | 69 | match := regex.find_all_string_submatch_n("([^/]+)/(.*)", component, 1)[0] 70 | repository_url = match[1] 71 | parts = split(match[2], "@") 72 | project := parts[0] 73 | ref := parts[1] 74 | 75 | dep := sprintf("pkg:gitlabci/include/component?%s", [urlquery.encode_object({ 76 | "project": project, 77 | "ref": ref, 78 | "repository_url": repository_url, 79 | })]) 80 | } 81 | -------------------------------------------------------------------------------- /opa/rego/poutine/queries/findings.rego: -------------------------------------------------------------------------------- 1 | package poutine.queries.findings 2 | 3 | import data.rules 4 | import rego.v1 5 | 6 | rules_by_id[id] = rules[id].rule 7 | 8 | skip(f) if { 9 | s := data.config.skip[_] 10 | o := object.union( 11 | { 12 | "purl": f.purl, 13 | "rule": f.rule_id, 14 | "level": rules_by_id[rule_id].level, 15 | }, 16 | object.filter(f.meta, {"osv_id", "job", "path"}), 17 | ) 18 | 19 | count(s) > 0 20 | [attr | s[attr]; not o[attr] in s[attr]] == [] 21 | } 22 | 23 | skip(f) if { 24 | data.poutine.config.skip with input as { 25 | "finding": f, 26 | "packages": input.packages, 27 | } 28 | } 29 | 30 | findings contains finding if { 31 | finding := rules[rule_id].results[_] 32 | 33 | not skip(finding) 34 | } 35 | 36 | result = { 37 | "findings": findings, 38 | "rules": rules_by_id, 39 | } 40 | -------------------------------------------------------------------------------- /opa/rego/poutine/queries/format.rego: -------------------------------------------------------------------------------- 1 | package poutine.queries.format 2 | 3 | import rego.v1 4 | 5 | default output := "" 6 | 7 | output = data.poutine.format[input.format].result 8 | 9 | formats contains format if data.poutine.format[format] 10 | 11 | formats contains input.builtin_formats[_] 12 | 13 | errors contains error if { 14 | not input.format in formats 15 | error := sprintf("format %s not found in the available formats: %s", [ 16 | input.format, 17 | concat(", ", formats), 18 | ]) 19 | } 20 | 21 | result = { 22 | "output": output, 23 | "error": concat(", ", errors), 24 | } 25 | -------------------------------------------------------------------------------- /opa/rego/poutine/queries/inventory.rego: -------------------------------------------------------------------------------- 1 | package poutine.queries.inventory 2 | 3 | import data.poutine.inventory.build_dependencies 4 | import data.poutine.inventory.package_dependencies 5 | 6 | result = { 7 | "build_dependencies": build_dependencies, 8 | "package_dependencies": package_dependencies, 9 | } 10 | -------------------------------------------------------------------------------- /opa/rego/rules/default_permissions_on_risky_events.rego: -------------------------------------------------------------------------------- 1 | # METADATA 2 | # title: Default permissions used on risky events 3 | # description: |- 4 | # The workflow and some of its jobs do not explicitely define permissions 5 | # and the workflow triggers on events that are typically used to run builds from forks. 6 | # Because no permissions is set, the workflow inherits the default permissions 7 | # configured on the repository or the organization. 8 | # custom: 9 | # level: warning 10 | package rules.default_permissions_on_risky_events 11 | 12 | import data.poutine 13 | import data.poutine.utils 14 | import rego.v1 15 | 16 | rule := poutine.rule(rego.metadata.chain()) 17 | 18 | github.events contains event if some event in { 19 | "pull_request_target", 20 | "issue_comment", 21 | } 22 | 23 | results contains poutine.finding(rule, pkg.purl, { 24 | "path": workflow.path, 25 | "event_triggers": [event | event := workflow.events[j].name], 26 | }) if { 27 | pkg := input.packages[_] 28 | workflow = pkg.github_actions_workflows[_] 29 | job := workflow.jobs[_] 30 | 31 | utils.filter_workflow_events(workflow, github.events) 32 | 33 | utils.empty(workflow.permissions) 34 | utils.empty(job.permissions) 35 | } 36 | 37 | results contains poutine.finding(rule, pkg.purl, { 38 | "path": workflow.path, 39 | "event_triggers": [event | event := workflow.events[j].name], 40 | }) if { 41 | pkg := input.packages[_] 42 | workflow = pkg.github_actions_workflows[_] 43 | job := workflow.jobs[_] 44 | 45 | utils.filter_workflow_events(workflow, github.events) 46 | 47 | not workflow.permissions 48 | not job.permissions 49 | } 50 | -------------------------------------------------------------------------------- /opa/rego/rules/if_always_true.rego: -------------------------------------------------------------------------------- 1 | # METADATA 2 | # title: If condition always evaluates to true 3 | # description: |- 4 | # GitHub Actions expressions used in if condition of jobs or steps 5 | # must not contain extra characters or spaces. 6 | # Otherwise, the condition is always true. 7 | # custom: 8 | # level: error 9 | package rules.if_always_true 10 | 11 | import data.poutine 12 | import rego.v1 13 | 14 | rule := poutine.rule(rego.metadata.chain()) 15 | 16 | results contains poutine.finding(rule, pkg.purl, meta) if { 17 | pkg := input.packages[_] 18 | meta := if_conditions[pkg.purl][_] 19 | } 20 | 21 | always_true(cond) if { 22 | contains(cond, "${{") 23 | not startswith(cond, "${{") 24 | } else if { 25 | contains(cond, "${{") 26 | not endswith(cond, "}}") 27 | } else if { 28 | contains(cond, "${{") 29 | count(split(cond, "${{")) > 2 30 | } 31 | 32 | if_conditions[pkg.purl] contains { 33 | "path": workflow.path, 34 | "line": object.get(job.lines, "if", 0), 35 | "job": job.id, 36 | "event_triggers": [event | event := workflow.events[j].name], 37 | } if { 38 | pkg := input.packages[_] 39 | workflow = pkg.github_actions_workflows[_] 40 | job := workflow.jobs[_] 41 | cond := object.get(job, "if", "") 42 | 43 | always_true(cond) 44 | } 45 | 46 | if_conditions[pkg.purl] contains { 47 | "path": workflow.path, 48 | "line": object.get(step.lines, "if", 0), 49 | "job": job.id, 50 | "step": step_id, 51 | "event_triggers": [event | event := workflow.events[j].name], 52 | } if { 53 | pkg := input.packages[_] 54 | workflow = pkg.github_actions_workflows[_] 55 | job := workflow.jobs[_] 56 | step := job.steps[step_id] 57 | cond := object.get(step, "if", "") 58 | 59 | always_true(cond) 60 | } 61 | 62 | if_conditions[pkg.purl] contains { 63 | "path": action.path, 64 | "line": object.get(step.lines, "if", 0), 65 | "step": step_id, 66 | } if { 67 | pkg := input.packages[_] 68 | action = pkg.github_actions_metadata[_] 69 | step := action.runs.steps[step_id] 70 | cond := object.get(step, "if", "") 71 | 72 | always_true(cond) 73 | } 74 | -------------------------------------------------------------------------------- /opa/rego/rules/job_all_secrets.rego: -------------------------------------------------------------------------------- 1 | # METADATA 2 | # title: Workflow job exposes all secrets 3 | # description: |- 4 | # The GitHub Actions Runner attempts to keep in memory only the secrets 5 | # that are necessary to execute a workflow job. 6 | # If a job converts the secrets object to JSON or accesses it using an expression, 7 | # all secrets will be retained in memory for the duration of the job. 8 | # custom: 9 | # level: warning 10 | package rules.job_all_secrets 11 | 12 | import data.poutine 13 | import rego.v1 14 | 15 | rule := poutine.rule(rego.metadata.chain()) 16 | 17 | results contains poutine.finding(rule, pkg.purl, { 18 | "path": workflow.path, 19 | "job": job.id, 20 | "line": job.lines.start, 21 | "event_triggers": [event | event := workflow.events[i].name], 22 | }) if { 23 | pkg := input.packages[_] 24 | workflow := pkg.github_actions_workflows[_] 25 | job := workflow.jobs[_] 26 | 27 | regex.match("\\$\\{\\{\\s*(secrets\\[|toJSON\\(secrets\\))", json.marshal(job)) 28 | } 29 | -------------------------------------------------------------------------------- /opa/rego/rules/known_vulnerability_in_build_component.rego: -------------------------------------------------------------------------------- 1 | # METADATA 2 | # title: Build Component with a Known Vulnerability used 3 | # description: |- 4 | # The workflow or action depends on a GitHub Action with known vulnerabilities. 5 | # related_resources: 6 | # - ref: https://osv.dev/ 7 | # description: Source Advisory Database 8 | # custom: 9 | # level: warning 10 | package rules.known_vulnerability_in_build_component 11 | 12 | import data.external.osv.advisories 13 | import data.poutine 14 | import rego.v1 15 | 16 | rule := poutine.rule(rego.metadata.chain()) 17 | 18 | step_advisory(step) = advisory if { 19 | parts = split(step.uses, "@") 20 | action := parts[0] 21 | version := trim_left(parts[1], "v") 22 | advisory := advisories[osv_id] 23 | advisory.package_name == action 24 | 25 | regex.match("^[0-9]+(\\.[0-9]+)*?$", version) 26 | 27 | semver.constraint_check(advisory.vulnerable_version_ranges[_], version) 28 | } 29 | 30 | results contains poutine.finding(rule, pkg.purl, { 31 | "path": workflow.path, 32 | "line": step.lines.uses, 33 | "job": job.id, 34 | "step": i, 35 | "osv_id": advisory.osv_id, 36 | "details": sprintf("Package: %s", [advisory.package_name]), 37 | "event_triggers": [event | event := workflow.events[j].name], 38 | }) if { 39 | pkg = input.packages[_] 40 | workflow = pkg.github_actions_workflows[_] 41 | job := workflow.jobs[_] 42 | step := job.steps[i] 43 | advisory := step_advisory(step) 44 | } 45 | 46 | results contains poutine.finding(rule, pkg.purl, { 47 | "path": action.path, 48 | "line": step.lines.uses, 49 | "step": i, 50 | "osv_id": advisory.osv_id, 51 | "details": sprintf("Package: %s", [advisory.package_name]), 52 | }) if { 53 | pkg = input.packages[_] 54 | action = pkg.github_actions_metadata[_] 55 | action.runs.using == "composite" 56 | step := action.runs.steps[i] 57 | advisory := step_advisory(step) 58 | } 59 | -------------------------------------------------------------------------------- /opa/rego/rules/known_vulnerability_in_build_platform.rego: -------------------------------------------------------------------------------- 1 | # METADATA 2 | # title: Build Platform with a Known Vulnerability used 3 | # description: |- 4 | # The build or SCM provider used has a known vulnerability. 5 | # related_resources: 6 | # - ref: https://osv.dev/ 7 | # description: Source Advisory Database 8 | # custom: 9 | # level: warning 10 | package rules.known_vulnerability_in_build_platform 11 | 12 | import data.external.build_platform.advisories 13 | import data.poutine 14 | import rego.v1 15 | 16 | rule := poutine.rule(rego.metadata.chain()) 17 | 18 | results contains poutine.finding(rule, input.provider, { 19 | "osv_id": advisory.osv_id, 20 | "details": sprintf("Provider: %s", [input.provider]), 21 | }) if { 22 | advisory := advisories[input.provider][osv_id] 23 | regex.match("^[0-9]+(\\.[0-9]+)*?$", input.version) 24 | semver.constraint_check(advisory.vulnerable_version_ranges[_], input.version) 25 | } 26 | -------------------------------------------------------------------------------- /opa/rego/rules/pr_runs_on_self_hosted.rego: -------------------------------------------------------------------------------- 1 | # METADATA 2 | # title: Pull Request Runs on Self-Hosted GitHub Actions Runner 3 | # description: |- 4 | # This job runs on a self-hosted GitHub Actions runner in a workflow 5 | # that is triggered by a pull request event. 6 | # custom: 7 | # level: warning 8 | # config: 9 | # allowed_runners: 10 | # default: [] 11 | # description: >- 12 | # List of runners name, label or group that are allowed to be used in PR workflows. 13 | package rules.pr_runs_on_self_hosted 14 | 15 | import data.poutine 16 | import data.poutine.utils 17 | import rego.v1 18 | 19 | rule := poutine.rule(rego.metadata.chain()) 20 | 21 | github.events contains event if some event in { 22 | "pull_request", 23 | "pull_request_review", 24 | "pull_request_review_comment", 25 | "pull_request_target", 26 | } 27 | 28 | results contains poutine.finding(rule, pkg.purl, { 29 | "path": workflow.path, 30 | "job": job.id, 31 | "line": job.lines.runs_on, 32 | "details": sprintf("runs-on: %s", [concat(", ", job.runs_on)]), 33 | "event_triggers": [event | event := workflow.events[i].name], 34 | }) if { 35 | pkg := input.packages[_] 36 | workflow = pkg.github_actions_workflows[_] 37 | job := workflow.jobs[_] 38 | 39 | utils.filter_workflow_events(workflow, github.events) 40 | utils.job_uses_self_hosted_runner(job) 41 | 42 | every runner in job.runs_on { 43 | not runner in utils.to_set(rule.config.allowed_runners.value) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /opa/rego/rules/unpinnable_action.rego: -------------------------------------------------------------------------------- 1 | # METADATA 2 | # title: Unpinnable CI component used 3 | # description: |- 4 | # Pinning this GitHub Action is likely ineffective 5 | # as it depends on other mutable supply chain components. 6 | # custom: 7 | # level: note 8 | package rules.unpinnable_action 9 | 10 | import data.external.reputation 11 | import data.poutine 12 | import data.poutine.utils 13 | import rego.v1 14 | 15 | rule := poutine.rule(rego.metadata.chain()) 16 | 17 | results contains poutine.finding(rule, pkg.purl, { 18 | "path": action.path, 19 | "dependencies": purls, 20 | }) if { 21 | pkg := input.packages[_] 22 | action := pkg.github_actions_metadata[_] 23 | source_git_repo := pkg.source_git_repo 24 | source_git_ref := pkg.source_git_ref 25 | purls := data.poutine.inventory.package_dependencies with input.packages as [{"github_actions_metadata": [action], "source_git_repo": source_git_repo, "source_git_ref": source_git_ref}] 26 | 27 | unpinned_purls := [p | 28 | p := purls[_] 29 | utils.unpinned_purl(p) 30 | ] 31 | 32 | unpinnable_purls := [p | 33 | p := purls[_] 34 | reputation.by_purl[p].attributes.unpinnable 35 | ] 36 | 37 | count(unpinnable_purls) + count(unpinned_purls) > 0 38 | } 39 | -------------------------------------------------------------------------------- /opa/testdata/config/sample.rego: -------------------------------------------------------------------------------- 1 | package poutine.config 2 | -------------------------------------------------------------------------------- /poutine.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/boostsecurityio/poutine/cmd" 5 | ) 6 | 7 | var ( 8 | version = "development" 9 | commit = "none" 10 | date = "unknown" 11 | ) 12 | 13 | func main() { 14 | cmd.Commit = commit 15 | cmd.Version = version 16 | cmd.Date = date 17 | cmd.Execute() 18 | } 19 | -------------------------------------------------------------------------------- /providers/github/round_tripper_rate_limit.go: -------------------------------------------------------------------------------- 1 | package github 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | ) 7 | 8 | type retryTransport struct{} 9 | 10 | type RateLimitError struct { 11 | RetryAfter string 12 | Err error 13 | } 14 | 15 | func (e *RateLimitError) Error() string { 16 | return fmt.Sprintf("retry after %s: %v", e.RetryAfter, e.Err) 17 | } 18 | 19 | func (e *RateLimitError) Unwrap() error { 20 | return e.Err 21 | } 22 | 23 | func (s *retryTransport) RoundTrip(r *http.Request) (*http.Response, error) { 24 | resp, err := http.DefaultTransport.RoundTrip(r) 25 | if err != nil { 26 | return nil, err 27 | } 28 | 29 | if resp != nil { 30 | retryAfter := resp.Header.Get("Retry-After") 31 | if retryAfter != "" { 32 | return nil, &RateLimitError{ 33 | RetryAfter: retryAfter, 34 | Err: fmt.Errorf("github graphql rate limit"), 35 | } 36 | } 37 | } 38 | 39 | return resp, err 40 | } 41 | -------------------------------------------------------------------------------- /providers/local/client_test.go: -------------------------------------------------------------------------------- 1 | package local 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func Test_extractHostnameFromSSHURL(t *testing.T) { 9 | type args struct { 10 | sshURL string 11 | } 12 | tests := []struct { 13 | name string 14 | args args 15 | want string 16 | }{ 17 | { 18 | name: "github", 19 | args: args{ 20 | sshURL: "git@github.com:org/repo.git", 21 | }, 22 | want: "github.com", 23 | }, 24 | } 25 | for _, tt := range tests { 26 | t.Run(tt.name, func(t *testing.T) { 27 | assert.Equal(t, tt.want, extractHostnameFromSSHURL(tt.args.sshURL)) 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /providers/pkgsupply/models.go: -------------------------------------------------------------------------------- 1 | package pkgsupply 2 | 3 | type PackageReputation struct { 4 | Purl string `json:"purl"` 5 | Repo string `json:"repo"` 6 | Risk float64 `json:"risk"` 7 | Attributes map[string]string `json:"attributes"` 8 | } 9 | 10 | type RepoReputation struct { 11 | Repo string `json:"repo"` 12 | Attributes map[string]string `json:"attributes"` 13 | } 14 | 15 | type ReputationResponse struct { 16 | Packages []PackageReputation `json:"packages"` 17 | Repos []RepoReputation `json:"repos"` 18 | } 19 | -------------------------------------------------------------------------------- /providers/pkgsupply/static.go: -------------------------------------------------------------------------------- 1 | package pkgsupply 2 | 3 | import ( 4 | "bufio" 5 | "context" 6 | _ "embed" 7 | "github.com/boostsecurityio/poutine/models" 8 | "strings" 9 | ) 10 | 11 | //go:embed unpinnable_actions.txt 12 | var unpinnableActions string 13 | 14 | type CachedPackageReputation struct { 15 | Purl string `json:"purl"` 16 | Tags []string `json:"tags"` 17 | } 18 | 19 | type StaticClient struct { 20 | unpinnableActions map[string]bool 21 | } 22 | 23 | func NewStaticClient() *StaticClient { 24 | client := &StaticClient{ 25 | unpinnableActions: make(map[string]bool), 26 | } 27 | scanner := bufio.NewScanner(strings.NewReader(unpinnableActions)) 28 | for scanner.Scan() { 29 | client.unpinnableActions[scanner.Text()] = true 30 | } 31 | 32 | return client 33 | } 34 | 35 | func (c *StaticClient) GetReputation(ctx context.Context, purls []string) (*ReputationResponse, error) { 36 | var reputation ReputationResponse 37 | 38 | for _, purl := range purls { 39 | p, err := models.NewPurl(purl) 40 | if err != nil { 41 | continue 42 | } 43 | 44 | purlPrefix := "pkg:githubactions/" + p.FullName() 45 | if len(p.Subpath) > 0 { 46 | purlPrefix += "/" + p.Subpath 47 | } 48 | 49 | if !c.unpinnableActions[purlPrefix] { 50 | continue 51 | } 52 | 53 | reputation.Packages = append(reputation.Packages, PackageReputation{ 54 | Purl: purl, 55 | Risk: 1, 56 | Attributes: map[string]string{ 57 | "unpinnable": "true", 58 | }, 59 | }) 60 | } 61 | 62 | return &reputation, nil 63 | } 64 | -------------------------------------------------------------------------------- /providers/pkgsupply/static_test.go: -------------------------------------------------------------------------------- 1 | package pkgsupply 2 | 3 | import ( 4 | "context" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func TestStaticGetReputation(t *testing.T) { 10 | client := NewStaticClient() 11 | p := "pkg:githubactions/bridgecrewio/checkov-action@foobar" 12 | res, err := client.GetReputation(context.TODO(), []string{p}) 13 | assert.Nil(t, err) 14 | 15 | assert.Equal(t, 1, len(res.Packages)) 16 | assert.Equal(t, p, res.Packages[0].Purl) 17 | assert.Equal(t, "true", res.Packages[0].Attributes["unpinnable"]) 18 | } 19 | -------------------------------------------------------------------------------- /providers/pkgsupply/testdata/reputation.json: -------------------------------------------------------------------------------- 1 | { 2 | "repos": [ 3 | { 4 | "repo": "actions/checkout", 5 | "risk": 0.5, 6 | "attributes": { 7 | "verified_org": "The organization is verified by GitHub", 8 | "workflow_default_permissions": "The repository has a workflow that uses default permissions", 9 | "workflow_injection": "The repository has workflows that have bash or JavaScript injection" 10 | } 11 | }, 12 | { 13 | "repo": "hashicorp/vault-action", 14 | "risk": 0.5, 15 | "attributes": { 16 | "verified_org": "The organization is verified by GitHub", 17 | "workflow_default_permissions": "The repository has a workflow that uses default permissions", 18 | "risky_workflows": "The repository has workflows that trigger on pull_request_target" 19 | } 20 | }, 21 | { 22 | "repo": "chainguard-images/actions", 23 | "risk": null, 24 | "attributes": { 25 | "not_analyzed": "No insights available for this action." 26 | } 27 | } 28 | ], 29 | "packages": [ 30 | { 31 | "purl": "pkg:githubactions/actions/checkout@v4", 32 | "repo": "actions/checkout", 33 | "risk": null, 34 | "attributes": { 35 | "popular": "Top 1k most used GitHub Action", 36 | "action_type": "This GitHub Action uses Node" 37 | } 38 | }, 39 | { 40 | "purl": "pkg:githubactions/hashicorp/vault-action@v1", 41 | "repo": "hashicorp/vault-action", 42 | "risk": 1, 43 | "attributes": { 44 | "popular": "Top 1k most used GitHub Action", 45 | "known_vulnerability": "The action has known vulnerabilities", 46 | "not_analyzed": "No insights available for this action." 47 | } 48 | }, 49 | { 50 | "purl": "pkg:githubactions/chainguard-images/actions/apko-build@main", 51 | "repo": "chainguard-images/actions", 52 | "risk": null, 53 | "attributes": { 54 | "not_analyzed": "No insights available for this action." 55 | } 56 | }, 57 | { 58 | "purl": "pkg:githubactions/hashicorp/vault-action@v3", 59 | "repo": "hashicorp/vault-action", 60 | "risk": null, 61 | "attributes": { 62 | "popular": "Top 1k most used GitHub Action", 63 | "not_analyzed": "No insights available for this action." 64 | } 65 | } 66 | ], 67 | "vulnerabilities": {} 68 | } 69 | -------------------------------------------------------------------------------- /providers/scm/domain/scm_domain.go: -------------------------------------------------------------------------------- 1 | package scm_domain 2 | 3 | import "strings" 4 | 5 | // ScmBaseDomain represent the base domain for a SCM provider. 6 | type ScmBaseDomain string 7 | 8 | const DefaultGitHubDomain string = "github.com" 9 | const DefaultGitLabDomain string = "gitlab.com" 10 | 11 | var schemePrefixes = []string{"https://", "http://"} 12 | 13 | func (d *ScmBaseDomain) Set(value string) error { 14 | for _, prefix := range schemePrefixes { 15 | value = strings.TrimPrefix(value, prefix) 16 | } 17 | value = strings.TrimRight(value, "/") 18 | 19 | *d = ScmBaseDomain(value) 20 | return nil 21 | } 22 | 23 | func (d *ScmBaseDomain) String() string { 24 | if d == nil { 25 | return "" 26 | } 27 | return string(*d) 28 | } 29 | 30 | func (d *ScmBaseDomain) Type() string { 31 | return "string" 32 | } 33 | -------------------------------------------------------------------------------- /providers/scm/domain/scm_domain_test.go: -------------------------------------------------------------------------------- 1 | package scm_domain 2 | 3 | import "testing" 4 | 5 | var tests = map[string]struct { 6 | input string 7 | expected string 8 | }{ 9 | "strip https": { 10 | input: "https://scm.com", 11 | expected: "scm.com", 12 | }, 13 | "strip http": { 14 | input: "http://example.scm.com", 15 | expected: "example.scm.com", 16 | }, 17 | "ignore": { 18 | input: "scm.com", 19 | expected: "scm.com", 20 | }, 21 | "empty": { 22 | input: "", 23 | expected: "", 24 | }, 25 | "trailing slash": { 26 | input: "https://scm.com/", 27 | expected: "scm.com", 28 | }, 29 | "sub path": { 30 | input: "https://scm.com/sub/domain", 31 | expected: "scm.com/sub/domain", 32 | }, 33 | } 34 | 35 | func TestScmBaseDomain(t *testing.T) { 36 | for name, test := range tests { 37 | t.Run(name, func(t *testing.T) { 38 | var d ScmBaseDomain 39 | err := d.Set(test.input) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | s := d.String() 44 | if s != test.expected { 45 | t.Errorf("expected %s, got %s", test.expected, s) 46 | } 47 | }) 48 | } 49 | } 50 | 51 | func TestScmBaseDomainNil(t *testing.T) { 52 | var d ScmBaseDomain 53 | if d.String() != "" { 54 | t.Error("expected default value of to be \"\"") 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /providers/scm/scm.go: -------------------------------------------------------------------------------- 1 | package scm 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | "fmt" 7 | 8 | "github.com/boostsecurityio/poutine/analyze" 9 | "github.com/boostsecurityio/poutine/providers/github" 10 | "github.com/boostsecurityio/poutine/providers/gitlab" 11 | ) 12 | 13 | const ( 14 | GitHub string = "github" 15 | GitLab string = "gitlab" 16 | ) 17 | 18 | func NewScmClient(ctx context.Context, providerType string, baseURL string, token string, command string) (analyze.ScmClient, error) { 19 | tokenError := "token must be provided via --token flag or GH_TOKEN environment variable" 20 | 21 | if command == "analyze_local" { 22 | return nil, nil 23 | } 24 | 25 | switch providerType { 26 | case "": 27 | if token == "" { 28 | return nil, errors.New(tokenError) 29 | } 30 | return github.NewGithubSCMClient(ctx, baseURL, token) 31 | 32 | case GitHub: 33 | if token == "" { 34 | return nil, errors.New(tokenError) 35 | } 36 | return github.NewGithubSCMClient(ctx, baseURL, token) 37 | 38 | case GitLab: 39 | if token == "" { 40 | return nil, errors.New(tokenError) 41 | } 42 | return gitlab.NewGitlabSCMClient(ctx, baseURL, token) 43 | 44 | default: 45 | return nil, fmt.Errorf("unsupported provider type: %s", providerType) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /results/results.go: -------------------------------------------------------------------------------- 1 | package results 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/json" 6 | "fmt" 7 | "strconv" 8 | 9 | "github.com/rs/zerolog/log" 10 | ) 11 | 12 | type FindingsResult struct { 13 | Findings []Finding `json:"findings"` 14 | Rules map[string]Rule `json:"rules"` 15 | } 16 | 17 | type FindingMeta struct { 18 | Path string `json:"path,omitempty"` 19 | Line int `json:"line,omitempty"` 20 | Job string `json:"job,omitempty"` 21 | Step string `json:"step,omitempty"` 22 | OsvId string `json:"osv_id,omitempty"` 23 | Details string `json:"details,omitempty"` 24 | EventTriggers []string `json:"event_triggers,omitempty"` 25 | BlobSHA string `json:"blobsha,omitempty"` 26 | } 27 | 28 | type Finding struct { 29 | RuleId string `json:"rule_id"` 30 | Purl string `json:"purl"` 31 | Meta FindingMeta `json:"meta"` 32 | } 33 | 34 | func (f *Finding) GenerateFindingFingerprint() string { 35 | fingerprintString := f.Meta.Path + strconv.Itoa(f.Meta.Line) + f.Meta.Job + f.Meta.Step + f.RuleId 36 | h := sha256.New() 37 | h.Write([]byte(fingerprintString)) 38 | fingerprint := h.Sum(nil) 39 | return fmt.Sprintf("%x", fingerprint) 40 | } 41 | 42 | func (m *FindingMeta) UnmarshalJSON(data []byte) error { 43 | type meta FindingMeta 44 | aux := &struct { 45 | Step json.Number `json:"step"` 46 | *meta 47 | }{ 48 | meta: (*meta)(m), 49 | } 50 | if err := json.Unmarshal(data, &aux); err != nil { 51 | log.Error().RawJSON("meta", data).Err(err).Msg("failed to unmarshal FindingMeta") 52 | return nil 53 | } 54 | m.Step = aux.Step.String() 55 | return nil 56 | } 57 | 58 | type Rule struct { 59 | Id string `json:"id"` 60 | Title string `json:"title"` 61 | Description string `json:"description"` 62 | Level string `json:"level"` 63 | Refs []struct { 64 | Ref string `json:"ref"` 65 | Description string `json:"description"` 66 | } `json:"refs,omitempty"` 67 | Config map[string]RuleConfig `json:"config,omitempty"` 68 | } 69 | 70 | type RuleConfig struct { 71 | Default interface{} `json:"default"` 72 | Description string `json:"description"` 73 | Value interface{} `json:"value"` 74 | } 75 | -------------------------------------------------------------------------------- /scanner/inventory_scanner.go: -------------------------------------------------------------------------------- 1 | package scanner 2 | 3 | import ( 4 | "github.com/boostsecurityio/poutine/models" 5 | "github.com/rs/zerolog/log" 6 | "io/fs" 7 | "path/filepath" 8 | "regexp" 9 | ) 10 | 11 | type Parser interface { 12 | MatchPattern() *regexp.Regexp 13 | Parse(filePath string, scanningPath string, pkgInsights *models.PackageInsights) error 14 | } 15 | 16 | type InventoryScanner struct { 17 | Path string 18 | Parsers []Parser 19 | } 20 | 21 | func NewInventoryScanner(path string) *InventoryScanner { 22 | return &InventoryScanner{ 23 | Path: path, 24 | Parsers: []Parser{ 25 | NewGithubActionsMetadataParser(), 26 | NewGithubActionWorkflowParser(), 27 | NewAzurePipelinesParser(), 28 | NewGitlabCiParser(), 29 | NewPipelineAsCodeTektonParser(), 30 | }, 31 | } 32 | } 33 | 34 | func (s *InventoryScanner) Run(pkgInsights *models.PackageInsights) error { 35 | return filepath.Walk(s.Path, func(filePath string, info fs.FileInfo, err error) error { 36 | if err != nil { 37 | return err 38 | } 39 | if info.IsDir() && info.Name() == ".git" { 40 | return filepath.SkipDir 41 | } 42 | if info.IsDir() { 43 | return nil 44 | } 45 | relativePath, err := filepath.Rel(s.Path, filePath) 46 | if err != nil { 47 | log.Error().Err(err).Msg("error getting relative path") 48 | return err 49 | } 50 | for _, parser := range s.Parsers { 51 | if parser.MatchPattern().MatchString(relativePath) { 52 | if err := parser.Parse(filePath, s.Path, pkgInsights); err != nil { 53 | log.Error().Str("file", filePath).Err(err).Msg("error parsing matched file") 54 | continue 55 | } 56 | } 57 | } 58 | return nil 59 | }) 60 | } 61 | -------------------------------------------------------------------------------- /scanner/inventory_scanner_mem.go: -------------------------------------------------------------------------------- 1 | package scanner 2 | 3 | import ( 4 | "regexp" 5 | 6 | "github.com/boostsecurityio/poutine/models" 7 | "github.com/rs/zerolog/log" 8 | ) 9 | 10 | type MemParser interface { 11 | MatchPattern() *regexp.Regexp 12 | ParseFromMemory(data []byte, filePath string, pkgInsights *models.PackageInsights) error 13 | } 14 | 15 | type InventoryScannerMem struct { 16 | Files map[string][]byte 17 | Parsers []MemParser 18 | } 19 | 20 | func (s *InventoryScannerMem) Run(pkgInsights *models.PackageInsights) error { 21 | for path, data := range s.Files { 22 | for _, parser := range s.Parsers { 23 | if !parser.MatchPattern().MatchString(path) { 24 | continue 25 | } 26 | if err := parser.ParseFromMemory(data, path, pkgInsights); err != nil { 27 | log.Error().Str("file", path).Err(err).Msg("error parsing matched file") 28 | } 29 | } 30 | } 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /scanner/testdata/.azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | pr: 2 | branches: 3 | include: 4 | - master 5 | 6 | variables: 7 | system.debug: 'true' 8 | 9 | # implicit stage 10 | jobs: 11 | - job: build 12 | steps: 13 | - task: Cache@2 14 | - powershell: echo "$(Build.SourceBranch)" 15 | -------------------------------------------------------------------------------- /scanner/testdata/.github/action.yaml: -------------------------------------------------------------------------------- 1 | not an action 2 | -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/allowed_pr_runner.yml: -------------------------------------------------------------------------------- 1 | name: allowed_pr_runner.yml 2 | on: 3 | pull_request: 4 | 5 | jobs: 6 | hosted: 7 | runs-on: [macos-latest, ubuntu-latest] 8 | steps: 9 | - uses: actions/checkout@v4 10 | 11 | group: 12 | runs-on: 13 | group: prdeploy 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | labels: 18 | runs-on: 19 | labels: linux 20 | steps: 21 | - uses: actions/checkout@v4 22 | -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/debug_enabled_valid.yml: -------------------------------------------------------------------------------- 1 | name: debug_enabled_valid.yml 2 | on: 3 | push: 4 | 5 | env: 6 | ACTIONS_RUNNER_DEBUG: true 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | env: 12 | ACTIONS_STEP_DEBUG: true 13 | steps: 14 | - id: one 15 | env: 16 | ACTIONS_STEP_DEBUG: true 17 | run: echo Hello 18 | -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/invalid-workflow.yaml: -------------------------------------------------------------------------------- 1 | foo: bar 2 | -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/invalid-yaml.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/matrix.yml: -------------------------------------------------------------------------------- 1 | name: matrix.yml 2 | on: 3 | push: 4 | 5 | jobs: 6 | example_matrix: 7 | strategy: 8 | matrix: 9 | os: [ubuntu-22.04, ubuntu-20.04] 10 | version: [10, 12, 14] 11 | runs-on: ${{ matrix.os }} 12 | steps: 13 | - uses: actions/setup-node@v4 14 | with: 15 | node-version: ${{ matrix.version }} -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/random-file: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostsecurityio/poutine/68f289d615c19b743f91bc0bd84c4922074df941/scanner/testdata/.github/workflows/random-file -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/reusable.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | ref: 5 | required: true 6 | 7 | jobs: 8 | clone: 9 | runs-on: ubuntu-latest 10 | container: 11 | image: node:latest 12 | steps: 13 | - uses: actions/checkout@main 14 | with: 15 | ref: ${{ inputs.ref }} 16 | 17 | uses: 18 | runs-on: ubuntu-latest 19 | uses: org/repo/.github/workflows/Reusable.yml@main 20 | with: 21 | ref: ${{ inputs.ref }} 22 | 23 | local-uses: 24 | runs-on: ubuntu-latest 25 | uses: ./.github/workflows/ci.yml 26 | -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/secrets.yaml: -------------------------------------------------------------------------------- 1 | on: pull_request 2 | 3 | jobs: 4 | matrix: 5 | strategy: 6 | matrix: 7 | image: ['ubuntu:20.04', 'centos:7'] 8 | env: [dev, prod] 9 | container: ${{ matrix.image }} 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: org/repo@main 13 | with: 14 | token: ${{ secrets[format('SECRET_%s', matrix.env)] }} 15 | 16 | json: 17 | runs-on: macos-14-xlarge 18 | env: 19 | SECRETS: ${{ toJSON(secrets) }} 20 | steps: 21 | - run: | 22 | echo $SECRETS 23 | -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/valid.yml: -------------------------------------------------------------------------------- 1 | name: valid.yml 2 | on: 3 | push: 4 | pull_request_target: 5 | 6 | 7 | jobs: 8 | build: 9 | runs-on: [self-hosted] 10 | if: ${{ github.event_name == 'push' }} 11 | steps: 12 | - id: 0 13 | uses: actions/checkout@v4 14 | with: 15 | ref: ${{ github.head_ref }} 16 | script: js 17 | 18 | # workflow-injection 19 | - id: 1 20 | run: | 21 | ${{ github.head_ref }} 22 | 23 | # TODO: workflow-injection 24 | - id: 2 25 | run: | 26 | ${{ github['head_ref'] }} 27 | 28 | # untrusted-checkout-exec 29 | - id: 3 30 | run: | 31 | npm install 32 | 33 | # ok 34 | - id: 4 35 | uses: kartverket/github-workflows/.github/workflows/run-terraform.yml@main 36 | 37 | # GHSA-f9qj-7gh3-mhj4 38 | - id: 5 39 | uses: kartverket/github-workflows/.github/workflows/run-terraform.yml@v2.7.1 40 | 41 | # GHSA-f9qj-7gh3-mhj4 42 | - id: 6 43 | uses: kartverket/github-workflows/.github/workflows/run-terraform.yml@v2.2 44 | 45 | - id: 7 46 | run: | 47 | ${{ github.event.workflow_run.head_branch }} 48 | 49 | - id: 8 50 | run: | 51 | ${{ github.event.client_payload.foo }} 52 | ${{ github.event.client_payload.foo }} 53 | 54 | # untrusted-checkout-exec 55 | - id: 9 56 | uses: bridgecrewio/checkov-action@main 57 | 58 | # TODO FP untrusted-checkout-exec context awareness 59 | - id: 10 60 | run: | 61 | echo "pre-commit run" 62 | 63 | - id: 11 64 | run: | 65 | # substring of go\ generate should not trigger 66 | cargo generate 67 | 68 | # unverified_script_exec 69 | - id: 12 70 | run: | 71 | curl https://example.com | bash 72 | 73 | # unverified_script_exec 74 | - id: 13 75 | run: | 76 | curl https://raw.githubusercontent.com/org/repo/main/install.sh | bash 77 | 78 | # safe unverified_script_exec 79 | - id: 13 80 | run: | 81 | curl https://raw.githubusercontent.com/org/repo/0a727065ae5a2313e8e6acf172844e8ca30c1822/install.sh | bash 82 | curl https://github.com/org/repo/raw/0a727065ae5a2313e8e6acf172844e8ca30c1822/install.sh | bash 83 | -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/workflow_run_reusable.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_run: 3 | workflows: [reusable.yml] 4 | 5 | jobs: 6 | pr: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v4 11 | with: 12 | ref: ${{ github.event.workflow_run.head_sha }} 13 | - run: npm install 14 | -------------------------------------------------------------------------------- /scanner/testdata/.github/workflows/workflow_run_valid.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_run: 3 | workflows: ["v[a-z]l[i]*.yml"] 4 | 5 | jobs: 6 | pr: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v4 11 | with: 12 | ref: ${{ github.event.workflow_run.head_sha }} 13 | - run: npm install 14 | -------------------------------------------------------------------------------- /scanner/testdata/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | spec: 2 | inputs: 3 | gem_name: 4 | gem_path_prefix: 5 | default: "gems/" 6 | --- 7 | 8 | include: 9 | - local: '/include.yml' 10 | inputs: 11 | foo: bar 12 | 13 | # TODO: not part of the inventory due to vars 14 | - project: '$CI_PROJECT_PATH' 15 | ref: main 16 | file: '/templates/.gitlab-ci-template.yml' 17 | 18 | - project: 'my-group/my-project' 19 | ref: main 20 | file: '/templates/.gitlab-ci-template.yml' 21 | 22 | - template: Auto-DevOps.gitlab-ci.yml 23 | 24 | - remote: https://example.com/.gitlab-ci.yml 25 | 26 | - component: gitlab.example.com/my-org/security-components/secret-detection@1.0 27 | 28 | workflow: 29 | name: '[$[[inputs.gem_name]] gem] Ruby $RUBY_VERSION pipeline' 30 | rules: 31 | - when: always 32 | 33 | variables: 34 | BUNDLE_PATH: "vendor" 35 | BUNDLE_FROZEN: "true" 36 | RUBY_VERSION: "3.2" 37 | CI_DEBUG_SERVICES: 'true' 38 | 39 | default: 40 | image: "ruby:3.2" 41 | services: 42 | - name: postgres:15 43 | cache: 44 | key: "$[[inputs.gem_name]]-3.2" 45 | paths: 46 | - "$[[inputs.gem_path_prefix]]$[[inputs.gem_name]]/vendor/ruby" 47 | before_script: 48 | - cd $[[inputs.gem_path_prefix]]$[[inputs.gem_name|expand_vars]] 49 | - ruby -v # Print out ruby version for debugging 50 | - bundle_version=$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1 | sed -e 's/[[:space:]]//') 51 | - gem install bundler --version "$bundle_version" --no-document # Bundler is not installed with the image 52 | - bundle config # Show bundler configuration 53 | - bundle install --jobs=$(nproc) --retry=3 54 | 55 | .ruby_matrix: 56 | image: "ruby:${RUBY_VERSION}" # TODO: inventory 57 | parallel: 58 | matrix: 59 | - RUBY_VERSION: ["3.0", "3.1", "3.2"] 60 | 61 | rubocop: 62 | extends: .ruby_matrix 63 | variables: 64 | CI_DEBUG_TRACE: 'TRUE' 65 | rules: 66 | - exists: ["$[[inputs.gem_path_prefix]]$[[inputs.gem_name]]/.rubocop.yml"] 67 | script: 68 | - bundle exec rubocop 69 | 70 | rspec: 71 | extends: .ruby_matrix 72 | script: 73 | - RAILS_ENV=test bundle exec rspec 74 | coverage: '/LOC \((\d+\.\d+%)\) covered.$/' 75 | artifacts: 76 | expire_in: 31d 77 | when: always 78 | paths: 79 | - coverage/ 80 | -------------------------------------------------------------------------------- /scanner/testdata/.local-ci-template.yml: -------------------------------------------------------------------------------- 1 | localjob: 2 | image: 3 | name: debian:vuln 4 | script: 5 | - echo 123 6 | -------------------------------------------------------------------------------- /scanner/testdata/.tekton/pipeline-as-code-tekton.yml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: PipelineRun 3 | metadata: 4 | name: linters 5 | annotations: 6 | pipelinesascode.tekton.dev/on-event: "[push, pull_request]" 7 | pipelinesascode.tekton.dev/on-target-branch: "[*]" 8 | pipelinesascode.tekton.dev/task: "[git-clone]" 9 | spec: 10 | params: 11 | - name: repo_url 12 | value: "{{repo_url}}" 13 | - name: revision 14 | value: "{{revision}}" 15 | pipelineSpec: 16 | params: 17 | - name: repo_url 18 | - name: revision 19 | tasks: 20 | - name: fetchit 21 | displayName: "Fetch git repository" 22 | params: 23 | - name: url 24 | value: $(params.repo_url) 25 | - name: revision 26 | value: $(params.revision) 27 | taskRef: 28 | name: git-clone 29 | workspaces: 30 | - name: output 31 | workspace: source 32 | - name: vale 33 | displayName: "Spelling and Grammar" 34 | runAfter: 35 | - fetchit 36 | taskSpec: 37 | workspaces: 38 | - name: source 39 | steps: 40 | - name: vale-lint 41 | image: jdkato/vale 42 | workingDir: $(workspaces.source.path) 43 | script: | 44 | vale docs/content --minAlertLevel=error --output=line 45 | - name: injection 46 | image: jdkato/vale 47 | workingDir: $(workspaces.source.path) 48 | script: | 49 | binary {{body.pull_request.body}} 50 | workspaces: 51 | - name: source 52 | workspace: source 53 | workspaces: 54 | - name: source 55 | workspaces: 56 | - name: source 57 | volumeClaimTemplate: 58 | spec: 59 | accessModes: 60 | - ReadWriteOnce 61 | resources: 62 | requests: 63 | storage: 5Gi -------------------------------------------------------------------------------- /scanner/testdata/action.yml: -------------------------------------------------------------------------------- 1 | runs: 2 | using: docker 3 | image: docker://alpine:latest 4 | -------------------------------------------------------------------------------- /scanner/testdata/azure-pipelines-1.yml: -------------------------------------------------------------------------------- 1 | pr: none 2 | 3 | # implicit stage, job 4 | steps: 5 | - task: DownloadPipelineArtifact@2 6 | - powershell: | 7 | echo "Hello, pr!" 8 | - bash: | 9 | curl $(URL) | bash 10 | - script: npm install 11 | -------------------------------------------------------------------------------- /scanner/testdata/azure-pipelines-2.yml: -------------------------------------------------------------------------------- 1 | pr: 2 | - main 3 | 4 | pool: 5 | vmImage: ubuntu-latest 6 | 7 | variables: 8 | - name: trustedSourceUrl 9 | value: https://gist.githubusercontent.com/fproulx-boostsecurity/fef312cd7d54b9420b10fd50d0793191/raw/a5f417b88fa2184a9726b274daf18d29da6c79ad/id 10 | 11 | steps: 12 | - checkout: self 13 | - script: bash script.sh 14 | - script: npm install -------------------------------------------------------------------------------- /scanner/testdata/azure-pipelines-3.yml: -------------------------------------------------------------------------------- 1 | pr: 2 | - main 3 | 4 | pool: 5 | vmImage: ubuntu-latest 6 | 7 | variables: 8 | - name: trustedSourceUrl 9 | value: https://gist.githubusercontent.com/fproulx-boostsecurity/fef312cd7d54b9420b10fd50d0793191/raw/a5f417b88fa2184a9726b274daf18d29da6c79ad/id 10 | 11 | steps: 12 | - script: bash script.sh 13 | - script: npm install 14 | - checkout: self 15 | -------------------------------------------------------------------------------- /scanner/testdata/azure-pipelines-4.yml: -------------------------------------------------------------------------------- 1 | pool: 2 | vmImage: ubuntu-latest 3 | 4 | variables: 5 | - name: trustedSourceUrl 6 | value: https://gist.githubusercontent.com/fproulx-boostsecurity/fef312cd7d54b9420b10fd50d0793191/raw/a5f417b88fa2184a9726b274daf18d29da6c79ad/id 7 | 8 | steps: 9 | - checkout: self 10 | - script: bash script.sh 11 | - script: npm install -------------------------------------------------------------------------------- /scanner/testdata/composite/action.yml: -------------------------------------------------------------------------------- 1 | runs: 2 | using: composite 3 | steps: 4 | - uses: actions/github-script@main 5 | with: 6 | script: ${{ inputs.foo }} 7 | 8 | # ok 9 | - uses: hashicorp/vault-action@v3 10 | 11 | 12 | # GHSA-4mgv-m5cm-f9h7 13 | - uses: hashicorp/vault-action@v2.1.0 14 | 15 | - id: if-always-true 16 | run: ls 17 | if: | 18 | ${{ github.event == 'not-checked' }} 19 | -------------------------------------------------------------------------------- /scanner/testdata/include.yml: -------------------------------------------------------------------------------- 1 | --- 2 | include: 3 | - /.local-ci-template.yml 4 | --------------------------------------------------------------------------------